Make GMs aware of what tool they're being run in.

Add a saveLayer set of draws to convex_poly_clip and fix GPU bug where polygon clips don't account for the translation between clip and device space.

BUG=skia:2051
R=robertphillips@google.com, reed@google.com

Author: bsalomon@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@13371 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp
index 13241e9..ba9bfca 100644
--- a/bench/benchmain.cpp
+++ b/bench/benchmain.cpp
@@ -55,6 +55,7 @@
 
     virtual SkBenchmark* operator()() const SK_OVERRIDE {
         skiagm::GM* gm = fGMFactory(NULL);
+        gm->setMode(skiagm::GM::kBench_Mode);
         return SkNEW_ARGS(SkGMBench, (gm));
     }
 
diff --git a/gm/convexpolyclip.cpp b/gm/convexpolyclip.cpp
index 0822f4c..a8037aa 100644
--- a/gm/convexpolyclip.cpp
+++ b/gm/convexpolyclip.cpp
@@ -83,7 +83,12 @@
     }
 
     virtual SkISize onISize() SK_OVERRIDE {
-        return make_isize(435, 540);
+        // When benchmarking the saveLayer set of draws is skipped.
+        int w = 435;
+        if (kBench_Mode != this->getMode()) {
+            w *= 2;
+        }
+        return make_isize(w, 540);
     }
 
     virtual void onOnceBeforeDraw() SK_OVERRIDE {
@@ -140,47 +145,70 @@
                                         SkIntToScalar(size.fHeight));
         canvas->drawBitmapRectToRect(fBmp, NULL, dstRect, &bgPaint);
 
-        for (SkTLList<Clip>::Iter iter(fClips, SkTLList<Clip>::Iter::kHead_IterStart);
-             NULL != iter.get();
-             iter.next()) {
-            const Clip* clip = iter.get();
-            SkScalar x = 0;
-            for (int aa = 0; aa < 2; ++aa) {
-                canvas->save();
-                canvas->translate(x, y);
-                clip->setOnCanvas(canvas, SkRegion::kIntersect_Op, SkToBool(aa));
-                canvas->drawBitmap(fBmp, 0, 0);
-                canvas->restore();
-                x += fBmp.width() + kMargin;
+        static const char kTxt[] = "Clip Me!";
+        SkPaint txtPaint;
+        txtPaint.setTextSize(23.f);
+        txtPaint.setAntiAlias(true);
+        txtPaint.setColor(SK_ColorDKGRAY);
+        SkScalar textW = txtPaint.measureText(kTxt, SK_ARRAY_COUNT(kTxt)-1);
+
+        SkScalar startX = 0;
+        int testLayers = kBench_Mode != this->getMode();
+        for (int doLayer = 0; doLayer <= testLayers; ++doLayer) {
+            for (SkTLList<Clip>::Iter iter(fClips, SkTLList<Clip>::Iter::kHead_IterStart);
+                 NULL != iter.get();
+                 iter.next()) {
+                const Clip* clip = iter.get();
+                SkScalar x = startX;
+                for (int aa = 0; aa < 2; ++aa) {
+                    if (doLayer) {
+                        SkRect bounds;
+                        clip->getBounds(&bounds);
+                        bounds.outset(2, 2);
+                        bounds.offset(x, y);
+                        canvas->saveLayer(&bounds, NULL);
+                    } else {
+                        canvas->save();
+                    }
+                    canvas->translate(x, y);
+                    clip->setOnCanvas(canvas, SkRegion::kIntersect_Op, SkToBool(aa));
+                    canvas->drawBitmap(fBmp, 0, 0);
+                    canvas->restore();
+                    x += fBmp.width() + kMargin;
+                }
+                for (int aa = 0; aa < 2; ++aa) {
+
+                    SkPaint clipOutlinePaint;
+                    clipOutlinePaint.setAntiAlias(true);
+                    clipOutlinePaint.setColor(0x50505050);
+                    clipOutlinePaint.setStyle(SkPaint::kStroke_Style);
+                    clipOutlinePaint.setStrokeWidth(0);
+
+                    if (doLayer) {
+                        SkRect bounds;
+                        clip->getBounds(&bounds);
+                        bounds.outset(2, 2);
+                        bounds.offset(x, y);
+                        canvas->saveLayer(&bounds, NULL);
+                    } else {
+                        canvas->save();
+                    }
+                    canvas->translate(x, y);
+                    SkPath closedClipPath;
+                    clip->asClosedPath(&closedClipPath);
+                    canvas->drawPath(closedClipPath, clipOutlinePaint);
+                    clip->setOnCanvas(canvas, SkRegion::kIntersect_Op, SkToBool(aa));
+                    canvas->scale(1.f, 1.8f);
+                    canvas->drawText(kTxt, SK_ARRAY_COUNT(kTxt)-1,
+                                     0, 1.5f * txtPaint.getTextSize(),
+                                     txtPaint);
+                    canvas->restore();
+                    x += textW + 2 * kMargin;
+                }
+                y += fBmp.height() + kMargin;
             }
-            for (int aa = 0; aa < 2; ++aa) {
-                static const char kTxt[] = "Clip Me!";
-                SkPaint txtPaint;
-                txtPaint.setTextSize(23.f);
-                txtPaint.setAntiAlias(true);
-                txtPaint.setColor(SK_ColorDKGRAY);
-
-                SkPaint clipOutlinePaint;
-                clipOutlinePaint.setAntiAlias(true);
-                clipOutlinePaint.setColor(0x50505050);
-                clipOutlinePaint.setStyle(SkPaint::kStroke_Style);
-                clipOutlinePaint.setStrokeWidth(0);
-
-                canvas->save();
-                canvas->translate(x, y);
-                SkPath closedClipPath;
-                clip->asClosedPath(&closedClipPath);
-                canvas->drawPath(closedClipPath, clipOutlinePaint);
-                clip->setOnCanvas(canvas, SkRegion::kIntersect_Op, SkToBool(aa));
-                canvas->scale(1.f, 1.8f);
-                canvas->drawText(kTxt, SK_ARRAY_COUNT(kTxt)-1,
-                                 0, 1.5f * txtPaint.getTextSize(),
-                                 txtPaint);
-                canvas->restore();
-                x += fBmp.width() + kMargin;
-            }
-
-            y += fBmp.height() + kMargin;
+            y = 0;
+            startX += 2 * fBmp.width() + SkScalarCeilToInt(2 * textW) + 6 * kMargin;
         }
     }
 
@@ -242,6 +270,20 @@
 
         ClipType getType() const { return fClipType; }
 
+        void getBounds(SkRect* bounds) const {
+            switch (fClipType) {
+                case kPath_ClipType:
+                    *bounds = fPath.getBounds();
+                    break;
+                case kRect_ClipType:
+                    *bounds = fRect;
+                    break;
+                case kNone_ClipType:
+                    SkDEBUGFAIL("Uninitialized Clip.");
+                    break;
+            }
+        }
+
     private:
         ClipType fClipType;
         SkPath fPath;
diff --git a/gm/gm.cpp b/gm/gm.cpp
index 29d02d1..82dd476 100644
--- a/gm/gm.cpp
+++ b/gm/gm.cpp
@@ -11,6 +11,7 @@
 SkString GM::gResourcePath;
 
 GM::GM() {
+    fMode = kGM_Mode;
     fBGColor = SK_ColorWHITE;
     fCanvasIsDeferred = false;
     fHaveCalledOnceBeforeDraw = false;
diff --git a/gm/gm.h b/gm/gm.h
index bb20c9c..4da688c 100644
--- a/gm/gm.h
+++ b/gm/gm.h
@@ -53,6 +53,15 @@
             kAsBench_Flag               = 1 << 10, // Run the GM as a benchmark in the bench tool
         };
 
+        enum Mode {
+            kGM_Mode,
+            kSample_Mode,
+            kBench_Mode,
+        };
+
+        void setMode(Mode mode) { fMode = mode; }
+        Mode getMode() const { return fMode; }
+
         void draw(SkCanvas*);
         void drawBackground(SkCanvas*);
         void drawContent(SkCanvas*);
@@ -101,10 +110,10 @@
             fCanvasIsDeferred = isDeferred;
         }
 
-    const SkMatrix& getStarterMatrix() { return fStarterMatrix; }
-    void setStarterMatrix(const SkMatrix& matrix) {
-        fStarterMatrix = matrix;
-    }
+        const SkMatrix& getStarterMatrix() { return fStarterMatrix; }
+        void setStarterMatrix(const SkMatrix& matrix) {
+            fStarterMatrix = matrix;
+        }
 
     protected:
         static SkString gResourcePath;
@@ -118,6 +127,7 @@
         virtual SkMatrix onGetInitialTransform() const { return SkMatrix::I(); }
 
     private:
+        Mode     fMode;
         SkString fShortName;
         SkColor  fBGColor;
         bool     fCanvasIsDeferred; // work-around problem in srcmode.cpp
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 287639a..53e15a5 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -386,7 +386,9 @@
 }
 
 SkView* SkGMSampleViewFactory::operator() () const {
-    return new GMSampleView(fFunc(NULL));
+    skiagm::GM* gm = fFunc(NULL);
+    gm->setMode(skiagm::GM::kSample_Mode);
+    return new GMSampleView(gm);
 }
 
 SkViewRegister* SkViewRegister::gHead;
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index c1c5973..adb6cee 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -158,18 +158,23 @@
     // clips against the edges.
     if (1 == elements.count() && SkClipStack::Element::kPath_Type == elements.tail()->getType() &&
         SkRegion::kReplace_Op == elements.tail()->getOp()) {
-        const SkPath& p = elements.tail()->getPath();
+        const SkPath& path = elements.tail()->getPath();
         bool isAA = GR_AA_CLIP && elements.tail()->isAA();
         SkAutoTUnref<GrEffectRef> effect;
         if (rt->isMultisampled()) {
             // A coverage effect for AA clipping won't play nicely with MSAA.
             if (!isAA) {
-                effect.reset(GrConvexPolyEffect::Create(GrConvexPolyEffect::kFillNoAA_EdgeType, p));
+                SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX),
+                                    SkIntToScalar(-clipDataIn->fOrigin.fY) };
+                effect.reset(GrConvexPolyEffect::Create(GrConvexPolyEffect::kFillNoAA_EdgeType,
+                                                        path, &offset));
             }
         } else {
+            SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX),
+                                SkIntToScalar(-clipDataIn->fOrigin.fY) };
             GrConvexPolyEffect::EdgeType type = isAA ? GrConvexPolyEffect::kFillAA_EdgeType :
                                                        GrConvexPolyEffect::kFillNoAA_EdgeType;
-            effect.reset(GrConvexPolyEffect::Create(type, p));
+            effect.reset(GrConvexPolyEffect::Create(type, path, &offset));
         }
         if (effect) {
             are->set(fGpu->drawState());
diff --git a/src/gpu/effects/GrConvexPolyEffect.cpp b/src/gpu/effects/GrConvexPolyEffect.cpp
index e47ed0f..98af694 100644
--- a/src/gpu/effects/GrConvexPolyEffect.cpp
+++ b/src/gpu/effects/GrConvexPolyEffect.cpp
@@ -97,7 +97,7 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-GrEffectRef* GrConvexPolyEffect::Create(EdgeType type, const SkPath& path) {
+GrEffectRef* GrConvexPolyEffect::Create(EdgeType type, const SkPath& path, const SkVector* offset) {
     if (path.getSegmentMasks() != SkPath::kLine_SegmentMask ||
         !path.isConvex() ||
         path.isInverseFillType()) {
@@ -114,6 +114,13 @@
     SkPath::Direction dir;
     SkAssertResult(path.cheapComputeDirection(&dir));
 
+    SkVector t;
+    if (NULL == offset) {
+        t.set(0, 0);
+    } else {
+        t = *offset;
+    }
+
     int count = path.getPoints(pts, kMaxEdges);
     int n = 0;
     for (int lastPt = count - 1, i = 0; i < count; lastPt = i++) {
@@ -127,7 +134,8 @@
                 edges[3 * n] = -v.fY;
                 edges[3 * n + 1] = v.fX;
             }
-            edges[3 * n + 2] = -(edges[3 * n] * pts[i].fX + edges[3 * n + 1] * pts[i].fY);
+            SkPoint p = pts[i] + t;
+            edges[3 * n + 2] = -(edges[3 * n] * p.fX + edges[3 * n + 1] * p.fY);
             ++n;
         }
     }
diff --git a/src/gpu/effects/GrConvexPolyEffect.h b/src/gpu/effects/GrConvexPolyEffect.h
index 035d9e9..225e729 100644
--- a/src/gpu/effects/GrConvexPolyEffect.h
+++ b/src/gpu/effects/GrConvexPolyEffect.h
@@ -57,9 +57,10 @@
 
     /**
      * Creates an effect that clips against the path. If the path is not a convex polygon, is
-     * inverse filled, or has too many edges, this will return NULL.
+     * inverse filled, or has too many edges, this will return NULL. If offset is non-NULL, then
+     * the path is translated by the vector.
      */
-    static GrEffectRef* Create(EdgeType, const SkPath&);
+    static GrEffectRef* Create(EdgeType, const SkPath&, const SkVector* offset= NULL);
 
     virtual ~GrConvexPolyEffect();