blob: b9e7b48ca320e9b5b43979d88569270b464584c5 [file] [log] [blame]
reed@android.comf2b98d62010-12-20 18:26:13 +00001#include <OpenGL/gl.h>
2
reed@android.com8a1c16f2008-12-17 15:59:43 +00003#include "SkCanvas.h"
4#include "SkDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00005#include "SkGraphics.h"
reed@android.comb08eb2b2009-01-06 20:16:26 +00006#include "SkImageEncoder.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00007#include "SkPaint.h"
8#include "SkPicture.h"
9#include "SkStream.h"
reed@android.com44177402009-11-23 21:07:51 +000010#include "SkTime.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011#include "SkWindow.h"
12
13#include "SampleCode.h"
14
reed@android.comf2b98d62010-12-20 18:26:13 +000015#ifdef SUPPORT_GPU
16 #include "SkGpuCanvas.h"
17 #include "GrContext.h"
18
19 #ifdef SK_SUPPORT_GL
20 #include "GrGLConfig.h"
21 #elif defined(SK_SUPPORT_D3D9)
22 #include <d3d9.h>
23 #endif
24#else
25 typedef SkCanvas SkGpuCanvas;
26 class GrContext;
27#endif
28
29//#define DEFAULT_TO_GPU
30
reed@android.come191b162009-12-18 21:33:39 +000031extern SkView* create_overview(int, const SkViewFactory[]);
reed@android.com34245c72009-11-03 04:00:48 +000032
reed@android.comcb342352010-07-22 18:27:53 +000033#define SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +000034//#define SK_SUPPORT_D3D9
reed@android.com8a1c16f2008-12-17 15:59:43 +000035
36#define ANIMATING_EVENTTYPE "nextSample"
37#define ANIMATING_DELAY 750
38
reed@android.comf2b98d62010-12-20 18:26:13 +000039#if !defined(SK_BUILD_FOR_WIN32)
40//#define USE_OFFSCREEN
41#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000042
43SkViewRegister* SkViewRegister::gHead;
44SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) {
45 static bool gOnce;
46 if (!gOnce) {
47 gHead = NULL;
48 gOnce = true;
49 }
50
51 fChain = gHead;
52 gHead = this;
53}
54
reed@android.comf2b98d62010-12-20 18:26:13 +000055#if defined(SK_SUPPORT_GL) && defined(SK_SUPPORT_D3D9)
56 #error "choose either GL or D3D9"
reed@android.com8a1c16f2008-12-17 15:59:43 +000057#endif
58
reed@android.comf2b98d62010-12-20 18:26:13 +000059#if defined(SK_SUPPORT_GL)
60 #define SK_USE_SHADERS
61#endif
62
63static GrContext* get_global_grctx(SkOSWindow* oswin) {
64#ifdef SUPPORT_GPU
65 // should be pthread-local at least
66 static GrContext* ctx;
67 if (NULL == ctx) {
68#if defined(SK_SUPPORT_GL)
69 #if defined(SK_USE_SHADERS)
70 ctx = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
71 #else
72 ctx = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, NULL);
73 #endif
74#elif defined(SK_SUPPORT_D3D9)
75 if (oswin->d3d9Device()) {
76 ctx = GrContext::Create(GrGpu::kDirect3D9_Engine,
77 (IDirect3DDevice9*) oswin->d3d9Device());
78 }
79#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000080 }
reed@android.comf2b98d62010-12-20 18:26:13 +000081 return ctx;
82#else
83 return NULL;
reed@android.com6efdc472008-12-19 18:24:35 +000084#endif
reed@android.comf2b98d62010-12-20 18:26:13 +000085}
reed@android.com8a1c16f2008-12-17 15:59:43 +000086
87//////////////////////////////////////////////////////////////////////////////
88
reed@android.comf2b98d62010-12-20 18:26:13 +000089static const char gCharEvtName[] = "SampleCode_Char_Event";
90static const char gKeyEvtName[] = "SampleCode_Key_Event";
reed@android.com8a1c16f2008-12-17 15:59:43 +000091static const char gTitleEvtName[] = "SampleCode_Title_Event";
92static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event";
reed@android.comf2b98d62010-12-20 18:26:13 +000093static const char gFastTextEvtName[] = "SampleCode_FastText_Event";
94
95bool SampleCode::CharQ(const SkEvent& evt, SkUnichar* outUni) {
96 if (evt.isType(gCharEvtName, sizeof(gCharEvtName) - 1)) {
97 if (outUni) {
98 *outUni = evt.getFast32();
99 }
100 return true;
101 }
102 return false;
103}
104
105bool SampleCode::KeyQ(const SkEvent& evt, SkKey* outKey) {
106 if (evt.isType(gKeyEvtName, sizeof(gKeyEvtName) - 1)) {
107 if (outKey) {
108 *outKey = (SkKey)evt.getFast32();
109 }
110 return true;
111 }
112 return false;
113}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114
115bool SampleCode::TitleQ(const SkEvent& evt) {
116 return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1);
117}
118
119void SampleCode::TitleR(SkEvent* evt, const char title[]) {
120 SkASSERT(evt && TitleQ(*evt));
121 evt->setString(gTitleEvtName, title);
122}
123
124bool SampleCode::PrefSizeQ(const SkEvent& evt) {
125 return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1);
126}
127
128void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) {
129 SkASSERT(evt && PrefSizeQ(*evt));
130 SkScalar size[2];
131 size[0] = width;
132 size[1] = height;
133 evt->setScalars(gPrefSizeEvtName, 2, size);
134}
135
reed@android.comf2b98d62010-12-20 18:26:13 +0000136bool SampleCode::FastTextQ(const SkEvent& evt) {
137 return evt.isType(gFastTextEvtName, sizeof(gFastTextEvtName) - 1);
138}
139
140///////////////////////////////////////////////////////////////////////////////
141
reed@android.com44177402009-11-23 21:07:51 +0000142static SkMSec gAnimTime;
reed@android.comf2b98d62010-12-20 18:26:13 +0000143static SkMSec gAnimTimePrev;
144
reed@android.com44177402009-11-23 21:07:51 +0000145SkMSec SampleCode::GetAnimTime() { return gAnimTime; }
reed@android.comf2b98d62010-12-20 18:26:13 +0000146SkMSec SampleCode::GetAnimTimeDelta() { return gAnimTime - gAnimTimePrev; }
147SkScalar SampleCode::GetAnimSecondsDelta() {
148 return SkDoubleToScalar(GetAnimTimeDelta() / 1000.0);
149}
reed@android.com44177402009-11-23 21:07:51 +0000150
151SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000152 // since gAnimTime can be up to 32 bits, we can't convert it to a float
153 // or we'll lose the low bits. Hence we use doubles for the intermediate
154 // calculations
155 double seconds = (double)gAnimTime / 1000.0;
156 double value = SkScalarToDouble(speed) * seconds;
reed@android.com44177402009-11-23 21:07:51 +0000157 if (period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000158 value = ::fmod(value, SkScalarToDouble(period));
reed@android.com44177402009-11-23 21:07:51 +0000159 }
reed@android.comf2b98d62010-12-20 18:26:13 +0000160 return SkDoubleToScalar(value);
reed@android.com44177402009-11-23 21:07:51 +0000161}
162
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163//////////////////////////////////////////////////////////////////////////////
164
reed@android.comf2b98d62010-12-20 18:26:13 +0000165static SkView* curr_view(SkWindow* wind) {
166 SkView::F2BIter iter(wind);
167 return iter.next();
168}
169
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170class SampleWindow : public SkOSWindow {
reed@android.com34245c72009-11-03 04:00:48 +0000171 SkTDArray<SkViewFactory> fSamples;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172public:
173 SampleWindow(void* hwnd);
174 virtual ~SampleWindow();
175
reed@android.come522ca52009-11-23 20:10:41 +0000176 virtual void draw(SkCanvas* canvas);
177
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178protected:
179 virtual void onDraw(SkCanvas* canvas);
180 virtual bool onHandleKey(SkKey key);
181 virtual bool onHandleChar(SkUnichar);
182 virtual void onSizeChange();
183
184 virtual SkCanvas* beforeChildren(SkCanvas*);
185 virtual void afterChildren(SkCanvas*);
reed@android.com6c5f6f22009-08-14 16:08:38 +0000186 virtual void beforeChild(SkView* child, SkCanvas* canvas);
187 virtual void afterChild(SkView* child, SkCanvas* canvas);
188
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 virtual bool onEvent(const SkEvent& evt);
reed@android.comf2b98d62010-12-20 18:26:13 +0000190 virtual bool onQuery(SkEvent* evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191
192#if 0
193 virtual bool handleChar(SkUnichar uni);
194 virtual bool handleEvent(const SkEvent& evt);
195 virtual bool handleKey(SkKey key);
196 virtual bool handleKeyUp(SkKey key);
197
198 virtual bool onClick(Click* click);
199 virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
200 virtual bool onHandleKeyUp(SkKey key);
201#endif
202private:
reed@android.com34245c72009-11-03 04:00:48 +0000203 int fCurrIndex;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204
205 SkPicture* fPicture;
reed@android.comf2b98d62010-12-20 18:26:13 +0000206 SkGpuCanvas* fGpuCanvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 SkPath fClipPath;
208
209 enum CanvasType {
210 kRaster_CanvasType,
211 kPicture_CanvasType,
reed@android.comf2b98d62010-12-20 18:26:13 +0000212 kGPU_CanvasType
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213 };
214 CanvasType fCanvasType;
215
216 bool fUseClip;
reed@android.come522ca52009-11-23 20:10:41 +0000217 bool fNClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 bool fRepeatDrawing;
219 bool fAnimating;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000220 bool fRotate;
221 bool fScale;
reed@android.comf2b98d62010-12-20 18:26:13 +0000222 bool fRequestGrabImage;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223
224 int fScrollTestX, fScrollTestY;
225
226 void loadView(SkView*);
227 void updateTitle();
228 bool nextSample();
229
230 void postAnimatingEvent() {
231 if (fAnimating) {
232 SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
233 evt->post(this->getSinkID(), ANIMATING_DELAY);
234 }
235 }
236
237
238 static CanvasType cycle_canvastype(CanvasType);
239
240 typedef SkOSWindow INHERITED;
241};
242
243SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
244 static const CanvasType gCT[] = {
245 kPicture_CanvasType,
reed@android.comf2b98d62010-12-20 18:26:13 +0000246 kGPU_CanvasType,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 kRaster_CanvasType
248 };
249 return gCT[ct];
250}
251
252SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253 fPicture = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000254 fGpuCanvas = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255
reed@android.comf2b98d62010-12-20 18:26:13 +0000256#ifdef DEFAULT_TO_GPU
257 fCanvasType = kGPU_CanvasType;
258#else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259 fCanvasType = kRaster_CanvasType;
reed@android.comf2b98d62010-12-20 18:26:13 +0000260#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261 fUseClip = false;
reed@android.come522ca52009-11-23 20:10:41 +0000262 fNClip = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 fRepeatDrawing = false;
264 fAnimating = false;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000265 fRotate = false;
266 fScale = false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000267 fRequestGrabImage = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268
269 fScrollTestX = fScrollTestY = 0;
270
271// this->setConfig(SkBitmap::kRGB_565_Config);
272 this->setConfig(SkBitmap::kARGB_8888_Config);
273 this->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000274 this->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275
reed@android.com34245c72009-11-03 04:00:48 +0000276 {
277 const SkViewRegister* reg = SkViewRegister::Head();
278 while (reg) {
279 *fSamples.append() = reg->factory();
280 reg = reg->next();
281 }
282 }
283 fCurrIndex = 0;
reed@android.come0f13ee2009-11-04 19:40:25 +0000284 this->loadView(fSamples[fCurrIndex]());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285}
286
287SampleWindow::~SampleWindow() {
288 delete fPicture;
reed@android.comf2b98d62010-12-20 18:26:13 +0000289 delete fGpuCanvas;
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);
302
303 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 }
reed@android.com55e76b22009-11-23 21:46:47 +0000351
352 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);
387
388 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();
391#elif defined(SK_SUPPORT_D3D9)
392 detachD3D9();
393#endif
394 }
395
reed@android.com8a1c16f2008-12-17 15:59:43 +0000396 switch (fCanvasType) {
397 case kRaster_CanvasType:
398 canvas = this->INHERITED::beforeChildren(canvas);
399 break;
400 case kPicture_CanvasType:
401 fPicture = new SkPicture;
402 canvas = fPicture->beginRecording(9999, 9999);
403 break;
reed@android.comf2b98d62010-12-20 18:26:13 +0000404#ifdef SUPPORT_GPU
405 case kGPU_CanvasType:
406 if (!alreadyGPU) {
407 SkDevice* device = canvas->getDevice();
408 const SkBitmap& bitmap = device->accessBitmap(true);
409#ifdef SK_SUPPORT_GL
410 #ifdef USE_OFFSCREEN
411 // first clear the raster bitmap, so we don't see any leftover bits
412 bitmap.eraseColor(0);
413 // now setup our glcanvas
414 attachGL(&bitmap);
415 #else
416 attachGL(NULL);
417 #endif
418 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
419#elif defined(SK_SUPPORT_D3D9)
420 // now setup our canvas
421 attachD3D9();
422#endif
423 SkBitmap viewport;
424 viewport.setConfig(SkBitmap::kARGB_8888_Config, bitmap.width(), bitmap.height());
425 fGpuCanvas = new SkGpuCanvas(get_global_grctx(this));
426 fGpuCanvas->setBitmapDevice(viewport);
427 canvas = fGpuCanvas;
428
429 } else {
430 canvas = this->INHERITED::beforeChildren(canvas);
431 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000433#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000434 }
435
436 if (fUseClip) {
437 canvas->drawColor(0xFFFF88FF);
438 canvas->clipPath(fClipPath);
439 }
440
441 return canvas;
442}
443
444static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
445 const SkRegion& rgn) {
446 SkCanvas canvas(bm);
447 SkRegion inval(rgn);
448
449 inval.translate(r.fLeft, r.fTop);
450 canvas.clipRegion(inval);
451 canvas.drawColor(0xFFFF8080);
452}
453
454void SampleWindow::afterChildren(SkCanvas* orig) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000455 if (fRequestGrabImage) {
456 fRequestGrabImage = false;
457
458 SkCanvas* canvas = fGpuCanvas ? fGpuCanvas : orig;
459 SkDevice* device = canvas->getDevice();
460 SkBitmap bitmap;
461 SkIRect bounds = { 0, 0, this->width(), this->height() };
462 if (device->readPixels(bounds, &bitmap)) {
463 static int gSampleGrabCounter;
464 SkString name;
465 name.printf("sample_grab_%d", gSampleGrabCounter++);
466 SkImageEncoder::EncodeFile(name.c_str(), bitmap,
467 SkImageEncoder::kPNG_Type, 100);
468 }
469 }
470
reed@android.com8a1c16f2008-12-17 15:59:43 +0000471 switch (fCanvasType) {
472 case kRaster_CanvasType:
473 break;
474 case kPicture_CanvasType:
reed@android.comaefd2bc2009-03-30 21:02:14 +0000475 if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000476 SkPicture* pict = new SkPicture(*fPicture);
477 fPicture->unref();
478 orig->drawPicture(*pict);
479 pict->unref();
reed@android.comaefd2bc2009-03-30 21:02:14 +0000480 } else if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000481 SkDynamicMemoryWStream ostream;
482 fPicture->serialize(&ostream);
483 fPicture->unref();
484
485 SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
486 SkPicture pict(&istream);
487 orig->drawPicture(pict);
488 } else {
489 fPicture->draw(orig);
490 fPicture->unref();
491 }
492 fPicture = NULL;
493 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000494#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000495 case kGPU_CanvasType:
496 delete fGpuCanvas;
497 fGpuCanvas = NULL;
498 presentGL();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000499#ifdef USE_OFFSCREEN
500 reverseRedAndBlue(orig->getDevice()->accessBitmap(true));
501#endif
502 break;
reed@android.comf2b98d62010-12-20 18:26:13 +0000503#elif defined(SK_SUPPORT_D3D9)
504 case kGPU_CanvasType: {
505 delete fGpuCanvas;
506 fGpuCanvas = NULL;
507 presentD3D9();
508 break;
509 }
reed@android.com6efdc472008-12-19 18:24:35 +0000510#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000511
reed@android.com8a1c16f2008-12-17 15:59:43 +0000512 }
513
514// if ((fScrollTestX | fScrollTestY) != 0)
reed@android.comf2b98d62010-12-20 18:26:13 +0000515 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516 const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
517 int dx = fScrollTestX * 7;
518 int dy = fScrollTestY * 7;
519 SkIRect r;
520 SkRegion inval;
521
522 r.set(50, 50, 50+100, 50+100);
523 bm.scrollRect(&r, dx, dy, &inval);
524 paint_rgn(bm, r, inval);
525 }
526}
527
reed@android.com6c5f6f22009-08-14 16:08:38 +0000528void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
529 if (fScale) {
530 SkScalar scale = SK_Scalar1 * 7 / 10;
531 SkScalar cx = this->width() / 2;
532 SkScalar cy = this->height() / 2;
533 canvas->translate(cx, cy);
534 canvas->scale(scale, scale);
535 canvas->translate(-cx, -cy);
536 }
537 if (fRotate) {
538 SkScalar cx = this->width() / 2;
539 SkScalar cy = this->height() / 2;
540 canvas->translate(cx, cy);
541 canvas->rotate(SkIntToScalar(30));
542 canvas->translate(-cx, -cy);
543 }
544}
545
546void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) {
547}
548
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549static SkBitmap::Config gConfigCycle[] = {
550 SkBitmap::kNo_Config, // none -> none
551 SkBitmap::kNo_Config, // a1 -> none
552 SkBitmap::kNo_Config, // a8 -> none
553 SkBitmap::kNo_Config, // index8 -> none
554 SkBitmap::kARGB_4444_Config, // 565 -> 4444
555 SkBitmap::kARGB_8888_Config, // 4444 -> 8888
556 SkBitmap::kRGB_565_Config // 8888 -> 565
557};
558
559static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
560 return gConfigCycle[c];
561}
562
563bool SampleWindow::nextSample() {
reed@android.com34245c72009-11-03 04:00:48 +0000564 fCurrIndex = (fCurrIndex + 1) % fSamples.count();
565 this->loadView(fSamples[fCurrIndex]());
566 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000567}
568
569bool SampleWindow::onEvent(const SkEvent& evt) {
570 if (evt.isType(ANIMATING_EVENTTYPE)) {
571 if (fAnimating) {
572 this->nextSample();
573 this->postAnimatingEvent();
574 }
575 return true;
576 }
reed@android.com34245c72009-11-03 04:00:48 +0000577 if (evt.isType("set-curr-index")) {
578 fCurrIndex = evt.getFast32() % fSamples.count();
579 this->loadView(fSamples[fCurrIndex]());
580 return true;
581 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000582 return this->INHERITED::onEvent(evt);
583}
584
reed@android.comf2b98d62010-12-20 18:26:13 +0000585bool SampleWindow::onQuery(SkEvent* query) {
586 if (query->isType("get-slide-count")) {
587 query->setFast32(fSamples.count());
588 return true;
589 }
590 if (query->isType("get-slide-title")) {
591 SkView* view = fSamples[query->getFast32()]();
592 SkEvent evt(gTitleEvtName);
593 if (view->doQuery(&evt)) {
594 query->setString("title", evt.findString(gTitleEvtName));
595 }
596 SkSafeUnref(view);
597 return true;
598 }
599 if (query->isType("use-fast-text")) {
600 SkEvent evt(gFastTextEvtName);
601 return curr_view(this)->doQuery(&evt);
602 }
603 return this->INHERITED::onQuery(query);
604}
605
reed@android.com0ae6b242008-12-23 16:49:54 +0000606static void cleanup_for_filename(SkString* name) {
607 char* str = name->writable_str();
reed@android.come191b162009-12-18 21:33:39 +0000608 for (size_t i = 0; i < name->size(); i++) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000609 switch (str[i]) {
610 case ':': str[i] = '-'; break;
611 case '/': str[i] = '-'; break;
612 case ' ': str[i] = '_'; break;
613 default: break;
614 }
615 }
616}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000617
618bool SampleWindow::onHandleChar(SkUnichar uni) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000619 {
620 SkView* view = curr_view(this);
621 if (view) {
622 SkEvent evt(gCharEvtName);
623 evt.setFast32(uni);
624 if (view->doQuery(&evt)) {
625 return true;
626 }
627 }
628 }
629
reed@android.com8a1c16f2008-12-17 15:59:43 +0000630 int dx = 0xFF;
631 int dy = 0xFF;
632
633 switch (uni) {
634 case '5': dx = 0; dy = 0; break;
635 case '8': dx = 0; dy = -1; break;
636 case '6': dx = 1; dy = 0; break;
637 case '2': dx = 0; dy = 1; break;
638 case '4': dx = -1; dy = 0; break;
639 case '7': dx = -1; dy = -1; break;
640 case '9': dx = 1; dy = -1; break;
641 case '3': dx = 1; dy = 1; break;
642 case '1': dx = -1; dy = 1; break;
643
644 default:
645 break;
646 }
647
648 if (0xFF != dx && 0xFF != dy) {
649 if ((dx | dy) == 0) {
650 fScrollTestX = fScrollTestY = 0;
651 } else {
652 fScrollTestX += dx;
653 fScrollTestY += dy;
654 }
655 this->inval(NULL);
656 return true;
657 }
658
reed@android.com0ae6b242008-12-23 16:49:54 +0000659 switch (uni) {
660 case 'a':
661 fAnimating = !fAnimating;
662 this->postAnimatingEvent();
663 this->updateTitle();
664 return true;
665 case 'f': {
666 const char* title = this->getTitle();
667 if (title[0] == 0) {
668 title = "sampleapp";
669 }
670 SkString name(title);
671 cleanup_for_filename(&name);
672 name.append(".png");
673 if (SkImageEncoder::EncodeFile(name.c_str(), this->getBitmap(),
reed@android.comb08eb2b2009-01-06 20:16:26 +0000674 SkImageEncoder::kPNG_Type, 100)) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000675 SkDebugf("Created %s\n", name.c_str());
676 }
677 return true;
678 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000679 case 'r':
680 fRotate = !fRotate;
681 this->inval(NULL);
682 this->updateTitle();
683 return true;
684 case 's':
685 fScale = !fScale;
686 this->inval(NULL);
687 this->updateTitle();
688 return true;
reed@android.comf2b98d62010-12-20 18:26:13 +0000689 case 'd':
690 SkGraphics::SetFontCacheUsed(0);
691 return true;
692 case 'g':
693 fRequestGrabImage = true;
694 this->inval(NULL);
695 break;
reed@android.com0ae6b242008-12-23 16:49:54 +0000696 default:
697 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000698 }
699
700 return this->INHERITED::onHandleChar(uni);
701}
702
703#include "SkDumpCanvas.h"
704
705bool SampleWindow::onHandleKey(SkKey key) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000706 {
707 SkView* view = curr_view(this);
708 if (view) {
709 SkEvent evt(gKeyEvtName);
710 evt.setFast32(key);
711 if (view->doQuery(&evt)) {
712 return true;
713 }
714 }
715 }
716
reed@android.com8a1c16f2008-12-17 15:59:43 +0000717 switch (key) {
718 case kRight_SkKey:
719 if (this->nextSample()) {
720 return true;
721 }
722 break;
723 case kLeft_SkKey:
724 fCanvasType = cycle_canvastype(fCanvasType);
725 this->updateTitle();
726 this->inval(NULL);
727 return true;
728 case kUp_SkKey:
reed@android.come522ca52009-11-23 20:10:41 +0000729 fNClip = !fNClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000730 this->updateTitle();
731 this->inval(NULL);
732 return true;
733 case kDown_SkKey:
734 this->setConfig(cycle_configs(this->getBitmap().config()));
735 this->updateTitle();
736 return true;
737 case kOK_SkKey:
reed@android.comf2b98d62010-12-20 18:26:13 +0000738 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000739 SkDebugfDumper dumper;
740 SkDumpCanvas dc(&dumper);
741 this->draw(&dc);
742 } else {
743 fRepeatDrawing = !fRepeatDrawing;
744 if (fRepeatDrawing) {
745 this->inval(NULL);
746 }
747 }
748 return true;
reed@android.com34245c72009-11-03 04:00:48 +0000749 case kBack_SkKey:
750 this->loadView(NULL);
751 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000752 default:
753 break;
754 }
755 return this->INHERITED::onHandleKey(key);
756}
757
758void SampleWindow::loadView(SkView* view) {
759 SkView::F2BIter iter(this);
760 SkView* prev = iter.next();
761 if (prev) {
762 prev->detachFromParent();
763 }
reed@android.com34245c72009-11-03 04:00:48 +0000764
765 if (NULL == view) {
766 view = create_overview(fSamples.count(), fSamples.begin());
767 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768 view->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000769 view->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000770 this->attachChildToFront(view)->unref();
771 view->setSize(this->width(), this->height());
772
773 this->updateTitle();
774}
775
776static const char* gConfigNames[] = {
777 "unknown config",
778 "A1",
779 "A8",
780 "Index8",
781 "565",
782 "4444",
783 "8888"
784};
785
786static const char* configToString(SkBitmap::Config c) {
787 return gConfigNames[c];
788}
789
790static const char* gCanvasTypePrefix[] = {
791 "raster: ",
792 "picture: ",
793 "opengl: "
794};
795
796void SampleWindow::updateTitle() {
797 SkString title;
798
799 SkView::F2BIter iter(this);
800 SkView* view = iter.next();
801 SkEvent evt(gTitleEvtName);
802 if (view->doQuery(&evt)) {
803 title.set(evt.findString(gTitleEvtName));
804 }
805 if (title.size() == 0) {
806 title.set("<unknown>");
807 }
808
809 title.prepend(gCanvasTypePrefix[fCanvasType]);
810
811 title.prepend(" ");
812 title.prepend(configToString(this->getBitmap().config()));
813
814 if (fAnimating) {
815 title.prepend("<A> ");
816 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000817 if (fScale) {
818 title.prepend("<S> ");
819 }
820 if (fRotate) {
821 title.prepend("<R> ");
822 }
reed@android.come522ca52009-11-23 20:10:41 +0000823 if (fNClip) {
824 title.prepend("<C> ");
825 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000826 this->setTitle(title.c_str());
827}
828
829void SampleWindow::onSizeChange() {
830 this->INHERITED::onSizeChange();
831
832 SkView::F2BIter iter(this);
833 SkView* view = iter.next();
834 view->setSize(this->width(), this->height());
835
836 // rebuild our clippath
837 {
838 const SkScalar W = this->width();
839 const SkScalar H = this->height();
840
841 fClipPath.reset();
842#if 0
843 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
844 SkRect r;
845 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
846 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
847 fClipPath.addRect(r);
848 }
849#else
850 SkRect r;
851 r.set(0, 0, W, H);
852 fClipPath.addRect(r, SkPath::kCCW_Direction);
853 r.set(W/4, H/4, W*3/4, H*3/4);
854 fClipPath.addRect(r, SkPath::kCW_Direction);
855#endif
856 }
857
858 this->updateTitle(); // to refresh our config
859}
860
861///////////////////////////////////////////////////////////////////////////////
862
reed@android.comf2b98d62010-12-20 18:26:13 +0000863template <typename T> void SkTBSort(T array[], int count) {
864 for (int i = 1; i < count - 1; i++) {
865 bool didSwap = false;
866 for (int j = count - 1; j > i; --j) {
867 if (array[j] < array[j-1]) {
868 T tmp(array[j-1]);
869 array[j-1] = array[j];
870 array[j] = tmp;
871 didSwap = true;
872 }
873 }
874 if (!didSwap) {
875 break;
876 }
877 }
878
879 for (int k = 0; k < count - 1; k++) {
880 SkASSERT(!(array[k+1] < array[k]));
881 }
882}
883
884#include "SkRandom.h"
885
886static void rand_rect(SkIRect* rect, SkRandom& rand) {
887 int bits = 8;
888 int shift = 32 - bits;
889 rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
890 rand.nextU() >> shift, rand.nextU() >> shift);
891 rect->sort();
892}
893
894static void dumpRect(const SkIRect& r) {
895 SkDebugf(" { %d, %d, %d, %d },\n",
896 r.fLeft, r.fTop,
897 r.fRight, r.fBottom);
898}
899
900static void test_rects(const SkIRect rect[], int count) {
901 SkRegion rgn0, rgn1;
902
903 for (int i = 0; i < count; i++) {
904 rgn0.op(rect[i], SkRegion::kUnion_Op);
905 // dumpRect(rect[i]);
906 }
907 rgn1.setRects(rect, count);
908
909 if (rgn0 != rgn1) {
910 SkDebugf("\n");
911 for (int i = 0; i < count; i++) {
912 dumpRect(rect[i]);
913 }
914 SkDebugf("\n");
915 }
916}
917
918static void test() {
919 size_t i;
920
921 const SkIRect r0[] = {
922 { 0, 0, 1, 1 },
923 { 2, 2, 3, 3 },
924 };
925 const SkIRect r1[] = {
926 { 0, 0, 1, 3 },
927 { 1, 1, 2, 2 },
928 { 2, 0, 3, 3 },
929 };
930 const SkIRect r2[] = {
931 { 0, 0, 1, 2 },
932 { 2, 1, 3, 3 },
933 { 4, 0, 5, 1 },
934 { 6, 0, 7, 4 },
935 };
936
937 static const struct {
938 const SkIRect* fRects;
939 int fCount;
940 } gRecs[] = {
941 { r0, SK_ARRAY_COUNT(r0) },
942 { r1, SK_ARRAY_COUNT(r1) },
943 { r2, SK_ARRAY_COUNT(r2) },
944 };
945
946 for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
947 test_rects(gRecs[i].fRects, gRecs[i].fCount);
948 }
949
950 SkRandom rand;
951 for (i = 0; i < 10000; i++) {
952 SkRegion rgn0, rgn1;
953
954 const int N = 8;
955 SkIRect rect[N];
956 for (int j = 0; j < N; j++) {
957 rand_rect(&rect[j], rand);
958 }
959 test_rects(rect, N);
960 }
961}
962
reed@android.com8a1c16f2008-12-17 15:59:43 +0000963SkOSWindow* create_sk_window(void* hwnd) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000964// test();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965 return new SampleWindow(hwnd);
966}
967
968void get_preferred_size(int* x, int* y, int* width, int* height) {
969 *x = 10;
970 *y = 50;
971 *width = 640;
972 *height = 480;
973}
974
975void application_init() {
976// setenv("ANDROID_ROOT", "../../../data", 0);
reed@android.come191b162009-12-18 21:33:39 +0000977#ifdef SK_BUILD_FOR_MAC
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978 setenv("ANDROID_ROOT", "/android/device/data", 0);
reed@android.come191b162009-12-18 21:33:39 +0000979#endif
reed@android.com5e5adfd2009-03-07 03:39:23 +0000980 SkGraphics::Init();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981 SkEvent::Init();
982}
983
984void application_term() {
985 SkEvent::Term();
986 SkGraphics::Term();
987}