blob: c71326bb7467cc5befb0a2d6f4a15b1e8cf272d9 [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 0
346 if (NULL != fGrContext) {
347 GrAssert(1 == fGrContext->refcnt());
348 fGrContext->unref();
349 fGrContext = NULL;
350 }
351#endif
bsalomon@google.com498a6232011-03-10 18:24:15 +0000352 if (NULL == fGrContext) {
353 #if defined(SK_USE_SHADERS)
354 fGrContext = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
355 #else
356 fGrContext = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, NULL);
357 #endif
358 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000359
bsalomon@google.com498a6232011-03-10 18:24:15 +0000360 if (NULL != fGrContext) {
361 return true;
362 } else {
363 detachGL();
364 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000365 }
366#endif
367 SkDebugf("Failed to setup 3D");
368 return false;
369}
370
reed@android.com8a1c16f2008-12-17 15:59:43 +0000371SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
372 static const CanvasType gCT[] = {
373 kPicture_CanvasType,
reed@android.comf2b98d62010-12-20 18:26:13 +0000374 kGPU_CanvasType,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375 kRaster_CanvasType
376 };
377 return gCT[ct];
378}
379
380SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381 fPicture = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000382 fGpuCanvas = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000384 fGrContext = NULL;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000385
reed@android.comf2b98d62010-12-20 18:26:13 +0000386#ifdef DEFAULT_TO_GPU
387 fCanvasType = kGPU_CanvasType;
388#else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000389 fCanvasType = kRaster_CanvasType;
reed@android.comf2b98d62010-12-20 18:26:13 +0000390#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000391 fUseClip = false;
reed@android.come522ca52009-11-23 20:10:41 +0000392 fNClip = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000393 fRepeatDrawing = false;
394 fAnimating = false;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000395 fRotate = false;
396 fScale = false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000397 fRequestGrabImage = false;
reed@google.comf0b5f682011-03-11 20:08:25 +0000398 fLCDMode = LCDTextDrawFilter::kNeutral_Mode;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000399 fScrollTestX = fScrollTestY = 0;
400
Scroggo0f185c22011-03-24 18:35:50 +0000401 fMouseX = fMouseY = 0;
402 fFatBitsScale = 1;
403 fTypeface = SkTypeface::CreateFromTypeface(NULL, SkTypeface::kBold);
404 fShowZoomer = false;
405
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000406 fZoomLevel = 0;
407 fZoomScale = SK_Scalar1;
408
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000409// this->setConfig(SkBitmap::kRGB_565_Config);
410 this->setConfig(SkBitmap::kARGB_8888_Config);
411 this->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000412 this->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000413
reed@android.com34245c72009-11-03 04:00:48 +0000414 {
415 const SkViewRegister* reg = SkViewRegister::Head();
416 while (reg) {
417 *fSamples.append() = reg->factory();
418 reg = reg->next();
419 }
420 }
421 fCurrIndex = 0;
reed@android.come0f13ee2009-11-04 19:40:25 +0000422 this->loadView(fSamples[fCurrIndex]());
reed@google.comf0b5f682011-03-11 20:08:25 +0000423
twiz@google.com06c3b6b2011-03-14 16:58:39 +0000424#ifdef SK_BUILD_FOR_MAC
reed@google.comf0b5f682011-03-11 20:08:25 +0000425 testpdf();
twiz@google.com06c3b6b2011-03-14 16:58:39 +0000426#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427}
428
429SampleWindow::~SampleWindow() {
430 delete fPicture;
reed@android.comf2b98d62010-12-20 18:26:13 +0000431 delete fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000432 if (NULL != fGrContext) {
433 fGrContext->unref();
434 }
Scroggo0f185c22011-03-24 18:35:50 +0000435 fTypeface->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000436}
437
reed@android.com55e76b22009-11-23 21:46:47 +0000438static SkBitmap capture_bitmap(SkCanvas* canvas) {
439 SkBitmap bm;
440 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
441 src.copyTo(&bm, src.config());
442 return bm;
443}
444
445static bool bitmap_diff(SkCanvas* canvas, const SkBitmap& orig,
446 SkBitmap* diff) {
447 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000448
reed@android.com55e76b22009-11-23 21:46:47 +0000449 SkAutoLockPixels alp0(src);
450 SkAutoLockPixels alp1(orig);
451 for (int y = 0; y < src.height(); y++) {
452 const void* srcP = src.getAddr(0, y);
453 const void* origP = orig.getAddr(0, y);
454 size_t bytes = src.width() * src.bytesPerPixel();
455 if (memcmp(srcP, origP, bytes)) {
456 SkDebugf("---------- difference on line %d\n", y);
457 return true;
458 }
459 }
460 return false;
461}
462
Scroggo0f185c22011-03-24 18:35:50 +0000463static void drawText(SkCanvas* canvas, SkString string, SkScalar left, SkScalar top, SkPaint& paint)
464{
465 SkColor desiredColor = paint.getColor();
466 paint.setColor(SK_ColorWHITE);
467 const char* c_str = string.c_str();
468 size_t size = string.size();
469 SkRect bounds;
470 paint.measureText(c_str, size, &bounds);
471 bounds.offset(left, top);
472 SkScalar inset = SkIntToScalar(-2);
473 bounds.inset(inset, inset);
474 canvas->drawRect(bounds, paint);
475 if (desiredColor != SK_ColorBLACK) {
476 paint.setColor(SK_ColorBLACK);
477 canvas->drawText(c_str, size, left + SK_Scalar1, top + SK_Scalar1, paint);
478 }
479 paint.setColor(desiredColor);
480 canvas->drawText(c_str, size, left, top, paint);
481}
482
reed@android.com44177402009-11-23 21:07:51 +0000483#define XCLIP_N 8
484#define YCLIP_N 8
reed@android.come522ca52009-11-23 20:10:41 +0000485
486void SampleWindow::draw(SkCanvas* canvas) {
reed@android.com44177402009-11-23 21:07:51 +0000487 // update the animation time
reed@android.comf2b98d62010-12-20 18:26:13 +0000488 gAnimTimePrev = gAnimTime;
reed@android.com44177402009-11-23 21:07:51 +0000489 gAnimTime = SkTime::GetMSecs();
490
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000491 if (fZoomLevel) {
492 SkMatrix m;
493 SkScalar cx = SkScalarHalf(this->width());
494 SkScalar cy = SkScalarHalf(this->height());
495 SkPoint center;
496 m = canvas->getTotalMatrix();//.invert(&m);
497 m.mapXY(cx, cy, &center);
498 cx = center.fX;
499 cy = center.fY;
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000500
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000501 m.setTranslate(-cx, -cy);
502 m.postScale(fZoomScale, fZoomScale);
503 m.postTranslate(cx, cy);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000504
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000505 canvas->concat(m);
506 }
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000507
reed@google.com52f57e12011-03-16 12:10:02 +0000508 // Apply any gesture matrix
509 if (true) {
510 const SkMatrix& localM = fGesture.localM();
511 if (localM.getType() & SkMatrix::kScale_Mask) {
512 canvas->setExternalMatrix(&localM);
513 }
514 canvas->concat(localM);
515 canvas->concat(fGesture.globalM());
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000516
reed@google.com52f57e12011-03-16 12:10:02 +0000517 if (fGesture.isActive()) {
518 this->inval(NULL);
519 }
520 }
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000521
reed@android.come522ca52009-11-23 20:10:41 +0000522 if (fNClip) {
reed@android.com55e76b22009-11-23 21:46:47 +0000523 this->INHERITED::draw(canvas);
524 SkBitmap orig = capture_bitmap(canvas);
reed@android.come522ca52009-11-23 20:10:41 +0000525
526 const SkScalar w = this->width();
527 const SkScalar h = this->height();
528 const SkScalar cw = w / XCLIP_N;
529 const SkScalar ch = h / YCLIP_N;
530 for (int y = 0; y < YCLIP_N; y++) {
reed@android.com55e76b22009-11-23 21:46:47 +0000531 SkRect r;
532 r.fTop = y * ch;
533 r.fBottom = (y + 1) * ch;
534 if (y == YCLIP_N - 1) {
535 r.fBottom = h;
536 }
reed@android.come522ca52009-11-23 20:10:41 +0000537 for (int x = 0; x < XCLIP_N; x++) {
538 SkAutoCanvasRestore acr(canvas, true);
reed@android.com55e76b22009-11-23 21:46:47 +0000539 r.fLeft = x * cw;
540 r.fRight = (x + 1) * cw;
541 if (x == XCLIP_N - 1) {
542 r.fRight = w;
543 }
reed@android.come522ca52009-11-23 20:10:41 +0000544 canvas->clipRect(r);
545 this->INHERITED::draw(canvas);
546 }
547 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000548
reed@android.com55e76b22009-11-23 21:46:47 +0000549 SkBitmap diff;
550 if (bitmap_diff(canvas, orig, &diff)) {
551 }
reed@android.come522ca52009-11-23 20:10:41 +0000552 } else {
553 this->INHERITED::draw(canvas);
554 }
Scroggo0f185c22011-03-24 18:35:50 +0000555 if (fShowZoomer) {
556 int count = canvas->save();
557 canvas->resetMatrix();
558 // Ensure the mouse position is on screen.
559 int width = this->width();
560 int height = this->height();
561 if (fMouseX >= width) fMouseX = width - 1;
562 else if (fMouseX < 0) fMouseX = 0;
563 if (fMouseY >= height) fMouseY = height - 1;
564 else if (fMouseY < 0) fMouseY = 0;
565 SkBitmap bitmap = capture_bitmap(canvas);
566 // Find the size of the zoomed in view, forced to be odd, so the examined pixel is in the middle.
567 int zoomedWidth = (width >> 2) | 1;
568 int zoomedHeight = (height >> 2) | 1;
569 SkIRect src;
570 src.set(0, 0, zoomedWidth / fFatBitsScale, zoomedHeight / fFatBitsScale);
571 src.offset(fMouseX - (src.width()>>1), fMouseY - (src.height()>>1));
572 SkRect dest;
573 dest.set(0, 0, SkIntToScalar(zoomedWidth), SkIntToScalar(zoomedHeight));
574 dest.offset(SkIntToScalar(width - zoomedWidth), SkIntToScalar(height - zoomedHeight));
575 SkPaint paint;
576 // Clear the background behind our zoomed in view
577 paint.setColor(SK_ColorWHITE);
578 canvas->drawRect(dest, paint);
579 canvas->drawBitmapRect(bitmap, &src, dest);
580 paint.setColor(SK_ColorBLACK);
581 paint.setStyle(SkPaint::kStroke_Style);
582 // Draw a border around the pixel in the middle
583 SkRect originalPixel;
584 originalPixel.set(SkIntToScalar(fMouseX), SkIntToScalar(fMouseY), SkIntToScalar(fMouseX + 1), SkIntToScalar(fMouseY + 1));
585 SkMatrix matrix;
586 SkRect scalarSrc;
587 scalarSrc.set(src);
588 SkColor color = bitmap.getColor(fMouseX, fMouseY);
589 if (matrix.setRectToRect(scalarSrc, dest, SkMatrix::kFill_ScaleToFit)) {
590 SkRect pixel;
591 matrix.mapRect(&pixel, originalPixel);
592 // TODO Perhaps measure the values and make the outline white if it's "dark"
593 if (color == SK_ColorBLACK) {
594 paint.setColor(SK_ColorWHITE);
595 }
596 canvas->drawRect(pixel, paint);
597 }
598 paint.setColor(SK_ColorBLACK);
599 // Draw a border around the destination rectangle
600 canvas->drawRect(dest, paint);
601 paint.setStyle(SkPaint::kStrokeAndFill_Style);
602 // Identify the pixel and its color on screen
603 paint.setTypeface(fTypeface);
604 paint.setAntiAlias(true);
605 SkScalar lineHeight = paint.getFontMetrics(NULL);
606 SkString string;
607 string.appendf("(%i, %i)", fMouseX, fMouseY);
608 SkScalar left = dest.fLeft + SkIntToScalar(3);
609 SkScalar i = SK_Scalar1;
610 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
611 // Alpha
612 i += SK_Scalar1;
613 string.reset();
614 string.appendf("A: %X", SkColorGetA(color));
615 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
616 // Red
617 i += SK_Scalar1;
618 string.reset();
619 string.appendf("R: %X", SkColorGetR(color));
620 paint.setColor(SK_ColorRED);
621 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
622 // Green
623 i += SK_Scalar1;
624 string.reset();
625 string.appendf("G: %X", SkColorGetG(color));
626 paint.setColor(SK_ColorGREEN);
627 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
628 // Blue
629 i += SK_Scalar1;
630 string.reset();
631 string.appendf("B: %X", SkColorGetB(color));
632 paint.setColor(SK_ColorBLUE);
633 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
634 canvas->restoreToCount(count);
635 }
reed@android.come522ca52009-11-23 20:10:41 +0000636}
637
reed@android.com8a1c16f2008-12-17 15:59:43 +0000638void SampleWindow::onDraw(SkCanvas* canvas) {
639 if (fRepeatDrawing) {
640 this->inval(NULL);
641 }
642}
643
644#include "SkColorPriv.h"
645
646static void reverseRedAndBlue(const SkBitmap& bm) {
647 SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
648 uint8_t* p = (uint8_t*)bm.getPixels();
649 uint8_t* stop = p + bm.getSize();
650 while (p < stop) {
651 // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
652 unsigned scale = SkAlpha255To256(p[3]);
653 unsigned r = p[2];
654 unsigned b = p[0];
655 p[0] = SkAlphaMul(r, scale);
656 p[1] = SkAlphaMul(p[1], scale);
657 p[2] = SkAlphaMul(b, scale);
658 p += 4;
659 }
660}
661
662SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000663 SkIPoint viewport;
664 bool alreadyGPU = canvas->getViewport(&viewport);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000665
reed@android.comf2b98d62010-12-20 18:26:13 +0000666 if (kGPU_CanvasType != fCanvasType) {
reed@android.com6efdc472008-12-19 18:24:35 +0000667#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000668 detachGL();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000669#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000670 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000671
reed@android.com8a1c16f2008-12-17 15:59:43 +0000672 switch (fCanvasType) {
673 case kRaster_CanvasType:
674 canvas = this->INHERITED::beforeChildren(canvas);
675 break;
676 case kPicture_CanvasType:
677 fPicture = new SkPicture;
678 canvas = fPicture->beginRecording(9999, 9999);
679 break;
reed@google.comac10a2d2010-12-22 21:39:39 +0000680 case kGPU_CanvasType: {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000681 if (!alreadyGPU && make3DReady()) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000682 SkDevice* device = canvas->getDevice();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000683 const SkBitmap& bitmap = device->accessBitmap(true);
684
bsalomon@google.com5782d712011-01-21 21:03:59 +0000685 GrRenderTarget* renderTarget;
686 renderTarget = fGrContext->createRenderTargetFrom3DApiState();
687 fGpuCanvas = new SkGpuCanvas(fGrContext, renderTarget);
688 renderTarget->unref();
689
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000690 device = fGpuCanvas->createDevice(SkBitmap::kARGB_8888_Config,
691 bitmap.width(), bitmap.height(),
692 false, false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000693 fGpuCanvas->setDevice(device)->unref();
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000694
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000695 fGpuCanvas->concat(canvas->getTotalMatrix());
reed@android.comf2b98d62010-12-20 18:26:13 +0000696 canvas = fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000697
reed@android.comf2b98d62010-12-20 18:26:13 +0000698 } else {
699 canvas = this->INHERITED::beforeChildren(canvas);
700 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000701 break;
reed@google.comac10a2d2010-12-22 21:39:39 +0000702 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000703 }
704
705 if (fUseClip) {
706 canvas->drawColor(0xFFFF88FF);
707 canvas->clipPath(fClipPath);
708 }
709
710 return canvas;
711}
712
713static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
714 const SkRegion& rgn) {
715 SkCanvas canvas(bm);
716 SkRegion inval(rgn);
717
718 inval.translate(r.fLeft, r.fTop);
719 canvas.clipRegion(inval);
720 canvas.drawColor(0xFFFF8080);
721}
722
723void SampleWindow::afterChildren(SkCanvas* orig) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000724 if (fRequestGrabImage) {
725 fRequestGrabImage = false;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000726
reed@android.comf2b98d62010-12-20 18:26:13 +0000727 SkCanvas* canvas = fGpuCanvas ? fGpuCanvas : orig;
728 SkDevice* device = canvas->getDevice();
729 SkBitmap bitmap;
reed@google.com5ba2d5b2011-03-10 19:40:34 +0000730 SkIRect bounds = {
731 0, 0,
732 SkScalarRound(this->width()),
733 SkScalarRound(this->height())
734 };
reed@android.comf2b98d62010-12-20 18:26:13 +0000735 if (device->readPixels(bounds, &bitmap)) {
736 static int gSampleGrabCounter;
737 SkString name;
738 name.printf("sample_grab_%d", gSampleGrabCounter++);
739 SkImageEncoder::EncodeFile(name.c_str(), bitmap,
740 SkImageEncoder::kPNG_Type, 100);
741 }
742 }
743
reed@android.com8a1c16f2008-12-17 15:59:43 +0000744 switch (fCanvasType) {
745 case kRaster_CanvasType:
746 break;
747 case kPicture_CanvasType:
reed@android.comaefd2bc2009-03-30 21:02:14 +0000748 if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000749 SkPicture* pict = new SkPicture(*fPicture);
750 fPicture->unref();
751 orig->drawPicture(*pict);
752 pict->unref();
reed@android.comaefd2bc2009-03-30 21:02:14 +0000753 } else if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000754 SkDynamicMemoryWStream ostream;
755 fPicture->serialize(&ostream);
756 fPicture->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000757
reed@android.com8a1c16f2008-12-17 15:59:43 +0000758 SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
759 SkPicture pict(&istream);
760 orig->drawPicture(pict);
761 } else {
762 fPicture->draw(orig);
763 fPicture->unref();
764 }
765 fPicture = NULL;
766 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000767#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000768 case kGPU_CanvasType:
769 delete fGpuCanvas;
770 fGpuCanvas = NULL;
771 presentGL();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000772 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000773#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000774 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000775
reed@android.com8a1c16f2008-12-17 15:59:43 +0000776// if ((fScrollTestX | fScrollTestY) != 0)
reed@android.comf2b98d62010-12-20 18:26:13 +0000777 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000778 const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
779 int dx = fScrollTestX * 7;
780 int dy = fScrollTestY * 7;
781 SkIRect r;
782 SkRegion inval;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000783
reed@android.com8a1c16f2008-12-17 15:59:43 +0000784 r.set(50, 50, 50+100, 50+100);
785 bm.scrollRect(&r, dx, dy, &inval);
786 paint_rgn(bm, r, inval);
787 }
788}
789
reed@android.com6c5f6f22009-08-14 16:08:38 +0000790void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
791 if (fScale) {
792 SkScalar scale = SK_Scalar1 * 7 / 10;
793 SkScalar cx = this->width() / 2;
794 SkScalar cy = this->height() / 2;
795 canvas->translate(cx, cy);
796 canvas->scale(scale, scale);
797 canvas->translate(-cx, -cy);
798 }
799 if (fRotate) {
800 SkScalar cx = this->width() / 2;
801 SkScalar cy = this->height() / 2;
802 canvas->translate(cx, cy);
803 canvas->rotate(SkIntToScalar(30));
804 canvas->translate(-cx, -cy);
805 }
reed@google.comf0b5f682011-03-11 20:08:25 +0000806
807 if (LCDTextDrawFilter::kNeutral_Mode != fLCDMode) {
808 canvas->setDrawFilter(new LCDTextDrawFilter(fLCDMode))->unref();
809 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000810}
811
812void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) {
reed@google.comf0b5f682011-03-11 20:08:25 +0000813 canvas->setDrawFilter(NULL);
reed@android.com6c5f6f22009-08-14 16:08:38 +0000814}
815
reed@android.com8a1c16f2008-12-17 15:59:43 +0000816static SkBitmap::Config gConfigCycle[] = {
817 SkBitmap::kNo_Config, // none -> none
818 SkBitmap::kNo_Config, // a1 -> none
819 SkBitmap::kNo_Config, // a8 -> none
820 SkBitmap::kNo_Config, // index8 -> none
821 SkBitmap::kARGB_4444_Config, // 565 -> 4444
822 SkBitmap::kARGB_8888_Config, // 4444 -> 8888
823 SkBitmap::kRGB_565_Config // 8888 -> 565
824};
825
826static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
827 return gConfigCycle[c];
828}
829
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000830void SampleWindow::changeZoomLevel(int delta) {
831 fZoomLevel += delta;
832 if (fZoomLevel > 0) {
833 fZoomLevel = SkMin32(fZoomLevel, MAX_ZOOM_LEVEL);
834 fZoomScale = SkIntToScalar(fZoomLevel + 1);
835 } else if (fZoomLevel < 0) {
836 fZoomLevel = SkMax32(fZoomLevel, MIN_ZOOM_LEVEL);
837 fZoomScale = SK_Scalar1 / (1 - fZoomLevel);
838 } else {
839 fZoomScale = SK_Scalar1;
840 }
841
842 this->inval(NULL);
843}
844
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845bool SampleWindow::nextSample() {
reed@android.com34245c72009-11-03 04:00:48 +0000846 fCurrIndex = (fCurrIndex + 1) % fSamples.count();
847 this->loadView(fSamples[fCurrIndex]());
848 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000849}
850
851bool SampleWindow::onEvent(const SkEvent& evt) {
852 if (evt.isType(ANIMATING_EVENTTYPE)) {
853 if (fAnimating) {
854 this->nextSample();
855 this->postAnimatingEvent();
856 }
857 return true;
858 }
reed@android.com34245c72009-11-03 04:00:48 +0000859 if (evt.isType("set-curr-index")) {
860 fCurrIndex = evt.getFast32() % fSamples.count();
861 this->loadView(fSamples[fCurrIndex]());
862 return true;
863 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000864 return this->INHERITED::onEvent(evt);
865}
866
reed@android.comf2b98d62010-12-20 18:26:13 +0000867bool SampleWindow::onQuery(SkEvent* query) {
868 if (query->isType("get-slide-count")) {
869 query->setFast32(fSamples.count());
870 return true;
871 }
872 if (query->isType("get-slide-title")) {
873 SkView* view = fSamples[query->getFast32()]();
874 SkEvent evt(gTitleEvtName);
875 if (view->doQuery(&evt)) {
876 query->setString("title", evt.findString(gTitleEvtName));
877 }
878 SkSafeUnref(view);
879 return true;
880 }
881 if (query->isType("use-fast-text")) {
882 SkEvent evt(gFastTextEvtName);
883 return curr_view(this)->doQuery(&evt);
884 }
885 return this->INHERITED::onQuery(query);
886}
887
reed@android.com0ae6b242008-12-23 16:49:54 +0000888static void cleanup_for_filename(SkString* name) {
889 char* str = name->writable_str();
reed@android.come191b162009-12-18 21:33:39 +0000890 for (size_t i = 0; i < name->size(); i++) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000891 switch (str[i]) {
892 case ':': str[i] = '-'; break;
893 case '/': str[i] = '-'; break;
894 case ' ': str[i] = '_'; break;
895 default: break;
896 }
897 }
898}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000899
900bool SampleWindow::onHandleChar(SkUnichar uni) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000901 {
902 SkView* view = curr_view(this);
903 if (view) {
904 SkEvent evt(gCharEvtName);
905 evt.setFast32(uni);
906 if (view->doQuery(&evt)) {
907 return true;
908 }
909 }
910 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000911
reed@android.com8a1c16f2008-12-17 15:59:43 +0000912 int dx = 0xFF;
913 int dy = 0xFF;
914
915 switch (uni) {
916 case '5': dx = 0; dy = 0; break;
917 case '8': dx = 0; dy = -1; break;
918 case '6': dx = 1; dy = 0; break;
919 case '2': dx = 0; dy = 1; break;
920 case '4': dx = -1; dy = 0; break;
921 case '7': dx = -1; dy = -1; break;
922 case '9': dx = 1; dy = -1; break;
923 case '3': dx = 1; dy = 1; break;
924 case '1': dx = -1; dy = 1; break;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000925
reed@android.com8a1c16f2008-12-17 15:59:43 +0000926 default:
927 break;
928 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000929
reed@android.com8a1c16f2008-12-17 15:59:43 +0000930 if (0xFF != dx && 0xFF != dy) {
931 if ((dx | dy) == 0) {
932 fScrollTestX = fScrollTestY = 0;
933 } else {
934 fScrollTestX += dx;
935 fScrollTestY += dy;
936 }
937 this->inval(NULL);
938 return true;
939 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000940
reed@android.com0ae6b242008-12-23 16:49:54 +0000941 switch (uni) {
942 case 'a':
943 fAnimating = !fAnimating;
944 this->postAnimatingEvent();
945 this->updateTitle();
946 return true;
947 case 'f': {
948 const char* title = this->getTitle();
949 if (title[0] == 0) {
950 title = "sampleapp";
951 }
952 SkString name(title);
953 cleanup_for_filename(&name);
954 name.append(".png");
955 if (SkImageEncoder::EncodeFile(name.c_str(), this->getBitmap(),
reed@android.comb08eb2b2009-01-06 20:16:26 +0000956 SkImageEncoder::kPNG_Type, 100)) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000957 SkDebugf("Created %s\n", name.c_str());
958 }
959 return true;
960 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000961 case 'r':
962 fRotate = !fRotate;
963 this->inval(NULL);
964 this->updateTitle();
965 return true;
966 case 's':
967 fScale = !fScale;
968 this->inval(NULL);
969 this->updateTitle();
970 return true;
reed@google.comfb56a9e2011-02-10 18:47:24 +0000971 case 'c':
972 fUseClip = !fUseClip;
973 this->inval(NULL);
974 this->updateTitle();
975 return true;
reed@android.comf2b98d62010-12-20 18:26:13 +0000976 case 'd':
977 SkGraphics::SetFontCacheUsed(0);
978 return true;
979 case 'g':
980 fRequestGrabImage = true;
981 this->inval(NULL);
982 break;
reed@google.comf0b5f682011-03-11 20:08:25 +0000983 case 'l':
984 fLCDMode = cycle_lcdmode(fLCDMode);
985 this->updateTitle();
986 this->inval(NULL);
987 break;
scroggo08526c02011-03-22 14:03:21 +0000988 case 'i':
989 this->zoomIn();
990 break;
991 case 'o':
992 this->zoomOut();
993 break;
994 case 'z':
995 this->toggleZoomer();
996 break;
reed@android.com0ae6b242008-12-23 16:49:54 +0000997 default:
998 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000999 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001000
reed@android.com8a1c16f2008-12-17 15:59:43 +00001001 return this->INHERITED::onHandleChar(uni);
1002}
1003
1004#include "SkDumpCanvas.h"
1005
1006bool SampleWindow::onHandleKey(SkKey key) {
reed@android.comf2b98d62010-12-20 18:26:13 +00001007 {
1008 SkView* view = curr_view(this);
1009 if (view) {
1010 SkEvent evt(gKeyEvtName);
1011 evt.setFast32(key);
1012 if (view->doQuery(&evt)) {
1013 return true;
1014 }
1015 }
1016 }
1017
reed@android.com8a1c16f2008-12-17 15:59:43 +00001018 switch (key) {
1019 case kRight_SkKey:
1020 if (this->nextSample()) {
1021 return true;
1022 }
1023 break;
1024 case kLeft_SkKey:
1025 fCanvasType = cycle_canvastype(fCanvasType);
1026 this->updateTitle();
1027 this->inval(NULL);
1028 return true;
1029 case kUp_SkKey:
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001030 if (USE_ARROWS_FOR_ZOOM) {
1031 this->changeZoomLevel(1);
1032 } else {
1033 fNClip = !fNClip;
1034 this->inval(NULL);
1035 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001036 this->updateTitle();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001037 return true;
1038 case kDown_SkKey:
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001039 if (USE_ARROWS_FOR_ZOOM) {
1040 this->changeZoomLevel(-1);
1041 } else {
1042 this->setConfig(cycle_configs(this->getBitmap().config()));
1043 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001044 this->updateTitle();
1045 return true;
1046 case kOK_SkKey:
reed@android.comf2b98d62010-12-20 18:26:13 +00001047 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001048 SkDebugfDumper dumper;
1049 SkDumpCanvas dc(&dumper);
1050 this->draw(&dc);
1051 } else {
1052 fRepeatDrawing = !fRepeatDrawing;
1053 if (fRepeatDrawing) {
1054 this->inval(NULL);
1055 }
1056 }
1057 return true;
reed@android.com34245c72009-11-03 04:00:48 +00001058 case kBack_SkKey:
1059 this->loadView(NULL);
1060 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001061 default:
1062 break;
1063 }
1064 return this->INHERITED::onHandleKey(key);
1065}
1066
reed@google.com52f57e12011-03-16 12:10:02 +00001067///////////////////////////////////////////////////////////////////////////////
1068
1069static const char gGestureClickType[] = "GestureClickType";
1070
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001071bool SampleWindow::onDispatchClick(int x, int y, Click::State state) {
Scroggo0f185c22011-03-24 18:35:50 +00001072 if (Click::kMoved_State == state) {
1073 updatePointer(x, y);
1074 }
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001075 int w = SkScalarRound(this->width());
1076 int h = SkScalarRound(this->height());
1077
1078 // check for the resize-box
1079 if (w - x < 16 && h - y < 16) {
1080 return false; // let the OS handle the click
1081 } else {
1082 return this->INHERITED::onDispatchClick(x, y, state);
1083 }
1084}
1085
reed@google.com52f57e12011-03-16 12:10:02 +00001086class GestureClick : public SkView::Click {
1087public:
1088 GestureClick(SkView* target) : SkView::Click(target) {
1089 this->setType(gGestureClickType);
1090 }
1091
1092 static bool IsGesture(Click* click) {
1093 return click->isType(gGestureClickType);
1094 }
1095};
1096
1097SkView::Click* SampleWindow::onFindClickHandler(SkScalar x, SkScalar y) {
1098 return new GestureClick(this);
1099}
1100
1101bool SampleWindow::onClick(Click* click) {
1102 if (GestureClick::IsGesture(click)) {
1103 float x = SkScalarToFloat(click->fCurr.fX);
1104 float y = SkScalarToFloat(click->fCurr.fY);
1105 switch (click->fState) {
1106 case SkView::Click::kDown_State:
1107 fGesture.touchBegin(click, x, y);
1108 break;
1109 case SkView::Click::kMoved_State:
1110 fGesture.touchMoved(click, x, y);
1111 this->inval(NULL);
1112 break;
1113 case SkView::Click::kUp_State:
1114 fGesture.touchEnd(click);
1115 this->inval(NULL);
1116 break;
1117 }
1118 return true;
1119 }
1120 return false;
1121}
1122
1123///////////////////////////////////////////////////////////////////////////////
1124
reed@android.com8a1c16f2008-12-17 15:59:43 +00001125void SampleWindow::loadView(SkView* view) {
1126 SkView::F2BIter iter(this);
1127 SkView* prev = iter.next();
1128 if (prev) {
1129 prev->detachFromParent();
1130 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001131
reed@android.com34245c72009-11-03 04:00:48 +00001132 if (NULL == view) {
1133 view = create_overview(fSamples.count(), fSamples.begin());
1134 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001135 view->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +00001136 view->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001137 this->attachChildToFront(view)->unref();
1138 view->setSize(this->width(), this->height());
1139
1140 this->updateTitle();
1141}
1142
1143static const char* gConfigNames[] = {
1144 "unknown config",
1145 "A1",
1146 "A8",
1147 "Index8",
1148 "565",
1149 "4444",
1150 "8888"
1151};
1152
1153static const char* configToString(SkBitmap::Config c) {
1154 return gConfigNames[c];
1155}
1156
1157static const char* gCanvasTypePrefix[] = {
1158 "raster: ",
1159 "picture: ",
1160 "opengl: "
1161};
1162
1163void SampleWindow::updateTitle() {
1164 SkString title;
1165
1166 SkView::F2BIter iter(this);
1167 SkView* view = iter.next();
1168 SkEvent evt(gTitleEvtName);
1169 if (view->doQuery(&evt)) {
1170 title.set(evt.findString(gTitleEvtName));
1171 }
1172 if (title.size() == 0) {
1173 title.set("<unknown>");
1174 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001175
reed@android.com8a1c16f2008-12-17 15:59:43 +00001176 title.prepend(gCanvasTypePrefix[fCanvasType]);
1177
1178 title.prepend(" ");
1179 title.prepend(configToString(this->getBitmap().config()));
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001180
reed@android.com8a1c16f2008-12-17 15:59:43 +00001181 if (fAnimating) {
1182 title.prepend("<A> ");
1183 }
reed@android.com6c5f6f22009-08-14 16:08:38 +00001184 if (fScale) {
1185 title.prepend("<S> ");
1186 }
1187 if (fRotate) {
1188 title.prepend("<R> ");
1189 }
reed@android.come522ca52009-11-23 20:10:41 +00001190 if (fNClip) {
1191 title.prepend("<C> ");
1192 }
reed@google.comf0b5f682011-03-11 20:08:25 +00001193 if (LCDTextDrawFilter::kForceOn_Mode == fLCDMode) {
1194 title.prepend("LCD ");
1195 } else if (LCDTextDrawFilter::kForceOff_Mode == fLCDMode) {
1196 title.prepend("lcd ");
1197 }
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001198
1199 if (fZoomLevel) {
1200 title.prependf("{%d} ", fZoomLevel);
1201 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001202 this->setTitle(title.c_str());
1203}
1204
1205void SampleWindow::onSizeChange() {
1206 this->INHERITED::onSizeChange();
1207
1208 SkView::F2BIter iter(this);
1209 SkView* view = iter.next();
1210 view->setSize(this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001211
reed@android.com8a1c16f2008-12-17 15:59:43 +00001212 // rebuild our clippath
1213 {
1214 const SkScalar W = this->width();
1215 const SkScalar H = this->height();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001216
reed@android.com8a1c16f2008-12-17 15:59:43 +00001217 fClipPath.reset();
1218#if 0
1219 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
1220 SkRect r;
1221 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
1222 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
1223 fClipPath.addRect(r);
1224 }
1225#else
1226 SkRect r;
1227 r.set(0, 0, W, H);
1228 fClipPath.addRect(r, SkPath::kCCW_Direction);
1229 r.set(W/4, H/4, W*3/4, H*3/4);
1230 fClipPath.addRect(r, SkPath::kCW_Direction);
1231#endif
1232 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001233
reed@android.com8a1c16f2008-12-17 15:59:43 +00001234 this->updateTitle(); // to refresh our config
1235}
1236
1237///////////////////////////////////////////////////////////////////////////////
1238
reed@android.comf2b98d62010-12-20 18:26:13 +00001239template <typename T> void SkTBSort(T array[], int count) {
1240 for (int i = 1; i < count - 1; i++) {
1241 bool didSwap = false;
1242 for (int j = count - 1; j > i; --j) {
1243 if (array[j] < array[j-1]) {
1244 T tmp(array[j-1]);
1245 array[j-1] = array[j];
1246 array[j] = tmp;
1247 didSwap = true;
1248 }
1249 }
1250 if (!didSwap) {
1251 break;
1252 }
1253 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001254
reed@android.comf2b98d62010-12-20 18:26:13 +00001255 for (int k = 0; k < count - 1; k++) {
1256 SkASSERT(!(array[k+1] < array[k]));
1257 }
1258}
1259
1260#include "SkRandom.h"
1261
1262static void rand_rect(SkIRect* rect, SkRandom& rand) {
1263 int bits = 8;
1264 int shift = 32 - bits;
1265 rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
1266 rand.nextU() >> shift, rand.nextU() >> shift);
1267 rect->sort();
1268}
1269
1270static void dumpRect(const SkIRect& r) {
1271 SkDebugf(" { %d, %d, %d, %d },\n",
1272 r.fLeft, r.fTop,
1273 r.fRight, r.fBottom);
1274}
1275
1276static void test_rects(const SkIRect rect[], int count) {
1277 SkRegion rgn0, rgn1;
1278
1279 for (int i = 0; i < count; i++) {
1280 rgn0.op(rect[i], SkRegion::kUnion_Op);
1281 // dumpRect(rect[i]);
1282 }
1283 rgn1.setRects(rect, count);
1284
1285 if (rgn0 != rgn1) {
1286 SkDebugf("\n");
1287 for (int i = 0; i < count; i++) {
1288 dumpRect(rect[i]);
1289 }
1290 SkDebugf("\n");
1291 }
1292}
1293
1294static void test() {
1295 size_t i;
1296
1297 const SkIRect r0[] = {
1298 { 0, 0, 1, 1 },
1299 { 2, 2, 3, 3 },
1300 };
1301 const SkIRect r1[] = {
1302 { 0, 0, 1, 3 },
1303 { 1, 1, 2, 2 },
1304 { 2, 0, 3, 3 },
1305 };
1306 const SkIRect r2[] = {
1307 { 0, 0, 1, 2 },
1308 { 2, 1, 3, 3 },
1309 { 4, 0, 5, 1 },
1310 { 6, 0, 7, 4 },
1311 };
1312
1313 static const struct {
1314 const SkIRect* fRects;
1315 int fCount;
1316 } gRecs[] = {
1317 { r0, SK_ARRAY_COUNT(r0) },
1318 { r1, SK_ARRAY_COUNT(r1) },
1319 { r2, SK_ARRAY_COUNT(r2) },
1320 };
1321
1322 for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
1323 test_rects(gRecs[i].fRects, gRecs[i].fCount);
1324 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001325
reed@android.comf2b98d62010-12-20 18:26:13 +00001326 SkRandom rand;
1327 for (i = 0; i < 10000; i++) {
1328 SkRegion rgn0, rgn1;
1329
1330 const int N = 8;
1331 SkIRect rect[N];
1332 for (int j = 0; j < N; j++) {
1333 rand_rect(&rect[j], rand);
1334 }
1335 test_rects(rect, N);
1336 }
1337}
1338
reed@android.com8a1c16f2008-12-17 15:59:43 +00001339SkOSWindow* create_sk_window(void* hwnd) {
reed@android.comf2b98d62010-12-20 18:26:13 +00001340// test();
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001341 return new SampleWindow(hwnd);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001342}
1343
1344void get_preferred_size(int* x, int* y, int* width, int* height) {
1345 *x = 10;
1346 *y = 50;
1347 *width = 640;
1348 *height = 480;
1349}
1350
1351void application_init() {
1352// setenv("ANDROID_ROOT", "../../../data", 0);
reed@android.come191b162009-12-18 21:33:39 +00001353#ifdef SK_BUILD_FOR_MAC
reed@android.com8a1c16f2008-12-17 15:59:43 +00001354 setenv("ANDROID_ROOT", "/android/device/data", 0);
reed@android.come191b162009-12-18 21:33:39 +00001355#endif
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001356 SkGraphics::Init();
1357 SkEvent::Init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001358}
1359
1360void application_term() {
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001361 SkEvent::Term();
1362 SkGraphics::Term();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001363}