work on raster device clipping

With the flag (SkDevice.h) enabled, I get correct drawing w/ the rasterbackend.

After this lands, hopefully we can work in parallel on gpu/pdf/svg/xps/etc.

BUG=skia:6214

Change-Id: Ie35fee818470aab57aebacca8a2a5b812a552ee2
Reviewed-on: https://skia-review.googlesource.com/8192
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 562e0ae..0c6f241 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -230,12 +230,17 @@
             fMatrixStorage.postTranslate(SkIntToScalar(-x),
                                          SkIntToScalar(-y));
             fMatrix = &fMatrixStorage;
-
             totalClip.translate(-x, -y, &fClip);
         }
 
         fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
 
+#ifdef SK_USE_DEVICE_CLIPPING
+        SkASSERT(*fMatrix == fDevice->ctm());
+        // TODO: debug tiles-rt-8888 so we can enable this all the time
+//        fDevice->validateDevBounds(fClip.getBounds());
+#endif
+
         // intersect clip, but don't translate it (yet)
 
         if (updateClip) {
@@ -392,7 +397,9 @@
         DeviceCM* layer = fMCRec->fTopLayer;        \
         while (layer) {                             \
             SkBaseDevice* device = layer->fDevice;  \
-            code;                                   \
+            if (device) {                           \
+                code;                               \
+            }                                       \
             layer = layer->fNext;                   \
         }                                           \
     } while (0)
@@ -694,6 +701,10 @@
         fMCRec->fLayer->fDevice = SkRef(device);
         fMCRec->fRasterClip.setRect(device->getGlobalBounds());
         fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
+
+#ifdef SK_USE_DEVICE_CLIPPING
+        device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
+#endif
     }
 
     return device;
@@ -720,7 +731,7 @@
     SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
         : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
     {
-        this->setOrigin(bounds.x(), bounds.y());
+        this->setOrigin(SkMatrix::I(), bounds.x(), bounds.y());
     }
 
 private:
@@ -1006,9 +1017,6 @@
     SkASSERT(fMCRec->fDeferredSaveCount > 0);
     fMCRec->fDeferredSaveCount -= 1;
     this->internalSave();
-#ifdef SK_USE_DEVICE_CLIPPING
-    FOR_EACH_TOP_DEVICE(device->save());
-#endif
 }
 
 void SkCanvas::restore() {
@@ -1024,9 +1032,6 @@
             fSaveCount -= 1;
             this->internalRestore();
             this->didRestore();
-#ifdef SK_USE_DEVICE_CLIPPING
-            FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
-#endif
         }
     }
 }
@@ -1049,6 +1054,9 @@
     fMCRec = newTop;
 
     fClipStack->save();
+#ifdef SK_USE_DEVICE_CLIPPING
+    FOR_EACH_TOP_DEVICE(device->save());
+#endif
 }
 
 bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
@@ -1123,8 +1131,8 @@
 }
 
 void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
-                                    SkBaseDevice* dst, const SkMatrix& ctm,
-                                    const SkClipStack* clipStack) {
+                                    SkBaseDevice* dst, const SkIPoint& dstOrigin,
+                                    const SkMatrix& ctm, const SkClipStack* clipStack) {
     SkDraw draw;
     SkRasterClip rc;
     rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
@@ -1139,8 +1147,8 @@
     SkPaint p;
     p.setImageFilter(filter->makeWithLocalMatrix(ctm));
 
-    int x = src->getOrigin().x() - dst->getOrigin().x();
-    int y = src->getOrigin().y() - dst->getOrigin().y();
+    int x = src->getOrigin().x() - dstOrigin.x();
+    int y = src->getOrigin().y() - dstOrigin.y();
     auto special = src->snapSpecial();
     if (special) {
         dst->drawSpecial(draw, special.get(), x, y, p);
@@ -1231,7 +1239,7 @@
     }
 
     SkBaseDevice* priorDevice = this->getTopDevice();
-    if (nullptr == priorDevice) {
+    if (nullptr == priorDevice) {   // Do we still need this check???
         SkDebugf("Unable to find device for layer.");
         return;
     }
@@ -1252,7 +1260,9 @@
             return;
         }
     }
-    newDevice->setOrigin(ir.fLeft, ir.fTop);
+#ifndef SK_USE_DEVICE_CLIPPING
+    newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
+#endif
 
     DeviceCM* layer =
             new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
@@ -1263,9 +1273,24 @@
     fMCRec->fTopLayer = layer;    // this field is NOT an owner of layer
 
     if (rec.fBackdrop) {
-        DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(),
+        DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
                              fMCRec->fMatrix, this->getClipStack());
     }
+
+#ifdef SK_USE_DEVICE_CLIPPING
+    newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
+
+    newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
+    if (layer->fNext) {
+        // need to punch a hole in the previous device, so we don't draw there, given that
+        // the new top-layer will allow drawing to happen "below" it.
+        SkRegion hole(ir);
+        do {
+            layer = layer->fNext;
+            layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
+        } while (layer->fNext);
+    }
+#endif
 }
 
 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
@@ -1295,6 +1320,12 @@
     fMCStack.pop_back();
     fMCRec = (MCRec*)fMCStack.back();
 
+#ifdef SK_USE_DEVICE_CLIPPING
+    if (fMCRec) {
+        FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
+    }
+#endif
+
     /*  Time to draw the layer's offscreen. We can't call the public drawSprite,
         since if we're being recorded, we don't want to record this (the
         recorder will have already recorded the restore).
@@ -1433,6 +1464,10 @@
         // Translate shouldn't affect the is-scale-translateness of the matrix.
         SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
 
+#ifdef SK_USE_DEVICE_CLIPPING
+        FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
+#endif
+
         this->didTranslate(dx,dy);
     }
 }
@@ -1482,6 +1517,10 @@
     fDeviceCMDirty = true;
     fMCRec->fMatrix = matrix;
     fIsScaleTranslate = matrix.isScaleTranslate();
+
+#ifdef SK_USE_DEVICE_CLIPPING
+    FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
+#endif
 }
 
 void SkCanvas::setMatrix(const SkMatrix& matrix) {
@@ -1542,6 +1581,10 @@
     fClipStack->setDeviceClipRestriction(fClipRestrictionRect);
     if (!fClipRestrictionRect.isEmpty()) {
         this->checkForDeferredSave();
+#ifdef SK_USE_DEVICE_CLIPPING
+        SkRegion restrictRgn(fClipRestrictionRect);
+        FOR_EACH_TOP_DEVICE(device->clipRegion(restrictRgn, SkClipOp::kIntersect));
+#endif
         AutoValidateClip avc(this);
         fClipStack->clipDevRect(fClipRestrictionRect, kIntersect_SkClipOp);
         fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);