blob: 3fe1f4e44e85082cf2bc3e40218a1406ed7d8d2b [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;
439 SkIRect bounds = { 0, 0, this->width(), this->height() };
440 if (device->readPixels(bounds, &bitmap)) {
441 static int gSampleGrabCounter;
442 SkString name;
443 name.printf("sample_grab_%d", gSampleGrabCounter++);
444 SkImageEncoder::EncodeFile(name.c_str(), bitmap,
445 SkImageEncoder::kPNG_Type, 100);
446 }
447 }
448
reed@android.com8a1c16f2008-12-17 15:59:43 +0000449 switch (fCanvasType) {
450 case kRaster_CanvasType:
451 break;
452 case kPicture_CanvasType:
reed@android.comaefd2bc2009-03-30 21:02:14 +0000453 if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000454 SkPicture* pict = new SkPicture(*fPicture);
455 fPicture->unref();
456 orig->drawPicture(*pict);
457 pict->unref();
reed@android.comaefd2bc2009-03-30 21:02:14 +0000458 } else if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000459 SkDynamicMemoryWStream ostream;
460 fPicture->serialize(&ostream);
461 fPicture->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000462
reed@android.com8a1c16f2008-12-17 15:59:43 +0000463 SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
464 SkPicture pict(&istream);
465 orig->drawPicture(pict);
466 } else {
467 fPicture->draw(orig);
468 fPicture->unref();
469 }
470 fPicture = NULL;
471 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000472#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000473 case kGPU_CanvasType:
474 delete fGpuCanvas;
475 fGpuCanvas = NULL;
476 presentGL();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000477 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000478#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000479 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000480
reed@android.com8a1c16f2008-12-17 15:59:43 +0000481// if ((fScrollTestX | fScrollTestY) != 0)
reed@android.comf2b98d62010-12-20 18:26:13 +0000482 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000483 const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
484 int dx = fScrollTestX * 7;
485 int dy = fScrollTestY * 7;
486 SkIRect r;
487 SkRegion inval;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000488
reed@android.com8a1c16f2008-12-17 15:59:43 +0000489 r.set(50, 50, 50+100, 50+100);
490 bm.scrollRect(&r, dx, dy, &inval);
491 paint_rgn(bm, r, inval);
492 }
493}
494
reed@android.com6c5f6f22009-08-14 16:08:38 +0000495void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
496 if (fScale) {
497 SkScalar scale = SK_Scalar1 * 7 / 10;
498 SkScalar cx = this->width() / 2;
499 SkScalar cy = this->height() / 2;
500 canvas->translate(cx, cy);
501 canvas->scale(scale, scale);
502 canvas->translate(-cx, -cy);
503 }
504 if (fRotate) {
505 SkScalar cx = this->width() / 2;
506 SkScalar cy = this->height() / 2;
507 canvas->translate(cx, cy);
508 canvas->rotate(SkIntToScalar(30));
509 canvas->translate(-cx, -cy);
510 }
511}
512
513void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) {
514}
515
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516static SkBitmap::Config gConfigCycle[] = {
517 SkBitmap::kNo_Config, // none -> none
518 SkBitmap::kNo_Config, // a1 -> none
519 SkBitmap::kNo_Config, // a8 -> none
520 SkBitmap::kNo_Config, // index8 -> none
521 SkBitmap::kARGB_4444_Config, // 565 -> 4444
522 SkBitmap::kARGB_8888_Config, // 4444 -> 8888
523 SkBitmap::kRGB_565_Config // 8888 -> 565
524};
525
526static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
527 return gConfigCycle[c];
528}
529
530bool SampleWindow::nextSample() {
reed@android.com34245c72009-11-03 04:00:48 +0000531 fCurrIndex = (fCurrIndex + 1) % fSamples.count();
532 this->loadView(fSamples[fCurrIndex]());
533 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534}
535
536bool SampleWindow::onEvent(const SkEvent& evt) {
537 if (evt.isType(ANIMATING_EVENTTYPE)) {
538 if (fAnimating) {
539 this->nextSample();
540 this->postAnimatingEvent();
541 }
542 return true;
543 }
reed@android.com34245c72009-11-03 04:00:48 +0000544 if (evt.isType("set-curr-index")) {
545 fCurrIndex = evt.getFast32() % fSamples.count();
546 this->loadView(fSamples[fCurrIndex]());
547 return true;
548 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549 return this->INHERITED::onEvent(evt);
550}
551
reed@android.comf2b98d62010-12-20 18:26:13 +0000552bool SampleWindow::onQuery(SkEvent* query) {
553 if (query->isType("get-slide-count")) {
554 query->setFast32(fSamples.count());
555 return true;
556 }
557 if (query->isType("get-slide-title")) {
558 SkView* view = fSamples[query->getFast32()]();
559 SkEvent evt(gTitleEvtName);
560 if (view->doQuery(&evt)) {
561 query->setString("title", evt.findString(gTitleEvtName));
562 }
563 SkSafeUnref(view);
564 return true;
565 }
566 if (query->isType("use-fast-text")) {
567 SkEvent evt(gFastTextEvtName);
568 return curr_view(this)->doQuery(&evt);
569 }
570 return this->INHERITED::onQuery(query);
571}
572
reed@android.com0ae6b242008-12-23 16:49:54 +0000573static void cleanup_for_filename(SkString* name) {
574 char* str = name->writable_str();
reed@android.come191b162009-12-18 21:33:39 +0000575 for (size_t i = 0; i < name->size(); i++) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000576 switch (str[i]) {
577 case ':': str[i] = '-'; break;
578 case '/': str[i] = '-'; break;
579 case ' ': str[i] = '_'; break;
580 default: break;
581 }
582 }
583}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000584
585bool SampleWindow::onHandleChar(SkUnichar uni) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000586 {
587 SkView* view = curr_view(this);
588 if (view) {
589 SkEvent evt(gCharEvtName);
590 evt.setFast32(uni);
591 if (view->doQuery(&evt)) {
592 return true;
593 }
594 }
595 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000596
reed@android.com8a1c16f2008-12-17 15:59:43 +0000597 int dx = 0xFF;
598 int dy = 0xFF;
599
600 switch (uni) {
601 case '5': dx = 0; dy = 0; break;
602 case '8': dx = 0; dy = -1; break;
603 case '6': dx = 1; dy = 0; break;
604 case '2': dx = 0; dy = 1; break;
605 case '4': dx = -1; dy = 0; break;
606 case '7': dx = -1; dy = -1; break;
607 case '9': dx = 1; dy = -1; break;
608 case '3': dx = 1; dy = 1; break;
609 case '1': dx = -1; dy = 1; break;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000610
reed@android.com8a1c16f2008-12-17 15:59:43 +0000611 default:
612 break;
613 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000614
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615 if (0xFF != dx && 0xFF != dy) {
616 if ((dx | dy) == 0) {
617 fScrollTestX = fScrollTestY = 0;
618 } else {
619 fScrollTestX += dx;
620 fScrollTestY += dy;
621 }
622 this->inval(NULL);
623 return true;
624 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000625
reed@android.com0ae6b242008-12-23 16:49:54 +0000626 switch (uni) {
627 case 'a':
628 fAnimating = !fAnimating;
629 this->postAnimatingEvent();
630 this->updateTitle();
631 return true;
632 case 'f': {
633 const char* title = this->getTitle();
634 if (title[0] == 0) {
635 title = "sampleapp";
636 }
637 SkString name(title);
638 cleanup_for_filename(&name);
639 name.append(".png");
640 if (SkImageEncoder::EncodeFile(name.c_str(), this->getBitmap(),
reed@android.comb08eb2b2009-01-06 20:16:26 +0000641 SkImageEncoder::kPNG_Type, 100)) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000642 SkDebugf("Created %s\n", name.c_str());
643 }
644 return true;
645 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000646 case 'r':
647 fRotate = !fRotate;
648 this->inval(NULL);
649 this->updateTitle();
650 return true;
651 case 's':
652 fScale = !fScale;
653 this->inval(NULL);
654 this->updateTitle();
655 return true;
reed@google.comfb56a9e2011-02-10 18:47:24 +0000656 case 'c':
657 fUseClip = !fUseClip;
658 this->inval(NULL);
659 this->updateTitle();
660 return true;
reed@android.comf2b98d62010-12-20 18:26:13 +0000661 case 'd':
662 SkGraphics::SetFontCacheUsed(0);
663 return true;
664 case 'g':
665 fRequestGrabImage = true;
666 this->inval(NULL);
667 break;
reed@android.com0ae6b242008-12-23 16:49:54 +0000668 default:
669 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000671
reed@android.com8a1c16f2008-12-17 15:59:43 +0000672 return this->INHERITED::onHandleChar(uni);
673}
674
675#include "SkDumpCanvas.h"
676
677bool SampleWindow::onHandleKey(SkKey key) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000678 {
679 SkView* view = curr_view(this);
680 if (view) {
681 SkEvent evt(gKeyEvtName);
682 evt.setFast32(key);
683 if (view->doQuery(&evt)) {
684 return true;
685 }
686 }
687 }
688
reed@android.com8a1c16f2008-12-17 15:59:43 +0000689 switch (key) {
690 case kRight_SkKey:
691 if (this->nextSample()) {
692 return true;
693 }
694 break;
695 case kLeft_SkKey:
696 fCanvasType = cycle_canvastype(fCanvasType);
697 this->updateTitle();
698 this->inval(NULL);
699 return true;
700 case kUp_SkKey:
reed@android.come522ca52009-11-23 20:10:41 +0000701 fNClip = !fNClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000702 this->updateTitle();
703 this->inval(NULL);
704 return true;
705 case kDown_SkKey:
706 this->setConfig(cycle_configs(this->getBitmap().config()));
707 this->updateTitle();
708 return true;
709 case kOK_SkKey:
reed@android.comf2b98d62010-12-20 18:26:13 +0000710 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000711 SkDebugfDumper dumper;
712 SkDumpCanvas dc(&dumper);
713 this->draw(&dc);
714 } else {
715 fRepeatDrawing = !fRepeatDrawing;
716 if (fRepeatDrawing) {
717 this->inval(NULL);
718 }
719 }
720 return true;
reed@android.com34245c72009-11-03 04:00:48 +0000721 case kBack_SkKey:
722 this->loadView(NULL);
723 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000724 default:
725 break;
726 }
727 return this->INHERITED::onHandleKey(key);
728}
729
730void SampleWindow::loadView(SkView* view) {
731 SkView::F2BIter iter(this);
732 SkView* prev = iter.next();
733 if (prev) {
734 prev->detachFromParent();
735 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000736
reed@android.com34245c72009-11-03 04:00:48 +0000737 if (NULL == view) {
738 view = create_overview(fSamples.count(), fSamples.begin());
739 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740 view->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000741 view->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742 this->attachChildToFront(view)->unref();
743 view->setSize(this->width(), this->height());
744
745 this->updateTitle();
746}
747
748static const char* gConfigNames[] = {
749 "unknown config",
750 "A1",
751 "A8",
752 "Index8",
753 "565",
754 "4444",
755 "8888"
756};
757
758static const char* configToString(SkBitmap::Config c) {
759 return gConfigNames[c];
760}
761
762static const char* gCanvasTypePrefix[] = {
763 "raster: ",
764 "picture: ",
765 "opengl: "
766};
767
768void SampleWindow::updateTitle() {
769 SkString title;
770
771 SkView::F2BIter iter(this);
772 SkView* view = iter.next();
773 SkEvent evt(gTitleEvtName);
774 if (view->doQuery(&evt)) {
775 title.set(evt.findString(gTitleEvtName));
776 }
777 if (title.size() == 0) {
778 title.set("<unknown>");
779 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000780
reed@android.com8a1c16f2008-12-17 15:59:43 +0000781 title.prepend(gCanvasTypePrefix[fCanvasType]);
782
783 title.prepend(" ");
784 title.prepend(configToString(this->getBitmap().config()));
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000785
reed@android.com8a1c16f2008-12-17 15:59:43 +0000786 if (fAnimating) {
787 title.prepend("<A> ");
788 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000789 if (fScale) {
790 title.prepend("<S> ");
791 }
792 if (fRotate) {
793 title.prepend("<R> ");
794 }
reed@android.come522ca52009-11-23 20:10:41 +0000795 if (fNClip) {
796 title.prepend("<C> ");
797 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000798 this->setTitle(title.c_str());
799}
800
801void SampleWindow::onSizeChange() {
802 this->INHERITED::onSizeChange();
803
804 SkView::F2BIter iter(this);
805 SkView* view = iter.next();
806 view->setSize(this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000807
reed@android.com8a1c16f2008-12-17 15:59:43 +0000808 // rebuild our clippath
809 {
810 const SkScalar W = this->width();
811 const SkScalar H = this->height();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000812
reed@android.com8a1c16f2008-12-17 15:59:43 +0000813 fClipPath.reset();
814#if 0
815 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
816 SkRect r;
817 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
818 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
819 fClipPath.addRect(r);
820 }
821#else
822 SkRect r;
823 r.set(0, 0, W, H);
824 fClipPath.addRect(r, SkPath::kCCW_Direction);
825 r.set(W/4, H/4, W*3/4, H*3/4);
826 fClipPath.addRect(r, SkPath::kCW_Direction);
827#endif
828 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000829
reed@android.com8a1c16f2008-12-17 15:59:43 +0000830 this->updateTitle(); // to refresh our config
831}
832
833///////////////////////////////////////////////////////////////////////////////
834
reed@android.comf2b98d62010-12-20 18:26:13 +0000835template <typename T> void SkTBSort(T array[], int count) {
836 for (int i = 1; i < count - 1; i++) {
837 bool didSwap = false;
838 for (int j = count - 1; j > i; --j) {
839 if (array[j] < array[j-1]) {
840 T tmp(array[j-1]);
841 array[j-1] = array[j];
842 array[j] = tmp;
843 didSwap = true;
844 }
845 }
846 if (!didSwap) {
847 break;
848 }
849 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000850
reed@android.comf2b98d62010-12-20 18:26:13 +0000851 for (int k = 0; k < count - 1; k++) {
852 SkASSERT(!(array[k+1] < array[k]));
853 }
854}
855
856#include "SkRandom.h"
857
858static void rand_rect(SkIRect* rect, SkRandom& rand) {
859 int bits = 8;
860 int shift = 32 - bits;
861 rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
862 rand.nextU() >> shift, rand.nextU() >> shift);
863 rect->sort();
864}
865
866static void dumpRect(const SkIRect& r) {
867 SkDebugf(" { %d, %d, %d, %d },\n",
868 r.fLeft, r.fTop,
869 r.fRight, r.fBottom);
870}
871
872static void test_rects(const SkIRect rect[], int count) {
873 SkRegion rgn0, rgn1;
874
875 for (int i = 0; i < count; i++) {
876 rgn0.op(rect[i], SkRegion::kUnion_Op);
877 // dumpRect(rect[i]);
878 }
879 rgn1.setRects(rect, count);
880
881 if (rgn0 != rgn1) {
882 SkDebugf("\n");
883 for (int i = 0; i < count; i++) {
884 dumpRect(rect[i]);
885 }
886 SkDebugf("\n");
887 }
888}
889
890static void test() {
891 size_t i;
892
893 const SkIRect r0[] = {
894 { 0, 0, 1, 1 },
895 { 2, 2, 3, 3 },
896 };
897 const SkIRect r1[] = {
898 { 0, 0, 1, 3 },
899 { 1, 1, 2, 2 },
900 { 2, 0, 3, 3 },
901 };
902 const SkIRect r2[] = {
903 { 0, 0, 1, 2 },
904 { 2, 1, 3, 3 },
905 { 4, 0, 5, 1 },
906 { 6, 0, 7, 4 },
907 };
908
909 static const struct {
910 const SkIRect* fRects;
911 int fCount;
912 } gRecs[] = {
913 { r0, SK_ARRAY_COUNT(r0) },
914 { r1, SK_ARRAY_COUNT(r1) },
915 { r2, SK_ARRAY_COUNT(r2) },
916 };
917
918 for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
919 test_rects(gRecs[i].fRects, gRecs[i].fCount);
920 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000921
reed@android.comf2b98d62010-12-20 18:26:13 +0000922 SkRandom rand;
923 for (i = 0; i < 10000; i++) {
924 SkRegion rgn0, rgn1;
925
926 const int N = 8;
927 SkIRect rect[N];
928 for (int j = 0; j < N; j++) {
929 rand_rect(&rect[j], rand);
930 }
931 test_rects(rect, N);
932 }
933}
934
reed@android.com8a1c16f2008-12-17 15:59:43 +0000935SkOSWindow* create_sk_window(void* hwnd) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000936// test();
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000937 return new SampleWindow(hwnd);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000938}
939
940void get_preferred_size(int* x, int* y, int* width, int* height) {
941 *x = 10;
942 *y = 50;
943 *width = 640;
944 *height = 480;
945}
946
947void application_init() {
948// setenv("ANDROID_ROOT", "../../../data", 0);
reed@android.come191b162009-12-18 21:33:39 +0000949#ifdef SK_BUILD_FOR_MAC
reed@android.com8a1c16f2008-12-17 15:59:43 +0000950 setenv("ANDROID_ROOT", "/android/device/data", 0);
reed@android.come191b162009-12-18 21:33:39 +0000951#endif
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000952 SkGraphics::Init();
953 SkEvent::Init();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000954}
955
956void application_term() {
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000957 SkEvent::Term();
958 SkGraphics::Term();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000959}