| 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 3542db9f82d5454f7d6cefb80898514bb72e5b52..ed0ab1fb2aeb0f17b1feefb915d01b8569599671 100644
|
| --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
|
| +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
|
| @@ -17,12 +17,15 @@
|
| #include "cc/trees/property_tree.h"
|
| #include "cc/trees/scroll_node.h"
|
| #include "cc/trees/transform_node.h"
|
| +#include "core/paint/PaintPropertyTreePrinter.h"
|
| #include "platform/RuntimeEnabledFeatures.h"
|
| #include "platform/graphics/paint/ClipPaintPropertyNode.h"
|
| #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"
|
| @@ -69,7 +72,6 @@ class PaintArtifactCompositor::ContentLayerClientImpl
|
| public:
|
| ContentLayerClientImpl(DisplayItem::Id paintChunkId)
|
| : m_id(paintChunkId),
|
| - m_debugName(paintChunkId.client.debugName()),
|
| m_ccPictureLayer(cc::PictureLayer::Create(this)) {}
|
|
|
| void SetDisplayList(scoped_refptr<cc::DisplayItemList> ccDisplayItemList) {
|
| @@ -77,6 +79,12 @@ class PaintArtifactCompositor::ContentLayerClientImpl
|
| }
|
| void SetPaintableRegion(gfx::Rect region) { m_paintableRegion = region; }
|
|
|
| + void addPaintChunkDebugData(std::unique_ptr<JSONArray> json) {
|
| + m_paintChunkDebugData.append(std::move(json));
|
| + }
|
| +
|
| + void clearPaintChunkDebugData() { m_paintChunkDebugData.clear(); }
|
| +
|
| // cc::ContentLayerClient
|
| gfx::Rect PaintableRegion() override { return m_paintableRegion; }
|
| scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList(
|
| @@ -132,7 +140,6 @@ class PaintArtifactCompositor::ContentLayerClientImpl
|
|
|
| std::unique_ptr<JSONObject> layerAsJSON() {
|
| std::unique_ptr<JSONObject> json = JSONObject::create();
|
| - json->setString("name", m_debugName);
|
| IntSize bounds(m_ccPictureLayer->bounds().width(),
|
| m_ccPictureLayer->bounds().height());
|
| if (!bounds.isEmpty())
|
| @@ -140,6 +147,12 @@ class PaintArtifactCompositor::ContentLayerClientImpl
|
| json->setBoolean("contentsOpaque", m_ccPictureLayer->contents_opaque());
|
| json->setBoolean("drawsContent", m_ccPictureLayer->DrawsContent());
|
|
|
| + std::unique_ptr<JSONArray> paintChunkContentsArray = JSONArray::create();
|
| + for (const auto& debugData : m_paintChunkDebugData) {
|
| + paintChunkContentsArray->pushValue(debugData->clone());
|
| + }
|
| + json->setArray("paintChunkContents", std::move(paintChunkContentsArray));
|
| +
|
| ccLayersRasterInvalidationTrackingMap().asJSON(m_ccPictureLayer.get(),
|
| json.get());
|
| return json;
|
| @@ -153,10 +166,11 @@ class PaintArtifactCompositor::ContentLayerClientImpl
|
|
|
| private:
|
| PaintChunk::Id m_id;
|
| - String m_debugName;
|
| scoped_refptr<cc::PictureLayer> m_ccPictureLayer;
|
| scoped_refptr<cc::DisplayItemList> m_ccDisplayItemList;
|
| gfx::Rect m_paintableRegion;
|
| +
|
| + Vector<std::unique_ptr<JSONArray>> m_paintChunkDebugData;
|
| };
|
|
|
| PaintArtifactCompositor::PaintArtifactCompositor() {
|
| @@ -224,7 +238,7 @@ static void appendDisplayItemToCcDisplayItemList(const DisplayItem& displayItem,
|
|
|
| static scoped_refptr<cc::DisplayItemList> recordPaintChunk(
|
| const PaintArtifact& artifact,
|
| - const PaintChunk& chunk,
|
| + const PendingLayer& pendingLayer,
|
| const gfx::Rect& combinedBounds) {
|
| cc::DisplayItemListSettings settings;
|
| scoped_refptr<cc::DisplayItemList> list =
|
| @@ -238,8 +252,10 @@ static scoped_refptr<cc::DisplayItemList> recordPaintChunk(
|
| list->CreateAndAppendPairedBeginItem<cc::TransformDisplayItem>(translation);
|
|
|
| const DisplayItemList& displayItems = artifact.getDisplayItemList();
|
| - for (const auto& displayItem : displayItems.itemsInPaintChunk(chunk))
|
| - appendDisplayItemToCcDisplayItemList(displayItem, list.get());
|
| + for (const auto& paintChunk : pendingLayer.paintChunks) {
|
| + for (const auto& displayItem : displayItems.itemsInPaintChunk(paintChunk))
|
| + appendDisplayItemToCcDisplayItemList(displayItem, list.get());
|
| + }
|
|
|
| list->CreateAndAppendPairedEndItem<cc::EndTransformDisplayItem>();
|
|
|
| @@ -296,50 +312,73 @@ 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) {
|
| - DCHECK(paintChunk.size());
|
| + RasterInvalidationTrackingMap<const PaintChunk>* trackingMap) {
|
| + 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);
|
| +
|
| + IntRect combinedBounds = enclosingIntRect(pendingLayer.bounds);
|
| + bool knownToBeOpaque = pendingLayer.knownToBeOpaque;
|
| + gfx::Rect ccCombinedBounds(combinedBounds);
|
|
|
| - gfx::Rect combinedBounds = enclosingIntRect(paintChunk.bounds);
|
| scoped_refptr<cc::DisplayItemList> displayList =
|
| - recordPaintChunk(paintArtifact, paintChunk, combinedBounds);
|
| + recordPaintChunk(paintArtifact, pendingLayer, ccCombinedBounds);
|
| contentLayerClient->SetDisplayList(std::move(displayList));
|
| - contentLayerClient->SetPaintableRegion(gfx::Rect(combinedBounds.size()));
|
| + contentLayerClient->SetPaintableRegion(gfx::Rect(ccCombinedBounds.size()));
|
|
|
| - layerOffset = combinedBounds.OffsetFromOrigin();
|
| + layerOffset = ccCombinedBounds.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());
|
| - 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);
|
| + ccPictureLayer->SetContentsOpaque(knownToBeOpaque);
|
| + contentLayerClient->clearPaintChunkDebugData();
|
| +
|
| + for (const auto& paintChunk : pendingLayer.paintChunks) {
|
| + RasterInvalidationTracking* rasterTracking =
|
| + trackingMap ? trackingMap->find(&paintChunk) : nullptr;
|
| + DCHECK(!rasterTracking ||
|
| + rasterTracking->trackedRasterInvalidations.size() ==
|
| + paintChunk.rasterInvalidationRects.size());
|
| + 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(-ccCombinedBounds.OffsetFromOrigin());
|
| + contentLayerClient->setNeedsDisplayRect(
|
| + ccInvalidationRect,
|
| + rasterTracking ? &rasterTracking->trackedRasterInvalidations[index]
|
| + : nullptr);
|
| + }
|
| + contentLayerClient->addPaintChunkDebugData(
|
| + paintArtifact.getDisplayItemList().subsequenceAsJSON(
|
| + paintChunk.beginIndex, paintChunk.endIndex, false, true));
|
| }
|
|
|
| newContentLayerClients.append(std::move(contentLayerClient));
|
| @@ -755,11 +794,98 @@ void PropertyTreeManager::buildEffectNodesRecursively(
|
|
|
| } // namespace
|
|
|
| +static bool canMergeInto(const PaintChunk& newChunk,
|
| + const PendingLayer& candidatePendingLayer) {
|
| + DCHECK(candidatePendingLayer.paintChunks.size() >= 1);
|
| + const PaintChunk& firstLayerChunk = candidatePendingLayer.paintChunks[0];
|
| +
|
| + PropertyTreeState newChunkProperties(
|
| + newChunk.properties.transform.get(), newChunk.properties.clip.get(),
|
| + newChunk.properties.effect.get(), newChunk.properties.scroll.get());
|
| +
|
| + PropertyTreeState currentLayerProperties(
|
| + firstLayerChunk.properties.transform.get(),
|
| + firstLayerChunk.properties.clip.get(),
|
| + firstLayerChunk.properties.effect.get(),
|
| + firstLayerChunk.properties.scroll.get());
|
| +
|
| + if (firstLayerChunk.properties.hasDirectCompositingReasons() ||
|
| + newChunk.properties.hasDirectCompositingReasons())
|
| + return false;
|
| +
|
| + for (PropertyTreeStateIterator it(newChunkProperties); it.hasNext();
|
| + it.next()) {
|
| + if (it.current().hasDirectCompositingReasons())
|
| + return false;
|
| +
|
| + if (it.current() == currentLayerProperties)
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +static bool overlaps(const PaintChunk& paintChunk,
|
| + const PendingLayer& candidatePendingLayer,
|
| + GeometryMapper& geometryMapper) {
|
| + PropertyTreeState rootPropertyTreeState(
|
| + TransformPaintPropertyNode::root(), ClipPaintPropertyNode::root(),
|
| + EffectPaintPropertyNode::root(), ScrollPaintPropertyNode::root());
|
| +
|
| + FloatRect paintChunkScreenVisualRect(paintChunk.bounds);
|
| + PropertyTreeState paintChunkPropertyState(
|
| + paintChunk.properties.transform.get(), paintChunk.properties.clip.get(),
|
| + paintChunk.properties.effect.get(), paintChunk.properties.scroll.get());
|
| + bool success = false;
|
| + geometryMapper.localToVisualRectInAncestorSpace(
|
| + paintChunkScreenVisualRect, paintChunkPropertyState,
|
| + rootPropertyTreeState, success);
|
| + DCHECK(success);
|
| +
|
| + PropertyTreeState candidatePendingLayerPropertyState(
|
| + candidatePendingLayer.paintChunks[0].properties.transform.get(),
|
| + candidatePendingLayer.paintChunks[0].properties.clip.get(),
|
| + candidatePendingLayer.paintChunks[0].properties.effect.get(),
|
| + candidatePendingLayer.paintChunks[0].properties.scroll.get());
|
| +
|
| + FloatRect pendingLayerScreenVisualRect(candidatePendingLayer.bounds);
|
| + success = false;
|
| + geometryMapper.localToVisualRectInAncestorSpace(
|
| + pendingLayerScreenVisualRect, candidatePendingLayerPropertyState,
|
| + rootPropertyTreeState, success);
|
| + DCHECK(success);
|
| +
|
| + return paintChunkScreenVisualRect.intersects(pendingLayerScreenVisualRect);
|
| + return true;
|
| +}
|
| +
|
| +void PaintArtifactCompositor::collectPendingLayers(
|
| + const Vector<PaintChunk>& paintChunks,
|
| + Vector<PendingLayer>& pendingLayers) {
|
| + GeometryMapper geometryMapper;
|
| + for (const PaintChunk& paintChunk : paintChunks) {
|
| + bool createNew = true;
|
| + for (Vector<PendingLayer>::reverse_iterator candidatePendingLayer =
|
| + pendingLayers.rbegin();
|
| + candidatePendingLayer != pendingLayers.rend();
|
| + ++candidatePendingLayer) {
|
| + if (canMergeInto(paintChunk, *candidatePendingLayer)) {
|
| + candidatePendingLayer->add(paintChunk);
|
| + createNew = false;
|
| + break;
|
| + }
|
| + if (overlaps(paintChunk, *candidatePendingLayer, geometryMapper)) {
|
| + break;
|
| + }
|
| + }
|
| + if (createNew)
|
| + pendingLayers.append(PendingLayer(paintChunk));
|
| + }
|
| +}
|
| +
|
| void PaintArtifactCompositor::update(
|
| const PaintArtifact& paintArtifact,
|
| RasterInvalidationTrackingMap<const PaintChunk>* rasterChunkInvalidations) {
|
| DCHECK(m_rootLayer);
|
| -
|
| cc::LayerTree* layerTree = m_rootLayer->GetLayerTree();
|
|
|
| // The tree will be null after detaching and this update can be ignored.
|
| @@ -776,23 +902,26 @@ void PaintArtifactCompositor::update(
|
| PropertyTreeManager propertyTreeManager(*layerTree->property_trees(),
|
| m_rootLayer.get());
|
|
|
| + Vector<PendingLayer> pendingLayers;
|
| + collectPendingLayers(paintArtifact.paintChunks(), pendingLayers);
|
| +
|
| 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);
|
| + scoped_refptr<cc::Layer> layer = compositedLayerForPendingLayer(
|
| + paintArtifact, pendingLayer, layerOffset, newContentLayerClients,
|
| + rasterChunkInvalidations);
|
|
|
| int transformId = propertyTreeManager.compositorIdForTransformNode(
|
| - paintChunk.properties.transform.get());
|
| + pendingLayer.paintChunks[0].properties.transform.get());
|
| int scrollId = propertyTreeManager.compositorIdForScrollNode(
|
| - paintChunk.properties.scroll.get());
|
| + pendingLayer.paintChunks[0].properties.scroll.get());
|
| int clipId = propertyTreeManager.compositorIdForClipNode(
|
| - paintChunk.properties.clip.get());
|
| + pendingLayer.paintChunks[0].properties.clip.get());
|
| int effectId = propertyTreeManager.switchToEffectNode(
|
| - *paintChunk.properties.effect.get());
|
| + *pendingLayer.paintChunks[0].properties.effect.get());
|
|
|
| propertyTreeManager.updateScrollOffset(layer->id(), scrollId);
|
|
|
| @@ -812,7 +941,7 @@ void PaintArtifactCompositor::update(
|
| ->sorting_context_id);
|
|
|
| layer->SetShouldCheckBackfaceVisibility(
|
| - paintChunk.properties.backfaceHidden);
|
| + pendingLayer.paintChunks[0].properties.backfaceHidden);
|
|
|
| if (m_extraDataForTestingEnabled)
|
| m_extraDataForTesting->contentLayers.append(layer);
|
|
|