SampleApp.cpp revision 5987f58036574ccf23049b5fe71f29a441d0641d
1/* 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 */ 7#include "SampleApp.h" 8 9#include "SkData.h" 10#include "SkCanvas.h" 11#include "SkDevice.h" 12#include "SkGraphics.h" 13#include "SkImageEncoder.h" 14#include "SkPaint.h" 15#include "SkPicture.h" 16#include "SkStream.h" 17#include "SkTime.h" 18#include "SkWindow.h" 19 20#include "SampleCode.h" 21#include "SkTypeface.h" 22 23#if SK_SUPPORT_GPU 24#include "gl/GrGLInterface.h" 25#include "gl/GrGLUtil.h" 26#include "GrRenderTarget.h" 27#include "GrContext.h" 28#include "SkGpuDevice.h" 29#else 30class GrContext; 31#endif 32 33#include "SkOSFile.h" 34#include "SkPDFDevice.h" 35#include "SkPDFDocument.h" 36#include "SkStream.h" 37 38#include "SkGPipe.h" 39#include "SamplePipeControllers.h" 40#include "OverView.h" 41#include "TransitionView.h" 42 43SK_DEFINE_INST_COUNT(SampleWindow::DeviceManager) 44 45extern SampleView* CreateSamplePictFileView(const char filename[]); 46 47class PictFileFactory : public SkViewFactory { 48 SkString fFilename; 49public: 50 PictFileFactory(const SkString& filename) : fFilename(filename) {} 51 virtual SkView* operator() () const SK_OVERRIDE { 52 return CreateSamplePictFileView(fFilename.c_str()); 53 } 54}; 55 56#define PIPE_FILEx 57#ifdef PIPE_FILE 58#define FILE_PATH "/path/to/drawing.data" 59#endif 60 61#define PIPE_NETx 62#ifdef PIPE_NET 63#include "SkSockets.h" 64SkTCPServer gServer; 65#endif 66 67#define DEBUGGERx 68#ifdef DEBUGGER 69extern SkView* create_debugger(const char* data, size_t size); 70extern bool is_debugger(SkView* view); 71SkTDArray<char> gTempDataStore; 72#endif 73 74 75#define USE_ARROWS_FOR_ZOOM true 76 77#if SK_ANGLE 78//#define DEFAULT_TO_ANGLE 1 79#else 80//#define DEFAULT_TO_GPU 1 81#endif 82 83#define ANIMATING_EVENTTYPE "nextSample" 84#define ANIMATING_DELAY 750 85 86#ifdef SK_DEBUG 87 #define FPS_REPEAT_MULTIPLIER 1 88#else 89 #define FPS_REPEAT_MULTIPLIER 10 90#endif 91#define FPS_REPEAT_COUNT (10 * FPS_REPEAT_MULTIPLIER) 92 93static SampleWindow* gSampleWindow; 94 95static void postEventToSink(SkEvent* evt, SkEventSink* sink) { 96 evt->setTargetID(sink->getSinkID())->post(); 97} 98 99/////////////////////////////////////////////////////////////////////////////// 100 101static const char* skip_until(const char* str, const char* skip) { 102 if (!str) { 103 return NULL; 104 } 105 return strstr(str, skip); 106} 107 108static const char* skip_past(const char* str, const char* skip) { 109 const char* found = skip_until(str, skip); 110 if (!found) { 111 return NULL; 112 } 113 return found + strlen(skip); 114} 115 116static const char* gPrefFileName = "sampleapp_prefs.txt"; 117 118static bool readTitleFromPrefs(SkString* title) { 119 SkFILEStream stream(gPrefFileName); 120 if (!stream.isValid()) { 121 return false; 122 } 123 124 int len = stream.getLength(); 125 SkString data(len); 126 stream.read(data.writable_str(), len); 127 const char* s = data.c_str(); 128 129 s = skip_past(s, "curr-slide-title"); 130 s = skip_past(s, "="); 131 s = skip_past(s, "\""); 132 const char* stop = skip_until(s, "\""); 133 if (stop > s) { 134 title->set(s, stop - s); 135 return true; 136 } 137 return false; 138} 139 140static void writeTitleToPrefs(const char* title) { 141 SkFILEWStream stream(gPrefFileName); 142 SkString data; 143 data.printf("curr-slide-title = \"%s\"\n", title); 144 stream.write(data.c_str(), data.size()); 145} 146 147/////////////////////////////////////////////////////////////////////////////// 148 149class SampleWindow::DefaultDeviceManager : public SampleWindow::DeviceManager { 150public: 151 152 DefaultDeviceManager() { 153#if SK_SUPPORT_GPU 154 fCurContext = NULL; 155 fCurIntf = NULL; 156 fCurRenderTarget = NULL; 157 fMSAASampleCount = 0; 158#endif 159 fBackend = kNone_BackEndType; 160 } 161 162 virtual ~DefaultDeviceManager() { 163#if SK_SUPPORT_GPU 164 SkSafeUnref(fCurContext); 165 SkSafeUnref(fCurIntf); 166 SkSafeUnref(fCurRenderTarget); 167#endif 168 } 169 170 virtual void setUpBackend(SampleWindow* win, int msaaSampleCount) { 171 SkASSERT(kNone_BackEndType == fBackend); 172 173 fBackend = kNone_BackEndType; 174 175#if SK_SUPPORT_GPU 176 switch (win->getDeviceType()) { 177 case kRaster_DeviceType: 178 // fallthrough 179 case kPicture_DeviceType: 180 // fallthrough 181 case kGPU_DeviceType: 182 // fallthrough 183 case kNullGPU_DeviceType: 184 // all these guys use the native backend 185 fBackend = kNativeGL_BackEndType; 186 break; 187#if SK_ANGLE 188 case kANGLE_DeviceType: 189 // ANGLE is really the only odd man out 190 fBackend = kANGLE_BackEndType; 191 break; 192#endif // SK_ANGLE 193 default: 194 SkASSERT(false); 195 break; 196 } 197 198 bool result = win->attach(fBackend, msaaSampleCount); 199 if (!result) { 200 SkDebugf("Failed to initialize GL"); 201 return; 202 } 203 fMSAASampleCount = msaaSampleCount; 204 205 SkASSERT(NULL == fCurIntf); 206 switch (win->getDeviceType()) { 207 case kRaster_DeviceType: 208 // fallthrough 209 case kPicture_DeviceType: 210 // fallthrough 211 case kGPU_DeviceType: 212 // all these guys use the native interface 213 fCurIntf = GrGLCreateNativeInterface(); 214 break; 215#if SK_ANGLE 216 case kANGLE_DeviceType: 217 fCurIntf = GrGLCreateANGLEInterface(); 218 break; 219#endif // SK_ANGLE 220 case kNullGPU_DeviceType: 221 fCurIntf = GrGLCreateNullInterface(); 222 break; 223 default: 224 SkASSERT(false); 225 break; 226 } 227 228 SkASSERT(NULL == fCurContext); 229 fCurContext = GrContext::Create(kOpenGL_Shaders_GrEngine, 230 (GrPlatform3DContext) fCurIntf); 231 232 if (NULL == fCurContext || NULL == fCurIntf) { 233 // We need some context and interface to see results 234 SkSafeUnref(fCurContext); 235 SkSafeUnref(fCurIntf); 236 SkDebugf("Failed to setup 3D"); 237 238 win->detach(); 239 } 240#endif // SK_SUPPORT_GPU 241 // call windowSizeChanged to create the render target 242 this->windowSizeChanged(win); 243 } 244 245 virtual void tearDownBackend(SampleWindow *win) { 246#if SK_SUPPORT_GPU 247 SkSafeUnref(fCurContext); 248 fCurContext = NULL; 249 250 SkSafeUnref(fCurIntf); 251 fCurIntf = NULL; 252 253 SkSafeUnref(fCurRenderTarget); 254 fCurRenderTarget = NULL; 255#endif 256 win->detach(); 257 fBackend = kNone_BackEndType; 258 } 259 260 virtual SkCanvas* createCanvas(SampleWindow::DeviceType dType, 261 SampleWindow* win) { 262 switch (dType) { 263 case kRaster_DeviceType: 264 // fallthrough 265 case kPicture_DeviceType: 266 // fallthrough 267#if SK_ANGLE 268 case kANGLE_DeviceType: 269#endif 270 break; 271#if SK_SUPPORT_GPU 272 case kGPU_DeviceType: 273 case kNullGPU_DeviceType: 274 if (fCurContext) { 275 SkAutoTUnref<SkDevice> device(new SkGpuDevice(fCurContext, 276 fCurRenderTarget)); 277 return new SkCanvas(device); 278 } else { 279 return NULL; 280 } 281 break; 282#endif 283 default: 284 SkASSERT(false); 285 return NULL; 286 } 287 return NULL; 288 } 289 290 virtual void publishCanvas(SampleWindow::DeviceType dType, 291 SkCanvas* canvas, 292 SampleWindow* win) { 293#if SK_SUPPORT_GPU 294 if (fCurContext) { 295 // in case we have queued drawing calls 296 fCurContext->flush(); 297 298 if (kGPU_DeviceType != dType && kNullGPU_DeviceType != dType) { 299 // need to send the raster bits to the (gpu) window 300 fCurContext->setRenderTarget(fCurRenderTarget); 301 const SkBitmap& bm = win->getBitmap(); 302 fCurRenderTarget->writePixels(0, 0, bm.width(), bm.height(), 303 kSkia8888_PM_GrPixelConfig, 304 bm.getPixels(), 305 bm.rowBytes()); 306 } 307 } 308#endif 309 310 win->present(); 311 } 312 313 virtual void windowSizeChanged(SampleWindow* win) { 314#if SK_SUPPORT_GPU 315 if (fCurContext) { 316 win->attach(fBackend, fMSAASampleCount); 317 318 GrPlatformRenderTargetDesc desc; 319 desc.fWidth = SkScalarRound(win->width()); 320 desc.fHeight = SkScalarRound(win->height()); 321 desc.fConfig = kSkia8888_PM_GrPixelConfig; 322 GR_GL_GetIntegerv(fCurIntf, GR_GL_SAMPLES, &desc.fSampleCnt); 323 GR_GL_GetIntegerv(fCurIntf, GR_GL_STENCIL_BITS, &desc.fStencilBits); 324 GrGLint buffer; 325 GR_GL_GetIntegerv(fCurIntf, GR_GL_FRAMEBUFFER_BINDING, &buffer); 326 desc.fRenderTargetHandle = buffer; 327 328 SkSafeUnref(fCurRenderTarget); 329 fCurRenderTarget = fCurContext->createPlatformRenderTarget(desc); 330 } 331#endif 332 } 333 334 virtual GrContext* getGrContext() { 335#if SK_SUPPORT_GPU 336 return fCurContext; 337#else 338 return NULL; 339#endif 340 } 341 342 virtual GrRenderTarget* getGrRenderTarget() SK_OVERRIDE { 343#if SK_SUPPORT_GPU 344 return fCurRenderTarget; 345#else 346 return NULL; 347#endif 348 } 349 350private: 351 352#if SK_SUPPORT_GPU 353 GrContext* fCurContext; 354 const GrGLInterface* fCurIntf; 355 GrRenderTarget* fCurRenderTarget; 356 int fMSAASampleCount; 357#endif 358 359 SkOSWindow::SkBackEndTypes fBackend; 360 361 typedef SampleWindow::DeviceManager INHERITED; 362}; 363 364/////////////// 365static const char view_inval_msg[] = "view-inval-msg"; 366 367void SampleWindow::postInvalDelay() { 368 (new SkEvent(view_inval_msg, this->getSinkID()))->postDelay(1); 369} 370 371static bool isInvalEvent(const SkEvent& evt) { 372 return evt.isType(view_inval_msg); 373} 374////////////////// 375 376SkFuncViewFactory::SkFuncViewFactory(SkViewCreateFunc func) 377 : fCreateFunc(func) { 378} 379 380SkView* SkFuncViewFactory::operator() () const { 381 return (*fCreateFunc)(); 382} 383 384#include "GMSampleView.h" 385 386SkGMSampleViewFactory::SkGMSampleViewFactory(GMFactoryFunc func) 387 : fFunc(func) { 388} 389 390SkView* SkGMSampleViewFactory::operator() () const { 391 return new GMSampleView(fFunc(NULL)); 392} 393 394SkViewRegister* SkViewRegister::gHead; 395SkViewRegister::SkViewRegister(SkViewFactory* fact) : fFact(fact) { 396 fFact->ref(); 397 fChain = gHead; 398 gHead = this; 399} 400 401SkViewRegister::SkViewRegister(SkViewCreateFunc func) { 402 fFact = new SkFuncViewFactory(func); 403 fChain = gHead; 404 gHead = this; 405} 406 407SkViewRegister::SkViewRegister(GMFactoryFunc func) { 408 fFact = new SkGMSampleViewFactory(func); 409 fChain = gHead; 410 gHead = this; 411} 412 413class AutoUnrefArray { 414public: 415 AutoUnrefArray() {} 416 ~AutoUnrefArray() { 417 int count = fObjs.count(); 418 for (int i = 0; i < count; ++i) { 419 fObjs[i]->unref(); 420 } 421 } 422 SkRefCnt*& push_back() { return *fObjs.append(); } 423 424private: 425 SkTDArray<SkRefCnt*> fObjs; 426}; 427 428// registers GMs as Samples 429// This can't be performed during static initialization because it could be 430// run before GMRegistry has been fully built. 431static void SkGMRegistyToSampleRegistry() { 432 static bool gOnce; 433 static AutoUnrefArray fRegisters; 434 435 if (!gOnce) { 436 const skiagm::GMRegistry* gmreg = skiagm::GMRegistry::Head(); 437 while (gmreg) { 438 fRegisters.push_back() = new SkViewRegister(gmreg->factory()); 439 gmreg = gmreg->next(); 440 } 441 gOnce = true; 442 } 443} 444 445#if 0 446#include <CoreFoundation/CoreFoundation.h> 447#include <CoreFoundation/CFURLAccess.h> 448 449static void testpdf() { 450 CFStringRef path = CFStringCreateWithCString(NULL, "/test.pdf", 451 kCFStringEncodingUTF8); 452 CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path, 453 kCFURLPOSIXPathStyle, 454 false); 455 CFRelease(path); 456 CGRect box = CGRectMake(0, 0, 8*72, 10*72); 457 CGContextRef cg = CGPDFContextCreateWithURL(url, &box, NULL); 458 CFRelease(url); 459 460 CGContextBeginPage(cg, &box); 461 CGRect r = CGRectMake(10, 10, 40 + 0.5, 50 + 0.5); 462 CGContextFillEllipseInRect(cg, r); 463 CGContextEndPage(cg); 464 CGContextRelease(cg); 465 466 if (false) { 467 SkBitmap bm; 468 bm.setConfig(SkBitmap::kA8_Config, 64, 64); 469 bm.allocPixels(); 470 bm.eraseColor(0); 471 472 SkCanvas canvas(bm); 473 474 } 475} 476#endif 477 478////////////////////////////////////////////////////////////////////////////// 479 480enum FlipAxisEnum { 481 kFlipAxis_X = (1 << 0), 482 kFlipAxis_Y = (1 << 1) 483}; 484 485#include "SkDrawFilter.h" 486 487class FlagsDrawFilter : public SkDrawFilter { 488public: 489 FlagsDrawFilter(SkOSMenu::TriState lcd, SkOSMenu::TriState aa, SkOSMenu::TriState filter, 490 SkOSMenu::TriState hinting) : 491 fLCDState(lcd), fAAState(aa), fFilterState(filter), fHintingState(hinting) {} 492 493 virtual void filter(SkPaint* paint, Type t) { 494 if (kText_Type == t && SkOSMenu::kMixedState != fLCDState) { 495 paint->setLCDRenderText(SkOSMenu::kOnState == fLCDState); 496 } 497 if (SkOSMenu::kMixedState != fAAState) { 498 paint->setAntiAlias(SkOSMenu::kOnState == fAAState); 499 } 500 if (SkOSMenu::kMixedState != fFilterState) { 501 paint->setFilterBitmap(SkOSMenu::kOnState == fFilterState); 502 } 503 if (SkOSMenu::kMixedState != fHintingState) { 504 paint->setHinting(SkOSMenu::kOnState == fHintingState ? 505 SkPaint::kNormal_Hinting : 506 SkPaint::kSlight_Hinting); 507 } 508 } 509 510private: 511 SkOSMenu::TriState fLCDState; 512 SkOSMenu::TriState fAAState; 513 SkOSMenu::TriState fFilterState; 514 SkOSMenu::TriState fHintingState; 515}; 516 517////////////////////////////////////////////////////////////////////////////// 518 519#define MAX_ZOOM_LEVEL 8 520#define MIN_ZOOM_LEVEL -8 521 522static const char gCharEvtName[] = "SampleCode_Char_Event"; 523static const char gKeyEvtName[] = "SampleCode_Key_Event"; 524static const char gTitleEvtName[] = "SampleCode_Title_Event"; 525static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event"; 526static const char gFastTextEvtName[] = "SampleCode_FastText_Event"; 527static const char gUpdateWindowTitleEvtName[] = "SampleCode_UpdateWindowTitle"; 528 529bool SampleCode::CharQ(const SkEvent& evt, SkUnichar* outUni) { 530 if (evt.isType(gCharEvtName, sizeof(gCharEvtName) - 1)) { 531 if (outUni) { 532 *outUni = evt.getFast32(); 533 } 534 return true; 535 } 536 return false; 537} 538 539bool SampleCode::KeyQ(const SkEvent& evt, SkKey* outKey) { 540 if (evt.isType(gKeyEvtName, sizeof(gKeyEvtName) - 1)) { 541 if (outKey) { 542 *outKey = (SkKey)evt.getFast32(); 543 } 544 return true; 545 } 546 return false; 547} 548 549bool SampleCode::TitleQ(const SkEvent& evt) { 550 return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1); 551} 552 553void SampleCode::TitleR(SkEvent* evt, const char title[]) { 554 SkASSERT(evt && TitleQ(*evt)); 555 evt->setString(gTitleEvtName, title); 556} 557 558bool SampleCode::RequestTitle(SkView* view, SkString* title) { 559 SkEvent evt(gTitleEvtName); 560 if (view->doQuery(&evt)) { 561 title->set(evt.findString(gTitleEvtName)); 562 return true; 563 } 564 return false; 565} 566 567bool SampleCode::PrefSizeQ(const SkEvent& evt) { 568 return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1); 569} 570 571void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) { 572 SkASSERT(evt && PrefSizeQ(*evt)); 573 SkScalar size[2]; 574 size[0] = width; 575 size[1] = height; 576 evt->setScalars(gPrefSizeEvtName, 2, size); 577} 578 579bool SampleCode::FastTextQ(const SkEvent& evt) { 580 return evt.isType(gFastTextEvtName, sizeof(gFastTextEvtName) - 1); 581} 582 583/////////////////////////////////////////////////////////////////////////////// 584 585static SkMSec gAnimTime; 586static SkMSec gAnimTimePrev; 587 588SkMSec SampleCode::GetAnimTime() { return gAnimTime; } 589SkMSec SampleCode::GetAnimTimeDelta() { return gAnimTime - gAnimTimePrev; } 590SkScalar SampleCode::GetAnimSecondsDelta() { 591 return SkDoubleToScalar(GetAnimTimeDelta() / 1000.0); 592} 593 594SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) { 595 // since gAnimTime can be up to 32 bits, we can't convert it to a float 596 // or we'll lose the low bits. Hence we use doubles for the intermediate 597 // calculations 598 double seconds = (double)gAnimTime / 1000.0; 599 double value = SkScalarToDouble(speed) * seconds; 600 if (period) { 601 value = ::fmod(value, SkScalarToDouble(period)); 602 } 603 return SkDoubleToScalar(value); 604} 605 606SkScalar SampleCode::GetAnimSinScalar(SkScalar amplitude, 607 SkScalar periodInSec, 608 SkScalar phaseInSec) { 609 if (!periodInSec) { 610 return 0; 611 } 612 double t = (double)gAnimTime / 1000.0 + phaseInSec; 613 t *= SkScalarToFloat(2 * SK_ScalarPI) / periodInSec; 614 amplitude = SK_ScalarHalf * amplitude; 615 return SkScalarMul(amplitude, SkDoubleToScalar(sin(t))) + amplitude; 616} 617 618GrContext* SampleCode::GetGr() { 619 return gSampleWindow ? gSampleWindow->getGrContext() : NULL; 620} 621 622// some GMs rely on having a skiagm::GetGr function defined 623namespace skiagm { 624 // FIXME: this should be moved into a header 625 GrContext* GetGr(); 626 GrContext* GetGr() { return SampleCode::GetGr(); } 627} 628 629////////////////////////////////////////////////////////////////////////////// 630 631static SkView* curr_view(SkWindow* wind) { 632 SkView::F2BIter iter(wind); 633 return iter.next(); 634} 635 636static bool curr_title(SkWindow* wind, SkString* title) { 637 SkView* view = curr_view(wind); 638 if (view) { 639 SkEvent evt(gTitleEvtName); 640 if (view->doQuery(&evt)) { 641 title->set(evt.findString(gTitleEvtName)); 642 return true; 643 } 644 } 645 return false; 646} 647 648void SampleWindow::setZoomCenter(float x, float y) 649{ 650 fZoomCenterX = SkFloatToScalar(x); 651 fZoomCenterY = SkFloatToScalar(y); 652} 653 654bool SampleWindow::zoomIn() 655{ 656 // Arbitrarily decided 657 if (fFatBitsScale == 25) return false; 658 fFatBitsScale++; 659 this->inval(NULL); 660 return true; 661} 662 663bool SampleWindow::zoomOut() 664{ 665 if (fFatBitsScale == 1) return false; 666 fFatBitsScale--; 667 this->inval(NULL); 668 return true; 669} 670 671void SampleWindow::updatePointer(int x, int y) 672{ 673 fMouseX = x; 674 fMouseY = y; 675 if (fShowZoomer) { 676 this->inval(NULL); 677 } 678} 679 680static inline SampleWindow::DeviceType cycle_devicetype(SampleWindow::DeviceType ct) { 681 static const SampleWindow::DeviceType gCT[] = { 682 SampleWindow::kPicture_DeviceType, 683#if SK_SUPPORT_GPU 684 SampleWindow::kGPU_DeviceType, 685#if SK_ANGLE 686 SampleWindow::kANGLE_DeviceType, 687#endif // SK_ANGLE 688 SampleWindow::kRaster_DeviceType, // skip the null gpu device in normal cycling 689#endif // SK_SUPPORT_GPU 690 SampleWindow::kRaster_DeviceType 691 }; 692 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gCT) == SampleWindow::kDeviceTypeCnt, array_size_mismatch); 693 return gCT[ct]; 694} 695 696static void usage(const char * argv0) { 697 SkDebugf("%s [--slide sampleName] [-i resourcePath] [--msaa sampleCount] [--pictureDir dirPath] [--picture path]\n", argv0); 698 SkDebugf(" sampleName: sample at which to start.\n"); 699 SkDebugf(" resourcePath: directory that stores image resources.\n"); 700 SkDebugf(" msaa: request multisampling with the given sample count.\n"); 701 SkDebugf(" dirPath: path to directory skia pictures are read from\n"); 702 SkDebugf(" path: path to skia picture\n"); 703} 704 705SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* devManager) 706 : INHERITED(hwnd) 707 , fDevManager(NULL) { 708 709 this->registerPictFileSamples(argv, argc); 710 this->registerPictFileSample(argv, argc); 711 SkGMRegistyToSampleRegistry(); 712 { 713 const SkViewRegister* reg = SkViewRegister::Head(); 714 while (reg) { 715 *fSamples.append() = reg->factory(); 716 reg = reg->next(); 717 } 718 } 719 720 const char* resourcePath = NULL; 721 fCurrIndex = -1; 722 fMSAASampleCount = 0; 723 724 const char* const commandName = argv[0]; 725 char* const* stop = argv + argc; 726 for (++argv; argv < stop; ++argv) { 727 if (strcmp(*argv, "-i") == 0) { 728 argv++; 729 if (argv < stop && **argv) { 730 resourcePath = *argv; 731 } 732 } else if (strcmp(*argv, "--slide") == 0) { 733 argv++; 734 if (argv < stop && **argv) { 735 fCurrIndex = findByTitle(*argv); 736 if (fCurrIndex < 0) { 737 fprintf(stderr, "Unknown sample \"%s\"\n", *argv); 738 listTitles(); 739 } 740 } 741 } else if (strcmp(*argv, "--msaa") == 0) { 742 ++argv; 743 if (argv < stop && **argv) { 744 fMSAASampleCount = atoi(*argv); 745 } 746 } else if (strcmp(*argv, "--list") == 0) { 747 listTitles(); 748 } 749 else { 750 usage(commandName); 751 } 752 } 753 754 if (fCurrIndex < 0) { 755 SkString title; 756 if (readTitleFromPrefs(&title)) { 757 fCurrIndex = findByTitle(title.c_str()); 758 } 759 } 760 761 if (fCurrIndex < 0) { 762 fCurrIndex = 0; 763 } 764 765 gSampleWindow = this; 766 767#ifdef PIPE_FILE 768 //Clear existing file or create file if it doesn't exist 769 FILE* f = fopen(FILE_PATH, "wb"); 770 fclose(f); 771#endif 772 773 fPicture = NULL; 774 775 fDeviceType = kRaster_DeviceType; 776 777#if DEFAULT_TO_GPU 778 fDeviceType = kGPU_DeviceType; 779#endif 780#if SK_ANGLE && DEFAULT_TO_ANGLE 781 fDeviceType = kANGLE_DeviceType; 782#endif 783 784 fUseClip = false; 785 fNClip = false; 786 fAnimating = false; 787 fRotate = false; 788 fPerspAnim = false; 789 fPerspAnimTime = 0; 790 fScale = false; 791 fRequestGrabImage = false; 792 fPipeState = SkOSMenu::kOffState; 793 fTilingState = SkOSMenu::kOffState; 794 fTileCount.set(1, 1); 795 fMeasureFPS = false; 796 fLCDState = SkOSMenu::kMixedState; 797 fAAState = SkOSMenu::kMixedState; 798 fFilterState = SkOSMenu::kMixedState; 799 fHintingState = SkOSMenu::kMixedState; 800 fFlipAxis = 0; 801 fScrollTestX = fScrollTestY = 0; 802 803 fMouseX = fMouseY = 0; 804 fFatBitsScale = 8; 805 fTypeface = SkTypeface::CreateFromTypeface(NULL, SkTypeface::kBold); 806 fShowZoomer = false; 807 808 fZoomLevel = 0; 809 fZoomScale = SK_Scalar1; 810 811 fMagnify = false; 812 fDebugger = false; 813 814 fSaveToPdf = false; 815 fPdfCanvas = NULL; 816 817 fTransitionNext = 6; 818 fTransitionPrev = 2; 819 820 int sinkID = this->getSinkID(); 821 fAppMenu = new SkOSMenu; 822 fAppMenu->setTitle("Global Settings"); 823 int itemID; 824 825 itemID =fAppMenu->appendList("Device Type", "Device Type", sinkID, 0, 826 "Raster", "Picture", "OpenGL", 827#if SK_ANGLE 828 "ANGLE", 829#endif 830 NULL); 831 fAppMenu->assignKeyEquivalentToItem(itemID, 'd'); 832 itemID = fAppMenu->appendTriState("AA", "AA", sinkID, fAAState); 833 fAppMenu->assignKeyEquivalentToItem(itemID, 'b'); 834 itemID = fAppMenu->appendTriState("LCD", "LCD", sinkID, fLCDState); 835 fAppMenu->assignKeyEquivalentToItem(itemID, 'l'); 836 itemID = fAppMenu->appendTriState("Filter", "Filter", sinkID, fFilterState); 837 fAppMenu->assignKeyEquivalentToItem(itemID, 'n'); 838 itemID = fAppMenu->appendTriState("Hinting", "Hinting", sinkID, fHintingState); 839 fAppMenu->assignKeyEquivalentToItem(itemID, 'h'); 840 841 fUsePipeMenuItemID = fAppMenu->appendTriState("Pipe", "Pipe" , sinkID, 842 fPipeState); 843 fAppMenu->assignKeyEquivalentToItem(fUsePipeMenuItemID, 'P'); 844 845 itemID = fAppMenu->appendTriState("Tiling", "Tiling", sinkID, fTilingState); 846 fAppMenu->assignKeyEquivalentToItem(itemID, 't'); 847 848#ifdef DEBUGGER 849 itemID = fAppMenu->appendSwitch("Debugger", "Debugger", sinkID, fDebugger); 850 fAppMenu->assignKeyEquivalentToItem(itemID, 'q'); 851#endif 852 itemID = fAppMenu->appendSwitch("Slide Show", "Slide Show" , sinkID, false); 853 fAppMenu->assignKeyEquivalentToItem(itemID, 'a'); 854 itemID = fAppMenu->appendSwitch("Clip", "Clip" , sinkID, fUseClip); 855 fAppMenu->assignKeyEquivalentToItem(itemID, 'c'); 856 itemID = fAppMenu->appendSwitch("Flip X", "Flip X" , sinkID, false); 857 fAppMenu->assignKeyEquivalentToItem(itemID, 'x'); 858 itemID = fAppMenu->appendSwitch("Flip Y", "Flip Y" , sinkID, false); 859 fAppMenu->assignKeyEquivalentToItem(itemID, 'y'); 860 itemID = fAppMenu->appendSwitch("Zoomer", "Zoomer" , sinkID, fShowZoomer); 861 fAppMenu->assignKeyEquivalentToItem(itemID, 'z'); 862 itemID = fAppMenu->appendSwitch("Magnify", "Magnify" , sinkID, fMagnify); 863 fAppMenu->assignKeyEquivalentToItem(itemID, 'm'); 864 itemID =fAppMenu->appendList("Transition-Next", "Transition-Next", sinkID, 865 fTransitionNext, "Up", "Up and Right", "Right", 866 "Down and Right", "Down", "Down and Left", 867 "Left", "Up and Left", NULL); 868 fAppMenu->assignKeyEquivalentToItem(itemID, 'j'); 869 itemID =fAppMenu->appendList("Transition-Prev", "Transition-Prev", sinkID, 870 fTransitionPrev, "Up", "Up and Right", "Right", 871 "Down and Right", "Down", "Down and Left", 872 "Left", "Up and Left", NULL); 873 fAppMenu->assignKeyEquivalentToItem(itemID, 'k'); 874 itemID = fAppMenu->appendAction("Save to PDF", sinkID); 875 fAppMenu->assignKeyEquivalentToItem(itemID, 'e'); 876 877 this->addMenu(fAppMenu); 878 fSlideMenu = new SkOSMenu; 879 this->addMenu(fSlideMenu); 880 881// this->setConfig(SkBitmap::kRGB_565_Config); 882 this->setConfig(SkBitmap::kARGB_8888_Config); 883 this->setVisibleP(true); 884 this->setClipToBounds(false); 885 886 skiagm::GM::SetResourcePath(resourcePath); 887 888 this->loadView((*fSamples[fCurrIndex])()); 889 890 fPDFData = NULL; 891 892 if (NULL == devManager) { 893 fDevManager = new DefaultDeviceManager(); 894 } else { 895 devManager->ref(); 896 fDevManager = devManager; 897 } 898 fDevManager->setUpBackend(this, fMSAASampleCount); 899 900 // If another constructor set our dimensions, ensure that our 901 // onSizeChange gets called. 902 if (this->height() && this->width()) { 903 this->onSizeChange(); 904 } 905 906 // can't call this synchronously, since it may require a subclass to 907 // to implement, or the caller may need us to have returned from the 908 // constructor first. Hence we post an event to ourselves. 909// this->updateTitle(); 910 postEventToSink(new SkEvent(gUpdateWindowTitleEvtName), this); 911} 912 913SampleWindow::~SampleWindow() { 914 delete fPicture; 915 delete fPdfCanvas; 916 fTypeface->unref(); 917 918 SkSafeUnref(fDevManager); 919} 920 921static void make_filepath(SkString* path, const char* dir, const SkString& name) { 922 size_t len = strlen(dir); 923 path->set(dir); 924 if (len > 0 && dir[len - 1] != '/') { 925 path->append("/"); 926 } 927 path->append(name); 928} 929 930void SampleWindow::registerPictFileSample(char** argv, int argc) { 931 const char* pict = NULL; 932 933 for (int i = 0; i < argc; ++i) { 934 if (!strcmp(argv[i], "--picture")) { 935 i += 1; 936 if (i < argc) { 937 pict = argv[i]; 938 break; 939 } 940 } 941 } 942 if (pict) { 943 SkString path(pict); 944 *fSamples.append() = new PictFileFactory(path); 945 } 946} 947 948void SampleWindow::registerPictFileSamples(char** argv, int argc) { 949 const char* pictDir = NULL; 950 951 for (int i = 0; i < argc; ++i) { 952 if (!strcmp(argv[i], "--pictureDir")) { 953 i += 1; 954 if (i < argc) { 955 pictDir = argv[i]; 956 break; 957 } 958 } 959 } 960 if (pictDir) { 961 SkOSFile::Iter iter(pictDir, "skp"); 962 SkString filename; 963 while (iter.next(&filename)) { 964 SkString path; 965 make_filepath(&path, pictDir, filename); 966 *fSamples.append() = new PictFileFactory(path); 967 } 968 } 969} 970 971int SampleWindow::findByTitle(const char title[]) { 972 int i, count = fSamples.count(); 973 for (i = 0; i < count; i++) { 974 if (getSampleTitle(i).equals(title)) { 975 return i; 976 } 977 } 978 return -1; 979} 980 981void SampleWindow::listTitles() { 982 int count = fSamples.count(); 983 SkDebugf("All Slides:\n"); 984 for (int i = 0; i < count; i++) { 985 SkDebugf(" %s\n", getSampleTitle(i).c_str()); 986 } 987} 988 989static SkBitmap capture_bitmap(SkCanvas* canvas) { 990 SkBitmap bm; 991 const SkBitmap& src = canvas->getDevice()->accessBitmap(false); 992 src.copyTo(&bm, src.config()); 993 return bm; 994} 995 996static bool bitmap_diff(SkCanvas* canvas, const SkBitmap& orig, 997 SkBitmap* diff) { 998 const SkBitmap& src = canvas->getDevice()->accessBitmap(false); 999 1000 SkAutoLockPixels alp0(src); 1001 SkAutoLockPixels alp1(orig); 1002 for (int y = 0; y < src.height(); y++) { 1003 const void* srcP = src.getAddr(0, y); 1004 const void* origP = orig.getAddr(0, y); 1005 size_t bytes = src.width() * src.bytesPerPixel(); 1006 if (memcmp(srcP, origP, bytes)) { 1007 SkDebugf("---------- difference on line %d\n", y); 1008 return true; 1009 } 1010 } 1011 return false; 1012} 1013 1014static void drawText(SkCanvas* canvas, SkString string, SkScalar left, SkScalar top, SkPaint& paint) 1015{ 1016 SkColor desiredColor = paint.getColor(); 1017 paint.setColor(SK_ColorWHITE); 1018 const char* c_str = string.c_str(); 1019 size_t size = string.size(); 1020 SkRect bounds; 1021 paint.measureText(c_str, size, &bounds); 1022 bounds.offset(left, top); 1023 SkScalar inset = SkIntToScalar(-2); 1024 bounds.inset(inset, inset); 1025 canvas->drawRect(bounds, paint); 1026 if (desiredColor != SK_ColorBLACK) { 1027 paint.setColor(SK_ColorBLACK); 1028 canvas->drawText(c_str, size, left + SK_Scalar1, top + SK_Scalar1, paint); 1029 } 1030 paint.setColor(desiredColor); 1031 canvas->drawText(c_str, size, left, top, paint); 1032} 1033 1034#define XCLIP_N 8 1035#define YCLIP_N 8 1036 1037void SampleWindow::draw(SkCanvas* canvas) { 1038 // update the animation time 1039 if (!gAnimTimePrev && !gAnimTime) { 1040 // first time make delta be 0 1041 gAnimTime = SkTime::GetMSecs(); 1042 gAnimTimePrev = gAnimTime; 1043 } else { 1044 gAnimTimePrev = gAnimTime; 1045 gAnimTime = SkTime::GetMSecs(); 1046 } 1047 1048 const SkMatrix& localM = fGesture.localM(); 1049 if (localM.getType() & SkMatrix::kScale_Mask) { 1050 canvas->setExternalMatrix(&localM); 1051 } 1052 if (fGesture.isActive()) { 1053 this->updateMatrix(); 1054 } 1055 1056 if (fNClip) { 1057 this->INHERITED::draw(canvas); 1058 SkBitmap orig = capture_bitmap(canvas); 1059 1060 const SkScalar w = this->width(); 1061 const SkScalar h = this->height(); 1062 const SkScalar cw = w / XCLIP_N; 1063 const SkScalar ch = h / YCLIP_N; 1064 for (int y = 0; y < YCLIP_N; y++) { 1065 SkRect r; 1066 r.fTop = y * ch; 1067 r.fBottom = (y + 1) * ch; 1068 if (y == YCLIP_N - 1) { 1069 r.fBottom = h; 1070 } 1071 for (int x = 0; x < XCLIP_N; x++) { 1072 SkAutoCanvasRestore acr(canvas, true); 1073 r.fLeft = x * cw; 1074 r.fRight = (x + 1) * cw; 1075 if (x == XCLIP_N - 1) { 1076 r.fRight = w; 1077 } 1078 canvas->clipRect(r); 1079 this->INHERITED::draw(canvas); 1080 } 1081 } 1082 1083 SkBitmap diff; 1084 if (bitmap_diff(canvas, orig, &diff)) { 1085 } 1086 } else { 1087 const SkScalar cw = SkScalarDiv(this->width(), SkIntToScalar(fTileCount.width())); 1088 const SkScalar ch = SkScalarDiv(this->height(), SkIntToScalar(fTileCount.height())); 1089 1090 for (int y = 0; y < fTileCount.height(); ++y) { 1091 for (int x = 0; x < fTileCount.width(); ++x) { 1092 SkAutoCanvasRestore acr(canvas, true); 1093 canvas->clipRect(SkRect::MakeXYWH(x * cw, y * ch, cw, ch)); 1094 this->INHERITED::draw(canvas); 1095 } 1096 } 1097 1098 if (!fTileCount.equals(1, 1)) { 1099 SkPaint paint; 1100 paint.setColor(0x60FF00FF); 1101 paint.setStyle(SkPaint::kStroke_Style); 1102 for (int y = 0; y < fTileCount.height(); ++y) { 1103 for (int x = 0; x < fTileCount.width(); ++x) { 1104 canvas->drawRect(SkRect::MakeXYWH(x * cw, y * ch, cw, ch), paint); 1105 } 1106 } 1107 } 1108 } 1109 if (fShowZoomer && !fSaveToPdf) { 1110 showZoomer(canvas); 1111 } 1112 if (fMagnify && !fSaveToPdf) { 1113 magnify(canvas); 1114 } 1115 1116 // do this last 1117 fDevManager->publishCanvas(fDeviceType, canvas, this); 1118} 1119 1120static float clipW = 200; 1121static float clipH = 200; 1122void SampleWindow::magnify(SkCanvas* canvas) { 1123 SkRect r; 1124 int count = canvas->save(); 1125 1126 SkMatrix m = canvas->getTotalMatrix(); 1127 if (!m.invert(&m)) { 1128 return; 1129 } 1130 SkPoint offset, center; 1131 SkScalar mouseX = fMouseX * SK_Scalar1; 1132 SkScalar mouseY = fMouseY * SK_Scalar1; 1133 m.mapXY(mouseX - clipW/2, mouseY - clipH/2, &offset); 1134 m.mapXY(mouseX, mouseY, ¢er); 1135 1136 r.set(0, 0, clipW * m.getScaleX(), clipH * m.getScaleX()); 1137 r.offset(offset.fX, offset.fY); 1138 1139 SkPaint paint; 1140 paint.setColor(0xFF66AAEE); 1141 paint.setStyle(SkPaint::kStroke_Style); 1142 paint.setStrokeWidth(10.f * m.getScaleX()); 1143 //lense offset 1144 //canvas->translate(0, -250); 1145 canvas->drawRect(r, paint); 1146 canvas->clipRect(r); 1147 1148 m = canvas->getTotalMatrix(); 1149 m.setTranslate(-center.fX, -center.fY); 1150 m.postScale(0.5f * fFatBitsScale, 0.5f * fFatBitsScale); 1151 m.postTranslate(center.fX, center.fY); 1152 canvas->concat(m); 1153 1154 this->INHERITED::draw(canvas); 1155 1156 canvas->restoreToCount(count); 1157} 1158 1159void SampleWindow::showZoomer(SkCanvas* canvas) { 1160 int count = canvas->save(); 1161 canvas->resetMatrix(); 1162 // Ensure the mouse position is on screen. 1163 int width = SkScalarRound(this->width()); 1164 int height = SkScalarRound(this->height()); 1165 if (fMouseX >= width) fMouseX = width - 1; 1166 else if (fMouseX < 0) fMouseX = 0; 1167 if (fMouseY >= height) fMouseY = height - 1; 1168 else if (fMouseY < 0) fMouseY = 0; 1169 1170 SkBitmap bitmap = capture_bitmap(canvas); 1171 bitmap.lockPixels(); 1172 1173 // Find the size of the zoomed in view, forced to be odd, so the examined pixel is in the middle. 1174 int zoomedWidth = (width >> 1) | 1; 1175 int zoomedHeight = (height >> 1) | 1; 1176 SkIRect src; 1177 src.set(0, 0, zoomedWidth / fFatBitsScale, zoomedHeight / fFatBitsScale); 1178 src.offset(fMouseX - (src.width()>>1), fMouseY - (src.height()>>1)); 1179 SkRect dest; 1180 dest.set(0, 0, SkIntToScalar(zoomedWidth), SkIntToScalar(zoomedHeight)); 1181 dest.offset(SkIntToScalar(width - zoomedWidth), SkIntToScalar(height - zoomedHeight)); 1182 SkPaint paint; 1183 // Clear the background behind our zoomed in view 1184 paint.setColor(SK_ColorWHITE); 1185 canvas->drawRect(dest, paint); 1186 canvas->drawBitmapRect(bitmap, &src, dest); 1187 paint.setColor(SK_ColorBLACK); 1188 paint.setStyle(SkPaint::kStroke_Style); 1189 // Draw a border around the pixel in the middle 1190 SkRect originalPixel; 1191 originalPixel.set(SkIntToScalar(fMouseX), SkIntToScalar(fMouseY), SkIntToScalar(fMouseX + 1), SkIntToScalar(fMouseY + 1)); 1192 SkMatrix matrix; 1193 SkRect scalarSrc; 1194 scalarSrc.set(src); 1195 SkColor color = bitmap.getColor(fMouseX, fMouseY); 1196 if (matrix.setRectToRect(scalarSrc, dest, SkMatrix::kFill_ScaleToFit)) { 1197 SkRect pixel; 1198 matrix.mapRect(&pixel, originalPixel); 1199 // TODO Perhaps measure the values and make the outline white if it's "dark" 1200 if (color == SK_ColorBLACK) { 1201 paint.setColor(SK_ColorWHITE); 1202 } 1203 canvas->drawRect(pixel, paint); 1204 } 1205 paint.setColor(SK_ColorBLACK); 1206 // Draw a border around the destination rectangle 1207 canvas->drawRect(dest, paint); 1208 paint.setStyle(SkPaint::kStrokeAndFill_Style); 1209 // Identify the pixel and its color on screen 1210 paint.setTypeface(fTypeface); 1211 paint.setAntiAlias(true); 1212 SkScalar lineHeight = paint.getFontMetrics(NULL); 1213 SkString string; 1214 string.appendf("(%i, %i)", fMouseX, fMouseY); 1215 SkScalar left = dest.fLeft + SkIntToScalar(3); 1216 SkScalar i = SK_Scalar1; 1217 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint); 1218 // Alpha 1219 i += SK_Scalar1; 1220 string.reset(); 1221 string.appendf("A: %X", SkColorGetA(color)); 1222 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint); 1223 // Red 1224 i += SK_Scalar1; 1225 string.reset(); 1226 string.appendf("R: %X", SkColorGetR(color)); 1227 paint.setColor(SK_ColorRED); 1228 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint); 1229 // Green 1230 i += SK_Scalar1; 1231 string.reset(); 1232 string.appendf("G: %X", SkColorGetG(color)); 1233 paint.setColor(SK_ColorGREEN); 1234 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint); 1235 // Blue 1236 i += SK_Scalar1; 1237 string.reset(); 1238 string.appendf("B: %X", SkColorGetB(color)); 1239 paint.setColor(SK_ColorBLUE); 1240 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint); 1241 canvas->restoreToCount(count); 1242} 1243 1244void SampleWindow::onDraw(SkCanvas* canvas) { 1245} 1246 1247#include "SkColorPriv.h" 1248 1249#if 0 // UNUSED 1250static void reverseRedAndBlue(const SkBitmap& bm) { 1251 SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config); 1252 uint8_t* p = (uint8_t*)bm.getPixels(); 1253 uint8_t* stop = p + bm.getSize(); 1254 while (p < stop) { 1255 // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply 1256 unsigned scale = SkAlpha255To256(p[3]); 1257 unsigned r = p[2]; 1258 unsigned b = p[0]; 1259 p[0] = SkAlphaMul(r, scale); 1260 p[1] = SkAlphaMul(p[1], scale); 1261 p[2] = SkAlphaMul(b, scale); 1262 p += 4; 1263 } 1264} 1265#endif 1266 1267void SampleWindow::saveToPdf() 1268{ 1269 fSaveToPdf = true; 1270 this->inval(NULL); 1271} 1272 1273SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) { 1274 if (fSaveToPdf) { 1275 const SkBitmap& bmp = canvas->getDevice()->accessBitmap(false); 1276 SkISize size = SkISize::Make(bmp.width(), bmp.height()); 1277 SkPDFDevice* pdfDevice = new SkPDFDevice(size, size, 1278 canvas->getTotalMatrix()); 1279 fPdfCanvas = new SkCanvas(pdfDevice); 1280 pdfDevice->unref(); 1281 canvas = fPdfCanvas; 1282 } else { 1283 switch (fDeviceType) { 1284 case kRaster_DeviceType: 1285 // fallthrough 1286#if SK_SUPPORT_GPU 1287 case kGPU_DeviceType: 1288 // fallthrough 1289#if SK_ANGLE 1290 case kANGLE_DeviceType: 1291#endif // SK_ANGLE 1292#endif // SK_SUPPORT_GPU 1293 canvas = this->INHERITED::beforeChildren(canvas); 1294 break; 1295 case kPicture_DeviceType: 1296 fPicture = new SkPicture; 1297 canvas = fPicture->beginRecording(9999, 9999); 1298 break; 1299#if SK_SUPPORT_GPU 1300 case kNullGPU_DeviceType: 1301 break; 1302#endif 1303 default: 1304 SkASSERT(false); 1305 break; 1306 } 1307 } 1308 1309 if (fUseClip) { 1310 canvas->drawColor(0xFFFF88FF); 1311 canvas->clipPath(fClipPath, SkRegion::kIntersect_Op, true); 1312 } 1313 1314 return canvas; 1315} 1316 1317static void paint_rgn(const SkBitmap& bm, const SkIRect& r, 1318 const SkRegion& rgn) { 1319 SkCanvas canvas(bm); 1320 SkRegion inval(rgn); 1321 1322 inval.translate(r.fLeft, r.fTop); 1323 canvas.clipRegion(inval); 1324 canvas.drawColor(0xFFFF8080); 1325} 1326#include "SkData.h" 1327void SampleWindow::afterChildren(SkCanvas* orig) { 1328 if (fSaveToPdf) { 1329 fSaveToPdf = false; 1330 if (fShowZoomer) { 1331 showZoomer(fPdfCanvas); 1332 } 1333 SkString name; 1334 name.printf("%s.pdf", this->getTitle()); 1335 SkPDFDocument doc; 1336 SkPDFDevice* device = static_cast<SkPDFDevice*>(fPdfCanvas->getDevice()); 1337 doc.appendPage(device); 1338#ifdef SK_BUILD_FOR_ANDROID 1339 name.prepend("/sdcard/"); 1340#endif 1341 1342#ifdef SK_BUILD_FOR_IOS 1343 SkDynamicMemoryWStream mstream; 1344 doc.emitPDF(&mstream); 1345 fPDFData = mstream.copyToData(); 1346#endif 1347 SkFILEWStream stream(name.c_str()); 1348 if (stream.isValid()) { 1349 doc.emitPDF(&stream); 1350 const char* desc = "File saved from Skia SampleApp"; 1351 this->onPDFSaved(this->getTitle(), desc, name.c_str()); 1352 } 1353 1354 delete fPdfCanvas; 1355 fPdfCanvas = NULL; 1356 1357 // We took over the draw calls in order to create the PDF, so we need 1358 // to redraw. 1359 this->inval(NULL); 1360 return; 1361 } 1362 1363 if (fRequestGrabImage) { 1364 fRequestGrabImage = false; 1365 1366 SkDevice* device = orig->getDevice(); 1367 SkBitmap bmp; 1368 if (device->accessBitmap(false).copyTo(&bmp, SkBitmap::kARGB_8888_Config)) { 1369 static int gSampleGrabCounter; 1370 SkString name; 1371 name.printf("sample_grab_%d.png", gSampleGrabCounter++); 1372 SkImageEncoder::EncodeFile(name.c_str(), bmp, 1373 SkImageEncoder::kPNG_Type, 100); 1374 } 1375 } 1376 1377 if (kPicture_DeviceType == fDeviceType) { 1378 if (true) { 1379 SkPicture* pict = new SkPicture(*fPicture); 1380 fPicture->unref(); 1381 this->installDrawFilter(orig); 1382 orig->drawPicture(*pict); 1383 pict->unref(); 1384 } else if (true) { 1385 SkDynamicMemoryWStream ostream; 1386 fPicture->serialize(&ostream); 1387 fPicture->unref(); 1388 1389 SkAutoDataUnref data(ostream.copyToData()); 1390 SkMemoryStream istream(data->data(), data->size()); 1391 SkPicture pict(&istream); 1392 orig->drawPicture(pict); 1393 } else { 1394 fPicture->draw(orig); 1395 fPicture->unref(); 1396 } 1397 fPicture = NULL; 1398 } 1399 1400 // Do this after presentGL and other finishing, rather than in afterChild 1401 if (fMeasureFPS && fMeasureFPS_Time) { 1402 fMeasureFPS_Time = SkTime::GetMSecs() - fMeasureFPS_Time; 1403 this->updateTitle(); 1404 this->postInvalDelay(); 1405 } 1406 1407 // if ((fScrollTestX | fScrollTestY) != 0) 1408 if (false) { 1409 const SkBitmap& bm = orig->getDevice()->accessBitmap(true); 1410 int dx = fScrollTestX * 7; 1411 int dy = fScrollTestY * 7; 1412 SkIRect r; 1413 SkRegion inval; 1414 1415 r.set(50, 50, 50+100, 50+100); 1416 bm.scrollRect(&r, dx, dy, &inval); 1417 paint_rgn(bm, r, inval); 1418 } 1419#ifdef DEBUGGER 1420 SkView* curr = curr_view(this); 1421 if (fDebugger && !is_debugger(curr) && !is_transition(curr) && !is_overview(curr)) { 1422 //Stop Pipe when fDebugger is active 1423 if (fPipeState != SkOSMenu::kOffState) { 1424 fPipeState = SkOSMenu::kOffState; 1425 (void)SampleView::SetUsePipe(curr, fPipeState); 1426 fAppMenu->getItemByID(fUsePipeMenuItemID)->setTriState(fPipeState); 1427 this->onUpdateMenu(fAppMenu); 1428 } 1429 1430 //Reset any transformations 1431 fGesture.stop(); 1432 fGesture.reset(); 1433 1434 this->loadView(create_debugger(gTempDataStore.begin(), 1435 gTempDataStore.count())); 1436 } 1437#endif 1438} 1439 1440void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) { 1441 if (fScale) { 1442 SkScalar scale = SK_Scalar1 * 7 / 10; 1443 SkScalar cx = this->width() / 2; 1444 SkScalar cy = this->height() / 2; 1445 canvas->translate(cx, cy); 1446 canvas->scale(scale, scale); 1447 canvas->translate(-cx, -cy); 1448 } 1449 if (fRotate) { 1450 SkScalar cx = this->width() / 2; 1451 SkScalar cy = this->height() / 2; 1452 canvas->translate(cx, cy); 1453 canvas->rotate(SkIntToScalar(30)); 1454 canvas->translate(-cx, -cy); 1455 } 1456 if (fPerspAnim) { 1457 fPerspAnimTime += SampleCode::GetAnimSecondsDelta(); 1458 1459 static const SkScalar gAnimPeriod = 10 * SK_Scalar1; 1460 static const SkScalar gAnimMag = SK_Scalar1 / 1000; 1461 SkScalar t = SkScalarMod(fPerspAnimTime, gAnimPeriod); 1462 if (SkScalarFloorToInt(SkScalarDiv(fPerspAnimTime, gAnimPeriod)) & 0x1) { 1463 t = gAnimPeriod - t; 1464 } 1465 t = 2 * t - gAnimPeriod; 1466 t = SkScalarMul(SkScalarDiv(t, gAnimPeriod), gAnimMag); 1467 SkMatrix m; 1468 m.reset(); 1469 m.setPerspY(t); 1470 canvas->concat(m); 1471 } 1472 1473 this->installDrawFilter(canvas); 1474 1475 if (fMeasureFPS) { 1476 fMeasureFPS_Time = 0; // 0 means the child is not aware of repeat-draw 1477 if (SampleView::SetRepeatDraw(child, FPS_REPEAT_COUNT)) { 1478 fMeasureFPS_Time = SkTime::GetMSecs(); 1479 } 1480 } else { 1481 (void)SampleView::SetRepeatDraw(child, 1); 1482 } 1483 if (fPerspAnim) { 1484 this->inval(NULL); 1485 } 1486} 1487 1488void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) { 1489 canvas->setDrawFilter(NULL); 1490} 1491 1492static SkBitmap::Config gConfigCycle[] = { 1493 SkBitmap::kNo_Config, // none -> none 1494 SkBitmap::kNo_Config, // a1 -> none 1495 SkBitmap::kNo_Config, // a8 -> none 1496 SkBitmap::kNo_Config, // index8 -> none 1497 SkBitmap::kARGB_4444_Config, // 565 -> 4444 1498 SkBitmap::kARGB_8888_Config, // 4444 -> 8888 1499 SkBitmap::kRGB_565_Config // 8888 -> 565 1500}; 1501 1502static SkBitmap::Config cycle_configs(SkBitmap::Config c) { 1503 return gConfigCycle[c]; 1504} 1505 1506void SampleWindow::changeZoomLevel(float delta) { 1507 fZoomLevel += SkFloatToScalar(delta); 1508 if (fZoomLevel > 0) { 1509 fZoomLevel = SkMinScalar(fZoomLevel, MAX_ZOOM_LEVEL); 1510 fZoomScale = fZoomLevel + SK_Scalar1; 1511 } else if (fZoomLevel < 0) { 1512 fZoomLevel = SkMaxScalar(fZoomLevel, MIN_ZOOM_LEVEL); 1513 fZoomScale = SK_Scalar1 / (SK_Scalar1 - fZoomLevel); 1514 } else { 1515 fZoomScale = SK_Scalar1; 1516 } 1517 this->updateMatrix(); 1518} 1519 1520void SampleWindow::updateMatrix(){ 1521 SkMatrix m; 1522 m.reset(); 1523 if (fZoomLevel) { 1524 SkPoint center; 1525 //m = this->getLocalMatrix();//.invert(&m); 1526 m.mapXY(fZoomCenterX, fZoomCenterY, ¢er); 1527 SkScalar cx = center.fX; 1528 SkScalar cy = center.fY; 1529 1530 m.setTranslate(-cx, -cy); 1531 m.postScale(fZoomScale, fZoomScale); 1532 m.postTranslate(cx, cy); 1533 } 1534 1535 if (fFlipAxis) { 1536 m.preTranslate(fZoomCenterX, fZoomCenterY); 1537 if (fFlipAxis & kFlipAxis_X) { 1538 m.preScale(-SK_Scalar1, SK_Scalar1); 1539 } 1540 if (fFlipAxis & kFlipAxis_Y) { 1541 m.preScale(SK_Scalar1, -SK_Scalar1); 1542 } 1543 m.preTranslate(-fZoomCenterX, -fZoomCenterY); 1544 //canvas->concat(m); 1545 } 1546 // Apply any gesture matrix 1547 m.preConcat(fGesture.localM()); 1548 m.preConcat(fGesture.globalM()); 1549 1550 this->setLocalMatrix(m); 1551 1552 this->updateTitle(); 1553 this->inval(NULL); 1554} 1555bool SampleWindow::previousSample() { 1556 fCurrIndex = (fCurrIndex - 1 + fSamples.count()) % fSamples.count(); 1557 this->loadView(create_transition(curr_view(this), (*fSamples[fCurrIndex])(), 1558 fTransitionPrev)); 1559 return true; 1560} 1561 1562bool SampleWindow::nextSample() { 1563 fCurrIndex = (fCurrIndex + 1) % fSamples.count(); 1564 this->loadView(create_transition(curr_view(this), (*fSamples[fCurrIndex])(), 1565 fTransitionNext)); 1566 return true; 1567} 1568 1569bool SampleWindow::goToSample(int i) { 1570 fCurrIndex = (i) % fSamples.count(); 1571 this->loadView(create_transition(curr_view(this),(*fSamples[fCurrIndex])(), 6)); 1572 return true; 1573} 1574 1575SkString SampleWindow::getSampleTitle(int i) { 1576 SkView* view = (*fSamples[i])(); 1577 SkString title; 1578 SampleCode::RequestTitle(view, &title); 1579 view->unref(); 1580 return title; 1581} 1582 1583int SampleWindow::sampleCount() { 1584 return fSamples.count(); 1585} 1586 1587void SampleWindow::showOverview() { 1588 this->loadView(create_transition(curr_view(this), 1589 create_overview(fSamples.count(), fSamples.begin()), 1590 4)); 1591} 1592 1593void SampleWindow::installDrawFilter(SkCanvas* canvas) { 1594 canvas->setDrawFilter(new FlagsDrawFilter(fLCDState, fAAState, 1595 fFilterState, fHintingState))->unref(); 1596} 1597 1598void SampleWindow::postAnimatingEvent() { 1599 if (fAnimating) { 1600 (new SkEvent(ANIMATING_EVENTTYPE, this->getSinkID()))->postDelay(ANIMATING_DELAY); 1601 } 1602} 1603 1604bool SampleWindow::onEvent(const SkEvent& evt) { 1605 if (evt.isType(gUpdateWindowTitleEvtName)) { 1606 this->updateTitle(); 1607 return true; 1608 } 1609 if (evt.isType(ANIMATING_EVENTTYPE)) { 1610 if (fAnimating) { 1611 this->nextSample(); 1612 this->postAnimatingEvent(); 1613 } 1614 return true; 1615 } 1616 if (evt.isType("replace-transition-view")) { 1617 this->loadView((SkView*)SkEventSink::FindSink(evt.getFast32())); 1618 return true; 1619 } 1620 if (evt.isType("set-curr-index")) { 1621 this->goToSample(evt.getFast32()); 1622 return true; 1623 } 1624 if (isInvalEvent(evt)) { 1625 this->inval(NULL); 1626 return true; 1627 } 1628 int selected = -1; 1629 if (SkOSMenu::FindListIndex(evt, "Device Type", &selected)) { 1630 this->setDeviceType((DeviceType)selected); 1631 return true; 1632 } 1633 if (SkOSMenu::FindTriState(evt, "Pipe", &fPipeState)) { 1634#ifdef PIPE_NET 1635 if (!fPipeState != SkOSMenu::kOnState) 1636 gServer.disconnectAll(); 1637#endif 1638 (void)SampleView::SetUsePipe(curr_view(this), fPipeState); 1639 this->updateTitle(); 1640 this->inval(NULL); 1641 return true; 1642 } 1643 if (SkOSMenu::FindTriState(evt, "Tiling", &fTilingState)) { 1644 int nx = 1, ny = 1; 1645 switch (fTilingState) { 1646 case SkOSMenu::kOffState: nx = 1; ny = 1; break; 1647 case SkOSMenu::kMixedState: nx = 1; ny = 16; break; 1648 case SkOSMenu::kOnState: nx = 4; ny = 4; break; 1649 } 1650 fTileCount.set(nx, ny); 1651 this->inval(NULL); 1652 return true; 1653 } 1654 if (SkOSMenu::FindSwitchState(evt, "Slide Show", NULL)) { 1655 this->toggleSlideshow(); 1656 return true; 1657 } 1658 if (SkOSMenu::FindTriState(evt, "AA", &fAAState) || 1659 SkOSMenu::FindTriState(evt, "LCD", &fLCDState) || 1660 SkOSMenu::FindTriState(evt, "Filter", &fFilterState) || 1661 SkOSMenu::FindTriState(evt, "Hinting", &fHintingState) || 1662 SkOSMenu::FindSwitchState(evt, "Clip", &fUseClip) || 1663 SkOSMenu::FindSwitchState(evt, "Zoomer", &fShowZoomer) || 1664 SkOSMenu::FindSwitchState(evt, "Magnify", &fMagnify) || 1665 SkOSMenu::FindListIndex(evt, "Transition-Next", &fTransitionNext) || 1666 SkOSMenu::FindListIndex(evt, "Transition-Prev", &fTransitionPrev)) { 1667 this->inval(NULL); 1668 this->updateTitle(); 1669 return true; 1670 } 1671 if (SkOSMenu::FindSwitchState(evt, "Flip X", NULL)) { 1672 fFlipAxis ^= kFlipAxis_X; 1673 this->updateMatrix(); 1674 return true; 1675 } 1676 if (SkOSMenu::FindSwitchState(evt, "Flip Y", NULL)) { 1677 fFlipAxis ^= kFlipAxis_Y; 1678 this->updateMatrix(); 1679 return true; 1680 } 1681 if (SkOSMenu::FindAction(evt,"Save to PDF")) { 1682 this->saveToPdf(); 1683 return true; 1684 } 1685#ifdef DEBUGGER 1686 if (SkOSMenu::FindSwitchState(evt, "Debugger", &fDebugger)) { 1687 if (fDebugger) { 1688 fPipeState = SkOSMenu::kOnState; 1689 (void)SampleView::SetUsePipe(curr_view(this), fPipeState); 1690 } else { 1691 this->loadView((*fSamples[fCurrIndex])()); 1692 } 1693 this->inval(NULL); 1694 return true; 1695 } 1696#endif 1697 return this->INHERITED::onEvent(evt); 1698} 1699 1700bool SampleWindow::onQuery(SkEvent* query) { 1701 if (query->isType("get-slide-count")) { 1702 query->setFast32(fSamples.count()); 1703 return true; 1704 } 1705 if (query->isType("get-slide-title")) { 1706 SkView* view = (*fSamples[query->getFast32()])(); 1707 SkEvent evt(gTitleEvtName); 1708 if (view->doQuery(&evt)) { 1709 query->setString("title", evt.findString(gTitleEvtName)); 1710 } 1711 SkSafeUnref(view); 1712 return true; 1713 } 1714 if (query->isType("use-fast-text")) { 1715 SkEvent evt(gFastTextEvtName); 1716 return curr_view(this)->doQuery(&evt); 1717 } 1718 if (query->isType("ignore-window-bitmap")) { 1719 query->setFast32(this->getGrContext() != NULL); 1720 return true; 1721 } 1722 return this->INHERITED::onQuery(query); 1723} 1724 1725#if 0 // UNUSED 1726static void cleanup_for_filename(SkString* name) { 1727 char* str = name->writable_str(); 1728 for (size_t i = 0; i < name->size(); i++) { 1729 switch (str[i]) { 1730 case ':': str[i] = '-'; break; 1731 case '/': str[i] = '-'; break; 1732 case ' ': str[i] = '_'; break; 1733 default: break; 1734 } 1735 } 1736} 1737#endif 1738 1739bool SampleWindow::onHandleChar(SkUnichar uni) { 1740 { 1741 SkView* view = curr_view(this); 1742 if (view) { 1743 SkEvent evt(gCharEvtName); 1744 evt.setFast32(uni); 1745 if (view->doQuery(&evt)) { 1746 return true; 1747 } 1748 } 1749 } 1750 1751 int dx = 0xFF; 1752 int dy = 0xFF; 1753 1754 switch (uni) { 1755 case '5': dx = 0; dy = 0; break; 1756 case '8': dx = 0; dy = -1; break; 1757 case '6': dx = 1; dy = 0; break; 1758 case '2': dx = 0; dy = 1; break; 1759 case '4': dx = -1; dy = 0; break; 1760 case '7': dx = -1; dy = -1; break; 1761 case '9': dx = 1; dy = -1; break; 1762 case '3': dx = 1; dy = 1; break; 1763 case '1': dx = -1; dy = 1; break; 1764 1765 default: 1766 break; 1767 } 1768 1769 if (0xFF != dx && 0xFF != dy) { 1770 if ((dx | dy) == 0) { 1771 fScrollTestX = fScrollTestY = 0; 1772 } else { 1773 fScrollTestX += dx; 1774 fScrollTestY += dy; 1775 } 1776 this->inval(NULL); 1777 return true; 1778 } 1779 1780 switch (uni) { 1781 case 'f': 1782 // only 1783 toggleFPS(); 1784 break; 1785 case 'g': 1786 fRequestGrabImage = true; 1787 this->inval(NULL); 1788 break; 1789 case 'i': 1790 this->zoomIn(); 1791 break; 1792 case 'o': 1793 this->zoomOut(); 1794 break; 1795 case 'r': 1796 fRotate = !fRotate; 1797 this->inval(NULL); 1798 this->updateTitle(); 1799 return true; 1800 case 'k': 1801 fPerspAnim = !fPerspAnim; 1802 this->inval(NULL); 1803 this->updateTitle(); 1804 return true; 1805#if SK_SUPPORT_GPU 1806 case '\\': 1807 this->setDeviceType(kNullGPU_DeviceType); 1808 this->inval(NULL); 1809 this->updateTitle(); 1810 return true; 1811 case 'p': 1812 { 1813 GrContext* grContext = this->getGrContext(); 1814 if (grContext) { 1815 size_t cacheBytes = grContext->getGpuTextureCacheBytes(); 1816 grContext->freeGpuResources(); 1817 SkDebugf("Purged %d bytes from the GPU resource cache.\n", 1818 cacheBytes); 1819 } 1820 } 1821 return true; 1822#endif 1823 case 's': 1824 fScale = !fScale; 1825 this->inval(NULL); 1826 this->updateTitle(); 1827 return true; 1828 default: 1829 break; 1830 } 1831 1832 if (fAppMenu->handleKeyEquivalent(uni)|| fSlideMenu->handleKeyEquivalent(uni)) { 1833 this->onUpdateMenu(fAppMenu); 1834 this->onUpdateMenu(fSlideMenu); 1835 return true; 1836 } 1837 return this->INHERITED::onHandleChar(uni); 1838} 1839 1840void SampleWindow::setDeviceType(DeviceType type) { 1841 if (type == fDeviceType) 1842 return; 1843 1844 fDevManager->tearDownBackend(this); 1845 1846 fDeviceType = type; 1847 1848 fDevManager->setUpBackend(this, fMSAASampleCount); 1849 1850 this->updateTitle(); 1851 this->inval(NULL); 1852} 1853 1854void SampleWindow::toggleSlideshow() { 1855 fAnimating = !fAnimating; 1856 this->postAnimatingEvent(); 1857 this->updateTitle(); 1858} 1859 1860void SampleWindow::toggleRendering() { 1861 this->setDeviceType(cycle_devicetype(fDeviceType)); 1862 this->updateTitle(); 1863 this->inval(NULL); 1864} 1865 1866void SampleWindow::toggleFPS() { 1867 fMeasureFPS = !fMeasureFPS; 1868 this->updateTitle(); 1869 this->inval(NULL); 1870} 1871 1872#include "SkDumpCanvas.h" 1873 1874bool SampleWindow::onHandleKey(SkKey key) { 1875 { 1876 SkView* view = curr_view(this); 1877 if (view) { 1878 SkEvent evt(gKeyEvtName); 1879 evt.setFast32(key); 1880 if (view->doQuery(&evt)) { 1881 return true; 1882 } 1883 } 1884 } 1885 switch (key) { 1886 case kRight_SkKey: 1887 if (this->nextSample()) { 1888 return true; 1889 } 1890 break; 1891 case kLeft_SkKey: 1892 if (this->previousSample()) { 1893 return true; 1894 } 1895 return true; 1896 case kUp_SkKey: 1897 if (USE_ARROWS_FOR_ZOOM) { 1898 this->changeZoomLevel(1.f); 1899 } else { 1900 fNClip = !fNClip; 1901 this->inval(NULL); 1902 this->updateTitle(); 1903 } 1904 return true; 1905 case kDown_SkKey: 1906 if (USE_ARROWS_FOR_ZOOM) { 1907 this->changeZoomLevel(-1.f); 1908 } else { 1909 this->setConfig(cycle_configs(this->getBitmap().config())); 1910 this->updateTitle(); 1911 } 1912 return true; 1913 case kOK_SkKey: { 1914 SkString title; 1915 if (curr_title(this, &title)) { 1916 writeTitleToPrefs(title.c_str()); 1917 } 1918 return true; 1919 } 1920 case kBack_SkKey: 1921 this->showOverview(); 1922 return true; 1923 default: 1924 break; 1925 } 1926 return this->INHERITED::onHandleKey(key); 1927} 1928 1929/////////////////////////////////////////////////////////////////////////////// 1930 1931static const char gGestureClickType[] = "GestureClickType"; 1932 1933bool SampleWindow::onDispatchClick(int x, int y, Click::State state, 1934 void* owner) { 1935 if (Click::kMoved_State == state) { 1936 updatePointer(x, y); 1937 } 1938 int w = SkScalarRound(this->width()); 1939 int h = SkScalarRound(this->height()); 1940 1941 // check for the resize-box 1942 if (w - x < 16 && h - y < 16) { 1943 return false; // let the OS handle the click 1944 } 1945 else if (fMagnify) { 1946 //it's only necessary to update the drawing if there's a click 1947 this->inval(NULL); 1948 return false; //prevent dragging while magnify is enabled 1949 } 1950 else { 1951 return this->INHERITED::onDispatchClick(x, y, state, owner); 1952 } 1953} 1954 1955class GestureClick : public SkView::Click { 1956public: 1957 GestureClick(SkView* target) : SkView::Click(target) { 1958 this->setType(gGestureClickType); 1959 } 1960 1961 static bool IsGesture(Click* click) { 1962 return click->isType(gGestureClickType); 1963 } 1964}; 1965 1966SkView::Click* SampleWindow::onFindClickHandler(SkScalar x, SkScalar y) { 1967 return new GestureClick(this); 1968} 1969 1970bool SampleWindow::onClick(Click* click) { 1971 if (GestureClick::IsGesture(click)) { 1972 float x = static_cast<float>(click->fICurr.fX); 1973 float y = static_cast<float>(click->fICurr.fY); 1974 1975 switch (click->fState) { 1976 case SkView::Click::kDown_State: 1977 fGesture.touchBegin(click->fOwner, x, y); 1978 break; 1979 case SkView::Click::kMoved_State: 1980 fGesture.touchMoved(click->fOwner, x, y); 1981 this->updateMatrix(); 1982 break; 1983 case SkView::Click::kUp_State: 1984 fGesture.touchEnd(click->fOwner); 1985 this->updateMatrix(); 1986 break; 1987 } 1988 return true; 1989 } 1990 return false; 1991} 1992 1993/////////////////////////////////////////////////////////////////////////////// 1994 1995void SampleWindow::loadView(SkView* view) { 1996 SkView::F2BIter iter(this); 1997 SkView* prev = iter.next(); 1998 if (prev) { 1999 prev->detachFromParent(); 2000 } 2001 2002 view->setVisibleP(true); 2003 view->setClipToBounds(false); 2004 this->attachChildToFront(view)->unref(); 2005 view->setSize(this->width(), this->height()); 2006 2007 //repopulate the slide menu when a view is loaded 2008 fSlideMenu->reset(); 2009#ifdef DEBUGGER 2010 if (!is_debugger(view) && !is_overview(view) && !is_transition(view) && fDebugger) { 2011 //Force Pipe to be on if using debugger 2012 fPipeState = SkOSMenu::kOnState; 2013 } 2014#endif 2015 (void)SampleView::SetUsePipe(view, fPipeState); 2016 if (SampleView::IsSampleView(view)) 2017 ((SampleView*)view)->requestMenu(fSlideMenu); 2018 this->onUpdateMenu(fSlideMenu); 2019 this->updateTitle(); 2020} 2021 2022static const char* gConfigNames[] = { 2023 "unknown config", 2024 "A1", 2025 "A8", 2026 "Index8", 2027 "565", 2028 "4444", 2029 "8888" 2030}; 2031 2032static const char* configToString(SkBitmap::Config c) { 2033 return gConfigNames[c]; 2034} 2035 2036static const char* gDeviceTypePrefix[] = { 2037 "raster: ", 2038 "picture: ", 2039#if SK_SUPPORT_GPU 2040 "opengl: ", 2041#if SK_ANGLE 2042 "angle: ", 2043#endif // SK_ANGLE 2044 "null-gl: " 2045#endif // SK_SUPPORT_GPU 2046}; 2047SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gDeviceTypePrefix) == SampleWindow::kDeviceTypeCnt, 2048 array_size_mismatch); 2049 2050static const bool gDeviceTypeIsGPU[] = { 2051 false, 2052 false, 2053#if SK_SUPPORT_GPU 2054 true, 2055#if SK_ANGLE 2056 true, 2057#endif // SK_ANGLE 2058 true 2059#endif // SK_SUPPORT_GPU 2060}; 2061SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gDeviceTypeIsGPU) == SampleWindow::kDeviceTypeCnt, 2062 array_size_mismatch); 2063 2064 2065static const char* trystate_str(SkOSMenu::TriState state, 2066 const char trueStr[], const char falseStr[]) { 2067 if (SkOSMenu::kOnState == state) { 2068 return trueStr; 2069 } else if (SkOSMenu::kOffState == state) { 2070 return falseStr; 2071 } 2072 return NULL; 2073} 2074 2075void SampleWindow::updateTitle() { 2076 SkView* view = curr_view(this); 2077 2078 SkString title; 2079 if (!curr_title(this, &title)) { 2080 title.set("<unknown>"); 2081 } 2082 2083 title.prepend(gDeviceTypePrefix[fDeviceType]); 2084 2085 title.prepend(" "); 2086 title.prepend(configToString(this->getBitmap().config())); 2087 2088 if (fAnimating) { 2089 title.prepend("<A> "); 2090 } 2091 if (fScale) { 2092 title.prepend("<S> "); 2093 } 2094 if (fRotate) { 2095 title.prepend("<R> "); 2096 } 2097 if (fNClip) { 2098 title.prepend("<C> "); 2099 } 2100 if (fPerspAnim) { 2101 title.prepend("<K> "); 2102 } 2103 2104 title.prepend(trystate_str(fLCDState, "LCD ", "lcd ")); 2105 title.prepend(trystate_str(fAAState, "AA ", "aa ")); 2106 title.prepend(trystate_str(fFilterState, "H ", "h ")); 2107 title.prepend(fFlipAxis & kFlipAxis_X ? "X " : NULL); 2108 title.prepend(fFlipAxis & kFlipAxis_Y ? "Y " : NULL); 2109 2110 if (fZoomLevel) { 2111 title.prependf("{%.2f} ", SkScalarToFloat(fZoomLevel)); 2112 } 2113 2114 if (fMeasureFPS) { 2115 title.appendf(" %8.3f ms", fMeasureFPS_Time / (float)FPS_REPEAT_COUNT); 2116 } 2117 if (SampleView::IsSampleView(view)) { 2118 switch (fPipeState) { 2119 case SkOSMenu::kOnState: 2120 title.prepend("<Pipe> "); 2121 break; 2122 case SkOSMenu::kMixedState: 2123 title.prepend("<Tiled Pipe> "); 2124 break; 2125 2126 default: 2127 break; 2128 } 2129 title.prepend("! "); 2130 } 2131 2132#if SK_SUPPORT_GPU 2133 if (gDeviceTypeIsGPU[fDeviceType] && 2134 NULL != fDevManager && 2135 fDevManager->getGrRenderTarget()->numSamples() > 0) { 2136 title.appendf(" [MSAA: %d]", 2137 fDevManager->getGrRenderTarget()->numSamples()); 2138 } 2139#endif 2140 2141 this->setTitle(title.c_str()); 2142} 2143 2144void SampleWindow::onSizeChange() { 2145 this->INHERITED::onSizeChange(); 2146 2147 SkView::F2BIter iter(this); 2148 SkView* view = iter.next(); 2149 view->setSize(this->width(), this->height()); 2150 2151 // rebuild our clippath 2152 { 2153 const SkScalar W = this->width(); 2154 const SkScalar H = this->height(); 2155 2156 fClipPath.reset(); 2157#if 0 2158 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) { 2159 SkRect r; 2160 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30)); 2161 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0)) 2162 fClipPath.addRect(r); 2163 } 2164#else 2165 SkRect r; 2166 r.set(0, 0, W, H); 2167 fClipPath.addRect(r, SkPath::kCCW_Direction); 2168 r.set(W/4, H/4, W*3/4, H*3/4); 2169 fClipPath.addRect(r, SkPath::kCW_Direction); 2170#endif 2171 } 2172 2173 fZoomCenterX = SkScalarHalf(this->width()); 2174 fZoomCenterY = SkScalarHalf(this->height()); 2175 2176#ifdef SK_BUILD_FOR_ANDROID 2177 // FIXME: The first draw after a size change does not work on Android, so 2178 // we post an invalidate. 2179 this->postInvalDelay(); 2180#endif 2181 this->updateTitle(); // to refresh our config 2182 fDevManager->windowSizeChanged(this); 2183} 2184 2185/////////////////////////////////////////////////////////////////////////////// 2186 2187static const char is_sample_view_tag[] = "sample-is-sample-view"; 2188static const char repeat_count_tag[] = "sample-set-repeat-count"; 2189static const char set_use_pipe_tag[] = "sample-set-use-pipe"; 2190 2191bool SampleView::IsSampleView(SkView* view) { 2192 SkEvent evt(is_sample_view_tag); 2193 return view->doQuery(&evt); 2194} 2195 2196bool SampleView::SetRepeatDraw(SkView* view, int count) { 2197 SkEvent evt(repeat_count_tag); 2198 evt.setFast32(count); 2199 return view->doEvent(evt); 2200} 2201 2202bool SampleView::SetUsePipe(SkView* view, SkOSMenu::TriState state) { 2203 SkEvent evt; 2204 evt.setS32(set_use_pipe_tag, state); 2205 return view->doEvent(evt); 2206} 2207 2208bool SampleView::onEvent(const SkEvent& evt) { 2209 if (evt.isType(repeat_count_tag)) { 2210 fRepeatCount = evt.getFast32(); 2211 return true; 2212 } 2213 int32_t pipeHolder; 2214 if (evt.findS32(set_use_pipe_tag, &pipeHolder)) { 2215 fPipeState = static_cast<SkOSMenu::TriState>(pipeHolder); 2216 return true; 2217 } 2218 return this->INHERITED::onEvent(evt); 2219} 2220 2221bool SampleView::onQuery(SkEvent* evt) { 2222 if (evt->isType(is_sample_view_tag)) { 2223 return true; 2224 } 2225 return this->INHERITED::onQuery(evt); 2226} 2227 2228 2229class SimplePC : public SkGPipeController { 2230public: 2231 SimplePC(SkCanvas* target); 2232 ~SimplePC(); 2233 2234 virtual void* requestBlock(size_t minRequest, size_t* actual); 2235 virtual void notifyWritten(size_t bytes); 2236 2237private: 2238 SkGPipeReader fReader; 2239 void* fBlock; 2240 size_t fBlockSize; 2241 size_t fBytesWritten; 2242 int fAtomsWritten; 2243 SkGPipeReader::Status fStatus; 2244 2245 size_t fTotalWritten; 2246}; 2247 2248SimplePC::SimplePC(SkCanvas* target) : fReader(target) { 2249 fBlock = NULL; 2250 fBlockSize = fBytesWritten = 0; 2251 fStatus = SkGPipeReader::kDone_Status; 2252 fTotalWritten = 0; 2253 fAtomsWritten = 0; 2254} 2255 2256SimplePC::~SimplePC() { 2257// SkASSERT(SkGPipeReader::kDone_Status == fStatus); 2258 if (fTotalWritten) { 2259 SkDebugf("--- %d bytes %d atoms, status %d\n", fTotalWritten, 2260 fAtomsWritten, fStatus); 2261#ifdef PIPE_FILE 2262 //File is open in append mode 2263 FILE* f = fopen(FILE_PATH, "ab"); 2264 SkASSERT(f != NULL); 2265 fwrite((const char*)fBlock + fBytesWritten, 1, bytes, f); 2266 fclose(f); 2267#endif 2268#ifdef PIPE_NET 2269 if (fAtomsWritten > 1 && fTotalWritten > 4) { //ignore done 2270 gServer.acceptConnections(); 2271 gServer.writePacket(fBlock, fTotalWritten); 2272 } 2273#endif 2274#ifdef DEBUGGER 2275 gTempDataStore.reset(); 2276 gTempDataStore.append(fTotalWritten, (const char*)fBlock); 2277#endif 2278 } 2279 sk_free(fBlock); 2280} 2281 2282void* SimplePC::requestBlock(size_t minRequest, size_t* actual) { 2283 sk_free(fBlock); 2284 2285 fBlockSize = minRequest * 4; 2286 fBlock = sk_malloc_throw(fBlockSize); 2287 fBytesWritten = 0; 2288 *actual = fBlockSize; 2289 return fBlock; 2290} 2291 2292void SimplePC::notifyWritten(size_t bytes) { 2293 SkASSERT(fBytesWritten + bytes <= fBlockSize); 2294 fStatus = fReader.playback((const char*)fBlock + fBytesWritten, bytes); 2295 SkASSERT(SkGPipeReader::kError_Status != fStatus); 2296 fBytesWritten += bytes; 2297 fTotalWritten += bytes; 2298 2299 fAtomsWritten += 1; 2300} 2301 2302void SampleView::draw(SkCanvas* canvas) { 2303 if (SkOSMenu::kOffState == fPipeState) { 2304 this->INHERITED::draw(canvas); 2305 } else { 2306 SkGPipeWriter writer; 2307 SimplePC controller(canvas); 2308 TiledPipeController tc(canvas->getDevice()->accessBitmap(false), 2309 &canvas->getTotalMatrix()); 2310 SkGPipeController* pc; 2311 if (SkOSMenu::kMixedState == fPipeState) { 2312 pc = &tc; 2313 } else { 2314 pc = &controller; 2315 } 2316 uint32_t flags = SkGPipeWriter::kCrossProcess_Flag; 2317 2318 canvas = writer.startRecording(pc, flags); 2319 //Must draw before controller goes out of scope and sends data 2320 this->INHERITED::draw(canvas); 2321 //explicitly end recording to ensure writer is flushed before the memory 2322 //is freed in the deconstructor of the controller 2323 writer.endRecording(); 2324 } 2325} 2326void SampleView::onDraw(SkCanvas* canvas) { 2327 this->onDrawBackground(canvas); 2328 2329 for (int i = 0; i < fRepeatCount; i++) { 2330 SkAutoCanvasRestore acr(canvas, true); 2331 this->onDrawContent(canvas); 2332 } 2333} 2334 2335void SampleView::onDrawBackground(SkCanvas* canvas) { 2336 canvas->drawColor(fBGColor); 2337} 2338 2339/////////////////////////////////////////////////////////////////////////////// 2340 2341template <typename T> void SkTBSort(T array[], int count) { 2342 for (int i = 1; i < count - 1; i++) { 2343 bool didSwap = false; 2344 for (int j = count - 1; j > i; --j) { 2345 if (array[j] < array[j-1]) { 2346 T tmp(array[j-1]); 2347 array[j-1] = array[j]; 2348 array[j] = tmp; 2349 didSwap = true; 2350 } 2351 } 2352 if (!didSwap) { 2353 break; 2354 } 2355 } 2356 2357 for (int k = 0; k < count - 1; k++) { 2358 SkASSERT(!(array[k+1] < array[k])); 2359 } 2360} 2361 2362#include "SkRandom.h" 2363 2364static void rand_rect(SkIRect* rect, SkRandom& rand) { 2365 int bits = 8; 2366 int shift = 32 - bits; 2367 rect->set(rand.nextU() >> shift, rand.nextU() >> shift, 2368 rand.nextU() >> shift, rand.nextU() >> shift); 2369 rect->sort(); 2370} 2371 2372static void dumpRect(const SkIRect& r) { 2373 SkDebugf(" { %d, %d, %d, %d },\n", 2374 r.fLeft, r.fTop, 2375 r.fRight, r.fBottom); 2376} 2377 2378static void test_rects(const SkIRect rect[], int count) { 2379 SkRegion rgn0, rgn1; 2380 2381 for (int i = 0; i < count; i++) { 2382 rgn0.op(rect[i], SkRegion::kUnion_Op); 2383 // dumpRect(rect[i]); 2384 } 2385 rgn1.setRects(rect, count); 2386 2387 if (rgn0 != rgn1) { 2388 SkDebugf("\n"); 2389 for (int i = 0; i < count; i++) { 2390 dumpRect(rect[i]); 2391 } 2392 SkDebugf("\n"); 2393 } 2394} 2395 2396static void test() { 2397 size_t i; 2398 2399 const SkIRect r0[] = { 2400 { 0, 0, 1, 1 }, 2401 { 2, 2, 3, 3 }, 2402 }; 2403 const SkIRect r1[] = { 2404 { 0, 0, 1, 3 }, 2405 { 1, 1, 2, 2 }, 2406 { 2, 0, 3, 3 }, 2407 }; 2408 const SkIRect r2[] = { 2409 { 0, 0, 1, 2 }, 2410 { 2, 1, 3, 3 }, 2411 { 4, 0, 5, 1 }, 2412 { 6, 0, 7, 4 }, 2413 }; 2414 2415 static const struct { 2416 const SkIRect* fRects; 2417 int fCount; 2418 } gRecs[] = { 2419 { r0, SK_ARRAY_COUNT(r0) }, 2420 { r1, SK_ARRAY_COUNT(r1) }, 2421 { r2, SK_ARRAY_COUNT(r2) }, 2422 }; 2423 2424 for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) { 2425 test_rects(gRecs[i].fRects, gRecs[i].fCount); 2426 } 2427 2428 SkRandom rand; 2429 for (i = 0; i < 10000; i++) { 2430 SkRegion rgn0, rgn1; 2431 2432 const int N = 8; 2433 SkIRect rect[N]; 2434 for (int j = 0; j < N; j++) { 2435 rand_rect(&rect[j], rand); 2436 } 2437 test_rects(rect, N); 2438 } 2439} 2440 2441// FIXME: this should be in a header 2442SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv); 2443SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) { 2444 if (false) { // avoid bit rot, suppress warning 2445 test(); 2446 } 2447 return new SampleWindow(hwnd, argc, argv, NULL); 2448} 2449 2450// FIXME: this should be in a header 2451void get_preferred_size(int* x, int* y, int* width, int* height); 2452void get_preferred_size(int* x, int* y, int* width, int* height) { 2453 *x = 10; 2454 *y = 50; 2455 *width = 640; 2456 *height = 480; 2457} 2458 2459#ifdef SK_BUILD_FOR_IOS 2460void save_args(int argc, char *argv[]) { 2461} 2462#endif 2463 2464// FIXME: this should be in a header 2465void application_init(); 2466void application_init() { 2467// setenv("ANDROID_ROOT", "../../../data", 0); 2468#ifdef SK_BUILD_FOR_MAC 2469 setenv("ANDROID_ROOT", "/android/device/data", 0); 2470#endif 2471 SkGraphics::Init(); 2472 SkEvent::Init(); 2473} 2474 2475// FIXME: this should be in a header 2476void application_term(); 2477void application_term() { 2478 SkEvent::Term(); 2479 SkGraphics::Term(); 2480} 2481