blob: bf8cb6bc019863332916cb1cbede85ad05fc729c [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#include "SkCanvas.h"
2#include "SkDevice.h"
reed@google.comac10a2d2010-12-22 21:39:39 +00003#include "SkGpuCanvas.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00004#include "SkGraphics.h"
reed@android.comb08eb2b2009-01-06 20:16:26 +00005#include "SkImageEncoder.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00006#include "SkPaint.h"
7#include "SkPicture.h"
8#include "SkStream.h"
reed@android.com44177402009-11-23 21:07:51 +00009#include "SkTime.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkWindow.h"
11
12#include "SampleCode.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000013#include "GrContext.h"
reed@android.comf2b98d62010-12-20 18:26:13 +000014
15//#define DEFAULT_TO_GPU
16
reed@android.come191b162009-12-18 21:33:39 +000017extern SkView* create_overview(int, const SkViewFactory[]);
reed@android.com34245c72009-11-03 04:00:48 +000018
reed@android.comcb342352010-07-22 18:27:53 +000019#define SK_SUPPORT_GL
reed@android.com8a1c16f2008-12-17 15:59:43 +000020
21#define ANIMATING_EVENTTYPE "nextSample"
22#define ANIMATING_DELAY 750
23
reed@android.comf2b98d62010-12-20 18:26:13 +000024#if !defined(SK_BUILD_FOR_WIN32)
25//#define USE_OFFSCREEN
26#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000027
reed@google.comac10a2d2010-12-22 21:39:39 +000028#ifdef SK_SUPPORT_GL
29 #include "GrGLConfig.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000030#endif
31
reed@android.com8a1c16f2008-12-17 15:59:43 +000032SkViewRegister* SkViewRegister::gHead;
33SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) {
34 static bool gOnce;
35 if (!gOnce) {
36 gHead = NULL;
37 gOnce = true;
38 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +000039
reed@android.com8a1c16f2008-12-17 15:59:43 +000040 fChain = gHead;
41 gHead = this;
42}
43
reed@android.comf2b98d62010-12-20 18:26:13 +000044#if defined(SK_SUPPORT_GL)
45 #define SK_USE_SHADERS
46#endif
47
reed@android.com8a1c16f2008-12-17 15:59:43 +000048//////////////////////////////////////////////////////////////////////////////
49
reed@android.comf2b98d62010-12-20 18:26:13 +000050static const char gCharEvtName[] = "SampleCode_Char_Event";
51static const char gKeyEvtName[] = "SampleCode_Key_Event";
reed@android.com8a1c16f2008-12-17 15:59:43 +000052static const char gTitleEvtName[] = "SampleCode_Title_Event";
53static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event";
reed@android.comf2b98d62010-12-20 18:26:13 +000054static const char gFastTextEvtName[] = "SampleCode_FastText_Event";
55
56bool SampleCode::CharQ(const SkEvent& evt, SkUnichar* outUni) {
57 if (evt.isType(gCharEvtName, sizeof(gCharEvtName) - 1)) {
58 if (outUni) {
59 *outUni = evt.getFast32();
60 }
61 return true;
62 }
63 return false;
64}
65
66bool SampleCode::KeyQ(const SkEvent& evt, SkKey* outKey) {
67 if (evt.isType(gKeyEvtName, sizeof(gKeyEvtName) - 1)) {
68 if (outKey) {
69 *outKey = (SkKey)evt.getFast32();
70 }
71 return true;
72 }
73 return false;
74}
reed@android.com8a1c16f2008-12-17 15:59:43 +000075
76bool SampleCode::TitleQ(const SkEvent& evt) {
77 return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1);
78}
79
80void SampleCode::TitleR(SkEvent* evt, const char title[]) {
81 SkASSERT(evt && TitleQ(*evt));
82 evt->setString(gTitleEvtName, title);
83}
84
85bool SampleCode::PrefSizeQ(const SkEvent& evt) {
86 return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1);
87}
88
89void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) {
90 SkASSERT(evt && PrefSizeQ(*evt));
91 SkScalar size[2];
92 size[0] = width;
93 size[1] = height;
94 evt->setScalars(gPrefSizeEvtName, 2, size);
95}
96
reed@android.comf2b98d62010-12-20 18:26:13 +000097bool SampleCode::FastTextQ(const SkEvent& evt) {
98 return evt.isType(gFastTextEvtName, sizeof(gFastTextEvtName) - 1);
99}
100
101///////////////////////////////////////////////////////////////////////////////
102
reed@android.com44177402009-11-23 21:07:51 +0000103static SkMSec gAnimTime;
reed@android.comf2b98d62010-12-20 18:26:13 +0000104static SkMSec gAnimTimePrev;
105
reed@android.com44177402009-11-23 21:07:51 +0000106SkMSec SampleCode::GetAnimTime() { return gAnimTime; }
reed@android.comf2b98d62010-12-20 18:26:13 +0000107SkMSec SampleCode::GetAnimTimeDelta() { return gAnimTime - gAnimTimePrev; }
108SkScalar SampleCode::GetAnimSecondsDelta() {
109 return SkDoubleToScalar(GetAnimTimeDelta() / 1000.0);
110}
reed@android.com44177402009-11-23 21:07:51 +0000111
112SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000113 // since gAnimTime can be up to 32 bits, we can't convert it to a float
114 // or we'll lose the low bits. Hence we use doubles for the intermediate
115 // calculations
116 double seconds = (double)gAnimTime / 1000.0;
117 double value = SkScalarToDouble(speed) * seconds;
reed@android.com44177402009-11-23 21:07:51 +0000118 if (period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000119 value = ::fmod(value, SkScalarToDouble(period));
reed@android.com44177402009-11-23 21:07:51 +0000120 }
reed@android.comf2b98d62010-12-20 18:26:13 +0000121 return SkDoubleToScalar(value);
reed@android.com44177402009-11-23 21:07:51 +0000122}
123
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124//////////////////////////////////////////////////////////////////////////////
125
reed@android.comf2b98d62010-12-20 18:26:13 +0000126static SkView* curr_view(SkWindow* wind) {
127 SkView::F2BIter iter(wind);
128 return iter.next();
129}
130
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131class SampleWindow : public SkOSWindow {
reed@android.com34245c72009-11-03 04:00:48 +0000132 SkTDArray<SkViewFactory> fSamples;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133public:
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000134 SampleWindow(void* hwnd);
135 virtual ~SampleWindow();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136
reed@android.come522ca52009-11-23 20:10:41 +0000137 virtual void draw(SkCanvas* canvas);
138
reed@android.com8a1c16f2008-12-17 15:59:43 +0000139protected:
140 virtual void onDraw(SkCanvas* canvas);
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000141 virtual bool onHandleKey(SkKey key);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142 virtual bool onHandleChar(SkUnichar);
143 virtual void onSizeChange();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000144
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145 virtual SkCanvas* beforeChildren(SkCanvas*);
146 virtual void afterChildren(SkCanvas*);
reed@android.com6c5f6f22009-08-14 16:08:38 +0000147 virtual void beforeChild(SkView* child, SkCanvas* canvas);
148 virtual void afterChild(SkView* child, SkCanvas* canvas);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000149
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000150 virtual bool onEvent(const SkEvent& evt);
reed@android.comf2b98d62010-12-20 18:26:13 +0000151 virtual bool onQuery(SkEvent* evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152
153#if 0
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000154 virtual bool handleChar(SkUnichar uni);
155 virtual bool handleEvent(const SkEvent& evt);
156 virtual bool handleKey(SkKey key);
157 virtual bool handleKeyUp(SkKey key);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000158
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000159 virtual bool onClick(Click* click);
160 virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 virtual bool onHandleKeyUp(SkKey key);
162#endif
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000163
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164private:
reed@android.com34245c72009-11-03 04:00:48 +0000165 int fCurrIndex;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000166
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167 SkPicture* fPicture;
reed@android.comf2b98d62010-12-20 18:26:13 +0000168 SkGpuCanvas* fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000169 GrContext* fGrContext;
170 GrRenderTarget* fGrRenderTarget;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171 SkPath fClipPath;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000172
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173 enum CanvasType {
174 kRaster_CanvasType,
175 kPicture_CanvasType,
reed@android.comf2b98d62010-12-20 18:26:13 +0000176 kGPU_CanvasType
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 };
178 CanvasType fCanvasType;
179
180 bool fUseClip;
reed@android.come522ca52009-11-23 20:10:41 +0000181 bool fNClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182 bool fRepeatDrawing;
183 bool fAnimating;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000184 bool fRotate;
185 bool fScale;
reed@android.comf2b98d62010-12-20 18:26:13 +0000186 bool fRequestGrabImage;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000187
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188 int fScrollTestX, fScrollTestY;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000189
190 bool make3DReady();
191
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192 void loadView(SkView*);
193 void updateTitle();
194 bool nextSample();
195
196 void postAnimatingEvent() {
197 if (fAnimating) {
198 SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
199 evt->post(this->getSinkID(), ANIMATING_DELAY);
200 }
201 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000202
203
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 static CanvasType cycle_canvastype(CanvasType);
205
206 typedef SkOSWindow INHERITED;
207};
208
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000209bool SampleWindow::make3DReady() {
210
211#if defined(SK_SUPPORT_GL)
212 #if defined(USE_OFFSCREEN)
213 // first clear the raster bitmap, so we don't see any leftover bits
214 bitmap.eraseColor(0);
215 // now setup our glcanvas
216 attachGL(&bitmap);
217 #else
218 attachGL(NULL);
219 #endif
220
221 if (NULL == fGrContext) {
222 SkASSERT(NULL == fGrRenderTarget);
223 #if defined(SK_USE_SHADERS)
224 fGrContext = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
225 #else
226 fGrContext = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, NULL);
227 #endif
228 if (NULL != fGrContext) {
229 fGrRenderTarget = fGrContext->createRenderTargetFrom3DApiState();
230 }
231 }
232
233 if (NULL != fGrContext) {
234 SkASSERT(NULL != fGrRenderTarget);
235 return true;
236 } else {
237 detachGL();
238 }
239#endif
240 SkDebugf("Failed to setup 3D");
241 return false;
242}
243
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
245 static const CanvasType gCT[] = {
246 kPicture_CanvasType,
reed@android.comf2b98d62010-12-20 18:26:13 +0000247 kGPU_CanvasType,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248 kRaster_CanvasType
249 };
250 return gCT[ct];
251}
252
253SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 fPicture = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000255 fGpuCanvas = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000257 fGrContext = NULL;
258 fGrRenderTarget = NULL;
259
reed@android.comf2b98d62010-12-20 18:26:13 +0000260#ifdef DEFAULT_TO_GPU
261 fCanvasType = kGPU_CanvasType;
262#else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 fCanvasType = kRaster_CanvasType;
reed@android.comf2b98d62010-12-20 18:26:13 +0000264#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265 fUseClip = false;
reed@android.come522ca52009-11-23 20:10:41 +0000266 fNClip = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267 fRepeatDrawing = false;
268 fAnimating = false;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000269 fRotate = false;
270 fScale = false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000271 fRequestGrabImage = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272
273 fScrollTestX = fScrollTestY = 0;
274
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000275// this->setConfig(SkBitmap::kRGB_565_Config);
276 this->setConfig(SkBitmap::kARGB_8888_Config);
277 this->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000278 this->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279
reed@android.com34245c72009-11-03 04:00:48 +0000280 {
281 const SkViewRegister* reg = SkViewRegister::Head();
282 while (reg) {
283 *fSamples.append() = reg->factory();
284 reg = reg->next();
285 }
286 }
287 fCurrIndex = 0;
reed@android.come0f13ee2009-11-04 19:40:25 +0000288 this->loadView(fSamples[fCurrIndex]());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289}
290
291SampleWindow::~SampleWindow() {
292 delete fPicture;
reed@android.comf2b98d62010-12-20 18:26:13 +0000293 delete fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000294 if (NULL != fGrRenderTarget) {
295 fGrRenderTarget->unref();
296 }
297 if (NULL != fGrContext) {
298 fGrContext->unref();
299 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000300}
301
reed@android.com55e76b22009-11-23 21:46:47 +0000302static SkBitmap capture_bitmap(SkCanvas* canvas) {
303 SkBitmap bm;
304 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
305 src.copyTo(&bm, src.config());
306 return bm;
307}
308
309static bool bitmap_diff(SkCanvas* canvas, const SkBitmap& orig,
310 SkBitmap* diff) {
311 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000312
reed@android.com55e76b22009-11-23 21:46:47 +0000313 SkAutoLockPixels alp0(src);
314 SkAutoLockPixels alp1(orig);
315 for (int y = 0; y < src.height(); y++) {
316 const void* srcP = src.getAddr(0, y);
317 const void* origP = orig.getAddr(0, y);
318 size_t bytes = src.width() * src.bytesPerPixel();
319 if (memcmp(srcP, origP, bytes)) {
320 SkDebugf("---------- difference on line %d\n", y);
321 return true;
322 }
323 }
324 return false;
325}
326
reed@android.com44177402009-11-23 21:07:51 +0000327#define XCLIP_N 8
328#define YCLIP_N 8
reed@android.come522ca52009-11-23 20:10:41 +0000329
330void SampleWindow::draw(SkCanvas* canvas) {
reed@android.com44177402009-11-23 21:07:51 +0000331 // update the animation time
reed@android.comf2b98d62010-12-20 18:26:13 +0000332 gAnimTimePrev = gAnimTime;
reed@android.com44177402009-11-23 21:07:51 +0000333 gAnimTime = SkTime::GetMSecs();
334
reed@android.come522ca52009-11-23 20:10:41 +0000335 if (fNClip) {
reed@android.com55e76b22009-11-23 21:46:47 +0000336 this->INHERITED::draw(canvas);
337 SkBitmap orig = capture_bitmap(canvas);
reed@android.come522ca52009-11-23 20:10:41 +0000338
339 const SkScalar w = this->width();
340 const SkScalar h = this->height();
341 const SkScalar cw = w / XCLIP_N;
342 const SkScalar ch = h / YCLIP_N;
343 for (int y = 0; y < YCLIP_N; y++) {
reed@android.com55e76b22009-11-23 21:46:47 +0000344 SkRect r;
345 r.fTop = y * ch;
346 r.fBottom = (y + 1) * ch;
347 if (y == YCLIP_N - 1) {
348 r.fBottom = h;
349 }
reed@android.come522ca52009-11-23 20:10:41 +0000350 for (int x = 0; x < XCLIP_N; x++) {
351 SkAutoCanvasRestore acr(canvas, true);
reed@android.com55e76b22009-11-23 21:46:47 +0000352 r.fLeft = x * cw;
353 r.fRight = (x + 1) * cw;
354 if (x == XCLIP_N - 1) {
355 r.fRight = w;
356 }
reed@android.come522ca52009-11-23 20:10:41 +0000357 canvas->clipRect(r);
358 this->INHERITED::draw(canvas);
359 }
360 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000361
reed@android.com55e76b22009-11-23 21:46:47 +0000362 SkBitmap diff;
363 if (bitmap_diff(canvas, orig, &diff)) {
364 }
reed@android.come522ca52009-11-23 20:10:41 +0000365 } else {
366 this->INHERITED::draw(canvas);
367 }
368}
369
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370void SampleWindow::onDraw(SkCanvas* canvas) {
371 if (fRepeatDrawing) {
372 this->inval(NULL);
373 }
374}
375
376#include "SkColorPriv.h"
377
378static void reverseRedAndBlue(const SkBitmap& bm) {
379 SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
380 uint8_t* p = (uint8_t*)bm.getPixels();
381 uint8_t* stop = p + bm.getSize();
382 while (p < stop) {
383 // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
384 unsigned scale = SkAlpha255To256(p[3]);
385 unsigned r = p[2];
386 unsigned b = p[0];
387 p[0] = SkAlphaMul(r, scale);
388 p[1] = SkAlphaMul(p[1], scale);
389 p[2] = SkAlphaMul(b, scale);
390 p += 4;
391 }
392}
393
394SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000395 SkIPoint viewport;
396 bool alreadyGPU = canvas->getViewport(&viewport);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000397
reed@android.comf2b98d62010-12-20 18:26:13 +0000398 if (kGPU_CanvasType != fCanvasType) {
reed@android.com6efdc472008-12-19 18:24:35 +0000399#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000400 detachGL();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000401#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000402 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000403
reed@android.com8a1c16f2008-12-17 15:59:43 +0000404 switch (fCanvasType) {
405 case kRaster_CanvasType:
406 canvas = this->INHERITED::beforeChildren(canvas);
407 break;
408 case kPicture_CanvasType:
409 fPicture = new SkPicture;
410 canvas = fPicture->beginRecording(9999, 9999);
411 break;
reed@google.comac10a2d2010-12-22 21:39:39 +0000412 case kGPU_CanvasType: {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000413 if (!alreadyGPU && make3DReady()) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000414 SkDevice* device = canvas->getDevice();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000415 const SkBitmap& bitmap = device->accessBitmap(true);
416
417 fGpuCanvas = new SkGpuCanvas(fGrContext, fGrRenderTarget);
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000418 device = fGpuCanvas->createDevice(SkBitmap::kARGB_8888_Config,
419 bitmap.width(), bitmap.height(),
420 false, false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000421 fGpuCanvas->setDevice(device)->unref();
reed@android.comf2b98d62010-12-20 18:26:13 +0000422 canvas = fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000423
reed@android.comf2b98d62010-12-20 18:26:13 +0000424 } else {
425 canvas = this->INHERITED::beforeChildren(canvas);
426 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427 break;
reed@google.comac10a2d2010-12-22 21:39:39 +0000428 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429 }
430
431 if (fUseClip) {
432 canvas->drawColor(0xFFFF88FF);
433 canvas->clipPath(fClipPath);
434 }
435
436 return canvas;
437}
438
439static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
440 const SkRegion& rgn) {
441 SkCanvas canvas(bm);
442 SkRegion inval(rgn);
443
444 inval.translate(r.fLeft, r.fTop);
445 canvas.clipRegion(inval);
446 canvas.drawColor(0xFFFF8080);
447}
448
449void SampleWindow::afterChildren(SkCanvas* orig) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000450 if (fRequestGrabImage) {
451 fRequestGrabImage = false;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000452
reed@android.comf2b98d62010-12-20 18:26:13 +0000453 SkCanvas* canvas = fGpuCanvas ? fGpuCanvas : orig;
454 SkDevice* device = canvas->getDevice();
455 SkBitmap bitmap;
456 SkIRect bounds = { 0, 0, this->width(), this->height() };
457 if (device->readPixels(bounds, &bitmap)) {
458 static int gSampleGrabCounter;
459 SkString name;
460 name.printf("sample_grab_%d", gSampleGrabCounter++);
461 SkImageEncoder::EncodeFile(name.c_str(), bitmap,
462 SkImageEncoder::kPNG_Type, 100);
463 }
464 }
465
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466 switch (fCanvasType) {
467 case kRaster_CanvasType:
468 break;
469 case kPicture_CanvasType:
reed@android.comaefd2bc2009-03-30 21:02:14 +0000470 if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000471 SkPicture* pict = new SkPicture(*fPicture);
472 fPicture->unref();
473 orig->drawPicture(*pict);
474 pict->unref();
reed@android.comaefd2bc2009-03-30 21:02:14 +0000475 } else if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000476 SkDynamicMemoryWStream ostream;
477 fPicture->serialize(&ostream);
478 fPicture->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000479
reed@android.com8a1c16f2008-12-17 15:59:43 +0000480 SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
481 SkPicture pict(&istream);
482 orig->drawPicture(pict);
483 } else {
484 fPicture->draw(orig);
485 fPicture->unref();
486 }
487 fPicture = NULL;
488 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000489#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000490 case kGPU_CanvasType:
491 delete fGpuCanvas;
492 fGpuCanvas = NULL;
493 presentGL();
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000494 #ifdef USE_OFFSCREEN
reed@android.com8a1c16f2008-12-17 15:59:43 +0000495 reverseRedAndBlue(orig->getDevice()->accessBitmap(true));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000496 #endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000497 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000498#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000499 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000500
reed@android.com8a1c16f2008-12-17 15:59:43 +0000501// if ((fScrollTestX | fScrollTestY) != 0)
reed@android.comf2b98d62010-12-20 18:26:13 +0000502 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000503 const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
504 int dx = fScrollTestX * 7;
505 int dy = fScrollTestY * 7;
506 SkIRect r;
507 SkRegion inval;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000508
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509 r.set(50, 50, 50+100, 50+100);
510 bm.scrollRect(&r, dx, dy, &inval);
511 paint_rgn(bm, r, inval);
512 }
513}
514
reed@android.com6c5f6f22009-08-14 16:08:38 +0000515void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
516 if (fScale) {
517 SkScalar scale = SK_Scalar1 * 7 / 10;
518 SkScalar cx = this->width() / 2;
519 SkScalar cy = this->height() / 2;
520 canvas->translate(cx, cy);
521 canvas->scale(scale, scale);
522 canvas->translate(-cx, -cy);
523 }
524 if (fRotate) {
525 SkScalar cx = this->width() / 2;
526 SkScalar cy = this->height() / 2;
527 canvas->translate(cx, cy);
528 canvas->rotate(SkIntToScalar(30));
529 canvas->translate(-cx, -cy);
530 }
531}
532
533void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) {
534}
535
reed@android.com8a1c16f2008-12-17 15:59:43 +0000536static SkBitmap::Config gConfigCycle[] = {
537 SkBitmap::kNo_Config, // none -> none
538 SkBitmap::kNo_Config, // a1 -> none
539 SkBitmap::kNo_Config, // a8 -> none
540 SkBitmap::kNo_Config, // index8 -> none
541 SkBitmap::kARGB_4444_Config, // 565 -> 4444
542 SkBitmap::kARGB_8888_Config, // 4444 -> 8888
543 SkBitmap::kRGB_565_Config // 8888 -> 565
544};
545
546static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
547 return gConfigCycle[c];
548}
549
550bool SampleWindow::nextSample() {
reed@android.com34245c72009-11-03 04:00:48 +0000551 fCurrIndex = (fCurrIndex + 1) % fSamples.count();
552 this->loadView(fSamples[fCurrIndex]());
553 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000554}
555
556bool SampleWindow::onEvent(const SkEvent& evt) {
557 if (evt.isType(ANIMATING_EVENTTYPE)) {
558 if (fAnimating) {
559 this->nextSample();
560 this->postAnimatingEvent();
561 }
562 return true;
563 }
reed@android.com34245c72009-11-03 04:00:48 +0000564 if (evt.isType("set-curr-index")) {
565 fCurrIndex = evt.getFast32() % fSamples.count();
566 this->loadView(fSamples[fCurrIndex]());
567 return true;
568 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000569 return this->INHERITED::onEvent(evt);
570}
571
reed@android.comf2b98d62010-12-20 18:26:13 +0000572bool SampleWindow::onQuery(SkEvent* query) {
573 if (query->isType("get-slide-count")) {
574 query->setFast32(fSamples.count());
575 return true;
576 }
577 if (query->isType("get-slide-title")) {
578 SkView* view = fSamples[query->getFast32()]();
579 SkEvent evt(gTitleEvtName);
580 if (view->doQuery(&evt)) {
581 query->setString("title", evt.findString(gTitleEvtName));
582 }
583 SkSafeUnref(view);
584 return true;
585 }
586 if (query->isType("use-fast-text")) {
587 SkEvent evt(gFastTextEvtName);
588 return curr_view(this)->doQuery(&evt);
589 }
590 return this->INHERITED::onQuery(query);
591}
592
reed@android.com0ae6b242008-12-23 16:49:54 +0000593static void cleanup_for_filename(SkString* name) {
594 char* str = name->writable_str();
reed@android.come191b162009-12-18 21:33:39 +0000595 for (size_t i = 0; i < name->size(); i++) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000596 switch (str[i]) {
597 case ':': str[i] = '-'; break;
598 case '/': str[i] = '-'; break;
599 case ' ': str[i] = '_'; break;
600 default: break;
601 }
602 }
603}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000604
605bool SampleWindow::onHandleChar(SkUnichar uni) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000606 {
607 SkView* view = curr_view(this);
608 if (view) {
609 SkEvent evt(gCharEvtName);
610 evt.setFast32(uni);
611 if (view->doQuery(&evt)) {
612 return true;
613 }
614 }
615 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000616
reed@android.com8a1c16f2008-12-17 15:59:43 +0000617 int dx = 0xFF;
618 int dy = 0xFF;
619
620 switch (uni) {
621 case '5': dx = 0; dy = 0; break;
622 case '8': dx = 0; dy = -1; break;
623 case '6': dx = 1; dy = 0; break;
624 case '2': dx = 0; dy = 1; break;
625 case '4': dx = -1; dy = 0; break;
626 case '7': dx = -1; dy = -1; break;
627 case '9': dx = 1; dy = -1; break;
628 case '3': dx = 1; dy = 1; break;
629 case '1': dx = -1; dy = 1; break;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000630
reed@android.com8a1c16f2008-12-17 15:59:43 +0000631 default:
632 break;
633 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000634
reed@android.com8a1c16f2008-12-17 15:59:43 +0000635 if (0xFF != dx && 0xFF != dy) {
636 if ((dx | dy) == 0) {
637 fScrollTestX = fScrollTestY = 0;
638 } else {
639 fScrollTestX += dx;
640 fScrollTestY += dy;
641 }
642 this->inval(NULL);
643 return true;
644 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000645
reed@android.com0ae6b242008-12-23 16:49:54 +0000646 switch (uni) {
647 case 'a':
648 fAnimating = !fAnimating;
649 this->postAnimatingEvent();
650 this->updateTitle();
651 return true;
652 case 'f': {
653 const char* title = this->getTitle();
654 if (title[0] == 0) {
655 title = "sampleapp";
656 }
657 SkString name(title);
658 cleanup_for_filename(&name);
659 name.append(".png");
660 if (SkImageEncoder::EncodeFile(name.c_str(), this->getBitmap(),
reed@android.comb08eb2b2009-01-06 20:16:26 +0000661 SkImageEncoder::kPNG_Type, 100)) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000662 SkDebugf("Created %s\n", name.c_str());
663 }
664 return true;
665 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000666 case 'r':
667 fRotate = !fRotate;
668 this->inval(NULL);
669 this->updateTitle();
670 return true;
671 case 's':
672 fScale = !fScale;
673 this->inval(NULL);
674 this->updateTitle();
675 return true;
reed@android.comf2b98d62010-12-20 18:26:13 +0000676 case 'd':
677 SkGraphics::SetFontCacheUsed(0);
678 return true;
679 case 'g':
680 fRequestGrabImage = true;
681 this->inval(NULL);
682 break;
reed@android.com0ae6b242008-12-23 16:49:54 +0000683 default:
684 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000685 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000686
reed@android.com8a1c16f2008-12-17 15:59:43 +0000687 return this->INHERITED::onHandleChar(uni);
688}
689
690#include "SkDumpCanvas.h"
691
692bool SampleWindow::onHandleKey(SkKey key) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000693 {
694 SkView* view = curr_view(this);
695 if (view) {
696 SkEvent evt(gKeyEvtName);
697 evt.setFast32(key);
698 if (view->doQuery(&evt)) {
699 return true;
700 }
701 }
702 }
703
reed@android.com8a1c16f2008-12-17 15:59:43 +0000704 switch (key) {
705 case kRight_SkKey:
706 if (this->nextSample()) {
707 return true;
708 }
709 break;
710 case kLeft_SkKey:
711 fCanvasType = cycle_canvastype(fCanvasType);
712 this->updateTitle();
713 this->inval(NULL);
714 return true;
715 case kUp_SkKey:
reed@android.come522ca52009-11-23 20:10:41 +0000716 fNClip = !fNClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000717 this->updateTitle();
718 this->inval(NULL);
719 return true;
720 case kDown_SkKey:
721 this->setConfig(cycle_configs(this->getBitmap().config()));
722 this->updateTitle();
723 return true;
724 case kOK_SkKey:
reed@android.comf2b98d62010-12-20 18:26:13 +0000725 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000726 SkDebugfDumper dumper;
727 SkDumpCanvas dc(&dumper);
728 this->draw(&dc);
729 } else {
730 fRepeatDrawing = !fRepeatDrawing;
731 if (fRepeatDrawing) {
732 this->inval(NULL);
733 }
734 }
735 return true;
reed@android.com34245c72009-11-03 04:00:48 +0000736 case kBack_SkKey:
737 this->loadView(NULL);
738 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000739 default:
740 break;
741 }
742 return this->INHERITED::onHandleKey(key);
743}
744
745void SampleWindow::loadView(SkView* view) {
746 SkView::F2BIter iter(this);
747 SkView* prev = iter.next();
748 if (prev) {
749 prev->detachFromParent();
750 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000751
reed@android.com34245c72009-11-03 04:00:48 +0000752 if (NULL == view) {
753 view = create_overview(fSamples.count(), fSamples.begin());
754 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000755 view->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000756 view->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000757 this->attachChildToFront(view)->unref();
758 view->setSize(this->width(), this->height());
759
760 this->updateTitle();
761}
762
763static const char* gConfigNames[] = {
764 "unknown config",
765 "A1",
766 "A8",
767 "Index8",
768 "565",
769 "4444",
770 "8888"
771};
772
773static const char* configToString(SkBitmap::Config c) {
774 return gConfigNames[c];
775}
776
777static const char* gCanvasTypePrefix[] = {
778 "raster: ",
779 "picture: ",
780 "opengl: "
781};
782
783void SampleWindow::updateTitle() {
784 SkString title;
785
786 SkView::F2BIter iter(this);
787 SkView* view = iter.next();
788 SkEvent evt(gTitleEvtName);
789 if (view->doQuery(&evt)) {
790 title.set(evt.findString(gTitleEvtName));
791 }
792 if (title.size() == 0) {
793 title.set("<unknown>");
794 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000795
reed@android.com8a1c16f2008-12-17 15:59:43 +0000796 title.prepend(gCanvasTypePrefix[fCanvasType]);
797
798 title.prepend(" ");
799 title.prepend(configToString(this->getBitmap().config()));
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000800
reed@android.com8a1c16f2008-12-17 15:59:43 +0000801 if (fAnimating) {
802 title.prepend("<A> ");
803 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000804 if (fScale) {
805 title.prepend("<S> ");
806 }
807 if (fRotate) {
808 title.prepend("<R> ");
809 }
reed@android.come522ca52009-11-23 20:10:41 +0000810 if (fNClip) {
811 title.prepend("<C> ");
812 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000813 this->setTitle(title.c_str());
814}
815
816void SampleWindow::onSizeChange() {
817 this->INHERITED::onSizeChange();
818
819 SkView::F2BIter iter(this);
820 SkView* view = iter.next();
821 view->setSize(this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000822
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823 // rebuild our clippath
824 {
825 const SkScalar W = this->width();
826 const SkScalar H = this->height();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000827
reed@android.com8a1c16f2008-12-17 15:59:43 +0000828 fClipPath.reset();
829#if 0
830 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
831 SkRect r;
832 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
833 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
834 fClipPath.addRect(r);
835 }
836#else
837 SkRect r;
838 r.set(0, 0, W, H);
839 fClipPath.addRect(r, SkPath::kCCW_Direction);
840 r.set(W/4, H/4, W*3/4, H*3/4);
841 fClipPath.addRect(r, SkPath::kCW_Direction);
842#endif
843 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000844
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845 this->updateTitle(); // to refresh our config
846}
847
848///////////////////////////////////////////////////////////////////////////////
849
reed@android.comf2b98d62010-12-20 18:26:13 +0000850template <typename T> void SkTBSort(T array[], int count) {
851 for (int i = 1; i < count - 1; i++) {
852 bool didSwap = false;
853 for (int j = count - 1; j > i; --j) {
854 if (array[j] < array[j-1]) {
855 T tmp(array[j-1]);
856 array[j-1] = array[j];
857 array[j] = tmp;
858 didSwap = true;
859 }
860 }
861 if (!didSwap) {
862 break;
863 }
864 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000865
reed@android.comf2b98d62010-12-20 18:26:13 +0000866 for (int k = 0; k < count - 1; k++) {
867 SkASSERT(!(array[k+1] < array[k]));
868 }
869}
870
871#include "SkRandom.h"
872
873static void rand_rect(SkIRect* rect, SkRandom& rand) {
874 int bits = 8;
875 int shift = 32 - bits;
876 rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
877 rand.nextU() >> shift, rand.nextU() >> shift);
878 rect->sort();
879}
880
881static void dumpRect(const SkIRect& r) {
882 SkDebugf(" { %d, %d, %d, %d },\n",
883 r.fLeft, r.fTop,
884 r.fRight, r.fBottom);
885}
886
887static void test_rects(const SkIRect rect[], int count) {
888 SkRegion rgn0, rgn1;
889
890 for (int i = 0; i < count; i++) {
891 rgn0.op(rect[i], SkRegion::kUnion_Op);
892 // dumpRect(rect[i]);
893 }
894 rgn1.setRects(rect, count);
895
896 if (rgn0 != rgn1) {
897 SkDebugf("\n");
898 for (int i = 0; i < count; i++) {
899 dumpRect(rect[i]);
900 }
901 SkDebugf("\n");
902 }
903}
904
905static void test() {
906 size_t i;
907
908 const SkIRect r0[] = {
909 { 0, 0, 1, 1 },
910 { 2, 2, 3, 3 },
911 };
912 const SkIRect r1[] = {
913 { 0, 0, 1, 3 },
914 { 1, 1, 2, 2 },
915 { 2, 0, 3, 3 },
916 };
917 const SkIRect r2[] = {
918 { 0, 0, 1, 2 },
919 { 2, 1, 3, 3 },
920 { 4, 0, 5, 1 },
921 { 6, 0, 7, 4 },
922 };
923
924 static const struct {
925 const SkIRect* fRects;
926 int fCount;
927 } gRecs[] = {
928 { r0, SK_ARRAY_COUNT(r0) },
929 { r1, SK_ARRAY_COUNT(r1) },
930 { r2, SK_ARRAY_COUNT(r2) },
931 };
932
933 for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
934 test_rects(gRecs[i].fRects, gRecs[i].fCount);
935 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000936
reed@android.comf2b98d62010-12-20 18:26:13 +0000937 SkRandom rand;
938 for (i = 0; i < 10000; i++) {
939 SkRegion rgn0, rgn1;
940
941 const int N = 8;
942 SkIRect rect[N];
943 for (int j = 0; j < N; j++) {
944 rand_rect(&rect[j], rand);
945 }
946 test_rects(rect, N);
947 }
948}
949
reed@android.com8a1c16f2008-12-17 15:59:43 +0000950SkOSWindow* create_sk_window(void* hwnd) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000951// test();
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000952 return new SampleWindow(hwnd);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000953}
954
955void get_preferred_size(int* x, int* y, int* width, int* height) {
956 *x = 10;
957 *y = 50;
958 *width = 640;
959 *height = 480;
960}
961
962void application_init() {
963// setenv("ANDROID_ROOT", "../../../data", 0);
reed@android.come191b162009-12-18 21:33:39 +0000964#ifdef SK_BUILD_FOR_MAC
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965 setenv("ANDROID_ROOT", "/android/device/data", 0);
reed@android.come191b162009-12-18 21:33:39 +0000966#endif
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000967 SkGraphics::Init();
968 SkEvent::Init();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000969}
970
971void application_term() {
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000972 SkEvent::Term();
973 SkGraphics::Term();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974}