Chromium Code Reviews| 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 const DisplayItem& existingItem = *list.elementAt(index); |
|
danakj
2015/06/30 18:49:01
This is using elementAt() in non-assert code AFAIC
jbroman
2015/06/30 18:59:17
I'd suggest attempting this in a followup CL. I el
pdr.
2015/06/30 22:16:06
I added a TODO here and filed crbug.com/505965.
| |
| 157 ASSERT(existingItem.isGone() || existingItem.client() == id.client); | 158 ASSERT(existingItem.ignoreFromDisplayList() || existingItem.client() == id.client); |
| 158 if (!existingItem.isGone() && existingItem.id().equalToExceptForType(id, matchingType)) | 159 if (!existingItem.ignoreFromDisplayList() && existingItem.id().equalToEx ceptForType(id, matchingType)) |
| 159 return index; | 160 return index; |
| 160 } | 161 } |
| 161 | 162 |
| 162 return kNotFound; | 163 return kNotFound; |
| 163 } | 164 } |
| 164 | 165 |
| 165 void DisplayItemList::addItemToIndex(DisplayItemClient client, DisplayItem::Type type, size_t index, DisplayItemIndicesByClientMap& displayItemIndicesByClient) | 166 void DisplayItemList::addItemToIndex(DisplayItemClient client, DisplayItem::Type type, size_t index, DisplayItemIndicesByClientMap& displayItemIndicesByClient) |
| 166 { | 167 { |
| 167 // Only need to index DrawingDisplayItems and FIXME: BeginSubtreeDisplayItem s. | 168 // Only need to index DrawingDisplayItems and FIXME: BeginSubtreeDisplayItem s. |
| 168 if (!DisplayItem::isDrawingType(type)) | 169 if (!DisplayItem::isDrawingType(type)) |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 184 return m_currentDisplayItems.iteratorAt(foundIndex); | 185 return m_currentDisplayItems.iteratorAt(foundIndex); |
| 185 | 186 |
| 186 return findOutOfOrderCachedItemForward(currentIt, id, matchingType, displayI temIndicesByClient); | 187 return findOutOfOrderCachedItemForward(currentIt, id, matchingType, displayI temIndicesByClient); |
| 187 } | 188 } |
| 188 | 189 |
| 189 // Find forward for the item and index all skipped indexable items. | 190 // 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) | 191 DisplayItems::Iterator DisplayItemList::findOutOfOrderCachedItemForward(DisplayI tems::Iterator currentIt, const DisplayItem::Id& id, DisplayItem::Type matchingT ype, DisplayItemIndicesByClientMap& displayItemIndicesByClient) |
| 191 { | 192 { |
| 192 DisplayItems::Iterator currentEnd = m_currentDisplayItems.end(); | 193 DisplayItems::Iterator currentEnd = m_currentDisplayItems.end(); |
| 193 for (; currentIt != currentEnd; ++currentIt) { | 194 for (; currentIt != currentEnd; ++currentIt) { |
| 194 DisplayItems::ItemHandle item = *currentIt; | 195 const DisplayItem& item = **currentIt; |
| 195 if (!item.isGone() | 196 if (!item.ignoreFromDisplayList() |
| 196 && DisplayItem::isDrawingType(item.type()) | 197 && DisplayItem::isDrawingType(item.type()) |
| 197 && m_validlyCachedClients.contains(item.client())) { | 198 && m_validlyCachedClients.contains(item.client())) { |
| 198 if (item.id().equalToExceptForType(id, matchingType)) | 199 if (item.id().equalToExceptForType(id, matchingType)) |
| 199 return currentIt; | 200 return currentIt; |
| 200 | 201 |
| 201 size_t currentDisplayItemsIndex = m_currentDisplayItems.indexForIter ator(currentIt); | 202 addItemToIndex(item.client(), item.type(), currentIt.index(), displa yItemIndicesByClient); |
| 202 addItemToIndex(item.client(), item.type(), currentDisplayItemsIndex, displayItemIndicesByClient); | |
| 203 } | 203 } |
| 204 } | 204 } |
| 205 return currentEnd; | 205 return currentEnd; |
| 206 } | 206 } |
| 207 | 207 |
| 208 // Update the existing display items by removing invalidated entries, updating | 208 // Update the existing display items by removing invalidated entries, updating |
| 209 // repainted ones, and appending new items. | 209 // repainted ones, and appending new items. |
| 210 // - For CachedDisplayItem, copy the corresponding cached DrawingDisplayItem; | 210 // - For CachedDisplayItem, copy the corresponding cached DrawingDisplayItem; |
| 211 // - FIXME: Re-enable SubtreeCachedDisplayItem: | 211 // - FIXME: Re-enable SubtreeCachedDisplayItem: |
| 212 // For SubtreeCachedDisplayItem, copy the cached display items between the | 212 // For SubtreeCachedDisplayItem, copy the cached display items between the |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 223 | 223 |
| 224 // These data structures are used during painting only. | 224 // These data structures are used during painting only. |
| 225 m_clientScopeIdMap.clear(); | 225 m_clientScopeIdMap.clear(); |
| 226 ASSERT(m_scopeStack.isEmpty()); | 226 ASSERT(m_scopeStack.isEmpty()); |
| 227 m_scopeStack.clear(); | 227 m_scopeStack.clear(); |
| 228 ASSERT(!skippingCache()); | 228 ASSERT(!skippingCache()); |
| 229 #if ENABLE(ASSERT) | 229 #if ENABLE(ASSERT) |
| 230 m_newDisplayItemIndicesByClient.clear(); | 230 m_newDisplayItemIndicesByClient.clear(); |
| 231 #endif | 231 #endif |
| 232 | 232 |
| 233 if (m_currentDisplayItems.isEmpty()) { | 233 if (m_currentDisplayItems.empty()) { |
| 234 #if ENABLE(ASSERT) | 234 #if ENABLE(ASSERT) |
| 235 for (auto& item : m_newDisplayItems) { | 235 for (const auto& item : m_newDisplayItems) { |
| 236 ASSERT(!DisplayItem::isCachedType(item.type()) | 236 ASSERT(!DisplayItem::isCachedType(item->type()) |
| 237 && !DisplayItem::isSubtreeCachedType(item.type())); | 237 && !DisplayItem::isSubtreeCachedType(item->type())); |
| 238 } | 238 } |
| 239 #endif | 239 #endif |
| 240 m_currentDisplayItems.swap(m_newDisplayItems); | 240 m_currentDisplayItems.swap(m_newDisplayItems); |
| 241 m_validlyCachedClientsDirty = true; | 241 m_validlyCachedClientsDirty = true; |
| 242 m_numCachedItems = 0; | 242 m_numCachedItems = 0; |
| 243 return; | 243 return; |
| 244 } | 244 } |
| 245 | 245 |
| 246 updateValidlyCachedClientsIfNeeded(); | 246 updateValidlyCachedClientsIfNeeded(); |
| 247 | 247 |
| 248 // Stores indices to valid DrawingDisplayItems in m_currentDisplayItems that have not been matched | 248 // 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 | 249 // 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 | 250 // 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 | 251 // 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. | 252 // looking for potential matches. Thus we can ensure that the algorithm runs in linear time. |
| 253 DisplayItemIndicesByClientMap displayItemIndicesByClient; | 253 DisplayItemIndicesByClientMap displayItemIndicesByClient; |
| 254 | 254 |
| 255 #if ENABLE(ASSERT) | 255 #if ENABLE(ASSERT) |
| 256 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled()) { | 256 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled()) { |
| 257 // Under-invalidation checking requires a full index of m_currentDisplay Items. | 257 // Under-invalidation checking requires a full index of m_currentDisplay Items. |
| 258 size_t i = 0; | 258 size_t i = 0; |
| 259 for (const auto& item : m_currentDisplayItems) { | 259 for (const auto& item : m_currentDisplayItems) { |
| 260 addItemToIndex(item.client(), item.type(), i, displayItemIndicesByCl ient); | 260 addItemToIndex(item->client(), item->type(), i, displayItemIndicesBy Client); |
| 261 ++i; | 261 ++i; |
| 262 } | 262 } |
| 263 } | 263 } |
| 264 #endif // ENABLE(ASSERT) | 264 #endif // ENABLE(ASSERT) |
| 265 | 265 |
| 266 DisplayItems updatedList; | 266 DisplayItems updatedList(kMaximumDisplayItemSize, std::max(m_currentDisplayI tems.size(), m_newDisplayItems.size())); |
| 267 DisplayItems::Iterator currentIt = m_currentDisplayItems.begin(); | 267 DisplayItems::Iterator currentIt = m_currentDisplayItems.begin(); |
| 268 DisplayItems::Iterator currentEnd = m_currentDisplayItems.end(); | 268 DisplayItems::Iterator currentEnd = m_currentDisplayItems.end(); |
| 269 for (DisplayItems::Iterator newIt = m_newDisplayItems.begin(); newIt != m_ne wDisplayItems.end(); ++newIt) { | 269 for (DisplayItems::Iterator newIt = m_newDisplayItems.begin(); newIt != m_ne wDisplayItems.end(); ++newIt) { |
| 270 DisplayItems::ItemHandle newDisplayItem = *newIt; | 270 const DisplayItem& newDisplayItem = **newIt; |
| 271 DisplayItem::Type matchingType = newDisplayItem.type(); | 271 DisplayItem::Type matchingType = newDisplayItem.type(); |
| 272 if (DisplayItem::isCachedType(newDisplayItem.type())) | 272 if (DisplayItem::isCachedType(newDisplayItem.type())) |
| 273 matchingType = DisplayItem::cachedTypeToDrawingType(matchingType); | 273 matchingType = DisplayItem::cachedTypeToDrawingType(matchingType); |
| 274 bool isSynchronized = currentIt != currentEnd | 274 bool isSynchronized = currentIt != currentEnd |
| 275 && !currentIt->isGone() | 275 && !currentIt->ignoreFromDisplayList() |
| 276 && currentIt->id().equalToExceptForType(newDisplayItem.id(), matchin gType); | 276 && currentIt->id().equalToExceptForType(newDisplayItem.id(), matchin gType); |
| 277 | 277 |
| 278 if (DisplayItem::isCachedType(newDisplayItem.type())) { | 278 if (DisplayItem::isCachedType(newDisplayItem.type())) { |
| 279 ASSERT(!RuntimeEnabledFeatures::slimmingPaintUnderInvalidationChecki ngEnabled()); | 279 ASSERT(!RuntimeEnabledFeatures::slimmingPaintUnderInvalidationChecki ngEnabled()); |
| 280 ASSERT(clientCacheIsValid(newDisplayItem.client())); | 280 ASSERT(clientCacheIsValid(newDisplayItem.client())); |
| 281 if (isSynchronized) { | 281 if (isSynchronized) { |
| 282 updatedList.appendByMoving(currentIt); | 282 updatedList.appendByMoving(*currentIt); |
| 283 } else { | 283 } else { |
| 284 DisplayItems::Iterator foundIt = findOutOfOrderCachedItem(curren tIt, newDisplayItem.id(), matchingType, displayItemIndicesByClient); | 284 DisplayItems::Iterator foundIt = findOutOfOrderCachedItem(curren tIt, newDisplayItem.id(), matchingType, displayItemIndicesByClient); |
| 285 isSynchronized = (foundIt == currentIt); | 285 isSynchronized = (foundIt == currentIt); |
| 286 | 286 |
| 287 #ifndef NDEBUG | 287 #ifndef NDEBUG |
| 288 if (foundIt == currentEnd) { | 288 if (foundIt == currentEnd) { |
| 289 showDebugData(); | 289 showDebugData(); |
| 290 WTFLogAlways("CachedDisplayItem %s not found in m_currentDis playItems\n", | 290 WTFLogAlways("CachedDisplayItem %s not found in m_currentDis playItems\n", |
| 291 newDisplayItem.asDebugString().utf8().data()); | 291 newDisplayItem.asDebugString().utf8().data()); |
| 292 ASSERT_NOT_REACHED(); | 292 ASSERT_NOT_REACHED(); |
| 293 } | 293 } |
| 294 #endif | 294 #endif |
| 295 // If foundIt == currentEnd, it means that we did not find the c ached display item. This should be impossible, but may occur | 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 there is a bug in the system, such as under-invalidation, incorrect cache checking or duplicate display ids. In this case, | 296 // 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. | 297 // attempt to recover rather than crashing or bailing on display of the rest of the display list. |
| 298 if (foundIt == currentEnd) | 298 if (foundIt == currentEnd) |
| 299 continue; | 299 continue; |
| 300 | 300 |
| 301 currentIt = foundIt; | 301 currentIt = foundIt; |
| 302 | 302 |
| 303 updatedList.appendByMoving(foundIt); | 303 updatedList.appendByMoving(*foundIt); |
| 304 } | 304 } |
| 305 } else { | 305 } else { |
| 306 #if ENABLE(ASSERT) | 306 #if ENABLE(ASSERT) |
| 307 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEn abled()) | 307 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEn abled()) |
| 308 checkCachedDisplayItemIsUnchanged(newDisplayItem, displayItemInd icesByClient); | 308 checkCachedDisplayItemIsUnchanged(newDisplayItem, displayItemInd icesByClient); |
| 309 else | 309 else |
| 310 ASSERT(!DisplayItem::isDrawingType(newDisplayItem.type()) || new DisplayItem.skippedCache() || !clientCacheIsValid(newDisplayItem.client())); | 310 ASSERT(!DisplayItem::isDrawingType(newDisplayItem.type()) || new DisplayItem.skippedCache() || !clientCacheIsValid(newDisplayItem.client())); |
| 311 #endif // ENABLE(ASSERT) | 311 #endif // ENABLE(ASSERT) |
| 312 updatedList.appendByMoving(newIt); | 312 updatedList.appendByMoving(*newIt); |
| 313 } | 313 } |
| 314 | 314 |
| 315 if (isSynchronized) | 315 if (isSynchronized) |
| 316 ++currentIt; | 316 ++currentIt; |
| 317 } | 317 } |
| 318 | 318 |
| 319 #if ENABLE(ASSERT) | 319 #if ENABLE(ASSERT) |
| 320 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled()) | 320 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled()) |
| 321 checkNoRemainingCachedDisplayItems(); | 321 checkNoRemainingCachedDisplayItems(); |
| 322 #endif // ENABLE(ASSERT) | 322 #endif // ENABLE(ASSERT) |
| 323 | 323 |
| 324 m_newDisplayItems.clear(); | 324 m_newDisplayItems.clear(); |
| 325 m_validlyCachedClientsDirty = true; | 325 m_validlyCachedClientsDirty = true; |
| 326 m_currentDisplayItems.clear(); | |
| 327 m_currentDisplayItems.swap(updatedList); | 326 m_currentDisplayItems.swap(updatedList); |
| 328 m_numCachedItems = 0; | 327 m_numCachedItems = 0; |
| 329 } | 328 } |
| 330 | 329 |
| 331 void DisplayItemList::updateValidlyCachedClientsIfNeeded() const | 330 void DisplayItemList::updateValidlyCachedClientsIfNeeded() const |
| 332 { | 331 { |
| 333 if (!m_validlyCachedClientsDirty) | 332 if (!m_validlyCachedClientsDirty) |
| 334 return; | 333 return; |
| 335 | 334 |
| 336 m_validlyCachedClients.clear(); | 335 m_validlyCachedClients.clear(); |
| 337 m_validlyCachedClientsDirty = false; | 336 m_validlyCachedClientsDirty = false; |
| 338 | 337 |
| 339 DisplayItemClient lastClient = nullptr; | 338 DisplayItemClient lastClient = nullptr; |
| 340 for (const auto& displayItem : m_currentDisplayItems) { | 339 for (const auto& displayItem : m_currentDisplayItems) { |
| 341 if (displayItem.client() == lastClient) | 340 if (displayItem->client() == lastClient) |
| 342 continue; | 341 continue; |
| 343 lastClient = displayItem.client(); | 342 lastClient = displayItem->client(); |
| 344 if (!displayItem.skippedCache()) | 343 if (!displayItem->skippedCache()) |
| 345 m_validlyCachedClients.add(lastClient); | 344 m_validlyCachedClients.add(lastClient); |
| 346 } | 345 } |
| 347 } | 346 } |
| 348 | 347 |
| 349 void DisplayItemList::commitNewDisplayItemsAndAppendToWebDisplayItemList(WebDisp layItemList* list) | 348 void DisplayItemList::commitNewDisplayItemsAndAppendToWebDisplayItemList(WebDisp layItemList* list) |
| 350 { | 349 { |
| 351 commitNewDisplayItems(); | 350 commitNewDisplayItems(); |
| 352 for (auto& item : m_currentDisplayItems) | 351 for (const auto& item : m_currentDisplayItems) |
| 353 item.appendToWebDisplayItemList(list); | 352 item->appendToWebDisplayItemList(list); |
| 354 } | 353 } |
| 355 | 354 |
| 356 #if ENABLE(ASSERT) | 355 #if ENABLE(ASSERT) |
| 357 | 356 |
| 358 static void showUnderInvalidationError(const char* reason, const DisplayItems::I temHandle& displayItem) | 357 static void showUnderInvalidationError(const char* reason, const DisplayItem& di splayItem) |
| 359 { | 358 { |
| 360 #ifndef NDEBUG | 359 #ifndef NDEBUG |
| 361 WTFLogAlways("%s: %s\nSee http://crbug.com/450725.", reason, displayItem.asD ebugString().utf8().data()); | 360 WTFLogAlways("%s: %s\nSee http://crbug.com/450725.", reason, displayItem.asD ebugString().utf8().data()); |
| 362 #else | 361 #else |
| 363 WTFLogAlways("%s. Run debug build to get more details\nSee http://crbug.com/ 450725.", reason); | 362 WTFLogAlways("%s. Run debug build to get more details\nSee http://crbug.com/ 450725.", reason); |
| 364 #endif // NDEBUG | 363 #endif // NDEBUG |
| 365 } | 364 } |
| 366 | 365 |
| 367 static bool bitmapIsAllZero(const SkBitmap& bitmap) | 366 static bool bitmapIsAllZero(const SkBitmap& bitmap) |
| 368 { | 367 { |
| 369 bitmap.lockPixels(); | 368 bitmap.lockPixels(); |
| 370 bool result = true; | 369 bool result = true; |
| 371 for (int x = 0; result && x < bitmap.width(); ++x) { | 370 for (int x = 0; result && x < bitmap.width(); ++x) { |
| 372 for (int y = 0; result && y < bitmap.height(); ++y) { | 371 for (int y = 0; result && y < bitmap.height(); ++y) { |
| 373 if (SkColorSetA(bitmap.getColor(x, y), 0) != SK_ColorTRANSPARENT) | 372 if (SkColorSetA(bitmap.getColor(x, y), 0) != SK_ColorTRANSPARENT) |
| 374 result = false; | 373 result = false; |
| 375 } | 374 } |
| 376 } | 375 } |
| 377 bitmap.unlockPixels(); | 376 bitmap.unlockPixels(); |
| 378 return result; | 377 return result; |
| 379 } | 378 } |
| 380 | 379 |
| 381 void DisplayItemList::checkCachedDisplayItemIsUnchanged(const DisplayItems::Item Handle& displayItem, DisplayItemIndicesByClientMap& displayItemIndicesByClient) | 380 void DisplayItemList::checkCachedDisplayItemIsUnchanged(const DisplayItem& displ ayItem, DisplayItemIndicesByClientMap& displayItemIndicesByClient) |
| 382 { | 381 { |
| 383 ASSERT(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled ()); | 382 ASSERT(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled ()); |
| 384 | 383 |
| 385 if (!DisplayItem::isDrawingType(displayItem.type()) || displayItem.skippedCa che() || !clientCacheIsValid(displayItem.client())) | 384 if (!DisplayItem::isDrawingType(displayItem.type()) || displayItem.skippedCa che() || !clientCacheIsValid(displayItem.client())) |
| 386 return; | 385 return; |
| 387 | 386 |
| 388 // If checking under-invalidation, we always generate new display item even if the client is not invalidated. | 387 // 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 | 388 // 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. | 389 // the client is not invalidated, issue error about under-invalidation. |
| 391 size_t index = findMatchingItemFromIndex(displayItem.id(), displayItem.type( ), displayItemIndicesByClient, m_currentDisplayItems); | 390 size_t index = findMatchingItemFromIndex(displayItem.id(), displayItem.type( ), displayItemIndicesByClient, m_currentDisplayItems); |
| 392 if (index == kNotFound) { | 391 if (index == kNotFound) { |
| 393 showUnderInvalidationError("ERROR: under-invalidation: no cached display item", displayItem); | 392 showUnderInvalidationError("ERROR: under-invalidation: no cached display item", displayItem); |
| 394 ASSERT_NOT_REACHED(); | 393 ASSERT_NOT_REACHED(); |
| 395 return; | 394 return; |
| 396 } | 395 } |
| 397 | 396 |
| 398 DisplayItems::Iterator foundItem = m_currentDisplayItems.iteratorAt(index); | 397 DisplayItems::Iterator foundItem = m_currentDisplayItems.iteratorAt(index); |
| 399 RefPtr<const SkPicture> newPicture = displayItem.picture(); | 398 RefPtr<const SkPicture> newPicture = static_cast<const DrawingDisplayItem&>( displayItem).picture(); |
| 400 RefPtr<const SkPicture> oldPicture = foundItem->picture(); | 399 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. | 400 // 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); | 401 foundItem->setIgnoredFromDisplayList(); |
| 403 | 402 |
| 404 if (!newPicture && !oldPicture) | 403 if (!newPicture && !oldPicture) |
| 405 return; | 404 return; |
| 406 if (newPicture && oldPicture) { | 405 if (newPicture && oldPicture) { |
| 407 switch (displayItem.underInvalidationCheckingMode()) { | 406 switch (static_cast<const DrawingDisplayItem&>(displayItem).underInvalid ationCheckingMode()) { |
| 408 case DrawingDisplayItem::CheckPicture: | 407 case DrawingDisplayItem::CheckPicture: |
| 409 if (newPicture->approximateOpCount() == oldPicture->approximateOpCou nt()) { | 408 if (newPicture->approximateOpCount() == oldPicture->approximateOpCou nt()) { |
| 410 SkDynamicMemoryWStream newPictureSerialized; | 409 SkDynamicMemoryWStream newPictureSerialized; |
| 411 newPicture->serialize(&newPictureSerialized); | 410 newPicture->serialize(&newPictureSerialized); |
| 412 SkDynamicMemoryWStream oldPictureSerialized; | 411 SkDynamicMemoryWStream oldPictureSerialized; |
| 413 oldPicture->serialize(&oldPictureSerialized); | 412 oldPicture->serialize(&oldPictureSerialized); |
| 414 | 413 |
| 415 if (newPictureSerialized.bytesWritten() == oldPictureSerialized. bytesWritten()) { | 414 if (newPictureSerialized.bytesWritten() == oldPictureSerialized. bytesWritten()) { |
| 416 RefPtr<SkData> oldData = adoptRef(oldPictureSerialized.copyT oData()); | 415 RefPtr<SkData> oldData = adoptRef(oldPictureSerialized.copyT oData()); |
| 417 RefPtr<SkData> newData = adoptRef(newPictureSerialized.copyT oData()); | 416 RefPtr<SkData> newData = adoptRef(newPictureSerialized.copyT oData()); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 448 #endif // NDEBUG | 447 #endif // NDEBUG |
| 449 | 448 |
| 450 ASSERT_NOT_REACHED(); | 449 ASSERT_NOT_REACHED(); |
| 451 } | 450 } |
| 452 | 451 |
| 453 void DisplayItemList::checkNoRemainingCachedDisplayItems() | 452 void DisplayItemList::checkNoRemainingCachedDisplayItems() |
| 454 { | 453 { |
| 455 ASSERT(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled ()); | 454 ASSERT(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled ()); |
| 456 | 455 |
| 457 for (const auto& displayItem : m_currentDisplayItems) { | 456 for (const auto& displayItem : m_currentDisplayItems) { |
| 458 if (displayItem.isGone() || !DisplayItem::isDrawingType(displayItem.type ()) || !clientCacheIsValid(displayItem.client())) | 457 if (displayItem->ignoreFromDisplayList() || !DisplayItem::isDrawingType( displayItem->type()) || !clientCacheIsValid(displayItem->client())) |
| 459 continue; | 458 continue; |
| 460 showUnderInvalidationError("May be under-invalidation: no new display it em", displayItem); | 459 showUnderInvalidationError("May be under-invalidation: no new display it em", *displayItem); |
| 461 } | 460 } |
| 462 } | 461 } |
| 463 | 462 |
| 464 #endif // ENABLE(ASSERT) | 463 #endif // ENABLE(ASSERT) |
| 465 | 464 |
| 466 #ifndef NDEBUG | 465 #ifndef NDEBUG |
| 467 | 466 |
| 468 WTF::String DisplayItemList::displayItemsAsDebugString(const DisplayItems& list) const | 467 WTF::String DisplayItemList::displayItemsAsDebugString(const DisplayItems& list) const |
| 469 { | 468 { |
| 470 StringBuilder stringBuilder; | 469 StringBuilder stringBuilder; |
| 471 size_t i = 0; | 470 size_t i = 0; |
| 472 for (auto it = list.begin(); it != list.end(); ++it, ++i) { | 471 for (auto it = list.begin(); it != list.end(); ++it, ++i) { |
| 473 DisplayItems::ItemHandle displayItem = list[i]; | 472 const DisplayItem& displayItem = *list.elementAt(i); |
| 474 if (i) | 473 if (i) |
| 475 stringBuilder.append(",\n"); | 474 stringBuilder.append(",\n"); |
| 476 if (displayItem.isGone()) { | 475 if (displayItem.ignoreFromDisplayList()) { |
| 477 stringBuilder.append("null"); | 476 stringBuilder.append("null"); |
| 478 continue; | 477 continue; |
| 479 } | 478 } |
| 480 stringBuilder.append(String::format("{index: %d, ", (int)i)); | 479 stringBuilder.append(String::format("{index: %d, ", (int)i)); |
| 481 displayItem.dumpPropertiesAsDebugString(stringBuilder); | 480 displayItem.dumpPropertiesAsDebugString(stringBuilder); |
| 482 stringBuilder.append(", cacheIsValid: "); | 481 stringBuilder.append(", cacheIsValid: "); |
| 483 stringBuilder.append(clientCacheIsValid(displayItem.client()) ? "true" : "false"); | 482 stringBuilder.append(clientCacheIsValid(displayItem.client()) ? "true" : "false"); |
| 484 stringBuilder.append('}'); | 483 stringBuilder.append('}'); |
| 485 } | 484 } |
| 486 return stringBuilder.toString(); | 485 return stringBuilder.toString(); |
| 487 } | 486 } |
| 488 | 487 |
| 489 void DisplayItemList::showDebugData() const | 488 void DisplayItemList::showDebugData() const |
| 490 { | 489 { |
| 491 WTFLogAlways("current display items: [%s]\n", displayItemsAsDebugString(m_cu rrentDisplayItems).utf8().data()); | 490 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()); | 491 WTFLogAlways("new display items: [%s]\n", displayItemsAsDebugString(m_newDis playItems).utf8().data()); |
| 493 } | 492 } |
| 494 | 493 |
| 495 #endif // ifndef NDEBUG | 494 #endif // ifndef NDEBUG |
| 496 | 495 |
| 497 void DisplayItemList::replay(GraphicsContext& context) const | 496 void DisplayItemList::replay(GraphicsContext& context) |
| 498 { | 497 { |
| 499 TRACE_EVENT0("blink,benchmark", "DisplayItemList::replay"); | 498 TRACE_EVENT0("blink,benchmark", "DisplayItemList::replay"); |
| 500 ASSERT(m_newDisplayItems.isEmpty()); | 499 ASSERT(m_newDisplayItems.empty()); |
| 501 for (auto& displayItem : m_currentDisplayItems) | 500 for (auto displayItem : m_currentDisplayItems) |
| 502 displayItem.replay(context); | 501 displayItem->replay(context); |
| 503 } | 502 } |
| 504 | 503 |
| 505 } // namespace blink | 504 } // namespace blink |
| OLD | NEW |