blob: 0cc85fef01f9e5f14305bd511e18fb50a1739c24 [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()) {
345 if (NULL == fGrContext) {
346 #if defined(SK_USE_SHADERS)
347 fGrContext = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
348 #else
349 fGrContext = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, NULL);
350 #endif
351 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000352
bsalomon@google.com498a6232011-03-10 18:24:15 +0000353 if (NULL != fGrContext) {
354 return true;
355 } else {
356 detachGL();
357 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000358 }
359#endif
360 SkDebugf("Failed to setup 3D");
361 return false;
362}
363
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
365 static const CanvasType gCT[] = {
366 kPicture_CanvasType,
reed@android.comf2b98d62010-12-20 18:26:13 +0000367 kGPU_CanvasType,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368 kRaster_CanvasType
369 };
370 return gCT[ct];
371}
372
373SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374 fPicture = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000375 fGpuCanvas = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000376
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000377 fGrContext = NULL;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000378
reed@android.comf2b98d62010-12-20 18:26:13 +0000379#ifdef DEFAULT_TO_GPU
380 fCanvasType = kGPU_CanvasType;
381#else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000382 fCanvasType = kRaster_CanvasType;
reed@android.comf2b98d62010-12-20 18:26:13 +0000383#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384 fUseClip = false;
reed@android.come522ca52009-11-23 20:10:41 +0000385 fNClip = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000386 fRepeatDrawing = false;
387 fAnimating = false;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000388 fRotate = false;
389 fScale = false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000390 fRequestGrabImage = false;
reed@google.comf0b5f682011-03-11 20:08:25 +0000391 fLCDMode = LCDTextDrawFilter::kNeutral_Mode;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000392 fScrollTestX = fScrollTestY = 0;
393
Scroggo0f185c22011-03-24 18:35:50 +0000394 fMouseX = fMouseY = 0;
395 fFatBitsScale = 1;
396 fTypeface = SkTypeface::CreateFromTypeface(NULL, SkTypeface::kBold);
397 fShowZoomer = false;
398
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000399 fZoomLevel = 0;
400 fZoomScale = SK_Scalar1;
401
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000402// this->setConfig(SkBitmap::kRGB_565_Config);
403 this->setConfig(SkBitmap::kARGB_8888_Config);
404 this->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000405 this->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000406
reed@android.com34245c72009-11-03 04:00:48 +0000407 {
408 const SkViewRegister* reg = SkViewRegister::Head();
409 while (reg) {
410 *fSamples.append() = reg->factory();
411 reg = reg->next();
412 }
413 }
414 fCurrIndex = 0;
reed@android.come0f13ee2009-11-04 19:40:25 +0000415 this->loadView(fSamples[fCurrIndex]());
reed@google.comf0b5f682011-03-11 20:08:25 +0000416
twiz@google.com06c3b6b2011-03-14 16:58:39 +0000417#ifdef SK_BUILD_FOR_MAC
reed@google.comf0b5f682011-03-11 20:08:25 +0000418 testpdf();
twiz@google.com06c3b6b2011-03-14 16:58:39 +0000419#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000420}
421
422SampleWindow::~SampleWindow() {
423 delete fPicture;
reed@android.comf2b98d62010-12-20 18:26:13 +0000424 delete fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000425 if (NULL != fGrContext) {
426 fGrContext->unref();
427 }
Scroggo0f185c22011-03-24 18:35:50 +0000428 fTypeface->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429}
430
reed@android.com55e76b22009-11-23 21:46:47 +0000431static SkBitmap capture_bitmap(SkCanvas* canvas) {
432 SkBitmap bm;
433 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
434 src.copyTo(&bm, src.config());
435 return bm;
436}
437
438static bool bitmap_diff(SkCanvas* canvas, const SkBitmap& orig,
439 SkBitmap* diff) {
440 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000441
reed@android.com55e76b22009-11-23 21:46:47 +0000442 SkAutoLockPixels alp0(src);
443 SkAutoLockPixels alp1(orig);
444 for (int y = 0; y < src.height(); y++) {
445 const void* srcP = src.getAddr(0, y);
446 const void* origP = orig.getAddr(0, y);
447 size_t bytes = src.width() * src.bytesPerPixel();
448 if (memcmp(srcP, origP, bytes)) {
449 SkDebugf("---------- difference on line %d\n", y);
450 return true;
451 }
452 }
453 return false;
454}
455
Scroggo0f185c22011-03-24 18:35:50 +0000456static void drawText(SkCanvas* canvas, SkString string, SkScalar left, SkScalar top, SkPaint& paint)
457{
458 SkColor desiredColor = paint.getColor();
459 paint.setColor(SK_ColorWHITE);
460 const char* c_str = string.c_str();
461 size_t size = string.size();
462 SkRect bounds;
463 paint.measureText(c_str, size, &bounds);
464 bounds.offset(left, top);
465 SkScalar inset = SkIntToScalar(-2);
466 bounds.inset(inset, inset);
467 canvas->drawRect(bounds, paint);
468 if (desiredColor != SK_ColorBLACK) {
469 paint.setColor(SK_ColorBLACK);
470 canvas->drawText(c_str, size, left + SK_Scalar1, top + SK_Scalar1, paint);
471 }
472 paint.setColor(desiredColor);
473 canvas->drawText(c_str, size, left, top, paint);
474}
475
reed@android.com44177402009-11-23 21:07:51 +0000476#define XCLIP_N 8
477#define YCLIP_N 8
reed@android.come522ca52009-11-23 20:10:41 +0000478
479void SampleWindow::draw(SkCanvas* canvas) {
reed@android.com44177402009-11-23 21:07:51 +0000480 // update the animation time
reed@android.comf2b98d62010-12-20 18:26:13 +0000481 gAnimTimePrev = gAnimTime;
reed@android.com44177402009-11-23 21:07:51 +0000482 gAnimTime = SkTime::GetMSecs();
483
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000484 if (fZoomLevel) {
485 SkMatrix m;
486 SkScalar cx = SkScalarHalf(this->width());
487 SkScalar cy = SkScalarHalf(this->height());
488 SkPoint center;
489 m = canvas->getTotalMatrix();//.invert(&m);
490 m.mapXY(cx, cy, &center);
491 cx = center.fX;
492 cy = center.fY;
493
494 m.setTranslate(-cx, -cy);
495 m.postScale(fZoomScale, fZoomScale);
496 m.postTranslate(cx, cy);
497
498 canvas->concat(m);
499 }
500
reed@google.com52f57e12011-03-16 12:10:02 +0000501 // Apply any gesture matrix
502 if (true) {
503 const SkMatrix& localM = fGesture.localM();
504 if (localM.getType() & SkMatrix::kScale_Mask) {
505 canvas->setExternalMatrix(&localM);
506 }
507 canvas->concat(localM);
508 canvas->concat(fGesture.globalM());
509
510 if (fGesture.isActive()) {
511 this->inval(NULL);
512 }
513 }
514
reed@android.come522ca52009-11-23 20:10:41 +0000515 if (fNClip) {
reed@android.com55e76b22009-11-23 21:46:47 +0000516 this->INHERITED::draw(canvas);
517 SkBitmap orig = capture_bitmap(canvas);
reed@android.come522ca52009-11-23 20:10:41 +0000518
519 const SkScalar w = this->width();
520 const SkScalar h = this->height();
521 const SkScalar cw = w / XCLIP_N;
522 const SkScalar ch = h / YCLIP_N;
523 for (int y = 0; y < YCLIP_N; y++) {
reed@android.com55e76b22009-11-23 21:46:47 +0000524 SkRect r;
525 r.fTop = y * ch;
526 r.fBottom = (y + 1) * ch;
527 if (y == YCLIP_N - 1) {
528 r.fBottom = h;
529 }
reed@android.come522ca52009-11-23 20:10:41 +0000530 for (int x = 0; x < XCLIP_N; x++) {
531 SkAutoCanvasRestore acr(canvas, true);
reed@android.com55e76b22009-11-23 21:46:47 +0000532 r.fLeft = x * cw;
533 r.fRight = (x + 1) * cw;
534 if (x == XCLIP_N - 1) {
535 r.fRight = w;
536 }
reed@android.come522ca52009-11-23 20:10:41 +0000537 canvas->clipRect(r);
538 this->INHERITED::draw(canvas);
539 }
540 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000541
reed@android.com55e76b22009-11-23 21:46:47 +0000542 SkBitmap diff;
543 if (bitmap_diff(canvas, orig, &diff)) {
544 }
reed@android.come522ca52009-11-23 20:10:41 +0000545 } else {
546 this->INHERITED::draw(canvas);
547 }
Scroggo0f185c22011-03-24 18:35:50 +0000548 if (fShowZoomer) {
549 int count = canvas->save();
550 canvas->resetMatrix();
551 // Ensure the mouse position is on screen.
552 int width = this->width();
553 int height = this->height();
554 if (fMouseX >= width) fMouseX = width - 1;
555 else if (fMouseX < 0) fMouseX = 0;
556 if (fMouseY >= height) fMouseY = height - 1;
557 else if (fMouseY < 0) fMouseY = 0;
558 SkBitmap bitmap = capture_bitmap(canvas);
559 // Find the size of the zoomed in view, forced to be odd, so the examined pixel is in the middle.
560 int zoomedWidth = (width >> 2) | 1;
561 int zoomedHeight = (height >> 2) | 1;
562 SkIRect src;
563 src.set(0, 0, zoomedWidth / fFatBitsScale, zoomedHeight / fFatBitsScale);
564 src.offset(fMouseX - (src.width()>>1), fMouseY - (src.height()>>1));
565 SkRect dest;
566 dest.set(0, 0, SkIntToScalar(zoomedWidth), SkIntToScalar(zoomedHeight));
567 dest.offset(SkIntToScalar(width - zoomedWidth), SkIntToScalar(height - zoomedHeight));
568 SkPaint paint;
569 // Clear the background behind our zoomed in view
570 paint.setColor(SK_ColorWHITE);
571 canvas->drawRect(dest, paint);
572 canvas->drawBitmapRect(bitmap, &src, dest);
573 paint.setColor(SK_ColorBLACK);
574 paint.setStyle(SkPaint::kStroke_Style);
575 // Draw a border around the pixel in the middle
576 SkRect originalPixel;
577 originalPixel.set(SkIntToScalar(fMouseX), SkIntToScalar(fMouseY), SkIntToScalar(fMouseX + 1), SkIntToScalar(fMouseY + 1));
578 SkMatrix matrix;
579 SkRect scalarSrc;
580 scalarSrc.set(src);
581 SkColor color = bitmap.getColor(fMouseX, fMouseY);
582 if (matrix.setRectToRect(scalarSrc, dest, SkMatrix::kFill_ScaleToFit)) {
583 SkRect pixel;
584 matrix.mapRect(&pixel, originalPixel);
585 // TODO Perhaps measure the values and make the outline white if it's "dark"
586 if (color == SK_ColorBLACK) {
587 paint.setColor(SK_ColorWHITE);
588 }
589 canvas->drawRect(pixel, paint);
590 }
591 paint.setColor(SK_ColorBLACK);
592 // Draw a border around the destination rectangle
593 canvas->drawRect(dest, paint);
594 paint.setStyle(SkPaint::kStrokeAndFill_Style);
595 // Identify the pixel and its color on screen
596 paint.setTypeface(fTypeface);
597 paint.setAntiAlias(true);
598 SkScalar lineHeight = paint.getFontMetrics(NULL);
599 SkString string;
600 string.appendf("(%i, %i)", fMouseX, fMouseY);
601 SkScalar left = dest.fLeft + SkIntToScalar(3);
602 SkScalar i = SK_Scalar1;
603 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
604 // Alpha
605 i += SK_Scalar1;
606 string.reset();
607 string.appendf("A: %X", SkColorGetA(color));
608 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
609 // Red
610 i += SK_Scalar1;
611 string.reset();
612 string.appendf("R: %X", SkColorGetR(color));
613 paint.setColor(SK_ColorRED);
614 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
615 // Green
616 i += SK_Scalar1;
617 string.reset();
618 string.appendf("G: %X", SkColorGetG(color));
619 paint.setColor(SK_ColorGREEN);
620 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
621 // Blue
622 i += SK_Scalar1;
623 string.reset();
624 string.appendf("B: %X", SkColorGetB(color));
625 paint.setColor(SK_ColorBLUE);
626 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
627 canvas->restoreToCount(count);
628 }
reed@android.come522ca52009-11-23 20:10:41 +0000629}
630
reed@android.com8a1c16f2008-12-17 15:59:43 +0000631void SampleWindow::onDraw(SkCanvas* canvas) {
632 if (fRepeatDrawing) {
633 this->inval(NULL);
634 }
635}
636
637#include "SkColorPriv.h"
638
639static void reverseRedAndBlue(const SkBitmap& bm) {
640 SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
641 uint8_t* p = (uint8_t*)bm.getPixels();
642 uint8_t* stop = p + bm.getSize();
643 while (p < stop) {
644 // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
645 unsigned scale = SkAlpha255To256(p[3]);
646 unsigned r = p[2];
647 unsigned b = p[0];
648 p[0] = SkAlphaMul(r, scale);
649 p[1] = SkAlphaMul(p[1], scale);
650 p[2] = SkAlphaMul(b, scale);
651 p += 4;
652 }
653}
654
655SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000656 SkIPoint viewport;
657 bool alreadyGPU = canvas->getViewport(&viewport);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000658
reed@android.comf2b98d62010-12-20 18:26:13 +0000659 if (kGPU_CanvasType != fCanvasType) {
reed@android.com6efdc472008-12-19 18:24:35 +0000660#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000661 detachGL();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000662#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000663 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000664
reed@android.com8a1c16f2008-12-17 15:59:43 +0000665 switch (fCanvasType) {
666 case kRaster_CanvasType:
667 canvas = this->INHERITED::beforeChildren(canvas);
668 break;
669 case kPicture_CanvasType:
670 fPicture = new SkPicture;
671 canvas = fPicture->beginRecording(9999, 9999);
672 break;
reed@google.comac10a2d2010-12-22 21:39:39 +0000673 case kGPU_CanvasType: {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000674 if (!alreadyGPU && make3DReady()) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000675 SkDevice* device = canvas->getDevice();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000676 const SkBitmap& bitmap = device->accessBitmap(true);
677
bsalomon@google.com5782d712011-01-21 21:03:59 +0000678 GrRenderTarget* renderTarget;
679 renderTarget = fGrContext->createRenderTargetFrom3DApiState();
680 fGpuCanvas = new SkGpuCanvas(fGrContext, renderTarget);
681 renderTarget->unref();
682
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000683 device = fGpuCanvas->createDevice(SkBitmap::kARGB_8888_Config,
684 bitmap.width(), bitmap.height(),
685 false, false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000686 fGpuCanvas->setDevice(device)->unref();
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000687
688 fGpuCanvas->concat(canvas->getTotalMatrix());
reed@android.comf2b98d62010-12-20 18:26:13 +0000689 canvas = fGpuCanvas;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000690
reed@android.comf2b98d62010-12-20 18:26:13 +0000691 } else {
692 canvas = this->INHERITED::beforeChildren(canvas);
693 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000694 break;
reed@google.comac10a2d2010-12-22 21:39:39 +0000695 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000696 }
697
698 if (fUseClip) {
699 canvas->drawColor(0xFFFF88FF);
700 canvas->clipPath(fClipPath);
701 }
702
703 return canvas;
704}
705
706static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
707 const SkRegion& rgn) {
708 SkCanvas canvas(bm);
709 SkRegion inval(rgn);
710
711 inval.translate(r.fLeft, r.fTop);
712 canvas.clipRegion(inval);
713 canvas.drawColor(0xFFFF8080);
714}
715
716void SampleWindow::afterChildren(SkCanvas* orig) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000717 if (fRequestGrabImage) {
718 fRequestGrabImage = false;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000719
reed@android.comf2b98d62010-12-20 18:26:13 +0000720 SkCanvas* canvas = fGpuCanvas ? fGpuCanvas : orig;
721 SkDevice* device = canvas->getDevice();
722 SkBitmap bitmap;
reed@google.com5ba2d5b2011-03-10 19:40:34 +0000723 SkIRect bounds = {
724 0, 0,
725 SkScalarRound(this->width()),
726 SkScalarRound(this->height())
727 };
reed@android.comf2b98d62010-12-20 18:26:13 +0000728 if (device->readPixels(bounds, &bitmap)) {
729 static int gSampleGrabCounter;
730 SkString name;
731 name.printf("sample_grab_%d", gSampleGrabCounter++);
732 SkImageEncoder::EncodeFile(name.c_str(), bitmap,
733 SkImageEncoder::kPNG_Type, 100);
734 }
735 }
736
reed@android.com8a1c16f2008-12-17 15:59:43 +0000737 switch (fCanvasType) {
738 case kRaster_CanvasType:
739 break;
740 case kPicture_CanvasType:
reed@android.comaefd2bc2009-03-30 21:02:14 +0000741 if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742 SkPicture* pict = new SkPicture(*fPicture);
743 fPicture->unref();
744 orig->drawPicture(*pict);
745 pict->unref();
reed@android.comaefd2bc2009-03-30 21:02:14 +0000746 } else if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000747 SkDynamicMemoryWStream ostream;
748 fPicture->serialize(&ostream);
749 fPicture->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000750
reed@android.com8a1c16f2008-12-17 15:59:43 +0000751 SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
752 SkPicture pict(&istream);
753 orig->drawPicture(pict);
754 } else {
755 fPicture->draw(orig);
756 fPicture->unref();
757 }
758 fPicture = NULL;
759 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000760#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000761 case kGPU_CanvasType:
762 delete fGpuCanvas;
763 fGpuCanvas = NULL;
764 presentGL();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000765 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000766#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000767 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000768
reed@android.com8a1c16f2008-12-17 15:59:43 +0000769// if ((fScrollTestX | fScrollTestY) != 0)
reed@android.comf2b98d62010-12-20 18:26:13 +0000770 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771 const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
772 int dx = fScrollTestX * 7;
773 int dy = fScrollTestY * 7;
774 SkIRect r;
775 SkRegion inval;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000776
reed@android.com8a1c16f2008-12-17 15:59:43 +0000777 r.set(50, 50, 50+100, 50+100);
778 bm.scrollRect(&r, dx, dy, &inval);
779 paint_rgn(bm, r, inval);
780 }
781}
782
reed@android.com6c5f6f22009-08-14 16:08:38 +0000783void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
784 if (fScale) {
785 SkScalar scale = SK_Scalar1 * 7 / 10;
786 SkScalar cx = this->width() / 2;
787 SkScalar cy = this->height() / 2;
788 canvas->translate(cx, cy);
789 canvas->scale(scale, scale);
790 canvas->translate(-cx, -cy);
791 }
792 if (fRotate) {
793 SkScalar cx = this->width() / 2;
794 SkScalar cy = this->height() / 2;
795 canvas->translate(cx, cy);
796 canvas->rotate(SkIntToScalar(30));
797 canvas->translate(-cx, -cy);
798 }
reed@google.comf0b5f682011-03-11 20:08:25 +0000799
800 if (LCDTextDrawFilter::kNeutral_Mode != fLCDMode) {
801 canvas->setDrawFilter(new LCDTextDrawFilter(fLCDMode))->unref();
802 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000803}
804
805void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) {
reed@google.comf0b5f682011-03-11 20:08:25 +0000806 canvas->setDrawFilter(NULL);
reed@android.com6c5f6f22009-08-14 16:08:38 +0000807}
808
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809static SkBitmap::Config gConfigCycle[] = {
810 SkBitmap::kNo_Config, // none -> none
811 SkBitmap::kNo_Config, // a1 -> none
812 SkBitmap::kNo_Config, // a8 -> none
813 SkBitmap::kNo_Config, // index8 -> none
814 SkBitmap::kARGB_4444_Config, // 565 -> 4444
815 SkBitmap::kARGB_8888_Config, // 4444 -> 8888
816 SkBitmap::kRGB_565_Config // 8888 -> 565
817};
818
819static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
820 return gConfigCycle[c];
821}
822
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000823void SampleWindow::changeZoomLevel(int delta) {
824 fZoomLevel += delta;
825 if (fZoomLevel > 0) {
826 fZoomLevel = SkMin32(fZoomLevel, MAX_ZOOM_LEVEL);
827 fZoomScale = SkIntToScalar(fZoomLevel + 1);
828 } else if (fZoomLevel < 0) {
829 fZoomLevel = SkMax32(fZoomLevel, MIN_ZOOM_LEVEL);
830 fZoomScale = SK_Scalar1 / (1 - fZoomLevel);
831 } else {
832 fZoomScale = SK_Scalar1;
833 }
834
835 this->inval(NULL);
836}
837
reed@android.com8a1c16f2008-12-17 15:59:43 +0000838bool SampleWindow::nextSample() {
reed@android.com34245c72009-11-03 04:00:48 +0000839 fCurrIndex = (fCurrIndex + 1) % fSamples.count();
840 this->loadView(fSamples[fCurrIndex]());
841 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000842}
843
844bool SampleWindow::onEvent(const SkEvent& evt) {
845 if (evt.isType(ANIMATING_EVENTTYPE)) {
846 if (fAnimating) {
847 this->nextSample();
848 this->postAnimatingEvent();
849 }
850 return true;
851 }
reed@android.com34245c72009-11-03 04:00:48 +0000852 if (evt.isType("set-curr-index")) {
853 fCurrIndex = evt.getFast32() % fSamples.count();
854 this->loadView(fSamples[fCurrIndex]());
855 return true;
856 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000857 return this->INHERITED::onEvent(evt);
858}
859
reed@android.comf2b98d62010-12-20 18:26:13 +0000860bool SampleWindow::onQuery(SkEvent* query) {
861 if (query->isType("get-slide-count")) {
862 query->setFast32(fSamples.count());
863 return true;
864 }
865 if (query->isType("get-slide-title")) {
866 SkView* view = fSamples[query->getFast32()]();
867 SkEvent evt(gTitleEvtName);
868 if (view->doQuery(&evt)) {
869 query->setString("title", evt.findString(gTitleEvtName));
870 }
871 SkSafeUnref(view);
872 return true;
873 }
874 if (query->isType("use-fast-text")) {
875 SkEvent evt(gFastTextEvtName);
876 return curr_view(this)->doQuery(&evt);
877 }
878 return this->INHERITED::onQuery(query);
879}
880
reed@android.com0ae6b242008-12-23 16:49:54 +0000881static void cleanup_for_filename(SkString* name) {
882 char* str = name->writable_str();
reed@android.come191b162009-12-18 21:33:39 +0000883 for (size_t i = 0; i < name->size(); i++) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000884 switch (str[i]) {
885 case ':': str[i] = '-'; break;
886 case '/': str[i] = '-'; break;
887 case ' ': str[i] = '_'; break;
888 default: break;
889 }
890 }
891}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000892
893bool SampleWindow::onHandleChar(SkUnichar uni) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000894 {
895 SkView* view = curr_view(this);
896 if (view) {
897 SkEvent evt(gCharEvtName);
898 evt.setFast32(uni);
899 if (view->doQuery(&evt)) {
900 return true;
901 }
902 }
903 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000904
reed@android.com8a1c16f2008-12-17 15:59:43 +0000905 int dx = 0xFF;
906 int dy = 0xFF;
907
908 switch (uni) {
909 case '5': dx = 0; dy = 0; break;
910 case '8': dx = 0; dy = -1; break;
911 case '6': dx = 1; dy = 0; break;
912 case '2': dx = 0; dy = 1; break;
913 case '4': dx = -1; dy = 0; break;
914 case '7': dx = -1; dy = -1; break;
915 case '9': dx = 1; dy = -1; break;
916 case '3': dx = 1; dy = 1; break;
917 case '1': dx = -1; dy = 1; break;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000918
reed@android.com8a1c16f2008-12-17 15:59:43 +0000919 default:
920 break;
921 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000922
reed@android.com8a1c16f2008-12-17 15:59:43 +0000923 if (0xFF != dx && 0xFF != dy) {
924 if ((dx | dy) == 0) {
925 fScrollTestX = fScrollTestY = 0;
926 } else {
927 fScrollTestX += dx;
928 fScrollTestY += dy;
929 }
930 this->inval(NULL);
931 return true;
932 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000933
reed@android.com0ae6b242008-12-23 16:49:54 +0000934 switch (uni) {
935 case 'a':
936 fAnimating = !fAnimating;
937 this->postAnimatingEvent();
938 this->updateTitle();
939 return true;
940 case 'f': {
941 const char* title = this->getTitle();
942 if (title[0] == 0) {
943 title = "sampleapp";
944 }
945 SkString name(title);
946 cleanup_for_filename(&name);
947 name.append(".png");
948 if (SkImageEncoder::EncodeFile(name.c_str(), this->getBitmap(),
reed@android.comb08eb2b2009-01-06 20:16:26 +0000949 SkImageEncoder::kPNG_Type, 100)) {
reed@android.com0ae6b242008-12-23 16:49:54 +0000950 SkDebugf("Created %s\n", name.c_str());
951 }
952 return true;
953 }
reed@android.com6c5f6f22009-08-14 16:08:38 +0000954 case 'r':
955 fRotate = !fRotate;
956 this->inval(NULL);
957 this->updateTitle();
958 return true;
959 case 's':
960 fScale = !fScale;
961 this->inval(NULL);
962 this->updateTitle();
963 return true;
reed@google.comfb56a9e2011-02-10 18:47:24 +0000964 case 'c':
965 fUseClip = !fUseClip;
966 this->inval(NULL);
967 this->updateTitle();
968 return true;
reed@android.comf2b98d62010-12-20 18:26:13 +0000969 case 'd':
970 SkGraphics::SetFontCacheUsed(0);
971 return true;
972 case 'g':
973 fRequestGrabImage = true;
974 this->inval(NULL);
975 break;
reed@google.comf0b5f682011-03-11 20:08:25 +0000976 case 'l':
977 fLCDMode = cycle_lcdmode(fLCDMode);
978 this->updateTitle();
979 this->inval(NULL);
980 break;
scroggo08526c02011-03-22 14:03:21 +0000981 case 'i':
982 this->zoomIn();
983 break;
984 case 'o':
985 this->zoomOut();
986 break;
987 case 'z':
988 this->toggleZoomer();
989 break;
reed@android.com0ae6b242008-12-23 16:49:54 +0000990 default:
991 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000992 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000993
reed@android.com8a1c16f2008-12-17 15:59:43 +0000994 return this->INHERITED::onHandleChar(uni);
995}
996
997#include "SkDumpCanvas.h"
998
999bool SampleWindow::onHandleKey(SkKey key) {
reed@android.comf2b98d62010-12-20 18:26:13 +00001000 {
1001 SkView* view = curr_view(this);
1002 if (view) {
1003 SkEvent evt(gKeyEvtName);
1004 evt.setFast32(key);
1005 if (view->doQuery(&evt)) {
1006 return true;
1007 }
1008 }
1009 }
1010
reed@android.com8a1c16f2008-12-17 15:59:43 +00001011 switch (key) {
1012 case kRight_SkKey:
1013 if (this->nextSample()) {
1014 return true;
1015 }
1016 break;
1017 case kLeft_SkKey:
1018 fCanvasType = cycle_canvastype(fCanvasType);
1019 this->updateTitle();
1020 this->inval(NULL);
1021 return true;
1022 case kUp_SkKey:
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001023 if (USE_ARROWS_FOR_ZOOM) {
1024 this->changeZoomLevel(1);
1025 } else {
1026 fNClip = !fNClip;
1027 this->inval(NULL);
1028 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001029 this->updateTitle();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001030 return true;
1031 case kDown_SkKey:
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001032 if (USE_ARROWS_FOR_ZOOM) {
1033 this->changeZoomLevel(-1);
1034 } else {
1035 this->setConfig(cycle_configs(this->getBitmap().config()));
1036 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001037 this->updateTitle();
1038 return true;
1039 case kOK_SkKey:
reed@android.comf2b98d62010-12-20 18:26:13 +00001040 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001041 SkDebugfDumper dumper;
1042 SkDumpCanvas dc(&dumper);
1043 this->draw(&dc);
1044 } else {
1045 fRepeatDrawing = !fRepeatDrawing;
1046 if (fRepeatDrawing) {
1047 this->inval(NULL);
1048 }
1049 }
1050 return true;
reed@android.com34245c72009-11-03 04:00:48 +00001051 case kBack_SkKey:
1052 this->loadView(NULL);
1053 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054 default:
1055 break;
1056 }
1057 return this->INHERITED::onHandleKey(key);
1058}
1059
reed@google.com52f57e12011-03-16 12:10:02 +00001060///////////////////////////////////////////////////////////////////////////////
1061
1062static const char gGestureClickType[] = "GestureClickType";
1063
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001064bool SampleWindow::onDispatchClick(int x, int y, Click::State state) {
Scroggo0f185c22011-03-24 18:35:50 +00001065 if (Click::kMoved_State == state) {
1066 updatePointer(x, y);
1067 }
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001068 int w = SkScalarRound(this->width());
1069 int h = SkScalarRound(this->height());
1070
1071 // check for the resize-box
1072 if (w - x < 16 && h - y < 16) {
1073 return false; // let the OS handle the click
1074 } else {
1075 return this->INHERITED::onDispatchClick(x, y, state);
1076 }
1077}
1078
reed@google.com52f57e12011-03-16 12:10:02 +00001079class GestureClick : public SkView::Click {
1080public:
1081 GestureClick(SkView* target) : SkView::Click(target) {
1082 this->setType(gGestureClickType);
1083 }
1084
1085 static bool IsGesture(Click* click) {
1086 return click->isType(gGestureClickType);
1087 }
1088};
1089
1090SkView::Click* SampleWindow::onFindClickHandler(SkScalar x, SkScalar y) {
1091 return new GestureClick(this);
1092}
1093
1094bool SampleWindow::onClick(Click* click) {
1095 if (GestureClick::IsGesture(click)) {
1096 float x = SkScalarToFloat(click->fCurr.fX);
1097 float y = SkScalarToFloat(click->fCurr.fY);
1098 switch (click->fState) {
1099 case SkView::Click::kDown_State:
1100 fGesture.touchBegin(click, x, y);
1101 break;
1102 case SkView::Click::kMoved_State:
1103 fGesture.touchMoved(click, x, y);
1104 this->inval(NULL);
1105 break;
1106 case SkView::Click::kUp_State:
1107 fGesture.touchEnd(click);
1108 this->inval(NULL);
1109 break;
1110 }
1111 return true;
1112 }
1113 return false;
1114}
1115
1116///////////////////////////////////////////////////////////////////////////////
1117
reed@android.com8a1c16f2008-12-17 15:59:43 +00001118void SampleWindow::loadView(SkView* view) {
1119 SkView::F2BIter iter(this);
1120 SkView* prev = iter.next();
1121 if (prev) {
1122 prev->detachFromParent();
1123 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001124
reed@android.com34245c72009-11-03 04:00:48 +00001125 if (NULL == view) {
1126 view = create_overview(fSamples.count(), fSamples.begin());
1127 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001128 view->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +00001129 view->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001130 this->attachChildToFront(view)->unref();
1131 view->setSize(this->width(), this->height());
1132
1133 this->updateTitle();
1134}
1135
1136static const char* gConfigNames[] = {
1137 "unknown config",
1138 "A1",
1139 "A8",
1140 "Index8",
1141 "565",
1142 "4444",
1143 "8888"
1144};
1145
1146static const char* configToString(SkBitmap::Config c) {
1147 return gConfigNames[c];
1148}
1149
1150static const char* gCanvasTypePrefix[] = {
1151 "raster: ",
1152 "picture: ",
1153 "opengl: "
1154};
1155
1156void SampleWindow::updateTitle() {
1157 SkString title;
1158
1159 SkView::F2BIter iter(this);
1160 SkView* view = iter.next();
1161 SkEvent evt(gTitleEvtName);
1162 if (view->doQuery(&evt)) {
1163 title.set(evt.findString(gTitleEvtName));
1164 }
1165 if (title.size() == 0) {
1166 title.set("<unknown>");
1167 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001168
reed@android.com8a1c16f2008-12-17 15:59:43 +00001169 title.prepend(gCanvasTypePrefix[fCanvasType]);
1170
1171 title.prepend(" ");
1172 title.prepend(configToString(this->getBitmap().config()));
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001173
reed@android.com8a1c16f2008-12-17 15:59:43 +00001174 if (fAnimating) {
1175 title.prepend("<A> ");
1176 }
reed@android.com6c5f6f22009-08-14 16:08:38 +00001177 if (fScale) {
1178 title.prepend("<S> ");
1179 }
1180 if (fRotate) {
1181 title.prepend("<R> ");
1182 }
reed@android.come522ca52009-11-23 20:10:41 +00001183 if (fNClip) {
1184 title.prepend("<C> ");
1185 }
reed@google.comf0b5f682011-03-11 20:08:25 +00001186 if (LCDTextDrawFilter::kForceOn_Mode == fLCDMode) {
1187 title.prepend("LCD ");
1188 } else if (LCDTextDrawFilter::kForceOff_Mode == fLCDMode) {
1189 title.prepend("lcd ");
1190 }
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001191
1192 if (fZoomLevel) {
1193 title.prependf("{%d} ", fZoomLevel);
1194 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001195 this->setTitle(title.c_str());
1196}
1197
1198void SampleWindow::onSizeChange() {
1199 this->INHERITED::onSizeChange();
1200
1201 SkView::F2BIter iter(this);
1202 SkView* view = iter.next();
1203 view->setSize(this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001204
reed@android.com8a1c16f2008-12-17 15:59:43 +00001205 // rebuild our clippath
1206 {
1207 const SkScalar W = this->width();
1208 const SkScalar H = this->height();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001209
reed@android.com8a1c16f2008-12-17 15:59:43 +00001210 fClipPath.reset();
1211#if 0
1212 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
1213 SkRect r;
1214 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
1215 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
1216 fClipPath.addRect(r);
1217 }
1218#else
1219 SkRect r;
1220 r.set(0, 0, W, H);
1221 fClipPath.addRect(r, SkPath::kCCW_Direction);
1222 r.set(W/4, H/4, W*3/4, H*3/4);
1223 fClipPath.addRect(r, SkPath::kCW_Direction);
1224#endif
1225 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001226
reed@android.com8a1c16f2008-12-17 15:59:43 +00001227 this->updateTitle(); // to refresh our config
1228}
1229
1230///////////////////////////////////////////////////////////////////////////////
1231
reed@android.comf2b98d62010-12-20 18:26:13 +00001232template <typename T> void SkTBSort(T array[], int count) {
1233 for (int i = 1; i < count - 1; i++) {
1234 bool didSwap = false;
1235 for (int j = count - 1; j > i; --j) {
1236 if (array[j] < array[j-1]) {
1237 T tmp(array[j-1]);
1238 array[j-1] = array[j];
1239 array[j] = tmp;
1240 didSwap = true;
1241 }
1242 }
1243 if (!didSwap) {
1244 break;
1245 }
1246 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001247
reed@android.comf2b98d62010-12-20 18:26:13 +00001248 for (int k = 0; k < count - 1; k++) {
1249 SkASSERT(!(array[k+1] < array[k]));
1250 }
1251}
1252
1253#include "SkRandom.h"
1254
1255static void rand_rect(SkIRect* rect, SkRandom& rand) {
1256 int bits = 8;
1257 int shift = 32 - bits;
1258 rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
1259 rand.nextU() >> shift, rand.nextU() >> shift);
1260 rect->sort();
1261}
1262
1263static void dumpRect(const SkIRect& r) {
1264 SkDebugf(" { %d, %d, %d, %d },\n",
1265 r.fLeft, r.fTop,
1266 r.fRight, r.fBottom);
1267}
1268
1269static void test_rects(const SkIRect rect[], int count) {
1270 SkRegion rgn0, rgn1;
1271
1272 for (int i = 0; i < count; i++) {
1273 rgn0.op(rect[i], SkRegion::kUnion_Op);
1274 // dumpRect(rect[i]);
1275 }
1276 rgn1.setRects(rect, count);
1277
1278 if (rgn0 != rgn1) {
1279 SkDebugf("\n");
1280 for (int i = 0; i < count; i++) {
1281 dumpRect(rect[i]);
1282 }
1283 SkDebugf("\n");
1284 }
1285}
1286
1287static void test() {
1288 size_t i;
1289
1290 const SkIRect r0[] = {
1291 { 0, 0, 1, 1 },
1292 { 2, 2, 3, 3 },
1293 };
1294 const SkIRect r1[] = {
1295 { 0, 0, 1, 3 },
1296 { 1, 1, 2, 2 },
1297 { 2, 0, 3, 3 },
1298 };
1299 const SkIRect r2[] = {
1300 { 0, 0, 1, 2 },
1301 { 2, 1, 3, 3 },
1302 { 4, 0, 5, 1 },
1303 { 6, 0, 7, 4 },
1304 };
1305
1306 static const struct {
1307 const SkIRect* fRects;
1308 int fCount;
1309 } gRecs[] = {
1310 { r0, SK_ARRAY_COUNT(r0) },
1311 { r1, SK_ARRAY_COUNT(r1) },
1312 { r2, SK_ARRAY_COUNT(r2) },
1313 };
1314
1315 for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
1316 test_rects(gRecs[i].fRects, gRecs[i].fCount);
1317 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001318
reed@android.comf2b98d62010-12-20 18:26:13 +00001319 SkRandom rand;
1320 for (i = 0; i < 10000; i++) {
1321 SkRegion rgn0, rgn1;
1322
1323 const int N = 8;
1324 SkIRect rect[N];
1325 for (int j = 0; j < N; j++) {
1326 rand_rect(&rect[j], rand);
1327 }
1328 test_rects(rect, N);
1329 }
1330}
1331
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332SkOSWindow* create_sk_window(void* hwnd) {
reed@android.comf2b98d62010-12-20 18:26:13 +00001333// test();
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001334 return new SampleWindow(hwnd);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335}
1336
1337void get_preferred_size(int* x, int* y, int* width, int* height) {
1338 *x = 10;
1339 *y = 50;
1340 *width = 640;
1341 *height = 480;
1342}
1343
1344void application_init() {
1345// setenv("ANDROID_ROOT", "../../../data", 0);
reed@android.come191b162009-12-18 21:33:39 +00001346#ifdef SK_BUILD_FOR_MAC
reed@android.com8a1c16f2008-12-17 15:59:43 +00001347 setenv("ANDROID_ROOT", "/android/device/data", 0);
reed@android.come191b162009-12-18 21:33:39 +00001348#endif
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001349 SkGraphics::Init();
1350 SkEvent::Init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001351}
1352
1353void application_term() {
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001354 SkEvent::Term();
1355 SkGraphics::Term();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001356}