blob: a0dd99a2d393fa22cfa0e1fee1c169ff32833c06 [file] [log] [blame]
Scroggo2c8208f2011-06-15 16:49:08 +00001#include "SampleApp.h"
2
reed@google.com8a85d0c2011-06-24 19:12:12 +00003#include "SkData.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00004#include "SkCanvas.h"
5#include "SkDevice.h"
reed@google.comaf951c92011-06-16 19:10:39 +00006#include "SkGpuDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00007#include "SkGraphics.h"
reed@android.comb08eb2b2009-01-06 20:16:26 +00008#include "SkImageEncoder.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkPaint.h"
10#include "SkPicture.h"
11#include "SkStream.h"
reed@android.com44177402009-11-23 21:07:51 +000012#include "SkTime.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkWindow.h"
14
15#include "SampleCode.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000016#include "GrContext.h"
Scroggo0f185c22011-03-24 18:35:50 +000017#include "SkTypeface.h"
reed@android.comf2b98d62010-12-20 18:26:13 +000018
Scroggo3e7ff9f2011-06-16 15:31:26 +000019#include "GrGLInterface.h"
Scroggo2c8208f2011-06-15 16:49:08 +000020
Scroggo8ac0d542011-06-21 14:44:57 +000021#include "SkPDFDevice.h"
22#include "SkPDFDocument.h"
23#include "SkStream.h"
24
yangsu@google.com1f394212011-06-01 18:03:34 +000025#define TEST_GPIPEx
26
27#ifdef TEST_GPIPE
28#define PIPE_FILE
29#define FILE_PATH "/path/to/drawing.data"
30#endif
31
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +000032#define USE_ARROWS_FOR_ZOOM true
reed@android.comf2b98d62010-12-20 18:26:13 +000033//#define DEFAULT_TO_GPU
34
reed@android.come191b162009-12-18 21:33:39 +000035extern SkView* create_overview(int, const SkViewFactory[]);
reed@android.com34245c72009-11-03 04:00:48 +000036
reed@android.comcb342352010-07-22 18:27:53 +000037#define SK_SUPPORT_GL
reed@android.com8a1c16f2008-12-17 15:59:43 +000038
39#define ANIMATING_EVENTTYPE "nextSample"
40#define ANIMATING_DELAY 750
41
mike@reedtribe.org2eb59522011-04-22 01:59:09 +000042#ifdef SK_DEBUG
reed@google.combad8c872011-05-18 20:10:31 +000043 #define FPS_REPEAT_MULTIPLIER 1
mike@reedtribe.org2eb59522011-04-22 01:59:09 +000044#else
reed@google.combad8c872011-05-18 20:10:31 +000045 #define FPS_REPEAT_MULTIPLIER 10
mike@reedtribe.org2eb59522011-04-22 01:59:09 +000046#endif
reed@google.combad8c872011-05-18 20:10:31 +000047#define FPS_REPEAT_COUNT (10 * FPS_REPEAT_MULTIPLIER)
mike@reedtribe.org2eb59522011-04-22 01:59:09 +000048
reed@google.comac10a2d2010-12-22 21:39:39 +000049#ifdef SK_SUPPORT_GL
50 #include "GrGLConfig.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000051#endif
52
reed@google.com3cec4d72011-07-06 13:59:47 +000053static SampleWindow* gSampleWindow;
54
mike@reedtribe.org2eb59522011-04-22 01:59:09 +000055///////////////
56static const char view_inval_msg[] = "view-inval-msg";
57
Scroggo62b65b02011-06-21 16:01:26 +000058void SampleWindow::postInvalDelay() {
mike@reedtribe.org2eb59522011-04-22 01:59:09 +000059 SkEvent* evt = new SkEvent(view_inval_msg);
Scroggo62b65b02011-06-21 16:01:26 +000060 evt->post(this->getSinkID(), 1);
mike@reedtribe.org2eb59522011-04-22 01:59:09 +000061}
62
63static bool isInvalEvent(const SkEvent& evt) {
64 return evt.isType(view_inval_msg);
65}
66//////////////////
67
reed@android.com8a1c16f2008-12-17 15:59:43 +000068SkViewRegister* SkViewRegister::gHead;
69SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) {
70 static bool gOnce;
71 if (!gOnce) {
72 gHead = NULL;
73 gOnce = true;
74 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +000075
reed@android.com8a1c16f2008-12-17 15:59:43 +000076 fChain = gHead;
77 gHead = this;
78}
79
reed@android.comf2b98d62010-12-20 18:26:13 +000080#if defined(SK_SUPPORT_GL)
81 #define SK_USE_SHADERS
82#endif
83
reed@google.com29038ed2011-07-06 17:56:47 +000084#if 0
reed@google.comf0b5f682011-03-11 20:08:25 +000085#include <CoreFoundation/CoreFoundation.h>
86#include <CoreFoundation/CFURLAccess.h>
87
88static void testpdf() {
89 CFStringRef path = CFStringCreateWithCString(NULL, "/test.pdf",
90 kCFStringEncodingUTF8);
91 CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path,
92 kCFURLPOSIXPathStyle,
93 false);
94 CFRelease(path);
95 CGRect box = CGRectMake(0, 0, 8*72, 10*72);
96 CGContextRef cg = CGPDFContextCreateWithURL(url, &box, NULL);
97 CFRelease(url);
98
99 CGContextBeginPage(cg, &box);
100 CGRect r = CGRectMake(10, 10, 40 + 0.5, 50 + 0.5);
101 CGContextFillEllipseInRect(cg, r);
102 CGContextEndPage(cg);
103 CGContextRelease(cg);
104
105 if (false) {
106 SkBitmap bm;
107 bm.setConfig(SkBitmap::kA8_Config, 64, 64);
108 bm.allocPixels();
109 bm.eraseColor(0);
110
111 SkCanvas canvas(bm);
112
113 }
114}
115#endif
116
117//////////////////////////////////////////////////////////////////////////////
118
reed@google.com569e0432011-04-05 13:07:03 +0000119enum FlipAxisEnum {
120 kFlipAxis_X = (1 << 0),
121 kFlipAxis_Y = (1 << 1)
122};
123
reed@google.com569e0432011-04-05 13:07:03 +0000124static SkTriState cycle_tristate(SkTriState state) {
125 static const SkTriState gCycle[] = {
126 /* kFalse_SkTriState -> */ kUnknown_SkTriState,
127 /* kTrue_SkTriState -> */ kFalse_SkTriState,
128 /* kUnknown_SkTriState -> */ kTrue_SkTriState,
129 };
130 return gCycle[state];
131}
132
reed@google.comf0b5f682011-03-11 20:08:25 +0000133#include "SkDrawFilter.h"
134
reed@google.com569e0432011-04-05 13:07:03 +0000135class FlagsDrawFilter : public SkDrawFilter {
reed@google.comf0b5f682011-03-11 20:08:25 +0000136public:
reed@google.com09e3baa2011-05-18 12:04:31 +0000137 FlagsDrawFilter(SkTriState lcd, SkTriState aa, SkTriState filter,
138 SkTriState hinting) :
139 fLCDState(lcd), fAAState(aa), fFilterState(filter), fHintingState(hinting) {}
reed@google.comf0b5f682011-03-11 20:08:25 +0000140
mike@reedtribe.org3ce59dc2011-04-08 00:38:05 +0000141 virtual void filter(SkPaint* paint, Type t) {
reed@google.com569e0432011-04-05 13:07:03 +0000142 if (kText_Type == t && kUnknown_SkTriState != fLCDState) {
reed@google.com569e0432011-04-05 13:07:03 +0000143 paint->setLCDRenderText(kTrue_SkTriState == fLCDState);
144 }
145 if (kUnknown_SkTriState != fAAState) {
reed@google.com569e0432011-04-05 13:07:03 +0000146 paint->setAntiAlias(kTrue_SkTriState == fAAState);
reed@google.comf0b5f682011-03-11 20:08:25 +0000147 }
reed@google.com176753a2011-05-17 15:32:04 +0000148 if (kUnknown_SkTriState != fFilterState) {
149 paint->setFilterBitmap(kTrue_SkTriState == fFilterState);
150 }
reed@google.com09e3baa2011-05-18 12:04:31 +0000151 if (kUnknown_SkTriState != fHintingState) {
152 paint->setHinting(kTrue_SkTriState == fHintingState ?
153 SkPaint::kNormal_Hinting :
154 SkPaint::kSlight_Hinting);
155 }
reed@google.comf0b5f682011-03-11 20:08:25 +0000156 }
157
158private:
reed@google.com569e0432011-04-05 13:07:03 +0000159 SkTriState fLCDState;
reed@google.com569e0432011-04-05 13:07:03 +0000160 SkTriState fAAState;
reed@google.com176753a2011-05-17 15:32:04 +0000161 SkTriState fFilterState;
reed@google.com09e3baa2011-05-18 12:04:31 +0000162 SkTriState fHintingState;
reed@google.comf0b5f682011-03-11 20:08:25 +0000163};
164
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165//////////////////////////////////////////////////////////////////////////////
166
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000167#define MAX_ZOOM_LEVEL 8
168#define MIN_ZOOM_LEVEL -8
169
reed@android.comf2b98d62010-12-20 18:26:13 +0000170static const char gCharEvtName[] = "SampleCode_Char_Event";
171static const char gKeyEvtName[] = "SampleCode_Key_Event";
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172static const char gTitleEvtName[] = "SampleCode_Title_Event";
173static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event";
reed@android.comf2b98d62010-12-20 18:26:13 +0000174static const char gFastTextEvtName[] = "SampleCode_FastText_Event";
175
176bool SampleCode::CharQ(const SkEvent& evt, SkUnichar* outUni) {
177 if (evt.isType(gCharEvtName, sizeof(gCharEvtName) - 1)) {
178 if (outUni) {
179 *outUni = evt.getFast32();
180 }
181 return true;
182 }
183 return false;
184}
185
186bool SampleCode::KeyQ(const SkEvent& evt, SkKey* outKey) {
187 if (evt.isType(gKeyEvtName, sizeof(gKeyEvtName) - 1)) {
188 if (outKey) {
189 *outKey = (SkKey)evt.getFast32();
190 }
191 return true;
192 }
193 return false;
194}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195
196bool SampleCode::TitleQ(const SkEvent& evt) {
197 return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1);
198}
199
200void SampleCode::TitleR(SkEvent* evt, const char title[]) {
201 SkASSERT(evt && TitleQ(*evt));
202 evt->setString(gTitleEvtName, title);
203}
204
205bool SampleCode::PrefSizeQ(const SkEvent& evt) {
206 return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1);
207}
208
209void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) {
210 SkASSERT(evt && PrefSizeQ(*evt));
211 SkScalar size[2];
212 size[0] = width;
213 size[1] = height;
214 evt->setScalars(gPrefSizeEvtName, 2, size);
215}
216
reed@android.comf2b98d62010-12-20 18:26:13 +0000217bool SampleCode::FastTextQ(const SkEvent& evt) {
218 return evt.isType(gFastTextEvtName, sizeof(gFastTextEvtName) - 1);
219}
220
221///////////////////////////////////////////////////////////////////////////////
222
reed@android.com44177402009-11-23 21:07:51 +0000223static SkMSec gAnimTime;
reed@android.comf2b98d62010-12-20 18:26:13 +0000224static SkMSec gAnimTimePrev;
225
reed@android.com44177402009-11-23 21:07:51 +0000226SkMSec SampleCode::GetAnimTime() { return gAnimTime; }
reed@android.comf2b98d62010-12-20 18:26:13 +0000227SkMSec SampleCode::GetAnimTimeDelta() { return gAnimTime - gAnimTimePrev; }
228SkScalar SampleCode::GetAnimSecondsDelta() {
229 return SkDoubleToScalar(GetAnimTimeDelta() / 1000.0);
230}
reed@android.com44177402009-11-23 21:07:51 +0000231
232SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000233 // since gAnimTime can be up to 32 bits, we can't convert it to a float
234 // or we'll lose the low bits. Hence we use doubles for the intermediate
235 // calculations
236 double seconds = (double)gAnimTime / 1000.0;
237 double value = SkScalarToDouble(speed) * seconds;
reed@android.com44177402009-11-23 21:07:51 +0000238 if (period) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000239 value = ::fmod(value, SkScalarToDouble(period));
reed@android.com44177402009-11-23 21:07:51 +0000240 }
reed@android.comf2b98d62010-12-20 18:26:13 +0000241 return SkDoubleToScalar(value);
reed@android.com44177402009-11-23 21:07:51 +0000242}
243
reed@google.com3cec4d72011-07-06 13:59:47 +0000244GrContext* SampleCode::GetGr() {
245 return gSampleWindow ? gSampleWindow->getGrContext() : NULL;
246}
247
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248//////////////////////////////////////////////////////////////////////////////
249
reed@android.comf2b98d62010-12-20 18:26:13 +0000250static SkView* curr_view(SkWindow* wind) {
251 SkView::F2BIter iter(wind);
252 return iter.next();
253}
254
Scroggo2c8208f2011-06-15 16:49:08 +0000255void SampleWindow::setZoomCenter(float x, float y)
256{
257 fZoomCenterX = SkFloatToScalar(x);
258 fZoomCenterY = SkFloatToScalar(y);
259}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260
djsollen@google.come32b5832011-06-13 16:58:40 +0000261bool SampleWindow::setGrContext(GrContext* context)
262{
263 if (fGrContext) {
264 fGrContext->unref();
265 }
266 fGrContext = context;
267 fGrContext->ref();
268 return true;
269}
270
271GrContext* SampleWindow::getGrContext()
272{
273 return fGrContext;
274}
djsollen@google.come32b5832011-06-13 16:58:40 +0000275
Scroggo0f185c22011-03-24 18:35:50 +0000276bool SampleWindow::zoomIn()
277{
278 // Arbitrarily decided
279 if (fFatBitsScale == 25) return false;
280 fFatBitsScale++;
281 this->inval(NULL);
282 return true;
283}
284
285bool SampleWindow::zoomOut()
286{
287 if (fFatBitsScale == 1) return false;
288 fFatBitsScale--;
289 this->inval(NULL);
290 return true;
291}
292
293void SampleWindow::toggleZoomer()
294{
295 fShowZoomer = !fShowZoomer;
296 this->inval(NULL);
297}
298
299void SampleWindow::updatePointer(int x, int y)
300{
301 fMouseX = x;
302 fMouseY = y;
303 if (fShowZoomer) {
304 this->inval(NULL);
305 }
306}
307
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000308bool SampleWindow::make3DReady() {
309
310#if defined(SK_SUPPORT_GL)
bsalomon@google.com498a6232011-03-10 18:24:15 +0000311 if (attachGL()) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000312 if (NULL != fGrContext) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000313 // various gr lifecycle tests
314 #if 0
315 fGrContext->freeGpuResources();
316 #elif 0
317 // this will leak resources.
318 fGrContext->contextLost();
319 #elif 0
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000320 GrAssert(1 == fGrContext->refcnt());
321 fGrContext->unref();
322 fGrContext = NULL;
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000323 #endif
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000324 }
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000325
bsalomon@google.com498a6232011-03-10 18:24:15 +0000326 if (NULL == fGrContext) {
327 #if defined(SK_USE_SHADERS)
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000328 fGrContext = GrContext::Create(kOpenGL_Shaders_GrEngine, NULL);
bsalomon@google.com498a6232011-03-10 18:24:15 +0000329 #else
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000330 fGrContext = GrContext::Create(kOpenGL_Fixed_GrEngine, NULL);
bsalomon@google.com498a6232011-03-10 18:24:15 +0000331 #endif
reed@google.com569e0432011-04-05 13:07:03 +0000332 SkDebugf("---- constructor\n");
bsalomon@google.com498a6232011-03-10 18:24:15 +0000333 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000334
bsalomon@google.com498a6232011-03-10 18:24:15 +0000335 if (NULL != fGrContext) {
336 return true;
337 } else {
338 detachGL();
339 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000340 }
341#endif
342 SkDebugf("Failed to setup 3D");
343 return false;
344}
345
reed@android.com8a1c16f2008-12-17 15:59:43 +0000346SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
347 static const CanvasType gCT[] = {
348 kPicture_CanvasType,
reed@android.comf2b98d62010-12-20 18:26:13 +0000349 kGPU_CanvasType,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 kRaster_CanvasType
351 };
352 return gCT[ct];
353}
354
senorblanco@chromium.org78b82532011-06-28 19:44:03 +0000355SampleWindow::SampleWindow(void* hwnd, int argc, char** argv) : INHERITED(hwnd) {
reed@google.com3cec4d72011-07-06 13:59:47 +0000356 gSampleWindow = this;
357
yangsu@google.com1f394212011-06-01 18:03:34 +0000358#ifdef PIPE_FILE
359 //Clear existing file or create file if it doesn't exist
360 FILE* f = fopen(FILE_PATH, "wb");
361 fclose(f);
362#endif
363
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364 fPicture = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000366 fGrContext = NULL;
reed@google.com29038ed2011-07-06 17:56:47 +0000367 fGrRenderTarget = NULL;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000368
reed@android.comf2b98d62010-12-20 18:26:13 +0000369#ifdef DEFAULT_TO_GPU
370 fCanvasType = kGPU_CanvasType;
371#else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372 fCanvasType = kRaster_CanvasType;
reed@android.comf2b98d62010-12-20 18:26:13 +0000373#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374 fUseClip = false;
reed@android.come522ca52009-11-23 20:10:41 +0000375 fNClip = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000376 fRepeatDrawing = false;
377 fAnimating = false;
reed@android.com6c5f6f22009-08-14 16:08:38 +0000378 fRotate = false;
379 fScale = false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000380 fRequestGrabImage = false;
reed@google.com0faac1e2011-05-11 05:58:58 +0000381 fUsePipe = false;
mike@reedtribe.org2eb59522011-04-22 01:59:09 +0000382 fMeasureFPS = false;
reed@google.com569e0432011-04-05 13:07:03 +0000383 fLCDState = kUnknown_SkTriState;
384 fAAState = kUnknown_SkTriState;
reed@google.com66f22fd2011-05-17 15:33:45 +0000385 fFilterState = kUnknown_SkTriState;
reed@google.com09e3baa2011-05-18 12:04:31 +0000386 fHintingState = kUnknown_SkTriState;
reed@google.com569e0432011-04-05 13:07:03 +0000387 fFlipAxis = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388 fScrollTestX = fScrollTestY = 0;
389
Scroggo0f185c22011-03-24 18:35:50 +0000390 fMouseX = fMouseY = 0;
mike@reedtribe.org3ce59dc2011-04-08 00:38:05 +0000391 fFatBitsScale = 8;
Scroggo0f185c22011-03-24 18:35:50 +0000392 fTypeface = SkTypeface::CreateFromTypeface(NULL, SkTypeface::kBold);
393 fShowZoomer = false;
394
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000395 fZoomLevel = 0;
396 fZoomScale = SK_Scalar1;
397
Scroggo8ac0d542011-06-21 14:44:57 +0000398 fSaveToPdf = false;
399 fPdfCanvas = NULL;
400
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000401// this->setConfig(SkBitmap::kRGB_565_Config);
402 this->setConfig(SkBitmap::kARGB_8888_Config);
403 this->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +0000404 this->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000405
reed@android.com34245c72009-11-03 04:00:48 +0000406 {
407 const SkViewRegister* reg = SkViewRegister::Head();
408 while (reg) {
409 *fSamples.append() = reg->factory();
410 reg = reg->next();
411 }
412 }
413 fCurrIndex = 0;
senorblanco@chromium.org78b82532011-06-28 19:44:03 +0000414 if (argc > 1) {
415 int i, count = fSamples.count();
416 for (i = 0; i < count; i++) {
417 SkString title = getSampleTitle(i);
418 if (title.equals(argv[1])) {
419 fCurrIndex = i;
420 break;
421 }
422 }
423 if (i == count) {
424 fprintf(stderr, "Unknown sample \"%s\"\n", argv[1]);
425 }
426 }
reed@android.come0f13ee2009-11-04 19:40:25 +0000427 this->loadView(fSamples[fCurrIndex]());
reed@google.comf0b5f682011-03-11 20:08:25 +0000428
Scroggob4490c72011-06-17 13:53:05 +0000429 // If another constructor set our dimensions, ensure that our
430 // onSizeChange gets called.
431 if (this->height() && this->width()) {
432 this->onSizeChange();
433 }
yangsu@google.com501775e2011-06-24 16:04:50 +0000434
435 fPDFData = NULL;
reed@google.com29038ed2011-07-06 17:56:47 +0000436
437 this-make3DReady();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438}
439
440SampleWindow::~SampleWindow() {
441 delete fPicture;
Scroggo8ac0d542011-06-21 14:44:57 +0000442 delete fPdfCanvas;
Scroggo0f185c22011-03-24 18:35:50 +0000443 fTypeface->unref();
reed@google.com29038ed2011-07-06 17:56:47 +0000444
445 SkSafeUnref(fGrRenderTarget);
446 SkSafeUnref(fGrContext);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000447}
448
reed@android.com55e76b22009-11-23 21:46:47 +0000449static SkBitmap capture_bitmap(SkCanvas* canvas) {
450 SkBitmap bm;
451 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
452 src.copyTo(&bm, src.config());
453 return bm;
454}
455
456static bool bitmap_diff(SkCanvas* canvas, const SkBitmap& orig,
457 SkBitmap* diff) {
458 const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000459
reed@android.com55e76b22009-11-23 21:46:47 +0000460 SkAutoLockPixels alp0(src);
461 SkAutoLockPixels alp1(orig);
462 for (int y = 0; y < src.height(); y++) {
463 const void* srcP = src.getAddr(0, y);
464 const void* origP = orig.getAddr(0, y);
465 size_t bytes = src.width() * src.bytesPerPixel();
466 if (memcmp(srcP, origP, bytes)) {
467 SkDebugf("---------- difference on line %d\n", y);
468 return true;
469 }
470 }
471 return false;
472}
473
Scroggo0f185c22011-03-24 18:35:50 +0000474static void drawText(SkCanvas* canvas, SkString string, SkScalar left, SkScalar top, SkPaint& paint)
475{
476 SkColor desiredColor = paint.getColor();
477 paint.setColor(SK_ColorWHITE);
478 const char* c_str = string.c_str();
479 size_t size = string.size();
480 SkRect bounds;
481 paint.measureText(c_str, size, &bounds);
482 bounds.offset(left, top);
483 SkScalar inset = SkIntToScalar(-2);
484 bounds.inset(inset, inset);
485 canvas->drawRect(bounds, paint);
486 if (desiredColor != SK_ColorBLACK) {
487 paint.setColor(SK_ColorBLACK);
488 canvas->drawText(c_str, size, left + SK_Scalar1, top + SK_Scalar1, paint);
489 }
490 paint.setColor(desiredColor);
491 canvas->drawText(c_str, size, left, top, paint);
492}
493
reed@android.com44177402009-11-23 21:07:51 +0000494#define XCLIP_N 8
495#define YCLIP_N 8
reed@android.come522ca52009-11-23 20:10:41 +0000496
497void SampleWindow::draw(SkCanvas* canvas) {
reed@google.com29038ed2011-07-06 17:56:47 +0000498 if (fGrContext && (kGPU_CanvasType == fCanvasType)) {
499 canvas->setDevice(new SkGpuDevice(fGrContext,
500 fGrRenderTarget))->unref();
501 }
502
reed@android.com44177402009-11-23 21:07:51 +0000503 // update the animation time
reed@android.comf2b98d62010-12-20 18:26:13 +0000504 gAnimTimePrev = gAnimTime;
reed@android.com44177402009-11-23 21:07:51 +0000505 gAnimTime = SkTime::GetMSecs();
506
Scroggo2c8208f2011-06-15 16:49:08 +0000507 SkScalar cx = fZoomCenterX;
508 SkScalar cy = fZoomCenterY;
reed@google.com569e0432011-04-05 13:07:03 +0000509
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000510 if (fZoomLevel) {
511 SkMatrix m;
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000512 SkPoint center;
513 m = canvas->getTotalMatrix();//.invert(&m);
514 m.mapXY(cx, cy, &center);
515 cx = center.fX;
516 cy = center.fY;
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000517
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000518 m.setTranslate(-cx, -cy);
519 m.postScale(fZoomScale, fZoomScale);
520 m.postTranslate(cx, cy);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000521
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000522 canvas->concat(m);
523 }
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000524
reed@google.com569e0432011-04-05 13:07:03 +0000525 if (fFlipAxis) {
526 SkMatrix m;
527 m.setTranslate(cx, cy);
528 if (fFlipAxis & kFlipAxis_X) {
529 m.preScale(-SK_Scalar1, SK_Scalar1);
530 }
531 if (fFlipAxis & kFlipAxis_Y) {
532 m.preScale(SK_Scalar1, -SK_Scalar1);
533 }
534 m.preTranslate(-cx, -cy);
535 canvas->concat(m);
536 }
537
reed@google.com52f57e12011-03-16 12:10:02 +0000538 // Apply any gesture matrix
539 if (true) {
540 const SkMatrix& localM = fGesture.localM();
541 if (localM.getType() & SkMatrix::kScale_Mask) {
542 canvas->setExternalMatrix(&localM);
543 }
544 canvas->concat(localM);
545 canvas->concat(fGesture.globalM());
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000546
reed@google.com52f57e12011-03-16 12:10:02 +0000547 if (fGesture.isActive()) {
548 this->inval(NULL);
549 }
550 }
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000551
reed@android.come522ca52009-11-23 20:10:41 +0000552 if (fNClip) {
reed@android.com55e76b22009-11-23 21:46:47 +0000553 this->INHERITED::draw(canvas);
554 SkBitmap orig = capture_bitmap(canvas);
reed@android.come522ca52009-11-23 20:10:41 +0000555
556 const SkScalar w = this->width();
557 const SkScalar h = this->height();
558 const SkScalar cw = w / XCLIP_N;
559 const SkScalar ch = h / YCLIP_N;
560 for (int y = 0; y < YCLIP_N; y++) {
reed@android.com55e76b22009-11-23 21:46:47 +0000561 SkRect r;
562 r.fTop = y * ch;
563 r.fBottom = (y + 1) * ch;
564 if (y == YCLIP_N - 1) {
565 r.fBottom = h;
566 }
reed@android.come522ca52009-11-23 20:10:41 +0000567 for (int x = 0; x < XCLIP_N; x++) {
568 SkAutoCanvasRestore acr(canvas, true);
reed@android.com55e76b22009-11-23 21:46:47 +0000569 r.fLeft = x * cw;
570 r.fRight = (x + 1) * cw;
571 if (x == XCLIP_N - 1) {
572 r.fRight = w;
573 }
reed@android.come522ca52009-11-23 20:10:41 +0000574 canvas->clipRect(r);
575 this->INHERITED::draw(canvas);
576 }
577 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000578
reed@android.com55e76b22009-11-23 21:46:47 +0000579 SkBitmap diff;
580 if (bitmap_diff(canvas, orig, &diff)) {
581 }
reed@android.come522ca52009-11-23 20:10:41 +0000582 } else {
583 this->INHERITED::draw(canvas);
584 }
Scroggo8ac0d542011-06-21 14:44:57 +0000585 if (fShowZoomer && fCanvasType != kGPU_CanvasType && !fSaveToPdf) {
Scroggo3272ba82011-05-25 20:50:42 +0000586 // In the GPU case, INHERITED::draw calls beforeChildren, which
587 // creates an SkGpuCanvas. All further draw calls are directed
588 // at that canvas, which is deleted in afterChildren (which is
589 // also called by draw), so we cannot show the zoomer here.
590 // Instead, we call it inside afterChildren.
591 showZoomer(canvas);
592 }
reed@google.com29038ed2011-07-06 17:56:47 +0000593
594 // do this last
595 if (fGrContext && (fCanvasType != kGPU_CanvasType)) {
596 fGrContext->setRenderTarget(fGrRenderTarget);
597 // need to send the bits to the (gpu) window
598 const SkBitmap& bm = this->getBitmap();
599 fGrContext->writePixels(0, 0, bm.width(), bm.height(),
600 kRGBA_8888_GrPixelConfig, bm.getPixels(),
601 bm.rowBytes());
602 }
603 presentGL();
Scroggo3272ba82011-05-25 20:50:42 +0000604}
605
606void SampleWindow::showZoomer(SkCanvas* canvas) {
Scroggo0f185c22011-03-24 18:35:50 +0000607 int count = canvas->save();
608 canvas->resetMatrix();
609 // Ensure the mouse position is on screen.
reed@google.com261b8e22011-04-14 17:53:24 +0000610 int width = SkScalarRound(this->width());
611 int height = SkScalarRound(this->height());
Scroggo0f185c22011-03-24 18:35:50 +0000612 if (fMouseX >= width) fMouseX = width - 1;
613 else if (fMouseX < 0) fMouseX = 0;
614 if (fMouseY >= height) fMouseY = height - 1;
615 else if (fMouseY < 0) fMouseY = 0;
reed@google.comb36334d2011-05-18 15:07:20 +0000616
Scroggo0f185c22011-03-24 18:35:50 +0000617 SkBitmap bitmap = capture_bitmap(canvas);
reed@google.comb36334d2011-05-18 15:07:20 +0000618 bitmap.lockPixels();
619
Scroggo0f185c22011-03-24 18:35:50 +0000620 // 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 +0000621 int zoomedWidth = (width >> 1) | 1;
622 int zoomedHeight = (height >> 1) | 1;
Scroggo0f185c22011-03-24 18:35:50 +0000623 SkIRect src;
624 src.set(0, 0, zoomedWidth / fFatBitsScale, zoomedHeight / fFatBitsScale);
625 src.offset(fMouseX - (src.width()>>1), fMouseY - (src.height()>>1));
626 SkRect dest;
627 dest.set(0, 0, SkIntToScalar(zoomedWidth), SkIntToScalar(zoomedHeight));
628 dest.offset(SkIntToScalar(width - zoomedWidth), SkIntToScalar(height - zoomedHeight));
629 SkPaint paint;
630 // Clear the background behind our zoomed in view
631 paint.setColor(SK_ColorWHITE);
632 canvas->drawRect(dest, paint);
633 canvas->drawBitmapRect(bitmap, &src, dest);
634 paint.setColor(SK_ColorBLACK);
635 paint.setStyle(SkPaint::kStroke_Style);
636 // Draw a border around the pixel in the middle
637 SkRect originalPixel;
638 originalPixel.set(SkIntToScalar(fMouseX), SkIntToScalar(fMouseY), SkIntToScalar(fMouseX + 1), SkIntToScalar(fMouseY + 1));
639 SkMatrix matrix;
640 SkRect scalarSrc;
641 scalarSrc.set(src);
642 SkColor color = bitmap.getColor(fMouseX, fMouseY);
643 if (matrix.setRectToRect(scalarSrc, dest, SkMatrix::kFill_ScaleToFit)) {
644 SkRect pixel;
645 matrix.mapRect(&pixel, originalPixel);
646 // TODO Perhaps measure the values and make the outline white if it's "dark"
647 if (color == SK_ColorBLACK) {
648 paint.setColor(SK_ColorWHITE);
649 }
650 canvas->drawRect(pixel, paint);
651 }
652 paint.setColor(SK_ColorBLACK);
653 // Draw a border around the destination rectangle
654 canvas->drawRect(dest, paint);
655 paint.setStyle(SkPaint::kStrokeAndFill_Style);
656 // Identify the pixel and its color on screen
657 paint.setTypeface(fTypeface);
658 paint.setAntiAlias(true);
659 SkScalar lineHeight = paint.getFontMetrics(NULL);
660 SkString string;
661 string.appendf("(%i, %i)", fMouseX, fMouseY);
662 SkScalar left = dest.fLeft + SkIntToScalar(3);
663 SkScalar i = SK_Scalar1;
664 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
665 // Alpha
666 i += SK_Scalar1;
667 string.reset();
668 string.appendf("A: %X", SkColorGetA(color));
669 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
670 // Red
671 i += SK_Scalar1;
672 string.reset();
673 string.appendf("R: %X", SkColorGetR(color));
674 paint.setColor(SK_ColorRED);
675 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
676 // Green
677 i += SK_Scalar1;
678 string.reset();
679 string.appendf("G: %X", SkColorGetG(color));
680 paint.setColor(SK_ColorGREEN);
681 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
682 // Blue
683 i += SK_Scalar1;
684 string.reset();
685 string.appendf("B: %X", SkColorGetB(color));
686 paint.setColor(SK_ColorBLUE);
687 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
688 canvas->restoreToCount(count);
reed@android.come522ca52009-11-23 20:10:41 +0000689}
690
reed@android.com8a1c16f2008-12-17 15:59:43 +0000691void SampleWindow::onDraw(SkCanvas* canvas) {
692 if (fRepeatDrawing) {
693 this->inval(NULL);
694 }
695}
696
697#include "SkColorPriv.h"
698
699static void reverseRedAndBlue(const SkBitmap& bm) {
700 SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
701 uint8_t* p = (uint8_t*)bm.getPixels();
702 uint8_t* stop = p + bm.getSize();
703 while (p < stop) {
704 // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
705 unsigned scale = SkAlpha255To256(p[3]);
706 unsigned r = p[2];
707 unsigned b = p[0];
708 p[0] = SkAlphaMul(r, scale);
709 p[1] = SkAlphaMul(p[1], scale);
710 p[2] = SkAlphaMul(b, scale);
711 p += 4;
712 }
713}
714
Scroggo8ac0d542011-06-21 14:44:57 +0000715void SampleWindow::saveToPdf()
716{
717 fSaveToPdf = true;
718 this->inval(NULL);
719}
720
reed@android.com8a1c16f2008-12-17 15:59:43 +0000721SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
Scroggo8ac0d542011-06-21 14:44:57 +0000722 if (fSaveToPdf) {
723 const SkBitmap& bmp = canvas->getDevice()->accessBitmap(false);
724 SkISize size = SkISize::Make(bmp.width(), bmp.height());
725 SkPDFDevice* pdfDevice = new SkPDFDevice(size, size,
726 canvas->getTotalMatrix());
727 fPdfCanvas = new SkCanvas(pdfDevice);
728 pdfDevice->unref();
729 canvas = fPdfCanvas;
730 } else {
731 switch (fCanvasType) {
732 case kRaster_CanvasType:
reed@google.com29038ed2011-07-06 17:56:47 +0000733 case kGPU_CanvasType:
reed@android.comf2b98d62010-12-20 18:26:13 +0000734 canvas = this->INHERITED::beforeChildren(canvas);
Scroggo8ac0d542011-06-21 14:44:57 +0000735 break;
736 case kPicture_CanvasType:
737 fPicture = new SkPicture;
738 canvas = fPicture->beginRecording(9999, 9999);
739 break;
reed@google.comac10a2d2010-12-22 21:39:39 +0000740 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000741 }
742
743 if (fUseClip) {
744 canvas->drawColor(0xFFFF88FF);
745 canvas->clipPath(fClipPath);
746 }
747
748 return canvas;
749}
750
751static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
752 const SkRegion& rgn) {
753 SkCanvas canvas(bm);
754 SkRegion inval(rgn);
755
756 inval.translate(r.fLeft, r.fTop);
757 canvas.clipRegion(inval);
758 canvas.drawColor(0xFFFF8080);
759}
yangsu@google.com501775e2011-06-24 16:04:50 +0000760#include "SkData.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +0000761void SampleWindow::afterChildren(SkCanvas* orig) {
Scroggo8ac0d542011-06-21 14:44:57 +0000762 if (fSaveToPdf) {
763 fSaveToPdf = false;
764 if (fShowZoomer) {
765 showZoomer(fPdfCanvas);
766 }
767 SkString name;
768 name.printf("%s.pdf", this->getTitle());
769 SkPDFDocument doc;
770 SkPDFDevice* device = static_cast<SkPDFDevice*>(fPdfCanvas->getDevice());
771 doc.appendPage(device);
772#ifdef ANDROID
773 name.prepend("/sdcard/");
774#endif
yangsu@google.com501775e2011-06-24 16:04:50 +0000775
776#ifdef SK_BUILD_FOR_IOS
777 SkDynamicMemoryWStream mstream;
778 doc.emitPDF(&mstream);
yangsu@google.comae8a2e52011-06-24 21:09:39 +0000779 fPDFData = mstream.copyToData();
yangsu@google.com501775e2011-06-24 16:04:50 +0000780#endif
Scroggo8ac0d542011-06-21 14:44:57 +0000781 SkFILEWStream stream(name.c_str());
782 if (stream.isValid()) {
783 doc.emitPDF(&stream);
784 const char* desc = "File saved from Skia SampleApp";
785 this->onPDFSaved(this->getTitle(), desc, name.c_str());
786 }
yangsu@google.com501775e2011-06-24 16:04:50 +0000787
Scroggo8ac0d542011-06-21 14:44:57 +0000788 delete fPdfCanvas;
789 fPdfCanvas = NULL;
790
791 // We took over the draw calls in order to create the PDF, so we need
792 // to redraw.
793 this->inval(NULL);
794 return;
795 }
796
reed@android.comf2b98d62010-12-20 18:26:13 +0000797 if (fRequestGrabImage) {
798 fRequestGrabImage = false;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000799
reed@google.com29038ed2011-07-06 17:56:47 +0000800 SkDevice* device = orig->getDevice();
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000801 SkBitmap bmp;
802 if (device->accessBitmap(false).copyTo(&bmp, SkBitmap::kARGB_8888_Config)) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000803 static int gSampleGrabCounter;
804 SkString name;
805 name.printf("sample_grab_%d", gSampleGrabCounter++);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000806 SkImageEncoder::EncodeFile(name.c_str(), bmp,
reed@android.comf2b98d62010-12-20 18:26:13 +0000807 SkImageEncoder::kPNG_Type, 100);
808 }
809 }
810
reed@android.com8a1c16f2008-12-17 15:59:43 +0000811 switch (fCanvasType) {
812 case kRaster_CanvasType:
813 break;
814 case kPicture_CanvasType:
reed@android.comaefd2bc2009-03-30 21:02:14 +0000815 if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000816 SkPicture* pict = new SkPicture(*fPicture);
817 fPicture->unref();
818 orig->drawPicture(*pict);
819 pict->unref();
reed@android.comaefd2bc2009-03-30 21:02:14 +0000820 } else if (true) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000821 SkDynamicMemoryWStream ostream;
822 fPicture->serialize(&ostream);
823 fPicture->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000824
reed@google.com8a85d0c2011-06-24 19:12:12 +0000825 SkAutoDataUnref data(ostream.copyToData());
826 SkMemoryStream istream(data.data(), data.size());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827 SkPicture pict(&istream);
828 orig->drawPicture(pict);
829 } else {
830 fPicture->draw(orig);
831 fPicture->unref();
832 }
833 fPicture = NULL;
834 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000835#ifdef SK_SUPPORT_GL
reed@android.comf2b98d62010-12-20 18:26:13 +0000836 case kGPU_CanvasType:
reed@google.com29038ed2011-07-06 17:56:47 +0000837 if (fShowZoomer) {
838 this->showZoomer(orig);
Scroggo3272ba82011-05-25 20:50:42 +0000839 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000840 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000841#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000842 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000843
reed@google.com17d7aec2011-04-25 14:31:44 +0000844 // Do this after presentGL and other finishing, rather than in afterChild
845 if (fMeasureFPS && fMeasureFPS_Time) {
846 fMeasureFPS_Time = SkTime::GetMSecs() - fMeasureFPS_Time;
847 this->updateTitle();
Scroggo62b65b02011-06-21 16:01:26 +0000848 this->postInvalDelay();
reed@google.com17d7aec2011-04-25 14:31:44 +0000849 }
850
851 // if ((fScrollTestX | fScrollTestY) != 0)
reed@android.comf2b98d62010-12-20 18:26:13 +0000852 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000853 const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
854 int dx = fScrollTestX * 7;
855 int dy = fScrollTestY * 7;
856 SkIRect r;
857 SkRegion inval;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000858
reed@android.com8a1c16f2008-12-17 15:59:43 +0000859 r.set(50, 50, 50+100, 50+100);
860 bm.scrollRect(&r, dx, dy, &inval);
861 paint_rgn(bm, r, inval);
mike@reedtribe.org2eb59522011-04-22 01:59:09 +0000862 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000863}
864
reed@android.com6c5f6f22009-08-14 16:08:38 +0000865void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
866 if (fScale) {
867 SkScalar scale = SK_Scalar1 * 7 / 10;
868 SkScalar cx = this->width() / 2;
869 SkScalar cy = this->height() / 2;
870 canvas->translate(cx, cy);
871 canvas->scale(scale, scale);
872 canvas->translate(-cx, -cy);
873 }
874 if (fRotate) {
875 SkScalar cx = this->width() / 2;
876 SkScalar cy = this->height() / 2;
877 canvas->translate(cx, cy);
878 canvas->rotate(SkIntToScalar(30));
879 canvas->translate(-cx, -cy);
880 }
reed@google.comf0b5f682011-03-11 20:08:25 +0000881
reed@google.com09e3baa2011-05-18 12:04:31 +0000882 canvas->setDrawFilter(new FlagsDrawFilter(fLCDState, fAAState,
883 fFilterState, fHintingState))->unref();
mike@reedtribe.org2eb59522011-04-22 01:59:09 +0000884
mike@reedtribe.org2eb59522011-04-22 01:59:09 +0000885 if (fMeasureFPS) {
reed@google.comf2183392011-04-22 14:10:48 +0000886 fMeasureFPS_Time = 0; // 0 means the child is not aware of repeat-draw
887 if (SampleView::SetRepeatDraw(child, FPS_REPEAT_COUNT)) {
888 fMeasureFPS_Time = SkTime::GetMSecs();
889 }
890 } else {
891 (void)SampleView::SetRepeatDraw(child, 1);
mike@reedtribe.org2eb59522011-04-22 01:59:09 +0000892 }
reed@google.com0faac1e2011-05-11 05:58:58 +0000893 (void)SampleView::SetUsePipe(child, fUsePipe);
reed@android.com6c5f6f22009-08-14 16:08:38 +0000894}
895
896void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) {
reed@google.comf0b5f682011-03-11 20:08:25 +0000897 canvas->setDrawFilter(NULL);
reed@android.com6c5f6f22009-08-14 16:08:38 +0000898}
899
reed@android.com8a1c16f2008-12-17 15:59:43 +0000900static SkBitmap::Config gConfigCycle[] = {
901 SkBitmap::kNo_Config, // none -> none
902 SkBitmap::kNo_Config, // a1 -> none
903 SkBitmap::kNo_Config, // a8 -> none
904 SkBitmap::kNo_Config, // index8 -> none
905 SkBitmap::kARGB_4444_Config, // 565 -> 4444
906 SkBitmap::kARGB_8888_Config, // 4444 -> 8888
907 SkBitmap::kRGB_565_Config // 8888 -> 565
908};
909
910static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
911 return gConfigCycle[c];
912}
913
djsollen@google.come32b5832011-06-13 16:58:40 +0000914void SampleWindow::changeZoomLevel(float delta) {
915 fZoomLevel += SkFloatToScalar(delta);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000916 if (fZoomLevel > 0) {
djsollen@google.come32b5832011-06-13 16:58:40 +0000917 fZoomLevel = SkMinScalar(fZoomLevel, MAX_ZOOM_LEVEL);
918 fZoomScale = fZoomLevel + SK_Scalar1;
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000919 } else if (fZoomLevel < 0) {
djsollen@google.come32b5832011-06-13 16:58:40 +0000920 fZoomLevel = SkMaxScalar(fZoomLevel, MIN_ZOOM_LEVEL);
921 fZoomScale = SK_Scalar1 / (SK_Scalar1 - fZoomLevel);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000922 } else {
923 fZoomScale = SK_Scalar1;
924 }
925
djsollen@google.come32b5832011-06-13 16:58:40 +0000926 this->updateTitle();
927
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +0000928 this->inval(NULL);
929}
930
Scroggo2c8208f2011-06-15 16:49:08 +0000931bool SampleWindow::previousSample() {
Scroggo62b65b02011-06-21 16:01:26 +0000932 fCurrIndex = (fCurrIndex - 1 + fSamples.count()) % fSamples.count();
Scroggo2c8208f2011-06-15 16:49:08 +0000933 this->loadView(fSamples[fCurrIndex]());
934 return true;
935}
936
reed@android.com8a1c16f2008-12-17 15:59:43 +0000937bool SampleWindow::nextSample() {
reed@android.com34245c72009-11-03 04:00:48 +0000938 fCurrIndex = (fCurrIndex + 1) % fSamples.count();
939 this->loadView(fSamples[fCurrIndex]());
940 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000941}
942
yangsu@google.com501775e2011-06-24 16:04:50 +0000943bool SampleWindow::goToSample(int i) {
944 fCurrIndex = (i) % fSamples.count();
945 this->loadView(fSamples[fCurrIndex]());
946 return true;
947}
948
949SkString SampleWindow::getSampleTitle(int i) {
950 SkView* view = fSamples[i]();
951 SkString title;
952 SkEvent evt(gTitleEvtName);
953 if (view->doQuery(&evt)) {
954 title.set(evt.findString(gTitleEvtName));
955 }
956 view->unref();
957 return title;
958}
959
960int SampleWindow::sampleCount() {
961 return fSamples.count();
962}
963
Scroggo2c8208f2011-06-15 16:49:08 +0000964void SampleWindow::postAnimatingEvent() {
965 if (fAnimating) {
966 SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
967 evt->post(this->getSinkID(), ANIMATING_DELAY);
968 }
969}
970
reed@android.com8a1c16f2008-12-17 15:59:43 +0000971bool SampleWindow::onEvent(const SkEvent& evt) {
972 if (evt.isType(ANIMATING_EVENTTYPE)) {
973 if (fAnimating) {
974 this->nextSample();
975 this->postAnimatingEvent();
976 }
977 return true;
978 }
reed@android.com34245c72009-11-03 04:00:48 +0000979 if (evt.isType("set-curr-index")) {
980 fCurrIndex = evt.getFast32() % fSamples.count();
981 this->loadView(fSamples[fCurrIndex]());
982 return true;
983 }
mike@reedtribe.org2eb59522011-04-22 01:59:09 +0000984 if (isInvalEvent(evt)) {
985 this->inval(NULL);
986 return true;
987 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000988 return this->INHERITED::onEvent(evt);
989}
990
reed@android.comf2b98d62010-12-20 18:26:13 +0000991bool SampleWindow::onQuery(SkEvent* query) {
992 if (query->isType("get-slide-count")) {
993 query->setFast32(fSamples.count());
994 return true;
995 }
996 if (query->isType("get-slide-title")) {
997 SkView* view = fSamples[query->getFast32()]();
998 SkEvent evt(gTitleEvtName);
999 if (view->doQuery(&evt)) {
1000 query->setString("title", evt.findString(gTitleEvtName));
1001 }
1002 SkSafeUnref(view);
1003 return true;
1004 }
1005 if (query->isType("use-fast-text")) {
1006 SkEvent evt(gFastTextEvtName);
1007 return curr_view(this)->doQuery(&evt);
1008 }
reed@google.com29038ed2011-07-06 17:56:47 +00001009 if (query->isType("ignore-window-bitmap")) {
1010 query->setFast32(this->getGrContext() != NULL);
1011 return true;
1012 }
reed@android.comf2b98d62010-12-20 18:26:13 +00001013 return this->INHERITED::onQuery(query);
1014}
1015
reed@android.com0ae6b242008-12-23 16:49:54 +00001016static void cleanup_for_filename(SkString* name) {
1017 char* str = name->writable_str();
reed@android.come191b162009-12-18 21:33:39 +00001018 for (size_t i = 0; i < name->size(); i++) {
reed@android.com0ae6b242008-12-23 16:49:54 +00001019 switch (str[i]) {
1020 case ':': str[i] = '-'; break;
1021 case '/': str[i] = '-'; break;
1022 case ' ': str[i] = '_'; break;
1023 default: break;
1024 }
1025 }
1026}
reed@android.com8a1c16f2008-12-17 15:59:43 +00001027
1028bool SampleWindow::onHandleChar(SkUnichar uni) {
reed@android.comf2b98d62010-12-20 18:26:13 +00001029 {
1030 SkView* view = curr_view(this);
1031 if (view) {
1032 SkEvent evt(gCharEvtName);
1033 evt.setFast32(uni);
1034 if (view->doQuery(&evt)) {
1035 return true;
1036 }
1037 }
1038 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001039
reed@android.com8a1c16f2008-12-17 15:59:43 +00001040 int dx = 0xFF;
1041 int dy = 0xFF;
1042
1043 switch (uni) {
1044 case '5': dx = 0; dy = 0; break;
1045 case '8': dx = 0; dy = -1; break;
1046 case '6': dx = 1; dy = 0; break;
1047 case '2': dx = 0; dy = 1; break;
1048 case '4': dx = -1; dy = 0; break;
1049 case '7': dx = -1; dy = -1; break;
1050 case '9': dx = 1; dy = -1; break;
1051 case '3': dx = 1; dy = 1; break;
1052 case '1': dx = -1; dy = 1; break;
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001053
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054 default:
1055 break;
1056 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001057
reed@android.com8a1c16f2008-12-17 15:59:43 +00001058 if (0xFF != dx && 0xFF != dy) {
1059 if ((dx | dy) == 0) {
1060 fScrollTestX = fScrollTestY = 0;
1061 } else {
1062 fScrollTestX += dx;
1063 fScrollTestY += dy;
1064 }
1065 this->inval(NULL);
1066 return true;
1067 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001068
reed@android.com0ae6b242008-12-23 16:49:54 +00001069 switch (uni) {
1070 case 'a':
Scroggo2c8208f2011-06-15 16:49:08 +00001071 this->toggleSlideshow();
reed@android.com0ae6b242008-12-23 16:49:54 +00001072 return true;
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001073 case 'b':
1074 fAAState = cycle_tristate(fAAState);
1075 this->updateTitle();
1076 this->inval(NULL);
1077 break;
1078 case 'c':
1079 fUseClip = !fUseClip;
1080 this->inval(NULL);
1081 this->updateTitle();
reed@android.com0ae6b242008-12-23 16:49:54 +00001082 return true;
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001083 case 'd':
1084 SkGraphics::SetFontCacheUsed(0);
1085 return true;
Scroggo8ac0d542011-06-21 14:44:57 +00001086 case 'e':
1087 this->saveToPdf();
1088 break;
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001089 case 'f':
Scroggo2c8208f2011-06-15 16:49:08 +00001090 this->toggleFPS();
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001091 break;
1092 case 'g':
1093 fRequestGrabImage = true;
1094 this->inval(NULL);
1095 break;
reed@google.com09e3baa2011-05-18 12:04:31 +00001096 case 'h':
1097 fHintingState = cycle_tristate(fHintingState);
1098 this->updateTitle();
1099 this->inval(NULL);
1100 break;
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001101 case 'i':
1102 this->zoomIn();
1103 break;
1104 case 'l':
1105 fLCDState = cycle_tristate(fLCDState);
1106 this->updateTitle();
1107 this->inval(NULL);
1108 break;
reed@google.com176753a2011-05-17 15:32:04 +00001109 case 'n':
1110 fFilterState = cycle_tristate(fFilterState);
1111 this->updateTitle();
1112 this->inval(NULL);
1113 break;
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001114 case 'o':
1115 this->zoomOut();
1116 break;
reed@google.com0faac1e2011-05-11 05:58:58 +00001117 case 'p':
1118 fUsePipe = !fUsePipe;
reed@google.coma6ff4dc2011-05-12 22:08:24 +00001119 this->updateTitle();
reed@google.com0faac1e2011-05-11 05:58:58 +00001120 this->inval(NULL);
1121 break;
reed@android.com6c5f6f22009-08-14 16:08:38 +00001122 case 'r':
1123 fRotate = !fRotate;
1124 this->inval(NULL);
1125 this->updateTitle();
1126 return true;
1127 case 's':
1128 fScale = !fScale;
1129 this->inval(NULL);
1130 this->updateTitle();
1131 return true;
reed@google.com569e0432011-04-05 13:07:03 +00001132 case 'x':
1133 fFlipAxis ^= kFlipAxis_X;
1134 this->updateTitle();
1135 this->inval(NULL);
1136 break;
1137 case 'y':
1138 fFlipAxis ^= kFlipAxis_Y;
1139 this->updateTitle();
1140 this->inval(NULL);
1141 break;
scroggo08526c02011-03-22 14:03:21 +00001142 case 'z':
1143 this->toggleZoomer();
1144 break;
reed@android.com0ae6b242008-12-23 16:49:54 +00001145 default:
1146 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001148
reed@android.com8a1c16f2008-12-17 15:59:43 +00001149 return this->INHERITED::onHandleChar(uni);
1150}
1151
Scroggo2c8208f2011-06-15 16:49:08 +00001152void SampleWindow::toggleFPS() {
1153 fMeasureFPS = !fMeasureFPS;
1154 this->inval(NULL);
1155 this->updateTitle();
1156}
1157
1158void SampleWindow::toggleSlideshow() {
1159 fAnimating = !fAnimating;
1160 this->postAnimatingEvent();
1161 this->updateTitle();
1162}
1163
1164void SampleWindow::toggleRendering() {
1165 fCanvasType = cycle_canvastype(fCanvasType);
1166 this->updateTitle();
1167 this->inval(NULL);
1168}
1169
reed@android.com8a1c16f2008-12-17 15:59:43 +00001170#include "SkDumpCanvas.h"
1171
1172bool SampleWindow::onHandleKey(SkKey key) {
reed@android.comf2b98d62010-12-20 18:26:13 +00001173 {
1174 SkView* view = curr_view(this);
1175 if (view) {
1176 SkEvent evt(gKeyEvtName);
1177 evt.setFast32(key);
1178 if (view->doQuery(&evt)) {
1179 return true;
1180 }
1181 }
1182 }
1183
reed@android.com8a1c16f2008-12-17 15:59:43 +00001184 switch (key) {
1185 case kRight_SkKey:
1186 if (this->nextSample()) {
1187 return true;
1188 }
1189 break;
1190 case kLeft_SkKey:
Scroggo2c8208f2011-06-15 16:49:08 +00001191 toggleRendering();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001192 return true;
1193 case kUp_SkKey:
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001194 if (USE_ARROWS_FOR_ZOOM) {
djsollen@google.come32b5832011-06-13 16:58:40 +00001195 this->changeZoomLevel(1.f);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001196 } else {
1197 fNClip = !fNClip;
1198 this->inval(NULL);
djsollen@google.come32b5832011-06-13 16:58:40 +00001199 this->updateTitle();
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001200 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001201 return true;
1202 case kDown_SkKey:
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001203 if (USE_ARROWS_FOR_ZOOM) {
djsollen@google.come32b5832011-06-13 16:58:40 +00001204 this->changeZoomLevel(-1.f);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001205 } else {
1206 this->setConfig(cycle_configs(this->getBitmap().config()));
djsollen@google.come32b5832011-06-13 16:58:40 +00001207 this->updateTitle();
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001208 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001209 return true;
1210 case kOK_SkKey:
reed@android.comf2b98d62010-12-20 18:26:13 +00001211 if (false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001212 SkDebugfDumper dumper;
1213 SkDumpCanvas dc(&dumper);
1214 this->draw(&dc);
1215 } else {
1216 fRepeatDrawing = !fRepeatDrawing;
1217 if (fRepeatDrawing) {
1218 this->inval(NULL);
1219 }
1220 }
1221 return true;
reed@android.com34245c72009-11-03 04:00:48 +00001222 case kBack_SkKey:
1223 this->loadView(NULL);
1224 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001225 default:
1226 break;
1227 }
1228 return this->INHERITED::onHandleKey(key);
1229}
1230
reed@google.com52f57e12011-03-16 12:10:02 +00001231///////////////////////////////////////////////////////////////////////////////
1232
1233static const char gGestureClickType[] = "GestureClickType";
1234
Scroggod3aed392011-06-22 13:26:56 +00001235bool SampleWindow::onDispatchClick(int x, int y, Click::State state,
1236 void* owner) {
Scroggo0f185c22011-03-24 18:35:50 +00001237 if (Click::kMoved_State == state) {
1238 updatePointer(x, y);
1239 }
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001240 int w = SkScalarRound(this->width());
1241 int h = SkScalarRound(this->height());
1242
1243 // check for the resize-box
1244 if (w - x < 16 && h - y < 16) {
1245 return false; // let the OS handle the click
1246 } else {
Scroggod3aed392011-06-22 13:26:56 +00001247 return this->INHERITED::onDispatchClick(x, y, state, owner);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001248 }
1249}
1250
reed@google.com52f57e12011-03-16 12:10:02 +00001251class GestureClick : public SkView::Click {
1252public:
1253 GestureClick(SkView* target) : SkView::Click(target) {
1254 this->setType(gGestureClickType);
1255 }
1256
1257 static bool IsGesture(Click* click) {
1258 return click->isType(gGestureClickType);
1259 }
1260};
1261
1262SkView::Click* SampleWindow::onFindClickHandler(SkScalar x, SkScalar y) {
1263 return new GestureClick(this);
1264}
1265
1266bool SampleWindow::onClick(Click* click) {
1267 if (GestureClick::IsGesture(click)) {
1268 float x = SkScalarToFloat(click->fCurr.fX);
1269 float y = SkScalarToFloat(click->fCurr.fY);
1270 switch (click->fState) {
1271 case SkView::Click::kDown_State:
Scroggod3aed392011-06-22 13:26:56 +00001272 fGesture.touchBegin(click->fOwner, x, y);
reed@google.com52f57e12011-03-16 12:10:02 +00001273 break;
1274 case SkView::Click::kMoved_State:
Scroggod3aed392011-06-22 13:26:56 +00001275 fGesture.touchMoved(click->fOwner, x, y);
reed@google.com52f57e12011-03-16 12:10:02 +00001276 this->inval(NULL);
1277 break;
1278 case SkView::Click::kUp_State:
Scroggod3aed392011-06-22 13:26:56 +00001279 fGesture.touchEnd(click->fOwner);
reed@google.com52f57e12011-03-16 12:10:02 +00001280 this->inval(NULL);
1281 break;
1282 }
1283 return true;
1284 }
1285 return false;
1286}
1287
1288///////////////////////////////////////////////////////////////////////////////
1289
reed@android.com8a1c16f2008-12-17 15:59:43 +00001290void SampleWindow::loadView(SkView* view) {
1291 SkView::F2BIter iter(this);
1292 SkView* prev = iter.next();
1293 if (prev) {
1294 prev->detachFromParent();
1295 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001296
reed@android.com34245c72009-11-03 04:00:48 +00001297 if (NULL == view) {
1298 view = create_overview(fSamples.count(), fSamples.begin());
1299 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300 view->setVisibleP(true);
reed@android.comf2b98d62010-12-20 18:26:13 +00001301 view->setClipToBounds(false);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302 this->attachChildToFront(view)->unref();
1303 view->setSize(this->width(), this->height());
1304
1305 this->updateTitle();
1306}
1307
1308static const char* gConfigNames[] = {
1309 "unknown config",
1310 "A1",
1311 "A8",
1312 "Index8",
1313 "565",
1314 "4444",
1315 "8888"
1316};
1317
1318static const char* configToString(SkBitmap::Config c) {
1319 return gConfigNames[c];
1320}
1321
1322static const char* gCanvasTypePrefix[] = {
1323 "raster: ",
1324 "picture: ",
1325 "opengl: "
1326};
1327
reed@google.com569e0432011-04-05 13:07:03 +00001328static const char* trystate_str(SkTriState state,
1329 const char trueStr[], const char falseStr[]) {
1330 if (kTrue_SkTriState == state) {
1331 return trueStr;
1332 } else if (kFalse_SkTriState == state) {
1333 return falseStr;
1334 }
1335 return NULL;
1336}
1337
reed@android.com8a1c16f2008-12-17 15:59:43 +00001338void SampleWindow::updateTitle() {
1339 SkString title;
1340
1341 SkView::F2BIter iter(this);
1342 SkView* view = iter.next();
1343 SkEvent evt(gTitleEvtName);
1344 if (view->doQuery(&evt)) {
1345 title.set(evt.findString(gTitleEvtName));
1346 }
1347 if (title.size() == 0) {
1348 title.set("<unknown>");
1349 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001350
reed@android.com8a1c16f2008-12-17 15:59:43 +00001351 title.prepend(gCanvasTypePrefix[fCanvasType]);
1352
1353 title.prepend(" ");
1354 title.prepend(configToString(this->getBitmap().config()));
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001355
reed@android.com8a1c16f2008-12-17 15:59:43 +00001356 if (fAnimating) {
1357 title.prepend("<A> ");
1358 }
reed@android.com6c5f6f22009-08-14 16:08:38 +00001359 if (fScale) {
1360 title.prepend("<S> ");
1361 }
1362 if (fRotate) {
1363 title.prepend("<R> ");
1364 }
reed@android.come522ca52009-11-23 20:10:41 +00001365 if (fNClip) {
1366 title.prepend("<C> ");
1367 }
reed@google.com569e0432011-04-05 13:07:03 +00001368
1369 title.prepend(trystate_str(fLCDState, "LCD ", "lcd "));
1370 title.prepend(trystate_str(fAAState, "AA ", "aa "));
reed@google.com09e3baa2011-05-18 12:04:31 +00001371 title.prepend(trystate_str(fFilterState, "H ", "h "));
reed@google.com569e0432011-04-05 13:07:03 +00001372 title.prepend(fFlipAxis & kFlipAxis_X ? "X " : NULL);
1373 title.prepend(fFlipAxis & kFlipAxis_Y ? "Y " : NULL);
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001374
1375 if (fZoomLevel) {
djsollen@google.come32b5832011-06-13 16:58:40 +00001376 title.prependf("{%.2f} ", SkScalarToFloat(fZoomLevel));
mike@reedtribe.orgdd0cd342011-03-21 00:53:39 +00001377 }
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001378
1379 if (fMeasureFPS) {
reed@google.combad8c872011-05-18 20:10:31 +00001380 title.appendf(" %6.1f ms", fMeasureFPS_Time / (float)FPS_REPEAT_MULTIPLIER);
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001381 }
reed@google.coma6ff4dc2011-05-12 22:08:24 +00001382 if (fUsePipe && SampleView::IsSampleView(view)) {
1383 title.prepend("<P> ");
1384 }
1385 if (SampleView::IsSampleView(view)) {
1386 title.prepend("! ");
1387 }
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001388
reed@android.com8a1c16f2008-12-17 15:59:43 +00001389 this->setTitle(title.c_str());
1390}
1391
1392void SampleWindow::onSizeChange() {
1393 this->INHERITED::onSizeChange();
1394
reed@google.com29038ed2011-07-06 17:56:47 +00001395 if (fGrContext) {
1396 this->attachGL();
1397
1398 GrPlatformSurfaceDesc desc;
1399 desc.reset();
1400 desc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType;
1401 desc.fWidth = SkScalarRound(this->width());
1402 desc.fHeight = SkScalarRound(this->height());
1403 desc.fConfig = kRGBA_8888_GrPixelConfig;
1404 desc.fStencilBits = 8;
1405 GrGLint buffer;
1406 GR_GL_GetIntegerv(GR_GL_FRAMEBUFFER_BINDING, &buffer);
1407 desc.fPlatformRenderTarget = buffer;
1408
1409 SkSafeUnref(fGrRenderTarget);
1410 fGrRenderTarget = static_cast<GrRenderTarget*>(
1411 fGrContext->createPlatformSurface(desc));
1412 }
1413
reed@android.com8a1c16f2008-12-17 15:59:43 +00001414 SkView::F2BIter iter(this);
1415 SkView* view = iter.next();
1416 view->setSize(this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001417
reed@android.com8a1c16f2008-12-17 15:59:43 +00001418 // rebuild our clippath
1419 {
1420 const SkScalar W = this->width();
1421 const SkScalar H = this->height();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001422
reed@android.com8a1c16f2008-12-17 15:59:43 +00001423 fClipPath.reset();
1424#if 0
1425 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
1426 SkRect r;
1427 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
1428 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
1429 fClipPath.addRect(r);
1430 }
1431#else
1432 SkRect r;
1433 r.set(0, 0, W, H);
1434 fClipPath.addRect(r, SkPath::kCCW_Direction);
1435 r.set(W/4, H/4, W*3/4, H*3/4);
1436 fClipPath.addRect(r, SkPath::kCW_Direction);
1437#endif
1438 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001439
Scroggo2c8208f2011-06-15 16:49:08 +00001440 fZoomCenterX = SkScalarHalf(this->width());
1441 fZoomCenterY = SkScalarHalf(this->height());
1442
Scroggo3e7ff9f2011-06-16 15:31:26 +00001443#ifdef ANDROID
Scroggob4490c72011-06-17 13:53:05 +00001444 // FIXME: The first draw after a size change does not work on Android, so
1445 // we post an invalidate.
Scroggo62b65b02011-06-21 16:01:26 +00001446 this->postInvalDelay();
Scroggo716a0382011-06-16 14:00:15 +00001447#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001448 this->updateTitle(); // to refresh our config
1449}
1450
1451///////////////////////////////////////////////////////////////////////////////
1452
reed@google.coma6ff4dc2011-05-12 22:08:24 +00001453static const char is_sample_view_tag[] = "sample-is-sample-view";
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001454static const char repeat_count_tag[] = "sample-set-repeat-count";
reed@google.com0faac1e2011-05-11 05:58:58 +00001455static const char set_use_pipe_tag[] = "sample-set-use-pipe";
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001456
reed@google.coma6ff4dc2011-05-12 22:08:24 +00001457bool SampleView::IsSampleView(SkView* view) {
1458 SkEvent evt(is_sample_view_tag);
1459 return view->doQuery(&evt);
1460}
1461
reed@google.comf2183392011-04-22 14:10:48 +00001462bool SampleView::SetRepeatDraw(SkView* view, int count) {
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001463 SkEvent evt(repeat_count_tag);
1464 evt.setFast32(count);
reed@google.comf2183392011-04-22 14:10:48 +00001465 return view->doEvent(evt);
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001466}
1467
reed@google.com0faac1e2011-05-11 05:58:58 +00001468bool SampleView::SetUsePipe(SkView* view, bool pred) {
1469 SkEvent evt(set_use_pipe_tag);
1470 evt.setFast32(pred);
1471 return view->doEvent(evt);
1472}
1473
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001474bool SampleView::onEvent(const SkEvent& evt) {
1475 if (evt.isType(repeat_count_tag)) {
1476 fRepeatCount = evt.getFast32();
1477 return true;
1478 }
reed@google.com0faac1e2011-05-11 05:58:58 +00001479 if (evt.isType(set_use_pipe_tag)) {
1480 fUsePipe = !!evt.getFast32();
1481 return true;
1482 }
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001483 return this->INHERITED::onEvent(evt);
1484}
1485
1486bool SampleView::onQuery(SkEvent* evt) {
reed@google.coma6ff4dc2011-05-12 22:08:24 +00001487 if (evt->isType(is_sample_view_tag)) {
1488 return true;
1489 }
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001490 return this->INHERITED::onQuery(evt);
1491}
1492
reed@google.com68f456d2011-05-02 18:55:39 +00001493#ifdef TEST_GPIPE
1494 #include "SkGPipe.h"
reed@google.com64e3eb22011-05-04 14:32:04 +00001495
1496class SimplePC : public SkGPipeController {
1497public:
1498 SimplePC(SkCanvas* target);
1499 ~SimplePC();
1500
1501 virtual void* requestBlock(size_t minRequest, size_t* actual);
1502 virtual void notifyWritten(size_t bytes);
1503
1504private:
reed@google.com961ddb02011-05-05 14:03:48 +00001505 SkGPipeReader fReader;
1506 void* fBlock;
1507 size_t fBlockSize;
1508 size_t fBytesWritten;
1509 int fAtomsWritten;
reed@google.com64e3eb22011-05-04 14:32:04 +00001510 SkGPipeReader::Status fStatus;
1511
1512 size_t fTotalWritten;
1513};
1514
1515SimplePC::SimplePC(SkCanvas* target) : fReader(target) {
1516 fBlock = NULL;
1517 fBlockSize = fBytesWritten = 0;
1518 fStatus = SkGPipeReader::kDone_Status;
1519 fTotalWritten = 0;
reed@google.com961ddb02011-05-05 14:03:48 +00001520 fAtomsWritten = 0;
reed@google.com64e3eb22011-05-04 14:32:04 +00001521}
1522
1523SimplePC::~SimplePC() {
1524// SkASSERT(SkGPipeReader::kDone_Status == fStatus);
1525 sk_free(fBlock);
1526
reed@google.com0faac1e2011-05-11 05:58:58 +00001527 if (fTotalWritten) {
1528 SkDebugf("--- %d bytes %d atoms, status %d\n", fTotalWritten,
1529 fAtomsWritten, fStatus);
1530 }
reed@google.com64e3eb22011-05-04 14:32:04 +00001531}
1532
1533void* SimplePC::requestBlock(size_t minRequest, size_t* actual) {
1534 sk_free(fBlock);
1535
1536 fBlockSize = minRequest * 4;
1537 fBlock = sk_malloc_throw(fBlockSize);
1538 fBytesWritten = 0;
1539 *actual = fBlockSize;
1540 return fBlock;
1541}
1542
1543void SimplePC::notifyWritten(size_t bytes) {
1544 SkASSERT(fBytesWritten + bytes <= fBlockSize);
yangsu@google.com1f394212011-06-01 18:03:34 +00001545
1546#ifdef PIPE_FILE
1547 //File is open in append mode
1548 FILE* f = fopen(FILE_PATH, "ab");
1549 SkASSERT(f != NULL);
1550 fwrite((const char*)fBlock + fBytesWritten, 1, bytes, f);
1551 fclose(f);
1552#endif
1553
reed@google.com64e3eb22011-05-04 14:32:04 +00001554 fStatus = fReader.playback((const char*)fBlock + fBytesWritten, bytes);
1555 SkASSERT(SkGPipeReader::kError_Status != fStatus);
1556 fBytesWritten += bytes;
1557 fTotalWritten += bytes;
reed@google.com961ddb02011-05-05 14:03:48 +00001558
1559 fAtomsWritten += 1;
reed@google.com64e3eb22011-05-04 14:32:04 +00001560}
1561
reed@google.com68f456d2011-05-02 18:55:39 +00001562#endif
reed@google.com2f3dc9d2011-05-02 17:33:45 +00001563
reed@google.com64e3eb22011-05-04 14:32:04 +00001564
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001565void SampleView::onDraw(SkCanvas* canvas) {
reed@google.com2f3dc9d2011-05-02 17:33:45 +00001566#ifdef TEST_GPIPE
reed@google.com64e3eb22011-05-04 14:32:04 +00001567 SimplePC controller(canvas);
reed@google.com2f3dc9d2011-05-02 17:33:45 +00001568 SkGPipeWriter writer;
reed@google.com0faac1e2011-05-11 05:58:58 +00001569 if (fUsePipe) {
reed@google.comdde09562011-05-23 12:21:05 +00001570 uint32_t flags = SkGPipeWriter::kCrossProcess_Flag;
1571// flags = 0;
1572 canvas = writer.startRecording(&controller, flags);
reed@google.com0faac1e2011-05-11 05:58:58 +00001573 }
reed@google.com2f3dc9d2011-05-02 17:33:45 +00001574#endif
1575
reed@google.com81e3d7f2011-06-01 12:42:36 +00001576 this->onDrawBackground(canvas);
1577
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001578 for (int i = 0; i < fRepeatCount; i++) {
1579 SkAutoCanvasRestore acr(canvas, true);
1580 this->onDrawContent(canvas);
1581 }
1582}
1583
1584void SampleView::onDrawBackground(SkCanvas* canvas) {
reed@google.comf2183392011-04-22 14:10:48 +00001585 canvas->drawColor(fBGColor);
mike@reedtribe.org2eb59522011-04-22 01:59:09 +00001586}
1587
1588///////////////////////////////////////////////////////////////////////////////
1589
reed@android.comf2b98d62010-12-20 18:26:13 +00001590template <typename T> void SkTBSort(T array[], int count) {
1591 for (int i = 1; i < count - 1; i++) {
1592 bool didSwap = false;
1593 for (int j = count - 1; j > i; --j) {
1594 if (array[j] < array[j-1]) {
1595 T tmp(array[j-1]);
1596 array[j-1] = array[j];
1597 array[j] = tmp;
1598 didSwap = true;
1599 }
1600 }
1601 if (!didSwap) {
1602 break;
1603 }
1604 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001605
reed@android.comf2b98d62010-12-20 18:26:13 +00001606 for (int k = 0; k < count - 1; k++) {
1607 SkASSERT(!(array[k+1] < array[k]));
1608 }
1609}
1610
1611#include "SkRandom.h"
1612
1613static void rand_rect(SkIRect* rect, SkRandom& rand) {
1614 int bits = 8;
1615 int shift = 32 - bits;
1616 rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
1617 rand.nextU() >> shift, rand.nextU() >> shift);
1618 rect->sort();
1619}
1620
1621static void dumpRect(const SkIRect& r) {
1622 SkDebugf(" { %d, %d, %d, %d },\n",
1623 r.fLeft, r.fTop,
1624 r.fRight, r.fBottom);
1625}
1626
1627static void test_rects(const SkIRect rect[], int count) {
1628 SkRegion rgn0, rgn1;
1629
1630 for (int i = 0; i < count; i++) {
1631 rgn0.op(rect[i], SkRegion::kUnion_Op);
1632 // dumpRect(rect[i]);
1633 }
1634 rgn1.setRects(rect, count);
1635
1636 if (rgn0 != rgn1) {
1637 SkDebugf("\n");
1638 for (int i = 0; i < count; i++) {
1639 dumpRect(rect[i]);
1640 }
1641 SkDebugf("\n");
1642 }
1643}
1644
1645static void test() {
1646 size_t i;
1647
1648 const SkIRect r0[] = {
1649 { 0, 0, 1, 1 },
1650 { 2, 2, 3, 3 },
1651 };
1652 const SkIRect r1[] = {
1653 { 0, 0, 1, 3 },
1654 { 1, 1, 2, 2 },
1655 { 2, 0, 3, 3 },
1656 };
1657 const SkIRect r2[] = {
1658 { 0, 0, 1, 2 },
1659 { 2, 1, 3, 3 },
1660 { 4, 0, 5, 1 },
1661 { 6, 0, 7, 4 },
1662 };
1663
1664 static const struct {
1665 const SkIRect* fRects;
1666 int fCount;
1667 } gRecs[] = {
1668 { r0, SK_ARRAY_COUNT(r0) },
1669 { r1, SK_ARRAY_COUNT(r1) },
1670 { r2, SK_ARRAY_COUNT(r2) },
1671 };
1672
1673 for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
1674 test_rects(gRecs[i].fRects, gRecs[i].fCount);
1675 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001676
reed@android.comf2b98d62010-12-20 18:26:13 +00001677 SkRandom rand;
1678 for (i = 0; i < 10000; i++) {
1679 SkRegion rgn0, rgn1;
1680
1681 const int N = 8;
1682 SkIRect rect[N];
1683 for (int j = 0; j < N; j++) {
1684 rand_rect(&rect[j], rand);
1685 }
1686 test_rects(rect, N);
1687 }
1688}
1689
senorblanco@chromium.org78b82532011-06-28 19:44:03 +00001690SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) {
reed@android.comf2b98d62010-12-20 18:26:13 +00001691// test();
senorblanco@chromium.org78b82532011-06-28 19:44:03 +00001692 return new SampleWindow(hwnd, argc, argv);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001693}
1694
1695void get_preferred_size(int* x, int* y, int* width, int* height) {
1696 *x = 10;
1697 *y = 50;
1698 *width = 640;
1699 *height = 480;
1700}
1701
1702void application_init() {
1703// setenv("ANDROID_ROOT", "../../../data", 0);
reed@android.come191b162009-12-18 21:33:39 +00001704#ifdef SK_BUILD_FOR_MAC
reed@android.com8a1c16f2008-12-17 15:59:43 +00001705 setenv("ANDROID_ROOT", "/android/device/data", 0);
reed@android.come191b162009-12-18 21:33:39 +00001706#endif
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001707 SkGraphics::Init();
1708 SkEvent::Init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001709}
1710
1711void application_term() {
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +00001712 SkEvent::Term();
1713 SkGraphics::Term();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001714}