Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Side by Side Diff: Source/platform/graphics/paint/DisplayItemList.cpp

Issue 1287863003: Avoid re-iterate out-of-order display items (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 size_t DisplayItemList::findMatchingItemFromIndex(const DisplayItem::Id& id, con st DisplayItemIndicesByClientMap& displayItemIndicesByClient, const DisplayItems & list) 142 size_t DisplayItemList::findMatchingItemFromIndex(const DisplayItem::Id& id, con st DisplayItemIndicesByClientMap& displayItemIndicesByClient, const DisplayItems & list)
143 { 143 {
144 DisplayItemIndicesByClientMap::const_iterator it = displayItemIndicesByClien t.find(id.client); 144 DisplayItemIndicesByClientMap::const_iterator it = displayItemIndicesByClien t.find(id.client);
145 if (it == displayItemIndicesByClient.end()) 145 if (it == displayItemIndicesByClient.end())
146 return kNotFound; 146 return kNotFound;
147 147
148 const Vector<size_t>& indices = it->value; 148 const Vector<size_t>& indices = it->value;
149 for (size_t index : indices) { 149 for (size_t index : indices) {
150 // TODO(pdr): elementAt is not cheap so this should be refactored (See c rbug.com/505965). 150 // TODO(pdr): elementAt is not cheap so this should be refactored (See c rbug.com/505965).
151 const DisplayItem& existingItem = list[index]; 151 const DisplayItem& existingItem = list[index];
152 ASSERT(existingItem.ignoreFromDisplayList() || existingItem.client() == id.client); 152 ASSERT(!existingItem.isValid() || existingItem.client() == id.client);
153 if (!existingItem.ignoreFromDisplayList() && id.matches(existingItem)) 153 if (existingItem.isValid() && id.matches(existingItem))
154 return index; 154 return index;
155 } 155 }
156 156
157 return kNotFound; 157 return kNotFound;
158 } 158 }
159 159
160 void DisplayItemList::addItemToIndexIfNeeded(const DisplayItem& displayItem, siz e_t index, DisplayItemIndicesByClientMap& displayItemIndicesByClient) 160 void DisplayItemList::addItemToIndexIfNeeded(const DisplayItem& displayItem, siz e_t index, DisplayItemIndicesByClientMap& displayItemIndicesByClient)
161 { 161 {
162 if (!displayItem.isCacheable()) 162 if (!displayItem.isCacheable())
163 return; 163 return;
164 164
165 DisplayItemIndicesByClientMap::iterator it = displayItemIndicesByClient.find (displayItem.client()); 165 DisplayItemIndicesByClientMap::iterator it = displayItemIndicesByClient.find (displayItem.client());
166 Vector<size_t>& indices = it == displayItemIndicesByClient.end() ? 166 Vector<size_t>& indices = it == displayItemIndicesByClient.end() ?
167 displayItemIndicesByClient.add(displayItem.client(), Vector<size_t>()).s toredValue->value : it->value; 167 displayItemIndicesByClient.add(displayItem.client(), Vector<size_t>()).s toredValue->value : it->value;
168 indices.append(index); 168 indices.append(index);
169 } 169 }
170 170
171 DisplayItems::iterator DisplayItemList::findOutOfOrderCachedItem(DisplayItems::i terator currentIt, const DisplayItem::Id& id, DisplayItemIndicesByClientMap& dis playItemIndicesByClient) 171 DisplayItems::iterator DisplayItemList::findOutOfOrderCachedItem(DisplayItems::i terator& nextItemToIndexIt, const DisplayItem::Id& id, DisplayItemIndicesByClien tMap& displayItemIndicesByClient)
172 { 172 {
173 ASSERT(clientCacheIsValid(id.client)); 173 ASSERT(clientCacheIsValid(id.client));
174 174
175 size_t foundIndex = findMatchingItemFromIndex(id, displayItemIndicesByClient , m_currentDisplayItems); 175 size_t foundIndex = findMatchingItemFromIndex(id, displayItemIndicesByClient , m_currentDisplayItems);
176 if (foundIndex != kNotFound) 176 if (foundIndex != kNotFound)
177 return m_currentDisplayItems.begin() + foundIndex; 177 return m_currentDisplayItems.begin() + foundIndex;
178 178
179 return findOutOfOrderCachedItemForward(currentIt, id, displayItemIndicesByCl ient); 179 return findOutOfOrderCachedItemForward(nextItemToIndexIt, id, displayItemInd icesByClient);
180 } 180 }
181 181
182 // Find forward for the item and index all skipped indexable items. 182 // Find forward for the item and index all skipped indexable items.
183 DisplayItems::iterator DisplayItemList::findOutOfOrderCachedItemForward(DisplayI tems::iterator currentIt, const DisplayItem::Id& id, DisplayItemIndicesByClientM ap& displayItemIndicesByClient) 183 DisplayItems::iterator DisplayItemList::findOutOfOrderCachedItemForward(DisplayI tems::iterator& nextItemToIndexIt, const DisplayItem::Id& id, DisplayItemIndices ByClientMap& displayItemIndicesByClient)
184 { 184 {
185 DisplayItems::iterator currentEnd = m_currentDisplayItems.end(); 185 DisplayItems::iterator currentEnd = m_currentDisplayItems.end();
186 for (; currentIt != currentEnd; ++currentIt) { 186 for (; nextItemToIndexIt != currentEnd; ++nextItemToIndexIt) {
187 const DisplayItem& item = *currentIt; 187 const DisplayItem& item = *nextItemToIndexIt;
188 if (!item.ignoreFromDisplayList() 188 ASSERT(item.isValid());
189 && item.isCacheable() 189 if (item.isCacheable() && clientCacheIsValid(item.client())) {
190 && m_validlyCachedClients.contains(item.client())) {
191 if (id.matches(item)) 190 if (id.matches(item))
192 return currentIt; 191 return nextItemToIndexIt++;
193 192
194 addItemToIndexIfNeeded(item, currentIt - m_currentDisplayItems.begin (), displayItemIndicesByClient); 193 addItemToIndexIfNeeded(item, nextItemToIndexIt - m_currentDisplayIte ms.begin(), displayItemIndicesByClient);
195 } 194 }
196 } 195 }
197 return currentEnd; 196 return currentEnd;
198 } 197 }
199 198
200 void DisplayItemList::copyCachedSubtree(DisplayItems::iterator& currentIt, Displ ayItems& updatedList) 199 void DisplayItemList::copyCachedSubtree(DisplayItems::iterator& currentIt, Displ ayItems& updatedList)
201 { 200 {
202 ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); 201 ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
203 ASSERT(currentIt->isBeginSubtree()); 202 ASSERT(currentIt->isBeginSubtree());
204 ASSERT(!currentIt->scope()); 203 ASSERT(!currentIt->scope());
205 DisplayItem::Id endSubtreeId(currentIt->client(), DisplayItem::beginSubtreeT ypeToEndSubtreeType(currentIt->type()), 0); 204 DisplayItem::Id endSubtreeId(currentIt->client(), DisplayItem::beginSubtreeT ypeToEndSubtreeType(currentIt->type()), 0);
206 while (true) { 205 do {
207 updatedList.appendByMoving(*currentIt, currentIt->derivedSize());
208 if (endSubtreeId.matches(updatedList.last()))
209 break;
210 ++currentIt;
211 // We should always find the EndSubtree display item. 206 // We should always find the EndSubtree display item.
212 ASSERT(currentIt != m_currentDisplayItems.end()); 207 ASSERT(currentIt != m_currentDisplayItems.end());
213 } 208 updatedList.appendByMoving(*currentIt, currentIt->derivedSize());
209 ++currentIt;
210 } while (!endSubtreeId.matches(updatedList.last()));
214 } 211 }
215 212
216 // Update the existing display items by removing invalidated entries, updating 213 // Update the existing display items by removing invalidated entries, updating
217 // repainted ones, and appending new items. 214 // repainted ones, and appending new items.
218 // - For CachedDisplayItem, copy the corresponding cached DrawingDisplayItem; 215 // - For CachedDisplayItem, copy the corresponding cached DrawingDisplayItem;
219 // - For SubtreeCachedDisplayItem, copy the cached display items between the 216 // - For SubtreeCachedDisplayItem, copy the cached display items between the
220 // corresponding BeginSubtreeDisplayItem and EndSubtreeDisplayItem (incl.); 217 // corresponding BeginSubtreeDisplayItem and EndSubtreeDisplayItem (incl.);
221 // - Otherwise, copy the new display item. 218 // - Otherwise, copy the new display item.
222 // 219 //
223 // The algorithm is O(|m_currentDisplayItems| + |m_newDisplayItems|). 220 // The algorithm is O(|m_currentDisplayItems| + |m_newDisplayItems|).
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 } 266 }
270 } 267 }
271 #endif // ENABLE(ASSERT) 268 #endif // ENABLE(ASSERT)
272 269
273 // TODO(jbroman): Consider revisiting this heuristic. 270 // TODO(jbroman): Consider revisiting this heuristic.
274 DisplayItems updatedList( 271 DisplayItems updatedList(
275 kMaximumDisplayItemSize, 272 kMaximumDisplayItemSize,
276 std::max(m_currentDisplayItems.usedCapacityInBytes(), m_newDisplayItems. usedCapacityInBytes())); 273 std::max(m_currentDisplayItems.usedCapacityInBytes(), m_newDisplayItems. usedCapacityInBytes()));
277 DisplayItems::iterator currentIt = m_currentDisplayItems.begin(); 274 DisplayItems::iterator currentIt = m_currentDisplayItems.begin();
278 DisplayItems::iterator currentEnd = m_currentDisplayItems.end(); 275 DisplayItems::iterator currentEnd = m_currentDisplayItems.end();
276 DisplayItems::iterator nextItemToIndexIt = currentIt;
279 for (DisplayItems::iterator newIt = m_newDisplayItems.begin(); newIt != m_ne wDisplayItems.end(); ++newIt) { 277 for (DisplayItems::iterator newIt = m_newDisplayItems.begin(); newIt != m_ne wDisplayItems.end(); ++newIt) {
280 const DisplayItem& newDisplayItem = *newIt; 278 const DisplayItem& newDisplayItem = *newIt;
281 const DisplayItem::Id newDisplayItemId = newDisplayItem.nonCachedId(); 279 const DisplayItem::Id newDisplayItemId = newDisplayItem.nonCachedId();
282 bool newDisplayItemHasCachedType = newDisplayItem.type() != newDisplayIt emId.type; 280 bool newDisplayItemHasCachedType = newDisplayItem.type() != newDisplayIt emId.type;
283 281
284 bool isSynchronized = currentIt != currentEnd 282 bool isSynchronized = currentIt != currentEnd && newDisplayItemId.matche s(*currentIt);
285 && !currentIt->ignoreFromDisplayList()
286 && newDisplayItemId.matches(*currentIt);
287 283
288 if (newDisplayItemHasCachedType) { 284 if (newDisplayItemHasCachedType) {
289 ASSERT(!RuntimeEnabledFeatures::slimmingPaintUnderInvalidationChecki ngEnabled()); 285 ASSERT(!RuntimeEnabledFeatures::slimmingPaintUnderInvalidationChecki ngEnabled());
290 ASSERT(newDisplayItem.isCached()); 286 ASSERT(newDisplayItem.isCached());
291 ASSERT(clientCacheIsValid(newDisplayItem.client())); 287 ASSERT(clientCacheIsValid(newDisplayItem.client()));
292 if (!isSynchronized) { 288 if (!isSynchronized) {
293 DisplayItems::iterator foundIt = findOutOfOrderCachedItem(curren tIt, newDisplayItemId, displayItemIndicesByClient); 289 // Skip indexing of copied items.
294 ASSERT(foundIt != currentIt); 290 if (currentIt - nextItemToIndexIt > 0)
291 nextItemToIndexIt = currentIt;
292 DisplayItems::iterator foundIt = findOutOfOrderCachedItem(nextIt emToIndexIt, newDisplayItemId, displayItemIndicesByClient);
295 293
296 if (foundIt == currentEnd) { 294 if (foundIt == currentEnd) {
297 #ifndef NDEBUG 295 #ifndef NDEBUG
298 showDebugData(); 296 showDebugData();
299 WTFLogAlways("%s not found in m_currentDisplayItems\n", newD isplayItem.asDebugString().utf8().data()); 297 WTFLogAlways("%s not found in m_currentDisplayItems\n", newD isplayItem.asDebugString().utf8().data());
300 #endif 298 #endif
301 ASSERT_NOT_REACHED(); 299 ASSERT_NOT_REACHED();
302 300
303 // If foundIt == currentEnd, it means that we did not find t he cached display item. This should be impossible, but may occur 301 // If foundIt == currentEnd, it means that we did not find t he cached display item. This should be impossible, but may occur
304 // if there is a bug in the system, such as under-invalidati on, incorrect cache checking or duplicate display ids. In this case, 302 // if there is a bug in the system, such as under-invalidati on, incorrect cache checking or duplicate display ids. In this case,
305 // attempt to recover rather than crashing or bailing on dis play of the rest of the display list. 303 // attempt to recover rather than crashing or bailing on dis play of the rest of the display list.
306 continue; 304 continue;
307 } 305 }
306
307 ASSERT(foundIt != currentIt); // otherwise isSynchronized should be true.
pdr. 2015/08/17 23:28:50 ASSERT(isSynchronized)?
Xianzhu 2015/08/17 23:46:59 The comment above seems confusing. Changed to:
308 currentIt = foundIt; 308 currentIt = foundIt;
309 } 309 }
310 310
311 if (newDisplayItem.isCachedDrawing()) { 311 if (newDisplayItem.isCachedDrawing()) {
312 updatedList.appendByMoving(*currentIt, currentIt->derivedSize()) ; 312 updatedList.appendByMoving(*currentIt, currentIt->derivedSize()) ;
313 ++currentIt;
313 } else { 314 } else {
314 ASSERT(newDisplayItem.isCachedSubtree()); 315 ASSERT(newDisplayItem.isCachedSubtree());
315 copyCachedSubtree(currentIt, updatedList); 316 copyCachedSubtree(currentIt, updatedList);
316 ASSERT(updatedList.last().isEndSubtree()); 317 ASSERT(updatedList.last().isEndSubtree());
317 } 318 }
318 } else { 319 } else {
319 #if ENABLE(ASSERT) 320 #if ENABLE(ASSERT)
320 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEn abled()) 321 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEn abled())
321 checkCachedDisplayItemIsUnchanged(newDisplayItem, displayItemInd icesByClient); 322 checkCachedDisplayItemIsUnchanged(newDisplayItem, displayItemInd icesByClient);
322 else 323 else
323 ASSERT(!newDisplayItem.isDrawing() || newDisplayItem.skippedCach e() || !clientCacheIsValid(newDisplayItem.client())); 324 ASSERT(!newDisplayItem.isDrawing() || newDisplayItem.skippedCach e() || !clientCacheIsValid(newDisplayItem.client()));
324 #endif // ENABLE(ASSERT) 325 #endif // ENABLE(ASSERT)
325 updatedList.appendByMoving(*newIt, newIt->derivedSize()); 326 updatedList.appendByMoving(*newIt, newIt->derivedSize());
327
328 if (isSynchronized)
329 ++currentIt;
326 } 330 }
327
328 if (isSynchronized)
329 ++currentIt;
330 } 331 }
331 332
332 #if ENABLE(ASSERT) 333 #if ENABLE(ASSERT)
333 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled()) 334 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled())
334 checkNoRemainingCachedDisplayItems(); 335 checkNoRemainingCachedDisplayItems();
335 #endif // ENABLE(ASSERT) 336 #endif // ENABLE(ASSERT)
336 337
337 m_newDisplayItems.clear(); 338 m_newDisplayItems.clear();
338 m_validlyCachedClientsDirty = true; 339 m_validlyCachedClientsDirty = true;
339 m_currentDisplayItems.swap(updatedList); 340 m_currentDisplayItems.swap(updatedList);
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 size_t index = findMatchingItemFromIndex(displayItem.nonCachedId(), displayI temIndicesByClient, m_currentDisplayItems); 434 size_t index = findMatchingItemFromIndex(displayItem.nonCachedId(), displayI temIndicesByClient, m_currentDisplayItems);
434 if (index == kNotFound) { 435 if (index == kNotFound) {
435 showUnderInvalidationError("ERROR: under-invalidation: no cached display item", displayItem); 436 showUnderInvalidationError("ERROR: under-invalidation: no cached display item", displayItem);
436 ASSERT_NOT_REACHED(); 437 ASSERT_NOT_REACHED();
437 return; 438 return;
438 } 439 }
439 440
440 DisplayItems::iterator foundItem = m_currentDisplayItems.begin() + index; 441 DisplayItems::iterator foundItem = m_currentDisplayItems.begin() + index;
441 RefPtr<const SkPicture> newPicture = static_cast<const DrawingDisplayItem&>( displayItem).picture(); 442 RefPtr<const SkPicture> newPicture = static_cast<const DrawingDisplayItem&>( displayItem).picture();
442 RefPtr<const SkPicture> oldPicture = static_cast<const DrawingDisplayItem&>( *foundItem).picture(); 443 RefPtr<const SkPicture> oldPicture = static_cast<const DrawingDisplayItem&>( *foundItem).picture();
443 // Mark the display item as ignored so that we can check if there are any re maining cached display items after merging. 444 // Invalidate the display item so that we can check if there are any remaini ng cached display items after merging.
444 foundItem->setIgnoredFromDisplayList(); 445 foundItem->invalidate();
445 446
446 if (!newPicture && !oldPicture) 447 if (!newPicture && !oldPicture)
447 return; 448 return;
448 if (newPicture && oldPicture) { 449 if (newPicture && oldPicture) {
449 switch (static_cast<const DrawingDisplayItem&>(displayItem).underInvalid ationCheckingMode()) { 450 switch (static_cast<const DrawingDisplayItem&>(displayItem).underInvalid ationCheckingMode()) {
450 case DrawingDisplayItem::CheckPicture: 451 case DrawingDisplayItem::CheckPicture:
451 if (newPicture->approximateOpCount() == oldPicture->approximateOpCou nt()) { 452 if (newPicture->approximateOpCount() == oldPicture->approximateOpCou nt()) {
452 SkDynamicMemoryWStream newPictureSerialized; 453 SkDynamicMemoryWStream newPictureSerialized;
453 newPicture->serialize(&newPictureSerialized); 454 newPicture->serialize(&newPictureSerialized);
454 SkDynamicMemoryWStream oldPictureSerialized; 455 SkDynamicMemoryWStream oldPictureSerialized;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 #endif // NDEBUG 491 #endif // NDEBUG
491 492
492 ASSERT_NOT_REACHED(); 493 ASSERT_NOT_REACHED();
493 } 494 }
494 495
495 void DisplayItemList::checkNoRemainingCachedDisplayItems() 496 void DisplayItemList::checkNoRemainingCachedDisplayItems()
496 { 497 {
497 ASSERT(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled ()); 498 ASSERT(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled ());
498 499
499 for (const auto& displayItem : m_currentDisplayItems) { 500 for (const auto& displayItem : m_currentDisplayItems) {
500 if (displayItem.ignoreFromDisplayList() || !displayItem.isDrawing() || ! clientCacheIsValid(displayItem.client())) 501 if (!displayItem.isValid() || !displayItem.isDrawing() || !clientCacheIs Valid(displayItem.client()))
501 continue; 502 continue;
502 showUnderInvalidationError("May be under-invalidation: no new display it em", displayItem); 503 showUnderInvalidationError("May be under-invalidation: no new display it em", displayItem);
503 } 504 }
504 } 505 }
505 506
506 #endif // ENABLE(ASSERT) 507 #endif // ENABLE(ASSERT)
507 508
508 #ifndef NDEBUG 509 #ifndef NDEBUG
509 510
510 WTF::String DisplayItemList::displayItemsAsDebugString(const DisplayItems& list) const 511 WTF::String DisplayItemList::displayItemsAsDebugString(const DisplayItems& list) const
511 { 512 {
512 StringBuilder stringBuilder; 513 StringBuilder stringBuilder;
513 size_t i = 0; 514 size_t i = 0;
514 for (auto it = list.begin(); it != list.end(); ++it, ++i) { 515 for (auto it = list.begin(); it != list.end(); ++it, ++i) {
515 const DisplayItem& displayItem = *it; 516 const DisplayItem& displayItem = *it;
516 if (i) 517 if (i)
517 stringBuilder.append(",\n"); 518 stringBuilder.append(",\n");
518 if (displayItem.ignoreFromDisplayList()) { 519 if (!displayItem.isValid()) {
519 stringBuilder.append("null"); 520 stringBuilder.append("null");
520 continue; 521 continue;
521 } 522 }
522 stringBuilder.append(String::format("{index: %d, ", (int)i)); 523 stringBuilder.append(String::format("{index: %d, ", (int)i));
523 displayItem.dumpPropertiesAsDebugString(stringBuilder); 524 displayItem.dumpPropertiesAsDebugString(stringBuilder);
524 stringBuilder.append(", cacheIsValid: "); 525 stringBuilder.append(", cacheIsValid: ");
525 stringBuilder.append(clientCacheIsValid(displayItem.client()) ? "true" : "false"); 526 stringBuilder.append(clientCacheIsValid(displayItem.client()) ? "true" : "false");
526 stringBuilder.append('}'); 527 stringBuilder.append('}');
527 } 528 }
528 return stringBuilder.toString(); 529 return stringBuilder.toString();
529 } 530 }
530 531
531 void DisplayItemList::showDebugData() const 532 void DisplayItemList::showDebugData() const
532 { 533 {
533 WTFLogAlways("current display items: [%s]\n", displayItemsAsDebugString(m_cu rrentDisplayItems).utf8().data()); 534 WTFLogAlways("current display items: [%s]\n", displayItemsAsDebugString(m_cu rrentDisplayItems).utf8().data());
534 WTFLogAlways("new display items: [%s]\n", displayItemsAsDebugString(m_newDis playItems).utf8().data()); 535 WTFLogAlways("new display items: [%s]\n", displayItemsAsDebugString(m_newDis playItems).utf8().data());
535 } 536 }
536 537
537 #endif // ifndef NDEBUG 538 #endif // ifndef NDEBUG
538 539
539 void DisplayItemList::replay(GraphicsContext& context) 540 void DisplayItemList::replay(GraphicsContext& context)
540 { 541 {
541 TRACE_EVENT0("blink,benchmark", "DisplayItemList::replay"); 542 TRACE_EVENT0("blink,benchmark", "DisplayItemList::replay");
542 ASSERT(m_newDisplayItems.isEmpty()); 543 ASSERT(m_newDisplayItems.isEmpty());
543 for (DisplayItem& displayItem : m_currentDisplayItems) 544 for (DisplayItem& displayItem : m_currentDisplayItems)
544 displayItem.replay(context); 545 displayItem.replay(context);
545 } 546 }
546 547
547 } // namespace blink 548 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698