SampleApp.cpp revision 0f185c2709f638c0f4d452cb38b434cadfd15ab9
1#include "SkCanvas.h" 2#include "SkDevice.h" 3#include "SkGpuCanvas.h" 4#include "SkGraphics.h" 5#include "SkImageEncoder.h" 6#include "SkPaint.h" 7#include "SkPicture.h" 8#include "SkStream.h" 9#include "SkTime.h" 10#include "SkWindow.h" 11 12#include "SampleCode.h" 13#include "GrContext.h" 14#include "SkTouchGesture.h" 15#include "SkTypeface.h" 16 17#define USE_ARROWS_FOR_ZOOM true 18//#define DEFAULT_TO_GPU 19 20extern SkView* create_overview(int, const SkViewFactory[]); 21 22#define SK_SUPPORT_GL 23 24#define ANIMATING_EVENTTYPE "nextSample" 25#define ANIMATING_DELAY 750 26 27#ifdef SK_SUPPORT_GL 28 #include "GrGLConfig.h" 29#endif 30 31SkViewRegister* SkViewRegister::gHead; 32SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) { 33 static bool gOnce; 34 if (!gOnce) { 35 gHead = NULL; 36 gOnce = true; 37 } 38 39 fChain = gHead; 40 gHead = this; 41} 42 43#if defined(SK_SUPPORT_GL) 44 #define SK_USE_SHADERS 45#endif 46 47#ifdef SK_BUILD_FOR_MAC 48#include <CoreFoundation/CoreFoundation.h> 49#include <CoreFoundation/CFURLAccess.h> 50 51static void testpdf() { 52 CFStringRef path = CFStringCreateWithCString(NULL, "/test.pdf", 53 kCFStringEncodingUTF8); 54 CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path, 55 kCFURLPOSIXPathStyle, 56 false); 57 CFRelease(path); 58 CGRect box = CGRectMake(0, 0, 8*72, 10*72); 59 CGContextRef cg = CGPDFContextCreateWithURL(url, &box, NULL); 60 CFRelease(url); 61 62 CGContextBeginPage(cg, &box); 63 CGRect r = CGRectMake(10, 10, 40 + 0.5, 50 + 0.5); 64 CGContextFillEllipseInRect(cg, r); 65 CGContextEndPage(cg); 66 CGContextRelease(cg); 67 68 if (false) { 69 SkBitmap bm; 70 bm.setConfig(SkBitmap::kA8_Config, 64, 64); 71 bm.allocPixels(); 72 bm.eraseColor(0); 73 74 SkCanvas canvas(bm); 75 76 } 77} 78#endif 79 80////////////////////////////////////////////////////////////////////////////// 81 82#include "SkDrawFilter.h" 83 84class LCDTextDrawFilter : public SkDrawFilter { 85public: 86 enum Mode { 87 kNeutral_Mode, 88 kForceOn_Mode, 89 kForceOff_Mode 90 }; 91 92 LCDTextDrawFilter(Mode mode) : fMode(mode) {} 93 94 virtual bool filter(SkCanvas*, SkPaint* paint, Type t) { 95 if (kText_Type == t && kNeutral_Mode != fMode) { 96 fPrevLCD = paint->isLCDRenderText(); 97 paint->setLCDRenderText(kForceOn_Mode == fMode); 98 } 99 return true; 100 } 101 102 /** If filter() returned true, then restore() will be called to restore the 103 canvas/paint to their previous states 104 */ 105 virtual void restore(SkCanvas*, SkPaint* paint, Type t) { 106 if (kText_Type == t && kNeutral_Mode != fMode) { 107 paint->setLCDRenderText(fPrevLCD); 108 } 109 } 110 111private: 112 Mode fMode; 113 bool fPrevLCD; 114}; 115 116LCDTextDrawFilter::Mode cycle_lcdmode(LCDTextDrawFilter::Mode mode) { 117 static const LCDTextDrawFilter::Mode gCycle[] = { 118 /* kNeutral_Mode -> */ LCDTextDrawFilter::kForceOn_Mode, 119 /* kForceOn_Mode -> */ LCDTextDrawFilter::kForceOff_Mode, 120 /* kForceOff_Mode -> */ LCDTextDrawFilter::kNeutral_Mode 121 }; 122 return gCycle[mode]; 123} 124 125////////////////////////////////////////////////////////////////////////////// 126 127#define MAX_ZOOM_LEVEL 8 128#define MIN_ZOOM_LEVEL -8 129 130static const char gCharEvtName[] = "SampleCode_Char_Event"; 131static const char gKeyEvtName[] = "SampleCode_Key_Event"; 132static const char gTitleEvtName[] = "SampleCode_Title_Event"; 133static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event"; 134static const char gFastTextEvtName[] = "SampleCode_FastText_Event"; 135 136bool SampleCode::CharQ(const SkEvent& evt, SkUnichar* outUni) { 137 if (evt.isType(gCharEvtName, sizeof(gCharEvtName) - 1)) { 138 if (outUni) { 139 *outUni = evt.getFast32(); 140 } 141 return true; 142 } 143 return false; 144} 145 146bool SampleCode::KeyQ(const SkEvent& evt, SkKey* outKey) { 147 if (evt.isType(gKeyEvtName, sizeof(gKeyEvtName) - 1)) { 148 if (outKey) { 149 *outKey = (SkKey)evt.getFast32(); 150 } 151 return true; 152 } 153 return false; 154} 155 156bool SampleCode::TitleQ(const SkEvent& evt) { 157 return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1); 158} 159 160void SampleCode::TitleR(SkEvent* evt, const char title[]) { 161 SkASSERT(evt && TitleQ(*evt)); 162 evt->setString(gTitleEvtName, title); 163} 164 165bool SampleCode::PrefSizeQ(const SkEvent& evt) { 166 return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1); 167} 168 169void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) { 170 SkASSERT(evt && PrefSizeQ(*evt)); 171 SkScalar size[2]; 172 size[0] = width; 173 size[1] = height; 174 evt->setScalars(gPrefSizeEvtName, 2, size); 175} 176 177bool SampleCode::FastTextQ(const SkEvent& evt) { 178 return evt.isType(gFastTextEvtName, sizeof(gFastTextEvtName) - 1); 179} 180 181/////////////////////////////////////////////////////////////////////////////// 182 183static SkMSec gAnimTime; 184static SkMSec gAnimTimePrev; 185 186SkMSec SampleCode::GetAnimTime() { return gAnimTime; } 187SkMSec SampleCode::GetAnimTimeDelta() { return gAnimTime - gAnimTimePrev; } 188SkScalar SampleCode::GetAnimSecondsDelta() { 189 return SkDoubleToScalar(GetAnimTimeDelta() / 1000.0); 190} 191 192SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) { 193 // since gAnimTime can be up to 32 bits, we can't convert it to a float 194 // or we'll lose the low bits. Hence we use doubles for the intermediate 195 // calculations 196 double seconds = (double)gAnimTime / 1000.0; 197 double value = SkScalarToDouble(speed) * seconds; 198 if (period) { 199 value = ::fmod(value, SkScalarToDouble(period)); 200 } 201 return SkDoubleToScalar(value); 202} 203 204////////////////////////////////////////////////////////////////////////////// 205 206static SkView* curr_view(SkWindow* wind) { 207 SkView::F2BIter iter(wind); 208 return iter.next(); 209} 210 211class SampleWindow : public SkOSWindow { 212 SkTDArray<SkViewFactory> fSamples; 213public: 214 SampleWindow(void* hwnd); 215 virtual ~SampleWindow(); 216 217 virtual void draw(SkCanvas* canvas); 218 219protected: 220 virtual void onDraw(SkCanvas* canvas); 221 virtual bool onHandleKey(SkKey key); 222 virtual bool onHandleChar(SkUnichar); 223 virtual void onSizeChange(); 224 225 virtual SkCanvas* beforeChildren(SkCanvas*); 226 virtual void afterChildren(SkCanvas*); 227 virtual void beforeChild(SkView* child, SkCanvas* canvas); 228 virtual void afterChild(SkView* child, SkCanvas* canvas); 229 230 virtual bool onEvent(const SkEvent& evt); 231 virtual bool onQuery(SkEvent* evt); 232 233 virtual bool onDispatchClick(int x, int y, Click::State); 234 virtual bool onClick(Click* click); 235 virtual Click* onFindClickHandler(SkScalar x, SkScalar y); 236 237#if 0 238 virtual bool handleChar(SkUnichar uni); 239 virtual bool handleEvent(const SkEvent& evt); 240 virtual bool handleKey(SkKey key); 241 virtual bool handleKeyUp(SkKey key); 242 virtual bool onHandleKeyUp(SkKey key); 243#endif 244 245private: 246 int fCurrIndex; 247 248 SkPicture* fPicture; 249 SkGpuCanvas* fGpuCanvas; 250 GrContext* fGrContext; 251 SkPath fClipPath; 252 253 SkTouchGesture fGesture; 254 int fZoomLevel; 255 SkScalar fZoomScale; 256 257 enum CanvasType { 258 kRaster_CanvasType, 259 kPicture_CanvasType, 260 kGPU_CanvasType 261 }; 262 CanvasType fCanvasType; 263 264 bool fUseClip; 265 bool fNClip; 266 bool fRepeatDrawing; 267 bool fAnimating; 268 bool fRotate; 269 bool fScale; 270 bool fRequestGrabImage; 271 272 // The following are for the 'fatbits' drawing 273 // Latest position of the mouse. 274 int fMouseX, fMouseY; 275 int fFatBitsScale; 276 // Used by the text showing position and color values. 277 SkTypeface* fTypeface; 278 bool fShowZoomer; 279 280 LCDTextDrawFilter::Mode fLCDMode; 281 282 int fScrollTestX, fScrollTestY; 283 284 bool make3DReady(); 285 void changeZoomLevel(int delta); 286 287 void loadView(SkView*); 288 void updateTitle(); 289 bool nextSample(); 290 291 void toggleZoomer(); 292 bool zoomIn(); 293 bool zoomOut(); 294 void updatePointer(int x, int y); 295 296 void postAnimatingEvent() { 297 if (fAnimating) { 298 SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE); 299 evt->post(this->getSinkID(), ANIMATING_DELAY); 300 } 301 } 302 303 304 static CanvasType cycle_canvastype(CanvasType); 305 306 typedef SkOSWindow INHERITED; 307}; 308 309bool SampleWindow::zoomIn() 310{ 311 // Arbitrarily decided 312 if (fFatBitsScale == 25) return false; 313 fFatBitsScale++; 314 this->inval(NULL); 315 return true; 316} 317 318bool SampleWindow::zoomOut() 319{ 320 if (fFatBitsScale == 1) return false; 321 fFatBitsScale--; 322 this->inval(NULL); 323 return true; 324} 325 326void SampleWindow::toggleZoomer() 327{ 328 fShowZoomer = !fShowZoomer; 329 this->inval(NULL); 330} 331 332void SampleWindow::updatePointer(int x, int y) 333{ 334 fMouseX = x; 335 fMouseY = y; 336 if (fShowZoomer) { 337 this->inval(NULL); 338 } 339} 340 341bool SampleWindow::make3DReady() { 342 343#if defined(SK_SUPPORT_GL) 344 if (attachGL()) { 345 if (NULL == fGrContext) { 346 #if defined(SK_USE_SHADERS) 347 fGrContext = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL); 348 #else 349 fGrContext = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, NULL); 350 #endif 351 } 352 353 if (NULL != fGrContext) { 354 return true; 355 } else { 356 detachGL(); 357 } 358 } 359#endif 360 SkDebugf("Failed to setup 3D"); 361 return false; 362} 363 364SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) { 365 static const CanvasType gCT[] = { 366 kPicture_CanvasType, 367 kGPU_CanvasType, 368 kRaster_CanvasType 369 }; 370 return gCT[ct]; 371} 372 373SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) { 374 fPicture = NULL; 375 fGpuCanvas = NULL; 376 377 fGrContext = NULL; 378 379#ifdef DEFAULT_TO_GPU 380 fCanvasType = kGPU_CanvasType; 381#else 382 fCanvasType = kRaster_CanvasType; 383#endif 384 fUseClip = false; 385 fNClip = false; 386 fRepeatDrawing = false; 387 fAnimating = false; 388 fRotate = false; 389 fScale = false; 390 fRequestGrabImage = false; 391 fLCDMode = LCDTextDrawFilter::kNeutral_Mode; 392 fScrollTestX = fScrollTestY = 0; 393 394 fMouseX = fMouseY = 0; 395 fFatBitsScale = 1; 396 fTypeface = SkTypeface::CreateFromTypeface(NULL, SkTypeface::kBold); 397 fShowZoomer = false; 398 399 fZoomLevel = 0; 400 fZoomScale = SK_Scalar1; 401 402// this->setConfig(SkBitmap::kRGB_565_Config); 403 this->setConfig(SkBitmap::kARGB_8888_Config); 404 this->setVisibleP(true); 405 this->setClipToBounds(false); 406 407 { 408 const SkViewRegister* reg = SkViewRegister::Head(); 409 while (reg) { 410 *fSamples.append() = reg->factory(); 411 reg = reg->next(); 412 } 413 } 414 fCurrIndex = 0; 415 this->loadView(fSamples[fCurrIndex]()); 416 417#ifdef SK_BUILD_FOR_MAC 418 testpdf(); 419#endif 420} 421 422SampleWindow::~SampleWindow() { 423 delete fPicture; 424 delete fGpuCanvas; 425 if (NULL != fGrContext) { 426 fGrContext->unref(); 427 } 428 fTypeface->unref(); 429} 430 431static SkBitmap capture_bitmap(SkCanvas* canvas) { 432 SkBitmap bm; 433 const SkBitmap& src = canvas->getDevice()->accessBitmap(false); 434 src.copyTo(&bm, src.config()); 435 return bm; 436} 437 438static bool bitmap_diff(SkCanvas* canvas, const SkBitmap& orig, 439 SkBitmap* diff) { 440 const SkBitmap& src = canvas->getDevice()->accessBitmap(false); 441 442 SkAutoLockPixels alp0(src); 443 SkAutoLockPixels alp1(orig); 444 for (int y = 0; y < src.height(); y++) { 445 const void* srcP = src.getAddr(0, y); 446 const void* origP = orig.getAddr(0, y); 447 size_t bytes = src.width() * src.bytesPerPixel(); 448 if (memcmp(srcP, origP, bytes)) { 449 SkDebugf("---------- difference on line %d\n", y); 450 return true; 451 } 452 } 453 return false; 454} 455 456static void drawText(SkCanvas* canvas, SkString string, SkScalar left, SkScalar top, SkPaint& paint) 457{ 458 SkColor desiredColor = paint.getColor(); 459 paint.setColor(SK_ColorWHITE); 460 const char* c_str = string.c_str(); 461 size_t size = string.size(); 462 SkRect bounds; 463 paint.measureText(c_str, size, &bounds); 464 bounds.offset(left, top); 465 SkScalar inset = SkIntToScalar(-2); 466 bounds.inset(inset, inset); 467 canvas->drawRect(bounds, paint); 468 if (desiredColor != SK_ColorBLACK) { 469 paint.setColor(SK_ColorBLACK); 470 canvas->drawText(c_str, size, left + SK_Scalar1, top + SK_Scalar1, paint); 471 } 472 paint.setColor(desiredColor); 473 canvas->drawText(c_str, size, left, top, paint); 474} 475 476#define XCLIP_N 8 477#define YCLIP_N 8 478 479void SampleWindow::draw(SkCanvas* canvas) { 480 // update the animation time 481 gAnimTimePrev = gAnimTime; 482 gAnimTime = SkTime::GetMSecs(); 483 484 if (fZoomLevel) { 485 SkMatrix m; 486 SkScalar cx = SkScalarHalf(this->width()); 487 SkScalar cy = SkScalarHalf(this->height()); 488 SkPoint center; 489 m = canvas->getTotalMatrix();//.invert(&m); 490 m.mapXY(cx, cy, ¢er); 491 cx = center.fX; 492 cy = center.fY; 493 494 m.setTranslate(-cx, -cy); 495 m.postScale(fZoomScale, fZoomScale); 496 m.postTranslate(cx, cy); 497 498 canvas->concat(m); 499 } 500 501 // Apply any gesture matrix 502 if (true) { 503 const SkMatrix& localM = fGesture.localM(); 504 if (localM.getType() & SkMatrix::kScale_Mask) { 505 canvas->setExternalMatrix(&localM); 506 } 507 canvas->concat(localM); 508 canvas->concat(fGesture.globalM()); 509 510 if (fGesture.isActive()) { 511 this->inval(NULL); 512 } 513 } 514 515 if (fNClip) { 516 this->INHERITED::draw(canvas); 517 SkBitmap orig = capture_bitmap(canvas); 518 519 const SkScalar w = this->width(); 520 const SkScalar h = this->height(); 521 const SkScalar cw = w / XCLIP_N; 522 const SkScalar ch = h / YCLIP_N; 523 for (int y = 0; y < YCLIP_N; y++) { 524 SkRect r; 525 r.fTop = y * ch; 526 r.fBottom = (y + 1) * ch; 527 if (y == YCLIP_N - 1) { 528 r.fBottom = h; 529 } 530 for (int x = 0; x < XCLIP_N; x++) { 531 SkAutoCanvasRestore acr(canvas, true); 532 r.fLeft = x * cw; 533 r.fRight = (x + 1) * cw; 534 if (x == XCLIP_N - 1) { 535 r.fRight = w; 536 } 537 canvas->clipRect(r); 538 this->INHERITED::draw(canvas); 539 } 540 } 541 542 SkBitmap diff; 543 if (bitmap_diff(canvas, orig, &diff)) { 544 } 545 } else { 546 this->INHERITED::draw(canvas); 547 } 548 if (fShowZoomer) { 549 int count = canvas->save(); 550 canvas->resetMatrix(); 551 // Ensure the mouse position is on screen. 552 int width = this->width(); 553 int height = this->height(); 554 if (fMouseX >= width) fMouseX = width - 1; 555 else if (fMouseX < 0) fMouseX = 0; 556 if (fMouseY >= height) fMouseY = height - 1; 557 else if (fMouseY < 0) fMouseY = 0; 558 SkBitmap bitmap = capture_bitmap(canvas); 559 // Find the size of the zoomed in view, forced to be odd, so the examined pixel is in the middle. 560 int zoomedWidth = (width >> 2) | 1; 561 int zoomedHeight = (height >> 2) | 1; 562 SkIRect src; 563 src.set(0, 0, zoomedWidth / fFatBitsScale, zoomedHeight / fFatBitsScale); 564 src.offset(fMouseX - (src.width()>>1), fMouseY - (src.height()>>1)); 565 SkRect dest; 566 dest.set(0, 0, SkIntToScalar(zoomedWidth), SkIntToScalar(zoomedHeight)); 567 dest.offset(SkIntToScalar(width - zoomedWidth), SkIntToScalar(height - zoomedHeight)); 568 SkPaint paint; 569 // Clear the background behind our zoomed in view 570 paint.setColor(SK_ColorWHITE); 571 canvas->drawRect(dest, paint); 572 canvas->drawBitmapRect(bitmap, &src, dest); 573 paint.setColor(SK_ColorBLACK); 574 paint.setStyle(SkPaint::kStroke_Style); 575 // Draw a border around the pixel in the middle 576 SkRect originalPixel; 577 originalPixel.set(SkIntToScalar(fMouseX), SkIntToScalar(fMouseY), SkIntToScalar(fMouseX + 1), SkIntToScalar(fMouseY + 1)); 578 SkMatrix matrix; 579 SkRect scalarSrc; 580 scalarSrc.set(src); 581 SkColor color = bitmap.getColor(fMouseX, fMouseY); 582 if (matrix.setRectToRect(scalarSrc, dest, SkMatrix::kFill_ScaleToFit)) { 583 SkRect pixel; 584 matrix.mapRect(&pixel, originalPixel); 585 // TODO Perhaps measure the values and make the outline white if it's "dark" 586 if (color == SK_ColorBLACK) { 587 paint.setColor(SK_ColorWHITE); 588 } 589 canvas->drawRect(pixel, paint); 590 } 591 paint.setColor(SK_ColorBLACK); 592 // Draw a border around the destination rectangle 593 canvas->drawRect(dest, paint); 594 paint.setStyle(SkPaint::kStrokeAndFill_Style); 595 // Identify the pixel and its color on screen 596 paint.setTypeface(fTypeface); 597 paint.setAntiAlias(true); 598 SkScalar lineHeight = paint.getFontMetrics(NULL); 599 SkString string; 600 string.appendf("(%i, %i)", fMouseX, fMouseY); 601 SkScalar left = dest.fLeft + SkIntToScalar(3); 602 SkScalar i = SK_Scalar1; 603 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint); 604 // Alpha 605 i += SK_Scalar1; 606 string.reset(); 607 string.appendf("A: %X", SkColorGetA(color)); 608 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint); 609 // Red 610 i += SK_Scalar1; 611 string.reset(); 612 string.appendf("R: %X", SkColorGetR(color)); 613 paint.setColor(SK_ColorRED); 614 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint); 615 // Green 616 i += SK_Scalar1; 617 string.reset(); 618 string.appendf("G: %X", SkColorGetG(color)); 619 paint.setColor(SK_ColorGREEN); 620 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint); 621 // Blue 622 i += SK_Scalar1; 623 string.reset(); 624 string.appendf("B: %X", SkColorGetB(color)); 625 paint.setColor(SK_ColorBLUE); 626 drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint); 627 canvas->restoreToCount(count); 628 } 629} 630 631void SampleWindow::onDraw(SkCanvas* canvas) { 632 if (fRepeatDrawing) { 633 this->inval(NULL); 634 } 635} 636 637#include "SkColorPriv.h" 638 639static void reverseRedAndBlue(const SkBitmap& bm) { 640 SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config); 641 uint8_t* p = (uint8_t*)bm.getPixels(); 642 uint8_t* stop = p + bm.getSize(); 643 while (p < stop) { 644 // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply 645 unsigned scale = SkAlpha255To256(p[3]); 646 unsigned r = p[2]; 647 unsigned b = p[0]; 648 p[0] = SkAlphaMul(r, scale); 649 p[1] = SkAlphaMul(p[1], scale); 650 p[2] = SkAlphaMul(b, scale); 651 p += 4; 652 } 653} 654 655SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) { 656 SkIPoint viewport; 657 bool alreadyGPU = canvas->getViewport(&viewport); 658 659 if (kGPU_CanvasType != fCanvasType) { 660#ifdef SK_SUPPORT_GL 661 detachGL(); 662#endif 663 } 664 665 switch (fCanvasType) { 666 case kRaster_CanvasType: 667 canvas = this->INHERITED::beforeChildren(canvas); 668 break; 669 case kPicture_CanvasType: 670 fPicture = new SkPicture; 671 canvas = fPicture->beginRecording(9999, 9999); 672 break; 673 case kGPU_CanvasType: { 674 if (!alreadyGPU && make3DReady()) { 675 SkDevice* device = canvas->getDevice(); 676 const SkBitmap& bitmap = device->accessBitmap(true); 677 678 GrRenderTarget* renderTarget; 679 renderTarget = fGrContext->createRenderTargetFrom3DApiState(); 680 fGpuCanvas = new SkGpuCanvas(fGrContext, renderTarget); 681 renderTarget->unref(); 682 683 device = fGpuCanvas->createDevice(SkBitmap::kARGB_8888_Config, 684 bitmap.width(), bitmap.height(), 685 false, false); 686 fGpuCanvas->setDevice(device)->unref(); 687 688 fGpuCanvas->concat(canvas->getTotalMatrix()); 689 canvas = fGpuCanvas; 690 691 } else { 692 canvas = this->INHERITED::beforeChildren(canvas); 693 } 694 break; 695 } 696 } 697 698 if (fUseClip) { 699 canvas->drawColor(0xFFFF88FF); 700 canvas->clipPath(fClipPath); 701 } 702 703 return canvas; 704} 705 706static void paint_rgn(const SkBitmap& bm, const SkIRect& r, 707 const SkRegion& rgn) { 708 SkCanvas canvas(bm); 709 SkRegion inval(rgn); 710 711 inval.translate(r.fLeft, r.fTop); 712 canvas.clipRegion(inval); 713 canvas.drawColor(0xFFFF8080); 714} 715 716void SampleWindow::afterChildren(SkCanvas* orig) { 717 if (fRequestGrabImage) { 718 fRequestGrabImage = false; 719 720 SkCanvas* canvas = fGpuCanvas ? fGpuCanvas : orig; 721 SkDevice* device = canvas->getDevice(); 722 SkBitmap bitmap; 723 SkIRect bounds = { 724 0, 0, 725 SkScalarRound(this->width()), 726 SkScalarRound(this->height()) 727 }; 728 if (device->readPixels(bounds, &bitmap)) { 729 static int gSampleGrabCounter; 730 SkString name; 731 name.printf("sample_grab_%d", gSampleGrabCounter++); 732 SkImageEncoder::EncodeFile(name.c_str(), bitmap, 733 SkImageEncoder::kPNG_Type, 100); 734 } 735 } 736 737 switch (fCanvasType) { 738 case kRaster_CanvasType: 739 break; 740 case kPicture_CanvasType: 741 if (true) { 742 SkPicture* pict = new SkPicture(*fPicture); 743 fPicture->unref(); 744 orig->drawPicture(*pict); 745 pict->unref(); 746 } else if (true) { 747 SkDynamicMemoryWStream ostream; 748 fPicture->serialize(&ostream); 749 fPicture->unref(); 750 751 SkMemoryStream istream(ostream.getStream(), ostream.getOffset()); 752 SkPicture pict(&istream); 753 orig->drawPicture(pict); 754 } else { 755 fPicture->draw(orig); 756 fPicture->unref(); 757 } 758 fPicture = NULL; 759 break; 760#ifdef SK_SUPPORT_GL 761 case kGPU_CanvasType: 762 delete fGpuCanvas; 763 fGpuCanvas = NULL; 764 presentGL(); 765 break; 766#endif 767 } 768 769// if ((fScrollTestX | fScrollTestY) != 0) 770 if (false) { 771 const SkBitmap& bm = orig->getDevice()->accessBitmap(true); 772 int dx = fScrollTestX * 7; 773 int dy = fScrollTestY * 7; 774 SkIRect r; 775 SkRegion inval; 776 777 r.set(50, 50, 50+100, 50+100); 778 bm.scrollRect(&r, dx, dy, &inval); 779 paint_rgn(bm, r, inval); 780 } 781} 782 783void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) { 784 if (fScale) { 785 SkScalar scale = SK_Scalar1 * 7 / 10; 786 SkScalar cx = this->width() / 2; 787 SkScalar cy = this->height() / 2; 788 canvas->translate(cx, cy); 789 canvas->scale(scale, scale); 790 canvas->translate(-cx, -cy); 791 } 792 if (fRotate) { 793 SkScalar cx = this->width() / 2; 794 SkScalar cy = this->height() / 2; 795 canvas->translate(cx, cy); 796 canvas->rotate(SkIntToScalar(30)); 797 canvas->translate(-cx, -cy); 798 } 799 800 if (LCDTextDrawFilter::kNeutral_Mode != fLCDMode) { 801 canvas->setDrawFilter(new LCDTextDrawFilter(fLCDMode))->unref(); 802 } 803} 804 805void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) { 806 canvas->setDrawFilter(NULL); 807} 808 809static SkBitmap::Config gConfigCycle[] = { 810 SkBitmap::kNo_Config, // none -> none 811 SkBitmap::kNo_Config, // a1 -> none 812 SkBitmap::kNo_Config, // a8 -> none 813 SkBitmap::kNo_Config, // index8 -> none 814 SkBitmap::kARGB_4444_Config, // 565 -> 4444 815 SkBitmap::kARGB_8888_Config, // 4444 -> 8888 816 SkBitmap::kRGB_565_Config // 8888 -> 565 817}; 818 819static SkBitmap::Config cycle_configs(SkBitmap::Config c) { 820 return gConfigCycle[c]; 821} 822 823void SampleWindow::changeZoomLevel(int delta) { 824 fZoomLevel += delta; 825 if (fZoomLevel > 0) { 826 fZoomLevel = SkMin32(fZoomLevel, MAX_ZOOM_LEVEL); 827 fZoomScale = SkIntToScalar(fZoomLevel + 1); 828 } else if (fZoomLevel < 0) { 829 fZoomLevel = SkMax32(fZoomLevel, MIN_ZOOM_LEVEL); 830 fZoomScale = SK_Scalar1 / (1 - fZoomLevel); 831 } else { 832 fZoomScale = SK_Scalar1; 833 } 834 835 this->inval(NULL); 836} 837 838bool SampleWindow::nextSample() { 839 fCurrIndex = (fCurrIndex + 1) % fSamples.count(); 840 this->loadView(fSamples[fCurrIndex]()); 841 return true; 842} 843 844bool SampleWindow::onEvent(const SkEvent& evt) { 845 if (evt.isType(ANIMATING_EVENTTYPE)) { 846 if (fAnimating) { 847 this->nextSample(); 848 this->postAnimatingEvent(); 849 } 850 return true; 851 } 852 if (evt.isType("set-curr-index")) { 853 fCurrIndex = evt.getFast32() % fSamples.count(); 854 this->loadView(fSamples[fCurrIndex]()); 855 return true; 856 } 857 return this->INHERITED::onEvent(evt); 858} 859 860bool SampleWindow::onQuery(SkEvent* query) { 861 if (query->isType("get-slide-count")) { 862 query->setFast32(fSamples.count()); 863 return true; 864 } 865 if (query->isType("get-slide-title")) { 866 SkView* view = fSamples[query->getFast32()](); 867 SkEvent evt(gTitleEvtName); 868 if (view->doQuery(&evt)) { 869 query->setString("title", evt.findString(gTitleEvtName)); 870 } 871 SkSafeUnref(view); 872 return true; 873 } 874 if (query->isType("use-fast-text")) { 875 SkEvent evt(gFastTextEvtName); 876 return curr_view(this)->doQuery(&evt); 877 } 878 return this->INHERITED::onQuery(query); 879} 880 881static void cleanup_for_filename(SkString* name) { 882 char* str = name->writable_str(); 883 for (size_t i = 0; i < name->size(); i++) { 884 switch (str[i]) { 885 case ':': str[i] = '-'; break; 886 case '/': str[i] = '-'; break; 887 case ' ': str[i] = '_'; break; 888 default: break; 889 } 890 } 891} 892 893bool SampleWindow::onHandleChar(SkUnichar uni) { 894 { 895 SkView* view = curr_view(this); 896 if (view) { 897 SkEvent evt(gCharEvtName); 898 evt.setFast32(uni); 899 if (view->doQuery(&evt)) { 900 return true; 901 } 902 } 903 } 904 905 int dx = 0xFF; 906 int dy = 0xFF; 907 908 switch (uni) { 909 case '5': dx = 0; dy = 0; break; 910 case '8': dx = 0; dy = -1; break; 911 case '6': dx = 1; dy = 0; break; 912 case '2': dx = 0; dy = 1; break; 913 case '4': dx = -1; dy = 0; break; 914 case '7': dx = -1; dy = -1; break; 915 case '9': dx = 1; dy = -1; break; 916 case '3': dx = 1; dy = 1; break; 917 case '1': dx = -1; dy = 1; break; 918 919 default: 920 break; 921 } 922 923 if (0xFF != dx && 0xFF != dy) { 924 if ((dx | dy) == 0) { 925 fScrollTestX = fScrollTestY = 0; 926 } else { 927 fScrollTestX += dx; 928 fScrollTestY += dy; 929 } 930 this->inval(NULL); 931 return true; 932 } 933 934 switch (uni) { 935 case 'a': 936 fAnimating = !fAnimating; 937 this->postAnimatingEvent(); 938 this->updateTitle(); 939 return true; 940 case 'f': { 941 const char* title = this->getTitle(); 942 if (title[0] == 0) { 943 title = "sampleapp"; 944 } 945 SkString name(title); 946 cleanup_for_filename(&name); 947 name.append(".png"); 948 if (SkImageEncoder::EncodeFile(name.c_str(), this->getBitmap(), 949 SkImageEncoder::kPNG_Type, 100)) { 950 SkDebugf("Created %s\n", name.c_str()); 951 } 952 return true; 953 } 954 case 'r': 955 fRotate = !fRotate; 956 this->inval(NULL); 957 this->updateTitle(); 958 return true; 959 case 's': 960 fScale = !fScale; 961 this->inval(NULL); 962 this->updateTitle(); 963 return true; 964 case 'c': 965 fUseClip = !fUseClip; 966 this->inval(NULL); 967 this->updateTitle(); 968 return true; 969 case 'd': 970 SkGraphics::SetFontCacheUsed(0); 971 return true; 972 case 'g': 973 fRequestGrabImage = true; 974 this->inval(NULL); 975 break; 976 case 'l': 977 fLCDMode = cycle_lcdmode(fLCDMode); 978 this->updateTitle(); 979 this->inval(NULL); 980 break; 981 case 'i': 982 this->zoomIn(); 983 break; 984 case 'o': 985 this->zoomOut(); 986 break; 987 case 'z': 988 this->toggleZoomer(); 989 break; 990 default: 991 break; 992 } 993 994 return this->INHERITED::onHandleChar(uni); 995} 996 997#include "SkDumpCanvas.h" 998 999bool SampleWindow::onHandleKey(SkKey key) { 1000 { 1001 SkView* view = curr_view(this); 1002 if (view) { 1003 SkEvent evt(gKeyEvtName); 1004 evt.setFast32(key); 1005 if (view->doQuery(&evt)) { 1006 return true; 1007 } 1008 } 1009 } 1010 1011 switch (key) { 1012 case kRight_SkKey: 1013 if (this->nextSample()) { 1014 return true; 1015 } 1016 break; 1017 case kLeft_SkKey: 1018 fCanvasType = cycle_canvastype(fCanvasType); 1019 this->updateTitle(); 1020 this->inval(NULL); 1021 return true; 1022 case kUp_SkKey: 1023 if (USE_ARROWS_FOR_ZOOM) { 1024 this->changeZoomLevel(1); 1025 } else { 1026 fNClip = !fNClip; 1027 this->inval(NULL); 1028 } 1029 this->updateTitle(); 1030 return true; 1031 case kDown_SkKey: 1032 if (USE_ARROWS_FOR_ZOOM) { 1033 this->changeZoomLevel(-1); 1034 } else { 1035 this->setConfig(cycle_configs(this->getBitmap().config())); 1036 } 1037 this->updateTitle(); 1038 return true; 1039 case kOK_SkKey: 1040 if (false) { 1041 SkDebugfDumper dumper; 1042 SkDumpCanvas dc(&dumper); 1043 this->draw(&dc); 1044 } else { 1045 fRepeatDrawing = !fRepeatDrawing; 1046 if (fRepeatDrawing) { 1047 this->inval(NULL); 1048 } 1049 } 1050 return true; 1051 case kBack_SkKey: 1052 this->loadView(NULL); 1053 return true; 1054 default: 1055 break; 1056 } 1057 return this->INHERITED::onHandleKey(key); 1058} 1059 1060/////////////////////////////////////////////////////////////////////////////// 1061 1062static const char gGestureClickType[] = "GestureClickType"; 1063 1064bool SampleWindow::onDispatchClick(int x, int y, Click::State state) { 1065 if (Click::kMoved_State == state) { 1066 updatePointer(x, y); 1067 } 1068 int w = SkScalarRound(this->width()); 1069 int h = SkScalarRound(this->height()); 1070 1071 // check for the resize-box 1072 if (w - x < 16 && h - y < 16) { 1073 return false; // let the OS handle the click 1074 } else { 1075 return this->INHERITED::onDispatchClick(x, y, state); 1076 } 1077} 1078 1079class GestureClick : public SkView::Click { 1080public: 1081 GestureClick(SkView* target) : SkView::Click(target) { 1082 this->setType(gGestureClickType); 1083 } 1084 1085 static bool IsGesture(Click* click) { 1086 return click->isType(gGestureClickType); 1087 } 1088}; 1089 1090SkView::Click* SampleWindow::onFindClickHandler(SkScalar x, SkScalar y) { 1091 return new GestureClick(this); 1092} 1093 1094bool SampleWindow::onClick(Click* click) { 1095 if (GestureClick::IsGesture(click)) { 1096 float x = SkScalarToFloat(click->fCurr.fX); 1097 float y = SkScalarToFloat(click->fCurr.fY); 1098 switch (click->fState) { 1099 case SkView::Click::kDown_State: 1100 fGesture.touchBegin(click, x, y); 1101 break; 1102 case SkView::Click::kMoved_State: 1103 fGesture.touchMoved(click, x, y); 1104 this->inval(NULL); 1105 break; 1106 case SkView::Click::kUp_State: 1107 fGesture.touchEnd(click); 1108 this->inval(NULL); 1109 break; 1110 } 1111 return true; 1112 } 1113 return false; 1114} 1115 1116/////////////////////////////////////////////////////////////////////////////// 1117 1118void SampleWindow::loadView(SkView* view) { 1119 SkView::F2BIter iter(this); 1120 SkView* prev = iter.next(); 1121 if (prev) { 1122 prev->detachFromParent(); 1123 } 1124 1125 if (NULL == view) { 1126 view = create_overview(fSamples.count(), fSamples.begin()); 1127 } 1128 view->setVisibleP(true); 1129 view->setClipToBounds(false); 1130 this->attachChildToFront(view)->unref(); 1131 view->setSize(this->width(), this->height()); 1132 1133 this->updateTitle(); 1134} 1135 1136static const char* gConfigNames[] = { 1137 "unknown config", 1138 "A1", 1139 "A8", 1140 "Index8", 1141 "565", 1142 "4444", 1143 "8888" 1144}; 1145 1146static const char* configToString(SkBitmap::Config c) { 1147 return gConfigNames[c]; 1148} 1149 1150static const char* gCanvasTypePrefix[] = { 1151 "raster: ", 1152 "picture: ", 1153 "opengl: " 1154}; 1155 1156void SampleWindow::updateTitle() { 1157 SkString title; 1158 1159 SkView::F2BIter iter(this); 1160 SkView* view = iter.next(); 1161 SkEvent evt(gTitleEvtName); 1162 if (view->doQuery(&evt)) { 1163 title.set(evt.findString(gTitleEvtName)); 1164 } 1165 if (title.size() == 0) { 1166 title.set("<unknown>"); 1167 } 1168 1169 title.prepend(gCanvasTypePrefix[fCanvasType]); 1170 1171 title.prepend(" "); 1172 title.prepend(configToString(this->getBitmap().config())); 1173 1174 if (fAnimating) { 1175 title.prepend("<A> "); 1176 } 1177 if (fScale) { 1178 title.prepend("<S> "); 1179 } 1180 if (fRotate) { 1181 title.prepend("<R> "); 1182 } 1183 if (fNClip) { 1184 title.prepend("<C> "); 1185 } 1186 if (LCDTextDrawFilter::kForceOn_Mode == fLCDMode) { 1187 title.prepend("LCD "); 1188 } else if (LCDTextDrawFilter::kForceOff_Mode == fLCDMode) { 1189 title.prepend("lcd "); 1190 } 1191 1192 if (fZoomLevel) { 1193 title.prependf("{%d} ", fZoomLevel); 1194 } 1195 this->setTitle(title.c_str()); 1196} 1197 1198void SampleWindow::onSizeChange() { 1199 this->INHERITED::onSizeChange(); 1200 1201 SkView::F2BIter iter(this); 1202 SkView* view = iter.next(); 1203 view->setSize(this->width(), this->height()); 1204 1205 // rebuild our clippath 1206 { 1207 const SkScalar W = this->width(); 1208 const SkScalar H = this->height(); 1209 1210 fClipPath.reset(); 1211#if 0 1212 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) { 1213 SkRect r; 1214 r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30)); 1215 for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0)) 1216 fClipPath.addRect(r); 1217 } 1218#else 1219 SkRect r; 1220 r.set(0, 0, W, H); 1221 fClipPath.addRect(r, SkPath::kCCW_Direction); 1222 r.set(W/4, H/4, W*3/4, H*3/4); 1223 fClipPath.addRect(r, SkPath::kCW_Direction); 1224#endif 1225 } 1226 1227 this->updateTitle(); // to refresh our config 1228} 1229 1230/////////////////////////////////////////////////////////////////////////////// 1231 1232template <typename T> void SkTBSort(T array[], int count) { 1233 for (int i = 1; i < count - 1; i++) { 1234 bool didSwap = false; 1235 for (int j = count - 1; j > i; --j) { 1236 if (array[j] < array[j-1]) { 1237 T tmp(array[j-1]); 1238 array[j-1] = array[j]; 1239 array[j] = tmp; 1240 didSwap = true; 1241 } 1242 } 1243 if (!didSwap) { 1244 break; 1245 } 1246 } 1247 1248 for (int k = 0; k < count - 1; k++) { 1249 SkASSERT(!(array[k+1] < array[k])); 1250 } 1251} 1252 1253#include "SkRandom.h" 1254 1255static void rand_rect(SkIRect* rect, SkRandom& rand) { 1256 int bits = 8; 1257 int shift = 32 - bits; 1258 rect->set(rand.nextU() >> shift, rand.nextU() >> shift, 1259 rand.nextU() >> shift, rand.nextU() >> shift); 1260 rect->sort(); 1261} 1262 1263static void dumpRect(const SkIRect& r) { 1264 SkDebugf(" { %d, %d, %d, %d },\n", 1265 r.fLeft, r.fTop, 1266 r.fRight, r.fBottom); 1267} 1268 1269static void test_rects(const SkIRect rect[], int count) { 1270 SkRegion rgn0, rgn1; 1271 1272 for (int i = 0; i < count; i++) { 1273 rgn0.op(rect[i], SkRegion::kUnion_Op); 1274 // dumpRect(rect[i]); 1275 } 1276 rgn1.setRects(rect, count); 1277 1278 if (rgn0 != rgn1) { 1279 SkDebugf("\n"); 1280 for (int i = 0; i < count; i++) { 1281 dumpRect(rect[i]); 1282 } 1283 SkDebugf("\n"); 1284 } 1285} 1286 1287static void test() { 1288 size_t i; 1289 1290 const SkIRect r0[] = { 1291 { 0, 0, 1, 1 }, 1292 { 2, 2, 3, 3 }, 1293 }; 1294 const SkIRect r1[] = { 1295 { 0, 0, 1, 3 }, 1296 { 1, 1, 2, 2 }, 1297 { 2, 0, 3, 3 }, 1298 }; 1299 const SkIRect r2[] = { 1300 { 0, 0, 1, 2 }, 1301 { 2, 1, 3, 3 }, 1302 { 4, 0, 5, 1 }, 1303 { 6, 0, 7, 4 }, 1304 }; 1305 1306 static const struct { 1307 const SkIRect* fRects; 1308 int fCount; 1309 } gRecs[] = { 1310 { r0, SK_ARRAY_COUNT(r0) }, 1311 { r1, SK_ARRAY_COUNT(r1) }, 1312 { r2, SK_ARRAY_COUNT(r2) }, 1313 }; 1314 1315 for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) { 1316 test_rects(gRecs[i].fRects, gRecs[i].fCount); 1317 } 1318 1319 SkRandom rand; 1320 for (i = 0; i < 10000; i++) { 1321 SkRegion rgn0, rgn1; 1322 1323 const int N = 8; 1324 SkIRect rect[N]; 1325 for (int j = 0; j < N; j++) { 1326 rand_rect(&rect[j], rand); 1327 } 1328 test_rects(rect, N); 1329 } 1330} 1331 1332SkOSWindow* create_sk_window(void* hwnd) { 1333// test(); 1334 return new SampleWindow(hwnd); 1335} 1336 1337void get_preferred_size(int* x, int* y, int* width, int* height) { 1338 *x = 10; 1339 *y = 50; 1340 *width = 640; 1341 *height = 480; 1342} 1343 1344void application_init() { 1345// setenv("ANDROID_ROOT", "../../../data", 0); 1346#ifdef SK_BUILD_FOR_MAC 1347 setenv("ANDROID_ROOT", "/android/device/data", 0); 1348#endif 1349 SkGraphics::Init(); 1350 SkEvent::Init(); 1351} 1352 1353void application_term() { 1354 SkEvent::Term(); 1355 SkGraphics::Term(); 1356} 1357