Added SkDevice onAttachToCanvas & onDetachFromCanvas methods
authorrobertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 13 Jul 2012 15:36:15 +0000 (15:36 +0000)
committerrobertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 13 Jul 2012 15:36:15 +0000 (15:36 +0000)
http://codereview.appspot.com/6348100/

git-svn-id: http://skia.googlecode.com/svn/trunk@4598 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkCanvas.h
include/core/SkDevice.h
include/gpu/SkGpuDevice.h
include/pdf/SkPDFDevice.h
include/utils/SkDeferredCanvas.h
src/core/SkCanvas.cpp
src/core/SkDevice.cpp
src/gpu/SkGpuDevice.cpp
src/pdf/SkPDFDevice.cpp

index fc95f9a..8fa73f6 100644 (file)
@@ -888,6 +888,15 @@ public:
      */
     const SkRegion& getTotalClip() const;
 
+    /** Return the clip stack. The clip stack stores all the individual
+     *  clips organized by the save/restore frame in which they were
+     *  added.
+     *  @return the current clip stack ("list" of individual clip elements)
+     */
+    const SkClipStack* getClipStack() const {
+        return &fClipStack;
+    }
+
     void setExternalMatrix(const SkMatrix* = NULL);
 
     class ClipVisitor {
@@ -973,8 +982,7 @@ private:
     SkDevice*   fLastDeviceToGainFocus;
     int         fSaveLayerCount;    // number of successful saveLayer calls
 
-    void prepareForDeviceDraw(SkDevice*, const SkMatrix&, const SkRegion&,
-                              const SkClipStack& clipStack);
+    void prepareForDeviceDraw(SkDevice*, const SkMatrix&, const SkRegion&);
 
     bool fDeviceCMDirty;            // cleared by updateDeviceCMCache()
     void updateDeviceCMCache();
index 184fb6f..5cf5c50 100644 (file)
@@ -138,6 +138,32 @@ public:
      */
     const SkIPoint& getOrigin() const { return fOrigin; }
 
+    /** 
+     * onAttachToCanvas is invoked whenever a device is installed in a canvas
+     * (i.e., setDevice, saveLayer (for the new device created by the save),
+     * and SkCanvas' SkDevice & SkBitmap -taking ctors). It allows the 
+     * devices to prepare for drawing (e.g., locking their pixels, etc.)
+     */
+    virtual void onAttachToCanvas(SkCanvas* canvas) {
+        this->lockPixels();
+#ifdef SK_DEBUG
+        fAttachedToCanvas = true;
+#endif
+    };
+
+    /**
+     * onDetachFromCanvas notifies a device that it will no longer be drawn to.
+     * It gives the device a chance to clean up (e.g., unlock its pixels). It
+     * is invoked from setDevice (for the displaced device), restore and 
+     * possibly from SkCanvas' dtor.
+     */
+    virtual void onDetachFromCanvas() {
+        this->unlockPixels();
+#ifdef SK_DEBUG
+        fAttachedToCanvas = false;
+#endif
+    };
+
 protected:
     enum Usage {
        kGeneral_Usage,
@@ -177,8 +203,9 @@ protected:
     /** Called when this device gains focus (i.e becomes the current device
         for drawing).
     */
-    virtual void gainFocus(SkCanvas*, const SkMatrix&, const SkRegion&,
-                           const SkClipStack&) {}
+    virtual void gainFocus(const SkMatrix&, const SkRegion&) {
+        SkASSERT(fAttachedToCanvas);
+    }
 
     /** Clears the entire device to the specified color (including alpha).
      *  Ignores the clip.
@@ -376,6 +403,10 @@ private:
     SkIPoint    fOrigin;
     SkMetaData* fMetaData;
 
+#ifdef SK_DEBUG
+    bool        fAttachedToCanvas;
+#endif
+
     typedef SkRefCnt INHERITED;
 };
 
index 40444a9..2390cdb 100644 (file)
@@ -55,8 +55,7 @@ public:
      *  Override from SkGpuDevice, so we can set our FBO to be the render target
      *  The canvas parameter must be a SkGpuCanvas
      */
-    virtual void gainFocus(SkCanvas*, const SkMatrix&, const SkRegion&,
-                           const SkClipStack& clipStack) SK_OVERRIDE;
+    virtual void gainFocus(const SkMatrix&, const SkRegion&) SK_OVERRIDE;
 
     virtual SkGpuRenderTarget* accessRenderTarget() SK_OVERRIDE;
 
@@ -101,6 +100,9 @@ public:
 
     virtual void flush();
 
+    virtual void onAttachToCanvas(SkCanvas* canvas) SK_OVERRIDE;
+    virtual void onDetachFromCanvas() SK_OVERRIDE;
+
     /**
      * Make's this device's rendertarget current in the underlying 3D API.
      * Also implicitly flushes.
@@ -131,6 +133,9 @@ private:
 
     GrSkDrawProcs*  fDrawProcs;
 
+    // the clip stack - on loan to us from SkCanvas so it can be NULL.
+    const SkClipStack*  fClipStack;
+
     // state for our offscreen render-target
     TexCache            fCache;
     GrTexture*          fTexture;
index 354729d..589cde9 100644 (file)
@@ -100,6 +100,9 @@ public:
     virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
                             const SkPaint&) SK_OVERRIDE;
 
+    virtual void onAttachToCanvas(SkCanvas* canvas) SK_OVERRIDE;
+    virtual void onDetachFromCanvas() SK_OVERRIDE;
+
     enum DrawingArea {
         kContent_DrawingArea,  // Drawing area for the page content.
         kMargin_DrawingArea,   // Drawing area for the margin content.
@@ -190,6 +193,8 @@ private:
     ContentEntry* fLastMarginContentEntry;
     DrawingArea fDrawingArea;
 
+    const SkClipStack* fClipStack;
+
     // Accessor and setter functions based on the current DrawingArea.
     SkTScopedPtr<ContentEntry>* getContentEntries();
     ContentEntry* getLastContentEntry();
@@ -258,9 +263,7 @@ private:
      */
     void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const;
 
-    // Disable the default copy and assign implementation.
-    SkPDFDevice(const SkPDFDevice&);
-    void operator=(const SkPDFDevice&);
+    typedef SkDevice INHERITED;
 };
 
 #endif
index dd2c1f0..8964e9e 100644 (file)
@@ -221,9 +221,6 @@ public:
         virtual void setMatrixClip(const SkMatrix&, const SkRegion&,
                                    const SkClipStack&) SK_OVERRIDE
             {}
-        virtual void gainFocus(SkCanvas*, const SkMatrix&, const SkRegion&,
-                               const SkClipStack&) SK_OVERRIDE
-            {}
 
         // None of the following drawing methods should ever get called on the
         // deferred device
index 7d1ecbf..c40275d 100644 (file)
@@ -78,11 +78,11 @@ struct DeviceCM {
     const SkMatrix*     fMVMatrix;
     const SkMatrix*     fExtMatrix;
 
-    DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint)
+    DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas)
             : fNext(NULL) {
         if (NULL != device) {
             device->ref();
-            device->lockPixels();
+            device->onAttachToCanvas(canvas);
         }
         fDevice = device;
         fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
@@ -90,7 +90,7 @@ struct DeviceCM {
 
     ~DeviceCM() {
         if (NULL != fDevice) {
-            fDevice->unlockPixels();
+            fDevice->onDetachFromCanvas();
             fDevice->unref();
         }
         SkDELETE(fPaint);
@@ -256,7 +256,7 @@ public:
             }
             // fCurrLayer may be NULL now
 
-            fCanvas->prepareForDeviceDraw(fDevice, *fMatrix, *fClip, *fClipStack);
+            fCanvas->prepareForDeviceDraw(fDevice, *fMatrix, *fClip);
             return true;
         }
         return false;
@@ -460,7 +460,7 @@ SkDevice* SkCanvas::init(SkDevice* device) {
     fMCRec = (MCRec*)fMCStack.push_back();
     new (fMCRec) MCRec(NULL, 0);
 
-    fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL));
+    fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL));
     fMCRec->fTopLayer = fMCRec->fLayer;
     fMCRec->fNext = NULL;
 
@@ -558,14 +558,11 @@ SkDevice* SkCanvas::setDevice(SkDevice* device) {
         return device;
     }
 
-    /* Notify the devices that they are going in/out of scope, so they can do
-       things like lock/unlock their pixels, etc.
-    */
     if (device) {
-        device->lockPixels();
+        device->onAttachToCanvas(this);
     }
     if (rootDevice) {
-        rootDevice->unlockPixels();
+        rootDevice->onDetachFromCanvas();
     }
 
     SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
@@ -682,11 +679,10 @@ void SkCanvas::updateDeviceCMCache() {
 }
 
 void SkCanvas::prepareForDeviceDraw(SkDevice* device, const SkMatrix& matrix,
-                                    const SkRegion& clip,
-                                    const SkClipStack& clipStack) {
+                                    const SkRegion& clip) {
     SkASSERT(device);
     if (fLastDeviceToGainFocus != device) {
-        device->gainFocus(this, matrix, clip, clipStack);
+        device->gainFocus(matrix, clip);
         fLastDeviceToGainFocus = device;
     }
 }
@@ -843,7 +839,7 @@ int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint,
     }
 
     device->setOrigin(ir.fLeft, ir.fTop);
-    DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint));
+    DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint, this));
     device->unref();
 
     layer->fNext = fMCRec->fTopLayer;
index 95664c8..4cd9310 100644 (file)
@@ -20,12 +20,21 @@ SK_DEFINE_INST_COUNT(SkDevice)
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkDevice::SkDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {
+SkDevice::SkDevice(const SkBitmap& bitmap) 
+    : fBitmap(bitmap)
+#ifdef SK_DEBUG
+    , fAttachedToCanvas(false) 
+#endif
+{
     fOrigin.setZero();
     fMetaData = NULL;
 }
 
-SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque) {
+SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque) 
+#ifdef SK_DEBUG
+    : fAttachedToCanvas(false) 
+#endif
+{
     fOrigin.setZero();
     fMetaData = NULL;
 
index 1154313..6443fa2 100644 (file)
@@ -165,12 +165,14 @@ static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
 }
 
 SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
-: SkDevice(make_bitmap(context, texture->asRenderTarget())) {
+: SkDevice(make_bitmap(context, texture->asRenderTarget()))
+, fClipStack(NULL) {
     this->initFromRenderTarget(context, texture->asRenderTarget());
 }
 
 SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
-: SkDevice(make_bitmap(context, renderTarget)) {
+: SkDevice(make_bitmap(context, renderTarget))
+, fClipStack(NULL) {
     this->initFromRenderTarget(context, renderTarget);
 }
 
@@ -211,7 +213,8 @@ SkGpuDevice::SkGpuDevice(GrContext* context,
                          SkBitmap::Config config,
                          int width,
                          int height)
-    : SkDevice(config, width, height, false /*isOpaque*/) {
+    : SkDevice(config, width, height, false /*isOpaque*/)
+    , fClipStack(NULL) {
     fNeedPrepareRenderTarget = false;
     fDrawProcs = NULL;
 
@@ -342,6 +345,19 @@ void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y,
                                config, bitmap.getPixels(), bitmap.rowBytes());
 }
 
+void SkGpuDevice::onAttachToCanvas(SkCanvas* canvas) {
+    INHERITED::onAttachToCanvas(canvas);
+
+    // Canvas promises that this ptr is valid until onDetachFromCanvas is called
+    fClipStack = canvas->getClipStack();
+}
+
+void SkGpuDevice::onDetachFromCanvas() {
+    INHERITED::onDetachFromCanvas();
+
+    fClipStack = NULL;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
@@ -366,13 +382,15 @@ static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
 // call this ever each draw call, to ensure that the context reflects our state,
 // and not the state from some other canvas/device
 void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
+    GrAssert(NULL != fClipStack);
+
     if (fNeedPrepareRenderTarget ||
         fContext->getRenderTarget() != fRenderTarget) {
 
         fContext->setRenderTarget(fRenderTarget);
-        SkASSERT(draw.fClipStack);
+        SkASSERT(draw.fClipStack && draw.fClipStack == fClipStack);
         convert_matrixclip(fContext, *draw.fMatrix,
-                           *draw.fClipStack, *draw.fClip, this->getOrigin());
+                           *fClipStack, *draw.fClip, this->getOrigin());
         fNeedPrepareRenderTarget = false;
     }
 }
@@ -384,14 +402,15 @@ void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
     fNeedPrepareRenderTarget = true;
 }
 
-void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
-                            const SkRegion& clip, const SkClipStack& clipStack) {
+void SkGpuDevice::gainFocus(const SkMatrix& matrix, const SkRegion& clip) {
+
+    GrAssert(NULL != fClipStack);
 
     fContext->setRenderTarget(fRenderTarget);
 
-    this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
+    this->INHERITED::gainFocus(matrix, clip);
 
-    convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
+    convert_matrixclip(fContext, matrix, *fClipStack, clip, this->getOrigin());
 
     DO_DEFERRED_CLEAR;
 }
@@ -1964,7 +1983,8 @@ SkGpuDevice::SkGpuDevice(GrContext* context,
                          GrTexture* texture,
                          TexCache cacheEntry,
                          bool needClear)
-    : SkDevice(make_bitmap(context, texture->asRenderTarget())) {
+    : SkDevice(make_bitmap(context, texture->asRenderTarget()))
+    , fClipStack(NULL) {
     GrAssert(texture && texture->asRenderTarget());
     GrAssert(NULL == cacheEntry.texture() || texture == cacheEntry.texture());
     this->initFromRenderTarget(context, texture->asRenderTarget());
index d05b640..55aae8d 100644 (file)
@@ -514,7 +514,8 @@ SkPDFDevice::SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize,
       fPageSize(pageSize),
       fContentSize(contentSize),
       fLastContentEntry(NULL),
-      fLastMarginContentEntry(NULL) {
+      fLastMarginContentEntry(NULL),
+      fClipStack(NULL) {
     // Skia generally uses the top left as the origin but PDF natively has the
     // origin at the bottom left. This matrix corrects for that.  But that only
     // needs to be done once, we don't do it when layering.
@@ -538,7 +539,8 @@ SkPDFDevice::SkPDFDevice(const SkISize& layerSize,
       fExistingClipStack(existingClipStack),
       fExistingClipRegion(existingClipRegion),
       fLastContentEntry(NULL),
-      fLastMarginContentEntry(NULL) {
+      fLastMarginContentEntry(NULL),
+      fClipStack(NULL) {
     fInitialTransform.reset();
     this->init();
 }
@@ -945,6 +947,19 @@ void SkPDFDevice::drawDevice(const SkDraw& d, SkDevice* device, int x, int y,
     fFontGlyphUsage->merge(pdfDevice->getFontGlyphUsage());
 }
 
+void SkPDFDevice::onAttachToCanvas(SkCanvas* canvas) {
+    INHERITED::onAttachToCanvas(canvas);
+
+    // Canvas promises that this ptr is valid until onDetachFromCanvas is called
+    fClipStack = canvas->getClipStack();
+}
+
+void SkPDFDevice::onDetachFromCanvas() {
+    INHERITED::onDetachFromCanvas();
+
+    fClipStack = NULL;
+}
+
 ContentEntry* SkPDFDevice::getLastContentEntry() {
     if (fDrawingArea == kContent_DrawingArea) {
         return fLastContentEntry;