blob: 983a910d4591bbe0499b0ce5e98d124d1d3a27ec [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@google.com52f57e12011-03-16 12:10:02 +000014#include "SkTouchGesture.h"
Scroggo0f185c22011-03-24 18:35:50 +000015#include "SkTypeface.h"
reed@android.comf2b98d62010-12-20 18:26:13 +000016
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +000017#define USE_ARROWS_FOR_ZOOM true
reed@android.comf2b98d62010-12-20 18:26:13 +000018//#define DEFAULT_TO_GPU
19
reed@android.come191b162009-12-18 21:33:39 +000020extern SkView* create_overview(int, const SkViewFactory[]);
reed@android.com34245c72009-11-03 04:00:48 +000021
reed@android.comcb342352010-07-22 18:27:53 +000022#define SK_SUPPORT_GL
reed@android.com8a1c16f2008-12-17 15:59:43 +000023
24#define ANIMATING_EVENTTYPE "nextSample"
25#define ANIMATING_DELAY 750
26
reed@google.comac10a2d2010-12-22 21:39:39 +000027#ifdef SK_SUPPORT_GL
28 #include "GrGLConfig.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000029#endif
30
reed@android.com8a1c16f2008-12-17 15:59:43 +000031SkViewRegister* SkViewRegister::gHead;
32SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) {
33 static bool gOnce;
34 if (!gOnce) {
35 gHead = NULL;
36 gOnce = true;
37 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +000038
reed@android.com8a1c16f2008-12-17 15:59:43 +000039 fChain = gHead;
40 gHead = this;
41}
42
reed@android.comf2b98d62010-12-20 18:26:13 +000043#if defined(SK_SUPPORT_GL)
44 #define SK_USE_SHADERS
45#endif
46
twiz@google.com06c3b6b2011-03-14 16:58:39 +000047#ifdef SK_BUILD_FOR_MAC
reed@google.comf0b5f682011-03-11 20:08:25 +000048#include <CoreFoundation/CoreFoundation.h>
49#include <CoreFoundation/CFURLAccess.h>
50
51static void testpdf() {
52 CFStringRef path = CFStringCreateWithCString(NULL, "/test.pdf",
53 kCFStringEncodingUTF8);
54 CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path,
55 kCFURLPOSIXPathStyle,
56 false);
57 CFRelease(path);
58 CGRect box = CGRectMake(0, 0, 8*72, 10*72);
59 CGContextRef cg = CGPDFContextCreateWithURL(url, &box, NULL);
60 CFRelease(url);
61
62 CGContextBeginPage(cg, &box);
63 CGRect r = CGRectMake(10, 10, 40 + 0.5, 50 + 0.5);
64 CGContextFillEllipseInRect(cg, r);
65 CGContextEndPage(cg);
66 CGContextRelease(cg);
67
68 if (false) {
69 SkBitmap bm;
70 bm.setConfig(SkBitmap::kA8_Config, 64, 64);
71 bm.allocPixels();
72 bm.eraseColor(0);
73
74 SkCanvas canvas(bm);
75
76 }
77}
78#endif
79
80//////////////////////////////////////////////////////////////////////////////
81
82#include "SkDrawFilter.h"
83
84class LCDTextDrawFilter : public SkDrawFilter {
85public:
86 enum Mode {
87 kNeutral_Mode,
88 kForceOn_Mode,
89 kForceOff_Mode
90 };
91
92 LCDTextDrawFilter(Mode mode) : fMode(mode) {}
93
94 virtual bool filter(SkCanvas*, SkPaint* paint, Type t) {
95 if (kText_Type == t && kNeutral_Mode != fMode) {
96 fPrevLCD = paint->isLCDRenderText();
97 paint->setLCDRenderText(kForceOn_Mode == fMode);
98 }
99 return true;
100 }
101
102 /** If filter() returned true, then restore() will be called to restore the
103 canvas/paint to their previous states
104 */
105 virtual void restore(SkCanvas*, SkPaint* paint, Type t) {
106 if (kText_Type == t && kNeutral_Mode != fMode) {
107 paint->setLCDRenderText(fPrevLCD);
108 }
109 }
110
111private:
112 Mode fMode;
113 bool fPrevLCD;
114};
115
116LCDTextDrawFilter::Mode cycle_lcdmode(LCDTextDrawFilter::Mode mode) {
117 static const LCDTextDrawFilter::Mode gCycle[] = {
118 /* kNeutral_Mode -> */ LCDTextDrawFilter::kForceOn_Mode,
119 /* kForceOn_Mode -> */ LCDTextDrawFilter::kForceOff_Mode,
120 /* kForceOff_Mode -> */ LCDTextDrawFilter::kNeutral_Mode
121 };
122 return gCycle[mode];
123}
124
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125//////////////////////////////////////////////////////////////////////////////
126
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000127#define MAX_ZOOM_LEVEL 8
128#define MIN_ZOOM_LEVEL -8
129
reed@android.comf2b98d62010-12-20 18:26:13 +0000130static const char gCharEvtName[] = "SampleCode_Char_Event";
131static const char gKeyEvtName[] = "SampleCode_Key_Event";
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132static const char gTitleEvtName[] = "SampleCode_Title_Event";
133static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event";
reed@android.comf2b98d62010-12-20 18:26:13 +0000134static const char gFastTextEvtName[] = "SampleCode_FastText_Event";
135
136bool SampleCode::CharQ(const SkEvent& evt, SkUnichar* outUni) {
137 if (evt.isType(gCharEvtName, sizeof(gCharEvtName) - 1)) {
138 if (outUni) {
139 *outUni = evt.getFast32();
140 }
141 return true;
142 }
143 return false;
144}
145
146bool SampleCode::KeyQ(const SkEvent& evt, SkKey* outKey) {
147 if (evt.isType(gKeyEvtName, sizeof(gKeyEvtName) - 1)) {
148 if (outKey) {
149 *outKey = (SkKey)evt.getFast32();
150 }
151 return true;
152 }
153 return false;
154}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000155
156bool SampleCode::TitleQ(const SkEvent& evt) {
157 return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1);
158}
159
160void SampleCode::TitleR(SkEvent* evt, const char title[]) {
161 SkASSERT(evt && TitleQ(*evt));
162 evt->setString(gTitleEvtName, title);
163}
164
165bool SampleCode::PrefSizeQ(const SkEvent& evt) {
166 return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1);
167}
168
169void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) {
170 SkASSERT(evt && PrefSizeQ(*evt));
171 SkScalar size[2];
172 size[0] = width;
173 size[1] = height;
174 evt->setScalars(gPrefSizeEvtName, 2, size);
175}
176
reed@android.comf2b98d62010-12-20 18:26:13 +0000177bool SampleCode::FastTextQ(const SkEvent& evt) {
178 return evt.isType(gFastTextEvtName, sizeof(gFastTextEvtName) - 1);
179}
180
181///////////////////////////////////////////////////////////////////////////////
182
reed@android.com44177402009-11-23 21:07:51 +0000183static SkMSec gAnimTime;
reed@android.comf2b98d62010-12-20 18:26:13 +0000184static SkMSec gAnimTimePrev;
185
reed@android.com44177402009-11-23 21:07:51 +0000186SkMSec SampleCode::GetAnimTime() { return gAnimTime; }
reed@android.comf2b98d62010-12-20 18:26:13 +0000187SkMSec SampleCode::GetAnimTimeDelta() { return gAnimTime - gAnimTimePrev; }
188SkScalar SampleCode::GetAnimSecondsDelta() {
189 return SkDoubleToScalar(GetAnimTimeDelta() / 1000.0);
190}
reed@android.com44177402009-11-23 21:07:51 +0000191
192SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000193 // since gAnimTime can be up to 32 bits, we can't convert it to a float
194 // or we'll lose the low bits. Hence we use doubles for the intermediate
195 // calculations
196 double seconds = (double)gAnimTime / 1000.0;
197 double value = SkScalarToDouble(speed) * seconds;
reed@android.com44177402009-11-23 21:07:51 +0000198 if (period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000199 value = ::fmod(value, SkScalarToDouble(period));
reed@android.com44177402009-11-23 21:07:51 +0000200 }
reed@android.comf2b98d62010-12-20 18:26:13 +0000201 return SkDoubleToScalar(value);
reed@android.com44177402009-11-23 21:07:51 +0000202}
203
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204//////////////////////////////////////////////////////////////////////////////
205
reed@android.comf2b98d62010-12-20 18:26:13 +0000206static SkView* curr_view(SkWindow* wind) {
207 SkView::F2BIter iter(wind);
208 return iter.next();
209}
210
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211class SampleWindow : public SkOSWindow {
reed@android.com34245c72009-11-03 04:00:48 +0000212 SkTDArray<SkViewFactory> fSamples;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213public:
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000214 SampleWindow(void* hwnd);
215 virtual ~SampleWindow();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216
reed@android.come522ca52009-11-23 20:10:41 +0000217 virtual void draw(SkCanvas* canvas);
218
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219protected:
220 virtual void onDraw(SkCanvas* canvas);
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000221 virtual bool onHandleKey(SkKey key);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 virtual bool onHandleChar(SkUnichar);
223 virtual void onSizeChange();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000224
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 virtual SkCanvas* beforeChildren(SkCanvas*);
226 virtual void afterChildren(SkCanvas*);
reed@android.com6c5f6f22009-08-14 16:08:38 +0000227 virtual void beforeChild(SkView* child, SkCanvas* canvas);
228 virtual void afterChild(SkView* child, SkCanvas* canvas);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000229
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000230 virtual bool onEvent(const SkEvent& evt);
reed@android.comf2b98d62010-12-20 18:26:13 +0000231 virtual bool onQuery(SkEvent* evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000233 virtual bool onDispatchClick(int x, int y, Click::State);
reed@google.com52f57e12011-03-16 12:10:02 +0000234 virtual bool onClick(Click* click);
235 virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
236
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237#if 0
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000238 virtual bool handleChar(SkUnichar uni);
239 virtual bool handleEvent(const SkEvent& evt);
240 virtual bool handleKey(SkKey key);
241 virtual bool handleKeyUp(SkKey key);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 virtual bool onHandleKeyUp(SkKey key);
243#endif
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000244
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245private:
reed@android.com34245c72009-11-03 04:00:48 +0000246 int fCurrIndex;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000247
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248 SkPicture* fPicture;
reed@android.comf2b98d62010-12-20 18:26:13 +0000249 SkGpuCanvas* fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000250 GrContext* fGrContext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 SkPath fClipPath;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000252
reed@google.com52f57e12011-03-16 12:10:02 +0000253 SkTouchGesture fGesture;
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000254 int fZoomLevel;
255 SkScalar fZoomScale;
reed@google.com52f57e12011-03-16 12:10:02 +0000256
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257 enum CanvasType {
258 kRaster_CanvasType,
259 kPicture_CanvasType,
reed@android.comf2b98d62010-12-20 18:26:13 +0000260 kGPU_CanvasType
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261 };
262 CanvasType fCanvasType;
263
264 bool fUseClip;
reed@android.come522ca52009-11-23 20:10:41 +0000265 bool fNClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266 bool fRepeatDrawing;
267 bool fAnimating;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000268 bool fRotate;
269 bool fScale;
reed@android.comf2b98d62010-12-20 18:26:13 +0000270 bool fRequestGrabImage;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000271
Scroggo0f185c22011-03-24 18:35:50 +0000272 // The following are for the 'fatbits' drawing
273 // Latest position of the mouse.
274 int fMouseX, fMouseY;
275 int fFatBitsScale;
276 // Used by the text showing position and color values.
277 SkTypeface* fTypeface;
278 bool fShowZoomer;
279
reed@google.comf0b5f682011-03-11 20:08:25 +0000280 LCDTextDrawFilter::Mode fLCDMode;
281
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282 int fScrollTestX, fScrollTestY;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000283
284 bool make3DReady();
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000285 void changeZoomLevel(int delta);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000286
reed@android.com8a1c16f2008-12-17 15:59:43 +0000287 void loadView(SkView*);
288 void updateTitle();
289 bool nextSample();
290
Scroggo0f185c22011-03-24 18:35:50 +0000291 void toggleZoomer();
292 bool zoomIn();
293 bool zoomOut();
294 void updatePointer(int x, int y);
295
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296 void postAnimatingEvent() {
297 if (fAnimating) {
298 SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
299 evt->post(this->getSinkID(), ANIMATING_DELAY);
300 }
301 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000302
303
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 static CanvasType cycle_canvastype(CanvasType);
305
306 typedef SkOSWindow INHERITED;
307};
308
Scroggo0f185c22011-03-24 18:35:50 +0000309bool SampleWindow::zoomIn()
310{
311 // Arbitrarily decided
312 if (fFatBitsScale == 25) return false;
313 fFatBitsScale++;
314 this->inval(NULL);
315 return true;
316}
317
318bool SampleWindow::zoomOut()
319{
320 if (fFatBitsScale == 1) return false;
321 fFatBitsScale--;
322 this->inval(NULL);
323 return true;
324}
325
326void SampleWindow::toggleZoomer()
327{
328 fShowZoomer = !fShowZoomer;
329 this->inval(NULL);
330}
331
332void SampleWindow::updatePointer(int x, int y)
333{
334 fMouseX = x;
335 fMouseY = y;
336 if (fShowZoomer) {
337 this->inval(NULL);
338 }
339}
340
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000341bool SampleWindow::make3DReady() {
342
343#if defined(SK_SUPPORT_GL)
bsalomon@google.com498a6232011-03-10 18:24:15 +0000344 if (attachGL()) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000345 if (NULL != fGrContext) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000346 // various gr lifecycle tests
347 #if 0
348 fGrContext->freeGpuResources();
349 #elif 0
350 // this will leak resources.
351 fGrContext->contextLost();
352 #elif 0
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000353 GrAssert(1 == fGrContext->refcnt());
354 fGrContext->unref();
355 fGrContext = NULL;
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000356 #endif
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000357 }
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000358
bsalomon@google.com498a6232011-03-10 18:24:15 +0000359 if (NULL == fGrContext) {
360 #if defined(SK_USE_SHADERS)
361 fGrContext = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
362 #else
363 fGrContext = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, NULL);
364 #endif
365 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000366
bsalomon@google.com498a6232011-03-10 18:24:15 +0000367 if (NULL != fGrContext) {
368 return true;
369 } else {
370 detachGL();
371 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000372 }
373#endif
374 SkDebugf("Failed to setup 3D");
375 return false;
376}
377
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
379 static const CanvasType gCT[] = {
380 kPicture_CanvasType,
reed@android.comf2b98d62010-12-20 18:26:13 +0000381 kGPU_CanvasType,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000382 kRaster_CanvasType
383 };
384 return gCT[ct];
385}
386
387SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388 fPicture = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000389 fGpuCanvas = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000390
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000391 fGrContext = NULL;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000392
reed@android.comf2b98d62010-12-20 18:26:13 +0000393#ifdef DEFAULT_TO_GPU
394 fCanvasType = kGPU_CanvasType;
395#else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000396 fCanvasType = kRaster_CanvasType;
reed@android.comf2b98d62010-12-20 18:26:13 +0000397#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000398 fUseClip = false;
reed@android.come522ca52009-11-23 20:10:41 +0000399 fNClip = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400 fRepeatDrawing = false;
401 fAnimating = false;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000402 fRotate = false;
403 fScale = false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000404 fRequestGrabImage = false;
reed@google.comf0b5f682011-03-11 20:08:25 +0000405 fLCDMode = LCDTextDrawFilter::kNeutral_Mode;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000406 fScrollTestX = fScrollTestY = 0;
407
Scroggo0f185c22011-03-24 18:35:50 +0000408 fMouseX = fMouseY = 0;
409 fFatBitsScale = 1;
410 fTypeface = SkTypeface::CreateFromTypeface(NULL, SkTypeface::kBold);
411 fShowZoomer = false;
412
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000413 fZoomLevel = 0;
414 fZoomScale = SK_Scalar1;
415
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000416// this->setConfig(SkBitmap::kRGB_565_Config);
417 this->setConfig(SkBitmap::kARGB_8888_Config);
418 this->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000419 this->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000420
reed@android.com34245c72009-11-03 04:00:48 +0000421 {
422 const SkViewRegister* reg = SkViewRegister::Head();
423 while (reg) {
424 *fSamples.append() = reg->factory();
425 reg = reg->next();
426 }
427 }
428 fCurrIndex = 0;
reed@android.come0f13ee2009-11-04 19:40:25 +0000429 this->loadView(fSamples[fCurrIndex]());
reed@google.comf0b5f682011-03-11 20:08:25 +0000430
twiz@google.com06c3b6b2011-03-14 16:58:39 +0000431#ifdef SK_BUILD_FOR_MAC
reed@google.comf0b5f682011-03-11 20:08:25 +0000432 testpdf();
twiz@google.com06c3b6b2011-03-14 16:58:39 +0000433#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000434}
435
436SampleWindow::~SampleWindow() {
437 delete fPicture;
reed@android.comf2b98d62010-12-20 18:26:13 +0000438 delete fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000439 if (NULL != fGrContext) {
440 fGrContext->unref();
441 }
Scroggo0f185c22011-03-24 18:35:50 +0000442 fTypeface->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443}
444
reed@android.com55e76b22009-11-23 21:46:47 +0000445static SkBitmap capture_bitmap(SkCanvas* canvas) {
446 SkBitmap bm;
447 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
448 src.copyTo(&bm, src.config());
449 return bm;
450}
451
452static bool bitmap_diff(SkCanvas* canvas, const SkBitmap& orig,
453 SkBitmap* diff) {
454 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000455
reed@android.com55e76b22009-11-23 21:46:47 +0000456 SkAutoLockPixels alp0(src);
457 SkAutoLockPixels alp1(orig);
458 for (int y = 0; y < src.height(); y++) {
459 const void* srcP = src.getAddr(0, y);
460 const void* origP = orig.getAddr(0, y);
461 size_t bytes = src.width() * src.bytesPerPixel();
462 if (memcmp(srcP, origP, bytes)) {
463 SkDebugf("---------- difference on line %d\n", y);
464 return true;
465 }
466 }
467 return false;
468}
469
Scroggo0f185c22011-03-24 18:35:50 +0000470static void drawText(SkCanvas* canvas, SkString string, SkScalar left, SkScalar top, SkPaint& paint)
471{
472 SkColor desiredColor = paint.getColor();
473 paint.setColor(SK_ColorWHITE);
474 const char* c_str = string.c_str();
475 size_t size = string.size();
476 SkRect bounds;
477 paint.measureText(c_str, size, &bounds);
478 bounds.offset(left, top);
479 SkScalar inset = SkIntToScalar(-2);
480 bounds.inset(inset, inset);
481 canvas->drawRect(bounds, paint);
482 if (desiredColor != SK_ColorBLACK) {
483 paint.setColor(SK_ColorBLACK);
484 canvas->drawText(c_str, size, left + SK_Scalar1, top + SK_Scalar1, paint);
485 }
486 paint.setColor(desiredColor);
487 canvas->drawText(c_str, size, left, top, paint);
488}
489
reed@android.com44177402009-11-23 21:07:51 +0000490#define XCLIP_N 8
491#define YCLIP_N 8
reed@android.come522ca52009-11-23 20:10:41 +0000492
493void SampleWindow::draw(SkCanvas* canvas) {
reed@android.com44177402009-11-23 21:07:51 +0000494 // update the animation time
reed@android.comf2b98d62010-12-20 18:26:13 +0000495 gAnimTimePrev = gAnimTime;
reed@android.com44177402009-11-23 21:07:51 +0000496 gAnimTime = SkTime::GetMSecs();
497
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000498 if (fZoomLevel) {
499 SkMatrix m;
500 SkScalar cx = SkScalarHalf(this->width());
501 SkScalar cy = SkScalarHalf(this->height());
502 SkPoint center;
503 m = canvas->getTotalMatrix();//.invert(&m);
504 m.mapXY(cx, cy, &center);
505 cx = center.fX;
506 cy = center.fY;
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000507
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000508 m.setTranslate(-cx, -cy);
509 m.postScale(fZoomScale, fZoomScale);
510 m.postTranslate(cx, cy);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000511
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000512 canvas->concat(m);
513 }
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000514
reed@google.com52f57e12011-03-16 12:10:02 +0000515 // Apply any gesture matrix
516 if (true) {
517 const SkMatrix& localM = fGesture.localM();
518 if (localM.getType() & SkMatrix::kScale_Mask) {
519 canvas->setExternalMatrix(&localM);
520 }
521 canvas->concat(localM);
522 canvas->concat(fGesture.globalM());
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000523
reed@google.com52f57e12011-03-16 12:10:02 +0000524 if (fGesture.isActive()) {
525 this->inval(NULL);
526 }
527 }
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000528
reed@android.come522ca52009-11-23 20:10:41 +0000529 if (fNClip) {
reed@android.com55e76b22009-11-23 21:46:47 +0000530 this->INHERITED::draw(canvas);
531 SkBitmap orig = capture_bitmap(canvas);
reed@android.come522ca52009-11-23 20:10:41 +0000532
533 const SkScalar w = this->width();
534 const SkScalar h = this->height();
535 const SkScalar cw = w / XCLIP_N;
536 const SkScalar ch = h / YCLIP_N;
537 for (int y = 0; y < YCLIP_N; y++) {
reed@android.com55e76b22009-11-23 21:46:47 +0000538 SkRect r;
539 r.fTop = y * ch;
540 r.fBottom = (y + 1) * ch;
541 if (y == YCLIP_N - 1) {
542 r.fBottom = h;
543 }
reed@android.come522ca52009-11-23 20:10:41 +0000544 for (int x = 0; x < XCLIP_N; x++) {
545 SkAutoCanvasRestore acr(canvas, true);
reed@android.com55e76b22009-11-23 21:46:47 +0000546 r.fLeft = x * cw;
547 r.fRight = (x + 1) * cw;
548 if (x == XCLIP_N - 1) {
549 r.fRight = w;
550 }
reed@android.come522ca52009-11-23 20:10:41 +0000551 canvas->clipRect(r);
552 this->INHERITED::draw(canvas);
553 }
554 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000555
reed@android.com55e76b22009-11-23 21:46:47 +0000556 SkBitmap diff;
557 if (bitmap_diff(canvas, orig, &diff)) {
558 }
reed@android.come522ca52009-11-23 20:10:41 +0000559 } else {
560 this->INHERITED::draw(canvas);
561 }
Scroggo0f185c22011-03-24 18:35:50 +0000562 if (fShowZoomer) {
563 int count = canvas->save();
564 canvas->resetMatrix();
565 // Ensure the mouse position is on screen.
566 int width = this->width();
567 int height = this->height();
568 if (fMouseX >= width) fMouseX = width - 1;
569 else if (fMouseX < 0) fMouseX = 0;
570 if (fMouseY >= height) fMouseY = height - 1;
571 else if (fMouseY < 0) fMouseY = 0;
572 SkBitmap bitmap = capture_bitmap(canvas);
573 // Find the size of the zoomed in view, forced to be odd, so the examined pixel is in the middle.
574 int zoomedWidth = (width >> 2) | 1;
575 int zoomedHeight = (height >> 2) | 1;
576 SkIRect src;
577 src.set(0, 0, zoomedWidth / fFatBitsScale, zoomedHeight / fFatBitsScale);
578 src.offset(fMouseX - (src.width()>>1), fMouseY - (src.height()>>1));
579 SkRect dest;
580 dest.set(0, 0, SkIntToScalar(zoomedWidth), SkIntToScalar(zoomedHeight));
581 dest.offset(SkIntToScalar(width - zoomedWidth), SkIntToScalar(height - zoomedHeight));
582 SkPaint paint;
583 // Clear the background behind our zoomed in view
584 paint.setColor(SK_ColorWHITE);
585 canvas->drawRect(dest, paint);
586 canvas->drawBitmapRect(bitmap, &src, dest);
587 paint.setColor(SK_ColorBLACK);
588 paint.setStyle(SkPaint::kStroke_Style);
589 // Draw a border around the pixel in the middle
590 SkRect originalPixel;
591 originalPixel.set(SkIntToScalar(fMouseX), SkIntToScalar(fMouseY), SkIntToScalar(fMouseX + 1), SkIntToScalar(fMouseY + 1));
592 SkMatrix matrix;
593 SkRect scalarSrc;
594 scalarSrc.set(src);
595 SkColor color = bitmap.getColor(fMouseX, fMouseY);
596 if (matrix.setRectToRect(scalarSrc, dest, SkMatrix::kFill_ScaleToFit)) {
597 SkRect pixel;
598 matrix.mapRect(&pixel, originalPixel);
599 // TODO Perhaps measure the values and make the outline white if it's "dark"
600 if (color == SK_ColorBLACK) {
601 paint.setColor(SK_ColorWHITE);
602 }
603 canvas->drawRect(pixel, paint);
604 }
605 paint.setColor(SK_ColorBLACK);
606 // Draw a border around the destination rectangle
607 canvas->drawRect(dest, paint);
608 paint.setStyle(SkPaint::kStrokeAndFill_Style);
609 // Identify the pixel and its color on screen
610 paint.setTypeface(fTypeface);
611 paint.setAntiAlias(true);
612 SkScalar lineHeight = paint.getFontMetrics(NULL);
613 SkString string;
614 string.appendf("(%i, %i)", fMouseX, fMouseY);
615 SkScalar left = dest.fLeft + SkIntToScalar(3);
616 SkScalar i = SK_Scalar1;
617 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
618 // Alpha
619 i += SK_Scalar1;
620 string.reset();
621 string.appendf("A: %X", SkColorGetA(color));
622 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
623 // Red
624 i += SK_Scalar1;
625 string.reset();
626 string.appendf("R: %X", SkColorGetR(color));
627 paint.setColor(SK_ColorRED);
628 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
629 // Green
630 i += SK_Scalar1;
631 string.reset();
632 string.appendf("G: %X", SkColorGetG(color));
633 paint.setColor(SK_ColorGREEN);
634 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
635 // Blue
636 i += SK_Scalar1;
637 string.reset();
638 string.appendf("B: %X", SkColorGetB(color));
639 paint.setColor(SK_ColorBLUE);
640 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
641 canvas->restoreToCount(count);
642 }
reed@android.come522ca52009-11-23 20:10:41 +0000643}
644
reed@android.com8a1c16f2008-12-17 15:59:43 +0000645void SampleWindow::onDraw(SkCanvas* canvas) {
646 if (fRepeatDrawing) {
647 this->inval(NULL);
648 }
649}
650
651#include "SkColorPriv.h"
652
653static void reverseRedAndBlue(const SkBitmap& bm) {
654 SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
655 uint8_t* p = (uint8_t*)bm.getPixels();
656 uint8_t* stop = p + bm.getSize();
657 while (p < stop) {
658 // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
659 unsigned scale = SkAlpha255To256(p[3]);
660 unsigned r = p[2];
661 unsigned b = p[0];
662 p[0] = SkAlphaMul(r, scale);
663 p[1] = SkAlphaMul(p[1], scale);
664 p[2] = SkAlphaMul(b, scale);
665 p += 4;
666 }
667}
668
669SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000670 SkIPoint viewport;
671 bool alreadyGPU = canvas->getViewport(&viewport);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000672
reed@android.comf2b98d62010-12-20 18:26:13 +0000673 if (kGPU_CanvasType != fCanvasType) {
reed@android.com6efdc472008-12-19 18:24:35 +0000674#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000675 detachGL();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000676#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000677 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000678
reed@android.com8a1c16f2008-12-17 15:59:43 +0000679 switch (fCanvasType) {
680 case kRaster_CanvasType:
681 canvas = this->INHERITED::beforeChildren(canvas);
682 break;
683 case kPicture_CanvasType:
684 fPicture = new SkPicture;
685 canvas = fPicture->beginRecording(9999, 9999);
686 break;
reed@google.comac10a2d2010-12-22 21:39:39 +0000687 case kGPU_CanvasType: {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000688 if (!alreadyGPU && make3DReady()) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000689 SkDevice* device = canvas->getDevice();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000690 const SkBitmap& bitmap = device->accessBitmap(true);
691
bsalomon@google.com5782d712011-01-21 21:03:59 +0000692 GrRenderTarget* renderTarget;
693 renderTarget = fGrContext->createRenderTargetFrom3DApiState();
694 fGpuCanvas = new SkGpuCanvas(fGrContext, renderTarget);
695 renderTarget->unref();
696
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000697 device = fGpuCanvas->createDevice(SkBitmap::kARGB_8888_Config,
698 bitmap.width(), bitmap.height(),
699 false, false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000700 fGpuCanvas->setDevice(device)->unref();
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000701
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000702 fGpuCanvas->concat(canvas->getTotalMatrix());
reed@android.comf2b98d62010-12-20 18:26:13 +0000703 canvas = fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000704
reed@android.comf2b98d62010-12-20 18:26:13 +0000705 } else {
706 canvas = this->INHERITED::beforeChildren(canvas);
707 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000708 break;
reed@google.comac10a2d2010-12-22 21:39:39 +0000709 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000710 }
711
712 if (fUseClip) {
713 canvas->drawColor(0xFFFF88FF);
714 canvas->clipPath(fClipPath);
715 }
716
717 return canvas;
718}
719
720static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
721 const SkRegion& rgn) {
722 SkCanvas canvas(bm);
723 SkRegion inval(rgn);
724
725 inval.translate(r.fLeft, r.fTop);
726 canvas.clipRegion(inval);
727 canvas.drawColor(0xFFFF8080);
728}
729
730void SampleWindow::afterChildren(SkCanvas* orig) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000731 if (fRequestGrabImage) {
732 fRequestGrabImage = false;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000733
reed@android.comf2b98d62010-12-20 18:26:13 +0000734 SkCanvas* canvas = fGpuCanvas ? fGpuCanvas : orig;
735 SkDevice* device = canvas->getDevice();
736 SkBitmap bitmap;
reed@google.com5ba2d5b2011-03-10 19:40:34 +0000737 SkIRect bounds = {
738 0, 0,
739 SkScalarRound(this->width()),
740 SkScalarRound(this->height())
741 };
reed@android.comf2b98d62010-12-20 18:26:13 +0000742 if (device->readPixels(bounds, &bitmap)) {
743 static int gSampleGrabCounter;
744 SkString name;
745 name.printf("sample_grab_%d", gSampleGrabCounter++);
746 SkImageEncoder::EncodeFile(name.c_str(), bitmap,
747 SkImageEncoder::kPNG_Type, 100);
748 }
749 }
750
reed@android.com8a1c16f2008-12-17 15:59:43 +0000751 switch (fCanvasType) {
752 case kRaster_CanvasType:
753 break;
754 case kPicture_CanvasType:
reed@android.comaefd2bc2009-03-30 21:02:14 +0000755 if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000756 SkPicture* pict = new SkPicture(*fPicture);
757 fPicture->unref();
758 orig->drawPicture(*pict);
759 pict->unref();
reed@android.comaefd2bc2009-03-30 21:02:14 +0000760 } else if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000761 SkDynamicMemoryWStream ostream;
762 fPicture->serialize(&ostream);
763 fPicture->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000764
reed@android.com8a1c16f2008-12-17 15:59:43 +0000765 SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
766 SkPicture pict(&istream);
767 orig->drawPicture(pict);
768 } else {
769 fPicture->draw(orig);
770 fPicture->unref();
771 }
772 fPicture = NULL;
773 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000774#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000775 case kGPU_CanvasType:
776 delete fGpuCanvas;
777 fGpuCanvas = NULL;
778 presentGL();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000779 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000780#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000781 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000782
reed@android.com8a1c16f2008-12-17 15:59:43 +0000783// if ((fScrollTestX | fScrollTestY) != 0)
reed@android.comf2b98d62010-12-20 18:26:13 +0000784 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000785 const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
786 int dx = fScrollTestX * 7;
787 int dy = fScrollTestY * 7;
788 SkIRect r;
789 SkRegion inval;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000790
reed@android.com8a1c16f2008-12-17 15:59:43 +0000791 r.set(50, 50, 50+100, 50+100);
792 bm.scrollRect(&r, dx, dy, &inval);
793 paint_rgn(bm, r, inval);
794 }
795}
796
reed@android.com6c5f6f22009-08-14 16:08:38 +0000797void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
798 if (fScale) {
799 SkScalar scale = SK_Scalar1 * 7 / 10;
800 SkScalar cx = this->width() / 2;
801 SkScalar cy = this->height() / 2;
802 canvas->translate(cx, cy);
803 canvas->scale(scale, scale);
804 canvas->translate(-cx, -cy);
805 }
806 if (fRotate) {
807 SkScalar cx = this->width() / 2;
808 SkScalar cy = this->height() / 2;
809 canvas->translate(cx, cy);
810 canvas->rotate(SkIntToScalar(30));
811 canvas->translate(-cx, -cy);
812 }
reed@google.comf0b5f682011-03-11 20:08:25 +0000813
814 if (LCDTextDrawFilter::kNeutral_Mode != fLCDMode) {
815 canvas->setDrawFilter(new LCDTextDrawFilter(fLCDMode))->unref();
816 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000817}
818
819void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) {
reed@google.comf0b5f682011-03-11 20:08:25 +0000820 canvas->setDrawFilter(NULL);
reed@android.com6c5f6f22009-08-14 16:08:38 +0000821}
822
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823static SkBitmap::Config gConfigCycle[] = {
824 SkBitmap::kNo_Config, // none -> none
825 SkBitmap::kNo_Config, // a1 -> none
826 SkBitmap::kNo_Config, // a8 -> none
827 SkBitmap::kNo_Config, // index8 -> none
828 SkBitmap::kARGB_4444_Config, // 565 -> 4444
829 SkBitmap::kARGB_8888_Config, // 4444 -> 8888
830 SkBitmap::kRGB_565_Config // 8888 -> 565
831};
832
833static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
834 return gConfigCycle[c];
835}
836
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000837void SampleWindow::changeZoomLevel(int delta) {
838 fZoomLevel += delta;
839 if (fZoomLevel > 0) {
840 fZoomLevel = SkMin32(fZoomLevel, MAX_ZOOM_LEVEL);
841 fZoomScale = SkIntToScalar(fZoomLevel + 1);
842 } else if (fZoomLevel < 0) {
843 fZoomLevel = SkMax32(fZoomLevel, MIN_ZOOM_LEVEL);
844 fZoomScale = SK_Scalar1 / (1 - fZoomLevel);
845 } else {
846 fZoomScale = SK_Scalar1;
847 }
848
849 this->inval(NULL);
850}
851
reed@android.com8a1c16f2008-12-17 15:59:43 +0000852bool SampleWindow::nextSample() {
reed@android.com34245c72009-11-03 04:00:48 +0000853 fCurrIndex = (fCurrIndex + 1) % fSamples.count();
854 this->loadView(fSamples[fCurrIndex]());
855 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000856}
857
858bool SampleWindow::onEvent(const SkEvent& evt) {
859 if (evt.isType(ANIMATING_EVENTTYPE)) {
860 if (fAnimating) {
861 this->nextSample();
862 this->postAnimatingEvent();
863 }
864 return true;
865 }
reed@android.com34245c72009-11-03 04:00:48 +0000866 if (evt.isType("set-curr-index")) {
867 fCurrIndex = evt.getFast32() % fSamples.count();
868 this->loadView(fSamples[fCurrIndex]());
869 return true;
870 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000871 return this->INHERITED::onEvent(evt);
872}
873
reed@android.comf2b98d62010-12-20 18:26:13 +0000874bool SampleWindow::onQuery(SkEvent* query) {
875 if (query->isType("get-slide-count")) {
876 query->setFast32(fSamples.count());
877 return true;
878 }
879 if (query->isType("get-slide-title")) {
880 SkView* view = fSamples[query->getFast32()]();
881 SkEvent evt(gTitleEvtName);
882 if (view->doQuery(&evt)) {
883 query->setString("title", evt.findString(gTitleEvtName));
884 }
885 SkSafeUnref(view);
886 return true;
887 }
888 if (query->isType("use-fast-text")) {
889 SkEvent evt(gFastTextEvtName);
890 return curr_view(this)->doQuery(&evt);
891 }
892 return this->INHERITED::onQuery(query);
893}
894
reed@android.com0ae6b242008-12-23 16:49:54 +0000895static void cleanup_for_filename(SkString* name) {
896 char* str = name->writable_str();
reed@android.come191b162009-12-18 21:33:39 +0000897 for (size_t i = 0; i < name->size(); i++) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000898 switch (str[i]) {
899 case ':': str[i] = '-'; break;
900 case '/': str[i] = '-'; break;
901 case ' ': str[i] = '_'; break;
902 default: break;
903 }
904 }
905}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000906
907bool SampleWindow::onHandleChar(SkUnichar uni) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000908 {
909 SkView* view = curr_view(this);
910 if (view) {
911 SkEvent evt(gCharEvtName);
912 evt.setFast32(uni);
913 if (view->doQuery(&evt)) {
914 return true;
915 }
916 }
917 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000918
reed@android.com8a1c16f2008-12-17 15:59:43 +0000919 int dx = 0xFF;
920 int dy = 0xFF;
921
922 switch (uni) {
923 case '5': dx = 0; dy = 0; break;
924 case '8': dx = 0; dy = -1; break;
925 case '6': dx = 1; dy = 0; break;
926 case '2': dx = 0; dy = 1; break;
927 case '4': dx = -1; dy = 0; break;
928 case '7': dx = -1; dy = -1; break;
929 case '9': dx = 1; dy = -1; break;
930 case '3': dx = 1; dy = 1; break;
931 case '1': dx = -1; dy = 1; break;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000932
reed@android.com8a1c16f2008-12-17 15:59:43 +0000933 default:
934 break;
935 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000936
reed@android.com8a1c16f2008-12-17 15:59:43 +0000937 if (0xFF != dx && 0xFF != dy) {
938 if ((dx | dy) == 0) {
939 fScrollTestX = fScrollTestY = 0;
940 } else {
941 fScrollTestX += dx;
942 fScrollTestY += dy;
943 }
944 this->inval(NULL);
945 return true;
946 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000947
reed@android.com0ae6b242008-12-23 16:49:54 +0000948 switch (uni) {
949 case 'a':
950 fAnimating = !fAnimating;
951 this->postAnimatingEvent();
952 this->updateTitle();
953 return true;
954 case 'f': {
955 const char* title = this->getTitle();
956 if (title[0] == 0) {
957 title = "sampleapp";
958 }
959 SkString name(title);
960 cleanup_for_filename(&name);
961 name.append(".png");
962 if (SkImageEncoder::EncodeFile(name.c_str(), this->getBitmap(),
reed@android.comb08eb2b2009-01-06 20:16:26 +0000963 SkImageEncoder::kPNG_Type, 100)) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000964 SkDebugf("Created %s\n", name.c_str());
965 }
966 return true;
967 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000968 case 'r':
969 fRotate = !fRotate;
970 this->inval(NULL);
971 this->updateTitle();
972 return true;
973 case 's':
974 fScale = !fScale;
975 this->inval(NULL);
976 this->updateTitle();
977 return true;
reed@google.comfb56a9e2011-02-10 18:47:24 +0000978 case 'c':
979 fUseClip = !fUseClip;
980 this->inval(NULL);
981 this->updateTitle();
982 return true;
reed@android.comf2b98d62010-12-20 18:26:13 +0000983 case 'd':
984 SkGraphics::SetFontCacheUsed(0);
985 return true;
986 case 'g':
987 fRequestGrabImage = true;
988 this->inval(NULL);
989 break;
reed@google.comf0b5f682011-03-11 20:08:25 +0000990 case 'l':
991 fLCDMode = cycle_lcdmode(fLCDMode);
992 this->updateTitle();
993 this->inval(NULL);
994 break;
scroggo08526c02011-03-22 14:03:21 +0000995 case 'i':
996 this->zoomIn();
997 break;
998 case 'o':
999 this->zoomOut();
1000 break;
1001 case 'z':
1002 this->toggleZoomer();
1003 break;
reed@android.com0ae6b242008-12-23 16:49:54 +00001004 default:
1005 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001006 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001007
reed@android.com8a1c16f2008-12-17 15:59:43 +00001008 return this->INHERITED::onHandleChar(uni);
1009}
1010
1011#include "SkDumpCanvas.h"
1012
1013bool SampleWindow::onHandleKey(SkKey key) {
reed@android.comf2b98d62010-12-20 18:26:13 +00001014 {
1015 SkView* view = curr_view(this);
1016 if (view) {
1017 SkEvent evt(gKeyEvtName);
1018 evt.setFast32(key);
1019 if (view->doQuery(&evt)) {
1020 return true;
1021 }
1022 }
1023 }
1024
reed@android.com8a1c16f2008-12-17 15:59:43 +00001025 switch (key) {
1026 case kRight_SkKey:
1027 if (this->nextSample()) {
1028 return true;
1029 }
1030 break;
1031 case kLeft_SkKey:
1032 fCanvasType = cycle_canvastype(fCanvasType);
1033 this->updateTitle();
1034 this->inval(NULL);
1035 return true;
1036 case kUp_SkKey:
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001037 if (USE_ARROWS_FOR_ZOOM) {
1038 this->changeZoomLevel(1);
1039 } else {
1040 fNClip = !fNClip;
1041 this->inval(NULL);
1042 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001043 this->updateTitle();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001044 return true;
1045 case kDown_SkKey:
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001046 if (USE_ARROWS_FOR_ZOOM) {
1047 this->changeZoomLevel(-1);
1048 } else {
1049 this->setConfig(cycle_configs(this->getBitmap().config()));
1050 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001051 this->updateTitle();
1052 return true;
1053 case kOK_SkKey:
reed@android.comf2b98d62010-12-20 18:26:13 +00001054 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001055 SkDebugfDumper dumper;
1056 SkDumpCanvas dc(&dumper);
1057 this->draw(&dc);
1058 } else {
1059 fRepeatDrawing = !fRepeatDrawing;
1060 if (fRepeatDrawing) {
1061 this->inval(NULL);
1062 }
1063 }
1064 return true;
reed@android.com34245c72009-11-03 04:00:48 +00001065 case kBack_SkKey:
1066 this->loadView(NULL);
1067 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001068 default:
1069 break;
1070 }
1071 return this->INHERITED::onHandleKey(key);
1072}
1073
reed@google.com52f57e12011-03-16 12:10:02 +00001074///////////////////////////////////////////////////////////////////////////////
1075
1076static const char gGestureClickType[] = "GestureClickType";
1077
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001078bool SampleWindow::onDispatchClick(int x, int y, Click::State state) {
Scroggo0f185c22011-03-24 18:35:50 +00001079 if (Click::kMoved_State == state) {
1080 updatePointer(x, y);
1081 }
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001082 int w = SkScalarRound(this->width());
1083 int h = SkScalarRound(this->height());
1084
1085 // check for the resize-box
1086 if (w - x < 16 && h - y < 16) {
1087 return false; // let the OS handle the click
1088 } else {
1089 return this->INHERITED::onDispatchClick(x, y, state);
1090 }
1091}
1092
reed@google.com52f57e12011-03-16 12:10:02 +00001093class GestureClick : public SkView::Click {
1094public:
1095 GestureClick(SkView* target) : SkView::Click(target) {
1096 this->setType(gGestureClickType);
1097 }
1098
1099 static bool IsGesture(Click* click) {
1100 return click->isType(gGestureClickType);
1101 }
1102};
1103
1104SkView::Click* SampleWindow::onFindClickHandler(SkScalar x, SkScalar y) {
1105 return new GestureClick(this);
1106}
1107
1108bool SampleWindow::onClick(Click* click) {
1109 if (GestureClick::IsGesture(click)) {
1110 float x = SkScalarToFloat(click->fCurr.fX);
1111 float y = SkScalarToFloat(click->fCurr.fY);
1112 switch (click->fState) {
1113 case SkView::Click::kDown_State:
1114 fGesture.touchBegin(click, x, y);
1115 break;
1116 case SkView::Click::kMoved_State:
1117 fGesture.touchMoved(click, x, y);
1118 this->inval(NULL);
1119 break;
1120 case SkView::Click::kUp_State:
1121 fGesture.touchEnd(click);
1122 this->inval(NULL);
1123 break;
1124 }
1125 return true;
1126 }
1127 return false;
1128}
1129
1130///////////////////////////////////////////////////////////////////////////////
1131
reed@android.com8a1c16f2008-12-17 15:59:43 +00001132void SampleWindow::loadView(SkView* view) {
1133 SkView::F2BIter iter(this);
1134 SkView* prev = iter.next();
1135 if (prev) {
1136 prev->detachFromParent();
1137 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001138
reed@android.com34245c72009-11-03 04:00:48 +00001139 if (NULL == view) {
1140 view = create_overview(fSamples.count(), fSamples.begin());
1141 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001142 view->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +00001143 view->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001144 this->attachChildToFront(view)->unref();
1145 view->setSize(this->width(), this->height());
1146
1147 this->updateTitle();
1148}
1149
1150static const char* gConfigNames[] = {
1151 "unknown config",
1152 "A1",
1153 "A8",
1154 "Index8",
1155 "565",
1156 "4444",
1157 "8888"
1158};
1159
1160static const char* configToString(SkBitmap::Config c) {
1161 return gConfigNames[c];
1162}
1163
1164static const char* gCanvasTypePrefix[] = {
1165 "raster: ",
1166 "picture: ",
1167 "opengl: "
1168};
1169
1170void SampleWindow::updateTitle() {
1171 SkString title;
1172
1173 SkView::F2BIter iter(this);
1174 SkView* view = iter.next();
1175 SkEvent evt(gTitleEvtName);
1176 if (view->doQuery(&evt)) {
1177 title.set(evt.findString(gTitleEvtName));
1178 }
1179 if (title.size() == 0) {
1180 title.set("<unknown>");
1181 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001182
reed@android.com8a1c16f2008-12-17 15:59:43 +00001183 title.prepend(gCanvasTypePrefix[fCanvasType]);
1184
1185 title.prepend(" ");
1186 title.prepend(configToString(this->getBitmap().config()));
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001187
reed@android.com8a1c16f2008-12-17 15:59:43 +00001188 if (fAnimating) {
1189 title.prepend("<A> ");
1190 }
reed@android.com6c5f6f22009-08-14 16:08:38 +00001191 if (fScale) {
1192 title.prepend("<S> ");
1193 }
1194 if (fRotate) {
1195 title.prepend("<R> ");
1196 }
reed@android.come522ca52009-11-23 20:10:41 +00001197 if (fNClip) {
1198 title.prepend("<C> ");
1199 }
reed@google.comf0b5f682011-03-11 20:08:25 +00001200 if (LCDTextDrawFilter::kForceOn_Mode == fLCDMode) {
1201 title.prepend("LCD ");
1202 } else if (LCDTextDrawFilter::kForceOff_Mode == fLCDMode) {
1203 title.prepend("lcd ");
1204 }
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001205
1206 if (fZoomLevel) {
1207 title.prependf("{%d} ", fZoomLevel);
1208 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001209 this->setTitle(title.c_str());
1210}
1211
1212void SampleWindow::onSizeChange() {
1213 this->INHERITED::onSizeChange();
1214
1215 SkView::F2BIter iter(this);
1216 SkView* view = iter.next();
1217 view->setSize(this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001218
reed@android.com8a1c16f2008-12-17 15:59:43 +00001219 // rebuild our clippath
1220 {
1221 const SkScalar W = this->width();
1222 const SkScalar H = this->height();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001223
reed@android.com8a1c16f2008-12-17 15:59:43 +00001224 fClipPath.reset();
1225#if 0
1226 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
1227 SkRect r;
1228 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
1229 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
1230 fClipPath.addRect(r);
1231 }
1232#else
1233 SkRect r;
1234 r.set(0, 0, W, H);
1235 fClipPath.addRect(r, SkPath::kCCW_Direction);
1236 r.set(W/4, H/4, W*3/4, H*3/4);
1237 fClipPath.addRect(r, SkPath::kCW_Direction);
1238#endif
1239 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001240
reed@android.com8a1c16f2008-12-17 15:59:43 +00001241 this->updateTitle(); // to refresh our config
1242}
1243
1244///////////////////////////////////////////////////////////////////////////////
1245
reed@android.comf2b98d62010-12-20 18:26:13 +00001246template <typename T> void SkTBSort(T array[], int count) {
1247 for (int i = 1; i < count - 1; i++) {
1248 bool didSwap = false;
1249 for (int j = count - 1; j > i; --j) {
1250 if (array[j] < array[j-1]) {
1251 T tmp(array[j-1]);
1252 array[j-1] = array[j];
1253 array[j] = tmp;
1254 didSwap = true;
1255 }
1256 }
1257 if (!didSwap) {
1258 break;
1259 }
1260 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001261
reed@android.comf2b98d62010-12-20 18:26:13 +00001262 for (int k = 0; k < count - 1; k++) {
1263 SkASSERT(!(array[k+1] < array[k]));
1264 }
1265}
1266
1267#include "SkRandom.h"
1268
1269static void rand_rect(SkIRect* rect, SkRandom& rand) {
1270 int bits = 8;
1271 int shift = 32 - bits;
1272 rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
1273 rand.nextU() >> shift, rand.nextU() >> shift);
1274 rect->sort();
1275}
1276
1277static void dumpRect(const SkIRect& r) {
1278 SkDebugf(" { %d, %d, %d, %d },\n",
1279 r.fLeft, r.fTop,
1280 r.fRight, r.fBottom);
1281}
1282
1283static void test_rects(const SkIRect rect[], int count) {
1284 SkRegion rgn0, rgn1;
1285
1286 for (int i = 0; i < count; i++) {
1287 rgn0.op(rect[i], SkRegion::kUnion_Op);
1288 // dumpRect(rect[i]);
1289 }
1290 rgn1.setRects(rect, count);
1291
1292 if (rgn0 != rgn1) {
1293 SkDebugf("\n");
1294 for (int i = 0; i < count; i++) {
1295 dumpRect(rect[i]);
1296 }
1297 SkDebugf("\n");
1298 }
1299}
1300
1301static void test() {
1302 size_t i;
1303
1304 const SkIRect r0[] = {
1305 { 0, 0, 1, 1 },
1306 { 2, 2, 3, 3 },
1307 };
1308 const SkIRect r1[] = {
1309 { 0, 0, 1, 3 },
1310 { 1, 1, 2, 2 },
1311 { 2, 0, 3, 3 },
1312 };
1313 const SkIRect r2[] = {
1314 { 0, 0, 1, 2 },
1315 { 2, 1, 3, 3 },
1316 { 4, 0, 5, 1 },
1317 { 6, 0, 7, 4 },
1318 };
1319
1320 static const struct {
1321 const SkIRect* fRects;
1322 int fCount;
1323 } gRecs[] = {
1324 { r0, SK_ARRAY_COUNT(r0) },
1325 { r1, SK_ARRAY_COUNT(r1) },
1326 { r2, SK_ARRAY_COUNT(r2) },
1327 };
1328
1329 for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
1330 test_rects(gRecs[i].fRects, gRecs[i].fCount);
1331 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001332
reed@android.comf2b98d62010-12-20 18:26:13 +00001333 SkRandom rand;
1334 for (i = 0; i < 10000; i++) {
1335 SkRegion rgn0, rgn1;
1336
1337 const int N = 8;
1338 SkIRect rect[N];
1339 for (int j = 0; j < N; j++) {
1340 rand_rect(&rect[j], rand);
1341 }
1342 test_rects(rect, N);
1343 }
1344}
1345
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346SkOSWindow* create_sk_window(void* hwnd) {
reed@android.comf2b98d62010-12-20 18:26:13 +00001347// test();
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001348 return new SampleWindow(hwnd);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001349}
1350
1351void get_preferred_size(int* x, int* y, int* width, int* height) {
1352 *x = 10;
1353 *y = 50;
1354 *width = 640;
1355 *height = 480;
1356}
1357
1358void application_init() {
1359// setenv("ANDROID_ROOT", "../../../data", 0);
reed@android.come191b162009-12-18 21:33:39 +00001360#ifdef SK_BUILD_FOR_MAC
reed@android.com8a1c16f2008-12-17 15:59:43 +00001361 setenv("ANDROID_ROOT", "/android/device/data", 0);
reed@android.come191b162009-12-18 21:33:39 +00001362#endif
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001363 SkGraphics::Init();
1364 SkEvent::Init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001365}
1366
1367void application_term() {
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001368 SkEvent::Term();
1369 SkGraphics::Term();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001370}