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