| 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 cfe2e254f150eeae2a97c53998492b9adb9346e4..99c1609120a32c2b2a7b711b553438f06b204e24 100644
 | 
| --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
 | 
| +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
 | 
| @@ -24,6 +24,7 @@
 | 
|  #include "platform/graphics/paint/ForeignLayerDisplayItem.h"
 | 
|  #include "platform/graphics/paint/GeometryPropertyTreeState.h"
 | 
|  #include "platform/graphics/paint/PaintArtifact.h"
 | 
| +#include "platform/graphics/paint/RasterInvalidationTracking.h"
 | 
|  #include "platform/graphics/paint/ScrollPaintPropertyNode.h"
 | 
|  #include "platform/graphics/paint/TransformPaintPropertyNode.h"
 | 
|  #include "public/platform/Platform.h"
 | 
| @@ -46,14 +47,31 @@
 | 
|  
 | 
|  namespace blink {
 | 
|  
 | 
| +template class RasterInvalidationTrackingMap<const cc::Layer>;
 | 
| +static RasterInvalidationTrackingMap<const cc::Layer>&
 | 
| +ccLayersRasterInvalidationTrackingMap() {
 | 
| +  DEFINE_STATIC_LOCAL(RasterInvalidationTrackingMap<const cc::Layer>, map, ());
 | 
| +  return map;
 | 
| +}
 | 
| +
 | 
| +template <typename T>
 | 
| +static std::unique_ptr<JSONArray> sizeAsJSONArray(const T& size) {
 | 
| +  std::unique_ptr<JSONArray> array = JSONArray::create();
 | 
| +  array->pushDouble(size.width());
 | 
| +  array->pushDouble(size.height());
 | 
| +  return array;
 | 
| +}
 | 
| +
 | 
|  class PaintArtifactCompositor::ContentLayerClientImpl
 | 
|      : public cc::ContentLayerClient {
 | 
|    WTF_MAKE_NONCOPYABLE(ContentLayerClientImpl);
 | 
|    USING_FAST_MALLOC(ContentLayerClientImpl);
 | 
|  
 | 
|   public:
 | 
| -  ContentLayerClientImpl(Optional<DisplayItem::Id> paintChunkId)
 | 
| -      : m_id(paintChunkId), m_ccPictureLayer(cc::PictureLayer::Create(this)) {}
 | 
| +  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) {
 | 
|      m_ccDisplayItemList = std::move(ccDisplayItemList);
 | 
| @@ -72,14 +90,70 @@ class PaintArtifactCompositor::ContentLayerClientImpl
 | 
|      return 0;
 | 
|    }
 | 
|  
 | 
| +  void resetTrackedRasterInvalidations() {
 | 
| +    RasterInvalidationTracking* tracking =
 | 
| +        ccLayersRasterInvalidationTrackingMap().find(m_ccPictureLayer.get());
 | 
| +    if (!tracking)
 | 
| +      return;
 | 
| +
 | 
| +    if (RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled())
 | 
| +      tracking->trackedRasterInvalidations.clear();
 | 
| +    else
 | 
| +      ccLayersRasterInvalidationTrackingMap().remove(m_ccPictureLayer.get());
 | 
| +  }
 | 
| +
 | 
| +  bool hasTrackedRasterInvalidations() const {
 | 
| +    RasterInvalidationTracking* tracking =
 | 
| +        ccLayersRasterInvalidationTrackingMap().find(m_ccPictureLayer.get());
 | 
| +    if (tracking)
 | 
| +      return !tracking->trackedRasterInvalidations.isEmpty();
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
| +  void setNeedsDisplayRect(const gfx::Rect& rect,
 | 
| +                           RasterInvalidationInfo* rasterInvalidationInfo) {
 | 
| +    m_ccPictureLayer->SetNeedsDisplayRect(rect);
 | 
| +
 | 
| +    if (!rasterInvalidationInfo || rect.IsEmpty())
 | 
| +      return;
 | 
| +
 | 
| +    RasterInvalidationTracking& tracking =
 | 
| +        ccLayersRasterInvalidationTrackingMap().add(m_ccPictureLayer.get());
 | 
| +
 | 
| +    tracking.trackedRasterInvalidations.append(*rasterInvalidationInfo);
 | 
| +
 | 
| +    if (RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) {
 | 
| +      // TODO(crbug.com/496260): Some antialiasing effects overflows the paint invalidation rect.
 | 
| +      IntRect r = rasterInvalidationInfo->rect;
 | 
| +      r.inflate(1);
 | 
| +      tracking.rasterInvalidationRegionSinceLastPaint.unite(r);
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  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())
 | 
| +      json->setArray("bounds", sizeAsJSONArray(bounds));
 | 
| +    json->setBoolean("contentsOpaque", m_ccPictureLayer->contents_opaque());
 | 
| +    json->setBoolean("drawsContent", m_ccPictureLayer->DrawsContent());
 | 
| +
 | 
| +    ccLayersRasterInvalidationTrackingMap().asJSON(m_ccPictureLayer.get(),
 | 
| +                                                   json.get());
 | 
| +    return json;
 | 
| +  }
 | 
| +
 | 
|    scoped_refptr<cc::PictureLayer> ccPictureLayer() { return m_ccPictureLayer; }
 | 
|  
 | 
|    bool matches(const PaintChunk& paintChunk) {
 | 
| -    return m_id && paintChunk.id && *m_id == *paintChunk.id;
 | 
| +    return paintChunk.id && m_id == *paintChunk.id;
 | 
|    }
 | 
|  
 | 
|   private:
 | 
| -  Optional<PaintChunk::Id> m_id;
 | 
| +  PaintChunk::Id m_id;
 | 
| +  String m_debugName;
 | 
|    scoped_refptr<cc::PictureLayer> m_ccPictureLayer;
 | 
|    scoped_refptr<cc::DisplayItemList> m_ccDisplayItemList;
 | 
|    gfx::Rect m_paintableRegion;
 | 
| @@ -92,10 +166,41 @@ PaintArtifactCompositor::PaintArtifactCompositor() {
 | 
|    m_webLayer = wrapUnique(
 | 
|        Platform::current()->compositorSupport()->createLayerFromCCLayer(
 | 
|            m_rootLayer.get()));
 | 
| +  m_isTrackingRasterInvalidations = false;
 | 
|  }
 | 
|  
 | 
|  PaintArtifactCompositor::~PaintArtifactCompositor() {}
 | 
|  
 | 
| +void PaintArtifactCompositor::setTracksRasterInvalidations(
 | 
| +    bool tracksPaintInvalidations) {
 | 
| +  resetTrackedRasterInvalidations();
 | 
| +  m_isTrackingRasterInvalidations = tracksPaintInvalidations;
 | 
| +}
 | 
| +
 | 
| +void PaintArtifactCompositor::resetTrackedRasterInvalidations() {
 | 
| +  for (auto& client : m_contentLayerClients)
 | 
| +    client->resetTrackedRasterInvalidations();
 | 
| +}
 | 
| +
 | 
| +bool PaintArtifactCompositor::hasTrackedRasterInvalidations() const {
 | 
| +  for (auto& client : m_contentLayerClients) {
 | 
| +    if (client->hasTrackedRasterInvalidations())
 | 
| +      return true;
 | 
| +  }
 | 
| +  return false;
 | 
| +}
 | 
| +
 | 
| +std::unique_ptr<JSONObject> PaintArtifactCompositor::layersAsJSON(
 | 
| +    LayerTreeFlags flags) const {
 | 
| +  std::unique_ptr<JSONArray> layersJSON = JSONArray::create();
 | 
| +  for (const auto& client : m_contentLayerClients) {
 | 
| +    layersJSON->pushObject(client->layerAsJSON());
 | 
| +  }
 | 
| +  std::unique_ptr<JSONObject> json = JSONObject::create();
 | 
| +  json->setArray("layers", std::move(layersJSON));
 | 
| +  return json;
 | 
| +}
 | 
| +
 | 
|  namespace {
 | 
|  
 | 
|  static gfx::Rect largeRect(-200000, -200000, 400000, 400000);
 | 
| @@ -213,21 +318,28 @@ void setMinimalPropertyTrees(cc::PropertyTrees* propertyTrees, int ownerId) {
 | 
|  }  // namespace
 | 
|  
 | 
|  std::unique_ptr<PaintArtifactCompositor::ContentLayerClientImpl>
 | 
| -PaintArtifactCompositor::clientForPaintChunk(const PaintChunk& paintChunk) {
 | 
| +PaintArtifactCompositor::clientForPaintChunk(
 | 
| +    const PaintChunk& paintChunk,
 | 
| +    const PaintArtifact& paintArtifact) {
 | 
|    // TODO(chrishtr): for now, just using a linear walk. In the future we can optimize this by using the same techniques used in
 | 
|    // PaintController for display lists.
 | 
|    for (auto& client : m_contentLayerClients) {
 | 
|      if (client && client->matches(paintChunk))
 | 
|        return std::move(client);
 | 
|    }
 | 
| -  return wrapUnique(new ContentLayerClientImpl(paintChunk.id));
 | 
| +
 | 
| +  return wrapUnique(new ContentLayerClientImpl(
 | 
| +      paintChunk.id
 | 
| +          ? *paintChunk.id
 | 
| +          : paintArtifact.getDisplayItemList()[paintChunk.beginIndex].getId()));
 | 
|  }
 | 
|  
 | 
|  scoped_refptr<cc::Layer> PaintArtifactCompositor::layerForPaintChunk(
 | 
|      const PaintArtifact& paintArtifact,
 | 
|      const PaintChunk& paintChunk,
 | 
|      gfx::Vector2dF& layerOffset,
 | 
| -    Vector<std::unique_ptr<ContentLayerClientImpl>>& newContentLayerClients) {
 | 
| +    Vector<std::unique_ptr<ContentLayerClientImpl>>& newContentLayerClients,
 | 
| +    RasterInvalidationTracking* tracking) {
 | 
|    DCHECK(paintChunk.size());
 | 
|  
 | 
|    // If the paint chunk is a foreign layer, just return that layer.
 | 
| @@ -237,7 +349,7 @@ scoped_refptr<cc::Layer> PaintArtifactCompositor::layerForPaintChunk(
 | 
|  
 | 
|    // The common case: create or reuse a PictureLayer for painted content.
 | 
|    std::unique_ptr<ContentLayerClientImpl> contentLayerClient =
 | 
| -      clientForPaintChunk(paintChunk);
 | 
| +      clientForPaintChunk(paintChunk, paintArtifact);
 | 
|  
 | 
|    gfx::Rect combinedBounds = enclosingIntRect(paintChunk.bounds);
 | 
|    scoped_refptr<cc::DisplayItemList> displayList =
 | 
| @@ -252,13 +364,19 @@ scoped_refptr<cc::Layer> PaintArtifactCompositor::layerForPaintChunk(
 | 
|    ccPictureLayer->SetIsDrawable(true);
 | 
|    if (paintChunk.knownToBeOpaque)
 | 
|      ccPictureLayer->SetContentsOpaque(true);
 | 
| -  for (auto& invalidation : paintChunk.rasterInvalidationRects) {
 | 
| -    IntRect rect(enclosingIntRect(invalidation));
 | 
| +  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());
 | 
| -    ccPictureLayer->SetNeedsDisplayRect(ccInvalidationRect);
 | 
| +    // Raster paintChunk.rasterInvalidationRects is in the space of the containing transform node, so need to subtract off the layer offset.
 | 
| +    contentLayerClient->setNeedsDisplayRect(
 | 
| +        ccInvalidationRect,
 | 
| +        tracking ? &tracking->trackedRasterInvalidations[index] : nullptr);
 | 
|    }
 | 
|  
 | 
|    newContentLayerClients.append(std::move(contentLayerClient));
 | 
| @@ -568,7 +686,9 @@ void PropertyTreeManager::buildEffectNodesRecursively(
 | 
|  
 | 
|  }  // namespace
 | 
|  
 | 
| -void PaintArtifactCompositor::update(const PaintArtifact& paintArtifact) {
 | 
| +void PaintArtifactCompositor::update(
 | 
| +    const PaintArtifact& paintArtifact,
 | 
| +    RasterInvalidationTrackingMap<const PaintChunk>* rasterChunkInvalidations) {
 | 
|    DCHECK(m_rootLayer);
 | 
|  
 | 
|    cc::LayerTree* layerTree = m_rootLayer->GetLayerTree();
 | 
| @@ -599,7 +719,9 @@ void PaintArtifactCompositor::update(const PaintArtifact& paintArtifact) {
 | 
|    for (const PaintChunk& paintChunk : paintArtifact.paintChunks()) {
 | 
|      gfx::Vector2dF layerOffset;
 | 
|      scoped_refptr<cc::Layer> layer = layerForPaintChunk(
 | 
| -        paintArtifact, paintChunk, layerOffset, newContentLayerClients);
 | 
| +        paintArtifact, paintChunk, layerOffset, newContentLayerClients,
 | 
| +        rasterChunkInvalidations ? rasterChunkInvalidations->find(&paintChunk)
 | 
| +                                 : nullptr);
 | 
|  
 | 
|      int transformId = propertyTreeManager.compositorIdForTransformNode(
 | 
|          paintChunk.properties.transform.get());
 | 
| 
 |