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
SK_DEFINE_INST_COUNT(SkSurface)12 SK_DEFINE_INST_COUNT(SkSurface)
13
14 ///////////////////////////////////////////////////////////////////////////////
15
16 void SkSurface_Base::installIntoCanvasForDirtyNotification() {
17 if (fCachedCanvas) {
18 fCachedCanvas->setSurfaceBase(this);
19 }
20 }
21
SkSurface_Base(int width,int height)22 SkSurface_Base::SkSurface_Base(int width, int height) : INHERITED(width, height) {
23 fCachedCanvas = NULL;
24 fCachedImage = NULL;
25 }
26
~SkSurface_Base()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
onDraw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkPaint * paint)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
getCachedCanvas()46 SkCanvas* SkSurface_Base::getCachedCanvas() {
47 if (NULL == fCachedCanvas) {
48 fCachedCanvas = this->onNewCanvas();
49 this->installIntoCanvasForDirtyNotification();
50 }
51 return fCachedCanvas;
52 }
53
getCachedImage()54 SkImage* SkSurface_Base::getCachedImage() {
55 if (NULL == fCachedImage) {
56 fCachedImage = this->onNewImageShapshot();
57 this->installIntoCanvasForDirtyNotification();
58 }
59 return fCachedImage;
60 }
61
aboutToDraw(SkCanvas * canvas)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
newGenerationID()86 uint32_t SkSurface_Base::newGenerationID() {
87 this->installIntoCanvasForDirtyNotification();
88
89 static int32_t gID;
90 return sk_atomic_inc(&gID) + 1;
91 }
92
asSB(SkSurface * surface)93 static SkSurface_Base* asSB(SkSurface* surface) {
94 return static_cast<SkSurface_Base*>(surface);
95 }
96
97 ///////////////////////////////////////////////////////////////////////////////
98
SkSurface(int width,int height)99 SkSurface::SkSurface(int width, int height) : fWidth(width), fHeight(height) {
100 SkASSERT(width >= 0);
101 SkASSERT(height >= 0);
102 fGenerationID = 0;
103 }
104
generationID()105 uint32_t SkSurface::generationID() {
106 if (0 == fGenerationID) {
107 fGenerationID = asSB(this)->newGenerationID();
108 }
109 return fGenerationID;
110 }
111
notifyContentChanged()112 void SkSurface::notifyContentChanged() {
113 asSB(this)->aboutToDraw(NULL);
114 }
115
getCanvas()116 SkCanvas* SkSurface::getCanvas() {
117 return asSB(this)->getCachedCanvas();
118 }
119
newImageShapshot()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
newSurface(const SkImage::Info & info)126 SkSurface* SkSurface::newSurface(const SkImage::Info& info) {
127 return asSB(this)->onNewSurface(info);
128 }
129
draw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkPaint * paint)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