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 |