Add drawRegion() API to SkCanvas

This will allow us to optimize for the RectGrid macrobench.
Currently, SkiaGL is much slower than OpenGL.
SkiaGL  12 items/s
OpenGL 160 items/s

This contains everything except for the fast implementation on GPU.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2277053002

Review-Url: https://codereview.chromium.org/2277053002
diff --git a/gm/drawregion.cpp b/gm/drawregion.cpp
new file mode 100644
index 0000000..1e9d6c5
--- /dev/null
+++ b/gm/drawregion.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+
+/**
+ *  This is very similar to the RectGrid macrobench in Android.
+ */
+class DrawRegionGM : public skiagm::GM {
+public:
+    DrawRegionGM() {}
+
+protected:
+    SkString onShortName() override {
+        return SkString("drawregion");
+    }
+
+    SkISize onISize() override {
+        return SkISize::Make(500, 500);
+    }
+
+    bool runAsBench() const override {
+        return true;
+    }
+
+    void onOnceBeforeDraw() override {
+        for (int x = 50; x < 250; x+=2) {
+            for (int y = 50; y < 250; y+=2) {
+                fRegion.op(x, y, x + 1, y + 1, SkRegion::kUnion_Op);
+            }
+        }
+    }
+
+    void onDraw(SkCanvas* canvas) override {
+        SkPaint paint;
+        paint.setStyle(SkPaint::kFill_Style);
+        paint.setColor(0xFFFF00FF);
+        canvas->drawRect(SkRect::MakeLTRB(50.0f, 50.0f, 250.0f, 250.0f), paint);
+
+        paint.setColor(0xFF00FFFF);
+        canvas->drawRegion(fRegion, paint);
+    }
+
+    SkRegion fRegion;
+
+private:
+    typedef skiagm::GM INHERITED;
+};
+DEF_GM( return new DrawRegionGM; )
diff --git a/gm/drawregionmodes.cpp b/gm/drawregionmodes.cpp
new file mode 100644
index 0000000..be1c2d2
--- /dev/null
+++ b/gm/drawregionmodes.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkBlurMaskFilter.h"
+#include "SkCanvas.h"
+#include "SkDashPathEffect.h"
+#include "SkGradientShader.h"
+#include "SkImageFilter.h"
+
+class DrawRegionModesGM : public skiagm::GM {
+public:
+    DrawRegionModesGM() {}
+
+protected:
+    SkString onShortName() override {
+        return SkString("drawregionmodes");
+    }
+
+    SkISize onISize() override {
+        return SkISize::Make(375, 500);
+    }
+
+    void onOnceBeforeDraw() override {
+        fRegion.op( 50,  50, 100, 100, SkRegion::kUnion_Op);
+        fRegion.op( 50, 100, 150, 150, SkRegion::kUnion_Op);
+    }
+
+    void onDraw(SkCanvas* canvas) override {
+        canvas->clear(SK_ColorGREEN);
+
+        SkPaint paint;
+        paint.setStyle(SkPaint::kFill_Style);
+        paint.setColor(0xFFFF0000);
+        paint.setAntiAlias(true);
+
+        canvas->translate(-50.0f, 75.0f);
+        canvas->rotate(-45.0f);
+        canvas->drawRegion(fRegion, paint);
+
+        canvas->translate(125.0f, 125.0f);
+        paint.setImageFilter(SkImageFilter::MakeBlur(5.0f, 5.0f, nullptr, nullptr));
+        canvas->drawRegion(fRegion, paint);
+
+        canvas->translate(-125.0f, 125.0f);
+        paint.setImageFilter(nullptr);
+        SkRect occluder = SkRect::MakeEmpty();
+        paint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 5.0f, occluder, 0));
+        canvas->drawRegion(fRegion, paint);
+
+        canvas->translate(-125.0f, -125.0f);
+        paint.setMaskFilter(nullptr);
+        paint.setStyle(SkPaint::kStroke_Style);
+        float intervals[] = { 5.0f, 5.0f };
+        paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 2.5f));
+        canvas->drawRegion(fRegion, paint);
+
+        canvas->setMatrix(SkMatrix::I());
+        canvas->translate(100, 325);
+        paint.setPathEffect(nullptr);
+        paint.setStyle(SkPaint::kFill_Style);
+        SkPoint points[] = { SkPoint::Make(50.0f, 50.0f), SkPoint::Make(150.0f, 150.0f) };
+        SkColor colors[] = { SK_ColorBLUE, SK_ColorYELLOW };
+        paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 2,
+                                                     SkShader::kClamp_TileMode));
+        canvas->drawRegion(fRegion, paint);
+    }
+
+    SkRegion fRegion;
+
+private:
+    typedef skiagm::GM INHERITED;
+};
+DEF_GM( return new DrawRegionModesGM; )
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index bc3b25d..780af10 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -703,6 +703,14 @@
     void drawRectCoords(SkScalar left, SkScalar top, SkScalar right,
                         SkScalar bottom, const SkPaint& paint);
 
+    /** Draw the outline of the specified region using the specified paint.
+        @param region   The region to be drawn
+        @param paint    The paint used to draw the region
+    */
+    void drawRegion(const SkRegion& region, const SkPaint& paint) {
+        this->onDrawRegion(region, paint);
+    }
+
     /** Draw the specified oval using the specified paint. The oval will be
         filled or framed based on the Style in the paint.
         @param oval     The rectangle bounds of the oval to be drawn
@@ -1412,6 +1420,7 @@
 
     virtual void onDrawPaint(const SkPaint&);
     virtual void onDrawRect(const SkRect&, const SkPaint&);
+    virtual void onDrawRegion(const SkRegion& region, const SkPaint& paint);
     virtual void onDrawOval(const SkRect&, const SkPaint&);
     virtual void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
                            const SkPaint&);
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index 44b8791..3d5d43b 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -159,6 +159,8 @@
                             const SkPoint[], const SkPaint& paint) = 0;
     virtual void drawRect(const SkDraw&, const SkRect& r,
                           const SkPaint& paint) = 0;
+    virtual void drawRegion(const SkDraw&, const SkRegion& r,
+                            const SkPaint& paint);
     virtual void drawOval(const SkDraw&, const SkRect& oval,
                           const SkPaint& paint) = 0;
     /** By the time this is called we know that abs(sweepAngle) is in the range [0, 360). */
diff --git a/include/private/SkRecords.h b/include/private/SkRecords.h
index 637a2ef..09961ce 100644
--- a/include/private/SkRecords.h
+++ b/include/private/SkRecords.h
@@ -75,6 +75,7 @@
     M(DrawTextRSXform)                                              \
     M(DrawRRect)                                                    \
     M(DrawRect)                                                     \
+    M(DrawRegion)                                                   \
     M(DrawTextBlob)                                                 \
     M(DrawAtlas)                                                    \
     M(DrawVertices)                                                 \
@@ -292,6 +293,9 @@
 RECORD(DrawRect, kDraw_Tag|kHasPaint_Tag,
         SkPaint paint;
         SkRect rect);
+RECORD(DrawRegion, kDraw_Tag|kHasPaint_Tag,
+        SkPaint paint;
+        SkRegion region);
 RECORD(DrawText, kDraw_Tag|kHasText_Tag|kHasPaint_Tag,
         SkPaint paint;
         PODArray<char> text;
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 8f9a576..4cf40e9 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -2250,6 +2250,26 @@
     }
 }
 
+void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
+    SkRect storage;
+    SkRect regionRect = SkRect::Make(region.getBounds());
+    const SkRect* bounds = nullptr;
+    if (paint.canComputeFastBounds()) {
+        if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
+            return;
+        }
+        bounds = &regionRect;
+    }
+
+    LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
+
+    while (iter.next()) {
+        iter.fDevice->drawRegion(iter, region, looper.paint());
+    }
+
+    LOOPER_END
+}
+
 void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
     TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
     SkRect storage;
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 1f3bd61..8a9fa96 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -73,6 +73,29 @@
     return geo;
 }
 
+static inline bool is_int(float x) {
+    return x == (float) sk_float_round2int(x);
+}
+
+void SkBaseDevice::drawRegion(const SkDraw& draw, const SkRegion& region, const SkPaint& paint) {
+    bool isNonTranslate = draw.fMatrix->getType() & ~(SkMatrix::kTranslate_Mask);
+    bool complexPaint = paint.getStyle() != SkPaint::kFill_Style || paint.getMaskFilter() ||
+                        paint.getPathEffect();
+    bool antiAlias = paint.isAntiAlias() && (!is_int(draw.fMatrix->getTranslateX()) ||
+                                             !is_int(draw.fMatrix->getTranslateY()));
+    if (isNonTranslate || complexPaint || antiAlias) {
+        SkPath path;
+        region.getBoundaryPath(&path);
+        return this->drawPath(draw, path, paint, nullptr, false);
+    }
+
+    SkRegion::Iterator it(region);
+    while (!it.done()) {
+        this->drawRect(draw, SkRect::Make(it.rect()), paint);
+        it.next();
+    }
+}
+
 void SkBaseDevice::drawArc(const SkDraw& draw, const SkRect& oval, SkScalar startAngle,
                            SkScalar sweepAngle, bool useCenter, const SkPaint& paint) {
     SkPath path;
diff --git a/src/core/SkLiteDL.cpp b/src/core/SkLiteDL.cpp
index d94e139..af4f5c2 100644
--- a/src/core/SkLiteDL.cpp
+++ b/src/core/SkLiteDL.cpp
@@ -54,8 +54,8 @@
     M(Save) M(Restore) M(SaveLayer)                                             \
     M(Concat) M(SetMatrix) M(Translate) M(TranslateZ)                           \
     M(ClipPath) M(ClipRect) M(ClipRRect) M(ClipRegion)                          \
-    M(DrawPaint) M(DrawPath) M(DrawRect) M(DrawOval) M(DrawArc) M(DrawRRect)    \
-    M(DrawDRRect) M(DrawAnnotation) M(DrawDrawable) M(DrawPicture)              \
+    M(DrawPaint) M(DrawPath) M(DrawRect) M(DrawRegion) M(DrawOval) M(DrawArc)   \
+    M(DrawRRect) M(DrawDRRect) M(DrawAnnotation) M(DrawDrawable) M(DrawPicture) \
     M(DrawShadowedPicture)                                                      \
     M(DrawImage) M(DrawImageNine) M(DrawImageRect) M(DrawImageLattice)          \
     M(DrawText) M(DrawPosText) M(DrawPosTextH)                                  \
@@ -189,6 +189,13 @@
         SkPaint paint;
         void draw(SkCanvas* c, const SkMatrix&) { c->drawRect(rect, paint); }
     };
+    struct DrawRegion final : Op {
+        static const auto kType = Type::DrawRegion;
+        DrawRegion(const SkRegion& region, const SkPaint& paint) : region(region), paint(paint) {}
+        SkRegion region;
+        SkPaint  paint;
+        void draw(SkCanvas* c, const SkMatrix&) { c->drawRegion(region, paint); }
+    };
     struct DrawOval final : Op {
         static const auto kType = Type::DrawOval;
         DrawOval(const SkRect& oval, const SkPaint& paint) : oval(oval), paint(paint) {}
@@ -592,6 +599,9 @@
 void SkLiteDL::drawRect(const SkRect& rect, const SkPaint& paint) {
     this->push<DrawRect>(0, rect, paint);
 }
+void SkLiteDL::drawRegion(const SkRegion& region, const SkPaint& paint) {
+    this->push<DrawRegion>(0, region, paint);
+}
 void SkLiteDL::drawOval(const SkRect& oval, const SkPaint& paint) {
     this->push<DrawOval>(0, oval, paint);
 }
diff --git a/src/core/SkLiteDL.h b/src/core/SkLiteDL.h
index 4f28486..1549576 100644
--- a/src/core/SkLiteDL.h
+++ b/src/core/SkLiteDL.h
@@ -40,6 +40,7 @@
     void drawPaint (const SkPaint&);
     void drawPath  (const SkPath&, const SkPaint&);
     void drawRect  (const SkRect&, const SkPaint&);
+    void drawRegion(const SkRegion&, const SkPaint&);
     void drawOval  (const SkRect&, const SkPaint&);
     void drawArc   (const SkRect&, SkScalar, SkScalar, bool, const SkPaint&);
     void drawRRect (const SkRRect&, const SkPaint&);
diff --git a/src/core/SkLiteRecorder.cpp b/src/core/SkLiteRecorder.cpp
index 42218ac..262cdda 100644
--- a/src/core/SkLiteRecorder.cpp
+++ b/src/core/SkLiteRecorder.cpp
@@ -55,6 +55,9 @@
 void SkLiteRecorder::onDrawRect(const SkRect& rect, const SkPaint& paint) {
     fDL->drawRect(rect, paint);
 }
+void SkLiteRecorder::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
+    fDL->drawRegion(region, paint);
+}
 void SkLiteRecorder::onDrawOval(const SkRect& oval, const SkPaint& paint) {
     fDL->drawOval(oval, paint);
 }
diff --git a/src/core/SkLiteRecorder.h b/src/core/SkLiteRecorder.h
index c4e80cd..a1a273c 100644
--- a/src/core/SkLiteRecorder.h
+++ b/src/core/SkLiteRecorder.h
@@ -33,9 +33,10 @@
     void onClipRegion(const SkRegion&, SkRegion::Op) override;
 
     void onDrawPaint (const SkPaint&) override;
-    void onDrawPath  (const SkPath&,  const SkPaint&) override;
-    void onDrawRect  (const SkRect&,  const SkPaint&) override;
-    void onDrawOval  (const SkRect&,  const SkPaint&) override;
+    void onDrawPath  (const SkPath&, const SkPaint&) override;
+    void onDrawRect  (const SkRect&, const SkPaint&) override;
+    void onDrawRegion(const SkRegion&, const SkPaint&) override;
+    void onDrawOval  (const SkRect&, const SkPaint&) override;
     void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override;
     void onDrawRRect (const SkRRect&, const SkPaint&) override;
     void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index a5c607d..acd2d82 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -93,8 +93,9 @@
     DRAW_SHADOWED_PICTURE_LIGHTS,
     DRAW_IMAGE_LATTICE,
     DRAW_ARC,
+    DRAW_REGION,
 
-    LAST_DRAWTYPE_ENUM = DRAW_ARC
+    LAST_DRAWTYPE_ENUM = DRAW_REGION
 };
 
 // In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index 611b556..3df6422 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -469,6 +469,14 @@
                 canvas->drawRect(rect, *paint);
             }
         } break;
+        case DRAW_REGION: {
+            const SkPaint* paint = fPictureData->getPaint(reader);
+            SkRegion region;
+            reader->readRegion(&region);
+            if (paint) {
+                canvas->drawRegion(region, *paint);
+            }
+        } break;
         case DRAW_RRECT: {
             const SkPaint* paint = fPictureData->getPaint(reader);
             SkRRect rrect;
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index c461bfb..d771699 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -451,6 +451,16 @@
     this->validate(initialOffset, size);
 }
 
+void SkPictureRecord::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
+    // op + paint index + region
+    size_t regionBytes = region.writeToMemory(nullptr);
+    size_t size = 2 * kUInt32Size + regionBytes;
+    size_t initialOffset = this->addDraw(DRAW_REGION, &size);
+    this->addPaint(paint);
+    fWriter.writeRegion(region);
+    this->validate(initialOffset, size);
+}
+
 void SkPictureRecord::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
     // op + paint index + rrect
     size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index 5601d2a..ac8058b 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -186,6 +186,7 @@
     void onDrawPaint(const SkPaint&) override;
     void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
     void onDrawRect(const SkRect&, const SkPaint&) override;
+    void onDrawRegion(const SkRegion&, const SkPaint&) override;
     void onDrawOval(const SkRect&, const SkPaint&) override;
     void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override;
     void onDrawRRect(const SkRRect&, const SkPaint&) override;
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 5b4bc6a..6545586 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -128,6 +128,7 @@
 DRAW(DrawPosTextH, drawPosTextH(r.text, r.byteLength, r.xpos, r.y, r.paint));
 DRAW(DrawRRect, drawRRect(r.rrect, r.paint));
 DRAW(DrawRect, drawRect(r.rect, r.paint));
+DRAW(DrawRegion, drawRegion(r.region, r.paint));
 DRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint));
 DRAW(DrawTextBlob, drawTextBlob(r.blob.get(), r.x, r.y, r.paint));
 DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, &r.matrix, r.paint));
@@ -413,6 +414,10 @@
     Bounds bounds(const NoOp&)  const { return Bounds::MakeEmpty(); }    // NoOps don't draw.
 
     Bounds bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect, &op.paint); }
+    Bounds bounds(const DrawRegion& op) const {
+        SkRect rect = SkRect::Make(op.region.getBounds());
+        return this->adjustAndMap(rect, &op.paint);
+    }
     Bounds bounds(const DrawOval& op) const { return this->adjustAndMap(op.oval, &op.paint); }
     // Tighter arc bounds?
     Bounds bounds(const DrawArc& op) const { return this->adjustAndMap(op.oval, &op.paint); }
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 214b075..840e19b 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -145,6 +145,10 @@
     APPEND(DrawRect, paint, rect);
 }
 
+void SkRecorder::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
+    APPEND(DrawRegion, paint, region);
+}
+
 void SkRecorder::onDrawOval(const SkRect& oval, const SkPaint& paint) {
     APPEND(DrawOval, paint, oval);
 }
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index 6892894..3ab958b 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -105,6 +105,7 @@
     void onDrawPaint(const SkPaint&) override;
     void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
     void onDrawRect(const SkRect&, const SkPaint&) override;
+    void onDrawRegion(const SkRegion&, const SkPaint&) override;
     void onDrawOval(const SkRect&, const SkPaint&) override;
     void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override;
     void onDrawRRect(const SkRRect&, const SkPaint&) override;