work on raster device clipping
authorMike Reed <reed@google.com>
Tue, 14 Feb 2017 19:25:14 +0000 (14:25 -0500)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Tue, 14 Feb 2017 20:07:08 +0000 (20:07 +0000)
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>
include/core/SkCanvas.h
src/core/SkBitmapDevice.cpp
src/core/SkBitmapDevice.h
src/core/SkCanvas.cpp
src/core/SkDevice.cpp
src/core/SkDevice.h
src/core/SkRasterClipStack.h [new file with mode: 0644]

index 193d1afd69abd3eadb85adbefa10e52280b70d8b..9d6614fffa397dcf3e939237a811cf1873c5b9be 100644 (file)
@@ -1537,8 +1537,8 @@ private:
     static SaveLayerFlags LegacySaveFlagsToSaveLayerFlags(uint32_t legacySaveFlags);
 
     static void 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);
 
     enum ShaderOverrideOpacity {
         kNone_ShaderOverrideOpacity,        //!< there is no overriding shader (bitmap or image)
index 45ec2b70ae23ecca221f9528b0a918f0d9fcbf0f..5742e1d0a3aa05f196ac4d750a118eebb409ff12 100644 (file)
@@ -71,11 +71,10 @@ static bool valid_for_bitmap_device(const SkImageInfo& info,
 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap)
     : INHERITED(bitmap.info(), SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType))
     , fBitmap(bitmap)
+    , fRCStack(bitmap.width(), bitmap.height())
 {
     SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
     fBitmap.lockPixels();
-
-    fRCStack.push_back().setRect(SkIRect::MakeWH(bitmap.width(), bitmap.height()));
 }
 
 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& info) {
@@ -87,11 +86,10 @@ SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& sur
     : INHERITED(bitmap.info(), surfaceProps)
     , fBitmap(bitmap)
     , fRasterHandle(hndl)
+    , fRCStack(bitmap.width(), bitmap.height())
 {
     SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
     fBitmap.lockPixels();
-
-    fRCStack.push_back().setRect(SkIRect::MakeWH(bitmap.width(), bitmap.height()));
 }
 
 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
@@ -137,6 +135,8 @@ void SkBitmapDevice::setNewSize(const SkISize& size) {
     SkASSERT(!fBitmap.pixelRef());
     fBitmap.setInfo(fBitmap.info().makeWH(size.fWidth, size.fHeight));
     this->privateResize(fBitmap.info().width(), fBitmap.info().height());
+
+    fRCStack.setNewSize(size.fWidth, size.fHeight);
 }
 
 void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
@@ -191,17 +191,35 @@ bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, s
 
 ///////////////////////////////////////////////////////////////////////////////
 
+#ifdef SK_USE_DEVICE_CLIPPING
+class ModifiedDraw : public SkDraw {
+public:
+    ModifiedDraw(const SkMatrix& devCTM, const SkRasterClip& rc, SkISize rcs,
+                 const SkDraw& draw) : SkDraw(draw) {
+#ifdef SK_DEBUG
+        SkISize dvs = { draw.fDevice->width(), draw.fDevice->height() };
+        SkASSERT(dvs == rcs);
+        SkASSERT(devCTM == *draw.fMatrix);
+#endif
+        fRC = &rc;
+    }
+};
+#define PREPARE_DRAW(draw)  ModifiedDraw(this->ctm(), fRCStack.rc(), fRCStack.getRootSize(), draw)
+#else
+#define PREPARE_DRAW(draw)  draw
+#endif
+
 void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
-    draw.drawPaint(paint);
+    PREPARE_DRAW(draw).drawPaint(paint);
 }
 
 void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
                                 const SkPoint pts[], const SkPaint& paint) {
-    draw.drawPoints(mode, count, pts, paint);
+    PREPARE_DRAW(draw).drawPoints(mode, count, pts, paint);
 }
 
 void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
-    draw.drawRect(r, paint);
+    PREPARE_DRAW(draw).drawRect(r, paint);
 }
 
 void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
@@ -221,20 +239,20 @@ void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const S
     // required to override drawRRect.
     this->drawPath(draw, path, paint, nullptr, true);
 #else
-    draw.drawRRect(rrect, paint);
+    PREPARE_DRAW(draw).drawRRect(rrect, paint);
 #endif
 }
 
 void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
                               const SkPaint& paint, const SkMatrix* prePathMatrix,
                               bool pathIsMutable) {
-    draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
+    PREPARE_DRAW(draw).drawPath(path, paint, prePathMatrix, pathIsMutable);
 }
 
 void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
                                 const SkMatrix& matrix, const SkPaint& paint) {
     LogDrawScaleFactor(SkMatrix::Concat(*draw.fMatrix, matrix), paint.getFilterQuality());
-    draw.drawBitmap(bitmap, matrix, nullptr, paint);
+    PREPARE_DRAW(draw).drawBitmap(bitmap, matrix, nullptr, paint);
 }
 
 static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) {
@@ -323,7 +341,7 @@ void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
         // matrix with the CTM, and try to call drawSprite if it can. If not,
         // it will make a shader and call drawRect, as we do below.
         if (CanApplyDstMatrixAsCTM(matrix, paint)) {
-            draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
+            PREPARE_DRAW(draw).drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
             return;
         }
     }
@@ -353,18 +371,18 @@ void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
 
 void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
                                 int x, int y, const SkPaint& paint) {
-    draw.drawSprite(bitmap, x, y, paint);
+    PREPARE_DRAW(draw).drawSprite(bitmap, x, y, paint);
 }
 
 void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
                               SkScalar x, SkScalar y, const SkPaint& paint) {
-    draw.drawText((const char*)text, len, x, y, paint);
+    PREPARE_DRAW(draw).drawText((const char*)text, len, x, y, paint);
 }
 
 void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
                                  const SkScalar xpos[], int scalarsPerPos,
                                  const SkPoint& offset, const SkPaint& paint) {
-    draw.drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint);
+    PREPARE_DRAW(draw).drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint);
 }
 
 void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
@@ -373,14 +391,14 @@ void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode
                                   const SkColor colors[], SkBlendMode bmode,
                                   const uint16_t indices[], int indexCount,
                                   const SkPaint& paint) {
-    draw.drawVertices(vmode, vertexCount, verts, textures, colors, bmode,
+    PREPARE_DRAW(draw).drawVertices(vmode, vertexCount, verts, textures, colors, bmode,
                       indices, indexCount, paint);
 }
 
 void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
                                 int x, int y, const SkPaint& paint) {
     SkASSERT(!paint.getImageFilter());
-    draw.drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint);
+    PREPARE_DRAW(draw).drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -459,28 +477,44 @@ bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const {
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 void SkBitmapDevice::onSave() {
-    fRCStack.push_back(fRCStack.back());
+    fRCStack.save();
 }
 
 void SkBitmapDevice::onRestore() {
-    fRCStack.pop_back();
+    fRCStack.restore();
 }
 
 void SkBitmapDevice::onClipRect(const SkRect& rect, SkClipOp op, bool aa) {
-    fRCStack.back().op(rect, this->ctm(), SkIRect::MakeWH(this->width(), this->height()),
-                       (SkRegion::Op)op, aa);
+    fRCStack.clipRect(this->ctm(), rect, op, aa);
 }
 
 void SkBitmapDevice::onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) {
-    fRCStack.back().op(rrect, this->ctm(), SkIRect::MakeWH(this->width(), this->height()),
-                       (SkRegion::Op)op, aa);
+    fRCStack.clipRRect(this->ctm(), rrect, op, aa);
 }
 
 void SkBitmapDevice::onClipPath(const SkPath& path, SkClipOp op, bool aa) {
-    fRCStack.back().op(path, this->ctm(), SkIRect::MakeWH(this->width(), this->height()),
-                       (SkRegion::Op)op, aa);
+    fRCStack.clipPath(this->ctm(), path, op, aa);
 }
 
 void SkBitmapDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) {
-    fRCStack.back().op(rgn, (SkRegion::Op)op);
+    SkIPoint origin = this->getOrigin();
+    SkRegion tmp;
+    const SkRegion* ptr = &rgn;
+    if (origin.fX | origin.fY) {
+        // translate from "global/canvas" coordinates to relative to this device
+        rgn.translate(-origin.fX, -origin.fY, &tmp);
+        ptr = &tmp;
+    }
+    fRCStack.clipRegion(*ptr, op);
+}
+
+void SkBitmapDevice::onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) {
+    fRCStack.setDeviceClipRestriction(mutableClipRestriction);
+}
+
+void SkBitmapDevice::validateDevBounds(const SkIRect& drawClipBounds) {
+#ifdef SK_DEBUG
+    const SkIRect& stackBounds = fRCStack.rc().getBounds();
+    SkASSERT(drawClipBounds == stackBounds);
+#endif
 }
index 0a6471080bf3dd675daf282870908c7bfa1fbd28..266b2d9513c4e329cc99e6896283f3b1b210c976 100644 (file)
@@ -15,6 +15,7 @@
 #include "SkImageInfo.h"
 #include "SkPixelRef.h"
 #include "SkRasterClip.h"
+#include "SkRasterClipStack.h"
 #include "SkRect.h"
 #include "SkScalar.h"
 #include "SkSize.h"
@@ -132,6 +133,8 @@ protected:
     void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override;
     void onClipPath(const SkPath& path, SkClipOp, bool aa) override;
     void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override;
+    void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override;
+    void validateDevBounds(const SkIRect& r) override;
 
 private:
     friend class SkCanvas;
@@ -155,7 +158,7 @@ private:
 
     SkBitmap    fBitmap;
     void*       fRasterHandle = nullptr;
-    SkTArray<SkRasterClip>  fRCStack;
+    SkRasterClipStack  fRCStack;
 
     void setNewSize(const SkISize&);  // Used by SkCanvas for resetForNextPicture().
 
index 562e0ae60612ec1b60ddee2faf7b7a2b03fdb94d..0c6f241e9749f3b8d0c60f9d6e092c308979ae37 100644 (file)
@@ -230,12 +230,17 @@ struct DeviceCM {
             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 @@ private:
         DeviceCM* layer = fMCRec->fTopLayer;        \
         while (layer) {                             \
             SkBaseDevice* device = layer->fDevice;  \
-            code;                                   \
+            if (device) {                           \
+                code;                               \
+            }                                       \
             layer = layer->fNext;                   \
         }                                           \
     } while (0)
@@ -694,6 +701,10 @@ SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
         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 @@ public:
     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 @@ void SkCanvas::doSave() {
     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 @@ void SkCanvas::restore() {
             fSaveCount -= 1;
             this->internalRestore();
             this->didRestore();
-#ifdef SK_USE_DEVICE_CLIPPING
-            FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
-#endif
         }
     }
 }
@@ -1049,6 +1054,9 @@ void SkCanvas::internalSave() {
     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 @@ int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
 }
 
 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 @@ void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filt
     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 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra
     }
 
     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 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra
             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 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra
     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 @@ void SkCanvas::internalRestore() {
     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 @@ void SkCanvas::translate(SkScalar dx, SkScalar dy) {
         // 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 @@ void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
     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 @@ void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
     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);
index 07b9c233739d1294e6c7500f8f3adb8cfb24e6b5..803cddd543c59867fe3fe7c4be51cfa1443143ee 100644 (file)
@@ -32,10 +32,24 @@ SkBaseDevice::SkBaseDevice(const SkImageInfo& info, const SkSurfaceProps& surfac
     , fSurfaceProps(surfaceProps)
 {
     fOrigin.setZero();
+    fCTM.reset();
 }
 
 SkBaseDevice::~SkBaseDevice() {}
 
+void SkBaseDevice::setOrigin(const SkMatrix& globalCTM, int x, int y) {
+    fOrigin.set(x, y);
+    fCTM = globalCTM;
+    fCTM.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
+}
+
+void SkBaseDevice::setGlobalCTM(const SkMatrix& ctm) {
+    fCTM = ctm;
+    if (fOrigin.fX | fOrigin.fY) {
+        fCTM.postTranslate(-SkIntToScalar(fOrigin.fX), -SkIntToScalar(fOrigin.fY));
+    }
+}
+
 SkPixelGeometry SkBaseDevice::CreateInfo::AdjustGeometry(const SkImageInfo& info,
                                                          TileUsage tileUsage,
                                                          SkPixelGeometry geo,
@@ -519,6 +533,10 @@ void SkBaseDevice::drawTextRSXform(const SkDraw& draw, const void* text, size_t
         localM.setRSXform(*xform++);
         currM.setConcat(*draw.fMatrix, localM);
         localD.fMatrix = &currM;
+#ifdef SK_USE_DEVICE_CLIPPING
+        SkAutoDeviceCTMRestore adc(this, currM);
+#endif
+
         int subLen = proc((const char*)text);
         this->drawText(localD, text, subLen, 0, 0, paint);
         text = (const char*)text + subLen;
index 3c0b7785d301757131896fccfd9135433b7f192f..3d1b558eabaf7c1d8db7af98d15e34f354801459 100644 (file)
@@ -121,18 +121,17 @@ public:
     void clipRegion(const SkRegion& region, SkClipOp op) {
         this->onClipRegion(region, op);
     }
+    void androidFramework_setDeviceClipRestriction(SkIRect* mutableClipRestriction) {
+        this->onSetDeviceClipRestriction(mutableClipRestriction);
+    }
 
     const SkMatrix& ctm() const { return fCTM; }
     void setCTM(const SkMatrix& ctm) {
         fCTM = ctm;
     }
-    void setGlobalCTM(const SkMatrix& ctm) {
-        fCTM = ctm;
-        if (fOrigin.fX | fOrigin.fY) {
-            fCTM.postTranslate(-SkIntToScalar(fOrigin.fX), -SkIntToScalar(fOrigin.fY));
-        }
-    }
-    
+    void setGlobalCTM(const SkMatrix& ctm);
+    virtual void validateDevBounds(const SkIRect&) {}
+
 protected:
     enum TileUsage {
         kPossible_TileUsage,    //!< the created device may be drawn tiled
@@ -157,6 +156,7 @@ protected:
     virtual void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) {}
     virtual void onClipPath(const SkPath& path, SkClipOp, bool aa) {}
     virtual void onClipRegion(const SkRegion& deviceRgn, SkClipOp) {}
+    virtual void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) {}
 
     /** These are called inside the per-device-layer loop for each draw call.
      When these are called, we have already applied any saveLayer operations,
@@ -367,7 +367,7 @@ private:
     virtual GrRenderTargetContext* accessRenderTargetContext() { return nullptr; }
 
     // just called by SkCanvas when built as a layer
-    void setOrigin(int x, int y) { fOrigin.set(x, y); }
+    void setOrigin(const SkMatrix& ctm, int x, int y);
 
     /** Causes any deferred drawing to the device to be completed.
      */
@@ -392,4 +392,21 @@ private:
     typedef SkRefCnt INHERITED;
 };
 
+class SkAutoDeviceCTMRestore : SkNoncopyable {
+public:
+    SkAutoDeviceCTMRestore(SkBaseDevice* device, const SkMatrix& ctm)
+        : fDevice(device)
+        , fPrevCTM(device->ctm())
+    {
+        fDevice->setCTM(ctm);
+    }
+    ~SkAutoDeviceCTMRestore() {
+        fDevice->setCTM(fPrevCTM);
+    }
+
+private:
+    SkBaseDevice*   fDevice;
+    const SkMatrix  fPrevCTM;
+};
+
 #endif
diff --git a/src/core/SkRasterClipStack.h b/src/core/SkRasterClipStack.h
new file mode 100644 (file)
index 0000000..f606259
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkRasterClipStack_DEFINED
+#define SkRasterClipStack_DEFINED
+
+#include "SkDeque.h"
+#include "SkRasterClip.h"
+
+template <typename T> class SkTStack {
+public:
+    SkTStack(void* storage, size_t size) : fDeque(sizeof(T), storage, size), fTop(nullptr) {}
+    ~SkTStack() {
+        while (!fDeque.empty()) {
+            ((T*)fDeque.back())->~T();
+            fDeque.pop_back();
+        }
+    }
+
+    bool empty() const { return fDeque.empty(); }
+
+    int count() const { return fDeque.count(); }
+
+    const T& top() const {
+        SkASSERT(fTop);
+        return *fTop;
+    }
+
+    T& top() {
+        SkASSERT(fTop);
+        return *fTop;
+    }
+
+    T* push_raw() { return (T*)fDeque.push_back(); }
+    T& push() {
+        fTop = this->push_raw();
+        new (fTop) T();
+        return *fTop;
+    }
+    T& push(const T& src) {
+        fTop = this->push_raw();
+        new (fTop) T(src);
+        return *fTop;
+    }
+
+    void pop() {
+        fTop->~T();
+        fDeque.pop_back();
+        fTop = fDeque.empty() ? nullptr : (T*)fDeque.back();
+    }
+
+private:
+    SkDeque fDeque;
+    T*      fTop;
+};
+
+class SkRasterClipStack : SkNoncopyable {
+    int fCounter = 0;
+public:
+    SkRasterClipStack(int width, int height)
+        : fStack(fStorage, sizeof(fStorage))
+        , fRootBounds(SkIRect::MakeWH(width, height))
+    {
+        Rec& rec = fStack.push();
+        rec.fRC.setRect(fRootBounds);
+        rec.fDeferredCount = 0;
+        SkASSERT(fStack.count() == 1);
+    }
+
+    void setNewSize(int w, int h) {
+        SkASSERT(fStack.count() == 1);
+        fRootBounds.setXYWH(0, 0, w, h);
+    }
+
+    SkISize getRootSize() const { return fRootBounds.size(); }
+
+    const SkRasterClip& rc() const { return fStack.top().fRC; }
+
+    void save() {
+        fCounter += 1;
+        SkASSERT(fStack.top().fDeferredCount >= 0);
+        fStack.top().fDeferredCount += 1;
+    }
+
+    void restore() {
+        fCounter -= 1; SkASSERT(fCounter >= 0);
+        if (--fStack.top().fDeferredCount < 0) {
+            SkASSERT(fStack.top().fDeferredCount == -1);
+            SkASSERT(fStack.count() > 1);
+            fStack.pop();
+        }
+    }
+
+    void clipRect(const SkMatrix& ctm, const SkRect& rect, SkClipOp op, bool aa) {
+        this->writable_rc().op(rect, ctm, fRootBounds, (SkRegion::Op)op, aa);
+        this->trimIfExpanding(op);
+        this->validate();
+    }
+
+    void clipRRect(const SkMatrix& ctm, const SkRRect& rrect, SkClipOp op, bool aa) {
+        this->writable_rc().op(rrect, ctm, fRootBounds, (SkRegion::Op)op, aa);
+        this->trimIfExpanding(op);
+        this->validate();
+    }
+
+    void clipPath(const SkMatrix& ctm, const SkPath& path, SkClipOp op, bool aa) {
+        this->writable_rc().op(path, ctm, fRootBounds, (SkRegion::Op)op, aa);
+        this->trimIfExpanding(op);
+        this->validate();
+    }
+
+    void clipRegion(const SkRegion& rgn, SkClipOp op) {
+        this->writable_rc().op(rgn, (SkRegion::Op)op);
+        this->trimIfExpanding(op);
+        this->validate();
+    }
+
+    void setDeviceClipRestriction(SkIRect* mutableClipRestriction) {
+        this->writable_rc().setDeviceClipRestriction(mutableClipRestriction);
+    }
+
+    void validate() const {
+#ifdef SK_DEBUG
+        const SkRasterClip& clip = this->rc();
+        if (fRootBounds.isEmpty()) {
+            SkASSERT(clip.isEmpty());
+        } else if (!clip.isEmpty()) {
+            SkASSERT(fRootBounds.contains(clip.getBounds()));
+        }
+#endif
+    }
+
+private:
+    struct Rec {
+        SkRasterClip    fRC;
+        int             fDeferredCount; // 0 for a "normal" entry
+    };
+
+    enum {
+        ELEM_COUNT = 16,
+        PTR_COUNT = ELEM_COUNT * sizeof(Rec) / sizeof(void*)
+    };
+    void*           fStorage[PTR_COUNT];
+    SkTStack<Rec>   fStack;
+    SkIRect         fRootBounds;
+
+    SkRasterClip& writable_rc() {
+        SkASSERT(fStack.top().fDeferredCount >= 0);
+        if (fStack.top().fDeferredCount > 0) {
+            fStack.top().fDeferredCount -= 1;
+            fStack.push(fStack.top());
+            fStack.top().fDeferredCount = 0;
+        }
+        return fStack.top().fRC;
+    }
+
+    void trimIfExpanding(SkClipOp op) {
+        if ((int)op > (int)SkClipOp::kIntersect) {
+            Rec& rec = fStack.top();
+            SkASSERT(rec.fDeferredCount == 0);
+            rec.fRC.op(fRootBounds, SkRegion::kIntersect_Op);
+        }
+    }
+};
+
+#endif