blob: 45cb2bbcde88deb1446239f7aaecd8a53d3726ef [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@google.comac10a2d2010-12-22 21:39:39 +000024#ifdef SK_SUPPORT_GL
25 #include "GrGLConfig.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000026#endif
27
reed@android.com8a1c16f2008-12-17 15:59:43 +000028SkViewRegister* SkViewRegister::gHead;
29SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) {
30 static bool gOnce;
31 if (!gOnce) {
32 gHead = NULL;
33 gOnce = true;
34 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +000035
reed@android.com8a1c16f2008-12-17 15:59:43 +000036 fChain = gHead;
37 gHead = this;
38}
39
reed@android.comf2b98d62010-12-20 18:26:13 +000040#if defined(SK_SUPPORT_GL)
41 #define SK_USE_SHADERS
42#endif
43
reed@android.com8a1c16f2008-12-17 15:59:43 +000044//////////////////////////////////////////////////////////////////////////////
45
reed@android.comf2b98d62010-12-20 18:26:13 +000046static const char gCharEvtName[] = "SampleCode_Char_Event";
47static const char gKeyEvtName[] = "SampleCode_Key_Event";
reed@android.com8a1c16f2008-12-17 15:59:43 +000048static const char gTitleEvtName[] = "SampleCode_Title_Event";
49static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event";
reed@android.comf2b98d62010-12-20 18:26:13 +000050static const char gFastTextEvtName[] = "SampleCode_FastText_Event";
51
52bool SampleCode::CharQ(const SkEvent& evt, SkUnichar* outUni) {
53 if (evt.isType(gCharEvtName, sizeof(gCharEvtName) - 1)) {
54 if (outUni) {
55 *outUni = evt.getFast32();
56 }
57 return true;
58 }
59 return false;
60}
61
62bool SampleCode::KeyQ(const SkEvent& evt, SkKey* outKey) {
63 if (evt.isType(gKeyEvtName, sizeof(gKeyEvtName) - 1)) {
64 if (outKey) {
65 *outKey = (SkKey)evt.getFast32();
66 }
67 return true;
68 }
69 return false;
70}
reed@android.com8a1c16f2008-12-17 15:59:43 +000071
72bool SampleCode::TitleQ(const SkEvent& evt) {
73 return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1);
74}
75
76void SampleCode::TitleR(SkEvent* evt, const char title[]) {
77 SkASSERT(evt && TitleQ(*evt));
78 evt->setString(gTitleEvtName, title);
79}
80
81bool SampleCode::PrefSizeQ(const SkEvent& evt) {
82 return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1);
83}
84
85void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) {
86 SkASSERT(evt && PrefSizeQ(*evt));
87 SkScalar size[2];
88 size[0] = width;
89 size[1] = height;
90 evt->setScalars(gPrefSizeEvtName, 2, size);
91}
92
reed@android.comf2b98d62010-12-20 18:26:13 +000093bool SampleCode::FastTextQ(const SkEvent& evt) {
94 return evt.isType(gFastTextEvtName, sizeof(gFastTextEvtName) - 1);
95}
96
97///////////////////////////////////////////////////////////////////////////////
98
reed@android.com44177402009-11-23 21:07:51 +000099static SkMSec gAnimTime;
reed@android.comf2b98d62010-12-20 18:26:13 +0000100static SkMSec gAnimTimePrev;
101
reed@android.com44177402009-11-23 21:07:51 +0000102SkMSec SampleCode::GetAnimTime() { return gAnimTime; }
reed@android.comf2b98d62010-12-20 18:26:13 +0000103SkMSec SampleCode::GetAnimTimeDelta() { return gAnimTime - gAnimTimePrev; }
104SkScalar SampleCode::GetAnimSecondsDelta() {
105 return SkDoubleToScalar(GetAnimTimeDelta() / 1000.0);
106}
reed@android.com44177402009-11-23 21:07:51 +0000107
108SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000109 // since gAnimTime can be up to 32 bits, we can't convert it to a float
110 // or we'll lose the low bits. Hence we use doubles for the intermediate
111 // calculations
112 double seconds = (double)gAnimTime / 1000.0;
113 double value = SkScalarToDouble(speed) * seconds;
reed@android.com44177402009-11-23 21:07:51 +0000114 if (period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000115 value = ::fmod(value, SkScalarToDouble(period));
reed@android.com44177402009-11-23 21:07:51 +0000116 }
reed@android.comf2b98d62010-12-20 18:26:13 +0000117 return SkDoubleToScalar(value);
reed@android.com44177402009-11-23 21:07:51 +0000118}
119
reed@android.com8a1c16f2008-12-17 15:59:43 +0000120//////////////////////////////////////////////////////////////////////////////
121
reed@android.comf2b98d62010-12-20 18:26:13 +0000122static SkView* curr_view(SkWindow* wind) {
123 SkView::F2BIter iter(wind);
124 return iter.next();
125}
126
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127class SampleWindow : public SkOSWindow {
reed@android.com34245c72009-11-03 04:00:48 +0000128 SkTDArray<SkViewFactory> fSamples;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129public:
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000130 SampleWindow(void* hwnd);
131 virtual ~SampleWindow();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132
reed@android.come522ca52009-11-23 20:10:41 +0000133 virtual void draw(SkCanvas* canvas);
134
reed@android.com8a1c16f2008-12-17 15:59:43 +0000135protected:
136 virtual void onDraw(SkCanvas* canvas);
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000137 virtual bool onHandleKey(SkKey key);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138 virtual bool onHandleChar(SkUnichar);
139 virtual void onSizeChange();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000140
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141 virtual SkCanvas* beforeChildren(SkCanvas*);
142 virtual void afterChildren(SkCanvas*);
reed@android.com6c5f6f22009-08-14 16:08:38 +0000143 virtual void beforeChild(SkView* child, SkCanvas* canvas);
144 virtual void afterChild(SkView* child, SkCanvas* canvas);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000145
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000146 virtual bool onEvent(const SkEvent& evt);
reed@android.comf2b98d62010-12-20 18:26:13 +0000147 virtual bool onQuery(SkEvent* evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148
149#if 0
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000150 virtual bool handleChar(SkUnichar uni);
151 virtual bool handleEvent(const SkEvent& evt);
152 virtual bool handleKey(SkKey key);
153 virtual bool handleKeyUp(SkKey key);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000154
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000155 virtual bool onClick(Click* click);
156 virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 virtual bool onHandleKeyUp(SkKey key);
158#endif
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000159
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160private:
reed@android.com34245c72009-11-03 04:00:48 +0000161 int fCurrIndex;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000162
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163 SkPicture* fPicture;
reed@android.comf2b98d62010-12-20 18:26:13 +0000164 SkGpuCanvas* fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000165 GrContext* fGrContext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166 SkPath fClipPath;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000167
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168 enum CanvasType {
169 kRaster_CanvasType,
170 kPicture_CanvasType,
reed@android.comf2b98d62010-12-20 18:26:13 +0000171 kGPU_CanvasType
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 };
173 CanvasType fCanvasType;
174
175 bool fUseClip;
reed@android.come522ca52009-11-23 20:10:41 +0000176 bool fNClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 bool fRepeatDrawing;
178 bool fAnimating;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000179 bool fRotate;
180 bool fScale;
reed@android.comf2b98d62010-12-20 18:26:13 +0000181 bool fRequestGrabImage;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000182
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183 int fScrollTestX, fScrollTestY;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000184
185 bool make3DReady();
186
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 void loadView(SkView*);
188 void updateTitle();
189 bool nextSample();
190
191 void postAnimatingEvent() {
192 if (fAnimating) {
193 SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
194 evt->post(this->getSinkID(), ANIMATING_DELAY);
195 }
196 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000197
198
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199 static CanvasType cycle_canvastype(CanvasType);
200
201 typedef SkOSWindow INHERITED;
202};
203
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000204bool SampleWindow::make3DReady() {
205
206#if defined(SK_SUPPORT_GL)
bsalomon@google.com498a6232011-03-10 18:24:15 +0000207 if (attachGL()) {
208 if (NULL == fGrContext) {
209 #if defined(SK_USE_SHADERS)
210 fGrContext = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
211 #else
212 fGrContext = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, NULL);
213 #endif
214 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000215
bsalomon@google.com498a6232011-03-10 18:24:15 +0000216 if (NULL != fGrContext) {
217 return true;
218 } else {
219 detachGL();
220 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000221 }
222#endif
223 SkDebugf("Failed to setup 3D");
224 return false;
225}
226
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
228 static const CanvasType gCT[] = {
229 kPicture_CanvasType,
reed@android.comf2b98d62010-12-20 18:26:13 +0000230 kGPU_CanvasType,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 kRaster_CanvasType
232 };
233 return gCT[ct];
234}
235
236SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237 fPicture = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000238 fGpuCanvas = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000240 fGrContext = NULL;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000241
reed@android.comf2b98d62010-12-20 18:26:13 +0000242#ifdef DEFAULT_TO_GPU
243 fCanvasType = kGPU_CanvasType;
244#else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245 fCanvasType = kRaster_CanvasType;
reed@android.comf2b98d62010-12-20 18:26:13 +0000246#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 fUseClip = false;
reed@android.come522ca52009-11-23 20:10:41 +0000248 fNClip = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249 fRepeatDrawing = false;
250 fAnimating = false;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000251 fRotate = false;
252 fScale = false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000253 fRequestGrabImage = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254
255 fScrollTestX = fScrollTestY = 0;
256
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000257// this->setConfig(SkBitmap::kRGB_565_Config);
258 this->setConfig(SkBitmap::kARGB_8888_Config);
259 this->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000260 this->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261
reed@android.com34245c72009-11-03 04:00:48 +0000262 {
263 const SkViewRegister* reg = SkViewRegister::Head();
264 while (reg) {
265 *fSamples.append() = reg->factory();
266 reg = reg->next();
267 }
268 }
269 fCurrIndex = 0;
reed@android.come0f13ee2009-11-04 19:40:25 +0000270 this->loadView(fSamples[fCurrIndex]());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271}
272
273SampleWindow::~SampleWindow() {
274 delete fPicture;
reed@android.comf2b98d62010-12-20 18:26:13 +0000275 delete fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000276 if (NULL != fGrContext) {
277 fGrContext->unref();
278 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279}
280
reed@android.com55e76b22009-11-23 21:46:47 +0000281static SkBitmap capture_bitmap(SkCanvas* canvas) {
282 SkBitmap bm;
283 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
284 src.copyTo(&bm, src.config());
285 return bm;
286}
287
288static bool bitmap_diff(SkCanvas* canvas, const SkBitmap& orig,
289 SkBitmap* diff) {
290 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000291
reed@android.com55e76b22009-11-23 21:46:47 +0000292 SkAutoLockPixels alp0(src);
293 SkAutoLockPixels alp1(orig);
294 for (int y = 0; y < src.height(); y++) {
295 const void* srcP = src.getAddr(0, y);
296 const void* origP = orig.getAddr(0, y);
297 size_t bytes = src.width() * src.bytesPerPixel();
298 if (memcmp(srcP, origP, bytes)) {
299 SkDebugf("---------- difference on line %d\n", y);
300 return true;
301 }
302 }
303 return false;
304}
305
reed@android.com44177402009-11-23 21:07:51 +0000306#define XCLIP_N 8
307#define YCLIP_N 8
reed@android.come522ca52009-11-23 20:10:41 +0000308
309void SampleWindow::draw(SkCanvas* canvas) {
reed@android.com44177402009-11-23 21:07:51 +0000310 // update the animation time
reed@android.comf2b98d62010-12-20 18:26:13 +0000311 gAnimTimePrev = gAnimTime;
reed@android.com44177402009-11-23 21:07:51 +0000312 gAnimTime = SkTime::GetMSecs();
313
reed@android.come522ca52009-11-23 20:10:41 +0000314 if (fNClip) {
reed@android.com55e76b22009-11-23 21:46:47 +0000315 this->INHERITED::draw(canvas);
316 SkBitmap orig = capture_bitmap(canvas);
reed@android.come522ca52009-11-23 20:10:41 +0000317
318 const SkScalar w = this->width();
319 const SkScalar h = this->height();
320 const SkScalar cw = w / XCLIP_N;
321 const SkScalar ch = h / YCLIP_N;
322 for (int y = 0; y < YCLIP_N; y++) {
reed@android.com55e76b22009-11-23 21:46:47 +0000323 SkRect r;
324 r.fTop = y * ch;
325 r.fBottom = (y + 1) * ch;
326 if (y == YCLIP_N - 1) {
327 r.fBottom = h;
328 }
reed@android.come522ca52009-11-23 20:10:41 +0000329 for (int x = 0; x < XCLIP_N; x++) {
330 SkAutoCanvasRestore acr(canvas, true);
reed@android.com55e76b22009-11-23 21:46:47 +0000331 r.fLeft = x * cw;
332 r.fRight = (x + 1) * cw;
333 if (x == XCLIP_N - 1) {
334 r.fRight = w;
335 }
reed@android.come522ca52009-11-23 20:10:41 +0000336 canvas->clipRect(r);
337 this->INHERITED::draw(canvas);
338 }
339 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000340
reed@android.com55e76b22009-11-23 21:46:47 +0000341 SkBitmap diff;
342 if (bitmap_diff(canvas, orig, &diff)) {
343 }
reed@android.come522ca52009-11-23 20:10:41 +0000344 } else {
345 this->INHERITED::draw(canvas);
346 }
347}
348
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349void SampleWindow::onDraw(SkCanvas* canvas) {
350 if (fRepeatDrawing) {
351 this->inval(NULL);
352 }
353}
354
355#include "SkColorPriv.h"
356
357static void reverseRedAndBlue(const SkBitmap& bm) {
358 SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
359 uint8_t* p = (uint8_t*)bm.getPixels();
360 uint8_t* stop = p + bm.getSize();
361 while (p < stop) {
362 // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
363 unsigned scale = SkAlpha255To256(p[3]);
364 unsigned r = p[2];
365 unsigned b = p[0];
366 p[0] = SkAlphaMul(r, scale);
367 p[1] = SkAlphaMul(p[1], scale);
368 p[2] = SkAlphaMul(b, scale);
369 p += 4;
370 }
371}
372
373SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000374 SkIPoint viewport;
375 bool alreadyGPU = canvas->getViewport(&viewport);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000376
reed@android.comf2b98d62010-12-20 18:26:13 +0000377 if (kGPU_CanvasType != fCanvasType) {
reed@android.com6efdc472008-12-19 18:24:35 +0000378#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000379 detachGL();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000380#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000381 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000382
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383 switch (fCanvasType) {
384 case kRaster_CanvasType:
385 canvas = this->INHERITED::beforeChildren(canvas);
386 break;
387 case kPicture_CanvasType:
388 fPicture = new SkPicture;
389 canvas = fPicture->beginRecording(9999, 9999);
390 break;
reed@google.comac10a2d2010-12-22 21:39:39 +0000391 case kGPU_CanvasType: {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000392 if (!alreadyGPU && make3DReady()) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000393 SkDevice* device = canvas->getDevice();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000394 const SkBitmap& bitmap = device->accessBitmap(true);
395
bsalomon@google.com5782d712011-01-21 21:03:59 +0000396 GrRenderTarget* renderTarget;
397 renderTarget = fGrContext->createRenderTargetFrom3DApiState();
398 fGpuCanvas = new SkGpuCanvas(fGrContext, renderTarget);
399 renderTarget->unref();
400
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000401 device = fGpuCanvas->createDevice(SkBitmap::kARGB_8888_Config,
402 bitmap.width(), bitmap.height(),
403 false, false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000404 fGpuCanvas->setDevice(device)->unref();
reed@android.comf2b98d62010-12-20 18:26:13 +0000405 canvas = fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000406
reed@android.comf2b98d62010-12-20 18:26:13 +0000407 } else {
408 canvas = this->INHERITED::beforeChildren(canvas);
409 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000410 break;
reed@google.comac10a2d2010-12-22 21:39:39 +0000411 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000412 }
413
414 if (fUseClip) {
415 canvas->drawColor(0xFFFF88FF);
416 canvas->clipPath(fClipPath);
417 }
418
419 return canvas;
420}
421
422static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
423 const SkRegion& rgn) {
424 SkCanvas canvas(bm);
425 SkRegion inval(rgn);
426
427 inval.translate(r.fLeft, r.fTop);
428 canvas.clipRegion(inval);
429 canvas.drawColor(0xFFFF8080);
430}
431
432void SampleWindow::afterChildren(SkCanvas* orig) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000433 if (fRequestGrabImage) {
434 fRequestGrabImage = false;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000435
reed@android.comf2b98d62010-12-20 18:26:13 +0000436 SkCanvas* canvas = fGpuCanvas ? fGpuCanvas : orig;
437 SkDevice* device = canvas->getDevice();
438 SkBitmap bitmap;
reed@google.com5ba2d5b2011-03-10 19:40:34 +0000439 SkIRect bounds = {
440 0, 0,
441 SkScalarRound(this->width()),
442 SkScalarRound(this->height())
443 };
reed@android.comf2b98d62010-12-20 18:26:13 +0000444 if (device->readPixels(bounds, &bitmap)) {
445 static int gSampleGrabCounter;
446 SkString name;
447 name.printf("sample_grab_%d", gSampleGrabCounter++);
448 SkImageEncoder::EncodeFile(name.c_str(), bitmap,
449 SkImageEncoder::kPNG_Type, 100);
450 }
451 }
452
reed@android.com8a1c16f2008-12-17 15:59:43 +0000453 switch (fCanvasType) {
454 case kRaster_CanvasType:
455 break;
456 case kPicture_CanvasType:
reed@android.comaefd2bc2009-03-30 21:02:14 +0000457 if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000458 SkPicture* pict = new SkPicture(*fPicture);
459 fPicture->unref();
460 orig->drawPicture(*pict);
461 pict->unref();
reed@android.comaefd2bc2009-03-30 21:02:14 +0000462 } else if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000463 SkDynamicMemoryWStream ostream;
464 fPicture->serialize(&ostream);
465 fPicture->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000466
reed@android.com8a1c16f2008-12-17 15:59:43 +0000467 SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
468 SkPicture pict(&istream);
469 orig->drawPicture(pict);
470 } else {
471 fPicture->draw(orig);
472 fPicture->unref();
473 }
474 fPicture = NULL;
475 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000476#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000477 case kGPU_CanvasType:
478 delete fGpuCanvas;
479 fGpuCanvas = NULL;
480 presentGL();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000481 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000482#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000483 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000484
reed@android.com8a1c16f2008-12-17 15:59:43 +0000485// if ((fScrollTestX | fScrollTestY) != 0)
reed@android.comf2b98d62010-12-20 18:26:13 +0000486 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000487 const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
488 int dx = fScrollTestX * 7;
489 int dy = fScrollTestY * 7;
490 SkIRect r;
491 SkRegion inval;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000492
reed@android.com8a1c16f2008-12-17 15:59:43 +0000493 r.set(50, 50, 50+100, 50+100);
494 bm.scrollRect(&r, dx, dy, &inval);
495 paint_rgn(bm, r, inval);
496 }
497}
498
reed@android.com6c5f6f22009-08-14 16:08:38 +0000499void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
500 if (fScale) {
501 SkScalar scale = SK_Scalar1 * 7 / 10;
502 SkScalar cx = this->width() / 2;
503 SkScalar cy = this->height() / 2;
504 canvas->translate(cx, cy);
505 canvas->scale(scale, scale);
506 canvas->translate(-cx, -cy);
507 }
508 if (fRotate) {
509 SkScalar cx = this->width() / 2;
510 SkScalar cy = this->height() / 2;
511 canvas->translate(cx, cy);
512 canvas->rotate(SkIntToScalar(30));
513 canvas->translate(-cx, -cy);
514 }
515}
516
517void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) {
518}
519
reed@android.com8a1c16f2008-12-17 15:59:43 +0000520static SkBitmap::Config gConfigCycle[] = {
521 SkBitmap::kNo_Config, // none -> none
522 SkBitmap::kNo_Config, // a1 -> none
523 SkBitmap::kNo_Config, // a8 -> none
524 SkBitmap::kNo_Config, // index8 -> none
525 SkBitmap::kARGB_4444_Config, // 565 -> 4444
526 SkBitmap::kARGB_8888_Config, // 4444 -> 8888
527 SkBitmap::kRGB_565_Config // 8888 -> 565
528};
529
530static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
531 return gConfigCycle[c];
532}
533
534bool SampleWindow::nextSample() {
reed@android.com34245c72009-11-03 04:00:48 +0000535 fCurrIndex = (fCurrIndex + 1) % fSamples.count();
536 this->loadView(fSamples[fCurrIndex]());
537 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000538}
539
540bool SampleWindow::onEvent(const SkEvent& evt) {
541 if (evt.isType(ANIMATING_EVENTTYPE)) {
542 if (fAnimating) {
543 this->nextSample();
544 this->postAnimatingEvent();
545 }
546 return true;
547 }
reed@android.com34245c72009-11-03 04:00:48 +0000548 if (evt.isType("set-curr-index")) {
549 fCurrIndex = evt.getFast32() % fSamples.count();
550 this->loadView(fSamples[fCurrIndex]());
551 return true;
552 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553 return this->INHERITED::onEvent(evt);
554}
555
reed@android.comf2b98d62010-12-20 18:26:13 +0000556bool SampleWindow::onQuery(SkEvent* query) {
557 if (query->isType("get-slide-count")) {
558 query->setFast32(fSamples.count());
559 return true;
560 }
561 if (query->isType("get-slide-title")) {
562 SkView* view = fSamples[query->getFast32()]();
563 SkEvent evt(gTitleEvtName);
564 if (view->doQuery(&evt)) {
565 query->setString("title", evt.findString(gTitleEvtName));
566 }
567 SkSafeUnref(view);
568 return true;
569 }
570 if (query->isType("use-fast-text")) {
571 SkEvent evt(gFastTextEvtName);
572 return curr_view(this)->doQuery(&evt);
573 }
574 return this->INHERITED::onQuery(query);
575}
576
reed@android.com0ae6b242008-12-23 16:49:54 +0000577static void cleanup_for_filename(SkString* name) {
578 char* str = name->writable_str();
reed@android.come191b162009-12-18 21:33:39 +0000579 for (size_t i = 0; i < name->size(); i++) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000580 switch (str[i]) {
581 case ':': str[i] = '-'; break;
582 case '/': str[i] = '-'; break;
583 case ' ': str[i] = '_'; break;
584 default: break;
585 }
586 }
587}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000588
589bool SampleWindow::onHandleChar(SkUnichar uni) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000590 {
591 SkView* view = curr_view(this);
592 if (view) {
593 SkEvent evt(gCharEvtName);
594 evt.setFast32(uni);
595 if (view->doQuery(&evt)) {
596 return true;
597 }
598 }
599 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000600
reed@android.com8a1c16f2008-12-17 15:59:43 +0000601 int dx = 0xFF;
602 int dy = 0xFF;
603
604 switch (uni) {
605 case '5': dx = 0; dy = 0; break;
606 case '8': dx = 0; dy = -1; break;
607 case '6': dx = 1; dy = 0; break;
608 case '2': dx = 0; dy = 1; break;
609 case '4': dx = -1; dy = 0; break;
610 case '7': dx = -1; dy = -1; break;
611 case '9': dx = 1; dy = -1; break;
612 case '3': dx = 1; dy = 1; break;
613 case '1': dx = -1; dy = 1; break;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000614
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615 default:
616 break;
617 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000618
reed@android.com8a1c16f2008-12-17 15:59:43 +0000619 if (0xFF != dx && 0xFF != dy) {
620 if ((dx | dy) == 0) {
621 fScrollTestX = fScrollTestY = 0;
622 } else {
623 fScrollTestX += dx;
624 fScrollTestY += dy;
625 }
626 this->inval(NULL);
627 return true;
628 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000629
reed@android.com0ae6b242008-12-23 16:49:54 +0000630 switch (uni) {
631 case 'a':
632 fAnimating = !fAnimating;
633 this->postAnimatingEvent();
634 this->updateTitle();
635 return true;
636 case 'f': {
637 const char* title = this->getTitle();
638 if (title[0] == 0) {
639 title = "sampleapp";
640 }
641 SkString name(title);
642 cleanup_for_filename(&name);
643 name.append(".png");
644 if (SkImageEncoder::EncodeFile(name.c_str(), this->getBitmap(),
reed@android.comb08eb2b2009-01-06 20:16:26 +0000645 SkImageEncoder::kPNG_Type, 100)) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000646 SkDebugf("Created %s\n", name.c_str());
647 }
648 return true;
649 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000650 case 'r':
651 fRotate = !fRotate;
652 this->inval(NULL);
653 this->updateTitle();
654 return true;
655 case 's':
656 fScale = !fScale;
657 this->inval(NULL);
658 this->updateTitle();
659 return true;
reed@google.comfb56a9e2011-02-10 18:47:24 +0000660 case 'c':
661 fUseClip = !fUseClip;
662 this->inval(NULL);
663 this->updateTitle();
664 return true;
reed@android.comf2b98d62010-12-20 18:26:13 +0000665 case 'd':
666 SkGraphics::SetFontCacheUsed(0);
667 return true;
668 case 'g':
669 fRequestGrabImage = true;
670 this->inval(NULL);
671 break;
reed@android.com0ae6b242008-12-23 16:49:54 +0000672 default:
673 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000674 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000675
reed@android.com8a1c16f2008-12-17 15:59:43 +0000676 return this->INHERITED::onHandleChar(uni);
677}
678
679#include "SkDumpCanvas.h"
680
681bool SampleWindow::onHandleKey(SkKey key) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000682 {
683 SkView* view = curr_view(this);
684 if (view) {
685 SkEvent evt(gKeyEvtName);
686 evt.setFast32(key);
687 if (view->doQuery(&evt)) {
688 return true;
689 }
690 }
691 }
692
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693 switch (key) {
694 case kRight_SkKey:
695 if (this->nextSample()) {
696 return true;
697 }
698 break;
699 case kLeft_SkKey:
700 fCanvasType = cycle_canvastype(fCanvasType);
701 this->updateTitle();
702 this->inval(NULL);
703 return true;
704 case kUp_SkKey:
reed@android.come522ca52009-11-23 20:10:41 +0000705 fNClip = !fNClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000706 this->updateTitle();
707 this->inval(NULL);
708 return true;
709 case kDown_SkKey:
710 this->setConfig(cycle_configs(this->getBitmap().config()));
711 this->updateTitle();
712 return true;
713 case kOK_SkKey:
reed@android.comf2b98d62010-12-20 18:26:13 +0000714 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000715 SkDebugfDumper dumper;
716 SkDumpCanvas dc(&dumper);
717 this->draw(&dc);
718 } else {
719 fRepeatDrawing = !fRepeatDrawing;
720 if (fRepeatDrawing) {
721 this->inval(NULL);
722 }
723 }
724 return true;
reed@android.com34245c72009-11-03 04:00:48 +0000725 case kBack_SkKey:
726 this->loadView(NULL);
727 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000728 default:
729 break;
730 }
731 return this->INHERITED::onHandleKey(key);
732}
733
734void SampleWindow::loadView(SkView* view) {
735 SkView::F2BIter iter(this);
736 SkView* prev = iter.next();
737 if (prev) {
738 prev->detachFromParent();
739 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000740
reed@android.com34245c72009-11-03 04:00:48 +0000741 if (NULL == view) {
742 view = create_overview(fSamples.count(), fSamples.begin());
743 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000744 view->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000745 view->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746 this->attachChildToFront(view)->unref();
747 view->setSize(this->width(), this->height());
748
749 this->updateTitle();
750}
751
752static const char* gConfigNames[] = {
753 "unknown config",
754 "A1",
755 "A8",
756 "Index8",
757 "565",
758 "4444",
759 "8888"
760};
761
762static const char* configToString(SkBitmap::Config c) {
763 return gConfigNames[c];
764}
765
766static const char* gCanvasTypePrefix[] = {
767 "raster: ",
768 "picture: ",
769 "opengl: "
770};
771
772void SampleWindow::updateTitle() {
773 SkString title;
774
775 SkView::F2BIter iter(this);
776 SkView* view = iter.next();
777 SkEvent evt(gTitleEvtName);
778 if (view->doQuery(&evt)) {
779 title.set(evt.findString(gTitleEvtName));
780 }
781 if (title.size() == 0) {
782 title.set("<unknown>");
783 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000784
reed@android.com8a1c16f2008-12-17 15:59:43 +0000785 title.prepend(gCanvasTypePrefix[fCanvasType]);
786
787 title.prepend(" ");
788 title.prepend(configToString(this->getBitmap().config()));
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000789
reed@android.com8a1c16f2008-12-17 15:59:43 +0000790 if (fAnimating) {
791 title.prepend("<A> ");
792 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000793 if (fScale) {
794 title.prepend("<S> ");
795 }
796 if (fRotate) {
797 title.prepend("<R> ");
798 }
reed@android.come522ca52009-11-23 20:10:41 +0000799 if (fNClip) {
800 title.prepend("<C> ");
801 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000802 this->setTitle(title.c_str());
803}
804
805void SampleWindow::onSizeChange() {
806 this->INHERITED::onSizeChange();
807
808 SkView::F2BIter iter(this);
809 SkView* view = iter.next();
810 view->setSize(this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000811
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812 // rebuild our clippath
813 {
814 const SkScalar W = this->width();
815 const SkScalar H = this->height();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000816
reed@android.com8a1c16f2008-12-17 15:59:43 +0000817 fClipPath.reset();
818#if 0
819 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
820 SkRect r;
821 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
822 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
823 fClipPath.addRect(r);
824 }
825#else
826 SkRect r;
827 r.set(0, 0, W, H);
828 fClipPath.addRect(r, SkPath::kCCW_Direction);
829 r.set(W/4, H/4, W*3/4, H*3/4);
830 fClipPath.addRect(r, SkPath::kCW_Direction);
831#endif
832 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000833
reed@android.com8a1c16f2008-12-17 15:59:43 +0000834 this->updateTitle(); // to refresh our config
835}
836
837///////////////////////////////////////////////////////////////////////////////
838
reed@android.comf2b98d62010-12-20 18:26:13 +0000839template <typename T> void SkTBSort(T array[], int count) {
840 for (int i = 1; i < count - 1; i++) {
841 bool didSwap = false;
842 for (int j = count - 1; j > i; --j) {
843 if (array[j] < array[j-1]) {
844 T tmp(array[j-1]);
845 array[j-1] = array[j];
846 array[j] = tmp;
847 didSwap = true;
848 }
849 }
850 if (!didSwap) {
851 break;
852 }
853 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000854
reed@android.comf2b98d62010-12-20 18:26:13 +0000855 for (int k = 0; k < count - 1; k++) {
856 SkASSERT(!(array[k+1] < array[k]));
857 }
858}
859
860#include "SkRandom.h"
861
862static void rand_rect(SkIRect* rect, SkRandom& rand) {
863 int bits = 8;
864 int shift = 32 - bits;
865 rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
866 rand.nextU() >> shift, rand.nextU() >> shift);
867 rect->sort();
868}
869
870static void dumpRect(const SkIRect& r) {
871 SkDebugf(" { %d, %d, %d, %d },\n",
872 r.fLeft, r.fTop,
873 r.fRight, r.fBottom);
874}
875
876static void test_rects(const SkIRect rect[], int count) {
877 SkRegion rgn0, rgn1;
878
879 for (int i = 0; i < count; i++) {
880 rgn0.op(rect[i], SkRegion::kUnion_Op);
881 // dumpRect(rect[i]);
882 }
883 rgn1.setRects(rect, count);
884
885 if (rgn0 != rgn1) {
886 SkDebugf("\n");
887 for (int i = 0; i < count; i++) {
888 dumpRect(rect[i]);
889 }
890 SkDebugf("\n");
891 }
892}
893
894static void test() {
895 size_t i;
896
897 const SkIRect r0[] = {
898 { 0, 0, 1, 1 },
899 { 2, 2, 3, 3 },
900 };
901 const SkIRect r1[] = {
902 { 0, 0, 1, 3 },
903 { 1, 1, 2, 2 },
904 { 2, 0, 3, 3 },
905 };
906 const SkIRect r2[] = {
907 { 0, 0, 1, 2 },
908 { 2, 1, 3, 3 },
909 { 4, 0, 5, 1 },
910 { 6, 0, 7, 4 },
911 };
912
913 static const struct {
914 const SkIRect* fRects;
915 int fCount;
916 } gRecs[] = {
917 { r0, SK_ARRAY_COUNT(r0) },
918 { r1, SK_ARRAY_COUNT(r1) },
919 { r2, SK_ARRAY_COUNT(r2) },
920 };
921
922 for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
923 test_rects(gRecs[i].fRects, gRecs[i].fCount);
924 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000925
reed@android.comf2b98d62010-12-20 18:26:13 +0000926 SkRandom rand;
927 for (i = 0; i < 10000; i++) {
928 SkRegion rgn0, rgn1;
929
930 const int N = 8;
931 SkIRect rect[N];
932 for (int j = 0; j < N; j++) {
933 rand_rect(&rect[j], rand);
934 }
935 test_rects(rect, N);
936 }
937}
938
reed@android.com8a1c16f2008-12-17 15:59:43 +0000939SkOSWindow* create_sk_window(void* hwnd) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000940// test();
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000941 return new SampleWindow(hwnd);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000942}
943
944void get_preferred_size(int* x, int* y, int* width, int* height) {
945 *x = 10;
946 *y = 50;
947 *width = 640;
948 *height = 480;
949}
950
951void application_init() {
952// setenv("ANDROID_ROOT", "../../../data", 0);
reed@android.come191b162009-12-18 21:33:39 +0000953#ifdef SK_BUILD_FOR_MAC
reed@android.com8a1c16f2008-12-17 15:59:43 +0000954 setenv("ANDROID_ROOT", "/android/device/data", 0);
reed@android.come191b162009-12-18 21:33:39 +0000955#endif
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000956 SkGraphics::Init();
957 SkEvent::Init();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000958}
959
960void application_term() {
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000961 SkEvent::Term();
962 SkGraphics::Term();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000963}