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/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;