blob: 9600b95c8f5c2f3ad151ef31d36c4df8f2fce5ff [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 }
39
40 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
48static GrContext* get_global_grctx(SkOSWindow* oswin) {
reed@android.comf2b98d62010-12-20 18:26:13 +000049 // should be pthread-local at least
50 static GrContext* ctx;
51 if (NULL == ctx) {
52#if defined(SK_SUPPORT_GL)
53 #if defined(SK_USE_SHADERS)
54 ctx = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
55 #else
56 ctx = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, NULL);
57 #endif
reed@android.comf2b98d62010-12-20 18:26:13 +000058#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000059 }
reed@android.comf2b98d62010-12-20 18:26:13 +000060 return ctx;
reed@android.comf2b98d62010-12-20 18:26:13 +000061}
reed@android.com8a1c16f2008-12-17 15:59:43 +000062
63//////////////////////////////////////////////////////////////////////////////
64
reed@android.comf2b98d62010-12-20 18:26:13 +000065static const char gCharEvtName[] = "SampleCode_Char_Event";
66static const char gKeyEvtName[] = "SampleCode_Key_Event";
reed@android.com8a1c16f2008-12-17 15:59:43 +000067static const char gTitleEvtName[] = "SampleCode_Title_Event";
68static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event";
reed@android.comf2b98d62010-12-20 18:26:13 +000069static const char gFastTextEvtName[] = "SampleCode_FastText_Event";
70
71bool SampleCode::CharQ(const SkEvent& evt, SkUnichar* outUni) {
72 if (evt.isType(gCharEvtName, sizeof(gCharEvtName) - 1)) {
73 if (outUni) {
74 *outUni = evt.getFast32();
75 }
76 return true;
77 }
78 return false;
79}
80
81bool SampleCode::KeyQ(const SkEvent& evt, SkKey* outKey) {
82 if (evt.isType(gKeyEvtName, sizeof(gKeyEvtName) - 1)) {
83 if (outKey) {
84 *outKey = (SkKey)evt.getFast32();
85 }
86 return true;
87 }
88 return false;
89}
reed@android.com8a1c16f2008-12-17 15:59:43 +000090
91bool SampleCode::TitleQ(const SkEvent& evt) {
92 return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1);
93}
94
95void SampleCode::TitleR(SkEvent* evt, const char title[]) {
96 SkASSERT(evt && TitleQ(*evt));
97 evt->setString(gTitleEvtName, title);
98}
99
100bool SampleCode::PrefSizeQ(const SkEvent& evt) {
101 return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1);
102}
103
104void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) {
105 SkASSERT(evt && PrefSizeQ(*evt));
106 SkScalar size[2];
107 size[0] = width;
108 size[1] = height;
109 evt->setScalars(gPrefSizeEvtName, 2, size);
110}
111
reed@android.comf2b98d62010-12-20 18:26:13 +0000112bool SampleCode::FastTextQ(const SkEvent& evt) {
113 return evt.isType(gFastTextEvtName, sizeof(gFastTextEvtName) - 1);
114}
115
116///////////////////////////////////////////////////////////////////////////////
117
reed@android.com44177402009-11-23 21:07:51 +0000118static SkMSec gAnimTime;
reed@android.comf2b98d62010-12-20 18:26:13 +0000119static SkMSec gAnimTimePrev;
120
reed@android.com44177402009-11-23 21:07:51 +0000121SkMSec SampleCode::GetAnimTime() { return gAnimTime; }
reed@android.comf2b98d62010-12-20 18:26:13 +0000122SkMSec SampleCode::GetAnimTimeDelta() { return gAnimTime - gAnimTimePrev; }
123SkScalar SampleCode::GetAnimSecondsDelta() {
124 return SkDoubleToScalar(GetAnimTimeDelta() / 1000.0);
125}
reed@android.com44177402009-11-23 21:07:51 +0000126
127SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000128 // since gAnimTime can be up to 32 bits, we can't convert it to a float
129 // or we'll lose the low bits. Hence we use doubles for the intermediate
130 // calculations
131 double seconds = (double)gAnimTime / 1000.0;
132 double value = SkScalarToDouble(speed) * seconds;
reed@android.com44177402009-11-23 21:07:51 +0000133 if (period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000134 value = ::fmod(value, SkScalarToDouble(period));
reed@android.com44177402009-11-23 21:07:51 +0000135 }
reed@android.comf2b98d62010-12-20 18:26:13 +0000136 return SkDoubleToScalar(value);
reed@android.com44177402009-11-23 21:07:51 +0000137}
138
reed@android.com8a1c16f2008-12-17 15:59:43 +0000139//////////////////////////////////////////////////////////////////////////////
140
reed@android.comf2b98d62010-12-20 18:26:13 +0000141static SkView* curr_view(SkWindow* wind) {
142 SkView::F2BIter iter(wind);
143 return iter.next();
144}
145
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146class SampleWindow : public SkOSWindow {
reed@android.com34245c72009-11-03 04:00:48 +0000147 SkTDArray<SkViewFactory> fSamples;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148public:
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000149 SampleWindow(void* hwnd);
150 virtual ~SampleWindow();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151
reed@android.come522ca52009-11-23 20:10:41 +0000152 virtual void draw(SkCanvas* canvas);
153
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154protected:
155 virtual void onDraw(SkCanvas* canvas);
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000156 virtual bool onHandleKey(SkKey key);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 virtual bool onHandleChar(SkUnichar);
158 virtual void onSizeChange();
159
160 virtual SkCanvas* beforeChildren(SkCanvas*);
161 virtual void afterChildren(SkCanvas*);
reed@android.com6c5f6f22009-08-14 16:08:38 +0000162 virtual void beforeChild(SkView* child, SkCanvas* canvas);
163 virtual void afterChild(SkView* child, SkCanvas* canvas);
164
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000165 virtual bool onEvent(const SkEvent& evt);
reed@android.comf2b98d62010-12-20 18:26:13 +0000166 virtual bool onQuery(SkEvent* evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167
168#if 0
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000169 virtual bool handleChar(SkUnichar uni);
170 virtual bool handleEvent(const SkEvent& evt);
171 virtual bool handleKey(SkKey key);
172 virtual bool handleKeyUp(SkKey key);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000174 virtual bool onClick(Click* click);
175 virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 virtual bool onHandleKeyUp(SkKey key);
177#endif
178private:
reed@android.com34245c72009-11-03 04:00:48 +0000179 int fCurrIndex;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180
181 SkPicture* fPicture;
reed@android.comf2b98d62010-12-20 18:26:13 +0000182 SkGpuCanvas* fGpuCanvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183 SkPath fClipPath;
184
185 enum CanvasType {
186 kRaster_CanvasType,
187 kPicture_CanvasType,
reed@android.comf2b98d62010-12-20 18:26:13 +0000188 kGPU_CanvasType
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 };
190 CanvasType fCanvasType;
191
192 bool fUseClip;
reed@android.come522ca52009-11-23 20:10:41 +0000193 bool fNClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194 bool fRepeatDrawing;
195 bool fAnimating;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000196 bool fRotate;
197 bool fScale;
reed@android.comf2b98d62010-12-20 18:26:13 +0000198 bool fRequestGrabImage;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199
200 int fScrollTestX, fScrollTestY;
201
202 void loadView(SkView*);
203 void updateTitle();
204 bool nextSample();
205
206 void postAnimatingEvent() {
207 if (fAnimating) {
208 SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
209 evt->post(this->getSinkID(), ANIMATING_DELAY);
210 }
211 }
212
213
214 static CanvasType cycle_canvastype(CanvasType);
215
216 typedef SkOSWindow INHERITED;
217};
218
219SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
220 static const CanvasType gCT[] = {
221 kPicture_CanvasType,
reed@android.comf2b98d62010-12-20 18:26:13 +0000222 kGPU_CanvasType,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 kRaster_CanvasType
224 };
225 return gCT[ct];
226}
227
228SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229 fPicture = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000230 fGpuCanvas = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231
reed@android.comf2b98d62010-12-20 18:26:13 +0000232#ifdef DEFAULT_TO_GPU
233 fCanvasType = kGPU_CanvasType;
234#else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235 fCanvasType = kRaster_CanvasType;
reed@android.comf2b98d62010-12-20 18:26:13 +0000236#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237 fUseClip = false;
reed@android.come522ca52009-11-23 20:10:41 +0000238 fNClip = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 fRepeatDrawing = false;
240 fAnimating = false;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000241 fRotate = false;
242 fScale = false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000243 fRequestGrabImage = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244
245 fScrollTestX = fScrollTestY = 0;
246
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000247// this->setConfig(SkBitmap::kRGB_565_Config);
248 this->setConfig(SkBitmap::kARGB_8888_Config);
249 this->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000250 this->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251
reed@android.com34245c72009-11-03 04:00:48 +0000252 {
253 const SkViewRegister* reg = SkViewRegister::Head();
254 while (reg) {
255 *fSamples.append() = reg->factory();
256 reg = reg->next();
257 }
258 }
259 fCurrIndex = 0;
reed@android.come0f13ee2009-11-04 19:40:25 +0000260 this->loadView(fSamples[fCurrIndex]());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261}
262
263SampleWindow::~SampleWindow() {
264 delete fPicture;
reed@android.comf2b98d62010-12-20 18:26:13 +0000265 delete fGpuCanvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266}
267
reed@android.com55e76b22009-11-23 21:46:47 +0000268static SkBitmap capture_bitmap(SkCanvas* canvas) {
269 SkBitmap bm;
270 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
271 src.copyTo(&bm, src.config());
272 return bm;
273}
274
275static bool bitmap_diff(SkCanvas* canvas, const SkBitmap& orig,
276 SkBitmap* diff) {
277 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
278
279 SkAutoLockPixels alp0(src);
280 SkAutoLockPixels alp1(orig);
281 for (int y = 0; y < src.height(); y++) {
282 const void* srcP = src.getAddr(0, y);
283 const void* origP = orig.getAddr(0, y);
284 size_t bytes = src.width() * src.bytesPerPixel();
285 if (memcmp(srcP, origP, bytes)) {
286 SkDebugf("---------- difference on line %d\n", y);
287 return true;
288 }
289 }
290 return false;
291}
292
reed@android.com44177402009-11-23 21:07:51 +0000293#define XCLIP_N 8
294#define YCLIP_N 8
reed@android.come522ca52009-11-23 20:10:41 +0000295
296void SampleWindow::draw(SkCanvas* canvas) {
reed@android.com44177402009-11-23 21:07:51 +0000297 // update the animation time
reed@android.comf2b98d62010-12-20 18:26:13 +0000298 gAnimTimePrev = gAnimTime;
reed@android.com44177402009-11-23 21:07:51 +0000299 gAnimTime = SkTime::GetMSecs();
300
reed@android.come522ca52009-11-23 20:10:41 +0000301 if (fNClip) {
reed@android.com55e76b22009-11-23 21:46:47 +0000302 this->INHERITED::draw(canvas);
303 SkBitmap orig = capture_bitmap(canvas);
reed@android.come522ca52009-11-23 20:10:41 +0000304
305 const SkScalar w = this->width();
306 const SkScalar h = this->height();
307 const SkScalar cw = w / XCLIP_N;
308 const SkScalar ch = h / YCLIP_N;
309 for (int y = 0; y < YCLIP_N; y++) {
reed@android.com55e76b22009-11-23 21:46:47 +0000310 SkRect r;
311 r.fTop = y * ch;
312 r.fBottom = (y + 1) * ch;
313 if (y == YCLIP_N - 1) {
314 r.fBottom = h;
315 }
reed@android.come522ca52009-11-23 20:10:41 +0000316 for (int x = 0; x < XCLIP_N; x++) {
317 SkAutoCanvasRestore acr(canvas, true);
reed@android.com55e76b22009-11-23 21:46:47 +0000318 r.fLeft = x * cw;
319 r.fRight = (x + 1) * cw;
320 if (x == XCLIP_N - 1) {
321 r.fRight = w;
322 }
reed@android.come522ca52009-11-23 20:10:41 +0000323 canvas->clipRect(r);
324 this->INHERITED::draw(canvas);
325 }
326 }
reed@android.com55e76b22009-11-23 21:46:47 +0000327
328 SkBitmap diff;
329 if (bitmap_diff(canvas, orig, &diff)) {
330 }
reed@android.come522ca52009-11-23 20:10:41 +0000331 } else {
332 this->INHERITED::draw(canvas);
333 }
334}
335
reed@android.com8a1c16f2008-12-17 15:59:43 +0000336void SampleWindow::onDraw(SkCanvas* canvas) {
337 if (fRepeatDrawing) {
338 this->inval(NULL);
339 }
340}
341
342#include "SkColorPriv.h"
343
344static void reverseRedAndBlue(const SkBitmap& bm) {
345 SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
346 uint8_t* p = (uint8_t*)bm.getPixels();
347 uint8_t* stop = p + bm.getSize();
348 while (p < stop) {
349 // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
350 unsigned scale = SkAlpha255To256(p[3]);
351 unsigned r = p[2];
352 unsigned b = p[0];
353 p[0] = SkAlphaMul(r, scale);
354 p[1] = SkAlphaMul(p[1], scale);
355 p[2] = SkAlphaMul(b, scale);
356 p += 4;
357 }
358}
359
360SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000361 SkIPoint viewport;
362 bool alreadyGPU = canvas->getViewport(&viewport);
363
364 if (kGPU_CanvasType != fCanvasType) {
reed@android.com6efdc472008-12-19 18:24:35 +0000365#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000366 detachGL();
reed@android.comf2b98d62010-12-20 18:26:13 +0000367#endif
368 }
369
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 switch (fCanvasType) {
371 case kRaster_CanvasType:
372 canvas = this->INHERITED::beforeChildren(canvas);
373 break;
374 case kPicture_CanvasType:
375 fPicture = new SkPicture;
376 canvas = fPicture->beginRecording(9999, 9999);
377 break;
reed@google.comac10a2d2010-12-22 21:39:39 +0000378 case kGPU_CanvasType: {
reed@android.comf2b98d62010-12-20 18:26:13 +0000379 if (!alreadyGPU) {
380 SkDevice* device = canvas->getDevice();
381 const SkBitmap& bitmap = device->accessBitmap(true);
382#ifdef SK_SUPPORT_GL
383 #ifdef USE_OFFSCREEN
384 // first clear the raster bitmap, so we don't see any leftover bits
385 bitmap.eraseColor(0);
386 // now setup our glcanvas
387 attachGL(&bitmap);
388 #else
389 attachGL(NULL);
390 #endif
391 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
reed@android.comf2b98d62010-12-20 18:26:13 +0000392#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000393 fGpuCanvas = new SkGpuCanvas(get_global_grctx(this));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000394 device = fGpuCanvas->createDevice(SkBitmap::kARGB_8888_Config,
395 bitmap.width(), bitmap.height(),
396 false, false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000397 fGpuCanvas->setDevice(device)->unref();
reed@android.comf2b98d62010-12-20 18:26:13 +0000398 canvas = fGpuCanvas;
399
400 } else {
401 canvas = this->INHERITED::beforeChildren(canvas);
402 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000403 break;
reed@google.comac10a2d2010-12-22 21:39:39 +0000404 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000405 }
406
407 if (fUseClip) {
408 canvas->drawColor(0xFFFF88FF);
409 canvas->clipPath(fClipPath);
410 }
411
412 return canvas;
413}
414
415static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
416 const SkRegion& rgn) {
417 SkCanvas canvas(bm);
418 SkRegion inval(rgn);
419
420 inval.translate(r.fLeft, r.fTop);
421 canvas.clipRegion(inval);
422 canvas.drawColor(0xFFFF8080);
423}
424
425void SampleWindow::afterChildren(SkCanvas* orig) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000426 if (fRequestGrabImage) {
427 fRequestGrabImage = false;
428
429 SkCanvas* canvas = fGpuCanvas ? fGpuCanvas : orig;
430 SkDevice* device = canvas->getDevice();
431 SkBitmap bitmap;
432 SkIRect bounds = { 0, 0, this->width(), this->height() };
433 if (device->readPixels(bounds, &bitmap)) {
434 static int gSampleGrabCounter;
435 SkString name;
436 name.printf("sample_grab_%d", gSampleGrabCounter++);
437 SkImageEncoder::EncodeFile(name.c_str(), bitmap,
438 SkImageEncoder::kPNG_Type, 100);
439 }
440 }
441
reed@android.com8a1c16f2008-12-17 15:59:43 +0000442 switch (fCanvasType) {
443 case kRaster_CanvasType:
444 break;
445 case kPicture_CanvasType:
reed@android.comaefd2bc2009-03-30 21:02:14 +0000446 if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000447 SkPicture* pict = new SkPicture(*fPicture);
448 fPicture->unref();
449 orig->drawPicture(*pict);
450 pict->unref();
reed@android.comaefd2bc2009-03-30 21:02:14 +0000451 } else if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452 SkDynamicMemoryWStream ostream;
453 fPicture->serialize(&ostream);
454 fPicture->unref();
455
456 SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
457 SkPicture pict(&istream);
458 orig->drawPicture(pict);
459 } else {
460 fPicture->draw(orig);
461 fPicture->unref();
462 }
463 fPicture = NULL;
464 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000465#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000466 case kGPU_CanvasType:
467 delete fGpuCanvas;
468 fGpuCanvas = NULL;
469 presentGL();
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000470 #ifdef USE_OFFSCREEN
reed@android.com8a1c16f2008-12-17 15:59:43 +0000471 reverseRedAndBlue(orig->getDevice()->accessBitmap(true));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000472 #endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000473 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000474#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000475 }
476
477// if ((fScrollTestX | fScrollTestY) != 0)
reed@android.comf2b98d62010-12-20 18:26:13 +0000478 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000479 const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
480 int dx = fScrollTestX * 7;
481 int dy = fScrollTestY * 7;
482 SkIRect r;
483 SkRegion inval;
484
485 r.set(50, 50, 50+100, 50+100);
486 bm.scrollRect(&r, dx, dy, &inval);
487 paint_rgn(bm, r, inval);
488 }
489}
490
reed@android.com6c5f6f22009-08-14 16:08:38 +0000491void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
492 if (fScale) {
493 SkScalar scale = SK_Scalar1 * 7 / 10;
494 SkScalar cx = this->width() / 2;
495 SkScalar cy = this->height() / 2;
496 canvas->translate(cx, cy);
497 canvas->scale(scale, scale);
498 canvas->translate(-cx, -cy);
499 }
500 if (fRotate) {
501 SkScalar cx = this->width() / 2;
502 SkScalar cy = this->height() / 2;
503 canvas->translate(cx, cy);
504 canvas->rotate(SkIntToScalar(30));
505 canvas->translate(-cx, -cy);
506 }
507}
508
509void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) {
510}
511
reed@android.com8a1c16f2008-12-17 15:59:43 +0000512static SkBitmap::Config gConfigCycle[] = {
513 SkBitmap::kNo_Config, // none -> none
514 SkBitmap::kNo_Config, // a1 -> none
515 SkBitmap::kNo_Config, // a8 -> none
516 SkBitmap::kNo_Config, // index8 -> none
517 SkBitmap::kARGB_4444_Config, // 565 -> 4444
518 SkBitmap::kARGB_8888_Config, // 4444 -> 8888
519 SkBitmap::kRGB_565_Config // 8888 -> 565
520};
521
522static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
523 return gConfigCycle[c];
524}
525
526bool SampleWindow::nextSample() {
reed@android.com34245c72009-11-03 04:00:48 +0000527 fCurrIndex = (fCurrIndex + 1) % fSamples.count();
528 this->loadView(fSamples[fCurrIndex]());
529 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530}
531
532bool SampleWindow::onEvent(const SkEvent& evt) {
533 if (evt.isType(ANIMATING_EVENTTYPE)) {
534 if (fAnimating) {
535 this->nextSample();
536 this->postAnimatingEvent();
537 }
538 return true;
539 }
reed@android.com34245c72009-11-03 04:00:48 +0000540 if (evt.isType("set-curr-index")) {
541 fCurrIndex = evt.getFast32() % fSamples.count();
542 this->loadView(fSamples[fCurrIndex]());
543 return true;
544 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000545 return this->INHERITED::onEvent(evt);
546}
547
reed@android.comf2b98d62010-12-20 18:26:13 +0000548bool SampleWindow::onQuery(SkEvent* query) {
549 if (query->isType("get-slide-count")) {
550 query->setFast32(fSamples.count());
551 return true;
552 }
553 if (query->isType("get-slide-title")) {
554 SkView* view = fSamples[query->getFast32()]();
555 SkEvent evt(gTitleEvtName);
556 if (view->doQuery(&evt)) {
557 query->setString("title", evt.findString(gTitleEvtName));
558 }
559 SkSafeUnref(view);
560 return true;
561 }
562 if (query->isType("use-fast-text")) {
563 SkEvent evt(gFastTextEvtName);
564 return curr_view(this)->doQuery(&evt);
565 }
566 return this->INHERITED::onQuery(query);
567}
568
reed@android.com0ae6b242008-12-23 16:49:54 +0000569static void cleanup_for_filename(SkString* name) {
570 char* str = name->writable_str();
reed@android.come191b162009-12-18 21:33:39 +0000571 for (size_t i = 0; i < name->size(); i++) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000572 switch (str[i]) {
573 case ':': str[i] = '-'; break;
574 case '/': str[i] = '-'; break;
575 case ' ': str[i] = '_'; break;
576 default: break;
577 }
578 }
579}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000580
581bool SampleWindow::onHandleChar(SkUnichar uni) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000582 {
583 SkView* view = curr_view(this);
584 if (view) {
585 SkEvent evt(gCharEvtName);
586 evt.setFast32(uni);
587 if (view->doQuery(&evt)) {
588 return true;
589 }
590 }
591 }
592
reed@android.com8a1c16f2008-12-17 15:59:43 +0000593 int dx = 0xFF;
594 int dy = 0xFF;
595
596 switch (uni) {
597 case '5': dx = 0; dy = 0; break;
598 case '8': dx = 0; dy = -1; break;
599 case '6': dx = 1; dy = 0; break;
600 case '2': dx = 0; dy = 1; break;
601 case '4': dx = -1; dy = 0; break;
602 case '7': dx = -1; dy = -1; break;
603 case '9': dx = 1; dy = -1; break;
604 case '3': dx = 1; dy = 1; break;
605 case '1': dx = -1; dy = 1; break;
606
607 default:
608 break;
609 }
610
611 if (0xFF != dx && 0xFF != dy) {
612 if ((dx | dy) == 0) {
613 fScrollTestX = fScrollTestY = 0;
614 } else {
615 fScrollTestX += dx;
616 fScrollTestY += dy;
617 }
618 this->inval(NULL);
619 return true;
620 }
621
reed@android.com0ae6b242008-12-23 16:49:54 +0000622 switch (uni) {
623 case 'a':
624 fAnimating = !fAnimating;
625 this->postAnimatingEvent();
626 this->updateTitle();
627 return true;
628 case 'f': {
629 const char* title = this->getTitle();
630 if (title[0] == 0) {
631 title = "sampleapp";
632 }
633 SkString name(title);
634 cleanup_for_filename(&name);
635 name.append(".png");
636 if (SkImageEncoder::EncodeFile(name.c_str(), this->getBitmap(),
reed@android.comb08eb2b2009-01-06 20:16:26 +0000637 SkImageEncoder::kPNG_Type, 100)) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000638 SkDebugf("Created %s\n", name.c_str());
639 }
640 return true;
641 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000642 case 'r':
643 fRotate = !fRotate;
644 this->inval(NULL);
645 this->updateTitle();
646 return true;
647 case 's':
648 fScale = !fScale;
649 this->inval(NULL);
650 this->updateTitle();
651 return true;
reed@android.comf2b98d62010-12-20 18:26:13 +0000652 case 'd':
653 SkGraphics::SetFontCacheUsed(0);
654 return true;
655 case 'g':
656 fRequestGrabImage = true;
657 this->inval(NULL);
658 break;
reed@android.com0ae6b242008-12-23 16:49:54 +0000659 default:
660 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661 }
662
663 return this->INHERITED::onHandleChar(uni);
664}
665
666#include "SkDumpCanvas.h"
667
668bool SampleWindow::onHandleKey(SkKey key) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000669 {
670 SkView* view = curr_view(this);
671 if (view) {
672 SkEvent evt(gKeyEvtName);
673 evt.setFast32(key);
674 if (view->doQuery(&evt)) {
675 return true;
676 }
677 }
678 }
679
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680 switch (key) {
681 case kRight_SkKey:
682 if (this->nextSample()) {
683 return true;
684 }
685 break;
686 case kLeft_SkKey:
687 fCanvasType = cycle_canvastype(fCanvasType);
688 this->updateTitle();
689 this->inval(NULL);
690 return true;
691 case kUp_SkKey:
reed@android.come522ca52009-11-23 20:10:41 +0000692 fNClip = !fNClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693 this->updateTitle();
694 this->inval(NULL);
695 return true;
696 case kDown_SkKey:
697 this->setConfig(cycle_configs(this->getBitmap().config()));
698 this->updateTitle();
699 return true;
700 case kOK_SkKey:
reed@android.comf2b98d62010-12-20 18:26:13 +0000701 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000702 SkDebugfDumper dumper;
703 SkDumpCanvas dc(&dumper);
704 this->draw(&dc);
705 } else {
706 fRepeatDrawing = !fRepeatDrawing;
707 if (fRepeatDrawing) {
708 this->inval(NULL);
709 }
710 }
711 return true;
reed@android.com34245c72009-11-03 04:00:48 +0000712 case kBack_SkKey:
713 this->loadView(NULL);
714 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000715 default:
716 break;
717 }
718 return this->INHERITED::onHandleKey(key);
719}
720
721void SampleWindow::loadView(SkView* view) {
722 SkView::F2BIter iter(this);
723 SkView* prev = iter.next();
724 if (prev) {
725 prev->detachFromParent();
726 }
reed@android.com34245c72009-11-03 04:00:48 +0000727
728 if (NULL == view) {
729 view = create_overview(fSamples.count(), fSamples.begin());
730 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000731 view->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000732 view->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000733 this->attachChildToFront(view)->unref();
734 view->setSize(this->width(), this->height());
735
736 this->updateTitle();
737}
738
739static const char* gConfigNames[] = {
740 "unknown config",
741 "A1",
742 "A8",
743 "Index8",
744 "565",
745 "4444",
746 "8888"
747};
748
749static const char* configToString(SkBitmap::Config c) {
750 return gConfigNames[c];
751}
752
753static const char* gCanvasTypePrefix[] = {
754 "raster: ",
755 "picture: ",
756 "opengl: "
757};
758
759void SampleWindow::updateTitle() {
760 SkString title;
761
762 SkView::F2BIter iter(this);
763 SkView* view = iter.next();
764 SkEvent evt(gTitleEvtName);
765 if (view->doQuery(&evt)) {
766 title.set(evt.findString(gTitleEvtName));
767 }
768 if (title.size() == 0) {
769 title.set("<unknown>");
770 }
771
772 title.prepend(gCanvasTypePrefix[fCanvasType]);
773
774 title.prepend(" ");
775 title.prepend(configToString(this->getBitmap().config()));
776
777 if (fAnimating) {
778 title.prepend("<A> ");
779 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000780 if (fScale) {
781 title.prepend("<S> ");
782 }
783 if (fRotate) {
784 title.prepend("<R> ");
785 }
reed@android.come522ca52009-11-23 20:10:41 +0000786 if (fNClip) {
787 title.prepend("<C> ");
788 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000789 this->setTitle(title.c_str());
790}
791
792void SampleWindow::onSizeChange() {
793 this->INHERITED::onSizeChange();
794
795 SkView::F2BIter iter(this);
796 SkView* view = iter.next();
797 view->setSize(this->width(), this->height());
798
799 // rebuild our clippath
800 {
801 const SkScalar W = this->width();
802 const SkScalar H = this->height();
803
804 fClipPath.reset();
805#if 0
806 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
807 SkRect r;
808 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
809 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
810 fClipPath.addRect(r);
811 }
812#else
813 SkRect r;
814 r.set(0, 0, W, H);
815 fClipPath.addRect(r, SkPath::kCCW_Direction);
816 r.set(W/4, H/4, W*3/4, H*3/4);
817 fClipPath.addRect(r, SkPath::kCW_Direction);
818#endif
819 }
820
821 this->updateTitle(); // to refresh our config
822}
823
824///////////////////////////////////////////////////////////////////////////////
825
reed@android.comf2b98d62010-12-20 18:26:13 +0000826template <typename T> void SkTBSort(T array[], int count) {
827 for (int i = 1; i < count - 1; i++) {
828 bool didSwap = false;
829 for (int j = count - 1; j > i; --j) {
830 if (array[j] < array[j-1]) {
831 T tmp(array[j-1]);
832 array[j-1] = array[j];
833 array[j] = tmp;
834 didSwap = true;
835 }
836 }
837 if (!didSwap) {
838 break;
839 }
840 }
841
842 for (int k = 0; k < count - 1; k++) {
843 SkASSERT(!(array[k+1] < array[k]));
844 }
845}
846
847#include "SkRandom.h"
848
849static void rand_rect(SkIRect* rect, SkRandom& rand) {
850 int bits = 8;
851 int shift = 32 - bits;
852 rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
853 rand.nextU() >> shift, rand.nextU() >> shift);
854 rect->sort();
855}
856
857static void dumpRect(const SkIRect& r) {
858 SkDebugf(" { %d, %d, %d, %d },\n",
859 r.fLeft, r.fTop,
860 r.fRight, r.fBottom);
861}
862
863static void test_rects(const SkIRect rect[], int count) {
864 SkRegion rgn0, rgn1;
865
866 for (int i = 0; i < count; i++) {
867 rgn0.op(rect[i], SkRegion::kUnion_Op);
868 // dumpRect(rect[i]);
869 }
870 rgn1.setRects(rect, count);
871
872 if (rgn0 != rgn1) {
873 SkDebugf("\n");
874 for (int i = 0; i < count; i++) {
875 dumpRect(rect[i]);
876 }
877 SkDebugf("\n");
878 }
879}
880
881static void test() {
882 size_t i;
883
884 const SkIRect r0[] = {
885 { 0, 0, 1, 1 },
886 { 2, 2, 3, 3 },
887 };
888 const SkIRect r1[] = {
889 { 0, 0, 1, 3 },
890 { 1, 1, 2, 2 },
891 { 2, 0, 3, 3 },
892 };
893 const SkIRect r2[] = {
894 { 0, 0, 1, 2 },
895 { 2, 1, 3, 3 },
896 { 4, 0, 5, 1 },
897 { 6, 0, 7, 4 },
898 };
899
900 static const struct {
901 const SkIRect* fRects;
902 int fCount;
903 } gRecs[] = {
904 { r0, SK_ARRAY_COUNT(r0) },
905 { r1, SK_ARRAY_COUNT(r1) },
906 { r2, SK_ARRAY_COUNT(r2) },
907 };
908
909 for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
910 test_rects(gRecs[i].fRects, gRecs[i].fCount);
911 }
912
913 SkRandom rand;
914 for (i = 0; i < 10000; i++) {
915 SkRegion rgn0, rgn1;
916
917 const int N = 8;
918 SkIRect rect[N];
919 for (int j = 0; j < N; j++) {
920 rand_rect(&rect[j], rand);
921 }
922 test_rects(rect, N);
923 }
924}
925
reed@android.com8a1c16f2008-12-17 15:59:43 +0000926SkOSWindow* create_sk_window(void* hwnd) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000927// test();
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000928 return new SampleWindow(hwnd);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000929}
930
931void get_preferred_size(int* x, int* y, int* width, int* height) {
932 *x = 10;
933 *y = 50;
934 *width = 640;
935 *height = 480;
936}
937
938void application_init() {
939// setenv("ANDROID_ROOT", "../../../data", 0);
reed@android.come191b162009-12-18 21:33:39 +0000940#ifdef SK_BUILD_FOR_MAC
reed@android.com8a1c16f2008-12-17 15:59:43 +0000941 setenv("ANDROID_ROOT", "/android/device/data", 0);
reed@android.come191b162009-12-18 21:33:39 +0000942#endif
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000943 SkGraphics::Init();
944 SkEvent::Init();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000945}
946
947void application_term() {
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000948 SkEvent::Term();
949 SkGraphics::Term();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000950}