From 40a1ae4df28810aa5aa5cf2627d8387b2dfb867a Mon Sep 17 00:00:00 2001 From: "robertphillips@google.com" Date: Fri, 13 Jul 2012 15:36:15 +0000 Subject: [PATCH] Added SkDevice onAttachToCanvas & onDetachFromCanvas methods http://codereview.appspot.com/6348100/ git-svn-id: http://skia.googlecode.com/svn/trunk@4598 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/core/SkCanvas.h | 12 ++++++++++-- include/core/SkDevice.h | 35 +++++++++++++++++++++++++++++++++-- include/gpu/SkGpuDevice.h | 9 +++++++-- include/pdf/SkPDFDevice.h | 9 ++++++--- include/utils/SkDeferredCanvas.h | 3 --- src/core/SkCanvas.cpp | 24 ++++++++++-------------- src/core/SkDevice.cpp | 13 +++++++++++-- src/gpu/SkGpuDevice.cpp | 40 ++++++++++++++++++++++++++++++---------- src/pdf/SkPDFDevice.cpp | 19 +++++++++++++++++-- 9 files changed, 124 insertions(+), 40 deletions(-) diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index fc95f9a..8fa73f6 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -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(); diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h index 184fb6f..5cf5c50 100644 --- a/include/core/SkDevice.h +++ b/include/core/SkDevice.h @@ -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; }; diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h index 40444a9..2390cdb 100644 --- a/include/gpu/SkGpuDevice.h +++ b/include/gpu/SkGpuDevice.h @@ -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; diff --git a/include/pdf/SkPDFDevice.h b/include/pdf/SkPDFDevice.h index 354729d..589cde9 100644 --- a/include/pdf/SkPDFDevice.h +++ b/include/pdf/SkPDFDevice.h @@ -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* 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 diff --git a/include/utils/SkDeferredCanvas.h b/include/utils/SkDeferredCanvas.h index dd2c1f0..8964e9e 100644 --- a/include/utils/SkDeferredCanvas.h +++ b/include/utils/SkDeferredCanvas.h @@ -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 diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 7d1ecbf..c40275d 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -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; diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 95664c8..4cd9310 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -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; diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 1154313..6443fa2 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -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()); diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index d05b640..55aae8d 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -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; -- 2.7.4