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