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