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