Infrastructure changes to support pull-saveLayers-forward task

This is split out of (First pass at pre-rendering saveLayers for GPU - https://codereview.chromium.org/261663003/).

It mainly:

	Moves NeedsDeepCopy to somewhere more accessible (so GrPictureUtils.cpp can use it)
	Moves ComputeAccelDataKey somewhere more accessible (so GPUPicture test can use it)
	Adds unit test for picture saveLayer analysis (done in EXPERIMENTAL_optimize)
        Adds new fields to SaveLayerInfo that are needed to pull forward layers

Committed: http://code.google.com/p/skia/source/detail?r=14571

R=bsalomon@google.com

Author: robertphillips@google.com

Review URL: https://codereview.chromium.org/266203003

git-svn-id: http://skia.googlecode.com/svn/trunk/src@14586 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/core/SkPaintPriv.cpp b/core/SkPaintPriv.cpp
index ce05389..65fd0e7 100644
--- a/core/SkPaintPriv.cpp
+++ b/core/SkPaintPriv.cpp
@@ -76,3 +76,24 @@
     }
     return false;
 }
+
+bool NeedsDeepCopy(const SkPaint& paint) {
+    /*
+     *  These fields are known to be immutable, and so can be shallow-copied
+     *
+     *  getTypeface()
+     *  getAnnotation()
+     *  paint.getColorFilter()
+     *  getXfermode()
+     *  getPathEffect()
+     *  getMaskFilter()
+     */
+
+    return paint.getShader() ||
+#ifdef SK_SUPPORT_LEGACY_LAYERRASTERIZER_API
+           paint.getRasterizer() ||
+#endif
+           paint.getLooper() || // needs to hide its addLayer...
+           paint.getImageFilter();
+}
+
diff --git a/core/SkPaintPriv.h b/core/SkPaintPriv.h
index 38c9063..9668fef 100644
--- a/core/SkPaintPriv.h
+++ b/core/SkPaintPriv.h
@@ -22,4 +22,11 @@
 */
 bool isPaintOpaque(const SkPaint* paint,
                    const SkBitmap* bmpReplacesShader = NULL);
+
+/** Returns true if the provided paint has fields which are not
+    immutable (and will thus require deep copying).
+    @param paint the paint to be analyzed
+    @return true if the paint requires a deep copy
+*/
+bool NeedsDeepCopy(const SkPaint& paint);
 #endif
diff --git a/core/SkPicture.cpp b/core/SkPicture.cpp
index 3b04906..6843430 100644
--- a/core/SkPicture.cpp
+++ b/core/SkPicture.cpp
@@ -15,6 +15,7 @@
 #include "SkBitmapDevice.h"
 #include "SkCanvas.h"
 #include "SkChunkAlloc.h"
+#include "SkPaintPriv.h"
 #include "SkPicture.h"
 #include "SkRegion.h"
 #include "SkStream.h"
@@ -217,26 +218,6 @@
     return clonedPicture;
 }
 
-static bool needs_deep_copy(const SkPaint& paint) {
-    /*
-     *  These fields are known to be immutable, and so can be shallow-copied
-     *
-     *  getTypeface()
-     *  getAnnotation()
-     *  paint.getColorFilter()
-     *  getXfermode()
-     *  getPathEffect()
-     *  getMaskFilter()
-     */
-
-    return paint.getShader() ||
-#ifdef SK_SUPPORT_LEGACY_LAYERRASTERIZER_API
-           paint.getRasterizer() ||
-#endif
-           paint.getLooper() || // needs to hide its addLayer...
-           paint.getImageFilter();
-}
-
 void SkPicture::clone(SkPicture* pictures, int count) const {
     SkPictCopyInfo copyInfo;
     SkPictInfo info;
@@ -282,7 +263,7 @@
 
                 SkDEBUGCODE(int heapSize = SafeCount(fPlayback->fBitmapHeap.get());)
                 for (int i = 0; i < paintCount; i++) {
-                    if (needs_deep_copy(fPlayback->fPaints->at(i))) {
+                    if (NeedsDeepCopy(fPlayback->fPaints->at(i))) {
                         copyInfo.paintData[i] =
                             SkFlatData::Create<SkPaint::FlatteningTraits>(&copyInfo.controller,
                                                               fPlayback->fPaints->at(i), 0);
diff --git a/gpu/GrPictureUtils.cpp b/gpu/GrPictureUtils.cpp
index e8c3b50..089e421 100644
--- a/gpu/GrPictureUtils.cpp
+++ b/gpu/GrPictureUtils.cpp
@@ -7,6 +7,14 @@
 
 #include "GrPictureUtils.h"
 #include "SkDevice.h"
+#include "SkDraw.h"
+#include "SkPaintPriv.h"
+
+SkPicture::AccelData::Key GPUAccelData::ComputeAccelDataKey() {
+    static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
+
+    return gGPUID;
+}
 
 // The GrGather device performs GPU-backend-specific preprocessing on
 // a picture. The results are stored in a GPUAccelData.
@@ -20,12 +28,17 @@
 public:
     SK_DECLARE_INST_COUNT(GrGatherDevice)
 
-    GrGatherDevice(int width, int height, SkPicture* picture, GPUAccelData* accelData) {
+    GrGatherDevice(int width, int height, SkPicture* picture, GPUAccelData* accelData,
+                   int saveLayerDepth) {
         fPicture = picture;
+        fSaveLayerDepth = saveLayerDepth;
+        fInfo.fValid = true;
         fInfo.fSize.set(width, height);
+        fInfo.fPaint = NULL;
         fInfo.fSaveLayerOpID = fPicture->EXPERIMENTAL_curOpID();
         fInfo.fRestoreOpID = 0;
         fInfo.fHasNestedLayers = false;
+        fInfo.fIsNested = (2 == fSaveLayerDepth);
 
         fEmptyBitmap.setConfig(SkImageInfo::Make(fInfo.fSize.fWidth,
                                                  fInfo.fSize.fHeight,
@@ -110,7 +123,8 @@
                               const SkPaint& paint) SK_OVERRIDE {
     }
     virtual void drawDevice(const SkDraw& draw, SkBaseDevice* deviceIn, int x, int y,
-                            const SkPaint&) SK_OVERRIDE {
+                            const SkPaint& paint) SK_OVERRIDE {
+        // deviceIn is the one that is being "restored" back to its parent
         GrGatherDevice* device = static_cast<GrGatherDevice*>(deviceIn);
 
         if (device->fAlreadyDrawn) {
@@ -118,6 +132,29 @@
         }
 
         device->fInfo.fRestoreOpID = fPicture->EXPERIMENTAL_curOpID();
+        device->fInfo.fCTM = *draw.fMatrix;
+        device->fInfo.fCTM.postTranslate(SkIntToScalar(-device->getOrigin().fX),
+                                         SkIntToScalar(-device->getOrigin().fY));
+
+        // We need the x & y values that will yield 'getOrigin' when transformed
+        // by 'draw.fMatrix'.
+        device->fInfo.fOffset.iset(device->getOrigin());
+
+        SkMatrix invMatrix;
+        if (draw.fMatrix->invert(&invMatrix)) {
+            invMatrix.mapPoints(&device->fInfo.fOffset, 1);
+        } else {
+            device->fInfo.fValid = false;
+        }
+
+        if (NeedsDeepCopy(paint)) {
+            // This NULL acts as a signal that the paint was uncopyable (for now)
+            device->fInfo.fPaint = NULL;
+            device->fInfo.fValid = false;
+        } else {
+            device->fInfo.fPaint = SkNEW_ARGS(SkPaint, (paint));
+        }
+
         fAccelData->addSaveLayerInfo(device->fInfo);
         device->fAlreadyDrawn = true;
     }
@@ -158,6 +195,9 @@
     // The information regarding the saveLayer call this device represents.
     GPUAccelData::SaveLayerInfo fInfo;
 
+    // The depth of this device in the saveLayer stack
+    int fSaveLayerDepth;
+
     virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
         NotSupported();
     }
@@ -167,7 +207,8 @@
         SkASSERT(kSaveLayer_Usage == usage);
 
         fInfo.fHasNestedLayers = true;
-        return SkNEW_ARGS(GrGatherDevice, (info.width(), info.height(), fPicture, fAccelData));
+        return SkNEW_ARGS(GrGatherDevice, (info.width(), info.height(), fPicture, 
+                                           fAccelData, fSaveLayerDepth+1));
     }
 
     virtual void flush() SK_OVERRIDE {}
@@ -239,7 +280,7 @@
         return ;
     }
 
-    GrGatherDevice device(pict->width(), pict->height(), pict, accelData);
+    GrGatherDevice device(pict->width(), pict->height(), pict, accelData, 0);
     GrGatherCanvas canvas(&device, pict);
 
     canvas.gather();
diff --git a/gpu/GrPictureUtils.h b/gpu/GrPictureUtils.h
index 6b4d901..8fdb3b8 100644
--- a/gpu/GrPictureUtils.h
+++ b/gpu/GrPictureUtils.h
@@ -17,8 +17,21 @@
 public:
     // Information about a given saveLayer in an SkPicture
     struct SaveLayerInfo {
+        // True if the SaveLayerInfo is valid. False if either 'fOffset' is
+        // invalid (due to a non-invertible CTM) or 'fPaint' is NULL (due
+        // to a non-copyable paint).
+        bool fValid;
         // The size of the saveLayer
         SkISize fSize;
+        // The CTM in which this layer's draws must occur. It already incorporates
+        // the translation needed to map the layer's top-left point to the origin.
+        SkMatrix fCTM;
+        // The offset that needs to be passed to drawBitmap to correctly
+        // position the pre-rendered layer.
+        SkPoint fOffset;
+        // The paint to use on restore. NULL if the paint was not copyable (and
+        // thus that this layer should not be pulled forward).
+        const SkPaint* fPaint;
         // The ID of this saveLayer in the picture. 0 is an invalid ID.
         size_t  fSaveLayerOpID;
         // The ID of the matching restore in the picture. 0 is an invalid ID.
@@ -26,6 +39,8 @@
         // True if this saveLayer has at least one other saveLayer nested within it.
         // False otherwise.
         bool    fHasNestedLayers;
+        // True if this saveLayer is nested within another. False otherwise.
+        bool    fIsNested;
     };
 
     GPUAccelData(Key key) : INHERITED(key) { }
@@ -43,6 +58,10 @@
         return fSaveLayerInfo[index];
     }
 
+    // We may, in the future, need to pass in the GPUDevice in order to
+    // incorporate the clip and matrix state into the key
+    static SkPicture::AccelData::Key ComputeAccelDataKey();
+
 protected:
     SkTDArray<SaveLayerInfo> fSaveLayerInfo;
 
diff --git a/gpu/SkGpuDevice.cpp b/gpu/SkGpuDevice.cpp
index 714a6da..3119a9e 100644
--- a/gpu/SkGpuDevice.cpp
+++ b/gpu/SkGpuDevice.cpp
@@ -1910,16 +1910,8 @@
     return SkSurface::NewRenderTarget(fContext, info, fRenderTarget->numSamples());
 }
 
-// In the future this may not be a static method if we need to incorporate the
-// clip and matrix state into the key
-SkPicture::AccelData::Key SkGpuDevice::ComputeAccelDataKey() {
-    static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
-
-    return gGPUID;
-}
-
 void SkGpuDevice::EXPERIMENTAL_optimize(SkPicture* picture) {
-    SkPicture::AccelData::Key key = ComputeAccelDataKey();
+    SkPicture::AccelData::Key key = GPUAccelData::ComputeAccelDataKey();
 
     GPUAccelData* data = SkNEW_ARGS(GPUAccelData, (key));
 
@@ -1934,7 +1926,7 @@
 
 bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* canvas, SkPicture* picture) {
 
-    SkPicture::AccelData::Key key = ComputeAccelDataKey();
+    SkPicture::AccelData::Key key = GPUAccelData::ComputeAccelDataKey();
 
     const SkPicture::AccelData* data = picture->EXPERIMENTAL_getAccelData(key);
     if (NULL == data) {
@@ -1943,27 +1935,6 @@
 
     const GPUAccelData *gpuData = static_cast<const GPUAccelData*>(data);
 
-//#define SK_PRINT_PULL_FORWARD_INFO 1
-
-#ifdef SK_PRINT_PULL_FORWARD_INFO
-    static bool gPrintedAccelData = false;
-
-    if (!gPrintedAccelData) {
-        for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
-            const GPUAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i);
-
-            SkDebugf("%d: Width: %d Height: %d SL: %d R: %d hasNestedLayers: %s\n",
-                                            i,
-                                            info.fSize.fWidth,
-                                            info.fSize.fHeight,
-                                            info.fSaveLayerOpID,
-                                            info.fRestoreOpID,
-                                            info.fHasNestedLayers ? "T" : "F");
-        }
-        gPrintedAccelData = true;
-    }
-#endif
-
     SkAutoTArray<bool> pullForward(gpuData->numSaveLayers());
     for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
         pullForward[i] = false;
@@ -1984,10 +1955,6 @@
 
     const SkPicture::OperationList& ops = picture->EXPERIMENTAL_getActiveOps(clip);
 
-#ifdef SK_PRINT_PULL_FORWARD_INFO
-    SkDebugf("rect: %d %d %d %d\n", clip.fLeft, clip.fTop, clip.fRight, clip.fBottom);
-#endif
-
     for (int i = 0; i < ops.numOps(); ++i) {
         for (int j = 0; j < gpuData->numSaveLayers(); ++j) {
             const GPUAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(j);
@@ -1998,17 +1965,5 @@
         }
     }
 
-#ifdef SK_PRINT_PULL_FORWARD_INFO
-    SkDebugf("Need SaveLayers: ");
-    for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
-        if (pullForward[i]) {
-            const GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture, i);
-
-            SkDebugf("%d (%d), ", i, layer->layerID());
-        }
-    }
-    SkDebugf("\n");
-#endif
-
     return false;
 }