blob: 254d209db1713b2fe8235254186a806fb5a5b9bb [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Scroggo2c8208f2011-06-15 16:49:08 +00007#include "SampleApp.h"
8
reed@google.com8a85d0c2011-06-24 19:12:12 +00009#include "SkData.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
11#include "SkDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkGraphics.h"
reed@android.comb08eb2b2009-01-06 20:16:26 +000013#include "SkImageEncoder.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkPaint.h"
15#include "SkPicture.h"
16#include "SkStream.h"
reed@android.com44177402009-11-23 21:07:51 +000017#include "SkTime.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000018#include "SkWindow.h"
19
20#include "SampleCode.h"
Scroggo0f185c22011-03-24 18:35:50 +000021#include "SkTypeface.h"
reed@android.comf2b98d62010-12-20 18:26:13 +000022
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000023#if SK_SUPPORT_GPU
tomhudson@google.com6bf38b52012-02-14 15:11:59 +000024#include "gl/GrGLInterface.h"
bsalomon@google.com9c1f1ac2012-05-07 17:09:37 +000025#include "gl/GrGLUtil.h"
bsalomon@google.com583a1e32011-08-17 13:42:46 +000026#include "GrRenderTarget.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000027#include "GrContext.h"
28#include "SkGpuDevice.h"
29#else
30class GrContext;
31#endif
Scroggo2c8208f2011-06-15 16:49:08 +000032
reed@google.com1830c7a2012-06-04 12:05:43 +000033#include "SkOSFile.h"
Scroggo8ac0d542011-06-21 14:44:57 +000034#include "SkPDFDevice.h"
35#include "SkPDFDocument.h"
36#include "SkStream.h"
37
scroggo@google.comb073d922012-06-08 15:35:03 +000038#include "SkGPipe.h"
39#include "SamplePipeControllers.h"
40
robertphillips@google.coma22e2112012-08-16 14:58:06 +000041SK_DEFINE_INST_COUNT(SampleWindow::DeviceManager)
42
reed@google.com1830c7a2012-06-04 12:05:43 +000043extern SampleView* CreateSamplePictFileView(const char filename[]);
44
45class PictFileFactory : public SkViewFactory {
46 SkString fFilename;
47public:
48 PictFileFactory(const SkString& filename) : fFilename(filename) {}
49 virtual SkView* operator() () const SK_OVERRIDE {
50 return CreateSamplePictFileView(fFilename.c_str());
51 }
52};
53
yangsu@google.comdb03eaa2011-08-08 15:37:23 +000054#define PIPE_FILEx
55#ifdef PIPE_FILE
yangsu@google.com1f394212011-06-01 18:03:34 +000056#define FILE_PATH "/path/to/drawing.data"
57#endif
58
yangsu@google.comf121b052011-08-08 16:02:51 +000059#define PIPE_NETx
yangsu@google.comdb03eaa2011-08-08 15:37:23 +000060#ifdef PIPE_NET
61#include "SkSockets.h"
62SkTCPServer gServer;
63#endif
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000064
65#define DEBUGGERx
66#ifdef DEBUGGER
67extern SkView* create_debugger(const char* data, size_t size);
68extern bool is_debugger(SkView* view);
69SkTDArray<char> gTempDataStore;
70#endif
71
yangsu@google.comdb03eaa2011-08-08 15:37:23 +000072
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +000073#define USE_ARROWS_FOR_ZOOM true
robertphillips@google.comb442a6d2012-04-02 19:24:21 +000074
75#if SK_ANGLE
76//#define DEFAULT_TO_ANGLE 1
77#else
78//#define DEFAULT_TO_GPU 1
79#endif
reed@android.comf2b98d62010-12-20 18:26:13 +000080
bsalomon@google.com48dd1a22011-10-31 14:18:20 +000081extern SkView* create_overview(int, const SkViewFactory*[]);
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000082extern bool is_overview(SkView* view);
yangsu@google.comdb03eaa2011-08-08 15:37:23 +000083extern SkView* create_transition(SkView*, SkView*, int);
yangsu@google.comef7bdfa2011-08-12 14:27:47 +000084extern bool is_transition(SkView* view);
85
reed@android.com34245c72009-11-03 04:00:48 +000086
reed@android.com8a1c16f2008-12-17 15:59:43 +000087#define ANIMATING_EVENTTYPE "nextSample"
88#define ANIMATING_DELAY 750
89
mike@reedtribe.org2eb59522011-04-22 01:59:09 +000090#ifdef SK_DEBUG
reed@google.combad8c872011-05-18 20:10:31 +000091 #define FPS_REPEAT_MULTIPLIER 1
mike@reedtribe.org2eb59522011-04-22 01:59:09 +000092#else
reed@google.combad8c872011-05-18 20:10:31 +000093 #define FPS_REPEAT_MULTIPLIER 10
mike@reedtribe.org2eb59522011-04-22 01:59:09 +000094#endif
reed@google.combad8c872011-05-18 20:10:31 +000095#define FPS_REPEAT_COUNT (10 * FPS_REPEAT_MULTIPLIER)
mike@reedtribe.org2eb59522011-04-22 01:59:09 +000096
reed@google.com3cec4d72011-07-06 13:59:47 +000097static SampleWindow* gSampleWindow;
98
reed@google.com2072db82011-11-08 15:18:10 +000099static void postEventToSink(SkEvent* evt, SkEventSink* sink) {
100 evt->setTargetID(sink->getSinkID())->post();
101}
102
mike@reedtribe.org6f6e8c32011-12-27 22:33:50 +0000103///////////////////////////////////////////////////////////////////////////////
104
105static const char* skip_until(const char* str, const char* skip) {
106 if (!str) {
107 return NULL;
108 }
109 return strstr(str, skip);
110}
111
112static const char* skip_past(const char* str, const char* skip) {
113 const char* found = skip_until(str, skip);
114 if (!found) {
115 return NULL;
116 }
117 return found + strlen(skip);
118}
119
120static const char* gPrefFileName = "sampleapp_prefs.txt";
121
epoger@google.com6fc7cc22011-12-28 15:13:41 +0000122static bool readTitleFromPrefs(SkString* title) {
mike@reedtribe.org6f6e8c32011-12-27 22:33:50 +0000123 SkFILEStream stream(gPrefFileName);
124 if (!stream.isValid()) {
125 return false;
126 }
127
128 int len = stream.getLength();
129 SkString data(len);
130 stream.read(data.writable_str(), len);
131 const char* s = data.c_str();
132
133 s = skip_past(s, "curr-slide-title");
134 s = skip_past(s, "=");
135 s = skip_past(s, "\"");
136 const char* stop = skip_until(s, "\"");
137 if (stop > s) {
138 title->set(s, stop - s);
139 return true;
140 }
141 return false;
142}
143
epoger@google.com6fc7cc22011-12-28 15:13:41 +0000144static void writeTitleToPrefs(const char* title) {
mike@reedtribe.org6f6e8c32011-12-27 22:33:50 +0000145 SkFILEWStream stream(gPrefFileName);
146 SkString data;
147 data.printf("curr-slide-title = \"%s\"\n", title);
148 stream.write(data.c_str(), data.size());
149}
150
151///////////////////////////////////////////////////////////////////////////////
152
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000153class SampleWindow::DefaultDeviceManager : public SampleWindow::DeviceManager {
154public:
155
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000156 DefaultDeviceManager() {
157#if SK_SUPPORT_GPU
158 fCurContext = NULL;
159 fCurIntf = NULL;
160 fCurRenderTarget = NULL;
161 fMSAASampleCount = 0;
162#endif
163 fBackend = kNone_BackEndType;
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000164 }
165
166 virtual ~DefaultDeviceManager() {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000167#if SK_SUPPORT_GPU
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000168 SkSafeUnref(fCurContext);
169 SkSafeUnref(fCurIntf);
170 SkSafeUnref(fCurRenderTarget);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000171#endif
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000172 }
173
bsalomon@google.com11959252012-04-06 20:13:38 +0000174 virtual void setUpBackend(SampleWindow* win, int msaaSampleCount) {
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000175 SkASSERT(kNone_BackEndType == fBackend);
robertphillips@google.com53e96a12012-03-30 14:47:53 +0000176
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000177 fBackend = kNone_BackEndType;
178
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000179#if SK_SUPPORT_GPU
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000180 switch (win->getDeviceType()) {
181 case kRaster_DeviceType:
182 // fallthrough
183 case kPicture_DeviceType:
184 // fallthrough
185 case kGPU_DeviceType:
186 // fallthrough
187 case kNullGPU_DeviceType:
188 // all these guys use the native backend
189 fBackend = kNativeGL_BackEndType;
190 break;
robertphillips@google.combd8d7ad2012-03-30 15:18:14 +0000191#if SK_ANGLE
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000192 case kANGLE_DeviceType:
193 // ANGLE is really the only odd man out
194 fBackend = kANGLE_BackEndType;
195 break;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000196#endif // SK_ANGLE
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000197 default:
198 SkASSERT(false);
199 break;
robertphillips@google.combd8d7ad2012-03-30 15:18:14 +0000200 }
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000201
bsalomon@google.com11959252012-04-06 20:13:38 +0000202 bool result = win->attach(fBackend, msaaSampleCount);
robertphillips@google.comd3b9fbb2012-03-28 16:19:11 +0000203 if (!result) {
bsalomon@google.com74913722011-10-27 20:44:19 +0000204 SkDebugf("Failed to initialize GL");
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000205 return;
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000206 }
bsalomon@google.com11959252012-04-06 20:13:38 +0000207 fMSAASampleCount = msaaSampleCount;
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000208
209 SkASSERT(NULL == fCurIntf);
210 switch (win->getDeviceType()) {
211 case kRaster_DeviceType:
212 // fallthrough
213 case kPicture_DeviceType:
214 // fallthrough
215 case kGPU_DeviceType:
216 // all these guys use the native interface
217 fCurIntf = GrGLCreateNativeInterface();
218 break;
robertphillips@google.comd3b9fbb2012-03-28 16:19:11 +0000219#if SK_ANGLE
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000220 case kANGLE_DeviceType:
221 fCurIntf = GrGLCreateANGLEInterface();
222 break;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000223#endif // SK_ANGLE
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000224 case kNullGPU_DeviceType:
225 fCurIntf = GrGLCreateNullInterface();
226 break;
227 default:
228 SkASSERT(false);
229 break;
bsalomon@google.com6fb736f2011-09-16 18:51:57 +0000230 }
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000231
232 SkASSERT(NULL == fCurContext);
233 fCurContext = GrContext::Create(kOpenGL_Shaders_GrEngine,
234 (GrPlatform3DContext) fCurIntf);
235
236 if (NULL == fCurContext || NULL == fCurIntf) {
237 // We need some context and interface to see results
238 SkSafeUnref(fCurContext);
239 SkSafeUnref(fCurIntf);
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000240 SkDebugf("Failed to setup 3D");
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000241
242 win->detach();
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000243 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000244#endif // SK_SUPPORT_GPU
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000245 // call windowSizeChanged to create the render target
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000246 this->windowSizeChanged(win);
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000247 }
248
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000249 virtual void tearDownBackend(SampleWindow *win) {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000250#if SK_SUPPORT_GPU
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000251 SkSafeUnref(fCurContext);
252 fCurContext = NULL;
253
254 SkSafeUnref(fCurIntf);
255 fCurIntf = NULL;
256
257 SkSafeUnref(fCurRenderTarget);
258 fCurRenderTarget = NULL;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000259#endif
bsalomon@google.comddd40e52012-04-10 15:56:29 +0000260 win->detach();
261 fBackend = kNone_BackEndType;
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000262 }
263
264 virtual bool prepareCanvas(SampleWindow::DeviceType dType,
265 SkCanvas* canvas,
266 SampleWindow* win) {
bsalomon@google.com74913722011-10-27 20:44:19 +0000267 switch (dType) {
robertphillips@google.combd8d7ad2012-03-30 15:18:14 +0000268 case kRaster_DeviceType:
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000269 // fallthrough
robertphillips@google.combd8d7ad2012-03-30 15:18:14 +0000270 case kPicture_DeviceType:
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000271 // fallthrough
272#if SK_ANGLE
273 case kANGLE_DeviceType:
274#endif
robertphillips@google.combd8d7ad2012-03-30 15:18:14 +0000275 break;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000276#if SK_SUPPORT_GPU
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000277 case kGPU_DeviceType:
278 case kNullGPU_DeviceType:
279 if (fCurContext) {
280 canvas->setDevice(new SkGpuDevice(fCurContext,
281 fCurRenderTarget))->unref();
282 } else {
283 return false;
284 }
285 break;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000286#endif
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000287 default:
288 SkASSERT(false);
289 return false;
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000290 }
291 return true;
292 }
293
294 virtual void publishCanvas(SampleWindow::DeviceType dType,
295 SkCanvas* canvas,
296 SampleWindow* win) {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000297#if SK_SUPPORT_GPU
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000298 if (fCurContext) {
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000299 // in case we have queued drawing calls
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000300 fCurContext->flush();
301
302 if (kGPU_DeviceType != dType && kNullGPU_DeviceType != dType) {
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000303 // need to send the raster bits to the (gpu) window
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000304 fCurContext->setRenderTarget(fCurRenderTarget);
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000305 const SkBitmap& bm = win->getBitmap();
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000306 fCurRenderTarget->writePixels(0, 0, bm.width(), bm.height(),
bsalomon@google.com6f379512011-11-16 20:36:03 +0000307 kSkia8888_PM_GrPixelConfig,
308 bm.getPixels(),
309 bm.rowBytes());
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000310 }
311 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000312#endif
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000313
314 win->present();
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000315 }
316
317 virtual void windowSizeChanged(SampleWindow* win) {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000318#if SK_SUPPORT_GPU
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000319 if (fCurContext) {
bsalomon@google.com11959252012-04-06 20:13:38 +0000320 win->attach(fBackend, fMSAASampleCount);
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000321
bsalomon@google.come269f212011-11-07 13:29:52 +0000322 GrPlatformRenderTargetDesc desc;
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000323 desc.fWidth = SkScalarRound(win->width());
324 desc.fHeight = SkScalarRound(win->height());
bsalomon@google.comc4364992011-11-07 15:54:49 +0000325 desc.fConfig = kSkia8888_PM_GrPixelConfig;
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000326 GR_GL_GetIntegerv(fCurIntf, GR_GL_SAMPLES, &desc.fSampleCnt);
327 GR_GL_GetIntegerv(fCurIntf, GR_GL_STENCIL_BITS, &desc.fStencilBits);
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000328 GrGLint buffer;
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000329 GR_GL_GetIntegerv(fCurIntf, GR_GL_FRAMEBUFFER_BINDING, &buffer);
bsalomon@google.come269f212011-11-07 13:29:52 +0000330 desc.fRenderTargetHandle = buffer;
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000331
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000332 SkSafeUnref(fCurRenderTarget);
333 fCurRenderTarget = fCurContext->createPlatformRenderTarget(desc);
bsalomon@google.com74913722011-10-27 20:44:19 +0000334 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000335#endif
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000336 }
337
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000338 virtual GrContext* getGrContext() {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000339#if SK_SUPPORT_GPU
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000340 return fCurContext;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000341#else
342 return NULL;
343#endif
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000344 }
bsalomon@google.com11959252012-04-06 20:13:38 +0000345
346 virtual GrRenderTarget* getGrRenderTarget() SK_OVERRIDE {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000347#if SK_SUPPORT_GPU
bsalomon@google.com11959252012-04-06 20:13:38 +0000348 return fCurRenderTarget;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000349#else
350 return NULL;
351#endif
bsalomon@google.com11959252012-04-06 20:13:38 +0000352 }
353
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000354private:
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000355
356#if SK_SUPPORT_GPU
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000357 GrContext* fCurContext;
358 const GrGLInterface* fCurIntf;
359 GrRenderTarget* fCurRenderTarget;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000360 int fMSAASampleCount;
361#endif
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000362
363 SkOSWindow::SkBackEndTypes fBackend;
364
365 typedef SampleWindow::DeviceManager INHERITED;
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000366};
367
368///////////////
mike@reedtribe.org2eb59522011-04-22 01:59:09 +0000369static const char view_inval_msg[] = "view-inval-msg";
370
Scroggo62b65b02011-06-21 16:01:26 +0000371void SampleWindow::postInvalDelay() {
reed@google.com87fac4a2011-08-04 13:50:17 +0000372 (new SkEvent(view_inval_msg, this->getSinkID()))->postDelay(1);
mike@reedtribe.org2eb59522011-04-22 01:59:09 +0000373}
374
375static bool isInvalEvent(const SkEvent& evt) {
376 return evt.isType(view_inval_msg);
377}
378//////////////////
379
bsalomon@google.com48dd1a22011-10-31 14:18:20 +0000380SkFuncViewFactory::SkFuncViewFactory(SkViewCreateFunc func)
381 : fCreateFunc(func) {
382}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000383
bsalomon@google.com8301de12011-10-31 16:47:13 +0000384SkView* SkFuncViewFactory::operator() () const {
bsalomon@google.com48dd1a22011-10-31 14:18:20 +0000385 return (*fCreateFunc)();
386}
387
388#include "GMSampleView.h"
389
390SkGMSampleViewFactory::SkGMSampleViewFactory(GMFactoryFunc func)
391 : fFunc(func) {
392}
393
394SkView* SkGMSampleViewFactory::operator() () const {
395 return new GMSampleView(fFunc(NULL));
396}
397
398SkViewRegister* SkViewRegister::gHead;
399SkViewRegister::SkViewRegister(SkViewFactory* fact) : fFact(fact) {
400 fFact->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000401 fChain = gHead;
402 gHead = this;
403}
404
bsalomon@google.com48dd1a22011-10-31 14:18:20 +0000405SkViewRegister::SkViewRegister(SkViewCreateFunc func) {
406 fFact = new SkFuncViewFactory(func);
407 fChain = gHead;
408 gHead = this;
409}
410
411SkViewRegister::SkViewRegister(GMFactoryFunc func) {
412 fFact = new SkGMSampleViewFactory(func);
413 fChain = gHead;
414 gHead = this;
415}
416
417class AutoUnrefArray {
418public:
419 AutoUnrefArray() {}
420 ~AutoUnrefArray() {
421 int count = fObjs.count();
422 for (int i = 0; i < count; ++i) {
423 fObjs[i]->unref();
424 }
425 }
426 SkRefCnt*& push_back() { return *fObjs.append(); }
chudy@google.com4605a3f2012-08-01 17:58:01 +0000427
bsalomon@google.com48dd1a22011-10-31 14:18:20 +0000428private:
429 SkTDArray<SkRefCnt*> fObjs;
430};
431
432// registers GMs as Samples
433// This can't be performed during static initialization because it could be
434// run before GMRegistry has been fully built.
caryclark@google.com02939ce2012-06-06 12:09:51 +0000435static void SkGMRegistyToSampleRegistry() {
bsalomon@google.com48dd1a22011-10-31 14:18:20 +0000436 static bool gOnce;
chudy@google.com4605a3f2012-08-01 17:58:01 +0000437 static AutoUnrefArray fRegisters;
bsalomon@google.com48dd1a22011-10-31 14:18:20 +0000438
439 if (!gOnce) {
440 const skiagm::GMRegistry* gmreg = skiagm::GMRegistry::Head();
441 while (gmreg) {
442 fRegisters.push_back() = new SkViewRegister(gmreg->factory());
443 gmreg = gmreg->next();
444 }
445 gOnce = true;
446 }
447}
448
reed@google.com29038ed2011-07-06 17:56:47 +0000449#if 0
reed@google.comf0b5f682011-03-11 20:08:25 +0000450#include <CoreFoundation/CoreFoundation.h>
451#include <CoreFoundation/CFURLAccess.h>
452
453static void testpdf() {
454 CFStringRef path = CFStringCreateWithCString(NULL, "/test.pdf",
455 kCFStringEncodingUTF8);
456 CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path,
457 kCFURLPOSIXPathStyle,
458 false);
459 CFRelease(path);
460 CGRect box = CGRectMake(0, 0, 8*72, 10*72);
461 CGContextRef cg = CGPDFContextCreateWithURL(url, &box, NULL);
462 CFRelease(url);
463
464 CGContextBeginPage(cg, &box);
465 CGRect r = CGRectMake(10, 10, 40 + 0.5, 50 + 0.5);
466 CGContextFillEllipseInRect(cg, r);
467 CGContextEndPage(cg);
468 CGContextRelease(cg);
469
470 if (false) {
471 SkBitmap bm;
472 bm.setConfig(SkBitmap::kA8_Config, 64, 64);
473 bm.allocPixels();
474 bm.eraseColor(0);
475
476 SkCanvas canvas(bm);
477
478 }
479}
480#endif
481
482//////////////////////////////////////////////////////////////////////////////
483
reed@google.com569e0432011-04-05 13:07:03 +0000484enum FlipAxisEnum {
485 kFlipAxis_X = (1 << 0),
486 kFlipAxis_Y = (1 << 1)
487};
488
reed@google.comf0b5f682011-03-11 20:08:25 +0000489#include "SkDrawFilter.h"
490
reed@google.com569e0432011-04-05 13:07:03 +0000491class FlagsDrawFilter : public SkDrawFilter {
reed@google.comf0b5f682011-03-11 20:08:25 +0000492public:
yangsu@google.comdb03eaa2011-08-08 15:37:23 +0000493 FlagsDrawFilter(SkOSMenu::TriState lcd, SkOSMenu::TriState aa, SkOSMenu::TriState filter,
494 SkOSMenu::TriState hinting) :
reed@google.com09e3baa2011-05-18 12:04:31 +0000495 fLCDState(lcd), fAAState(aa), fFilterState(filter), fHintingState(hinting) {}
reed@google.comf0b5f682011-03-11 20:08:25 +0000496
mike@reedtribe.org3ce59dc2011-04-08 00:38:05 +0000497 virtual void filter(SkPaint* paint, Type t) {
yangsu@google.comdb03eaa2011-08-08 15:37:23 +0000498 if (kText_Type == t && SkOSMenu::kMixedState != fLCDState) {
499 paint->setLCDRenderText(SkOSMenu::kOnState == fLCDState);
reed@google.com569e0432011-04-05 13:07:03 +0000500 }
yangsu@google.comdb03eaa2011-08-08 15:37:23 +0000501 if (SkOSMenu::kMixedState != fAAState) {
502 paint->setAntiAlias(SkOSMenu::kOnState == fAAState);
reed@google.comf0b5f682011-03-11 20:08:25 +0000503 }
yangsu@google.comdb03eaa2011-08-08 15:37:23 +0000504 if (SkOSMenu::kMixedState != fFilterState) {
505 paint->setFilterBitmap(SkOSMenu::kOnState == fFilterState);
reed@google.com176753a2011-05-17 15:32:04 +0000506 }
yangsu@google.comdb03eaa2011-08-08 15:37:23 +0000507 if (SkOSMenu::kMixedState != fHintingState) {
508 paint->setHinting(SkOSMenu::kOnState == fHintingState ?
reed@google.com09e3baa2011-05-18 12:04:31 +0000509 SkPaint::kNormal_Hinting :
510 SkPaint::kSlight_Hinting);
511 }
reed@google.comf0b5f682011-03-11 20:08:25 +0000512 }
513
514private:
yangsu@google.comdb03eaa2011-08-08 15:37:23 +0000515 SkOSMenu::TriState fLCDState;
516 SkOSMenu::TriState fAAState;
517 SkOSMenu::TriState fFilterState;
518 SkOSMenu::TriState fHintingState;
reed@google.comf0b5f682011-03-11 20:08:25 +0000519};
520
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521//////////////////////////////////////////////////////////////////////////////
522
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000523#define MAX_ZOOM_LEVEL 8
524#define MIN_ZOOM_LEVEL -8
525
reed@android.comf2b98d62010-12-20 18:26:13 +0000526static const char gCharEvtName[] = "SampleCode_Char_Event";
527static const char gKeyEvtName[] = "SampleCode_Key_Event";
reed@android.com8a1c16f2008-12-17 15:59:43 +0000528static const char gTitleEvtName[] = "SampleCode_Title_Event";
529static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event";
reed@android.comf2b98d62010-12-20 18:26:13 +0000530static const char gFastTextEvtName[] = "SampleCode_FastText_Event";
reed@google.com2072db82011-11-08 15:18:10 +0000531static const char gUpdateWindowTitleEvtName[] = "SampleCode_UpdateWindowTitle";
reed@android.comf2b98d62010-12-20 18:26:13 +0000532
533bool SampleCode::CharQ(const SkEvent& evt, SkUnichar* outUni) {
534 if (evt.isType(gCharEvtName, sizeof(gCharEvtName) - 1)) {
535 if (outUni) {
536 *outUni = evt.getFast32();
537 }
538 return true;
539 }
540 return false;
541}
542
543bool SampleCode::KeyQ(const SkEvent& evt, SkKey* outKey) {
544 if (evt.isType(gKeyEvtName, sizeof(gKeyEvtName) - 1)) {
545 if (outKey) {
546 *outKey = (SkKey)evt.getFast32();
547 }
548 return true;
549 }
550 return false;
551}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552
553bool SampleCode::TitleQ(const SkEvent& evt) {
554 return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1);
555}
556
557void SampleCode::TitleR(SkEvent* evt, const char title[]) {
558 SkASSERT(evt && TitleQ(*evt));
559 evt->setString(gTitleEvtName, title);
560}
561
yangsu@google.comdb03eaa2011-08-08 15:37:23 +0000562bool SampleCode::RequestTitle(SkView* view, SkString* title) {
563 SkEvent evt(gTitleEvtName);
564 if (view->doQuery(&evt)) {
565 title->set(evt.findString(gTitleEvtName));
566 return true;
567 }
568 return false;
569}
570
reed@android.com8a1c16f2008-12-17 15:59:43 +0000571bool SampleCode::PrefSizeQ(const SkEvent& evt) {
572 return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1);
573}
574
575void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) {
576 SkASSERT(evt && PrefSizeQ(*evt));
577 SkScalar size[2];
578 size[0] = width;
579 size[1] = height;
580 evt->setScalars(gPrefSizeEvtName, 2, size);
581}
582
reed@android.comf2b98d62010-12-20 18:26:13 +0000583bool SampleCode::FastTextQ(const SkEvent& evt) {
584 return evt.isType(gFastTextEvtName, sizeof(gFastTextEvtName) - 1);
585}
586
587///////////////////////////////////////////////////////////////////////////////
588
reed@android.com44177402009-11-23 21:07:51 +0000589static SkMSec gAnimTime;
reed@android.comf2b98d62010-12-20 18:26:13 +0000590static SkMSec gAnimTimePrev;
591
reed@android.com44177402009-11-23 21:07:51 +0000592SkMSec SampleCode::GetAnimTime() { return gAnimTime; }
reed@android.comf2b98d62010-12-20 18:26:13 +0000593SkMSec SampleCode::GetAnimTimeDelta() { return gAnimTime - gAnimTimePrev; }
594SkScalar SampleCode::GetAnimSecondsDelta() {
595 return SkDoubleToScalar(GetAnimTimeDelta() / 1000.0);
596}
reed@android.com44177402009-11-23 21:07:51 +0000597
598SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000599 // since gAnimTime can be up to 32 bits, we can't convert it to a float
600 // or we'll lose the low bits. Hence we use doubles for the intermediate
601 // calculations
602 double seconds = (double)gAnimTime / 1000.0;
603 double value = SkScalarToDouble(speed) * seconds;
reed@android.com44177402009-11-23 21:07:51 +0000604 if (period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000605 value = ::fmod(value, SkScalarToDouble(period));
reed@android.com44177402009-11-23 21:07:51 +0000606 }
reed@android.comf2b98d62010-12-20 18:26:13 +0000607 return SkDoubleToScalar(value);
reed@android.com44177402009-11-23 21:07:51 +0000608}
609
bsalomon@google.com85003222012-03-28 14:44:37 +0000610SkScalar SampleCode::GetAnimSinScalar(SkScalar amplitude,
611 SkScalar periodInSec,
612 SkScalar phaseInSec) {
613 if (!periodInSec) {
614 return 0;
615 }
616 double t = (double)gAnimTime / 1000.0 + phaseInSec;
617 t *= SkScalarToFloat(2 * SK_ScalarPI) / periodInSec;
618 amplitude = SK_ScalarHalf * amplitude;
619 return SkScalarMul(amplitude, SkDoubleToScalar(sin(t))) + amplitude;
620}
621
reed@google.com3cec4d72011-07-06 13:59:47 +0000622GrContext* SampleCode::GetGr() {
623 return gSampleWindow ? gSampleWindow->getGrContext() : NULL;
624}
625
bsalomon@google.com48dd1a22011-10-31 14:18:20 +0000626// some GMs rely on having a skiagm::GetGr function defined
627namespace skiagm {
caryclark@google.com02939ce2012-06-06 12:09:51 +0000628 // FIXME: this should be moved into a header
629 GrContext* GetGr();
bsalomon@google.com48dd1a22011-10-31 14:18:20 +0000630 GrContext* GetGr() { return SampleCode::GetGr(); }
631}
632
reed@android.com8a1c16f2008-12-17 15:59:43 +0000633//////////////////////////////////////////////////////////////////////////////
634
reed@android.comf2b98d62010-12-20 18:26:13 +0000635static SkView* curr_view(SkWindow* wind) {
636 SkView::F2BIter iter(wind);
637 return iter.next();
638}
639
mike@reedtribe.org6f6e8c32011-12-27 22:33:50 +0000640static bool curr_title(SkWindow* wind, SkString* title) {
641 SkView* view = curr_view(wind);
642 if (view) {
643 SkEvent evt(gTitleEvtName);
644 if (view->doQuery(&evt)) {
645 title->set(evt.findString(gTitleEvtName));
646 return true;
647 }
648 }
649 return false;
650}
651
Scroggo2c8208f2011-06-15 16:49:08 +0000652void SampleWindow::setZoomCenter(float x, float y)
653{
654 fZoomCenterX = SkFloatToScalar(x);
655 fZoomCenterY = SkFloatToScalar(y);
656}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000657
Scroggo0f185c22011-03-24 18:35:50 +0000658bool SampleWindow::zoomIn()
659{
660 // Arbitrarily decided
661 if (fFatBitsScale == 25) return false;
662 fFatBitsScale++;
663 this->inval(NULL);
664 return true;
665}
666
667bool SampleWindow::zoomOut()
668{
669 if (fFatBitsScale == 1) return false;
670 fFatBitsScale--;
671 this->inval(NULL);
672 return true;
673}
674
Scroggo0f185c22011-03-24 18:35:50 +0000675void SampleWindow::updatePointer(int x, int y)
676{
677 fMouseX = x;
678 fMouseY = y;
679 if (fShowZoomer) {
680 this->inval(NULL);
681 }
682}
683
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000684static inline SampleWindow::DeviceType cycle_devicetype(SampleWindow::DeviceType ct) {
685 static const SampleWindow::DeviceType gCT[] = {
686 SampleWindow::kPicture_DeviceType,
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000687#if SK_SUPPORT_GPU
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000688 SampleWindow::kGPU_DeviceType,
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000689#if SK_ANGLE
690 SampleWindow::kANGLE_DeviceType,
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000691#endif // SK_ANGLE
bsalomon@google.com74913722011-10-27 20:44:19 +0000692 SampleWindow::kRaster_DeviceType, // skip the null gpu device in normal cycling
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000693#endif // SK_SUPPORT_GPU
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000694 SampleWindow::kRaster_DeviceType
reed@android.com8a1c16f2008-12-17 15:59:43 +0000695 };
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000696 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gCT) == SampleWindow::kDeviceTypeCnt, array_size_mismatch);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000697 return gCT[ct];
698}
699
robertphillips@google.com8570b5c2012-03-20 17:40:58 +0000700static void usage(const char * argv0) {
chudy@google.com4605a3f2012-08-01 17:58:01 +0000701 SkDebugf("%s [--slide sampleName] [-i resourcePath] [--msaa sampleCount] [--pictureDir dirPath] [--picture path]\n", argv0);
robertphillips@google.com8570b5c2012-03-20 17:40:58 +0000702 SkDebugf(" sampleName: sample at which to start.\n");
703 SkDebugf(" resourcePath: directory that stores image resources.\n");
bsalomon@google.com11959252012-04-06 20:13:38 +0000704 SkDebugf(" msaa: request multisampling with the given sample count.\n");
chudy@google.com4605a3f2012-08-01 17:58:01 +0000705 SkDebugf(" dirPath: path to directory skia pictures are read from\n");
706 SkDebugf(" path: path to skia picture\n");
robertphillips@google.com8570b5c2012-03-20 17:40:58 +0000707}
708
chudy@google.com4605a3f2012-08-01 17:58:01 +0000709SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* devManager)
robertphillips@google.com4750fa52012-04-10 13:34:11 +0000710 : INHERITED(hwnd)
711 , fDevManager(NULL) {
robertphillips@google.com8570b5c2012-03-20 17:40:58 +0000712
reed@google.com1830c7a2012-06-04 12:05:43 +0000713 this->registerPictFileSamples(argv, argc);
chudy@google.com4605a3f2012-08-01 17:58:01 +0000714 this->registerPictFileSample(argv, argc);
robertphillips@google.com76d40212012-03-22 14:12:15 +0000715 SkGMRegistyToSampleRegistry();
716 {
717 const SkViewRegister* reg = SkViewRegister::Head();
718 while (reg) {
719 *fSamples.append() = reg->factory();
720 reg = reg->next();
721 }
722 }
723
robertphillips@google.com8570b5c2012-03-20 17:40:58 +0000724 const char* resourcePath = NULL;
725 fCurrIndex = -1;
bsalomon@google.com11959252012-04-06 20:13:38 +0000726 fMSAASampleCount = 0;
robertphillips@google.com8570b5c2012-03-20 17:40:58 +0000727
728 const char* const commandName = argv[0];
729 char* const* stop = argv + argc;
730 for (++argv; argv < stop; ++argv) {
731 if (strcmp(*argv, "-i") == 0) {
732 argv++;
733 if (argv < stop && **argv) {
734 resourcePath = *argv;
735 }
robertphillips@google.com76d40212012-03-22 14:12:15 +0000736 } else if (strcmp(*argv, "--slide") == 0) {
737 argv++;
738 if (argv < stop && **argv) {
739 fCurrIndex = findByTitle(*argv);
740 if (fCurrIndex < 0) {
741 fprintf(stderr, "Unknown sample \"%s\"\n", *argv);
robertphillips@google.com7265e722012-05-03 18:22:28 +0000742 listTitles();
robertphillips@google.com76d40212012-03-22 14:12:15 +0000743 }
robertphillips@google.com8570b5c2012-03-20 17:40:58 +0000744 }
bsalomon@google.com11959252012-04-06 20:13:38 +0000745 } else if (strcmp(*argv, "--msaa") == 0) {
746 ++argv;
747 if (argv < stop && **argv) {
748 fMSAASampleCount = atoi(*argv);
749 }
robertphillips@google.com7265e722012-05-03 18:22:28 +0000750 } else if (strcmp(*argv, "--list") == 0) {
751 listTitles();
bsalomon@google.com11959252012-04-06 20:13:38 +0000752 }
robertphillips@google.comd3b9fbb2012-03-28 16:19:11 +0000753 else {
robertphillips@google.com76d40212012-03-22 14:12:15 +0000754 usage(commandName);
robertphillips@google.com8570b5c2012-03-20 17:40:58 +0000755 }
756 }
757
758 if (fCurrIndex < 0) {
759 SkString title;
760 if (readTitleFromPrefs(&title)) {
761 fCurrIndex = findByTitle(title.c_str());
762 }
763 }
764
765 if (fCurrIndex < 0) {
766 fCurrIndex = 0;
767 }
768
reed@google.com3cec4d72011-07-06 13:59:47 +0000769 gSampleWindow = this;
770
yangsu@google.com1f394212011-06-01 18:03:34 +0000771#ifdef PIPE_FILE
772 //Clear existing file or create file if it doesn't exist
773 FILE* f = fopen(FILE_PATH, "wb");
774 fclose(f);
775#endif
chudy@google.com4605a3f2012-08-01 17:58:01 +0000776
reed@android.com8a1c16f2008-12-17 15:59:43 +0000777 fPicture = NULL;
chudy@google.com4605a3f2012-08-01 17:58:01 +0000778
robertphillips@google.combd8d7ad2012-03-30 15:18:14 +0000779 fDeviceType = kRaster_DeviceType;
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000780
781#if DEFAULT_TO_GPU
782 fDeviceType = kGPU_DeviceType;
reed@android.comf2b98d62010-12-20 18:26:13 +0000783#endif
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000784#if SK_ANGLE && DEFAULT_TO_ANGLE
785 fDeviceType = kANGLE_DeviceType;
786#endif
787
reed@android.com8a1c16f2008-12-17 15:59:43 +0000788 fUseClip = false;
reed@android.come522ca52009-11-23 20:10:41 +0000789 fNClip = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000790 fAnimating = false;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000791 fRotate = false;
bsalomon@google.come8f09102011-09-08 18:48:12 +0000792 fPerspAnim = false;
793 fPerspAnimTime = 0;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000794 fScale = false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000795 fRequestGrabImage = false;
scroggo@google.comb073d922012-06-08 15:35:03 +0000796 fPipeState = SkOSMenu::kOffState;
reed@google.com67b89ee2012-08-15 14:41:58 +0000797 fTilingState = SkOSMenu::kOffState;
mike@reedtribe.org2eb59522011-04-22 01:59:09 +0000798 fMeasureFPS = false;
yangsu@google.comdb03eaa2011-08-08 15:37:23 +0000799 fLCDState = SkOSMenu::kMixedState;
800 fAAState = SkOSMenu::kMixedState;
801 fFilterState = SkOSMenu::kMixedState;
802 fHintingState = SkOSMenu::kMixedState;
reed@google.com569e0432011-04-05 13:07:03 +0000803 fFlipAxis = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000804 fScrollTestX = fScrollTestY = 0;
805
Scroggo0f185c22011-03-24 18:35:50 +0000806 fMouseX = fMouseY = 0;
mike@reedtribe.org3ce59dc2011-04-08 00:38:05 +0000807 fFatBitsScale = 8;
Scroggo0f185c22011-03-24 18:35:50 +0000808 fTypeface = SkTypeface::CreateFromTypeface(NULL, SkTypeface::kBold);
809 fShowZoomer = false;
chudy@google.com4605a3f2012-08-01 17:58:01 +0000810
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000811 fZoomLevel = 0;
812 fZoomScale = SK_Scalar1;
chudy@google.com4605a3f2012-08-01 17:58:01 +0000813
yangsu@google.comdb03eaa2011-08-08 15:37:23 +0000814 fMagnify = false;
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000815 fDebugger = false;
chudy@google.com4605a3f2012-08-01 17:58:01 +0000816
Scroggo8ac0d542011-06-21 14:44:57 +0000817 fSaveToPdf = false;
818 fPdfCanvas = NULL;
819
yangsu@google.comdb03eaa2011-08-08 15:37:23 +0000820 fTransitionNext = 6;
821 fTransitionPrev = 2;
chudy@google.com4605a3f2012-08-01 17:58:01 +0000822
yangsu@google.com921091f2011-08-02 13:39:12 +0000823 int sinkID = this->getSinkID();
scroggo@google.com7dadc742012-04-18 14:07:57 +0000824 fAppMenu = new SkOSMenu;
825 fAppMenu->setTitle("Global Settings");
yangsu@google.comdb03eaa2011-08-08 15:37:23 +0000826 int itemID;
chudy@google.com4605a3f2012-08-01 17:58:01 +0000827
828 itemID =fAppMenu->appendList("Device Type", "Device Type", sinkID, 0,
829 "Raster", "Picture", "OpenGL",
robertphillips@google.comb442a6d2012-04-02 19:24:21 +0000830#if SK_ANGLE
831 "ANGLE",
832#endif
833 NULL);
scroggo@google.com7dadc742012-04-18 14:07:57 +0000834 fAppMenu->assignKeyEquivalentToItem(itemID, 'd');
835 itemID = fAppMenu->appendTriState("AA", "AA", sinkID, fAAState);
836 fAppMenu->assignKeyEquivalentToItem(itemID, 'b');
837 itemID = fAppMenu->appendTriState("LCD", "LCD", sinkID, fLCDState);
838 fAppMenu->assignKeyEquivalentToItem(itemID, 'l');
839 itemID = fAppMenu->appendTriState("Filter", "Filter", sinkID, fFilterState);
840 fAppMenu->assignKeyEquivalentToItem(itemID, 'n');
841 itemID = fAppMenu->appendTriState("Hinting", "Hinting", sinkID, fHintingState);
842 fAppMenu->assignKeyEquivalentToItem(itemID, 'h');
reed@google.com67b89ee2012-08-15 14:41:58 +0000843
scroggo@google.comb073d922012-06-08 15:35:03 +0000844 fUsePipeMenuItemID = fAppMenu->appendTriState("Pipe", "Pipe" , sinkID,
chudy@google.com4605a3f2012-08-01 17:58:01 +0000845 fPipeState);
scroggo@google.comb073d922012-06-08 15:35:03 +0000846 fAppMenu->assignKeyEquivalentToItem(fUsePipeMenuItemID, 'P');
reed@google.com67b89ee2012-08-15 14:41:58 +0000847
848 itemID = fAppMenu->appendTriState("Tiling", "Tiling", sinkID, fTilingState);
849 fAppMenu->assignKeyEquivalentToItem(itemID, 't');
850
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000851#ifdef DEBUGGER
scroggo@google.com7dadc742012-04-18 14:07:57 +0000852 itemID = fAppMenu->appendSwitch("Debugger", "Debugger", sinkID, fDebugger);
853 fAppMenu->assignKeyEquivalentToItem(itemID, 'q');
yangsu@google.comef7bdfa2011-08-12 14:27:47 +0000854#endif
chudy@google.com4605a3f2012-08-01 17:58:01 +0000855 itemID = fAppMenu->appendSwitch("Slide Show", "Slide Show" , sinkID, false);
856 fAppMenu->assignKeyEquivalentToItem(itemID, 'a');
857 itemID = fAppMenu->appendSwitch("Clip", "Clip" , sinkID, fUseClip);
scroggo@google.com7dadc742012-04-18 14:07:57 +0000858 fAppMenu->assignKeyEquivalentToItem(itemID, 'c');
chudy@google.com4605a3f2012-08-01 17:58:01 +0000859 itemID = fAppMenu->appendSwitch("Flip X", "Flip X" , sinkID, false);
scroggo@google.com7dadc742012-04-18 14:07:57 +0000860 fAppMenu->assignKeyEquivalentToItem(itemID, 'x');
861 itemID = fAppMenu->appendSwitch("Flip Y", "Flip Y" , sinkID, false);
862 fAppMenu->assignKeyEquivalentToItem(itemID, 'y');
863 itemID = fAppMenu->appendSwitch("Zoomer", "Zoomer" , sinkID, fShowZoomer);
864 fAppMenu->assignKeyEquivalentToItem(itemID, 'z');
865 itemID = fAppMenu->appendSwitch("Magnify", "Magnify" , sinkID, fMagnify);
866 fAppMenu->assignKeyEquivalentToItem(itemID, 'm');
chudy@google.com4605a3f2012-08-01 17:58:01 +0000867 itemID =fAppMenu->appendList("Transition-Next", "Transition-Next", sinkID,
868 fTransitionNext, "Up", "Up and Right", "Right",
869 "Down and Right", "Down", "Down and Left",
yangsu@google.comdb03eaa2011-08-08 15:37:23 +0000870 "Left", "Up and Left", NULL);
scroggo@google.com7dadc742012-04-18 14:07:57 +0000871 fAppMenu->assignKeyEquivalentToItem(itemID, 'j');
chudy@google.com4605a3f2012-08-01 17:58:01 +0000872 itemID =fAppMenu->appendList("Transition-Prev", "Transition-Prev", sinkID,
873 fTransitionPrev, "Up", "Up and Right", "Right",
874 "Down and Right", "Down", "Down and Left",
yangsu@google.comdb03eaa2011-08-08 15:37:23 +0000875 "Left", "Up and Left", NULL);
scroggo@google.com7dadc742012-04-18 14:07:57 +0000876 fAppMenu->assignKeyEquivalentToItem(itemID, 'k');
877 itemID = fAppMenu->appendAction("Save to PDF", sinkID);
878 fAppMenu->assignKeyEquivalentToItem(itemID, 'e');
chudy@google.com4605a3f2012-08-01 17:58:01 +0000879
scroggo@google.com7dadc742012-04-18 14:07:57 +0000880 this->addMenu(fAppMenu);
881 fSlideMenu = new SkOSMenu;
882 this->addMenu(fSlideMenu);
chudy@google.com4605a3f2012-08-01 17:58:01 +0000883
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000884// this->setConfig(SkBitmap::kRGB_565_Config);
885 this->setConfig(SkBitmap::kARGB_8888_Config);
886 this->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000887 this->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000888
robertphillips@google.com8570b5c2012-03-20 17:40:58 +0000889 skiagm::GM::SetResourcePath(resourcePath);
890
bsalomon@google.com48dd1a22011-10-31 14:18:20 +0000891 this->loadView((*fSamples[fCurrIndex])());
chudy@google.com4605a3f2012-08-01 17:58:01 +0000892
bsalomon@google.com840e9f32011-07-06 21:59:09 +0000893 fPDFData = NULL;
reed@google.comf0b5f682011-03-11 20:08:25 +0000894
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000895 if (NULL == devManager) {
896 fDevManager = new DefaultDeviceManager();
897 } else {
898 devManager->ref();
899 fDevManager = devManager;
900 }
bsalomon@google.com11959252012-04-06 20:13:38 +0000901 fDevManager->setUpBackend(this, fMSAASampleCount);
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000902
Scroggob4490c72011-06-17 13:53:05 +0000903 // If another constructor set our dimensions, ensure that our
904 // onSizeChange gets called.
905 if (this->height() && this->width()) {
906 this->onSizeChange();
907 }
reed@google.com2072db82011-11-08 15:18:10 +0000908
909 // can't call this synchronously, since it may require a subclass to
910 // to implement, or the caller may need us to have returned from the
911 // constructor first. Hence we post an event to ourselves.
912// this->updateTitle();
913 postEventToSink(new SkEvent(gUpdateWindowTitleEvtName), this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000914}
915
916SampleWindow::~SampleWindow() {
917 delete fPicture;
Scroggo8ac0d542011-06-21 14:44:57 +0000918 delete fPdfCanvas;
Scroggo0f185c22011-03-24 18:35:50 +0000919 fTypeface->unref();
reed@google.com29038ed2011-07-06 17:56:47 +0000920
bsalomon@google.com098e96d2011-07-14 14:30:46 +0000921 SkSafeUnref(fDevManager);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000922}
923
reed@google.com1830c7a2012-06-04 12:05:43 +0000924static void make_filepath(SkString* path, const char* dir, const SkString& name) {
925 size_t len = strlen(dir);
926 path->set(dir);
927 if (len > 0 && dir[len - 1] != '/') {
928 path->append("/");
929 }
930 path->append(name);
931}
932
chudy@google.com4605a3f2012-08-01 17:58:01 +0000933void SampleWindow::registerPictFileSample(char** argv, int argc) {
934 const char* pict = NULL;
935
936 for (int i = 0; i < argc; ++i) {
937 if (!strcmp(argv[i], "--picture")) {
938 i += 1;
939 if (i < argc) {
940 pict = argv[i];
941 break;
942 }
943 }
944 }
945 if (pict) {
946 SkString path(pict);
947 *fSamples.append() = new PictFileFactory(path);
948 }
949}
950
reed@google.com1830c7a2012-06-04 12:05:43 +0000951void SampleWindow::registerPictFileSamples(char** argv, int argc) {
952 const char* pictDir = NULL;
953
954 for (int i = 0; i < argc; ++i) {
955 if (!strcmp(argv[i], "--pictureDir")) {
956 i += 1;
957 if (i < argc) {
958 pictDir = argv[i];
959 break;
960 }
961 }
962 }
963 if (pictDir) {
964 SkOSFile::Iter iter(pictDir, "skp");
965 SkString filename;
966 while (iter.next(&filename)) {
967 SkString path;
968 make_filepath(&path, pictDir, filename);
969 *fSamples.append() = new PictFileFactory(path);
970 }
971 }
972}
973
mike@reedtribe.org6f6e8c32011-12-27 22:33:50 +0000974int SampleWindow::findByTitle(const char title[]) {
975 int i, count = fSamples.count();
976 for (i = 0; i < count; i++) {
977 if (getSampleTitle(i).equals(title)) {
978 return i;
979 }
980 }
mike@reedtribe.orgdd52caa2011-12-28 20:02:10 +0000981 return -1;
mike@reedtribe.org6f6e8c32011-12-27 22:33:50 +0000982}
983
robertphillips@google.com7265e722012-05-03 18:22:28 +0000984void SampleWindow::listTitles() {
985 int count = fSamples.count();
986 SkDebugf("All Slides:\n");
987 for (int i = 0; i < count; i++) {
988 SkDebugf(" %s\n", getSampleTitle(i).c_str());
989 }
990}
991
reed@android.com55e76b22009-11-23 21:46:47 +0000992static SkBitmap capture_bitmap(SkCanvas* canvas) {
993 SkBitmap bm;
994 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
995 src.copyTo(&bm, src.config());
996 return bm;
997}
998
999static bool bitmap_diff(SkCanvas* canvas, const SkBitmap& orig,
1000 SkBitmap* diff) {
1001 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001002
reed@android.com55e76b22009-11-23 21:46:47 +00001003 SkAutoLockPixels alp0(src);
1004 SkAutoLockPixels alp1(orig);
1005 for (int y = 0; y < src.height(); y++) {
1006 const void* srcP = src.getAddr(0, y);
1007 const void* origP = orig.getAddr(0, y);
1008 size_t bytes = src.width() * src.bytesPerPixel();
1009 if (memcmp(srcP, origP, bytes)) {
1010 SkDebugf("---------- difference on line %d\n", y);
1011 return true;
1012 }
1013 }
1014 return false;
1015}
1016
Scroggo0f185c22011-03-24 18:35:50 +00001017static void drawText(SkCanvas* canvas, SkString string, SkScalar left, SkScalar top, SkPaint& paint)
1018{
1019 SkColor desiredColor = paint.getColor();
1020 paint.setColor(SK_ColorWHITE);
1021 const char* c_str = string.c_str();
1022 size_t size = string.size();
1023 SkRect bounds;
1024 paint.measureText(c_str, size, &bounds);
1025 bounds.offset(left, top);
1026 SkScalar inset = SkIntToScalar(-2);
1027 bounds.inset(inset, inset);
1028 canvas->drawRect(bounds, paint);
1029 if (desiredColor != SK_ColorBLACK) {
1030 paint.setColor(SK_ColorBLACK);
1031 canvas->drawText(c_str, size, left + SK_Scalar1, top + SK_Scalar1, paint);
1032 }
1033 paint.setColor(desiredColor);
1034 canvas->drawText(c_str, size, left, top, paint);
1035}
1036
reed@android.com44177402009-11-23 21:07:51 +00001037#define XCLIP_N 8
1038#define YCLIP_N 8
reed@android.come522ca52009-11-23 20:10:41 +00001039
1040void SampleWindow::draw(SkCanvas* canvas) {
bsalomon@google.com098e96d2011-07-14 14:30:46 +00001041 if (!fDevManager->prepareCanvas(fDeviceType, canvas, this)) {
1042 return;
1043 }
reed@android.com44177402009-11-23 21:07:51 +00001044 // update the animation time
bsalomon@google.come8f09102011-09-08 18:48:12 +00001045 if (!gAnimTimePrev && !gAnimTime) {
1046 // first time make delta be 0
1047 gAnimTime = SkTime::GetMSecs();
1048 gAnimTimePrev = gAnimTime;
1049 } else {
1050 gAnimTimePrev = gAnimTime;
1051 gAnimTime = SkTime::GetMSecs();
1052 }
chudy@google.com4605a3f2012-08-01 17:58:01 +00001053
reed@google.comf03bb562011-11-11 21:42:12 +00001054 const SkMatrix& localM = fGesture.localM();
1055 if (localM.getType() & SkMatrix::kScale_Mask) {
1056 canvas->setExternalMatrix(&localM);
1057 }
1058 if (fGesture.isActive()) {
1059 this->updateMatrix();
reed@google.com52f57e12011-03-16 12:10:02 +00001060 }
chudy@google.com4605a3f2012-08-01 17:58:01 +00001061
reed@android.come522ca52009-11-23 20:10:41 +00001062 if (fNClip) {
reed@android.com55e76b22009-11-23 21:46:47 +00001063 this->INHERITED::draw(canvas);
1064 SkBitmap orig = capture_bitmap(canvas);
reed@android.come522ca52009-11-23 20:10:41 +00001065
1066 const SkScalar w = this->width();
1067 const SkScalar h = this->height();
1068 const SkScalar cw = w / XCLIP_N;
1069 const SkScalar ch = h / YCLIP_N;
1070 for (int y = 0; y < YCLIP_N; y++) {
reed@android.com55e76b22009-11-23 21:46:47 +00001071 SkRect r;
1072 r.fTop = y * ch;
1073 r.fBottom = (y + 1) * ch;
1074 if (y == YCLIP_N - 1) {
1075 r.fBottom = h;
1076 }
reed@android.come522ca52009-11-23 20:10:41 +00001077 for (int x = 0; x < XCLIP_N; x++) {
1078 SkAutoCanvasRestore acr(canvas, true);
reed@android.com55e76b22009-11-23 21:46:47 +00001079 r.fLeft = x * cw;
1080 r.fRight = (x + 1) * cw;
1081 if (x == XCLIP_N - 1) {
1082 r.fRight = w;
1083 }
reed@android.come522ca52009-11-23 20:10:41 +00001084 canvas->clipRect(r);
1085 this->INHERITED::draw(canvas);
1086 }
1087 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001088
reed@android.com55e76b22009-11-23 21:46:47 +00001089 SkBitmap diff;
1090 if (bitmap_diff(canvas, orig, &diff)) {
1091 }
reed@android.come522ca52009-11-23 20:10:41 +00001092 } else {
1093 this->INHERITED::draw(canvas);
1094 }
bsalomon@google.com098e96d2011-07-14 14:30:46 +00001095 if (fShowZoomer && !fSaveToPdf) {
Scroggo3272ba82011-05-25 20:50:42 +00001096 showZoomer(canvas);
1097 }
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001098 if (fMagnify && !fSaveToPdf) {
1099 magnify(canvas);
1100 }
chudy@google.com4605a3f2012-08-01 17:58:01 +00001101
reed@google.com29038ed2011-07-06 17:56:47 +00001102 // do this last
bsalomon@google.com098e96d2011-07-14 14:30:46 +00001103 fDevManager->publishCanvas(fDeviceType, canvas, this);
Scroggo3272ba82011-05-25 20:50:42 +00001104}
1105
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001106static float clipW = 200;
1107static float clipH = 200;
1108void SampleWindow::magnify(SkCanvas* canvas) {
1109 SkRect r;
1110 int count = canvas->save();
chudy@google.com4605a3f2012-08-01 17:58:01 +00001111
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001112 SkMatrix m = canvas->getTotalMatrix();
robertphillips@google.com07ef9112012-06-04 13:22:14 +00001113 if (!m.invert(&m)) {
1114 return;
1115 }
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001116 SkPoint offset, center;
bsalomon@google.com820e80a2011-10-24 21:09:40 +00001117 SkScalar mouseX = fMouseX * SK_Scalar1;
1118 SkScalar mouseY = fMouseY * SK_Scalar1;
1119 m.mapXY(mouseX - clipW/2, mouseY - clipH/2, &offset);
1120 m.mapXY(mouseX, mouseY, &center);
chudy@google.com4605a3f2012-08-01 17:58:01 +00001121
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001122 r.set(0, 0, clipW * m.getScaleX(), clipH * m.getScaleX());
1123 r.offset(offset.fX, offset.fY);
chudy@google.com4605a3f2012-08-01 17:58:01 +00001124
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001125 SkPaint paint;
1126 paint.setColor(0xFF66AAEE);
1127 paint.setStyle(SkPaint::kStroke_Style);
bsalomon@google.com820e80a2011-10-24 21:09:40 +00001128 paint.setStrokeWidth(10.f * m.getScaleX());
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001129 //lense offset
1130 //canvas->translate(0, -250);
1131 canvas->drawRect(r, paint);
1132 canvas->clipRect(r);
chudy@google.com4605a3f2012-08-01 17:58:01 +00001133
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001134 m = canvas->getTotalMatrix();
1135 m.setTranslate(-center.fX, -center.fY);
bsalomon@google.com820e80a2011-10-24 21:09:40 +00001136 m.postScale(0.5f * fFatBitsScale, 0.5f * fFatBitsScale);
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001137 m.postTranslate(center.fX, center.fY);
1138 canvas->concat(m);
chudy@google.com4605a3f2012-08-01 17:58:01 +00001139
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001140 this->INHERITED::draw(canvas);
chudy@google.com4605a3f2012-08-01 17:58:01 +00001141
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001142 canvas->restoreToCount(count);
1143}
1144
Scroggo3272ba82011-05-25 20:50:42 +00001145void SampleWindow::showZoomer(SkCanvas* canvas) {
Scroggo0f185c22011-03-24 18:35:50 +00001146 int count = canvas->save();
1147 canvas->resetMatrix();
1148 // Ensure the mouse position is on screen.
reed@google.com261b8e22011-04-14 17:53:24 +00001149 int width = SkScalarRound(this->width());
1150 int height = SkScalarRound(this->height());
Scroggo0f185c22011-03-24 18:35:50 +00001151 if (fMouseX >= width) fMouseX = width - 1;
1152 else if (fMouseX < 0) fMouseX = 0;
1153 if (fMouseY >= height) fMouseY = height - 1;
1154 else if (fMouseY < 0) fMouseY = 0;
reed@google.comb36334d2011-05-18 15:07:20 +00001155
Scroggo0f185c22011-03-24 18:35:50 +00001156 SkBitmap bitmap = capture_bitmap(canvas);
reed@google.comb36334d2011-05-18 15:07:20 +00001157 bitmap.lockPixels();
1158
Scroggo0f185c22011-03-24 18:35:50 +00001159 // Find the size of the zoomed in view, forced to be odd, so the examined pixel is in the middle.
mike@reedtribe.org3ce59dc2011-04-08 00:38:05 +00001160 int zoomedWidth = (width >> 1) | 1;
1161 int zoomedHeight = (height >> 1) | 1;
Scroggo0f185c22011-03-24 18:35:50 +00001162 SkIRect src;
1163 src.set(0, 0, zoomedWidth / fFatBitsScale, zoomedHeight / fFatBitsScale);
1164 src.offset(fMouseX - (src.width()>>1), fMouseY - (src.height()>>1));
1165 SkRect dest;
1166 dest.set(0, 0, SkIntToScalar(zoomedWidth), SkIntToScalar(zoomedHeight));
1167 dest.offset(SkIntToScalar(width - zoomedWidth), SkIntToScalar(height - zoomedHeight));
1168 SkPaint paint;
1169 // Clear the background behind our zoomed in view
1170 paint.setColor(SK_ColorWHITE);
1171 canvas->drawRect(dest, paint);
1172 canvas->drawBitmapRect(bitmap, &src, dest);
1173 paint.setColor(SK_ColorBLACK);
1174 paint.setStyle(SkPaint::kStroke_Style);
1175 // Draw a border around the pixel in the middle
1176 SkRect originalPixel;
1177 originalPixel.set(SkIntToScalar(fMouseX), SkIntToScalar(fMouseY), SkIntToScalar(fMouseX + 1), SkIntToScalar(fMouseY + 1));
1178 SkMatrix matrix;
1179 SkRect scalarSrc;
1180 scalarSrc.set(src);
1181 SkColor color = bitmap.getColor(fMouseX, fMouseY);
1182 if (matrix.setRectToRect(scalarSrc, dest, SkMatrix::kFill_ScaleToFit)) {
1183 SkRect pixel;
1184 matrix.mapRect(&pixel, originalPixel);
1185 // TODO Perhaps measure the values and make the outline white if it's "dark"
1186 if (color == SK_ColorBLACK) {
1187 paint.setColor(SK_ColorWHITE);
1188 }
1189 canvas->drawRect(pixel, paint);
1190 }
1191 paint.setColor(SK_ColorBLACK);
1192 // Draw a border around the destination rectangle
1193 canvas->drawRect(dest, paint);
1194 paint.setStyle(SkPaint::kStrokeAndFill_Style);
1195 // Identify the pixel and its color on screen
1196 paint.setTypeface(fTypeface);
1197 paint.setAntiAlias(true);
1198 SkScalar lineHeight = paint.getFontMetrics(NULL);
1199 SkString string;
1200 string.appendf("(%i, %i)", fMouseX, fMouseY);
1201 SkScalar left = dest.fLeft + SkIntToScalar(3);
1202 SkScalar i = SK_Scalar1;
1203 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
1204 // Alpha
1205 i += SK_Scalar1;
1206 string.reset();
1207 string.appendf("A: %X", SkColorGetA(color));
1208 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
1209 // Red
1210 i += SK_Scalar1;
1211 string.reset();
1212 string.appendf("R: %X", SkColorGetR(color));
1213 paint.setColor(SK_ColorRED);
1214 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
1215 // Green
1216 i += SK_Scalar1;
1217 string.reset();
1218 string.appendf("G: %X", SkColorGetG(color));
1219 paint.setColor(SK_ColorGREEN);
1220 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
1221 // Blue
1222 i += SK_Scalar1;
1223 string.reset();
1224 string.appendf("B: %X", SkColorGetB(color));
1225 paint.setColor(SK_ColorBLUE);
1226 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
1227 canvas->restoreToCount(count);
reed@android.come522ca52009-11-23 20:10:41 +00001228}
1229
reed@android.com8a1c16f2008-12-17 15:59:43 +00001230void SampleWindow::onDraw(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001231}
1232
1233#include "SkColorPriv.h"
1234
caryclark@google.com02939ce2012-06-06 12:09:51 +00001235#if 0 // UNUSED
reed@android.com8a1c16f2008-12-17 15:59:43 +00001236static void reverseRedAndBlue(const SkBitmap& bm) {
1237 SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
1238 uint8_t* p = (uint8_t*)bm.getPixels();
1239 uint8_t* stop = p + bm.getSize();
1240 while (p < stop) {
1241 // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
1242 unsigned scale = SkAlpha255To256(p[3]);
1243 unsigned r = p[2];
1244 unsigned b = p[0];
1245 p[0] = SkAlphaMul(r, scale);
1246 p[1] = SkAlphaMul(p[1], scale);
1247 p[2] = SkAlphaMul(b, scale);
1248 p += 4;
1249 }
1250}
caryclark@google.com02939ce2012-06-06 12:09:51 +00001251#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001252
Scroggo8ac0d542011-06-21 14:44:57 +00001253void SampleWindow::saveToPdf()
1254{
1255 fSaveToPdf = true;
1256 this->inval(NULL);
1257}
1258
reed@android.com8a1c16f2008-12-17 15:59:43 +00001259SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
Scroggo8ac0d542011-06-21 14:44:57 +00001260 if (fSaveToPdf) {
1261 const SkBitmap& bmp = canvas->getDevice()->accessBitmap(false);
1262 SkISize size = SkISize::Make(bmp.width(), bmp.height());
1263 SkPDFDevice* pdfDevice = new SkPDFDevice(size, size,
1264 canvas->getTotalMatrix());
1265 fPdfCanvas = new SkCanvas(pdfDevice);
1266 pdfDevice->unref();
1267 canvas = fPdfCanvas;
1268 } else {
bsalomon@google.com098e96d2011-07-14 14:30:46 +00001269 switch (fDeviceType) {
1270 case kRaster_DeviceType:
robertphillips@google.comb442a6d2012-04-02 19:24:21 +00001271 // fallthrough
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001272#if SK_SUPPORT_GPU
bsalomon@google.com098e96d2011-07-14 14:30:46 +00001273 case kGPU_DeviceType:
robertphillips@google.comb442a6d2012-04-02 19:24:21 +00001274 // fallthrough
1275#if SK_ANGLE
1276 case kANGLE_DeviceType:
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001277#endif // SK_ANGLE
1278#endif // SK_SUPPORT_GPU
reed@android.comf2b98d62010-12-20 18:26:13 +00001279 canvas = this->INHERITED::beforeChildren(canvas);
Scroggo8ac0d542011-06-21 14:44:57 +00001280 break;
bsalomon@google.com098e96d2011-07-14 14:30:46 +00001281 case kPicture_DeviceType:
Scroggo8ac0d542011-06-21 14:44:57 +00001282 fPicture = new SkPicture;
1283 canvas = fPicture->beginRecording(9999, 9999);
1284 break;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001285#if SK_SUPPORT_GPU
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001286 case kNullGPU_DeviceType:
1287 break;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001288#endif
robertphillips@google.comb442a6d2012-04-02 19:24:21 +00001289 default:
1290 SkASSERT(false);
1291 break;
reed@google.comac10a2d2010-12-22 21:39:39 +00001292 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001293 }
1294
1295 if (fUseClip) {
1296 canvas->drawColor(0xFFFF88FF);
reed@google.com045e62d2011-10-24 12:19:46 +00001297 canvas->clipPath(fClipPath, SkRegion::kIntersect_Op, true);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298 }
1299
1300 return canvas;
1301}
1302
1303static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
1304 const SkRegion& rgn) {
1305 SkCanvas canvas(bm);
1306 SkRegion inval(rgn);
1307
1308 inval.translate(r.fLeft, r.fTop);
1309 canvas.clipRegion(inval);
1310 canvas.drawColor(0xFFFF8080);
1311}
yangsu@google.com501775e2011-06-24 16:04:50 +00001312#include "SkData.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313void SampleWindow::afterChildren(SkCanvas* orig) {
Scroggo8ac0d542011-06-21 14:44:57 +00001314 if (fSaveToPdf) {
1315 fSaveToPdf = false;
1316 if (fShowZoomer) {
1317 showZoomer(fPdfCanvas);
1318 }
1319 SkString name;
1320 name.printf("%s.pdf", this->getTitle());
1321 SkPDFDocument doc;
1322 SkPDFDevice* device = static_cast<SkPDFDevice*>(fPdfCanvas->getDevice());
1323 doc.appendPage(device);
djsollen@google.com56c69772011-11-08 19:00:26 +00001324#ifdef SK_BUILD_FOR_ANDROID
Scroggo8ac0d542011-06-21 14:44:57 +00001325 name.prepend("/sdcard/");
1326#endif
chudy@google.com4605a3f2012-08-01 17:58:01 +00001327
yangsu@google.com501775e2011-06-24 16:04:50 +00001328#ifdef SK_BUILD_FOR_IOS
1329 SkDynamicMemoryWStream mstream;
1330 doc.emitPDF(&mstream);
yangsu@google.comae8a2e52011-06-24 21:09:39 +00001331 fPDFData = mstream.copyToData();
yangsu@google.com501775e2011-06-24 16:04:50 +00001332#endif
Scroggo8ac0d542011-06-21 14:44:57 +00001333 SkFILEWStream stream(name.c_str());
1334 if (stream.isValid()) {
1335 doc.emitPDF(&stream);
1336 const char* desc = "File saved from Skia SampleApp";
1337 this->onPDFSaved(this->getTitle(), desc, name.c_str());
1338 }
chudy@google.com4605a3f2012-08-01 17:58:01 +00001339
Scroggo8ac0d542011-06-21 14:44:57 +00001340 delete fPdfCanvas;
1341 fPdfCanvas = NULL;
1342
1343 // We took over the draw calls in order to create the PDF, so we need
1344 // to redraw.
1345 this->inval(NULL);
1346 return;
1347 }
chudy@google.com4605a3f2012-08-01 17:58:01 +00001348
reed@android.comf2b98d62010-12-20 18:26:13 +00001349 if (fRequestGrabImage) {
1350 fRequestGrabImage = false;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001351
reed@google.com29038ed2011-07-06 17:56:47 +00001352 SkDevice* device = orig->getDevice();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001353 SkBitmap bmp;
1354 if (device->accessBitmap(false).copyTo(&bmp, SkBitmap::kARGB_8888_Config)) {
reed@android.comf2b98d62010-12-20 18:26:13 +00001355 static int gSampleGrabCounter;
1356 SkString name;
1357 name.printf("sample_grab_%d", gSampleGrabCounter++);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001358 SkImageEncoder::EncodeFile(name.c_str(), bmp,
reed@android.comf2b98d62010-12-20 18:26:13 +00001359 SkImageEncoder::kPNG_Type, 100);
1360 }
1361 }
1362
bsalomon@google.com098e96d2011-07-14 14:30:46 +00001363 if (kPicture_DeviceType == fDeviceType) {
1364 if (true) {
1365 SkPicture* pict = new SkPicture(*fPicture);
1366 fPicture->unref();
reed@google.come23f1942011-12-08 19:36:00 +00001367 this->installDrawFilter(orig);
bsalomon@google.com098e96d2011-07-14 14:30:46 +00001368 orig->drawPicture(*pict);
1369 pict->unref();
1370 } else if (true) {
1371 SkDynamicMemoryWStream ostream;
1372 fPicture->serialize(&ostream);
1373 fPicture->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001374
bsalomon@google.com098e96d2011-07-14 14:30:46 +00001375 SkAutoDataUnref data(ostream.copyToData());
robertphillips@google.com59f46b82012-07-10 17:30:58 +00001376 SkMemoryStream istream(data->data(), data->size());
bsalomon@google.com098e96d2011-07-14 14:30:46 +00001377 SkPicture pict(&istream);
1378 orig->drawPicture(pict);
1379 } else {
1380 fPicture->draw(orig);
1381 fPicture->unref();
1382 }
1383 fPicture = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001384 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001385
reed@google.com17d7aec2011-04-25 14:31:44 +00001386 // Do this after presentGL and other finishing, rather than in afterChild
1387 if (fMeasureFPS && fMeasureFPS_Time) {
1388 fMeasureFPS_Time = SkTime::GetMSecs() - fMeasureFPS_Time;
1389 this->updateTitle();
Scroggo62b65b02011-06-21 16:01:26 +00001390 this->postInvalDelay();
reed@google.com17d7aec2011-04-25 14:31:44 +00001391 }
1392
1393 // if ((fScrollTestX | fScrollTestY) != 0)
reed@android.comf2b98d62010-12-20 18:26:13 +00001394 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001395 const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
1396 int dx = fScrollTestX * 7;
1397 int dy = fScrollTestY * 7;
1398 SkIRect r;
1399 SkRegion inval;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001400
reed@android.com8a1c16f2008-12-17 15:59:43 +00001401 r.set(50, 50, 50+100, 50+100);
1402 bm.scrollRect(&r, dx, dy, &inval);
1403 paint_rgn(bm, r, inval);
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001404 }
1405#ifdef DEBUGGER
1406 SkView* curr = curr_view(this);
1407 if (fDebugger && !is_debugger(curr) && !is_transition(curr) && !is_overview(curr)) {
1408 //Stop Pipe when fDebugger is active
scroggo@google.comb073d922012-06-08 15:35:03 +00001409 if (fPipeState != SkOSMenu::kOffState) {
1410 fPipeState = SkOSMenu::kOffState;
1411 (void)SampleView::SetUsePipe(curr, fPipeState);
1412 fAppMenu->getItemByID(fUsePipeMenuItemID)->setTriState(fPipeState);
1413 this->onUpdateMenu(fAppMenu);
1414 }
chudy@google.com4605a3f2012-08-01 17:58:01 +00001415
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001416 //Reset any transformations
1417 fGesture.stop();
1418 fGesture.reset();
chudy@google.com4605a3f2012-08-01 17:58:01 +00001419
1420 this->loadView(create_debugger(gTempDataStore.begin(),
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001421 gTempDataStore.count()));
1422 }
1423#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424}
1425
reed@android.com6c5f6f22009-08-14 16:08:38 +00001426void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
1427 if (fScale) {
1428 SkScalar scale = SK_Scalar1 * 7 / 10;
1429 SkScalar cx = this->width() / 2;
1430 SkScalar cy = this->height() / 2;
1431 canvas->translate(cx, cy);
1432 canvas->scale(scale, scale);
1433 canvas->translate(-cx, -cy);
1434 }
1435 if (fRotate) {
1436 SkScalar cx = this->width() / 2;
1437 SkScalar cy = this->height() / 2;
1438 canvas->translate(cx, cy);
1439 canvas->rotate(SkIntToScalar(30));
1440 canvas->translate(-cx, -cy);
1441 }
bsalomon@google.come8f09102011-09-08 18:48:12 +00001442 if (fPerspAnim) {
bsalomon@google.com6fb736f2011-09-16 18:51:57 +00001443 fPerspAnimTime += SampleCode::GetAnimSecondsDelta();
1444
1445 static const SkScalar gAnimPeriod = 10 * SK_Scalar1;
1446 static const SkScalar gAnimMag = SK_Scalar1 / 1000;
1447 SkScalar t = SkScalarMod(fPerspAnimTime, gAnimPeriod);
1448 if (SkScalarFloorToInt(SkScalarDiv(fPerspAnimTime, gAnimPeriod)) & 0x1) {
1449 t = gAnimPeriod - t;
1450 }
1451 t = 2 * t - gAnimPeriod;
1452 t = SkScalarMul(SkScalarDiv(t, gAnimPeriod), gAnimMag);
1453 SkMatrix m;
1454 m.reset();
1455 m.setPerspY(t);
bsalomon@google.come8f09102011-09-08 18:48:12 +00001456 canvas->concat(m);
1457 }
reed@google.comf0b5f682011-03-11 20:08:25 +00001458
reed@google.come23f1942011-12-08 19:36:00 +00001459 this->installDrawFilter(canvas);
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001460
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001461 if (fMeasureFPS) {
reed@google.comf2183392011-04-22 14:10:48 +00001462 fMeasureFPS_Time = 0; // 0 means the child is not aware of repeat-draw
1463 if (SampleView::SetRepeatDraw(child, FPS_REPEAT_COUNT)) {
1464 fMeasureFPS_Time = SkTime::GetMSecs();
1465 }
1466 } else {
1467 (void)SampleView::SetRepeatDraw(child, 1);
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001468 }
bsalomon@google.come8f09102011-09-08 18:48:12 +00001469 if (fPerspAnim) {
1470 this->inval(NULL);
1471 }
reed@android.com6c5f6f22009-08-14 16:08:38 +00001472}
1473
1474void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) {
reed@google.comf0b5f682011-03-11 20:08:25 +00001475 canvas->setDrawFilter(NULL);
reed@android.com6c5f6f22009-08-14 16:08:38 +00001476}
1477
reed@android.com8a1c16f2008-12-17 15:59:43 +00001478static SkBitmap::Config gConfigCycle[] = {
1479 SkBitmap::kNo_Config, // none -> none
1480 SkBitmap::kNo_Config, // a1 -> none
1481 SkBitmap::kNo_Config, // a8 -> none
1482 SkBitmap::kNo_Config, // index8 -> none
1483 SkBitmap::kARGB_4444_Config, // 565 -> 4444
1484 SkBitmap::kARGB_8888_Config, // 4444 -> 8888
1485 SkBitmap::kRGB_565_Config // 8888 -> 565
1486};
1487
1488static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
1489 return gConfigCycle[c];
1490}
1491
djsollen@google.come32b5832011-06-13 16:58:40 +00001492void SampleWindow::changeZoomLevel(float delta) {
1493 fZoomLevel += SkFloatToScalar(delta);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001494 if (fZoomLevel > 0) {
djsollen@google.come32b5832011-06-13 16:58:40 +00001495 fZoomLevel = SkMinScalar(fZoomLevel, MAX_ZOOM_LEVEL);
1496 fZoomScale = fZoomLevel + SK_Scalar1;
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001497 } else if (fZoomLevel < 0) {
djsollen@google.come32b5832011-06-13 16:58:40 +00001498 fZoomLevel = SkMaxScalar(fZoomLevel, MIN_ZOOM_LEVEL);
1499 fZoomScale = SK_Scalar1 / (SK_Scalar1 - fZoomLevel);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001500 } else {
1501 fZoomScale = SK_Scalar1;
1502 }
reed@google.comf03bb562011-11-11 21:42:12 +00001503 this->updateMatrix();
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001504}
1505
reed@google.comf03bb562011-11-11 21:42:12 +00001506void SampleWindow::updateMatrix(){
1507 SkMatrix m;
1508 m.reset();
1509 if (fZoomLevel) {
1510 SkPoint center;
1511 //m = this->getLocalMatrix();//.invert(&m);
1512 m.mapXY(fZoomCenterX, fZoomCenterY, &center);
1513 SkScalar cx = center.fX;
1514 SkScalar cy = center.fY;
chudy@google.com4605a3f2012-08-01 17:58:01 +00001515
reed@google.comf03bb562011-11-11 21:42:12 +00001516 m.setTranslate(-cx, -cy);
1517 m.postScale(fZoomScale, fZoomScale);
1518 m.postTranslate(cx, cy);
1519 }
chudy@google.com4605a3f2012-08-01 17:58:01 +00001520
reed@google.comf03bb562011-11-11 21:42:12 +00001521 if (fFlipAxis) {
1522 m.preTranslate(fZoomCenterX, fZoomCenterY);
1523 if (fFlipAxis & kFlipAxis_X) {
1524 m.preScale(-SK_Scalar1, SK_Scalar1);
1525 }
1526 if (fFlipAxis & kFlipAxis_Y) {
1527 m.preScale(SK_Scalar1, -SK_Scalar1);
1528 }
1529 m.preTranslate(-fZoomCenterX, -fZoomCenterY);
1530 //canvas->concat(m);
1531 }
1532 // Apply any gesture matrix
1533 m.preConcat(fGesture.localM());
1534 m.preConcat(fGesture.globalM());
chudy@google.com4605a3f2012-08-01 17:58:01 +00001535
reed@google.comf03bb562011-11-11 21:42:12 +00001536 this->setLocalMatrix(m);
chudy@google.com4605a3f2012-08-01 17:58:01 +00001537
reed@google.comf03bb562011-11-11 21:42:12 +00001538 this->updateTitle();
1539 this->inval(NULL);
1540}
Scroggo2c8208f2011-06-15 16:49:08 +00001541bool SampleWindow::previousSample() {
Scroggo62b65b02011-06-21 16:01:26 +00001542 fCurrIndex = (fCurrIndex - 1 + fSamples.count()) % fSamples.count();
chudy@google.com4605a3f2012-08-01 17:58:01 +00001543 this->loadView(create_transition(curr_view(this), (*fSamples[fCurrIndex])(),
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001544 fTransitionPrev));
Scroggo2c8208f2011-06-15 16:49:08 +00001545 return true;
1546}
1547
reed@android.com8a1c16f2008-12-17 15:59:43 +00001548bool SampleWindow::nextSample() {
reed@android.com34245c72009-11-03 04:00:48 +00001549 fCurrIndex = (fCurrIndex + 1) % fSamples.count();
chudy@google.com4605a3f2012-08-01 17:58:01 +00001550 this->loadView(create_transition(curr_view(this), (*fSamples[fCurrIndex])(),
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001551 fTransitionNext));
reed@android.com34245c72009-11-03 04:00:48 +00001552 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001553}
1554
yangsu@google.com501775e2011-06-24 16:04:50 +00001555bool SampleWindow::goToSample(int i) {
1556 fCurrIndex = (i) % fSamples.count();
bsalomon@google.com48dd1a22011-10-31 14:18:20 +00001557 this->loadView(create_transition(curr_view(this),(*fSamples[fCurrIndex])(), 6));
yangsu@google.com501775e2011-06-24 16:04:50 +00001558 return true;
1559}
1560
1561SkString SampleWindow::getSampleTitle(int i) {
bsalomon@google.com48dd1a22011-10-31 14:18:20 +00001562 SkView* view = (*fSamples[i])();
yangsu@google.com501775e2011-06-24 16:04:50 +00001563 SkString title;
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001564 SampleCode::RequestTitle(view, &title);
yangsu@google.com501775e2011-06-24 16:04:50 +00001565 view->unref();
1566 return title;
1567}
1568
1569int SampleWindow::sampleCount() {
1570 return fSamples.count();
1571}
1572
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001573void SampleWindow::showOverview() {
chudy@google.com4605a3f2012-08-01 17:58:01 +00001574 this->loadView(create_transition(curr_view(this),
1575 create_overview(fSamples.count(), fSamples.begin()),
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001576 4));
1577}
1578
reed@google.come23f1942011-12-08 19:36:00 +00001579void SampleWindow::installDrawFilter(SkCanvas* canvas) {
1580 canvas->setDrawFilter(new FlagsDrawFilter(fLCDState, fAAState,
1581 fFilterState, fHintingState))->unref();
1582}
1583
Scroggo2c8208f2011-06-15 16:49:08 +00001584void SampleWindow::postAnimatingEvent() {
1585 if (fAnimating) {
reed@google.com87fac4a2011-08-04 13:50:17 +00001586 (new SkEvent(ANIMATING_EVENTTYPE, this->getSinkID()))->postDelay(ANIMATING_DELAY);
Scroggo2c8208f2011-06-15 16:49:08 +00001587 }
1588}
reed@google.come23f1942011-12-08 19:36:00 +00001589
reed@android.com8a1c16f2008-12-17 15:59:43 +00001590bool SampleWindow::onEvent(const SkEvent& evt) {
reed@google.com2072db82011-11-08 15:18:10 +00001591 if (evt.isType(gUpdateWindowTitleEvtName)) {
1592 this->updateTitle();
1593 return true;
1594 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001595 if (evt.isType(ANIMATING_EVENTTYPE)) {
1596 if (fAnimating) {
1597 this->nextSample();
1598 this->postAnimatingEvent();
1599 }
1600 return true;
1601 }
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001602 if (evt.isType("replace-transition-view")) {
1603 this->loadView((SkView*)SkEventSink::FindSink(evt.getFast32()));
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001604 return true;
1605 }
reed@android.com34245c72009-11-03 04:00:48 +00001606 if (evt.isType("set-curr-index")) {
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001607 this->goToSample(evt.getFast32());
reed@android.com34245c72009-11-03 04:00:48 +00001608 return true;
1609 }
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001610 if (isInvalEvent(evt)) {
1611 this->inval(NULL);
1612 return true;
1613 }
yangsu@google.com921091f2011-08-02 13:39:12 +00001614 int selected = -1;
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001615 if (SkOSMenu::FindListIndex(evt, "Device Type", &selected)) {
yangsu@google.com921091f2011-08-02 13:39:12 +00001616 this->setDeviceType((DeviceType)selected);
chudy@google.com4605a3f2012-08-01 17:58:01 +00001617 return true;
yangsu@google.com921091f2011-08-02 13:39:12 +00001618 }
scroggo@google.comb073d922012-06-08 15:35:03 +00001619 if (SkOSMenu::FindTriState(evt, "Pipe", &fPipeState)) {
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001620#ifdef PIPE_NET
scroggo@google.comb073d922012-06-08 15:35:03 +00001621 if (!fPipeState != SkOSMenu::kOnState)
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001622 gServer.disconnectAll();
1623#endif
scroggo@google.comb073d922012-06-08 15:35:03 +00001624 (void)SampleView::SetUsePipe(curr_view(this), fPipeState);
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001625 this->updateTitle();
1626 this->inval(NULL);
yangsu@google.com921091f2011-08-02 13:39:12 +00001627 return true;
1628 }
reed@google.com67b89ee2012-08-15 14:41:58 +00001629 if (SkOSMenu::FindTriState(evt, "Tiling", &fTilingState)) {
1630 int nx = 1, ny = 1;
1631 switch (fTilingState) {
1632 case SkOSMenu::kOffState: nx = 1; ny = 1; break;
reed@google.com56b64a52012-08-15 20:44:36 +00001633 case SkOSMenu::kMixedState: nx = 1; ny = 16; break;
1634 case SkOSMenu::kOnState: nx = 4; ny = 4; break;
reed@google.com67b89ee2012-08-15 14:41:58 +00001635 }
1636 (void)SampleView::SetTileCount(curr_view(this), nx, ny);
1637 this->updateTitle();
1638 this->inval(NULL);
1639 return true;
1640 }
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001641 if (SkOSMenu::FindSwitchState(evt, "Slide Show", NULL)) {
yangsu@google.com921091f2011-08-02 13:39:12 +00001642 this->toggleSlideshow();
1643 return true;
1644 }
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001645 if (SkOSMenu::FindTriState(evt, "AA", &fAAState) ||
1646 SkOSMenu::FindTriState(evt, "LCD", &fLCDState) ||
1647 SkOSMenu::FindTriState(evt, "Filter", &fFilterState) ||
1648 SkOSMenu::FindTriState(evt, "Hinting", &fHintingState) ||
1649 SkOSMenu::FindSwitchState(evt, "Clip", &fUseClip) ||
1650 SkOSMenu::FindSwitchState(evt, "Zoomer", &fShowZoomer) ||
1651 SkOSMenu::FindSwitchState(evt, "Magnify", &fMagnify) ||
1652 SkOSMenu::FindListIndex(evt, "Transition-Next", &fTransitionNext) ||
1653 SkOSMenu::FindListIndex(evt, "Transition-Prev", &fTransitionPrev)) {
yangsu@google.com921091f2011-08-02 13:39:12 +00001654 this->inval(NULL);
1655 this->updateTitle();
1656 return true;
1657 }
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001658 if (SkOSMenu::FindSwitchState(evt, "Flip X", NULL)) {
yangsu@google.com921091f2011-08-02 13:39:12 +00001659 fFlipAxis ^= kFlipAxis_X;
reed@google.comf03bb562011-11-11 21:42:12 +00001660 this->updateMatrix();
yangsu@google.com921091f2011-08-02 13:39:12 +00001661 return true;
1662 }
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001663 if (SkOSMenu::FindSwitchState(evt, "Flip Y", NULL)) {
yangsu@google.com921091f2011-08-02 13:39:12 +00001664 fFlipAxis ^= kFlipAxis_Y;
reed@google.comf03bb562011-11-11 21:42:12 +00001665 this->updateMatrix();
yangsu@google.com921091f2011-08-02 13:39:12 +00001666 return true;
1667 }
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001668 if (SkOSMenu::FindAction(evt,"Save to PDF")) {
yangsu@google.com921091f2011-08-02 13:39:12 +00001669 this->saveToPdf();
1670 return true;
chudy@google.com4605a3f2012-08-01 17:58:01 +00001671 }
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001672#ifdef DEBUGGER
1673 if (SkOSMenu::FindSwitchState(evt, "Debugger", &fDebugger)) {
1674 if (fDebugger) {
scroggo@google.comb073d922012-06-08 15:35:03 +00001675 fPipeState = SkOSMenu::kOnState;
1676 (void)SampleView::SetUsePipe(curr_view(this), fPipeState);
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001677 } else {
scroggo@google.comb073d922012-06-08 15:35:03 +00001678 this->loadView((*fSamples[fCurrIndex])());
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001679 }
1680 this->inval(NULL);
1681 return true;
1682 }
1683#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001684 return this->INHERITED::onEvent(evt);
1685}
1686
reed@android.comf2b98d62010-12-20 18:26:13 +00001687bool SampleWindow::onQuery(SkEvent* query) {
1688 if (query->isType("get-slide-count")) {
1689 query->setFast32(fSamples.count());
1690 return true;
1691 }
1692 if (query->isType("get-slide-title")) {
bsalomon@google.com48dd1a22011-10-31 14:18:20 +00001693 SkView* view = (*fSamples[query->getFast32()])();
reed@android.comf2b98d62010-12-20 18:26:13 +00001694 SkEvent evt(gTitleEvtName);
1695 if (view->doQuery(&evt)) {
1696 query->setString("title", evt.findString(gTitleEvtName));
1697 }
1698 SkSafeUnref(view);
1699 return true;
1700 }
1701 if (query->isType("use-fast-text")) {
1702 SkEvent evt(gFastTextEvtName);
1703 return curr_view(this)->doQuery(&evt);
1704 }
reed@google.com29038ed2011-07-06 17:56:47 +00001705 if (query->isType("ignore-window-bitmap")) {
1706 query->setFast32(this->getGrContext() != NULL);
1707 return true;
1708 }
reed@android.comf2b98d62010-12-20 18:26:13 +00001709 return this->INHERITED::onQuery(query);
1710}
1711
caryclark@google.com02939ce2012-06-06 12:09:51 +00001712#if 0 // UNUSED
reed@android.com0ae6b242008-12-23 16:49:54 +00001713static void cleanup_for_filename(SkString* name) {
1714 char* str = name->writable_str();
reed@android.come191b162009-12-18 21:33:39 +00001715 for (size_t i = 0; i < name->size(); i++) {
reed@android.com0ae6b242008-12-23 16:49:54 +00001716 switch (str[i]) {
1717 case ':': str[i] = '-'; break;
1718 case '/': str[i] = '-'; break;
1719 case ' ': str[i] = '_'; break;
1720 default: break;
1721 }
1722 }
1723}
caryclark@google.com02939ce2012-06-06 12:09:51 +00001724#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001725
1726bool SampleWindow::onHandleChar(SkUnichar uni) {
reed@android.comf2b98d62010-12-20 18:26:13 +00001727 {
1728 SkView* view = curr_view(this);
1729 if (view) {
1730 SkEvent evt(gCharEvtName);
1731 evt.setFast32(uni);
1732 if (view->doQuery(&evt)) {
1733 return true;
1734 }
1735 }
1736 }
chudy@google.com4605a3f2012-08-01 17:58:01 +00001737
reed@android.com8a1c16f2008-12-17 15:59:43 +00001738 int dx = 0xFF;
1739 int dy = 0xFF;
1740
1741 switch (uni) {
1742 case '5': dx = 0; dy = 0; break;
1743 case '8': dx = 0; dy = -1; break;
1744 case '6': dx = 1; dy = 0; break;
1745 case '2': dx = 0; dy = 1; break;
1746 case '4': dx = -1; dy = 0; break;
1747 case '7': dx = -1; dy = -1; break;
1748 case '9': dx = 1; dy = -1; break;
1749 case '3': dx = 1; dy = 1; break;
1750 case '1': dx = -1; dy = 1; break;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001751
reed@android.com8a1c16f2008-12-17 15:59:43 +00001752 default:
1753 break;
1754 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001755
reed@android.com8a1c16f2008-12-17 15:59:43 +00001756 if (0xFF != dx && 0xFF != dy) {
1757 if ((dx | dy) == 0) {
1758 fScrollTestX = fScrollTestY = 0;
1759 } else {
1760 fScrollTestX += dx;
1761 fScrollTestY += dy;
1762 }
1763 this->inval(NULL);
1764 return true;
1765 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001766
reed@android.com0ae6b242008-12-23 16:49:54 +00001767 switch (uni) {
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001768 case 'f':
chudy@google.com4605a3f2012-08-01 17:58:01 +00001769 // only
djsollen@google.com6ff82552011-11-07 15:43:57 +00001770 toggleFPS();
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001771 break;
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001772 case 'g':
1773 fRequestGrabImage = true;
1774 this->inval(NULL);
1775 break;
1776 case 'i':
1777 this->zoomIn();
1778 break;
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001779 case 'o':
1780 this->zoomOut();
1781 break;
reed@android.com6c5f6f22009-08-14 16:08:38 +00001782 case 'r':
1783 fRotate = !fRotate;
1784 this->inval(NULL);
1785 this->updateTitle();
1786 return true;
bsalomon@google.come8f09102011-09-08 18:48:12 +00001787 case 'k':
1788 fPerspAnim = !fPerspAnim;
1789 this->inval(NULL);
1790 this->updateTitle();
1791 return true;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001792#if SK_SUPPORT_GPU
bsalomon@google.com74913722011-10-27 20:44:19 +00001793 case '\\':
robertphillips@google.comb442a6d2012-04-02 19:24:21 +00001794 this->setDeviceType(kNullGPU_DeviceType);
1795 this->inval(NULL);
1796 this->updateTitle();
bsalomon@google.com74913722011-10-27 20:44:19 +00001797 return true;
twiz@google.com05e70242012-01-27 19:12:00 +00001798 case 'p':
1799 {
1800 GrContext* grContext = this->getGrContext();
1801 if (grContext) {
1802 size_t cacheBytes = grContext->getGpuTextureCacheBytes();
1803 grContext->freeGpuResources();
1804 SkDebugf("Purged %d bytes from the GPU resource cache.\n",
1805 cacheBytes);
1806 }
1807 }
1808 return true;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001809#endif
reed@android.com6c5f6f22009-08-14 16:08:38 +00001810 case 's':
1811 fScale = !fScale;
1812 this->inval(NULL);
1813 this->updateTitle();
1814 return true;
reed@android.com0ae6b242008-12-23 16:49:54 +00001815 default:
1816 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001817 }
chudy@google.com4605a3f2012-08-01 17:58:01 +00001818
scroggo@google.com7dadc742012-04-18 14:07:57 +00001819 if (fAppMenu->handleKeyEquivalent(uni)|| fSlideMenu->handleKeyEquivalent(uni)) {
1820 this->onUpdateMenu(fAppMenu);
1821 this->onUpdateMenu(fSlideMenu);
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001822 return true;
1823 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001824 return this->INHERITED::onHandleChar(uni);
1825}
1826
yangsu@google.com921091f2011-08-02 13:39:12 +00001827void SampleWindow::setDeviceType(DeviceType type) {
robertphillips@google.comb442a6d2012-04-02 19:24:21 +00001828 if (type == fDeviceType)
1829 return;
1830
1831 fDevManager->tearDownBackend(this);
1832
1833 fDeviceType = type;
1834
bsalomon@google.com11959252012-04-06 20:13:38 +00001835 fDevManager->setUpBackend(this, fMSAASampleCount);
robertphillips@google.comb442a6d2012-04-02 19:24:21 +00001836
yangsu@google.com921091f2011-08-02 13:39:12 +00001837 this->updateTitle();
1838 this->inval(NULL);
1839}
1840
Scroggo2c8208f2011-06-15 16:49:08 +00001841void SampleWindow::toggleSlideshow() {
1842 fAnimating = !fAnimating;
1843 this->postAnimatingEvent();
1844 this->updateTitle();
1845}
1846
1847void SampleWindow::toggleRendering() {
robertphillips@google.comb442a6d2012-04-02 19:24:21 +00001848 this->setDeviceType(cycle_devicetype(fDeviceType));
Scroggo2c8208f2011-06-15 16:49:08 +00001849 this->updateTitle();
1850 this->inval(NULL);
1851}
1852
djsollen@google.com6ff82552011-11-07 15:43:57 +00001853void SampleWindow::toggleFPS() {
1854 fMeasureFPS = !fMeasureFPS;
1855 this->updateTitle();
1856 this->inval(NULL);
1857}
1858
reed@android.com8a1c16f2008-12-17 15:59:43 +00001859#include "SkDumpCanvas.h"
1860
1861bool SampleWindow::onHandleKey(SkKey key) {
reed@android.comf2b98d62010-12-20 18:26:13 +00001862 {
1863 SkView* view = curr_view(this);
1864 if (view) {
1865 SkEvent evt(gKeyEvtName);
1866 evt.setFast32(key);
1867 if (view->doQuery(&evt)) {
1868 return true;
1869 }
1870 }
1871 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001872 switch (key) {
1873 case kRight_SkKey:
1874 if (this->nextSample()) {
1875 return true;
1876 }
1877 break;
1878 case kLeft_SkKey:
scroggo@google.come2dd9732012-08-15 20:03:06 +00001879 if (this->previousSample()) {
1880 return true;
1881 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001882 return true;
1883 case kUp_SkKey:
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001884 if (USE_ARROWS_FOR_ZOOM) {
djsollen@google.come32b5832011-06-13 16:58:40 +00001885 this->changeZoomLevel(1.f);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001886 } else {
1887 fNClip = !fNClip;
1888 this->inval(NULL);
djsollen@google.come32b5832011-06-13 16:58:40 +00001889 this->updateTitle();
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001890 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001891 return true;
1892 case kDown_SkKey:
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001893 if (USE_ARROWS_FOR_ZOOM) {
djsollen@google.come32b5832011-06-13 16:58:40 +00001894 this->changeZoomLevel(-1.f);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001895 } else {
1896 this->setConfig(cycle_configs(this->getBitmap().config()));
djsollen@google.come32b5832011-06-13 16:58:40 +00001897 this->updateTitle();
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001898 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001899 return true;
mike@reedtribe.org6f6e8c32011-12-27 22:33:50 +00001900 case kOK_SkKey: {
1901 SkString title;
1902 if (curr_title(this, &title)) {
1903 writeTitleToPrefs(title.c_str());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001904 }
1905 return true;
mike@reedtribe.org6f6e8c32011-12-27 22:33:50 +00001906 }
reed@android.com34245c72009-11-03 04:00:48 +00001907 case kBack_SkKey:
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001908 this->showOverview();
reed@android.com34245c72009-11-03 04:00:48 +00001909 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001910 default:
1911 break;
1912 }
1913 return this->INHERITED::onHandleKey(key);
1914}
1915
reed@google.com52f57e12011-03-16 12:10:02 +00001916///////////////////////////////////////////////////////////////////////////////
1917
1918static const char gGestureClickType[] = "GestureClickType";
1919
Scroggod3aed392011-06-22 13:26:56 +00001920bool SampleWindow::onDispatchClick(int x, int y, Click::State state,
1921 void* owner) {
Scroggo0f185c22011-03-24 18:35:50 +00001922 if (Click::kMoved_State == state) {
1923 updatePointer(x, y);
1924 }
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001925 int w = SkScalarRound(this->width());
1926 int h = SkScalarRound(this->height());
1927
1928 // check for the resize-box
1929 if (w - x < 16 && h - y < 16) {
1930 return false; // let the OS handle the click
chudy@google.com4605a3f2012-08-01 17:58:01 +00001931 }
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00001932 else if (fMagnify) {
1933 //it's only necessary to update the drawing if there's a click
1934 this->inval(NULL);
1935 return false; //prevent dragging while magnify is enabled
1936 }
1937 else {
Scroggod3aed392011-06-22 13:26:56 +00001938 return this->INHERITED::onDispatchClick(x, y, state, owner);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001939 }
1940}
1941
reed@google.com52f57e12011-03-16 12:10:02 +00001942class GestureClick : public SkView::Click {
1943public:
1944 GestureClick(SkView* target) : SkView::Click(target) {
1945 this->setType(gGestureClickType);
1946 }
1947
1948 static bool IsGesture(Click* click) {
1949 return click->isType(gGestureClickType);
1950 }
1951};
1952
1953SkView::Click* SampleWindow::onFindClickHandler(SkScalar x, SkScalar y) {
1954 return new GestureClick(this);
1955}
1956
1957bool SampleWindow::onClick(Click* click) {
1958 if (GestureClick::IsGesture(click)) {
bsalomon@google.com4d4f2812011-12-12 18:34:01 +00001959 float x = static_cast<float>(click->fICurr.fX);
1960 float y = static_cast<float>(click->fICurr.fY);
chudy@google.com4605a3f2012-08-01 17:58:01 +00001961
reed@google.com52f57e12011-03-16 12:10:02 +00001962 switch (click->fState) {
1963 case SkView::Click::kDown_State:
Scroggod3aed392011-06-22 13:26:56 +00001964 fGesture.touchBegin(click->fOwner, x, y);
reed@google.com52f57e12011-03-16 12:10:02 +00001965 break;
1966 case SkView::Click::kMoved_State:
Scroggod3aed392011-06-22 13:26:56 +00001967 fGesture.touchMoved(click->fOwner, x, y);
reed@google.comf03bb562011-11-11 21:42:12 +00001968 this->updateMatrix();
reed@google.com52f57e12011-03-16 12:10:02 +00001969 break;
1970 case SkView::Click::kUp_State:
Scroggod3aed392011-06-22 13:26:56 +00001971 fGesture.touchEnd(click->fOwner);
reed@google.comf03bb562011-11-11 21:42:12 +00001972 this->updateMatrix();
reed@google.com52f57e12011-03-16 12:10:02 +00001973 break;
1974 }
1975 return true;
1976 }
1977 return false;
1978}
1979
1980///////////////////////////////////////////////////////////////////////////////
1981
reed@android.com8a1c16f2008-12-17 15:59:43 +00001982void SampleWindow::loadView(SkView* view) {
1983 SkView::F2BIter iter(this);
1984 SkView* prev = iter.next();
1985 if (prev) {
1986 prev->detachFromParent();
1987 }
chudy@google.com4605a3f2012-08-01 17:58:01 +00001988
reed@android.com8a1c16f2008-12-17 15:59:43 +00001989 view->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +00001990 view->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001991 this->attachChildToFront(view)->unref();
1992 view->setSize(this->width(), this->height());
1993
yangsu@google.com921091f2011-08-02 13:39:12 +00001994 //repopulate the slide menu when a view is loaded
scroggo@google.com7dadc742012-04-18 14:07:57 +00001995 fSlideMenu->reset();
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00001996#ifdef DEBUGGER
1997 if (!is_debugger(view) && !is_overview(view) && !is_transition(view) && fDebugger) {
1998 //Force Pipe to be on if using debugger
scroggo@google.comb073d922012-06-08 15:35:03 +00001999 fPipeState = SkOSMenu::kOnState;
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00002000 }
2001#endif
scroggo@google.comb073d922012-06-08 15:35:03 +00002002 (void)SampleView::SetUsePipe(view, fPipeState);
yangsu@google.com921091f2011-08-02 13:39:12 +00002003 if (SampleView::IsSampleView(view))
scroggo@google.com7dadc742012-04-18 14:07:57 +00002004 ((SampleView*)view)->requestMenu(fSlideMenu);
2005 this->onUpdateMenu(fSlideMenu);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002006 this->updateTitle();
2007}
2008
2009static const char* gConfigNames[] = {
2010 "unknown config",
2011 "A1",
2012 "A8",
2013 "Index8",
2014 "565",
2015 "4444",
2016 "8888"
2017};
2018
2019static const char* configToString(SkBitmap::Config c) {
2020 return gConfigNames[c];
2021}
2022
bsalomon@google.com098e96d2011-07-14 14:30:46 +00002023static const char* gDeviceTypePrefix[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002024 "raster: ",
2025 "picture: ",
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002026#if SK_SUPPORT_GPU
bsalomon@google.com74913722011-10-27 20:44:19 +00002027 "opengl: ",
robertphillips@google.comb442a6d2012-04-02 19:24:21 +00002028#if SK_ANGLE
2029 "angle: ",
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002030#endif // SK_ANGLE
bsalomon@google.com74913722011-10-27 20:44:19 +00002031 "null-gl: "
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002032#endif // SK_SUPPORT_GPU
reed@android.com8a1c16f2008-12-17 15:59:43 +00002033};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002034SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gDeviceTypePrefix) == SampleWindow::kDeviceTypeCnt,
2035 array_size_mismatch);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002036
bsalomon@google.com11959252012-04-06 20:13:38 +00002037static const bool gDeviceTypeIsGPU[] = {
2038 false,
2039 false,
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002040#if SK_SUPPORT_GPU
bsalomon@google.com11959252012-04-06 20:13:38 +00002041 true,
2042#if SK_ANGLE
2043 true,
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002044#endif // SK_ANGLE
bsalomon@google.com11959252012-04-06 20:13:38 +00002045 true
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002046#endif // SK_SUPPORT_GPU
bsalomon@google.com11959252012-04-06 20:13:38 +00002047};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002048SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gDeviceTypeIsGPU) == SampleWindow::kDeviceTypeCnt,
2049 array_size_mismatch);
2050
bsalomon@google.com11959252012-04-06 20:13:38 +00002051
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00002052static const char* trystate_str(SkOSMenu::TriState state,
reed@google.com569e0432011-04-05 13:07:03 +00002053 const char trueStr[], const char falseStr[]) {
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00002054 if (SkOSMenu::kOnState == state) {
reed@google.com569e0432011-04-05 13:07:03 +00002055 return trueStr;
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00002056 } else if (SkOSMenu::kOffState == state) {
reed@google.com569e0432011-04-05 13:07:03 +00002057 return falseStr;
2058 }
2059 return NULL;
2060}
2061
reed@android.com8a1c16f2008-12-17 15:59:43 +00002062void SampleWindow::updateTitle() {
mike@reedtribe.org6f6e8c32011-12-27 22:33:50 +00002063 SkView* view = curr_view(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002064
mike@reedtribe.org6f6e8c32011-12-27 22:33:50 +00002065 SkString title;
2066 if (!curr_title(this, &title)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002067 title.set("<unknown>");
2068 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00002069
bsalomon@google.com098e96d2011-07-14 14:30:46 +00002070 title.prepend(gDeviceTypePrefix[fDeviceType]);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002071
2072 title.prepend(" ");
2073 title.prepend(configToString(this->getBitmap().config()));
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00002074
reed@android.com8a1c16f2008-12-17 15:59:43 +00002075 if (fAnimating) {
2076 title.prepend("<A> ");
2077 }
reed@android.com6c5f6f22009-08-14 16:08:38 +00002078 if (fScale) {
2079 title.prepend("<S> ");
2080 }
2081 if (fRotate) {
2082 title.prepend("<R> ");
2083 }
reed@android.come522ca52009-11-23 20:10:41 +00002084 if (fNClip) {
2085 title.prepend("<C> ");
2086 }
bsalomon@google.come8f09102011-09-08 18:48:12 +00002087 if (fPerspAnim) {
2088 title.prepend("<K> ");
2089 }
reed@google.com569e0432011-04-05 13:07:03 +00002090
2091 title.prepend(trystate_str(fLCDState, "LCD ", "lcd "));
2092 title.prepend(trystate_str(fAAState, "AA ", "aa "));
reed@google.com09e3baa2011-05-18 12:04:31 +00002093 title.prepend(trystate_str(fFilterState, "H ", "h "));
reed@google.com569e0432011-04-05 13:07:03 +00002094 title.prepend(fFlipAxis & kFlipAxis_X ? "X " : NULL);
2095 title.prepend(fFlipAxis & kFlipAxis_Y ? "Y " : NULL);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00002096
2097 if (fZoomLevel) {
djsollen@google.come32b5832011-06-13 16:58:40 +00002098 title.prependf("{%.2f} ", SkScalarToFloat(fZoomLevel));
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00002099 }
chudy@google.com4605a3f2012-08-01 17:58:01 +00002100
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00002101 if (fMeasureFPS) {
reed@google.combad8c872011-05-18 20:10:31 +00002102 title.appendf(" %6.1f ms", fMeasureFPS_Time / (float)FPS_REPEAT_MULTIPLIER);
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00002103 }
reed@google.coma6ff4dc2011-05-12 22:08:24 +00002104 if (SampleView::IsSampleView(view)) {
scroggo@google.comb073d922012-06-08 15:35:03 +00002105 switch (fPipeState) {
2106 case SkOSMenu::kOnState:
2107 title.prepend("<Pipe> ");
2108 break;
2109 case SkOSMenu::kMixedState:
2110 title.prepend("<Tiled Pipe> ");
2111 break;
chudy@google.com4605a3f2012-08-01 17:58:01 +00002112
scroggo@google.comb073d922012-06-08 15:35:03 +00002113 default:
2114 break;
2115 }
reed@google.coma6ff4dc2011-05-12 22:08:24 +00002116 title.prepend("! ");
2117 }
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00002118
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002119#if SK_SUPPORT_GPU
bsalomon@google.com11959252012-04-06 20:13:38 +00002120 if (gDeviceTypeIsGPU[fDeviceType] &&
robertphillips@google.com4750fa52012-04-10 13:34:11 +00002121 NULL != fDevManager &&
bsalomon@google.com11959252012-04-06 20:13:38 +00002122 fDevManager->getGrRenderTarget()->numSamples() > 0) {
2123 title.appendf(" [MSAA: %d]",
2124 fDevManager->getGrRenderTarget()->numSamples());
2125 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00002126#endif
bsalomon@google.com11959252012-04-06 20:13:38 +00002127
reed@android.com8a1c16f2008-12-17 15:59:43 +00002128 this->setTitle(title.c_str());
2129}
2130
2131void SampleWindow::onSizeChange() {
2132 this->INHERITED::onSizeChange();
chudy@google.com4605a3f2012-08-01 17:58:01 +00002133
reed@android.com8a1c16f2008-12-17 15:59:43 +00002134 SkView::F2BIter iter(this);
2135 SkView* view = iter.next();
2136 view->setSize(this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00002137
reed@android.com8a1c16f2008-12-17 15:59:43 +00002138 // rebuild our clippath
2139 {
2140 const SkScalar W = this->width();
2141 const SkScalar H = this->height();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00002142
reed@android.com8a1c16f2008-12-17 15:59:43 +00002143 fClipPath.reset();
2144#if 0
2145 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
2146 SkRect r;
2147 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
2148 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
2149 fClipPath.addRect(r);
2150 }
2151#else
2152 SkRect r;
2153 r.set(0, 0, W, H);
2154 fClipPath.addRect(r, SkPath::kCCW_Direction);
2155 r.set(W/4, H/4, W*3/4, H*3/4);
2156 fClipPath.addRect(r, SkPath::kCW_Direction);
2157#endif
2158 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00002159
Scroggo2c8208f2011-06-15 16:49:08 +00002160 fZoomCenterX = SkScalarHalf(this->width());
2161 fZoomCenterY = SkScalarHalf(this->height());
2162
djsollen@google.com56c69772011-11-08 19:00:26 +00002163#ifdef SK_BUILD_FOR_ANDROID
Scroggob4490c72011-06-17 13:53:05 +00002164 // FIXME: The first draw after a size change does not work on Android, so
2165 // we post an invalidate.
Scroggo62b65b02011-06-21 16:01:26 +00002166 this->postInvalDelay();
Scroggo716a0382011-06-16 14:00:15 +00002167#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002168 this->updateTitle(); // to refresh our config
bsalomon@google.com098e96d2011-07-14 14:30:46 +00002169 fDevManager->windowSizeChanged(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002170}
2171
2172///////////////////////////////////////////////////////////////////////////////
2173
reed@google.coma6ff4dc2011-05-12 22:08:24 +00002174static const char is_sample_view_tag[] = "sample-is-sample-view";
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00002175static const char repeat_count_tag[] = "sample-set-repeat-count";
reed@google.com0faac1e2011-05-11 05:58:58 +00002176static const char set_use_pipe_tag[] = "sample-set-use-pipe";
reed@google.com67b89ee2012-08-15 14:41:58 +00002177static const char set_tile_count_tag[] = "sample-set-tile-count";
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00002178
reed@google.coma6ff4dc2011-05-12 22:08:24 +00002179bool SampleView::IsSampleView(SkView* view) {
2180 SkEvent evt(is_sample_view_tag);
2181 return view->doQuery(&evt);
2182}
2183
reed@google.comf2183392011-04-22 14:10:48 +00002184bool SampleView::SetRepeatDraw(SkView* view, int count) {
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00002185 SkEvent evt(repeat_count_tag);
2186 evt.setFast32(count);
reed@google.comf2183392011-04-22 14:10:48 +00002187 return view->doEvent(evt);
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00002188}
2189
scroggo@google.comb073d922012-06-08 15:35:03 +00002190bool SampleView::SetUsePipe(SkView* view, SkOSMenu::TriState state) {
2191 SkEvent evt;
2192 evt.setS32(set_use_pipe_tag, state);
reed@google.com0faac1e2011-05-11 05:58:58 +00002193 return view->doEvent(evt);
2194}
2195
reed@google.com67b89ee2012-08-15 14:41:58 +00002196bool SampleView::SetTileCount(SkView* view, int nx, int ny) {
2197 SkEvent evt(set_tile_count_tag);
2198 evt.setFast32((ny << 16) | nx);
2199 return view->doEvent(evt);
2200}
2201
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00002202bool SampleView::onEvent(const SkEvent& evt) {
2203 if (evt.isType(repeat_count_tag)) {
2204 fRepeatCount = evt.getFast32();
2205 return true;
2206 }
reed@google.com67b89ee2012-08-15 14:41:58 +00002207 if (evt.isType(set_tile_count_tag)) {
2208 unsigned packed = evt.getFast32();
2209 fTileCount.set(packed & 0xFFFF, packed >> 16);
2210 return true;
2211 }
scroggo@google.comb073d922012-06-08 15:35:03 +00002212 int32_t pipeHolder;
2213 if (evt.findS32(set_use_pipe_tag, &pipeHolder)) {
2214 fPipeState = static_cast<SkOSMenu::TriState>(pipeHolder);
reed@google.com0faac1e2011-05-11 05:58:58 +00002215 return true;
2216 }
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00002217 return this->INHERITED::onEvent(evt);
2218}
2219
2220bool SampleView::onQuery(SkEvent* evt) {
reed@google.coma6ff4dc2011-05-12 22:08:24 +00002221 if (evt->isType(is_sample_view_tag)) {
2222 return true;
2223 }
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00002224 return this->INHERITED::onQuery(evt);
2225}
2226
reed@google.com64e3eb22011-05-04 14:32:04 +00002227
2228class SimplePC : public SkGPipeController {
2229public:
2230 SimplePC(SkCanvas* target);
2231 ~SimplePC();
chudy@google.com4605a3f2012-08-01 17:58:01 +00002232
reed@google.com64e3eb22011-05-04 14:32:04 +00002233 virtual void* requestBlock(size_t minRequest, size_t* actual);
2234 virtual void notifyWritten(size_t bytes);
2235
2236private:
reed@google.com961ddb02011-05-05 14:03:48 +00002237 SkGPipeReader fReader;
2238 void* fBlock;
2239 size_t fBlockSize;
2240 size_t fBytesWritten;
2241 int fAtomsWritten;
reed@google.com64e3eb22011-05-04 14:32:04 +00002242 SkGPipeReader::Status fStatus;
2243
2244 size_t fTotalWritten;
2245};
2246
2247SimplePC::SimplePC(SkCanvas* target) : fReader(target) {
2248 fBlock = NULL;
2249 fBlockSize = fBytesWritten = 0;
2250 fStatus = SkGPipeReader::kDone_Status;
2251 fTotalWritten = 0;
reed@google.com961ddb02011-05-05 14:03:48 +00002252 fAtomsWritten = 0;
reed@google.com64e3eb22011-05-04 14:32:04 +00002253}
2254
2255SimplePC::~SimplePC() {
2256// SkASSERT(SkGPipeReader::kDone_Status == fStatus);
reed@google.com0faac1e2011-05-11 05:58:58 +00002257 if (fTotalWritten) {
scroggo@google.comb073d922012-06-08 15:35:03 +00002258 SkDebugf("--- %d bytes %d atoms, status %d\n", fTotalWritten,
2259 fAtomsWritten, fStatus);
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00002260#ifdef PIPE_FILE
scroggo@google.comb073d922012-06-08 15:35:03 +00002261 //File is open in append mode
2262 FILE* f = fopen(FILE_PATH, "ab");
2263 SkASSERT(f != NULL);
2264 fwrite((const char*)fBlock + fBytesWritten, 1, bytes, f);
2265 fclose(f);
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00002266#endif
2267#ifdef PIPE_NET
scroggo@google.comb073d922012-06-08 15:35:03 +00002268 if (fAtomsWritten > 1 && fTotalWritten > 4) { //ignore done
2269 gServer.acceptConnections();
2270 gServer.writePacket(fBlock, fTotalWritten);
2271 }
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00002272#endif
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00002273#ifdef DEBUGGER
scroggo@google.comb073d922012-06-08 15:35:03 +00002274 gTempDataStore.reset();
2275 gTempDataStore.append(fTotalWritten, (const char*)fBlock);
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00002276#endif
reed@google.com0faac1e2011-05-11 05:58:58 +00002277 }
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00002278 sk_free(fBlock);
reed@google.com64e3eb22011-05-04 14:32:04 +00002279}
2280
2281void* SimplePC::requestBlock(size_t minRequest, size_t* actual) {
2282 sk_free(fBlock);
2283
2284 fBlockSize = minRequest * 4;
2285 fBlock = sk_malloc_throw(fBlockSize);
2286 fBytesWritten = 0;
2287 *actual = fBlockSize;
2288 return fBlock;
2289}
2290
2291void SimplePC::notifyWritten(size_t bytes) {
2292 SkASSERT(fBytesWritten + bytes <= fBlockSize);
reed@google.com64e3eb22011-05-04 14:32:04 +00002293 fStatus = fReader.playback((const char*)fBlock + fBytesWritten, bytes);
2294 SkASSERT(SkGPipeReader::kError_Status != fStatus);
2295 fBytesWritten += bytes;
2296 fTotalWritten += bytes;
chudy@google.com4605a3f2012-08-01 17:58:01 +00002297
reed@google.com961ddb02011-05-05 14:03:48 +00002298 fAtomsWritten += 1;
reed@google.com64e3eb22011-05-04 14:32:04 +00002299}
2300
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00002301void SampleView::draw(SkCanvas* canvas) {
scroggo@google.comb073d922012-06-08 15:35:03 +00002302 if (SkOSMenu::kOffState == fPipeState) {
2303 this->INHERITED::draw(canvas);
2304 } else {
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00002305 SkGPipeWriter writer;
2306 SimplePC controller(canvas);
scroggo@google.comb073d922012-06-08 15:35:03 +00002307 TiledPipeController tc(canvas->getDevice()->accessBitmap(false),
2308 &canvas->getTotalMatrix());
2309 SkGPipeController* pc;
2310 if (SkOSMenu::kMixedState == fPipeState) {
2311 pc = &tc;
2312 } else {
2313 pc = &controller;
2314 }
reed@google.comdde09562011-05-23 12:21:05 +00002315 uint32_t flags = SkGPipeWriter::kCrossProcess_Flag;
chudy@google.com4605a3f2012-08-01 17:58:01 +00002316
scroggo@google.comb073d922012-06-08 15:35:03 +00002317 canvas = writer.startRecording(pc, flags);
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00002318 //Must draw before controller goes out of scope and sends data
2319 this->INHERITED::draw(canvas);
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00002320 //explicitly end recording to ensure writer is flushed before the memory
2321 //is freed in the deconstructor of the controller
2322 writer.endRecording();
reed@google.com0faac1e2011-05-11 05:58:58 +00002323 }
yangsu@google.comdb03eaa2011-08-08 15:37:23 +00002324}
2325void SampleView::onDraw(SkCanvas* canvas) {
reed@google.com81e3d7f2011-06-01 12:42:36 +00002326 this->onDrawBackground(canvas);
2327
reed@google.com67b89ee2012-08-15 14:41:58 +00002328 const SkScalar cw = this->width() / fTileCount.width();
2329 const SkScalar ch = this->height() / fTileCount.height();
2330
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00002331 for (int i = 0; i < fRepeatCount; i++) {
reed@google.com67b89ee2012-08-15 14:41:58 +00002332 for (int y = 0; y < fTileCount.height(); ++y) {
2333 for (int x = 0; x < fTileCount.width(); ++x) {
2334 SkAutoCanvasRestore acr(canvas, true);
2335 canvas->clipRect(SkRect::MakeXYWH(x * cw, y * ch, cw, ch));
2336 this->onDrawContent(canvas);
2337 }
2338 }
2339 }
2340
2341 if (!fTileCount.equals(1, 1)) {
2342 SkPaint paint;
2343 paint.setColor(0x60FF00FF);
2344 paint.setStyle(SkPaint::kStroke_Style);
2345 for (int y = 0; y < fTileCount.height(); ++y) {
2346 for (int x = 0; x < fTileCount.width(); ++x) {
2347 canvas->drawRect(SkRect::MakeXYWH(x * cw, y * ch, cw, ch), paint);
2348 }
2349 }
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00002350 }
2351}
2352
2353void SampleView::onDrawBackground(SkCanvas* canvas) {
reed@google.comf2183392011-04-22 14:10:48 +00002354 canvas->drawColor(fBGColor);
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00002355}
2356
2357///////////////////////////////////////////////////////////////////////////////
2358
reed@android.comf2b98d62010-12-20 18:26:13 +00002359template <typename T> void SkTBSort(T array[], int count) {
2360 for (int i = 1; i < count - 1; i++) {
2361 bool didSwap = false;
2362 for (int j = count - 1; j > i; --j) {
2363 if (array[j] < array[j-1]) {
2364 T tmp(array[j-1]);
2365 array[j-1] = array[j];
2366 array[j] = tmp;
2367 didSwap = true;
2368 }
2369 }
2370 if (!didSwap) {
2371 break;
2372 }
2373 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00002374
reed@android.comf2b98d62010-12-20 18:26:13 +00002375 for (int k = 0; k < count - 1; k++) {
2376 SkASSERT(!(array[k+1] < array[k]));
2377 }
2378}
2379
2380#include "SkRandom.h"
2381
2382static void rand_rect(SkIRect* rect, SkRandom& rand) {
2383 int bits = 8;
2384 int shift = 32 - bits;
2385 rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
2386 rand.nextU() >> shift, rand.nextU() >> shift);
2387 rect->sort();
2388}
2389
2390static void dumpRect(const SkIRect& r) {
2391 SkDebugf(" { %d, %d, %d, %d },\n",
2392 r.fLeft, r.fTop,
2393 r.fRight, r.fBottom);
2394}
2395
2396static void test_rects(const SkIRect rect[], int count) {
2397 SkRegion rgn0, rgn1;
2398
2399 for (int i = 0; i < count; i++) {
2400 rgn0.op(rect[i], SkRegion::kUnion_Op);
2401 // dumpRect(rect[i]);
2402 }
2403 rgn1.setRects(rect, count);
2404
2405 if (rgn0 != rgn1) {
2406 SkDebugf("\n");
2407 for (int i = 0; i < count; i++) {
2408 dumpRect(rect[i]);
2409 }
2410 SkDebugf("\n");
2411 }
2412}
2413
2414static void test() {
2415 size_t i;
2416
2417 const SkIRect r0[] = {
2418 { 0, 0, 1, 1 },
2419 { 2, 2, 3, 3 },
2420 };
2421 const SkIRect r1[] = {
2422 { 0, 0, 1, 3 },
2423 { 1, 1, 2, 2 },
2424 { 2, 0, 3, 3 },
2425 };
2426 const SkIRect r2[] = {
2427 { 0, 0, 1, 2 },
2428 { 2, 1, 3, 3 },
2429 { 4, 0, 5, 1 },
2430 { 6, 0, 7, 4 },
2431 };
2432
2433 static const struct {
2434 const SkIRect* fRects;
2435 int fCount;
2436 } gRecs[] = {
2437 { r0, SK_ARRAY_COUNT(r0) },
2438 { r1, SK_ARRAY_COUNT(r1) },
2439 { r2, SK_ARRAY_COUNT(r2) },
2440 };
2441
2442 for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
2443 test_rects(gRecs[i].fRects, gRecs[i].fCount);
2444 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00002445
reed@android.comf2b98d62010-12-20 18:26:13 +00002446 SkRandom rand;
2447 for (i = 0; i < 10000; i++) {
2448 SkRegion rgn0, rgn1;
2449
2450 const int N = 8;
2451 SkIRect rect[N];
2452 for (int j = 0; j < N; j++) {
2453 rand_rect(&rect[j], rand);
2454 }
2455 test_rects(rect, N);
2456 }
2457}
2458
caryclark@google.com02939ce2012-06-06 12:09:51 +00002459// FIXME: this should be in a header
2460SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv);
senorblanco@chromium.org78b82532011-06-28 19:44:03 +00002461SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) {
caryclark@google.com02939ce2012-06-06 12:09:51 +00002462 if (false) { // avoid bit rot, suppress warning
2463 test();
2464 }
bsalomon@google.com098e96d2011-07-14 14:30:46 +00002465 return new SampleWindow(hwnd, argc, argv, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002466}
2467
caryclark@google.com02939ce2012-06-06 12:09:51 +00002468// FIXME: this should be in a header
2469void get_preferred_size(int* x, int* y, int* width, int* height);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002470void get_preferred_size(int* x, int* y, int* width, int* height) {
2471 *x = 10;
2472 *y = 50;
2473 *width = 640;
2474 *height = 480;
2475}
2476
caryclark@google.com02939ce2012-06-06 12:09:51 +00002477// FIXME: this should be in a header
2478void application_init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002479void application_init() {
2480// setenv("ANDROID_ROOT", "../../../data", 0);
reed@android.come191b162009-12-18 21:33:39 +00002481#ifdef SK_BUILD_FOR_MAC
reed@android.com8a1c16f2008-12-17 15:59:43 +00002482 setenv("ANDROID_ROOT", "/android/device/data", 0);
reed@android.come191b162009-12-18 21:33:39 +00002483#endif
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00002484 SkGraphics::Init();
2485 SkEvent::Init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002486}
2487
caryclark@google.com02939ce2012-06-06 12:09:51 +00002488// FIXME: this should be in a header
2489void application_term();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002490void application_term() {
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00002491 SkEvent::Term();
2492 SkGraphics::Term();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002493}