1 #include "SampleCode.h"
2 #include "SkDumpCanvas.h"
3 #include "SkView.h"
4 #include "SkCanvas.h"
5 #include "Sk64.h"
6 #include "SkGradientShader.h"
7 #include "SkGraphics.h"
8 #include "SkImageDecoder.h"
9 #include "SkPath.h"
10 #include "SkPicture.h"
11 #include "SkRandom.h"
12 #include "SkRegion.h"
13 #include "SkShader.h"
14 #include "SkUtils.h"
15 #include "SkColorPriv.h"
16 #include "SkColorFilter.h"
17 #include "SkShape.h"
18 #include "SkTime.h"
19 #include "SkTypeface.h"
20 #include "SkXfermode.h"
21
22 #include "SkStream.h"
23 #include "SkXMLParser.h"
24
25 class SignalShape : public SkShape {
26 public:
SignalShape()27 SignalShape() : fSignal(0) {}
28
setSignal(int n)29 SkShape* setSignal(int n) {
30 fSignal = n;
31 return this;
32 }
33
34 protected:
onDraw(SkCanvas * canvas)35 virtual void onDraw(SkCanvas* canvas) {
36 // SkDebugf("---- sc %d\n", canvas->getSaveCount() - 1);
37 }
38
39 private:
40 int fSignal;
41 };
42
SignalProc(SkPMColor src,SkPMColor dst)43 static SkPMColor SignalProc(SkPMColor src, SkPMColor dst) {
44 return dst;
45 }
46
47 /* Picture playback will skip blocks of draw calls that follow a clip() call
48 that returns empty, and jump down to the corresponding restore() call.
49
50 This is a great preformance win for drawing very large/tall pictures with
51 a small visible window (think scrolling a long document). These tests make
52 sure that (a) we are performing the culling, and (b) we don't get confused
53 by nested save() calls, nor by calls to restoreToCount().
54 */
test_saveRestoreCulling()55 static void test_saveRestoreCulling() {
56 SkPaint signalPaint;
57 SignalShape signalShape;
58
59 SkPicture pic;
60 SkRect r = SkRect::MakeWH(0, 0);
61 int n;
62 SkCanvas* canvas = pic.beginRecording(100, 100);
63 int startN = canvas->getSaveCount();
64 SkDebugf("---- start sc %d\n", startN);
65 canvas->drawShape(signalShape.setSignal(1));
66 canvas->save();
67 canvas->drawShape(signalShape.setSignal(2));
68 n = canvas->save();
69 canvas->drawShape(signalShape.setSignal(3));
70 canvas->save();
71 canvas->clipRect(r);
72 canvas->drawShape(signalShape.setSignal(4));
73 canvas->restoreToCount(n);
74 canvas->drawShape(signalShape.setSignal(5));
75 canvas->restore();
76 canvas->drawShape(signalShape.setSignal(6));
77 SkASSERT(canvas->getSaveCount() == startN);
78
79 SkBitmap bm;
80 bm.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
81 bm.allocPixels();
82 SkCanvas c(bm);
83 c.drawPicture(pic);
84 }
85
86 ///////////////////////////////////////////////////////////////////////////////
87
88 #include "SkImageRef_GlobalPool.h"
89
load_bitmap()90 static SkBitmap load_bitmap() {
91 SkStream* stream = new SkFILEStream("/skimages/sesame_street_ensemble-hp.jpg");
92 SkAutoUnref aur(stream);
93
94 SkBitmap bm;
95 if (SkImageDecoder::DecodeStream(stream, &bm, SkBitmap::kNo_Config,
96 SkImageDecoder::kDecodeBounds_Mode)) {
97 SkPixelRef* pr = new SkImageRef_GlobalPool(stream, bm.config(), 1);
98 bm.setPixelRef(pr)->unref();
99 }
100 return bm;
101 }
102
drawCircle(SkCanvas * canvas,int r,SkColor color)103 static void drawCircle(SkCanvas* canvas, int r, SkColor color) {
104 SkPaint paint;
105 paint.setAntiAlias(true);
106 paint.setColor(color);
107
108 canvas->drawCircle(SkIntToScalar(r), SkIntToScalar(r), SkIntToScalar(r),
109 paint);
110 }
111
112 class PictureView : public SampleView {
113 SkBitmap fBitmap;
114 public:
PictureView()115 PictureView() {
116 SkImageRef_GlobalPool::SetRAMBudget(16 * 1024);
117
118 fBitmap = load_bitmap();
119
120 fPicture = new SkPicture;
121 SkCanvas* canvas = fPicture->beginRecording(100, 100);
122 SkPaint paint;
123 paint.setAntiAlias(true);
124
125 canvas->drawBitmap(fBitmap, 0, 0, NULL);
126
127 drawCircle(canvas, 50, SK_ColorBLACK);
128 fSubPicture = new SkPicture;
129 canvas->drawPicture(*fSubPicture);
130 canvas->translate(SkIntToScalar(50), 0);
131 canvas->drawPicture(*fSubPicture);
132 canvas->translate(0, SkIntToScalar(50));
133 canvas->drawPicture(*fSubPicture);
134 canvas->translate(SkIntToScalar(-50), 0);
135 canvas->drawPicture(*fSubPicture);
136 // fPicture now has (4) references to us. We can release ours, and just
137 // unref fPicture in our destructor, and it will in turn take care of
138 // the other references to fSubPicture
139 fSubPicture->unref();
140
141 test_saveRestoreCulling();
142 }
143
~PictureView()144 virtual ~PictureView() {
145 fPicture->unref();
146 }
147
148 protected:
149 // overrides from SkEventSink
onQuery(SkEvent * evt)150 virtual bool onQuery(SkEvent* evt) {
151 if (SampleCode::TitleQ(*evt)) {
152 SampleCode::TitleR(evt, "Picture");
153 return true;
154 }
155 return this->INHERITED::onQuery(evt);
156 }
157
drawSomething(SkCanvas * canvas)158 void drawSomething(SkCanvas* canvas) {
159 SkPaint paint;
160
161 canvas->save();
162 canvas->scale(0.5f, 0.5f);
163 canvas->drawBitmap(fBitmap, 0, 0, NULL);
164 canvas->restore();
165
166 const char beforeStr[] = "before circle";
167 const char afterStr[] = "after circle";
168
169 paint.setAntiAlias(true);
170
171 paint.setColor(SK_ColorRED);
172 canvas->drawData(beforeStr, sizeof(beforeStr));
173 canvas->drawCircle(SkIntToScalar(50), SkIntToScalar(50),
174 SkIntToScalar(40), paint);
175 canvas->drawData(afterStr, sizeof(afterStr));
176 paint.setColor(SK_ColorBLACK);
177 paint.setTextSize(SkIntToScalar(40));
178 canvas->drawText("Picture", 7, SkIntToScalar(50), SkIntToScalar(62),
179 paint);
180
181 }
182
onDrawContent(SkCanvas * canvas)183 virtual void onDrawContent(SkCanvas* canvas) {
184 drawSomething(canvas);
185
186 SkPicture* pict = new SkPicture;
187 SkAutoUnref aur(pict);
188
189 drawSomething(pict->beginRecording(100, 100));
190 pict->endRecording();
191
192 canvas->save();
193 canvas->translate(SkIntToScalar(300), SkIntToScalar(50));
194 canvas->scale(-SK_Scalar1, -SK_Scalar1);
195 canvas->translate(-SkIntToScalar(100), -SkIntToScalar(50));
196 canvas->drawPicture(*pict);
197 canvas->restore();
198
199 canvas->save();
200 canvas->translate(SkIntToScalar(200), SkIntToScalar(150));
201 canvas->scale(SK_Scalar1, -SK_Scalar1);
202 canvas->translate(0, -SkIntToScalar(50));
203 canvas->drawPicture(*pict);
204 canvas->restore();
205
206 canvas->save();
207 canvas->translate(SkIntToScalar(100), SkIntToScalar(100));
208 canvas->scale(-SK_Scalar1, SK_Scalar1);
209 canvas->translate(-SkIntToScalar(100), 0);
210 canvas->drawPicture(*pict);
211 canvas->restore();
212
213 if (false) {
214 SkDebugfDumper dumper;
215 SkDumpCanvas dumpCanvas(&dumper);
216 dumpCanvas.drawPicture(*pict);
217 }
218
219 // test that we can re-record a subpicture, and see the results
220
221 SkRandom rand(SampleCode::GetAnimTime());
222 canvas->translate(SkIntToScalar(10), SkIntToScalar(250));
223 drawCircle(fSubPicture->beginRecording(50, 50), 25,
224 rand.nextU() | 0xFF000000);
225 canvas->drawPicture(*fPicture);
226 delayInval(500);
227 }
228
229 private:
230 #define INVAL_ALL_TYPE "inval-all"
231
delayInval(SkMSec delay)232 void delayInval(SkMSec delay) {
233 (new SkEvent(INVAL_ALL_TYPE))->post(this->getSinkID(), delay);
234 }
235
onEvent(const SkEvent & evt)236 virtual bool onEvent(const SkEvent& evt) {
237 if (evt.isType(INVAL_ALL_TYPE)) {
238 this->inval(NULL);
239 return true;
240 }
241 return this->INHERITED::onEvent(evt);
242 }
243
244 SkPicture* fPicture;
245 SkPicture* fSubPicture;
246
247 typedef SampleView INHERITED;
248 };
249
250 //////////////////////////////////////////////////////////////////////////////
251
MyFactory()252 static SkView* MyFactory() { return new PictureView; }
253 static SkViewRegister reg(MyFactory);
254
255