1 /* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkSurface_Base.h" 9 #include "SkImagePriv.h" 10 #include "SkCanvas.h" 11 12 SK_DEFINE_INST_COUNT(SkSurface) 13 14 /////////////////////////////////////////////////////////////////////////////// 15 16 void SkSurface_Base::installIntoCanvasForDirtyNotification() { 17 if (fCachedCanvas) { 18 fCachedCanvas->setSurfaceBase(this); 19 } 20 } 21 22 SkSurface_Base::SkSurface_Base(int width, int height) : INHERITED(width, height) { 23 fCachedCanvas = NULL; 24 fCachedImage = NULL; 25 } 26 27 SkSurface_Base::~SkSurface_Base() { 28 // in case the canvas outsurvives us, we null the callback 29 if (fCachedCanvas) { 30 fCachedCanvas->setSurfaceBase(NULL); 31 } 32 33 SkSafeUnref(fCachedImage); 34 SkSafeUnref(fCachedCanvas); 35 } 36 37 void SkSurface_Base::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, 38 const SkPaint* paint) { 39 SkImage* image = this->newImageShapshot(); 40 if (image) { 41 image->draw(canvas, x, y, paint); 42 image->unref(); 43 } 44 } 45 46 SkCanvas* SkSurface_Base::getCachedCanvas() { 47 if (NULL == fCachedCanvas) { 48 fCachedCanvas = this->onNewCanvas(); 49 this->installIntoCanvasForDirtyNotification(); 50 } 51 return fCachedCanvas; 52 } 53 54 SkImage* SkSurface_Base::getCachedImage() { 55 if (NULL == fCachedImage) { 56 fCachedImage = this->onNewImageShapshot(); 57 this->installIntoCanvasForDirtyNotification(); 58 } 59 return fCachedImage; 60 } 61 62 void SkSurface_Base::aboutToDraw(SkCanvas* canvas) { 63 this->dirtyGenerationID(); 64 65 if (canvas) { 66 SkASSERT(canvas == fCachedCanvas); 67 SkASSERT(canvas->getSurfaceBase() == this); 68 canvas->setSurfaceBase(NULL); 69 } 70 71 if (fCachedImage) { 72 // the surface may need to fork its backend, if its sharing it with 73 // the cached image. Note: we only call if there is an outstanding owner 74 // on the image (besides us). 75 if (fCachedImage->getRefCnt() > 1) { 76 this->onCopyOnWrite(fCachedImage, canvas); 77 } 78 79 // regardless of copy-on-write, we must drop our cached image now, so 80 // that the next request will get our new contents. 81 fCachedImage->unref(); 82 fCachedImage = NULL; 83 } 84 } 85 86 uint32_t SkSurface_Base::newGenerationID() { 87 this->installIntoCanvasForDirtyNotification(); 88 89 static int32_t gID; 90 return sk_atomic_inc(&gID) + 1; 91 } 92 93 static SkSurface_Base* asSB(SkSurface* surface) { 94 return static_cast<SkSurface_Base*>(surface); 95 } 96 97 /////////////////////////////////////////////////////////////////////////////// 98 99 SkSurface::SkSurface(int width, int height) : fWidth(width), fHeight(height) { 100 SkASSERT(width >= 0); 101 SkASSERT(height >= 0); 102 fGenerationID = 0; 103 } 104 105 uint32_t SkSurface::generationID() { 106 if (0 == fGenerationID) { 107 fGenerationID = asSB(this)->newGenerationID(); 108 } 109 return fGenerationID; 110 } 111 112 void SkSurface::notifyContentChanged() { 113 asSB(this)->aboutToDraw(NULL); 114 } 115 116 SkCanvas* SkSurface::getCanvas() { 117 return asSB(this)->getCachedCanvas(); 118 } 119 120 SkImage* SkSurface::newImageShapshot() { 121 SkImage* image = asSB(this)->getCachedImage(); 122 SkSafeRef(image); // the caller will call unref() to balance this 123 return image; 124 } 125 126 SkSurface* SkSurface::newSurface(const SkImage::Info& info) { 127 return asSB(this)->onNewSurface(info); 128 } 129 130 void SkSurface::draw(SkCanvas* canvas, SkScalar x, SkScalar y, 131 const SkPaint* paint) { 132 return asSB(this)->onDraw(canvas, x, y, paint); 133 } 134