DisplayItemList::iterator PaintController::findOutOfOrderCachedItem(const DisplayItem::Id& id, OutOfOrderIndexContext& context) { ASSERT(clientCacheIsValid(id.client)); size_t foundIndex = findMatchingItemFromIndex(id, context.displayItemIndicesByClient, m_currentPaintArtifact.displayItemList()); if (foundIndex != kNotFound) return m_currentPaintArtifact.displayItemList().begin() + foundIndex; return findOutOfOrderCachedItemForward(id, context); }
DisplayItems::iterator DisplayItemList::findOutOfOrderCachedItem(DisplayItems::iterator currentIt, const DisplayItem::Id& id, OutOfOrderIndexContext& context) { ASSERT(clientCacheIsValid(id.client)); // Skip indexing of copied items. if (currentIt - context.nextItemToIndex > 0) context.nextItemToIndex = currentIt; size_t foundIndex = findMatchingItemFromIndex(id, context.displayItemIndicesByClient, m_currentDisplayItems); if (foundIndex != kNotFound) return m_currentDisplayItems.begin() + foundIndex; return findOutOfOrderCachedItemForward(id, context); }
void PaintController::processNewItem(DisplayItem& displayItem) { ASSERT(!m_constructionDisabled); ASSERT(!skippingCache() || !displayItem.isCached()); if (displayItem.isCached()) ++m_numCachedNewItems; #if ENABLE(ASSERT) // Verify noop begin/end pairs have been removed. if (m_newDisplayItemList.size() >= 2 && displayItem.isEnd()) { const auto& beginDisplayItem = m_newDisplayItemList[m_newDisplayItemList.size() - 2]; if (beginDisplayItem.isBegin() && beginDisplayItem.type() != DisplayItem::Subsequence && !beginDisplayItem.drawsContent()) ASSERT(!displayItem.isEndAndPairedWith(beginDisplayItem.type())); } #endif if (!m_scopeStack.isEmpty()) displayItem.setScope(m_scopeStack.last()); #if ENABLE(ASSERT) size_t index = findMatchingItemFromIndex(displayItem.nonCachedId(), m_newDisplayItemIndicesByClient, m_newDisplayItemList); if (index != kNotFound) { #ifndef NDEBUG showDebugData(); WTFLogAlways("DisplayItem %s has duplicated id with previous %s (index=%d)\n", displayItem.asDebugString().utf8().data(), m_newDisplayItemList[index].asDebugString().utf8().data(), static_cast<int>(index)); #endif ASSERT_NOT_REACHED(); } addItemToIndexIfNeeded(displayItem, m_newDisplayItemList.size() - 1, m_newDisplayItemIndicesByClient); #endif // ENABLE(ASSERT) if (skippingCache()) displayItem.setSkippedCache(); if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) m_newPaintChunks.incrementDisplayItemIndex(); }
void DisplayItemList::checkCachedDisplayItemIsUnchanged(const DisplayItem& displayItem, DisplayItemIndicesByClientMap& displayItemIndicesByClient) { ASSERT(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled()); if (!displayItem.isDrawing() || displayItem.skippedCache() || !clientCacheIsValid(displayItem.client())) return; // If checking under-invalidation, we always generate new display item even if the client is not invalidated. // Checks if the new picture is the same as the cached old picture. If the new picture is different but // the client is not invalidated, issue error about under-invalidation. size_t index = findMatchingItemFromIndex(displayItem.nonCachedId(), displayItemIndicesByClient, m_currentDisplayItems); if (index == kNotFound) { showUnderInvalidationError("ERROR: under-invalidation: no cached display item", displayItem); ASSERT_NOT_REACHED(); return; } DisplayItems::iterator foundItem = m_currentDisplayItems.begin() + index; RefPtr<const SkPicture> newPicture = static_cast<const DrawingDisplayItem&>(displayItem).picture(); RefPtr<const SkPicture> oldPicture = static_cast<const DrawingDisplayItem&>(*foundItem).picture(); // Invalidate the display item so that we can check if there are any remaining cached display items after merging. foundItem->clearClientForUnderInvalidationChecking(); if (!newPicture && !oldPicture) return; if (newPicture && oldPicture) { switch (static_cast<const DrawingDisplayItem&>(displayItem).underInvalidationCheckingMode()) { case DrawingDisplayItem::CheckPicture: if (newPicture->approximateOpCount() == oldPicture->approximateOpCount()) { SkDynamicMemoryWStream newPictureSerialized; newPicture->serialize(&newPictureSerialized); SkDynamicMemoryWStream oldPictureSerialized; oldPicture->serialize(&oldPictureSerialized); if (newPictureSerialized.bytesWritten() == oldPictureSerialized.bytesWritten()) { RefPtr<SkData> oldData = adoptRef(oldPictureSerialized.copyToData()); RefPtr<SkData> newData = adoptRef(newPictureSerialized.copyToData()); if (oldData->equals(newData.get())) return; } } break; case DrawingDisplayItem::CheckBitmap: if (newPicture->cullRect() == oldPicture->cullRect()) { SkBitmap bitmap; SkRect rect = newPicture->cullRect(); bitmap.allocPixels(SkImageInfo::MakeN32Premul(rect.width(), rect.height())); SkCanvas canvas(bitmap); canvas.translate(-rect.x(), -rect.y()); canvas.drawPicture(oldPicture.get()); SkPaint diffPaint; diffPaint.setXfermodeMode(SkXfermode::kDifference_Mode); canvas.drawPicture(newPicture.get(), nullptr, &diffPaint); if (bitmapIsAllZero(bitmap)) // Contents are the same. return; } default: ASSERT_NOT_REACHED(); } } showUnderInvalidationError("ERROR: under-invalidation: display item changed", displayItem); #ifndef NDEBUG String oldPictureDebugString = oldPicture ? pictureAsDebugString(oldPicture.get()) : "None"; String newPictureDebugString = newPicture ? pictureAsDebugString(newPicture.get()) : "None"; WTFLogAlways("old picture:\n%s\n", oldPictureDebugString.utf8().data()); WTFLogAlways("new picture:\n%s\n", newPictureDebugString.utf8().data()); #endif // NDEBUG ASSERT_NOT_REACHED(); }