Chromium Code Reviews| Index: third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp |
| diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp |
| index a6ab798f344de8be6f12f48c5959530b344d7126..ae0c2193014109c4688b262167a6149a6d3902b1 100644 |
| --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp |
| +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp |
| @@ -7,9 +7,12 @@ |
| #include "cc/layers/content_layer_client.h" |
| #include "cc/layers/layer.h" |
| #include "cc/layers/picture_layer.h" |
| +#include "cc/playback/compositing_display_item.h" |
| #include "cc/playback/display_item_list.h" |
| #include "cc/playback/display_item_list_settings.h" |
| #include "cc/playback/drawing_display_item.h" |
| +#include "cc/playback/filter_display_item.h" |
| +#include "cc/playback/float_clip_display_item.h" |
| #include "cc/playback/transform_display_item.h" |
| #include "cc/trees/clip_node.h" |
| #include "cc/trees/effect_node.h" |
| @@ -22,7 +25,9 @@ |
| #include "platform/graphics/paint/DisplayItem.h" |
| #include "platform/graphics/paint/DrawingDisplayItem.h" |
| #include "platform/graphics/paint/ForeignLayerDisplayItem.h" |
| +#include "platform/graphics/paint/GeometryMapper.h" |
| #include "platform/graphics/paint/PaintArtifact.h" |
| +#include "platform/graphics/paint/PropertyTreeState.h" |
| #include "platform/graphics/paint/RasterInvalidationTracking.h" |
| #include "platform/graphics/paint/ScrollPaintPropertyNode.h" |
| #include "platform/graphics/paint/TransformPaintPropertyNode.h" |
| @@ -236,31 +241,6 @@ static void appendDisplayItemToCcDisplayItemList(const DisplayItem& displayItem, |
| } |
| } |
| -static scoped_refptr<cc::DisplayItemList> recordPaintChunk( |
| - const PaintArtifact& artifact, |
| - const PaintChunk& chunk, |
| - const gfx::Rect& combinedBounds) { |
| - cc::DisplayItemListSettings settings; |
| - scoped_refptr<cc::DisplayItemList> list = |
| - cc::DisplayItemList::Create(settings); |
| - |
| - gfx::Transform translation; |
| - translation.Translate(-combinedBounds.x(), -combinedBounds.y()); |
| - // Passing combinedBounds as the visual rect for the begin/end transform item |
| - // would normally be the sensible thing to do, but see comment above re: |
| - // visual rects for drawing items and further rework in flight. |
| - list->CreateAndAppendPairedBeginItem<cc::TransformDisplayItem>(translation); |
| - |
| - const DisplayItemList& displayItems = artifact.getDisplayItemList(); |
| - for (const auto& displayItem : displayItems.itemsInPaintChunk(chunk)) |
| - appendDisplayItemToCcDisplayItemList(displayItem, list.get()); |
| - |
| - list->CreateAndAppendPairedEndItem<cc::EndTransformDisplayItem>(); |
| - |
| - list->Finalize(); |
| - return list; |
| -} |
| - |
| scoped_refptr<cc::Layer> foreignLayerForPaintChunk( |
| const PaintArtifact& paintArtifact, |
| const PaintChunk& paintChunk, |
| @@ -290,8 +270,221 @@ constexpr int kRealRootNodeId = 0; |
| constexpr int kSecondaryRootNodeId = 1; |
| constexpr int kPropertyTreeSequenceNumber = 1; |
| +enum EndDisplayItemType { EndTransform, EndClip, EndEffect }; |
| + |
| +// Applies the clips between |localState| and |ancestorState| into a single |
| +// combined cc::FloatClipDisplayItem on |ccList|. |
| +static void applyClipsBetweenStates(const PropertyTreeState& localState, |
| + const PropertyTreeState& ancestorState, |
| + cc::DisplayItemList& ccList, |
| + Vector<EndDisplayItemType>& endDisplayItems, |
| + GeometryMapper& geometryMapper) { |
| + DCHECK(localState.transform() == ancestorState.transform()); |
| +#ifdef DCHECK_IS_ON |
| + const TransformPaintPropertyNode* transformNode = |
| + localState.clip()->localTransformSpace(); |
| + if (transformNode != ancestorState.transform()) { |
| + bool success = false; |
| + const TransformationMatrix& localToAncestorMatrix = |
| + geometryMapper.localToAncestorMatrix(transformNode, ancestorState, |
| + success); |
| + DCHECK(success); |
| + // Clips are only in descendant spaces that are transformed by one |
| + // or more scrolls. |
| + DCHECK(localToAncestorMatrix.isIdentityOrTranslation()); |
| + } |
| +#endif |
| + |
| + FloatRect combinedClip; |
| + bool success = false; |
| + // TODO(chrishtr) :get rid of infiniteIntRect here. |
| + combinedClip = geometryMapper.localToVisualRectInAncestorSpace( |
| + FloatRect(LayoutRect::infiniteIntRect()), localState, ancestorState, |
| + success); |
| + |
| + DCHECK(success); |
| + |
| + ccList.CreateAndAppendPairedBeginItem<cc::FloatClipDisplayItem>( |
| + gfx::RectF(combinedClip)); |
| + endDisplayItems.push_back(EndClip); |
| +} |
| + |
| +static void recordPairedBeginDisplayItems( |
| + const Vector<PropertyTreeState>& pairedStates, |
| + const PropertyTreeState& pendingLayerState, |
| + cc::DisplayItemList& ccList, |
| + Vector<EndDisplayItemType>& endDisplayItems, |
| + GeometryMapper& geometryMapper) { |
| + PropertyTreeState mappedClipDestinationSpace = pendingLayerState; |
| + PropertyTreeState clipSpace = pendingLayerState; |
| + bool hasClip = false; |
| + |
| + for (Vector<PropertyTreeState>::const_reverse_iterator pairedState = |
| + pairedStates.rbegin(); |
| + pairedState != pairedStates.rend(); ++pairedState) { |
| + switch (pairedState->innermostNode()) { |
| + case PropertyTreeState::Transform: { |
| + if (hasClip) { |
| + applyClipsBetweenStates(clipSpace, mappedClipDestinationSpace, ccList, |
| + endDisplayItems, geometryMapper); |
| + hasClip = false; |
| + } |
| + mappedClipDestinationSpace = *pairedState; |
| + clipSpace = *pairedState; |
| + |
| + TransformationMatrix matrix = pairedState->transform()->matrix(); |
| + matrix.applyTransformOrigin(pairedState->transform()->origin()); |
| + |
| + gfx::Transform transform(gfx::Transform::kSkipInitialization); |
| + transform.matrix() = TransformationMatrix::toSkMatrix44(matrix); |
| + |
| + ccList.CreateAndAppendPairedBeginItem<cc::TransformDisplayItem>( |
| + transform); |
| + endDisplayItems.push_back(EndTransform); |
| + break; |
| + } |
| + case PropertyTreeState::Clip: { |
| + // Clips are handled in |applyClips| when ending the iterator, or |
| + // transitioning between transform spaces. Here we store off the |
| + // PropertyTreeState of the first found clip, under the transform of |
| + // pairedState->transform(). All subsequent clips before applying the |
| + // transform will be applied in applyClips. |
| + clipSpace = *pairedState; |
| + hasClip = true; |
| +#ifdef DCHECK_IS_ON |
| + if (pairedState->clip()->localTransformSpace() != |
| + pairedState->transform()) { |
| + const TransformationMatrix& localTransformMatrix = |
| + pairedState->effect()->localTransformSpace()->matrix(); |
| + // Clips are only in descendant spaces that are transformed by scroll. |
| + DCHECK(localTransformMatrix.isIdentityOrTranslation()); |
| + } |
| +#endif |
| + break; |
| + } |
| + case PropertyTreeState::Effect: { |
| + // TODO(chrishtr): skip effect and/or compositing display items if |
| + // not necessary. |
| + |
| + FloatRect clipRect = |
| + pairedState->effect()->outputClip()->clipRect().rect(); |
| + // TODO(chrishtr): specify origin of the filter. |
| + FloatPoint filterOrigin; |
| + if (pairedState->effect()->localTransformSpace() != |
| + pairedState->transform()) { |
| + bool success = false; |
| + const TransformPaintPropertyNode* transformNode = |
| + pairedState->effect()->localTransformSpace(); |
| + const TransformationMatrix& localToAncestorMatrix = |
| + geometryMapper.localToAncestorMatrix(transformNode, *pairedState, |
| + success); |
| + DCHECK(success); |
| + // Effects are only in descendant spaces that are transformed by one |
| + // or more scrolls. |
| + DCHECK(localToAncestorMatrix.isIdentityOrTranslation()); |
| + |
| + clipRect = localToAncestorMatrix.mapRect(clipRect); |
| + filterOrigin = localToAncestorMatrix.mapPoint(filterOrigin); |
| + } |
| + |
| + const bool kLcdTextRequiresOpaqueLayer = true; |
| + ccList.CreateAndAppendPairedBeginItem<cc::CompositingDisplayItem>( |
|
chrishtr
2016/12/24 20:56:59
Switched these in order. Old one was wrong.
|
| + static_cast<uint8_t>( |
| + gfx::ToFlooredInt(255 * pairedState->effect()->opacity())), |
| + pairedState->effect()->blendMode(), |
| + // TODO(chrishtr): compute bounds as necessary. |
| + nullptr, nullptr, kLcdTextRequiresOpaqueLayer); |
| + |
| + ccList.CreateAndAppendPairedBeginItem<cc::FilterDisplayItem>( |
| + pairedState->effect()->filter().asCcFilterOperations(), |
| + clipRect, |
| + gfx::PointF(filterOrigin.x(), filterOrigin.y())); |
| + |
| + endDisplayItems.push_back(EndEffect); |
| + break; |
| + } |
| + case PropertyTreeState::None: |
| + break; |
| + } |
| + } |
| + |
| + if (hasClip) { |
| + applyClipsBetweenStates(clipSpace, mappedClipDestinationSpace, ccList, |
| + endDisplayItems, geometryMapper); |
| + } |
| +} |
| + |
| +static void recordPairedEndDisplayItems( |
| + const Vector<EndDisplayItemType>& endDisplayItemTypes, |
| + cc::DisplayItemList* ccList) { |
| + for (Vector<EndDisplayItemType>::const_reverse_iterator endType = |
| + endDisplayItemTypes.rbegin(); |
| + endType != endDisplayItemTypes.rend(); ++endType) { |
| + switch (*endType) { |
| + case EndTransform: |
| + ccList->CreateAndAppendPairedEndItem<cc::EndTransformDisplayItem>(); |
| + break; |
| + case EndClip: |
| + ccList->CreateAndAppendPairedEndItem<cc::EndFloatClipDisplayItem>(); |
| + break; |
| + case EndEffect: |
| + ccList->CreateAndAppendPairedEndItem<cc::EndFilterDisplayItem>(); |
| + ccList->CreateAndAppendPairedEndItem<cc::EndCompositingDisplayItem>(); |
| + break; |
| + } |
| + } |
| +} |
| + |
| } // namespace |
| +scoped_refptr<cc::DisplayItemList> PaintArtifactCompositor::recordPendingLayer( |
| + const PaintArtifact& artifact, |
| + const PendingLayer& pendingLayer, |
| + const gfx::Rect& combinedBounds, |
| + GeometryMapper& geometryMapper) { |
| + cc::DisplayItemListSettings settings; |
| + scoped_refptr<cc::DisplayItemList> ccList = |
| + cc::DisplayItemList::Create(settings); |
| + |
| + gfx::Transform translation; |
| + translation.Translate(-combinedBounds.x(), -combinedBounds.y()); |
| + // Passing combinedBounds as the visual rect for the begin/end transform item |
| + // would normally be the sensible thing to do, but see comment above re: |
| + // visual rects for drawing items and further rework in flight. |
| + ccList->CreateAndAppendPairedBeginItem<cc::TransformDisplayItem>(translation); |
| + |
| + const DisplayItemList& displayItems = artifact.getDisplayItemList(); |
| + for (const auto& paintChunk : pendingLayer.paintChunks) { |
| + const PropertyTreeState* state = &paintChunk->properties.propertyTreeState; |
| + PropertyTreeStateIterator iterator(*state); |
| + Vector<PropertyTreeState> pairedStates; |
| + for (; state && *state != pendingLayer.propertyTreeState; |
| + state = iterator.next()) { |
| + if (state->innermostNode() != PropertyTreeState::None) |
| + pairedStates.push_back(*state); |
| + } |
| + |
| + // TODO(chrishtr): we can avoid some extra paired display items if |
| + // multiple PaintChunks share them. We can also collapse clips between |
| + // transforms into single clips in the same way that PaintLayerClipper does. |
| + Vector<EndDisplayItemType> endDisplayItems; |
| + |
| + recordPairedBeginDisplayItems(pairedStates, pendingLayer.propertyTreeState, |
| + *ccList.get(), endDisplayItems, |
| + geometryMapper); |
| + |
| + for (const auto& displayItem : displayItems.itemsInPaintChunk(*paintChunk)) |
| + appendDisplayItemToCcDisplayItemList(displayItem, ccList.get()); |
| + |
| + recordPairedEndDisplayItems(endDisplayItems, ccList.get()); |
| + } |
| + |
| + ccList->CreateAndAppendPairedEndItem<cc::EndTransformDisplayItem>(); |
| + |
| + ccList->Finalize(); |
| + return ccList; |
| +} |
| + |
| std::unique_ptr<PaintArtifactCompositor::ContentLayerClientImpl> |
| PaintArtifactCompositor::clientForPaintChunk( |
| const PaintChunk& paintChunk, |
| @@ -310,61 +503,83 @@ PaintArtifactCompositor::clientForPaintChunk( |
| : paintArtifact.getDisplayItemList()[paintChunk.beginIndex].getId())); |
| } |
| -scoped_refptr<cc::Layer> PaintArtifactCompositor::layerForPaintChunk( |
| +scoped_refptr<cc::Layer> |
| +PaintArtifactCompositor::compositedLayerForPendingLayer( |
| const PaintArtifact& paintArtifact, |
| - const PaintChunk& paintChunk, |
| + const PendingLayer& pendingLayer, |
| gfx::Vector2dF& layerOffset, |
| Vector<std::unique_ptr<ContentLayerClientImpl>>& newContentLayerClients, |
| - RasterInvalidationTracking* tracking, |
| - bool storeDebugInfo) { |
| - DCHECK(paintChunk.size()); |
| + RasterInvalidationTrackingMap<const PaintChunk>* trackingMap, |
| + bool storeDebugInfo, |
| + GeometryMapper& geometryMapper) { |
| + DCHECK(pendingLayer.paintChunks.size()); |
| + const PaintChunk& firstPaintChunk = *pendingLayer.paintChunks[0]; |
| + DCHECK(firstPaintChunk.size()); |
| +#if DCHECK_IS_ON |
| + for (const auto& paintChunk : pendingLayer.paintChunks) { |
| + DCHECK(paintChunk.properties == firstPaintChunk.properties); |
| + } |
| +#endif |
| // If the paint chunk is a foreign layer, just return that layer. |
| - if (scoped_refptr<cc::Layer> foreignLayer = |
| - foreignLayerForPaintChunk(paintArtifact, paintChunk, layerOffset)) |
| + if (scoped_refptr<cc::Layer> foreignLayer = foreignLayerForPaintChunk( |
| + paintArtifact, firstPaintChunk, layerOffset)) { |
| + DCHECK(pendingLayer.paintChunks.size() == 1); |
| return foreignLayer; |
| + } |
| // The common case: create or reuse a PictureLayer for painted content. |
| std::unique_ptr<ContentLayerClientImpl> contentLayerClient = |
| - clientForPaintChunk(paintChunk, paintArtifact); |
| + clientForPaintChunk(firstPaintChunk, paintArtifact); |
| + |
| + gfx::Rect ccCombinedBounds(enclosingIntRect(pendingLayer.bounds)); |
| - gfx::Rect combinedBounds = enclosingIntRect(paintChunk.bounds); |
| - scoped_refptr<cc::DisplayItemList> displayList = |
| - recordPaintChunk(paintArtifact, paintChunk, combinedBounds); |
| + scoped_refptr<cc::DisplayItemList> displayList = recordPendingLayer( |
| + paintArtifact, pendingLayer, ccCombinedBounds, geometryMapper); |
| contentLayerClient->SetDisplayList(std::move(displayList)); |
| - contentLayerClient->SetPaintableRegion(gfx::Rect(combinedBounds.size())); |
| + contentLayerClient->SetPaintableRegion(gfx::Rect(ccCombinedBounds.size())); |
| + |
| + layerOffset = ccCombinedBounds.OffsetFromOrigin(); |
| - layerOffset = combinedBounds.OffsetFromOrigin(); |
| scoped_refptr<cc::PictureLayer> ccPictureLayer = |
| contentLayerClient->ccPictureLayer(); |
| - ccPictureLayer->SetBounds(combinedBounds.size()); |
| + ccPictureLayer->SetBounds(ccCombinedBounds.size()); |
| ccPictureLayer->SetIsDrawable(true); |
| - if (paintChunk.knownToBeOpaque) |
| - ccPictureLayer->SetContentsOpaque(true); |
| - DCHECK(!tracking || |
| - tracking->trackedRasterInvalidations.size() == |
| - paintChunk.rasterInvalidationRects.size()); |
| - |
| + ccPictureLayer->SetContentsOpaque(pendingLayer.knownToBeOpaque); |
| contentLayerClient->clearPaintChunkDebugData(); |
| - if (storeDebugInfo) { |
| - contentLayerClient->addPaintChunkDebugData( |
| - paintArtifact.getDisplayItemList().subsequenceAsJSON( |
| - paintChunk.beginIndex, paintChunk.endIndex, |
| - DisplayItemList::SkipNonDrawings | |
| - DisplayItemList::ShownOnlyDisplayItemTypes)); |
| - } |
| - |
| - for (unsigned index = 0; index < paintChunk.rasterInvalidationRects.size(); |
| - ++index) { |
| - IntRect rect(enclosingIntRect(paintChunk.rasterInvalidationRects[index])); |
| - gfx::Rect ccInvalidationRect(rect.x(), rect.y(), std::max(0, rect.width()), |
| - std::max(0, rect.height())); |
| - // Raster paintChunk.rasterInvalidationRects is in the space of the |
| - // containing transform node, so need to subtract off the layer offset. |
| - ccInvalidationRect.Offset(-combinedBounds.OffsetFromOrigin()); |
| - contentLayerClient->setNeedsDisplayRect( |
| - ccInvalidationRect, |
| - tracking ? &tracking->trackedRasterInvalidations[index] : nullptr); |
| + |
| + for (const auto& paintChunk : pendingLayer.paintChunks) { |
| + RasterInvalidationTracking* rasterTracking = |
| + trackingMap ? trackingMap->find(paintChunk) : nullptr; |
| + DCHECK(!rasterTracking || |
| + rasterTracking->trackedRasterInvalidations.size() == |
| + paintChunk->rasterInvalidationRects.size()); |
| + |
| + if (storeDebugInfo) { |
| + contentLayerClient->addPaintChunkDebugData( |
| + paintArtifact.getDisplayItemList().subsequenceAsJSON( |
| + paintChunk->beginIndex, paintChunk->endIndex, |
| + DisplayItemList::SkipNonDrawings | |
| + DisplayItemList::ShownOnlyDisplayItemTypes)); |
| + } |
| + |
| + for (unsigned index = 0; index < paintChunk->rasterInvalidationRects.size(); |
| + ++index) { |
| + IntRect rect( |
| + enclosingIntRect(paintChunk->rasterInvalidationRects[index])); |
| + gfx::Rect ccInvalidationRect(rect.x(), rect.y(), |
| + std::max(0, rect.width()), |
| + std::max(0, rect.height())); |
| + if (ccInvalidationRect.IsEmpty()) |
| + continue; |
| + // Raster paintChunk.rasterInvalidationRects is in the space of the |
| + // containing transform node, so need to subtract off the layer offset. |
| + ccInvalidationRect.Offset(-ccCombinedBounds.OffsetFromOrigin()); |
| + contentLayerClient->setNeedsDisplayRect( |
| + ccInvalidationRect, |
| + rasterTracking ? &rasterTracking->trackedRasterInvalidations[index] |
| + : nullptr); |
| + } |
| } |
| newContentLayerClients.append(std::move(contentLayerClient)); |
| @@ -677,6 +892,8 @@ unsigned depth(const EffectPaintPropertyNode* node) { |
| return result; |
| } |
| +// TODO(chrishtr): templatize this to avoid duplication of |
| +// GeometryMapper::leastCommonAncestor. |
| const EffectPaintPropertyNode* lowestCommonAncestor( |
| const EffectPaintPropertyNode* nodeA, |
| const EffectPaintPropertyNode* nodeB) { |
| @@ -791,10 +1008,108 @@ void PropertyTreeManager::buildEffectNodesRecursively( |
| } // namespace |
| +bool PaintArtifactCompositor::canMergeInto( |
| + const PaintArtifact& paintArtifact, |
| + const PaintChunk& newChunk, |
| + const PendingLayer& candidatePendingLayer) { |
| + const PaintChunk& pendingLayerFirstChunk = *candidatePendingLayer.paintChunks[0]; |
| + if (paintArtifact.getDisplayItemList()[newChunk.beginIndex].isForeignLayer()) |
| + return false; |
| + |
| + if (paintArtifact |
| + .getDisplayItemList()[pendingLayerFirstChunk.beginIndex] |
| + .isForeignLayer()) |
| + return false; |
| + |
| + if (newChunk.properties.backfaceHidden != pendingLayerFirstChunk.properties.backfaceHidden) |
|
chrishtr
2016/12/24 20:56:59
Added this code to not merge with backface visibil
|
| + return false; |
| + |
| + DCHECK(candidatePendingLayer.paintChunks.size() >= 1); |
| + PropertyTreeStateIterator iterator(newChunk.properties.propertyTreeState); |
| + for (const PropertyTreeState* currentState = |
| + &newChunk.properties.propertyTreeState; |
| + currentState; currentState = iterator.next()) { |
| + if (currentState->hasDirectCompositingReasons()) |
| + return false; |
| + if (*currentState == candidatePendingLayer.propertyTreeState) |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +bool PaintArtifactCompositor::mightOverlap( |
| + const PaintChunk& paintChunk, |
| + const PendingLayer& candidatePendingLayer, |
| + GeometryMapper& geometryMapper) { |
| + // TODO(chrishtr): implement |
| + return true; |
| +} |
| + |
| +PaintArtifactCompositor::PendingLayer::PendingLayer( |
| + const PaintChunk& firstPaintChunk) |
| + : bounds(firstPaintChunk.bounds), |
| + knownToBeOpaque(firstPaintChunk.knownToBeOpaque), |
| + backfaceHidden(firstPaintChunk.properties.backfaceHidden), |
| + propertyTreeState(firstPaintChunk.properties.propertyTreeState) { |
| + paintChunks.append(&firstPaintChunk); |
| +} |
| + |
| +void PaintArtifactCompositor::PendingLayer::add( |
| + const PaintChunk& paintChunk, |
| + GeometryMapper* geometryMapper) { |
| + DCHECK(paintChunk.properties.backfaceHidden == backfaceHidden); |
| + paintChunks.append(&paintChunk); |
| + FloatRect mappedBounds = paintChunk.bounds; |
| + if (geometryMapper) { |
| + bool success = false; |
| + mappedBounds = geometryMapper->localToAncestorRect( |
| + mappedBounds, paintChunk.properties.propertyTreeState, |
| + propertyTreeState, success); |
| + DCHECK(success); |
| + } |
| + bounds.unite(mappedBounds); |
| + if (bounds.size() != paintChunks[0]->bounds.size()) { |
| + if (bounds.size() != paintChunk.bounds.size()) |
| + knownToBeOpaque = false; |
| + else |
| + knownToBeOpaque = paintChunk.knownToBeOpaque; |
| + } |
| +} |
| + |
| +void PaintArtifactCompositor::collectPendingLayers( |
| + const PaintArtifact& paintArtifact, |
| + Vector<PendingLayer>& pendingLayers, |
| + GeometryMapper& geometryMapper) { |
| + // n = # of paint chunks. Memoizing canMergeInto() can get it to O(n^2), and |
| + // other heuristics can make worst-case behavior better. |
| + for (const PaintChunk& paintChunk : paintArtifact.paintChunks()) { |
| + bool createNew = true; |
| + for (Vector<PendingLayer>::reverse_iterator candidatePendingLayer = |
| + pendingLayers.rbegin(); |
| + candidatePendingLayer != pendingLayers.rend(); |
| + ++candidatePendingLayer) { |
| + if (canMergeInto(paintArtifact, paintChunk, *candidatePendingLayer)) { |
| + candidatePendingLayer->add(paintChunk, &geometryMapper); |
| + createNew = false; |
| + break; |
| + } |
| + if (mightOverlap(paintChunk, *candidatePendingLayer, geometryMapper)) { |
| + break; |
| + } |
| + } |
| + if (createNew) |
| + pendingLayers.append(PendingLayer(paintChunk)); |
| + } |
| +} |
| + |
| void PaintArtifactCompositor::update( |
| const PaintArtifact& paintArtifact, |
| RasterInvalidationTrackingMap<const PaintChunk>* rasterChunkInvalidations, |
| bool storeDebugInfo) { |
| +#ifndef NDEBUG |
| + storeDebugInfo = true; |
| +#endif |
| + |
| DCHECK(m_rootLayer); |
| cc::LayerTree* layerTree = m_rootLayer->GetLayerTree(); |
| @@ -813,24 +1128,26 @@ void PaintArtifactCompositor::update( |
| PropertyTreeManager propertyTreeManager(*layerTree->property_trees(), |
| m_rootLayer.get()); |
| + Vector<PendingLayer, 0> pendingLayers; |
| + GeometryMapper geometryMapper; |
| + collectPendingLayers(paintArtifact, pendingLayers, geometryMapper); |
| + |
| Vector<std::unique_ptr<ContentLayerClientImpl>> newContentLayerClients; |
| newContentLayerClients.reserveCapacity(paintArtifact.paintChunks().size()); |
| - for (const PaintChunk& paintChunk : paintArtifact.paintChunks()) { |
| + for (const PendingLayer& pendingLayer : pendingLayers) { |
| gfx::Vector2dF layerOffset; |
| - scoped_refptr<cc::Layer> layer = layerForPaintChunk( |
| - paintArtifact, paintChunk, layerOffset, newContentLayerClients, |
| - rasterChunkInvalidations ? rasterChunkInvalidations->find(&paintChunk) |
| - : nullptr, |
| - storeDebugInfo); |
| + scoped_refptr<cc::Layer> layer = compositedLayerForPendingLayer( |
| + paintArtifact, pendingLayer, layerOffset, newContentLayerClients, |
| + rasterChunkInvalidations, storeDebugInfo, geometryMapper); |
| int transformId = propertyTreeManager.compositorIdForTransformNode( |
| - paintChunk.properties.propertyTreeState.transform()); |
| + pendingLayer.propertyTreeState.transform()); |
| int scrollId = propertyTreeManager.compositorIdForScrollNode( |
| - paintChunk.properties.propertyTreeState.scroll()); |
| + pendingLayer.propertyTreeState.scroll()); |
| int clipId = propertyTreeManager.compositorIdForClipNode( |
| - paintChunk.properties.propertyTreeState.clip()); |
| + pendingLayer.propertyTreeState.clip()); |
| int effectId = propertyTreeManager.switchToEffectNode( |
| - *paintChunk.properties.propertyTreeState.effect()); |
| + *pendingLayer.propertyTreeState.effect()); |
| propertyTreeManager.updateScrollOffset(layer->id(), scrollId); |
| @@ -849,8 +1166,7 @@ void PaintArtifactCompositor::update( |
| ->transform_tree.Node(transformId) |
| ->sorting_context_id); |
| - layer->SetShouldCheckBackfaceVisibility( |
| - paintChunk.properties.backfaceHidden); |
| + layer->SetShouldCheckBackfaceVisibility(pendingLayer.backfaceHidden); |
| if (m_extraDataForTestingEnabled) |
| m_extraDataForTesting->contentLayers.append(layer); |
| @@ -864,4 +1180,13 @@ void PaintArtifactCompositor::update( |
| layerTree->property_trees()->ResetCachedData(); |
| } |
| +#ifndef NDEBUG |
| +void PaintArtifactCompositor::showDebugData() { |
| + LOG(ERROR) << layersAsJSON(LayerTreeIncludesDebugInfo) |
| + ->toPrettyJSONString() |
| + .utf8() |
| + .data(); |
| +} |
| +#endif |
| + |
| } // namespace blink |