| 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..00b42f49923192a032fd0eac271336db5f9aa865 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,220 @@ 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>(
|
| + 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 +502,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_EQ(pendingLayer.paintChunks.size(), 1u);
|
| 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 +891,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 +1007,109 @@ 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)
|
| + return false;
|
| +
|
| + DCHECK_GE(candidatePendingLayer.paintChunks.size(), 1u);
|
| + 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
|
|
|