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