blob: 586541745e772f3d6cb25af253c74e4b46814fc0 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#include "SkCanvas.h"
2#include "SkDevice.h"
reed@google.comac10a2d2010-12-22 21:39:39 +00003#include "SkGpuCanvas.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00004#include "SkGraphics.h"
reed@android.comb08eb2b2009-01-06 20:16:26 +00005#include "SkImageEncoder.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00006#include "SkPaint.h"
7#include "SkPicture.h"
8#include "SkStream.h"
reed@android.com44177402009-11-23 21:07:51 +00009#include "SkTime.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkWindow.h"
11
12#include "SampleCode.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000013#include "GrContext.h"
reed@android.comf2b98d62010-12-20 18:26:13 +000014
15//#define DEFAULT_TO_GPU
16
reed@android.come191b162009-12-18 21:33:39 +000017extern SkView* create_overview(int, const SkViewFactory[]);
reed@android.com34245c72009-11-03 04:00:48 +000018
reed@android.comcb342352010-07-22 18:27:53 +000019#define SK_SUPPORT_GL
reed@android.com8a1c16f2008-12-17 15:59:43 +000020
21#define ANIMATING_EVENTTYPE "nextSample"
22#define ANIMATING_DELAY 750
23
reed@android.comf2b98d62010-12-20 18:26:13 +000024#if !defined(SK_BUILD_FOR_WIN32)
25//#define USE_OFFSCREEN
26#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000027
reed@google.comac10a2d2010-12-22 21:39:39 +000028#ifdef SK_SUPPORT_GL
29 #include "GrGLConfig.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000030#endif
31
reed@android.com8a1c16f2008-12-17 15:59:43 +000032SkViewRegister* SkViewRegister::gHead;
33SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) {
34 static bool gOnce;
35 if (!gOnce) {
36 gHead = NULL;
37 gOnce = true;
38 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +000039
reed@android.com8a1c16f2008-12-17 15:59:43 +000040 fChain = gHead;
41 gHead = this;
42}
43
reed@android.comf2b98d62010-12-20 18:26:13 +000044#if defined(SK_SUPPORT_GL)
45 #define SK_USE_SHADERS
46#endif
47
reed@android.com8a1c16f2008-12-17 15:59:43 +000048//////////////////////////////////////////////////////////////////////////////
49
reed@android.comf2b98d62010-12-20 18:26:13 +000050static const char gCharEvtName[] = "SampleCode_Char_Event";
51static const char gKeyEvtName[] = "SampleCode_Key_Event";
reed@android.com8a1c16f2008-12-17 15:59:43 +000052static const char gTitleEvtName[] = "SampleCode_Title_Event";
53static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event";
reed@android.comf2b98d62010-12-20 18:26:13 +000054static const char gFastTextEvtName[] = "SampleCode_FastText_Event";
55
56bool SampleCode::CharQ(const SkEvent& evt, SkUnichar* outUni) {
57 if (evt.isType(gCharEvtName, sizeof(gCharEvtName) - 1)) {
58 if (outUni) {
59 *outUni = evt.getFast32();
60 }
61 return true;
62 }
63 return false;
64}
65
66bool SampleCode::KeyQ(const SkEvent& evt, SkKey* outKey) {
67 if (evt.isType(gKeyEvtName, sizeof(gKeyEvtName) - 1)) {
68 if (outKey) {
69 *outKey = (SkKey)evt.getFast32();
70 }
71 return true;
72 }
73 return false;
74}
reed@android.com8a1c16f2008-12-17 15:59:43 +000075
76bool SampleCode::TitleQ(const SkEvent& evt) {
77 return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1);
78}
79
80void SampleCode::TitleR(SkEvent* evt, const char title[]) {
81 SkASSERT(evt && TitleQ(*evt));
82 evt->setString(gTitleEvtName, title);
83}
84
85bool SampleCode::PrefSizeQ(const SkEvent& evt) {
86 return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1);
87}
88
89void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) {
90 SkASSERT(evt && PrefSizeQ(*evt));
91 SkScalar size[2];
92 size[0] = width;
93 size[1] = height;
94 evt->setScalars(gPrefSizeEvtName, 2, size);
95}
96
reed@android.comf2b98d62010-12-20 18:26:13 +000097bool SampleCode::FastTextQ(const SkEvent& evt) {
98 return evt.isType(gFastTextEvtName, sizeof(gFastTextEvtName) - 1);
99}
100
101///////////////////////////////////////////////////////////////////////////////
102
reed@android.com44177402009-11-23 21:07:51 +0000103static SkMSec gAnimTime;
reed@android.comf2b98d62010-12-20 18:26:13 +0000104static SkMSec gAnimTimePrev;
105
reed@android.com44177402009-11-23 21:07:51 +0000106SkMSec SampleCode::GetAnimTime() { return gAnimTime; }
reed@android.comf2b98d62010-12-20 18:26:13 +0000107SkMSec SampleCode::GetAnimTimeDelta() { return gAnimTime - gAnimTimePrev; }
108SkScalar SampleCode::GetAnimSecondsDelta() {
109 return SkDoubleToScalar(GetAnimTimeDelta() / 1000.0);
110}
reed@android.com44177402009-11-23 21:07:51 +0000111
112SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000113 // since gAnimTime can be up to 32 bits, we can't convert it to a float
114 // or we'll lose the low bits. Hence we use doubles for the intermediate
115 // calculations
116 double seconds = (double)gAnimTime / 1000.0;
117 double value = SkScalarToDouble(speed) * seconds;
reed@android.com44177402009-11-23 21:07:51 +0000118 if (period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000119 value = ::fmod(value, SkScalarToDouble(period));
reed@android.com44177402009-11-23 21:07:51 +0000120 }
reed@android.comf2b98d62010-12-20 18:26:13 +0000121 return SkDoubleToScalar(value);
reed@android.com44177402009-11-23 21:07:51 +0000122}
123
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124//////////////////////////////////////////////////////////////////////////////
125
reed@android.comf2b98d62010-12-20 18:26:13 +0000126static SkView* curr_view(SkWindow* wind) {
127 SkView::F2BIter iter(wind);
128 return iter.next();
129}
130
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131class SampleWindow : public SkOSWindow {
reed@android.com34245c72009-11-03 04:00:48 +0000132 SkTDArray<SkViewFactory> fSamples;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133public:
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000134 SampleWindow(void* hwnd);
135 virtual ~SampleWindow();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136
reed@android.come522ca52009-11-23 20:10:41 +0000137 virtual void draw(SkCanvas* canvas);
138
reed@android.com8a1c16f2008-12-17 15:59:43 +0000139protected:
140 virtual void onDraw(SkCanvas* canvas);
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000141 virtual bool onHandleKey(SkKey key);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142 virtual bool onHandleChar(SkUnichar);
143 virtual void onSizeChange();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000144
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145 virtual SkCanvas* beforeChildren(SkCanvas*);
146 virtual void afterChildren(SkCanvas*);
reed@android.com6c5f6f22009-08-14 16:08:38 +0000147 virtual void beforeChild(SkView* child, SkCanvas* canvas);
148 virtual void afterChild(SkView* child, SkCanvas* canvas);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000149
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000150 virtual bool onEvent(const SkEvent& evt);
reed@android.comf2b98d62010-12-20 18:26:13 +0000151 virtual bool onQuery(SkEvent* evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152
153#if 0
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000154 virtual bool handleChar(SkUnichar uni);
155 virtual bool handleEvent(const SkEvent& evt);
156 virtual bool handleKey(SkKey key);
157 virtual bool handleKeyUp(SkKey key);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000158
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000159 virtual bool onClick(Click* click);
160 virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 virtual bool onHandleKeyUp(SkKey key);
162#endif
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000163
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164private:
reed@android.com34245c72009-11-03 04:00:48 +0000165 int fCurrIndex;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000166
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167 SkPicture* fPicture;
reed@android.comf2b98d62010-12-20 18:26:13 +0000168 SkGpuCanvas* fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000169 GrContext* fGrContext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170 SkPath fClipPath;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000171
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 enum CanvasType {
173 kRaster_CanvasType,
174 kPicture_CanvasType,
reed@android.comf2b98d62010-12-20 18:26:13 +0000175 kGPU_CanvasType
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 };
177 CanvasType fCanvasType;
178
179 bool fUseClip;
reed@android.come522ca52009-11-23 20:10:41 +0000180 bool fNClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181 bool fRepeatDrawing;
182 bool fAnimating;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000183 bool fRotate;
184 bool fScale;
reed@android.comf2b98d62010-12-20 18:26:13 +0000185 bool fRequestGrabImage;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000186
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 int fScrollTestX, fScrollTestY;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000188
189 bool make3DReady();
190
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191 void loadView(SkView*);
192 void updateTitle();
193 bool nextSample();
194
195 void postAnimatingEvent() {
196 if (fAnimating) {
197 SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
198 evt->post(this->getSinkID(), ANIMATING_DELAY);
199 }
200 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000201
202
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 static CanvasType cycle_canvastype(CanvasType);
204
205 typedef SkOSWindow INHERITED;
206};
207
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000208bool SampleWindow::make3DReady() {
209
210#if defined(SK_SUPPORT_GL)
211 #if defined(USE_OFFSCREEN)
212 // first clear the raster bitmap, so we don't see any leftover bits
213 bitmap.eraseColor(0);
214 // now setup our glcanvas
215 attachGL(&bitmap);
216 #else
217 attachGL(NULL);
218 #endif
219
220 if (NULL == fGrContext) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000221 #if defined(SK_USE_SHADERS)
222 fGrContext = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
223 #else
224 fGrContext = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, NULL);
225 #endif
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000226 }
227
228 if (NULL != fGrContext) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000229 return true;
230 } else {
231 detachGL();
232 }
233#endif
234 SkDebugf("Failed to setup 3D");
235 return false;
236}
237
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
239 static const CanvasType gCT[] = {
240 kPicture_CanvasType,
reed@android.comf2b98d62010-12-20 18:26:13 +0000241 kGPU_CanvasType,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 kRaster_CanvasType
243 };
244 return gCT[ct];
245}
246
247SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248 fPicture = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000249 fGpuCanvas = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000251 fGrContext = NULL;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000252
reed@android.comf2b98d62010-12-20 18:26:13 +0000253#ifdef DEFAULT_TO_GPU
254 fCanvasType = kGPU_CanvasType;
255#else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256 fCanvasType = kRaster_CanvasType;
reed@android.comf2b98d62010-12-20 18:26:13 +0000257#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258 fUseClip = false;
reed@android.come522ca52009-11-23 20:10:41 +0000259 fNClip = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260 fRepeatDrawing = false;
261 fAnimating = false;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000262 fRotate = false;
263 fScale = false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000264 fRequestGrabImage = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265
266 fScrollTestX = fScrollTestY = 0;
267
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000268// this->setConfig(SkBitmap::kRGB_565_Config);
269 this->setConfig(SkBitmap::kARGB_8888_Config);
270 this->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000271 this->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272
reed@android.com34245c72009-11-03 04:00:48 +0000273 {
274 const SkViewRegister* reg = SkViewRegister::Head();
275 while (reg) {
276 *fSamples.append() = reg->factory();
277 reg = reg->next();
278 }
279 }
280 fCurrIndex = 0;
reed@android.come0f13ee2009-11-04 19:40:25 +0000281 this->loadView(fSamples[fCurrIndex]());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282}
283
284SampleWindow::~SampleWindow() {
285 delete fPicture;
reed@android.comf2b98d62010-12-20 18:26:13 +0000286 delete fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000287 if (NULL != fGrContext) {
288 fGrContext->unref();
289 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290}
291
reed@android.com55e76b22009-11-23 21:46:47 +0000292static SkBitmap capture_bitmap(SkCanvas* canvas) {
293 SkBitmap bm;
294 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
295 src.copyTo(&bm, src.config());
296 return bm;
297}
298
299static bool bitmap_diff(SkCanvas* canvas, const SkBitmap& orig,
300 SkBitmap* diff) {
301 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000302
reed@android.com55e76b22009-11-23 21:46:47 +0000303 SkAutoLockPixels alp0(src);
304 SkAutoLockPixels alp1(orig);
305 for (int y = 0; y < src.height(); y++) {
306 const void* srcP = src.getAddr(0, y);
307 const void* origP = orig.getAddr(0, y);
308 size_t bytes = src.width() * src.bytesPerPixel();
309 if (memcmp(srcP, origP, bytes)) {
310 SkDebugf("---------- difference on line %d\n", y);
311 return true;
312 }
313 }
314 return false;
315}
316
reed@android.com44177402009-11-23 21:07:51 +0000317#define XCLIP_N 8
318#define YCLIP_N 8
reed@android.come522ca52009-11-23 20:10:41 +0000319
320void SampleWindow::draw(SkCanvas* canvas) {
reed@android.com44177402009-11-23 21:07:51 +0000321 // update the animation time
reed@android.comf2b98d62010-12-20 18:26:13 +0000322 gAnimTimePrev = gAnimTime;
reed@android.com44177402009-11-23 21:07:51 +0000323 gAnimTime = SkTime::GetMSecs();
324
reed@android.come522ca52009-11-23 20:10:41 +0000325 if (fNClip) {
reed@android.com55e76b22009-11-23 21:46:47 +0000326 this->INHERITED::draw(canvas);
327 SkBitmap orig = capture_bitmap(canvas);
reed@android.come522ca52009-11-23 20:10:41 +0000328
329 const SkScalar w = this->width();
330 const SkScalar h = this->height();
331 const SkScalar cw = w / XCLIP_N;
332 const SkScalar ch = h / YCLIP_N;
333 for (int y = 0; y < YCLIP_N; y++) {
reed@android.com55e76b22009-11-23 21:46:47 +0000334 SkRect r;
335 r.fTop = y * ch;
336 r.fBottom = (y + 1) * ch;
337 if (y == YCLIP_N - 1) {
338 r.fBottom = h;
339 }
reed@android.come522ca52009-11-23 20:10:41 +0000340 for (int x = 0; x < XCLIP_N; x++) {
341 SkAutoCanvasRestore acr(canvas, true);
reed@android.com55e76b22009-11-23 21:46:47 +0000342 r.fLeft = x * cw;
343 r.fRight = (x + 1) * cw;
344 if (x == XCLIP_N - 1) {
345 r.fRight = w;
346 }
reed@android.come522ca52009-11-23 20:10:41 +0000347 canvas->clipRect(r);
348 this->INHERITED::draw(canvas);
349 }
350 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000351
reed@android.com55e76b22009-11-23 21:46:47 +0000352 SkBitmap diff;
353 if (bitmap_diff(canvas, orig, &diff)) {
354 }
reed@android.come522ca52009-11-23 20:10:41 +0000355 } else {
356 this->INHERITED::draw(canvas);
357 }
358}
359
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360void SampleWindow::onDraw(SkCanvas* canvas) {
361 if (fRepeatDrawing) {
362 this->inval(NULL);
363 }
364}
365
366#include "SkColorPriv.h"
367
368static void reverseRedAndBlue(const SkBitmap& bm) {
369 SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
370 uint8_t* p = (uint8_t*)bm.getPixels();
371 uint8_t* stop = p + bm.getSize();
372 while (p < stop) {
373 // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
374 unsigned scale = SkAlpha255To256(p[3]);
375 unsigned r = p[2];
376 unsigned b = p[0];
377 p[0] = SkAlphaMul(r, scale);
378 p[1] = SkAlphaMul(p[1], scale);
379 p[2] = SkAlphaMul(b, scale);
380 p += 4;
381 }
382}
383
384SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000385 SkIPoint viewport;
386 bool alreadyGPU = canvas->getViewport(&viewport);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000387
reed@android.comf2b98d62010-12-20 18:26:13 +0000388 if (kGPU_CanvasType != fCanvasType) {
reed@android.com6efdc472008-12-19 18:24:35 +0000389#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000390 detachGL();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000391#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000392 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000393
reed@android.com8a1c16f2008-12-17 15:59:43 +0000394 switch (fCanvasType) {
395 case kRaster_CanvasType:
396 canvas = this->INHERITED::beforeChildren(canvas);
397 break;
398 case kPicture_CanvasType:
399 fPicture = new SkPicture;
400 canvas = fPicture->beginRecording(9999, 9999);
401 break;
reed@google.comac10a2d2010-12-22 21:39:39 +0000402 case kGPU_CanvasType: {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000403 if (!alreadyGPU && make3DReady()) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000404 SkDevice* device = canvas->getDevice();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000405 const SkBitmap& bitmap = device->accessBitmap(true);
406
bsalomon@google.com5782d712011-01-21 21:03:59 +0000407 GrRenderTarget* renderTarget;
408 renderTarget = fGrContext->createRenderTargetFrom3DApiState();
409 fGpuCanvas = new SkGpuCanvas(fGrContext, renderTarget);
410 renderTarget->unref();
411
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000412 device = fGpuCanvas->createDevice(SkBitmap::kARGB_8888_Config,
413 bitmap.width(), bitmap.height(),
414 false, false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000415 fGpuCanvas->setDevice(device)->unref();
reed@android.comf2b98d62010-12-20 18:26:13 +0000416 canvas = fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000417
reed@android.comf2b98d62010-12-20 18:26:13 +0000418 } else {
419 canvas = this->INHERITED::beforeChildren(canvas);
420 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000421 break;
reed@google.comac10a2d2010-12-22 21:39:39 +0000422 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000423 }
424
425 if (fUseClip) {
426 canvas->drawColor(0xFFFF88FF);
427 canvas->clipPath(fClipPath);
428 }
429
430 return canvas;
431}
432
433static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
434 const SkRegion& rgn) {
435 SkCanvas canvas(bm);
436 SkRegion inval(rgn);
437
438 inval.translate(r.fLeft, r.fTop);
439 canvas.clipRegion(inval);
440 canvas.drawColor(0xFFFF8080);
441}
442
443void SampleWindow::afterChildren(SkCanvas* orig) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000444 if (fRequestGrabImage) {
445 fRequestGrabImage = false;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000446
reed@android.comf2b98d62010-12-20 18:26:13 +0000447 SkCanvas* canvas = fGpuCanvas ? fGpuCanvas : orig;
448 SkDevice* device = canvas->getDevice();
449 SkBitmap bitmap;
450 SkIRect bounds = { 0, 0, this->width(), this->height() };
451 if (device->readPixels(bounds, &bitmap)) {
452 static int gSampleGrabCounter;
453 SkString name;
454 name.printf("sample_grab_%d", gSampleGrabCounter++);
455 SkImageEncoder::EncodeFile(name.c_str(), bitmap,
456 SkImageEncoder::kPNG_Type, 100);
457 }
458 }
459
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460 switch (fCanvasType) {
461 case kRaster_CanvasType:
462 break;
463 case kPicture_CanvasType:
reed@android.comaefd2bc2009-03-30 21:02:14 +0000464 if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000465 SkPicture* pict = new SkPicture(*fPicture);
466 fPicture->unref();
467 orig->drawPicture(*pict);
468 pict->unref();
reed@android.comaefd2bc2009-03-30 21:02:14 +0000469 } else if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000470 SkDynamicMemoryWStream ostream;
471 fPicture->serialize(&ostream);
472 fPicture->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000473
reed@android.com8a1c16f2008-12-17 15:59:43 +0000474 SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
475 SkPicture pict(&istream);
476 orig->drawPicture(pict);
477 } else {
478 fPicture->draw(orig);
479 fPicture->unref();
480 }
481 fPicture = NULL;
482 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000483#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000484 case kGPU_CanvasType:
485 delete fGpuCanvas;
486 fGpuCanvas = NULL;
487 presentGL();
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000488 #ifdef USE_OFFSCREEN
reed@android.com8a1c16f2008-12-17 15:59:43 +0000489 reverseRedAndBlue(orig->getDevice()->accessBitmap(true));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000490 #endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000491 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000492#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000493 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000494
reed@android.com8a1c16f2008-12-17 15:59:43 +0000495// if ((fScrollTestX | fScrollTestY) != 0)
reed@android.comf2b98d62010-12-20 18:26:13 +0000496 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000497 const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
498 int dx = fScrollTestX * 7;
499 int dy = fScrollTestY * 7;
500 SkIRect r;
501 SkRegion inval;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000502
reed@android.com8a1c16f2008-12-17 15:59:43 +0000503 r.set(50, 50, 50+100, 50+100);
504 bm.scrollRect(&r, dx, dy, &inval);
505 paint_rgn(bm, r, inval);
506 }
507}
508
reed@android.com6c5f6f22009-08-14 16:08:38 +0000509void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
510 if (fScale) {
511 SkScalar scale = SK_Scalar1 * 7 / 10;
512 SkScalar cx = this->width() / 2;
513 SkScalar cy = this->height() / 2;
514 canvas->translate(cx, cy);
515 canvas->scale(scale, scale);
516 canvas->translate(-cx, -cy);
517 }
518 if (fRotate) {
519 SkScalar cx = this->width() / 2;
520 SkScalar cy = this->height() / 2;
521 canvas->translate(cx, cy);
522 canvas->rotate(SkIntToScalar(30));
523 canvas->translate(-cx, -cy);
524 }
525}
526
527void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) {
528}
529
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530static SkBitmap::Config gConfigCycle[] = {
531 SkBitmap::kNo_Config, // none -> none
532 SkBitmap::kNo_Config, // a1 -> none
533 SkBitmap::kNo_Config, // a8 -> none
534 SkBitmap::kNo_Config, // index8 -> none
535 SkBitmap::kARGB_4444_Config, // 565 -> 4444
536 SkBitmap::kARGB_8888_Config, // 4444 -> 8888
537 SkBitmap::kRGB_565_Config // 8888 -> 565
538};
539
540static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
541 return gConfigCycle[c];
542}
543
544bool SampleWindow::nextSample() {
reed@android.com34245c72009-11-03 04:00:48 +0000545 fCurrIndex = (fCurrIndex + 1) % fSamples.count();
546 this->loadView(fSamples[fCurrIndex]());
547 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000548}
549
550bool SampleWindow::onEvent(const SkEvent& evt) {
551 if (evt.isType(ANIMATING_EVENTTYPE)) {
552 if (fAnimating) {
553 this->nextSample();
554 this->postAnimatingEvent();
555 }
556 return true;
557 }
reed@android.com34245c72009-11-03 04:00:48 +0000558 if (evt.isType("set-curr-index")) {
559 fCurrIndex = evt.getFast32() % fSamples.count();
560 this->loadView(fSamples[fCurrIndex]());
561 return true;
562 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000563 return this->INHERITED::onEvent(evt);
564}
565
reed@android.comf2b98d62010-12-20 18:26:13 +0000566bool SampleWindow::onQuery(SkEvent* query) {
567 if (query->isType("get-slide-count")) {
568 query->setFast32(fSamples.count());
569 return true;
570 }
571 if (query->isType("get-slide-title")) {
572 SkView* view = fSamples[query->getFast32()]();
573 SkEvent evt(gTitleEvtName);
574 if (view->doQuery(&evt)) {
575 query->setString("title", evt.findString(gTitleEvtName));
576 }
577 SkSafeUnref(view);
578 return true;
579 }
580 if (query->isType("use-fast-text")) {
581 SkEvent evt(gFastTextEvtName);
582 return curr_view(this)->doQuery(&evt);
583 }
584 return this->INHERITED::onQuery(query);
585}
586
reed@android.com0ae6b242008-12-23 16:49:54 +0000587static void cleanup_for_filename(SkString* name) {
588 char* str = name->writable_str();
reed@android.come191b162009-12-18 21:33:39 +0000589 for (size_t i = 0; i < name->size(); i++) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000590 switch (str[i]) {
591 case ':': str[i] = '-'; break;
592 case '/': str[i] = '-'; break;
593 case ' ': str[i] = '_'; break;
594 default: break;
595 }
596 }
597}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000598
599bool SampleWindow::onHandleChar(SkUnichar uni) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000600 {
601 SkView* view = curr_view(this);
602 if (view) {
603 SkEvent evt(gCharEvtName);
604 evt.setFast32(uni);
605 if (view->doQuery(&evt)) {
606 return true;
607 }
608 }
609 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000610
reed@android.com8a1c16f2008-12-17 15:59:43 +0000611 int dx = 0xFF;
612 int dy = 0xFF;
613
614 switch (uni) {
615 case '5': dx = 0; dy = 0; break;
616 case '8': dx = 0; dy = -1; break;
617 case '6': dx = 1; dy = 0; break;
618 case '2': dx = 0; dy = 1; break;
619 case '4': dx = -1; dy = 0; break;
620 case '7': dx = -1; dy = -1; break;
621 case '9': dx = 1; dy = -1; break;
622 case '3': dx = 1; dy = 1; break;
623 case '1': dx = -1; dy = 1; break;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000624
reed@android.com8a1c16f2008-12-17 15:59:43 +0000625 default:
626 break;
627 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000628
reed@android.com8a1c16f2008-12-17 15:59:43 +0000629 if (0xFF != dx && 0xFF != dy) {
630 if ((dx | dy) == 0) {
631 fScrollTestX = fScrollTestY = 0;
632 } else {
633 fScrollTestX += dx;
634 fScrollTestY += dy;
635 }
636 this->inval(NULL);
637 return true;
638 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000639
reed@android.com0ae6b242008-12-23 16:49:54 +0000640 switch (uni) {
641 case 'a':
642 fAnimating = !fAnimating;
643 this->postAnimatingEvent();
644 this->updateTitle();
645 return true;
646 case 'f': {
647 const char* title = this->getTitle();
648 if (title[0] == 0) {
649 title = "sampleapp";
650 }
651 SkString name(title);
652 cleanup_for_filename(&name);
653 name.append(".png");
654 if (SkImageEncoder::EncodeFile(name.c_str(), this->getBitmap(),
reed@android.comb08eb2b2009-01-06 20:16:26 +0000655 SkImageEncoder::kPNG_Type, 100)) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000656 SkDebugf("Created %s\n", name.c_str());
657 }
658 return true;
659 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000660 case 'r':
661 fRotate = !fRotate;
662 this->inval(NULL);
663 this->updateTitle();
664 return true;
665 case 's':
666 fScale = !fScale;
667 this->inval(NULL);
668 this->updateTitle();
669 return true;
reed@google.comfb56a9e2011-02-10 18:47:24 +0000670 case 'c':
671 fUseClip = !fUseClip;
672 this->inval(NULL);
673 this->updateTitle();
674 return true;
reed@android.comf2b98d62010-12-20 18:26:13 +0000675 case 'd':
676 SkGraphics::SetFontCacheUsed(0);
677 return true;
678 case 'g':
679 fRequestGrabImage = true;
680 this->inval(NULL);
681 break;
reed@android.com0ae6b242008-12-23 16:49:54 +0000682 default:
683 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000684 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000685
reed@android.com8a1c16f2008-12-17 15:59:43 +0000686 return this->INHERITED::onHandleChar(uni);
687}
688
689#include "SkDumpCanvas.h"
690
691bool SampleWindow::onHandleKey(SkKey key) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000692 {
693 SkView* view = curr_view(this);
694 if (view) {
695 SkEvent evt(gKeyEvtName);
696 evt.setFast32(key);
697 if (view->doQuery(&evt)) {
698 return true;
699 }
700 }
701 }
702
reed@android.com8a1c16f2008-12-17 15:59:43 +0000703 switch (key) {
704 case kRight_SkKey:
705 if (this->nextSample()) {
706 return true;
707 }
708 break;
709 case kLeft_SkKey:
710 fCanvasType = cycle_canvastype(fCanvasType);
711 this->updateTitle();
712 this->inval(NULL);
713 return true;
714 case kUp_SkKey:
reed@android.come522ca52009-11-23 20:10:41 +0000715 fNClip = !fNClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000716 this->updateTitle();
717 this->inval(NULL);
718 return true;
719 case kDown_SkKey:
720 this->setConfig(cycle_configs(this->getBitmap().config()));
721 this->updateTitle();
722 return true;
723 case kOK_SkKey:
reed@android.comf2b98d62010-12-20 18:26:13 +0000724 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000725 SkDebugfDumper dumper;
726 SkDumpCanvas dc(&dumper);
727 this->draw(&dc);
728 } else {
729 fRepeatDrawing = !fRepeatDrawing;
730 if (fRepeatDrawing) {
731 this->inval(NULL);
732 }
733 }
734 return true;
reed@android.com34245c72009-11-03 04:00:48 +0000735 case kBack_SkKey:
736 this->loadView(NULL);
737 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000738 default:
739 break;
740 }
741 return this->INHERITED::onHandleKey(key);
742}
743
744void SampleWindow::loadView(SkView* view) {
745 SkView::F2BIter iter(this);
746 SkView* prev = iter.next();
747 if (prev) {
748 prev->detachFromParent();
749 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000750
reed@android.com34245c72009-11-03 04:00:48 +0000751 if (NULL == view) {
752 view = create_overview(fSamples.count(), fSamples.begin());
753 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000754 view->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000755 view->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000756 this->attachChildToFront(view)->unref();
757 view->setSize(this->width(), this->height());
758
759 this->updateTitle();
760}
761
762static const char* gConfigNames[] = {
763 "unknown config",
764 "A1",
765 "A8",
766 "Index8",
767 "565",
768 "4444",
769 "8888"
770};
771
772static const char* configToString(SkBitmap::Config c) {
773 return gConfigNames[c];
774}
775
776static const char* gCanvasTypePrefix[] = {
777 "raster: ",
778 "picture: ",
779 "opengl: "
780};
781
782void SampleWindow::updateTitle() {
783 SkString title;
784
785 SkView::F2BIter iter(this);
786 SkView* view = iter.next();
787 SkEvent evt(gTitleEvtName);
788 if (view->doQuery(&evt)) {
789 title.set(evt.findString(gTitleEvtName));
790 }
791 if (title.size() == 0) {
792 title.set("<unknown>");
793 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000794
reed@android.com8a1c16f2008-12-17 15:59:43 +0000795 title.prepend(gCanvasTypePrefix[fCanvasType]);
796
797 title.prepend(" ");
798 title.prepend(configToString(this->getBitmap().config()));
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000799
reed@android.com8a1c16f2008-12-17 15:59:43 +0000800 if (fAnimating) {
801 title.prepend("<A> ");
802 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000803 if (fScale) {
804 title.prepend("<S> ");
805 }
806 if (fRotate) {
807 title.prepend("<R> ");
808 }
reed@android.come522ca52009-11-23 20:10:41 +0000809 if (fNClip) {
810 title.prepend("<C> ");
811 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812 this->setTitle(title.c_str());
813}
814
815void SampleWindow::onSizeChange() {
816 this->INHERITED::onSizeChange();
817
818 SkView::F2BIter iter(this);
819 SkView* view = iter.next();
820 view->setSize(this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000821
reed@android.com8a1c16f2008-12-17 15:59:43 +0000822 // rebuild our clippath
823 {
824 const SkScalar W = this->width();
825 const SkScalar H = this->height();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000826
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827 fClipPath.reset();
828#if 0
829 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
830 SkRect r;
831 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
832 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
833 fClipPath.addRect(r);
834 }
835#else
836 SkRect r;
837 r.set(0, 0, W, H);
838 fClipPath.addRect(r, SkPath::kCCW_Direction);
839 r.set(W/4, H/4, W*3/4, H*3/4);
840 fClipPath.addRect(r, SkPath::kCW_Direction);
841#endif
842 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000843
reed@android.com8a1c16f2008-12-17 15:59:43 +0000844 this->updateTitle(); // to refresh our config
845}
846
847///////////////////////////////////////////////////////////////////////////////
848
reed@android.comf2b98d62010-12-20 18:26:13 +0000849template <typename T> void SkTBSort(T array[], int count) {
850 for (int i = 1; i < count - 1; i++) {
851 bool didSwap = false;
852 for (int j = count - 1; j > i; --j) {
853 if (array[j] < array[j-1]) {
854 T tmp(array[j-1]);
855 array[j-1] = array[j];
856 array[j] = tmp;
857 didSwap = true;
858 }
859 }
860 if (!didSwap) {
861 break;
862 }
863 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000864
reed@android.comf2b98d62010-12-20 18:26:13 +0000865 for (int k = 0; k < count - 1; k++) {
866 SkASSERT(!(array[k+1] < array[k]));
867 }
868}
869
870#include "SkRandom.h"
871
872static void rand_rect(SkIRect* rect, SkRandom& rand) {
873 int bits = 8;
874 int shift = 32 - bits;
875 rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
876 rand.nextU() >> shift, rand.nextU() >> shift);
877 rect->sort();
878}
879
880static void dumpRect(const SkIRect& r) {
881 SkDebugf(" { %d, %d, %d, %d },\n",
882 r.fLeft, r.fTop,
883 r.fRight, r.fBottom);
884}
885
886static void test_rects(const SkIRect rect[], int count) {
887 SkRegion rgn0, rgn1;
888
889 for (int i = 0; i < count; i++) {
890 rgn0.op(rect[i], SkRegion::kUnion_Op);
891 // dumpRect(rect[i]);
892 }
893 rgn1.setRects(rect, count);
894
895 if (rgn0 != rgn1) {
896 SkDebugf("\n");
897 for (int i = 0; i < count; i++) {
898 dumpRect(rect[i]);
899 }
900 SkDebugf("\n");
901 }
902}
903
904static void test() {
905 size_t i;
906
907 const SkIRect r0[] = {
908 { 0, 0, 1, 1 },
909 { 2, 2, 3, 3 },
910 };
911 const SkIRect r1[] = {
912 { 0, 0, 1, 3 },
913 { 1, 1, 2, 2 },
914 { 2, 0, 3, 3 },
915 };
916 const SkIRect r2[] = {
917 { 0, 0, 1, 2 },
918 { 2, 1, 3, 3 },
919 { 4, 0, 5, 1 },
920 { 6, 0, 7, 4 },
921 };
922
923 static const struct {
924 const SkIRect* fRects;
925 int fCount;
926 } gRecs[] = {
927 { r0, SK_ARRAY_COUNT(r0) },
928 { r1, SK_ARRAY_COUNT(r1) },
929 { r2, SK_ARRAY_COUNT(r2) },
930 };
931
932 for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
933 test_rects(gRecs[i].fRects, gRecs[i].fCount);
934 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000935
reed@android.comf2b98d62010-12-20 18:26:13 +0000936 SkRandom rand;
937 for (i = 0; i < 10000; i++) {
938 SkRegion rgn0, rgn1;
939
940 const int N = 8;
941 SkIRect rect[N];
942 for (int j = 0; j < N; j++) {
943 rand_rect(&rect[j], rand);
944 }
945 test_rects(rect, N);
946 }
947}
948
reed@android.com8a1c16f2008-12-17 15:59:43 +0000949SkOSWindow* create_sk_window(void* hwnd) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000950// test();
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000951 return new SampleWindow(hwnd);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000952}
953
954void get_preferred_size(int* x, int* y, int* width, int* height) {
955 *x = 10;
956 *y = 50;
957 *width = 640;
958 *height = 480;
959}
960
961void application_init() {
962// setenv("ANDROID_ROOT", "../../../data", 0);
reed@android.come191b162009-12-18 21:33:39 +0000963#ifdef SK_BUILD_FOR_MAC
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964 setenv("ANDROID_ROOT", "/android/device/data", 0);
reed@android.come191b162009-12-18 21:33:39 +0000965#endif
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000966 SkGraphics::Init();
967 SkEvent::Init();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968}
969
970void application_term() {
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000971 SkEvent::Term();
972 SkGraphics::Term();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973}