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