| Index: third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
|
| diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
|
| index fa5209e751107c4f0f9f924bae93f7da4b670292..ac49b8ada5618d180554bfaf35424a13018f422f 100644
|
| --- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
|
| +++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
|
| @@ -99,22 +99,28 @@ bool PaintController::useCachedSubsequenceIfPossible(
|
| return false;
|
| }
|
|
|
| - size_t cachedItem =
|
| - findCachedItem(DisplayItem::Id(client, DisplayItem::kSubsequence));
|
| - if (cachedItem == kNotFound) {
|
| - NOTREACHED();
|
| + SubsequenceMarkers* markers = getSubsequenceMarkers(client);
|
| + if (!markers) {
|
| return false;
|
| }
|
|
|
| // |cachedItem| will point to the first item after the subsequence or end of
|
| // the current list.
|
| ensureNewDisplayItemListInitialCapacity();
|
| - copyCachedSubsequence(cachedItem);
|
|
|
| - m_nextItemToMatch = cachedItem;
|
| - // Items before |cachedItem| have been copied so we don't need to index them.
|
| - if (cachedItem > m_nextItemToIndex)
|
| - m_nextItemToIndex = cachedItem;
|
| + size_t sizeBeforeCopy = m_newDisplayItemList.size();
|
| + copyCachedSubsequence(markers->start, markers->end);
|
| +
|
| + if (!RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) {
|
| + addCachedSubsequence(client, sizeBeforeCopy,
|
| + m_newDisplayItemList.size() - 1);
|
| + }
|
| +
|
| + m_nextItemToMatch = markers->end + 1;
|
| + // Items before |m_nextItemToMatch| have been copied so we don't need to index
|
| + // them.
|
| + if (m_nextItemToMatch > m_nextItemToIndex)
|
| + m_nextItemToIndex = m_nextItemToMatch;
|
|
|
| if (RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) {
|
| // Return false to let the painter actually paint. We will check if the new
|
| @@ -125,6 +131,40 @@ bool PaintController::useCachedSubsequenceIfPossible(
|
| return true;
|
| }
|
|
|
| +PaintController::SubsequenceMarkers* PaintController::getSubsequenceMarkers(
|
| + const DisplayItemClient& client) {
|
| + auto result = m_currentCachedSubsequences.find(&client);
|
| + if (result == m_currentCachedSubsequences.end())
|
| + return nullptr;
|
| + return &result->value;
|
| +}
|
| +
|
| +void PaintController::addCachedSubsequence(const DisplayItemClient& client,
|
| + unsigned start,
|
| + unsigned end) {
|
| + DCHECK(start <= end);
|
| + DCHECK(end < m_newDisplayItemList.size());
|
| + if (isCheckingUnderInvalidation()) {
|
| + SubsequenceMarkers* markers = getSubsequenceMarkers(client);
|
| + if (!markers) {
|
| + showSequenceUnderInvalidationError(
|
| + "under-invalidation : unexpected subsequence", client, start, end);
|
| + DCHECK(false);
|
| + }
|
| + if (markers->end - markers->start != end - start) {
|
| + showSequenceUnderInvalidationError(
|
| + "under-invalidation: new subsequence wrong length", client, start,
|
| + end);
|
| + DCHECK(false);
|
| + }
|
| + }
|
| +
|
| + DCHECK(m_newCachedSubsequences.find(&client) ==
|
| + m_newCachedSubsequences.end());
|
| +
|
| + m_newCachedSubsequences.insert(&client, SubsequenceMarkers(start, end));
|
| +}
|
| +
|
| bool PaintController::lastDisplayItemIsNoopBegin() const {
|
| if (m_newDisplayItemList.isEmpty())
|
| return false;
|
| @@ -170,31 +210,29 @@ const DisplayItem* PaintController::lastDisplayItem(unsigned offset) {
|
| return nullptr;
|
| }
|
|
|
| -void PaintController::processNewItem(DisplayItem& displayItem) {
|
| - DCHECK(!m_constructionDisabled);
|
| -
|
| #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
|
| +void PaintController::beginShouldKeepAlive(const DisplayItemClient& client) {
|
| if (!isSkippingCache()) {
|
| - if (displayItem.isCacheable()) {
|
| - // Mark the client shouldKeepAlive under this PaintController.
|
| - // The status will end after the new display items are committed.
|
| - displayItem.client().beginShouldKeepAlive(this);
|
| -
|
| - if (!m_currentSubsequenceClients.isEmpty()) {
|
| - // Mark the client shouldKeepAlive under the current subsequence.
|
| - // The status will end when the subsequence owner is invalidated or
|
| - // deleted.
|
| - displayItem.client().beginShouldKeepAlive(
|
| - m_currentSubsequenceClients.back());
|
| - }
|
| + // Mark the client shouldKeepAlive under this PaintController.
|
| + // The status will end after the new display items are committed.
|
| + client.beginShouldKeepAlive(this);
|
| +
|
| + if (!m_currentSubsequenceClients.isEmpty()) {
|
| + // Mark the client shouldKeepAlive under the current subsequence.
|
| + // The status will end when the subsequence owner is invalidated or
|
| + // deleted.
|
| + client.beginShouldKeepAlive(m_currentSubsequenceClients.back());
|
| }
|
| + }
|
| +}
|
| +#endif
|
|
|
| - if (displayItem.getType() == DisplayItem::kSubsequence) {
|
| - m_currentSubsequenceClients.push_back(&displayItem.client());
|
| - } else if (displayItem.getType() == DisplayItem::kEndSubsequence) {
|
| - CHECK(m_currentSubsequenceClients.back() == &displayItem.client());
|
| - m_currentSubsequenceClients.pop_back();
|
| - }
|
| +void PaintController::processNewItem(DisplayItem& displayItem) {
|
| + DCHECK(!m_constructionDisabled);
|
| +
|
| +#if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
|
| + if (displayItem.isCacheable()) {
|
| + beginShouldKeepAlive(displayItem.client());
|
| }
|
| #endif
|
|
|
| @@ -217,7 +255,6 @@ void PaintController::processNewItem(DisplayItem& displayItem) {
|
| const auto& beginDisplayItem =
|
| m_newDisplayItemList[m_newDisplayItemList.size() - 2];
|
| if (beginDisplayItem.isBegin() &&
|
| - beginDisplayItem.getType() != DisplayItem::kSubsequence &&
|
| !beginDisplayItem.drawsContent())
|
| DCHECK(!displayItem.isEndAndPairedWith(beginDisplayItem.getType()));
|
| }
|
| @@ -393,32 +430,29 @@ size_t PaintController::findOutOfOrderCachedItemForward(
|
| return kNotFound;
|
| }
|
|
|
| -// Copies a cached subsequence from current list to the new list. On return,
|
| -// |cachedItemIndex| points to the item after the EndSubsequence item of the
|
| -// subsequence. When paintUnderInvaldiationCheckingEnabled() we'll not actually
|
| +// Copies a cached subsequence from current list to the new list.
|
| +// When paintUnderInvaldiationCheckingEnabled() we'll not actually
|
| // copy the subsequence, but mark the begin and end of the subsequence for
|
| // under-invalidation checking.
|
| -void PaintController::copyCachedSubsequence(size_t& cachedItemIndex) {
|
| +void PaintController::copyCachedSubsequence(size_t beginIndex,
|
| + size_t endIndex) {
|
| AutoReset<size_t> subsequenceBeginIndex(
|
| &m_currentCachedSubsequenceBeginIndexInNewList,
|
| m_newDisplayItemList.size());
|
| DisplayItem* cachedItem =
|
| - &m_currentPaintArtifact.getDisplayItemList()[cachedItemIndex];
|
| - DCHECK(cachedItem->getType() == DisplayItem::kSubsequence);
|
| + &m_currentPaintArtifact.getDisplayItemList()[beginIndex];
|
|
|
| if (RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) {
|
| DCHECK(!isCheckingUnderInvalidation());
|
| - m_underInvalidationCheckingBegin = cachedItemIndex;
|
| + m_underInvalidationCheckingBegin = beginIndex;
|
| m_underInvalidationMessagePrefix =
|
| "(In cached subsequence of " + cachedItem->client().debugName() + ")";
|
| }
|
|
|
| - DisplayItem::Id endSubsequenceId(cachedItem->client(),
|
| - DisplayItem::kEndSubsequence);
|
| Vector<PaintChunk>::const_iterator cachedChunk;
|
| if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) {
|
| cachedChunk =
|
| - m_currentPaintArtifact.findChunkByDisplayItemIndex(cachedItemIndex);
|
| + m_currentPaintArtifact.findChunkByDisplayItemIndex(beginIndex);
|
| DCHECK(cachedChunk != m_currentPaintArtifact.paintChunks().end());
|
| updateCurrentPaintChunkProperties(
|
| cachedChunk->id ? &*cachedChunk->id : nullptr, cachedChunk->properties);
|
| @@ -427,40 +461,32 @@ void PaintController::copyCachedSubsequence(size_t& cachedItemIndex) {
|
| cachedChunk = m_currentPaintArtifact.paintChunks().begin();
|
| }
|
|
|
| - while (true) {
|
| + for (size_t currentIndex = beginIndex; currentIndex <= endIndex;
|
| + ++currentIndex) {
|
| + cachedItem = &m_currentPaintArtifact.getDisplayItemList()[currentIndex];
|
| DCHECK(cachedItem->hasValidClient());
|
| #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
|
| CHECK(cachedItem->client().isAlive());
|
| #endif
|
| ++m_numCachedNewItems;
|
| - bool metEndSubsequence = cachedItem->getId() == endSubsequenceId;
|
| if (!RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) {
|
| if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() &&
|
| - cachedItemIndex == cachedChunk->endIndex) {
|
| + currentIndex == cachedChunk->endIndex) {
|
| ++cachedChunk;
|
| DCHECK(cachedChunk != m_currentPaintArtifact.paintChunks().end());
|
| updateCurrentPaintChunkProperties(
|
| cachedChunk->id ? &*cachedChunk->id : nullptr,
|
| cachedChunk->properties);
|
| }
|
| - processNewItem(moveItemFromCurrentListToNewList(cachedItemIndex));
|
| + processNewItem(moveItemFromCurrentListToNewList(currentIndex));
|
| if (RuntimeEnabledFeatures::slimmingPaintV2Enabled())
|
| DCHECK((!m_newPaintChunks.lastChunk().id && !cachedChunk->id) ||
|
| m_newPaintChunks.lastChunk().matches(*cachedChunk));
|
| }
|
| -
|
| - ++cachedItemIndex;
|
| - if (metEndSubsequence)
|
| - break;
|
| -
|
| - // We should always be able to find the EndSubsequence display item.
|
| - DCHECK(cachedItemIndex <
|
| - m_currentPaintArtifact.getDisplayItemList().size());
|
| - cachedItem = &m_currentPaintArtifact.getDisplayItemList()[cachedItemIndex];
|
| }
|
|
|
| if (RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) {
|
| - m_underInvalidationCheckingEnd = cachedItemIndex;
|
| + m_underInvalidationCheckingEnd = endIndex + 1;
|
| DCHECK(isCheckingUnderInvalidation());
|
| }
|
| }
|
| @@ -492,7 +518,6 @@ void PaintController::commitNewDisplayItems(
|
| "num_non_cached_new_items",
|
| (int)m_newDisplayItemList.size() - m_numCachedNewItems);
|
| m_numCachedNewItems = 0;
|
| -
|
| // These data structures are used during painting only.
|
| DCHECK(!isSkippingCache());
|
| #if DCHECK_IS_ON()
|
| @@ -507,6 +532,16 @@ void PaintController::commitNewDisplayItems(
|
|
|
| m_currentCacheGeneration =
|
| DisplayItemClient::CacheGenerationOrInvalidationReason::next();
|
| +
|
| + m_newCachedSubsequences.swap(m_currentCachedSubsequences);
|
| + m_newCachedSubsequences.clear();
|
| + for (auto& item : m_currentCachedSubsequences) {
|
| + item.key->setDisplayItemsCached(m_currentCacheGeneration);
|
| +#if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
|
| + DisplayItemClient::endShouldKeepAliveAllClients(item.key);
|
| +#endif
|
| + }
|
| +
|
| Vector<const DisplayItemClient*> skippedCacheClients;
|
| for (const auto& item : m_newDisplayItemList) {
|
| // No reason to continue the analysis once we have a veto.
|
| @@ -566,7 +601,6 @@ void PaintController::commitNewDisplayItems(
|
| m_newDisplayItemList = DisplayItemList(0);
|
|
|
| #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
|
| - CHECK(m_currentSubsequenceClients.isEmpty());
|
| DisplayItemClient::endShouldKeepAliveAllClients(this);
|
| #endif
|
|
|
| @@ -785,6 +819,21 @@ void PaintController::showUnderInvalidationError(
|
| #endif // NDEBUG
|
| }
|
|
|
| +void PaintController::showSequenceUnderInvalidationError(
|
| + const char* reason,
|
| + const DisplayItemClient& client,
|
| + int start,
|
| + int end) {
|
| + LOG(ERROR) << m_underInvalidationMessagePrefix << " " << reason;
|
| + LOG(ERROR) << "Subsequence client: " << client.debugName();
|
| +#ifndef NDEBUG
|
| +// showDebugData();
|
| +#else
|
| + LOG(ERROR) << "Run debug build to get more details.";
|
| +#endif
|
| + LOG(ERROR) << "See http://crbug.com/619103.";
|
| +}
|
| +
|
| void PaintController::checkUnderInvalidation() {
|
| DCHECK(RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled());
|
|
|
|
|