SkCanvas.cpp revision f20fc24a7def23093a1abd2fc8de4a1302aeb9f8
1 2/* 3 * Copyright 2008 The Android Open Source Project 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 9 10#include "SkCanvas.h" 11#include "SkBitmapDevice.h" 12#include "SkBounder.h" 13#include "SkDeviceImageFilterProxy.h" 14#include "SkDraw.h" 15#include "SkDrawFilter.h" 16#include "SkDrawLooper.h" 17#include "SkMetaData.h" 18#include "SkPathOps.h" 19#include "SkPicture.h" 20#include "SkRasterClip.h" 21#include "SkRRect.h" 22#include "SkSmallAllocator.h" 23#include "SkSurface_Base.h" 24#include "SkTemplates.h" 25#include "SkTextFormatParams.h" 26#include "SkTLazy.h" 27#include "SkUtils.h" 28 29#if SK_SUPPORT_GPU 30#include "GrRenderTarget.h" 31#endif 32 33// experimental for faster tiled drawing... 34//#define SK_ENABLE_CLIP_QUICKREJECT 35 36//#define SK_TRACE_SAVERESTORE 37 38#ifdef SK_TRACE_SAVERESTORE 39 static int gLayerCounter; 40 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); } 41 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); } 42 43 static int gRecCounter; 44 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); } 45 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); } 46 47 static int gCanvasCounter; 48 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); } 49 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); } 50#else 51 #define inc_layer() 52 #define dec_layer() 53 #define inc_rec() 54 #define dec_rec() 55 #define inc_canvas() 56 #define dec_canvas() 57#endif 58 59#ifdef SK_DEBUG 60#include "SkPixelRef.h" 61 62/* 63 * Some pixelref subclasses can support being "locked" from another thread 64 * during the lock-scope of skia calling them. In these instances, this balance 65 * check will fail, but may not be indicative of a problem, so we allow a build 66 * flag to disable this check. 67 * 68 * Potentially another fix would be to have a (debug-only) virtual or flag on 69 * pixelref, which could tell us at runtime if this check is valid. That would 70 * eliminate the need for this heavy-handed build check. 71 */ 72#ifdef SK_DISABLE_PIXELREF_LOCKCOUNT_BALANCE_CHECK 73class AutoCheckLockCountBalance { 74public: 75 AutoCheckLockCountBalance(const SkBitmap&) { /* do nothing */ } 76}; 77#else 78class AutoCheckLockCountBalance { 79public: 80 AutoCheckLockCountBalance(const SkBitmap& bm) : fPixelRef(bm.pixelRef()) { 81 fLockCount = fPixelRef ? fPixelRef->getLockCount() : 0; 82 } 83 ~AutoCheckLockCountBalance() { 84 const int count = fPixelRef ? fPixelRef->getLockCount() : 0; 85 SkASSERT(count == fLockCount); 86 } 87 88private: 89 const SkPixelRef* fPixelRef; 90 int fLockCount; 91}; 92#endif 93 94class AutoCheckNoSetContext { 95public: 96 AutoCheckNoSetContext(const SkPaint& paint) : fPaint(paint) { 97 this->assertNoSetContext(fPaint); 98 } 99 ~AutoCheckNoSetContext() { 100 this->assertNoSetContext(fPaint); 101 } 102 103private: 104 const SkPaint& fPaint; 105 106 void assertNoSetContext(const SkPaint& paint) { 107 SkShader* s = paint.getShader(); 108 if (s) { 109 SkASSERT(!s->setContextHasBeenCalled()); 110 } 111 } 112}; 113 114#define CHECK_LOCKCOUNT_BALANCE(bitmap) AutoCheckLockCountBalance clcb(bitmap) 115#define CHECK_SHADER_NOSETCONTEXT(paint) AutoCheckNoSetContext cshsc(paint) 116 117#else 118 #define CHECK_LOCKCOUNT_BALANCE(bitmap) 119 #define CHECK_SHADER_NOSETCONTEXT(paint) 120#endif 121 122typedef SkTLazy<SkPaint> SkLazyPaint; 123 124void SkCanvas::predrawNotify() { 125 if (fSurfaceBase) { 126 fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode); 127 } 128} 129 130/////////////////////////////////////////////////////////////////////////////// 131 132/* This is the record we keep for each SkBaseDevice that the user installs. 133 The clip/matrix/proc are fields that reflect the top of the save/restore 134 stack. Whenever the canvas changes, it marks a dirty flag, and then before 135 these are used (assuming we're not on a layer) we rebuild these cache 136 values: they reflect the top of the save stack, but translated and clipped 137 by the device's XY offset and bitmap-bounds. 138*/ 139struct DeviceCM { 140 DeviceCM* fNext; 141 SkBaseDevice* fDevice; 142 SkRasterClip fClip; 143 const SkMatrix* fMatrix; 144 SkPaint* fPaint; // may be null (in the future) 145 146 DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas) 147 : fNext(NULL) { 148 if (NULL != device) { 149 device->ref(); 150 device->onAttachToCanvas(canvas); 151 } 152 fDevice = device; 153 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL; 154 } 155 156 ~DeviceCM() { 157 if (NULL != fDevice) { 158 fDevice->onDetachFromCanvas(); 159 fDevice->unref(); 160 } 161 SkDELETE(fPaint); 162 } 163 164 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip, 165 const SkClipStack& clipStack, SkRasterClip* updateClip) { 166 int x = fDevice->getOrigin().x(); 167 int y = fDevice->getOrigin().y(); 168 int width = fDevice->width(); 169 int height = fDevice->height(); 170 171 if ((x | y) == 0) { 172 fMatrix = &totalMatrix; 173 fClip = totalClip; 174 } else { 175 fMatrixStorage = totalMatrix; 176 fMatrixStorage.postTranslate(SkIntToScalar(-x), 177 SkIntToScalar(-y)); 178 fMatrix = &fMatrixStorage; 179 180 totalClip.translate(-x, -y, &fClip); 181 } 182 183 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op); 184 185 // intersect clip, but don't translate it (yet) 186 187 if (updateClip) { 188 updateClip->op(SkIRect::MakeXYWH(x, y, width, height), 189 SkRegion::kDifference_Op); 190 } 191 192 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack); 193 194#ifdef SK_DEBUG 195 if (!fClip.isEmpty()) { 196 SkIRect deviceR; 197 deviceR.set(0, 0, width, height); 198 SkASSERT(deviceR.contains(fClip.getBounds())); 199 } 200#endif 201 } 202 203private: 204 SkMatrix fMatrixStorage; 205}; 206 207/* This is the record we keep for each save/restore level in the stack. 208 Since a level optionally copies the matrix and/or stack, we have pointers 209 for these fields. If the value is copied for this level, the copy is 210 stored in the ...Storage field, and the pointer points to that. If the 211 value is not copied for this level, we ignore ...Storage, and just point 212 at the corresponding value in the previous level in the stack. 213*/ 214class SkCanvas::MCRec { 215public: 216 int fFlags; 217 SkMatrix* fMatrix; // points to either fMatrixStorage or prev MCRec 218 SkRasterClip* fRasterClip; // points to either fRegionStorage or prev MCRec 219 SkDrawFilter* fFilter; // the current filter (or null) 220 221 DeviceCM* fLayer; 222 /* If there are any layers in the stack, this points to the top-most 223 one that is at or below this level in the stack (so we know what 224 bitmap/device to draw into from this level. This value is NOT 225 reference counted, since the real owner is either our fLayer field, 226 or a previous one in a lower level.) 227 */ 228 DeviceCM* fTopLayer; 229 230 MCRec(const MCRec* prev, int flags) : fFlags(flags) { 231 if (NULL != prev) { 232 if (flags & SkCanvas::kMatrix_SaveFlag) { 233 fMatrixStorage = *prev->fMatrix; 234 fMatrix = &fMatrixStorage; 235 } else { 236 fMatrix = prev->fMatrix; 237 } 238 239 if (flags & SkCanvas::kClip_SaveFlag) { 240 fRasterClipStorage = *prev->fRasterClip; 241 fRasterClip = &fRasterClipStorage; 242 } else { 243 fRasterClip = prev->fRasterClip; 244 } 245 246 fFilter = prev->fFilter; 247 SkSafeRef(fFilter); 248 249 fTopLayer = prev->fTopLayer; 250 } else { // no prev 251 fMatrixStorage.reset(); 252 253 fMatrix = &fMatrixStorage; 254 fRasterClip = &fRasterClipStorage; 255 fFilter = NULL; 256 fTopLayer = NULL; 257 } 258 fLayer = NULL; 259 260 // don't bother initializing fNext 261 inc_rec(); 262 } 263 ~MCRec() { 264 SkSafeUnref(fFilter); 265 SkDELETE(fLayer); 266 dec_rec(); 267 } 268 269private: 270 SkMatrix fMatrixStorage; 271 SkRasterClip fRasterClipStorage; 272}; 273 274class SkDrawIter : public SkDraw { 275public: 276 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) { 277 canvas = canvas->canvasForDrawIter(); 278 fCanvas = canvas; 279 canvas->updateDeviceCMCache(); 280 281 fClipStack = &canvas->fClipStack; 282 fBounder = canvas->getBounder(); 283 fCurrLayer = canvas->fMCRec->fTopLayer; 284 fSkipEmptyClips = skipEmptyClips; 285 } 286 287 bool next() { 288 // skip over recs with empty clips 289 if (fSkipEmptyClips) { 290 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) { 291 fCurrLayer = fCurrLayer->fNext; 292 } 293 } 294 295 const DeviceCM* rec = fCurrLayer; 296 if (rec && rec->fDevice) { 297 298 fMatrix = rec->fMatrix; 299 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW(); 300 fRC = &rec->fClip; 301 fDevice = rec->fDevice; 302 fBitmap = &fDevice->accessBitmap(true); 303 fPaint = rec->fPaint; 304 SkDEBUGCODE(this->validate();) 305 306 fCurrLayer = rec->fNext; 307 if (fBounder) { 308 fBounder->setClip(fClip); 309 } 310 // fCurrLayer may be NULL now 311 312 return true; 313 } 314 return false; 315 } 316 317 SkBaseDevice* getDevice() const { return fDevice; } 318 int getX() const { return fDevice->getOrigin().x(); } 319 int getY() const { return fDevice->getOrigin().y(); } 320 const SkMatrix& getMatrix() const { return *fMatrix; } 321 const SkRegion& getClip() const { return *fClip; } 322 const SkPaint* getPaint() const { return fPaint; } 323 324private: 325 SkCanvas* fCanvas; 326 const DeviceCM* fCurrLayer; 327 const SkPaint* fPaint; // May be null. 328 SkBool8 fSkipEmptyClips; 329 330 typedef SkDraw INHERITED; 331}; 332 333///////////////////////////////////////////////////////////////////////////// 334 335class AutoDrawLooper { 336public: 337 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, 338 bool skipLayerForImageFilter = false, 339 const SkRect* bounds = NULL) : fOrigPaint(paint) { 340 fCanvas = canvas; 341 fFilter = canvas->getDrawFilter(); 342 fPaint = NULL; 343 fSaveCount = canvas->getSaveCount(); 344 fDoClearImageFilter = false; 345 fDone = false; 346 347 if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) { 348 SkPaint tmp; 349 tmp.setImageFilter(fOrigPaint.getImageFilter()); 350 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag, 351 true, SkCanvas::kFullLayer_SaveLayerStrategy); 352 // we'll clear the imageFilter for the actual draws in next(), so 353 // it will only be applied during the restore(). 354 fDoClearImageFilter = true; 355 } 356 357 if (SkDrawLooper* looper = paint.getLooper()) { 358 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>( 359 looper->contextSize()); 360 fLooperContext = looper->createContext(canvas, buffer); 361 fIsSimple = false; 362 } else { 363 fLooperContext = NULL; 364 // can we be marked as simple? 365 fIsSimple = !fFilter && !fDoClearImageFilter; 366 } 367 } 368 369 ~AutoDrawLooper() { 370 if (fDoClearImageFilter) { 371 fCanvas->internalRestore(); 372 } 373 SkASSERT(fCanvas->getSaveCount() == fSaveCount); 374 } 375 376 const SkPaint& paint() const { 377 SkASSERT(fPaint); 378 return *fPaint; 379 } 380 381 bool next(SkDrawFilter::Type drawType) { 382 if (fDone) { 383 return false; 384 } else if (fIsSimple) { 385 fDone = true; 386 fPaint = &fOrigPaint; 387 return !fPaint->nothingToDraw(); 388 } else { 389 return this->doNext(drawType); 390 } 391 } 392 393private: 394 SkLazyPaint fLazyPaint; 395 SkCanvas* fCanvas; 396 const SkPaint& fOrigPaint; 397 SkDrawFilter* fFilter; 398 const SkPaint* fPaint; 399 int fSaveCount; 400 bool fDoClearImageFilter; 401 bool fDone; 402 bool fIsSimple; 403 SkDrawLooper::Context* fLooperContext; 404 SkSmallAllocator<1, 32> fLooperContextAllocator; 405 406 bool doNext(SkDrawFilter::Type drawType); 407}; 408 409bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) { 410 fPaint = NULL; 411 SkASSERT(!fIsSimple); 412 SkASSERT(fLooperContext || fFilter || fDoClearImageFilter); 413 414 SkPaint* paint = fLazyPaint.set(fOrigPaint); 415 416 if (fDoClearImageFilter) { 417 paint->setImageFilter(NULL); 418 } 419 420 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) { 421 fDone = true; 422 return false; 423 } 424 if (fFilter) { 425 if (!fFilter->filter(paint, drawType)) { 426 fDone = true; 427 return false; 428 } 429 if (NULL == fLooperContext) { 430 // no looper means we only draw once 431 fDone = true; 432 } 433 } 434 fPaint = paint; 435 436 // if we only came in here for the imagefilter, mark us as done 437 if (!fLooperContext && !fFilter) { 438 fDone = true; 439 } 440 441 // call this after any possible paint modifiers 442 if (fPaint->nothingToDraw()) { 443 fPaint = NULL; 444 return false; 445 } 446 return true; 447} 448 449/* Stack helper for managing a SkBounder. In the destructor, if we were 450 given a bounder, we call its commit() method, signifying that we are 451 done accumulating bounds for that draw. 452*/ 453class SkAutoBounderCommit { 454public: 455 SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {} 456 ~SkAutoBounderCommit() { 457 if (NULL != fBounder) { 458 fBounder->commit(); 459 } 460 } 461private: 462 SkBounder* fBounder; 463}; 464#define SkAutoBounderCommit(...) SK_REQUIRE_LOCAL_VAR(SkAutoBounderCommit) 465 466#include "SkColorPriv.h" 467 468////////// macros to place around the internal draw calls ////////////////// 469 470#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \ 471 this->predrawNotify(); \ 472 AutoDrawLooper looper(this, paint, true); \ 473 while (looper.next(type)) { \ 474 SkAutoBounderCommit ac(fBounder); \ 475 SkDrawIter iter(this); 476 477#define LOOPER_BEGIN(paint, type, bounds) \ 478 this->predrawNotify(); \ 479 AutoDrawLooper looper(this, paint, false, bounds); \ 480 while (looper.next(type)) { \ 481 SkAutoBounderCommit ac(fBounder); \ 482 SkDrawIter iter(this); 483 484#define LOOPER_END } 485 486//////////////////////////////////////////////////////////////////////////// 487 488SkBaseDevice* SkCanvas::init(SkBaseDevice* device) { 489 fBounder = NULL; 490 fCachedLocalClipBounds.setEmpty(); 491 fCachedLocalClipBoundsDirty = true; 492 fAllowSoftClip = true; 493 fAllowSimplifyClip = false; 494 fDeviceCMDirty = false; 495 fSaveLayerCount = 0; 496 fCullCount = 0; 497 fMetaData = NULL; 498 499 fMCRec = (MCRec*)fMCStack.push_back(); 500 new (fMCRec) MCRec(NULL, 0); 501 502 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL)); 503 fMCRec->fTopLayer = fMCRec->fLayer; 504 505 fSurfaceBase = NULL; 506 507 return this->setRootDevice(device); 508} 509 510SkCanvas::SkCanvas() 511 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 512{ 513 inc_canvas(); 514 515 this->init(NULL); 516} 517 518SkCanvas::SkCanvas(int width, int height) 519 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 520{ 521 inc_canvas(); 522 523 SkBitmap bitmap; 524 bitmap.setConfig(SkImageInfo::MakeUnknown(width, height)); 525 this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref(); 526} 527 528SkCanvas::SkCanvas(SkBaseDevice* device) 529 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 530{ 531 inc_canvas(); 532 533 this->init(device); 534} 535 536SkCanvas::SkCanvas(const SkBitmap& bitmap) 537 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 538{ 539 inc_canvas(); 540 541 this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref(); 542} 543 544SkCanvas::~SkCanvas() { 545 // free up the contents of our deque 546 this->restoreToCount(1); // restore everything but the last 547 SkASSERT(0 == fSaveLayerCount); 548 549 this->internalRestore(); // restore the last, since we're going away 550 551 SkSafeUnref(fBounder); 552 SkDELETE(fMetaData); 553 554 dec_canvas(); 555} 556 557SkBounder* SkCanvas::setBounder(SkBounder* bounder) { 558 SkRefCnt_SafeAssign(fBounder, bounder); 559 return bounder; 560} 561 562SkDrawFilter* SkCanvas::getDrawFilter() const { 563 return fMCRec->fFilter; 564} 565 566SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) { 567 SkRefCnt_SafeAssign(fMCRec->fFilter, filter); 568 return filter; 569} 570 571SkMetaData& SkCanvas::getMetaData() { 572 // metadata users are rare, so we lazily allocate it. If that changes we 573 // can decide to just make it a field in the device (rather than a ptr) 574 if (NULL == fMetaData) { 575 fMetaData = new SkMetaData; 576 } 577 return *fMetaData; 578} 579 580/////////////////////////////////////////////////////////////////////////////// 581 582void SkCanvas::flush() { 583 SkBaseDevice* device = this->getDevice(); 584 if (device) { 585 device->flush(); 586 } 587} 588 589SkISize SkCanvas::getTopLayerSize() const { 590 SkBaseDevice* d = this->getTopDevice(); 591 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0); 592} 593 594SkIPoint SkCanvas::getTopLayerOrigin() const { 595 SkBaseDevice* d = this->getTopDevice(); 596 return d ? d->getOrigin() : SkIPoint::Make(0, 0); 597} 598 599SkISize SkCanvas::getBaseLayerSize() const { 600 SkBaseDevice* d = this->getDevice(); 601 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0); 602} 603 604SkBaseDevice* SkCanvas::getDevice() const { 605 // return root device 606 MCRec* rec = (MCRec*) fMCStack.front(); 607 SkASSERT(rec && rec->fLayer); 608 return rec->fLayer->fDevice; 609} 610 611SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const { 612 if (updateMatrixClip) { 613 const_cast<SkCanvas*>(this)->updateDeviceCMCache(); 614 } 615 return fMCRec->fTopLayer->fDevice; 616} 617 618SkBaseDevice* SkCanvas::setRootDevice(SkBaseDevice* device) { 619 // return root device 620 SkDeque::F2BIter iter(fMCStack); 621 MCRec* rec = (MCRec*)iter.next(); 622 SkASSERT(rec && rec->fLayer); 623 SkBaseDevice* rootDevice = rec->fLayer->fDevice; 624 625 if (rootDevice == device) { 626 return device; 627 } 628 629 if (device) { 630 device->onAttachToCanvas(this); 631 } 632 if (rootDevice) { 633 rootDevice->onDetachFromCanvas(); 634 } 635 636 SkRefCnt_SafeAssign(rec->fLayer->fDevice, device); 637 rootDevice = device; 638 639 fDeviceCMDirty = true; 640 641 /* Now we update our initial region to have the bounds of the new device, 642 and then intersect all of the clips in our stack with these bounds, 643 to ensure that we can't draw outside of the device's bounds (and trash 644 memory). 645 646 NOTE: this is only a partial-fix, since if the new device is larger than 647 the previous one, we don't know how to "enlarge" the clips in our stack, 648 so drawing may be artificially restricted. Without keeping a history of 649 all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly 650 reconstruct the correct clips, so this approximation will have to do. 651 The caller really needs to restore() back to the base if they want to 652 accurately take advantage of the new device bounds. 653 */ 654 655 SkIRect bounds; 656 if (device) { 657 bounds.set(0, 0, device->width(), device->height()); 658 } else { 659 bounds.setEmpty(); 660 } 661 // now jam our 1st clip to be bounds, and intersect the rest with that 662 rec->fRasterClip->setRect(bounds); 663 while ((rec = (MCRec*)iter.next()) != NULL) { 664 (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op); 665 } 666 667 return device; 668} 669 670bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) { 671 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) { 672 return false; 673 } 674 675 bool weAllocated = false; 676 if (NULL == bitmap->pixelRef()) { 677 if (!bitmap->allocPixels()) { 678 return false; 679 } 680 weAllocated = true; 681 } 682 683 SkBitmap bm(*bitmap); 684 bm.lockPixels(); 685 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) { 686 return true; 687 } 688 689 if (weAllocated) { 690 bitmap->setPixelRef(NULL); 691 } 692 return false; 693} 694 695bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) { 696 SkIRect r = srcRect; 697 const SkISize size = this->getBaseLayerSize(); 698 if (!r.intersect(0, 0, size.width(), size.height())) { 699 bitmap->reset(); 700 return false; 701 } 702 703 if (!bitmap->allocN32Pixels(r.width(), r.height())) { 704 // bitmap will already be reset. 705 return false; 706 } 707 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) { 708 bitmap->reset(); 709 return false; 710 } 711 return true; 712} 713 714bool SkCanvas::readPixels(const SkImageInfo& origInfo, void* dstP, size_t rowBytes, int x, int y) { 715 switch (origInfo.colorType()) { 716 case kUnknown_SkColorType: 717 case kIndex_8_SkColorType: 718 return false; 719 default: 720 break; 721 } 722 if (NULL == dstP || rowBytes < origInfo.minRowBytes()) { 723 return false; 724 } 725 if (0 == origInfo.width() || 0 == origInfo.height()) { 726 return false; 727 } 728 729 SkBaseDevice* device = this->getDevice(); 730 if (!device) { 731 return false; 732 } 733 734 const SkISize size = this->getBaseLayerSize(); 735 SkIRect srcR = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height()); 736 if (!srcR.intersect(0, 0, size.width(), size.height())) { 737 return false; 738 } 739 740 SkImageInfo info = origInfo; 741 // the intersect may have shrunk info's logical size 742 info.fWidth = srcR.width(); 743 info.fHeight = srcR.height(); 744 745 // if x or y are negative, then we have to adjust pixels 746 if (x > 0) { 747 x = 0; 748 } 749 if (y > 0) { 750 y = 0; 751 } 752 // here x,y are either 0 or negative 753 dstP = ((char*)dstP - y * rowBytes - x * info.bytesPerPixel()); 754 755 // The device can assert that the requested area is always contained in its bounds 756 return device->readPixels(info, dstP, rowBytes, srcR.x(), srcR.y()); 757} 758 759bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) { 760 if (bitmap.getTexture()) { 761 return false; 762 } 763 SkBitmap bm(bitmap); 764 bm.lockPixels(); 765 if (bm.getPixels()) { 766 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y); 767 } 768 return false; 769} 770 771bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes, 772 int x, int y) { 773 switch (origInfo.colorType()) { 774 case kUnknown_SkColorType: 775 case kIndex_8_SkColorType: 776 return false; 777 default: 778 break; 779 } 780 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) { 781 return false; 782 } 783 784 const SkISize size = this->getBaseLayerSize(); 785 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height()); 786 if (!target.intersect(0, 0, size.width(), size.height())) { 787 return false; 788 } 789 790 SkBaseDevice* device = this->getDevice(); 791 if (!device) { 792 return false; 793 } 794 795 SkImageInfo info = origInfo; 796 // the intersect may have shrunk info's logical size 797 info.fWidth = target.width(); 798 info.fHeight = target.height(); 799 800 // if x or y are negative, then we have to adjust pixels 801 if (x > 0) { 802 x = 0; 803 } 804 if (y > 0) { 805 y = 0; 806 } 807 // here x,y are either 0 or negative 808 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel()); 809 810 // The device can assert that the requested area is always contained in its bounds 811 return device->writePixels(info, pixels, rowBytes, target.x(), target.y()); 812} 813 814SkCanvas* SkCanvas::canvasForDrawIter() { 815 return this; 816} 817 818////////////////////////////////////////////////////////////////////////////// 819 820void SkCanvas::updateDeviceCMCache() { 821 if (fDeviceCMDirty) { 822 const SkMatrix& totalMatrix = this->getTotalMatrix(); 823 const SkRasterClip& totalClip = *fMCRec->fRasterClip; 824 DeviceCM* layer = fMCRec->fTopLayer; 825 826 if (NULL == layer->fNext) { // only one layer 827 layer->updateMC(totalMatrix, totalClip, fClipStack, NULL); 828 } else { 829 SkRasterClip clip(totalClip); 830 do { 831 layer->updateMC(totalMatrix, clip, fClipStack, &clip); 832 } while ((layer = layer->fNext) != NULL); 833 } 834 fDeviceCMDirty = false; 835 } 836} 837 838/////////////////////////////////////////////////////////////////////////////// 839 840int SkCanvas::internalSave(SaveFlags flags) { 841 int saveCount = this->getSaveCount(); // record this before the actual save 842 843 MCRec* newTop = (MCRec*)fMCStack.push_back(); 844 new (newTop) MCRec(fMCRec, flags); // balanced in restore() 845 846 fMCRec = newTop; 847 848 if (SkCanvas::kClip_SaveFlag & flags) { 849 fClipStack.save(); 850 } 851 852 return saveCount; 853} 854 855void SkCanvas::willSave(SaveFlags) { 856 // Do nothing. Subclasses may do something. 857} 858 859int SkCanvas::save(SaveFlags flags) { 860 this->willSave(flags); 861 // call shared impl 862 return this->internalSave(flags); 863} 864 865static bool bounds_affects_clip(SkCanvas::SaveFlags flags) { 866#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG 867 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0; 868#else 869 return true; 870#endif 871} 872 873bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, 874 SkIRect* intersection, const SkImageFilter* imageFilter) { 875 SkIRect clipBounds; 876 SkRegion::Op op = SkRegion::kIntersect_Op; 877 if (!this->getClipDeviceBounds(&clipBounds)) { 878 return false; 879 } 880 881 if (imageFilter) { 882 imageFilter->filterBounds(clipBounds, *fMCRec->fMatrix, &clipBounds); 883 // Filters may grow the bounds beyond the device bounds. 884 op = SkRegion::kReplace_Op; 885 } 886 SkIRect ir; 887 if (NULL != bounds) { 888 SkRect r; 889 890 this->getTotalMatrix().mapRect(&r, *bounds); 891 r.roundOut(&ir); 892 // early exit if the layer's bounds are clipped out 893 if (!ir.intersect(clipBounds)) { 894 if (bounds_affects_clip(flags)) { 895 fMCRec->fRasterClip->setEmpty(); 896 } 897 return false; 898 } 899 } else { // no user bounds, so just use the clip 900 ir = clipBounds; 901 } 902 903 if (bounds_affects_clip(flags)) { 904 fClipStack.clipDevRect(ir, op); 905 // early exit if the clip is now empty 906 if (!fMCRec->fRasterClip->op(ir, op)) { 907 return false; 908 } 909 } 910 911 if (intersection) { 912 *intersection = ir; 913 } 914 return true; 915} 916 917SkCanvas::SaveLayerStrategy SkCanvas::willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) { 918 919 // Do nothing. Subclasses may do something. 920 return kFullLayer_SaveLayerStrategy; 921} 922 923int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, 924 SaveFlags flags) { 925 // Overriding classes may return false to signal that we don't need to create a layer. 926 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags); 927 return this->internalSaveLayer(bounds, paint, flags, false, strategy); 928} 929 930static SkBaseDevice* create_compatible_device(SkCanvas* canvas, 931 const SkImageInfo& info) { 932 SkBaseDevice* device = canvas->getDevice(); 933 return device ? device->createCompatibleDevice(info) : NULL; 934} 935 936int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags, 937 bool justForImageFilter, SaveLayerStrategy strategy) { 938#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG 939 flags = (SaveFlags)(flags | kClipToLayer_SaveFlag); 940#endif 941 942 // do this before we create the layer. We don't call the public save() since 943 // that would invoke a possibly overridden virtual 944 int count = this->internalSave(flags); 945 946 fDeviceCMDirty = true; 947 948 SkIRect ir; 949 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) { 950 return count; 951 } 952 953 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about 954 // the clipRectBounds() call above? 955 if (kNoLayer_SaveLayerStrategy == strategy) { 956 return count; 957 } 958 959 // Kill the imagefilter if our device doesn't allow it 960 SkLazyPaint lazyP; 961 if (paint && paint->getImageFilter()) { 962 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) { 963 if (justForImageFilter) { 964 // early exit if the layer was just for the imageFilter 965 return count; 966 } 967 SkPaint* p = lazyP.set(*paint); 968 p->setImageFilter(NULL); 969 paint = p; 970 } 971 } 972 973 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag); 974 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(), 975 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); 976 977 SkBaseDevice* device; 978 if (paint && paint->getImageFilter()) { 979 device = create_compatible_device(this, info); 980 } else { 981 device = this->createLayerDevice(info); 982 } 983 if (NULL == device) { 984 SkDebugf("Unable to create device for layer."); 985 return count; 986 } 987 988 device->setOrigin(ir.fLeft, ir.fTop); 989 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint, this)); 990 device->unref(); 991 992 layer->fNext = fMCRec->fTopLayer; 993 fMCRec->fLayer = layer; 994 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer 995 996 fSaveLayerCount += 1; 997 return count; 998} 999 1000int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha, 1001 SaveFlags flags) { 1002 if (0xFF == alpha) { 1003 return this->saveLayer(bounds, NULL, flags); 1004 } else { 1005 SkPaint tmpPaint; 1006 tmpPaint.setAlpha(alpha); 1007 return this->saveLayer(bounds, &tmpPaint, flags); 1008 } 1009} 1010 1011void SkCanvas::willRestore() { 1012 // Do nothing. Subclasses may do something. 1013} 1014 1015void SkCanvas::restore() { 1016 // check for underflow 1017 if (fMCStack.count() > 1) { 1018 this->willRestore(); 1019 this->internalRestore(); 1020 } 1021} 1022 1023void SkCanvas::internalRestore() { 1024 SkASSERT(fMCStack.count() != 0); 1025 1026 fDeviceCMDirty = true; 1027 fCachedLocalClipBoundsDirty = true; 1028 1029 if (SkCanvas::kClip_SaveFlag & fMCRec->fFlags) { 1030 fClipStack.restore(); 1031 } 1032 1033 // reserve our layer (if any) 1034 DeviceCM* layer = fMCRec->fLayer; // may be null 1035 // now detach it from fMCRec so we can pop(). Gets freed after its drawn 1036 fMCRec->fLayer = NULL; 1037 1038 // now do the normal restore() 1039 fMCRec->~MCRec(); // balanced in save() 1040 fMCStack.pop_back(); 1041 fMCRec = (MCRec*)fMCStack.back(); 1042 1043 /* Time to draw the layer's offscreen. We can't call the public drawSprite, 1044 since if we're being recorded, we don't want to record this (the 1045 recorder will have already recorded the restore). 1046 */ 1047 if (NULL != layer) { 1048 if (layer->fNext) { 1049 const SkIPoint& origin = layer->fDevice->getOrigin(); 1050 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), 1051 layer->fPaint); 1052 // reset this, since internalDrawDevice will have set it to true 1053 fDeviceCMDirty = true; 1054 1055 SkASSERT(fSaveLayerCount > 0); 1056 fSaveLayerCount -= 1; 1057 } 1058 SkDELETE(layer); 1059 } 1060} 1061 1062int SkCanvas::getSaveCount() const { 1063 return fMCStack.count(); 1064} 1065 1066void SkCanvas::restoreToCount(int count) { 1067 // sanity check 1068 if (count < 1) { 1069 count = 1; 1070 } 1071 1072 int n = this->getSaveCount() - count; 1073 for (int i = 0; i < n; ++i) { 1074 this->restore(); 1075 } 1076} 1077 1078bool SkCanvas::isDrawingToLayer() const { 1079 return fSaveLayerCount > 0; 1080} 1081 1082SkSurface* SkCanvas::newSurface(const SkImageInfo& info) { 1083 return this->onNewSurface(info); 1084} 1085 1086SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info) { 1087 SkBaseDevice* dev = this->getDevice(); 1088 return dev ? dev->newSurface(info) : NULL; 1089} 1090 1091SkImageInfo SkCanvas::imageInfo() const { 1092 SkBaseDevice* dev = this->getDevice(); 1093 if (dev) { 1094 return dev->imageInfo(); 1095 } else { 1096 return SkImageInfo::MakeUnknown(0, 0); 1097 } 1098} 1099 1100const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) { 1101 return this->onPeekPixels(info, rowBytes); 1102} 1103 1104const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) { 1105 SkBaseDevice* dev = this->getDevice(); 1106 return dev ? dev->peekPixels(info, rowBytes) : NULL; 1107} 1108 1109void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) { 1110 return this->onAccessTopLayerPixels(info, rowBytes); 1111} 1112 1113void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) { 1114 SkBaseDevice* dev = this->getTopDevice(); 1115 return dev ? dev->accessPixels(info, rowBytes) : NULL; 1116} 1117 1118SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) { 1119 fAddr = canvas->peekPixels(&fInfo, &fRowBytes); 1120 if (NULL == fAddr) { 1121 fInfo = canvas->imageInfo(); 1122 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.allocPixels(fInfo)) { 1123 return; // failure, fAddr is NULL 1124 } 1125 if (!canvas->readPixels(&fBitmap, 0, 0)) { 1126 return; // failure, fAddr is NULL 1127 } 1128 fAddr = fBitmap.getPixels(); 1129 fRowBytes = fBitmap.rowBytes(); 1130 } 1131 SkASSERT(fAddr); // success 1132} 1133 1134bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const { 1135 if (fAddr) { 1136 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes, 1137 NULL, NULL); 1138 } else { 1139 bitmap->reset(); 1140 return false; 1141 } 1142} 1143 1144void SkCanvas::onPushCull(const SkRect& cullRect) { 1145 // do nothing. Subclasses may do something 1146} 1147 1148void SkCanvas::onPopCull() { 1149 // do nothing. Subclasses may do something 1150} 1151 1152///////////////////////////////////////////////////////////////////////////// 1153#ifdef SK_DEBUG 1154// Ensure that cull rects are monotonically nested in device space. 1155void SkCanvas::validateCull(const SkIRect& devCull) { 1156 if (fCullStack.isEmpty() 1157 || devCull.isEmpty() 1158 || fCullStack.top().contains(devCull)) { 1159 return; 1160 } 1161 1162 SkDEBUGF(("Invalid cull: [%d %d %d %d] (previous cull: [%d %d %d %d])\n", 1163 devCull.x(), devCull.y(), devCull.right(), devCull.bottom(), 1164 fCullStack.top().x(), fCullStack.top().y(), 1165 fCullStack.top().right(), fCullStack.top().bottom())); 1166 1167#ifdef ASSERT_NESTED_CULLING 1168 SkDEBUGFAIL("Invalid cull."); 1169#endif 1170} 1171#endif 1172 1173void SkCanvas::pushCull(const SkRect& cullRect) { 1174 ++fCullCount; 1175 this->onPushCull(cullRect); 1176 1177#ifdef SK_DEBUG 1178 // Map the cull rect into device space. 1179 SkRect mappedCull; 1180 this->getTotalMatrix().mapRect(&mappedCull, cullRect); 1181 1182 // Take clipping into account. 1183 SkIRect devClip, devCull; 1184 mappedCull.roundOut(&devCull); 1185 this->getClipDeviceBounds(&devClip); 1186 if (!devCull.intersect(devClip)) { 1187 devCull.setEmpty(); 1188 } 1189 1190 this->validateCull(devCull); 1191 fCullStack.push(devCull); // balanced in popCull 1192#endif 1193} 1194 1195void SkCanvas::popCull() { 1196 SkASSERT(fCullStack.count() == fCullCount); 1197 1198 if (fCullCount > 0) { 1199 --fCullCount; 1200 this->onPopCull(); 1201 1202 SkDEBUGCODE(fCullStack.pop()); 1203 } 1204} 1205 1206///////////////////////////////////////////////////////////////////////////// 1207 1208void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, 1209 const SkMatrix& matrix, const SkPaint* paint) { 1210 if (bitmap.drawsNothing()) { 1211 return; 1212 } 1213 1214 SkLazyPaint lazy; 1215 if (NULL == paint) { 1216 paint = lazy.init(); 1217 } 1218 1219 SkDEBUGCODE(bitmap.validate();) 1220 CHECK_LOCKCOUNT_BALANCE(bitmap); 1221 1222 SkRect storage; 1223 const SkRect* bounds = NULL; 1224 if (paint && paint->canComputeFastBounds()) { 1225 bitmap.getBounds(&storage); 1226 matrix.mapRect(&storage); 1227 bounds = &paint->computeFastBounds(storage, &storage); 1228 } 1229 1230 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) 1231 1232 while (iter.next()) { 1233 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint()); 1234 } 1235 1236 LOOPER_END 1237} 1238 1239void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, 1240 const SkPaint* paint) { 1241 SkPaint tmp; 1242 if (NULL == paint) { 1243 tmp.setDither(true); 1244 paint = &tmp; 1245 } 1246 1247 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 1248 while (iter.next()) { 1249 SkBaseDevice* dstDev = iter.fDevice; 1250 paint = &looper.paint(); 1251 SkImageFilter* filter = paint->getImageFilter(); 1252 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 1253 if (filter && !dstDev->canHandleImageFilter(filter)) { 1254 SkDeviceImageFilterProxy proxy(dstDev); 1255 SkBitmap dst; 1256 SkIPoint offset = SkIPoint::Make(0, 0); 1257 const SkBitmap& src = srcDev->accessBitmap(false); 1258 SkMatrix matrix = *iter.fMatrix; 1259 matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); 1260 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height()); 1261 SkImageFilter::Context ctx(matrix, clipBounds); 1262 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) { 1263 SkPaint tmpUnfiltered(*paint); 1264 tmpUnfiltered.setImageFilter(NULL); 1265 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(), 1266 tmpUnfiltered); 1267 } 1268 } else { 1269 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint); 1270 } 1271 } 1272 LOOPER_END 1273} 1274 1275void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, 1276 const SkPaint* paint) { 1277 if (bitmap.drawsNothing()) { 1278 return; 1279 } 1280 SkDEBUGCODE(bitmap.validate();) 1281 CHECK_LOCKCOUNT_BALANCE(bitmap); 1282 1283 SkPaint tmp; 1284 if (NULL == paint) { 1285 paint = &tmp; 1286 } 1287 1288 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 1289 1290 while (iter.next()) { 1291 paint = &looper.paint(); 1292 SkImageFilter* filter = paint->getImageFilter(); 1293 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 1294 if (filter && !iter.fDevice->canHandleImageFilter(filter)) { 1295 SkDeviceImageFilterProxy proxy(iter.fDevice); 1296 SkBitmap dst; 1297 SkIPoint offset = SkIPoint::Make(0, 0); 1298 SkMatrix matrix = *iter.fMatrix; 1299 matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); 1300 SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height()); 1301 SkImageFilter::Context ctx(matrix, clipBounds); 1302 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) { 1303 SkPaint tmpUnfiltered(*paint); 1304 tmpUnfiltered.setImageFilter(NULL); 1305 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(), 1306 tmpUnfiltered); 1307 } 1308 } else { 1309 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint); 1310 } 1311 } 1312 LOOPER_END 1313} 1314 1315///////////////////////////////////////////////////////////////////////////// 1316void SkCanvas::translate(SkScalar dx, SkScalar dy) { 1317 SkMatrix m; 1318 m.setTranslate(dx, dy); 1319 this->concat(m); 1320} 1321 1322void SkCanvas::scale(SkScalar sx, SkScalar sy) { 1323 SkMatrix m; 1324 m.setScale(sx, sy); 1325 this->concat(m); 1326} 1327 1328void SkCanvas::rotate(SkScalar degrees) { 1329 SkMatrix m; 1330 m.setRotate(degrees); 1331 this->concat(m); 1332} 1333 1334void SkCanvas::skew(SkScalar sx, SkScalar sy) { 1335 SkMatrix m; 1336 m.setSkew(sx, sy); 1337 this->concat(m); 1338} 1339 1340void SkCanvas::didConcat(const SkMatrix&) { 1341 // Do nothing. Subclasses may do something. 1342} 1343 1344void SkCanvas::concat(const SkMatrix& matrix) { 1345 if (matrix.isIdentity()) { 1346 return; 1347 } 1348 1349 fDeviceCMDirty = true; 1350 fCachedLocalClipBoundsDirty = true; 1351 fMCRec->fMatrix->preConcat(matrix); 1352 1353 this->didConcat(matrix); 1354} 1355 1356void SkCanvas::didSetMatrix(const SkMatrix&) { 1357 // Do nothing. Subclasses may do something. 1358} 1359 1360void SkCanvas::setMatrix(const SkMatrix& matrix) { 1361 fDeviceCMDirty = true; 1362 fCachedLocalClipBoundsDirty = true; 1363 *fMCRec->fMatrix = matrix; 1364 this->didSetMatrix(matrix); 1365} 1366 1367void SkCanvas::resetMatrix() { 1368 SkMatrix matrix; 1369 1370 matrix.reset(); 1371 this->setMatrix(matrix); 1372} 1373 1374////////////////////////////////////////////////////////////////////////////// 1375 1376void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 1377 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1378 this->onClipRect(rect, op, edgeStyle); 1379} 1380 1381void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1382#ifdef SK_ENABLE_CLIP_QUICKREJECT 1383 if (SkRegion::kIntersect_Op == op) { 1384 if (fMCRec->fRasterClip->isEmpty()) { 1385 return false; 1386 } 1387 1388 if (this->quickReject(rect)) { 1389 fDeviceCMDirty = true; 1390 fCachedLocalClipBoundsDirty = true; 1391 1392 fClipStack.clipEmpty(); 1393 return fMCRec->fRasterClip->setEmpty(); 1394 } 1395 } 1396#endif 1397 1398 AutoValidateClip avc(this); 1399 1400 fDeviceCMDirty = true; 1401 fCachedLocalClipBoundsDirty = true; 1402 if (!fAllowSoftClip) { 1403 edgeStyle = kHard_ClipEdgeStyle; 1404 } 1405 1406 if (fMCRec->fMatrix->rectStaysRect()) { 1407 // for these simpler matrices, we can stay a rect even after applying 1408 // the matrix. This means we don't have to a) make a path, and b) tell 1409 // the region code to scan-convert the path, only to discover that it 1410 // is really just a rect. 1411 SkRect r; 1412 1413 fMCRec->fMatrix->mapRect(&r, rect); 1414 fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle); 1415 fMCRec->fRasterClip->op(r, op, kSoft_ClipEdgeStyle == edgeStyle); 1416 } else { 1417 // since we're rotated or some such thing, we convert the rect to a path 1418 // and clip against that, since it can handle any matrix. However, to 1419 // avoid recursion in the case where we are subclassed (e.g. Pictures) 1420 // we explicitly call "our" version of clipPath. 1421 SkPath path; 1422 1423 path.addRect(rect); 1424 this->SkCanvas::onClipPath(path, op, edgeStyle); 1425 } 1426} 1427 1428static void clip_path_helper(const SkCanvas* canvas, SkRasterClip* currClip, 1429 const SkPath& devPath, SkRegion::Op op, bool doAA) { 1430 // base is used to limit the size (and therefore memory allocation) of the 1431 // region that results from scan converting devPath. 1432 SkRegion base; 1433 1434 if (SkRegion::kIntersect_Op == op) { 1435 // since we are intersect, we can do better (tighter) with currRgn's 1436 // bounds, than just using the device. However, if currRgn is complex, 1437 // our region blitter may hork, so we do that case in two steps. 1438 if (currClip->isRect()) { 1439 // FIXME: we should also be able to do this when currClip->isBW(), 1440 // but relaxing the test above triggers GM asserts in 1441 // SkRgnBuilder::blitH(). We need to investigate what's going on. 1442 currClip->setPath(devPath, currClip->bwRgn(), doAA); 1443 } else { 1444 base.setRect(currClip->getBounds()); 1445 SkRasterClip clip; 1446 clip.setPath(devPath, base, doAA); 1447 currClip->op(clip, op); 1448 } 1449 } else { 1450 const SkBaseDevice* device = canvas->getDevice(); 1451 if (!device) { 1452 currClip->setEmpty(); 1453 return; 1454 } 1455 1456 base.setRect(0, 0, device->width(), device->height()); 1457 1458 if (SkRegion::kReplace_Op == op) { 1459 currClip->setPath(devPath, base, doAA); 1460 } else { 1461 SkRasterClip clip; 1462 clip.setPath(devPath, base, doAA); 1463 currClip->op(clip, op); 1464 } 1465 } 1466} 1467 1468void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 1469 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1470 if (rrect.isRect()) { 1471 this->onClipRect(rrect.getBounds(), op, edgeStyle); 1472 } else { 1473 this->onClipRRect(rrect, op, edgeStyle); 1474 } 1475} 1476 1477void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1478 SkRRect transformedRRect; 1479 if (rrect.transform(*fMCRec->fMatrix, &transformedRRect)) { 1480 AutoValidateClip avc(this); 1481 1482 fDeviceCMDirty = true; 1483 fCachedLocalClipBoundsDirty = true; 1484 if (!fAllowSoftClip) { 1485 edgeStyle = kHard_ClipEdgeStyle; 1486 } 1487 1488 fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle); 1489 1490 SkPath devPath; 1491 devPath.addRRect(transformedRRect); 1492 1493 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, kSoft_ClipEdgeStyle == edgeStyle); 1494 return; 1495 } 1496 1497 SkPath path; 1498 path.addRRect(rrect); 1499 // call the non-virtual version 1500 this->SkCanvas::onClipPath(path, op, edgeStyle); 1501} 1502 1503void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 1504 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1505 SkRect r; 1506 if (!path.isInverseFillType() && path.isRect(&r)) { 1507 this->onClipRect(r, op, edgeStyle); 1508 } else { 1509 this->onClipPath(path, op, edgeStyle); 1510 } 1511} 1512 1513void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1514#ifdef SK_ENABLE_CLIP_QUICKREJECT 1515 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { 1516 if (fMCRec->fRasterClip->isEmpty()) { 1517 return false; 1518 } 1519 1520 if (this->quickReject(path.getBounds())) { 1521 fDeviceCMDirty = true; 1522 fCachedLocalClipBoundsDirty = true; 1523 1524 fClipStack.clipEmpty(); 1525 return fMCRec->fRasterClip->setEmpty(); 1526 } 1527 } 1528#endif 1529 1530 AutoValidateClip avc(this); 1531 1532 fDeviceCMDirty = true; 1533 fCachedLocalClipBoundsDirty = true; 1534 if (!fAllowSoftClip) { 1535 edgeStyle = kHard_ClipEdgeStyle; 1536 } 1537 1538 SkPath devPath; 1539 path.transform(*fMCRec->fMatrix, &devPath); 1540 1541 // Check if the transfomation, or the original path itself 1542 // made us empty. Note this can also happen if we contained NaN 1543 // values. computing the bounds detects this, and will set our 1544 // bounds to empty if that is the case. (see SkRect::set(pts, count)) 1545 if (devPath.getBounds().isEmpty()) { 1546 // resetting the path will remove any NaN or other wanky values 1547 // that might upset our scan converter. 1548 devPath.reset(); 1549 } 1550 1551 // if we called path.swap() we could avoid a deep copy of this path 1552 fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle); 1553 1554 if (fAllowSimplifyClip) { 1555 devPath.reset(); 1556 devPath.setFillType(SkPath::kInverseEvenOdd_FillType); 1557 const SkClipStack* clipStack = getClipStack(); 1558 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart); 1559 const SkClipStack::Element* element; 1560 while ((element = iter.next())) { 1561 SkClipStack::Element::Type type = element->getType(); 1562 if (type == SkClipStack::Element::kEmpty_Type) { 1563 continue; 1564 } 1565 SkPath operand; 1566 element->asPath(&operand); 1567 SkRegion::Op elementOp = element->getOp(); 1568 if (elementOp == SkRegion::kReplace_Op) { 1569 devPath = operand; 1570 } else { 1571 Op(devPath, operand, (SkPathOp) elementOp, &devPath); 1572 } 1573 // if the prev and curr clips disagree about aa -vs- not, favor the aa request. 1574 // perhaps we need an API change to avoid this sort of mixed-signals about 1575 // clipping. 1576 if (element->isAA()) { 1577 edgeStyle = kSoft_ClipEdgeStyle; 1578 } 1579 } 1580 op = SkRegion::kReplace_Op; 1581 } 1582 1583 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, edgeStyle); 1584} 1585 1586void SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op, 1587 bool inverseFilled) { 1588 // This is for updating the clip conservatively using only bounds 1589 // information. 1590 // Contract: 1591 // The current clip must contain the true clip. The true 1592 // clip is the clip that would have normally been computed 1593 // by calls to clipPath and clipRRect 1594 // Objective: 1595 // Keep the current clip as small as possible without 1596 // breaking the contract, using only clip bounding rectangles 1597 // (for performance). 1598 1599 // N.B.: This *never* calls back through a virtual on canvas, so subclasses 1600 // don't have to worry about getting caught in a loop. Thus anywhere 1601 // we call a virtual method, we explicitly prefix it with 1602 // SkCanvas:: to be sure to call the base-class. 1603 1604 if (inverseFilled) { 1605 switch (op) { 1606 case SkRegion::kIntersect_Op: 1607 case SkRegion::kDifference_Op: 1608 // These ops can only shrink the current clip. So leaving 1609 // the clip unchanged conservatively respects the contract. 1610 break; 1611 case SkRegion::kUnion_Op: 1612 case SkRegion::kReplace_Op: 1613 case SkRegion::kReverseDifference_Op: 1614 case SkRegion::kXOR_Op: { 1615 // These ops can grow the current clip up to the extents of 1616 // the input clip, which is inverse filled, so we just set 1617 // the current clip to the device bounds. 1618 SkRect deviceBounds; 1619 SkIRect deviceIBounds; 1620 this->getDevice()->getGlobalBounds(&deviceIBounds); 1621 deviceBounds = SkRect::Make(deviceIBounds); 1622 this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag); 1623 // set the clip in device space 1624 this->SkCanvas::setMatrix(SkMatrix::I()); 1625 this->SkCanvas::onClipRect(deviceBounds, SkRegion::kReplace_Op, 1626 kHard_ClipEdgeStyle); 1627 this->SkCanvas::restore(); //pop the matrix, but keep the clip 1628 break; 1629 } 1630 default: 1631 SkASSERT(0); // unhandled op? 1632 } 1633 } else { 1634 // Not inverse filled 1635 switch (op) { 1636 case SkRegion::kIntersect_Op: 1637 case SkRegion::kUnion_Op: 1638 case SkRegion::kReplace_Op: 1639 this->SkCanvas::onClipRect(bounds, op, kHard_ClipEdgeStyle); 1640 break; 1641 case SkRegion::kDifference_Op: 1642 // Difference can only shrink the current clip. 1643 // Leaving clip unchanged conservatively fullfills the contract. 1644 break; 1645 case SkRegion::kReverseDifference_Op: 1646 // To reverse, we swap in the bounds with a replace op. 1647 // As with difference, leave it unchanged. 1648 this->SkCanvas::onClipRect(bounds, SkRegion::kReplace_Op, kHard_ClipEdgeStyle); 1649 break; 1650 case SkRegion::kXOR_Op: 1651 // Be conservative, based on (A XOR B) always included in (A union B), 1652 // which is always included in (bounds(A) union bounds(B)) 1653 this->SkCanvas::onClipRect(bounds, SkRegion::kUnion_Op, kHard_ClipEdgeStyle); 1654 break; 1655 default: 1656 SkASSERT(0); // unhandled op? 1657 } 1658 } 1659} 1660 1661void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1662 this->onClipRegion(rgn, op); 1663} 1664 1665void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { 1666 AutoValidateClip avc(this); 1667 1668 fDeviceCMDirty = true; 1669 fCachedLocalClipBoundsDirty = true; 1670 1671 // todo: signal fClipStack that we have a region, and therefore (I guess) 1672 // we have to ignore it, and use the region directly? 1673 fClipStack.clipDevRect(rgn.getBounds(), op); 1674 1675 fMCRec->fRasterClip->op(rgn, op); 1676} 1677 1678#ifdef SK_DEBUG 1679void SkCanvas::validateClip() const { 1680 // construct clipRgn from the clipstack 1681 const SkBaseDevice* device = this->getDevice(); 1682 if (!device) { 1683 SkASSERT(this->isClipEmpty()); 1684 return; 1685 } 1686 1687 SkIRect ir; 1688 ir.set(0, 0, device->width(), device->height()); 1689 SkRasterClip tmpClip(ir); 1690 1691 SkClipStack::B2TIter iter(fClipStack); 1692 const SkClipStack::Element* element; 1693 while ((element = iter.next()) != NULL) { 1694 switch (element->getType()) { 1695 case SkClipStack::Element::kRect_Type: 1696 element->getRect().round(&ir); 1697 tmpClip.op(ir, element->getOp()); 1698 break; 1699 case SkClipStack::Element::kEmpty_Type: 1700 tmpClip.setEmpty(); 1701 break; 1702 default: { 1703 SkPath path; 1704 element->asPath(&path); 1705 clip_path_helper(this, &tmpClip, path, element->getOp(), element->isAA()); 1706 break; 1707 } 1708 } 1709 } 1710} 1711#endif 1712 1713void SkCanvas::replayClips(ClipVisitor* visitor) const { 1714 SkClipStack::B2TIter iter(fClipStack); 1715 const SkClipStack::Element* element; 1716 1717 static const SkRect kEmpty = { 0, 0, 0, 0 }; 1718 while ((element = iter.next()) != NULL) { 1719 switch (element->getType()) { 1720 case SkClipStack::Element::kPath_Type: 1721 visitor->clipPath(element->getPath(), element->getOp(), element->isAA()); 1722 break; 1723 case SkClipStack::Element::kRRect_Type: 1724 visitor->clipRRect(element->getRRect(), element->getOp(), element->isAA()); 1725 break; 1726 case SkClipStack::Element::kRect_Type: 1727 visitor->clipRect(element->getRect(), element->getOp(), element->isAA()); 1728 break; 1729 case SkClipStack::Element::kEmpty_Type: 1730 visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false); 1731 break; 1732 } 1733 } 1734} 1735 1736/////////////////////////////////////////////////////////////////////////////// 1737 1738bool SkCanvas::isClipEmpty() const { 1739 return fMCRec->fRasterClip->isEmpty(); 1740} 1741 1742bool SkCanvas::isClipRect() const { 1743 return fMCRec->fRasterClip->isRect(); 1744} 1745 1746bool SkCanvas::quickReject(const SkRect& rect) const { 1747 1748 if (!rect.isFinite()) 1749 return true; 1750 1751 if (fMCRec->fRasterClip->isEmpty()) { 1752 return true; 1753 } 1754 1755 if (fMCRec->fMatrix->hasPerspective()) { 1756 SkRect dst; 1757 fMCRec->fMatrix->mapRect(&dst, rect); 1758 SkIRect idst; 1759 dst.roundOut(&idst); 1760 return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds()); 1761 } else { 1762 const SkRect& clipR = this->getLocalClipBounds(); 1763 1764 // for speed, do the most likely reject compares first 1765 // TODO: should we use | instead, or compare all 4 at once? 1766 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) { 1767 return true; 1768 } 1769 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) { 1770 return true; 1771 } 1772 return false; 1773 } 1774} 1775 1776bool SkCanvas::quickReject(const SkPath& path) const { 1777 return path.isEmpty() || this->quickReject(path.getBounds()); 1778} 1779 1780bool SkCanvas::getClipBounds(SkRect* bounds) const { 1781 SkIRect ibounds; 1782 if (!this->getClipDeviceBounds(&ibounds)) { 1783 return false; 1784 } 1785 1786 SkMatrix inverse; 1787 // if we can't invert the CTM, we can't return local clip bounds 1788 if (!fMCRec->fMatrix->invert(&inverse)) { 1789 if (bounds) { 1790 bounds->setEmpty(); 1791 } 1792 return false; 1793 } 1794 1795 if (NULL != bounds) { 1796 SkRect r; 1797 // adjust it outwards in case we are antialiasing 1798 const int inset = 1; 1799 1800 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset, 1801 ibounds.fRight + inset, ibounds.fBottom + inset); 1802 inverse.mapRect(bounds, r); 1803 } 1804 return true; 1805} 1806 1807bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const { 1808 const SkRasterClip& clip = *fMCRec->fRasterClip; 1809 if (clip.isEmpty()) { 1810 if (bounds) { 1811 bounds->setEmpty(); 1812 } 1813 return false; 1814 } 1815 1816 if (NULL != bounds) { 1817 *bounds = clip.getBounds(); 1818 } 1819 return true; 1820} 1821 1822const SkMatrix& SkCanvas::getTotalMatrix() const { 1823 return *fMCRec->fMatrix; 1824} 1825 1826#ifdef SK_SUPPORT_LEGACY_GETCLIPTYPE 1827SkCanvas::ClipType SkCanvas::getClipType() const { 1828 if (fMCRec->fRasterClip->isEmpty()) { 1829 return kEmpty_ClipType; 1830 } 1831 if (fMCRec->fRasterClip->isRect()) { 1832 return kRect_ClipType; 1833 } 1834 return kComplex_ClipType; 1835} 1836#endif 1837 1838#ifdef SK_SUPPORT_LEGACY_GETTOTALCLIP 1839const SkRegion& SkCanvas::getTotalClip() const { 1840 return fMCRec->fRasterClip->forceGetBW(); 1841} 1842#endif 1843 1844const SkRegion& SkCanvas::internal_private_getTotalClip() const { 1845 return fMCRec->fRasterClip->forceGetBW(); 1846} 1847 1848void SkCanvas::internal_private_getTotalClipAsPath(SkPath* path) const { 1849 path->reset(); 1850 1851 const SkRegion& rgn = fMCRec->fRasterClip->forceGetBW(); 1852 if (rgn.isEmpty()) { 1853 return; 1854 } 1855 (void)rgn.getBoundaryPath(path); 1856} 1857 1858GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() { 1859 SkBaseDevice* dev = this->getTopDevice(); 1860 return dev ? dev->accessRenderTarget() : NULL; 1861} 1862 1863SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) { 1864 SkBaseDevice* device = this->getTopDevice(); 1865 return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL; 1866} 1867 1868GrContext* SkCanvas::getGrContext() { 1869#if SK_SUPPORT_GPU 1870 SkBaseDevice* device = this->getTopDevice(); 1871 if (NULL != device) { 1872 GrRenderTarget* renderTarget = device->accessRenderTarget(); 1873 if (NULL != renderTarget) { 1874 return renderTarget->getContext(); 1875 } 1876 } 1877#endif 1878 1879 return NULL; 1880 1881} 1882 1883void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner, 1884 const SkPaint& paint) { 1885 if (outer.isEmpty()) { 1886 return; 1887 } 1888 if (inner.isEmpty()) { 1889 this->drawRRect(outer, paint); 1890 return; 1891 } 1892 1893 // We don't have this method (yet), but technically this is what we should 1894 // be able to assert... 1895 // SkASSERT(outer.contains(inner)); 1896 // 1897 // For now at least check for containment of bounds 1898 SkASSERT(outer.getBounds().contains(inner.getBounds())); 1899 1900 this->onDrawDRRect(outer, inner, paint); 1901} 1902 1903////////////////////////////////////////////////////////////////////////////// 1904// These are the virtual drawing methods 1905////////////////////////////////////////////////////////////////////////////// 1906 1907void SkCanvas::clear(SkColor color) { 1908 SkDrawIter iter(this); 1909 this->predrawNotify(); 1910 while (iter.next()) { 1911 iter.fDevice->clear(color); 1912 } 1913} 1914 1915void SkCanvas::drawPaint(const SkPaint& paint) { 1916 this->internalDrawPaint(paint); 1917} 1918 1919void SkCanvas::internalDrawPaint(const SkPaint& paint) { 1920 CHECK_SHADER_NOSETCONTEXT(paint); 1921 1922 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL) 1923 1924 while (iter.next()) { 1925 iter.fDevice->drawPaint(iter, looper.paint()); 1926 } 1927 1928 LOOPER_END 1929} 1930 1931void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1932 const SkPaint& paint) { 1933 if ((long)count <= 0) { 1934 return; 1935 } 1936 1937 CHECK_SHADER_NOSETCONTEXT(paint); 1938 1939 SkRect r, storage; 1940 const SkRect* bounds = NULL; 1941 if (paint.canComputeFastBounds()) { 1942 // special-case 2 points (common for drawing a single line) 1943 if (2 == count) { 1944 r.set(pts[0], pts[1]); 1945 } else { 1946 r.set(pts, SkToInt(count)); 1947 } 1948 bounds = &paint.computeFastStrokeBounds(r, &storage); 1949 if (this->quickReject(*bounds)) { 1950 return; 1951 } 1952 } 1953 1954 SkASSERT(pts != NULL); 1955 1956 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds) 1957 1958 while (iter.next()) { 1959 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); 1960 } 1961 1962 LOOPER_END 1963} 1964 1965void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1966 CHECK_SHADER_NOSETCONTEXT(paint); 1967 1968 SkRect storage; 1969 const SkRect* bounds = NULL; 1970 if (paint.canComputeFastBounds()) { 1971 bounds = &paint.computeFastBounds(r, &storage); 1972 if (this->quickReject(*bounds)) { 1973 return; 1974 } 1975 } 1976 1977 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds) 1978 1979 while (iter.next()) { 1980 iter.fDevice->drawRect(iter, r, looper.paint()); 1981 } 1982 1983 LOOPER_END 1984} 1985 1986void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1987 CHECK_SHADER_NOSETCONTEXT(paint); 1988 1989 SkRect storage; 1990 const SkRect* bounds = NULL; 1991 if (paint.canComputeFastBounds()) { 1992 bounds = &paint.computeFastBounds(oval, &storage); 1993 if (this->quickReject(*bounds)) { 1994 return; 1995 } 1996 } 1997 1998 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds) 1999 2000 while (iter.next()) { 2001 iter.fDevice->drawOval(iter, oval, looper.paint()); 2002 } 2003 2004 LOOPER_END 2005} 2006 2007void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 2008 CHECK_SHADER_NOSETCONTEXT(paint); 2009 2010 SkRect storage; 2011 const SkRect* bounds = NULL; 2012 if (paint.canComputeFastBounds()) { 2013 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage); 2014 if (this->quickReject(*bounds)) { 2015 return; 2016 } 2017 } 2018 2019 if (rrect.isRect()) { 2020 // call the non-virtual version 2021 this->SkCanvas::drawRect(rrect.getBounds(), paint); 2022 return; 2023 } else if (rrect.isOval()) { 2024 // call the non-virtual version 2025 this->SkCanvas::drawOval(rrect.getBounds(), paint); 2026 return; 2027 } 2028 2029 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) 2030 2031 while (iter.next()) { 2032 iter.fDevice->drawRRect(iter, rrect, looper.paint()); 2033 } 2034 2035 LOOPER_END 2036} 2037 2038void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, 2039 const SkPaint& paint) { 2040 CHECK_SHADER_NOSETCONTEXT(paint); 2041 2042 SkRect storage; 2043 const SkRect* bounds = NULL; 2044 if (paint.canComputeFastBounds()) { 2045 bounds = &paint.computeFastBounds(outer.getBounds(), &storage); 2046 if (this->quickReject(*bounds)) { 2047 return; 2048 } 2049 } 2050 2051 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) 2052 2053 while (iter.next()) { 2054 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint()); 2055 } 2056 2057 LOOPER_END 2058} 2059 2060void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 2061 CHECK_SHADER_NOSETCONTEXT(paint); 2062 2063 if (!path.isFinite()) { 2064 return; 2065 } 2066 2067 SkRect storage; 2068 const SkRect* bounds = NULL; 2069 if (!path.isInverseFillType() && paint.canComputeFastBounds()) { 2070 const SkRect& pathBounds = path.getBounds(); 2071 bounds = &paint.computeFastBounds(pathBounds, &storage); 2072 if (this->quickReject(*bounds)) { 2073 return; 2074 } 2075 } 2076 2077 const SkRect& r = path.getBounds(); 2078 if (r.width() <= 0 && r.height() <= 0) { 2079 if (path.isInverseFillType()) { 2080 this->internalDrawPaint(paint); 2081 } 2082 return; 2083 } 2084 2085 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds) 2086 2087 while (iter.next()) { 2088 iter.fDevice->drawPath(iter, path, looper.paint()); 2089 } 2090 2091 LOOPER_END 2092} 2093 2094void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, 2095 const SkPaint* paint) { 2096 SkDEBUGCODE(bitmap.validate();) 2097 2098 if (NULL == paint || paint->canComputeFastBounds()) { 2099 SkRect bounds = { 2100 x, y, 2101 x + SkIntToScalar(bitmap.width()), 2102 y + SkIntToScalar(bitmap.height()) 2103 }; 2104 if (paint) { 2105 (void)paint->computeFastBounds(bounds, &bounds); 2106 } 2107 if (this->quickReject(bounds)) { 2108 return; 2109 } 2110 } 2111 2112 SkMatrix matrix; 2113 matrix.setTranslate(x, y); 2114 this->internalDrawBitmap(bitmap, matrix, paint); 2115} 2116 2117// this one is non-virtual, so it can be called safely by other canvas apis 2118void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, 2119 const SkRect& dst, const SkPaint* paint, 2120 DrawBitmapRectFlags flags) { 2121 if (bitmap.drawsNothing() || dst.isEmpty()) { 2122 return; 2123 } 2124 2125 CHECK_LOCKCOUNT_BALANCE(bitmap); 2126 2127 SkRect storage; 2128 const SkRect* bounds = &dst; 2129 if (NULL == paint || paint->canComputeFastBounds()) { 2130 if (paint) { 2131 bounds = &paint->computeFastBounds(dst, &storage); 2132 } 2133 if (this->quickReject(*bounds)) { 2134 return; 2135 } 2136 } 2137 2138 SkLazyPaint lazy; 2139 if (NULL == paint) { 2140 paint = lazy.init(); 2141 } 2142 2143 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) 2144 2145 while (iter.next()) { 2146 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags); 2147 } 2148 2149 LOOPER_END 2150} 2151 2152void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, 2153 const SkRect& dst, const SkPaint* paint, 2154 DrawBitmapRectFlags flags) { 2155 SkDEBUGCODE(bitmap.validate();) 2156 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags); 2157} 2158 2159void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 2160 const SkPaint* paint) { 2161 SkDEBUGCODE(bitmap.validate();) 2162 this->internalDrawBitmap(bitmap, matrix, paint); 2163} 2164 2165void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap, 2166 const SkIRect& center, const SkRect& dst, 2167 const SkPaint* paint) { 2168 if (bitmap.drawsNothing()) { 2169 return; 2170 } 2171 if (NULL == paint || paint->canComputeFastBounds()) { 2172 SkRect storage; 2173 const SkRect* bounds = &dst; 2174 if (paint) { 2175 bounds = &paint->computeFastBounds(dst, &storage); 2176 } 2177 if (this->quickReject(*bounds)) { 2178 return; 2179 } 2180 } 2181 2182 const int32_t w = bitmap.width(); 2183 const int32_t h = bitmap.height(); 2184 2185 SkIRect c = center; 2186 // pin center to the bounds of the bitmap 2187 c.fLeft = SkMax32(0, center.fLeft); 2188 c.fTop = SkMax32(0, center.fTop); 2189 c.fRight = SkPin32(center.fRight, c.fLeft, w); 2190 c.fBottom = SkPin32(center.fBottom, c.fTop, h); 2191 2192 const SkScalar srcX[4] = { 2193 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w) 2194 }; 2195 const SkScalar srcY[4] = { 2196 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h) 2197 }; 2198 SkScalar dstX[4] = { 2199 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft), 2200 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight 2201 }; 2202 SkScalar dstY[4] = { 2203 dst.fTop, dst.fTop + SkIntToScalar(c.fTop), 2204 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom 2205 }; 2206 2207 if (dstX[1] > dstX[2]) { 2208 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width()); 2209 dstX[2] = dstX[1]; 2210 } 2211 2212 if (dstY[1] > dstY[2]) { 2213 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height()); 2214 dstY[2] = dstY[1]; 2215 } 2216 2217 for (int y = 0; y < 3; y++) { 2218 SkRect s, d; 2219 2220 s.fTop = srcY[y]; 2221 s.fBottom = srcY[y+1]; 2222 d.fTop = dstY[y]; 2223 d.fBottom = dstY[y+1]; 2224 for (int x = 0; x < 3; x++) { 2225 s.fLeft = srcX[x]; 2226 s.fRight = srcX[x+1]; 2227 d.fLeft = dstX[x]; 2228 d.fRight = dstX[x+1]; 2229 this->internalDrawBitmapRect(bitmap, &s, d, paint, 2230 kNone_DrawBitmapRectFlag); 2231 } 2232 } 2233} 2234 2235void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 2236 const SkRect& dst, const SkPaint* paint) { 2237 SkDEBUGCODE(bitmap.validate();) 2238 2239 // Need a device entry-point, so gpu can use a mesh 2240 this->internalDrawBitmapNine(bitmap, center, dst, paint); 2241} 2242 2243class SkDeviceFilteredPaint { 2244public: 2245 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) { 2246 SkBaseDevice::TextFlags flags; 2247 if (device->filterTextFlags(paint, &flags)) { 2248 SkPaint* newPaint = fLazy.set(paint); 2249 newPaint->setFlags(flags.fFlags); 2250 newPaint->setHinting(flags.fHinting); 2251 fPaint = newPaint; 2252 } else { 2253 fPaint = &paint; 2254 } 2255 } 2256 2257 const SkPaint& paint() const { return *fPaint; } 2258 2259private: 2260 const SkPaint* fPaint; 2261 SkLazyPaint fLazy; 2262}; 2263 2264void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, 2265 const SkRect& r, SkScalar textSize) { 2266 if (paint.getStyle() == SkPaint::kFill_Style) { 2267 draw.fDevice->drawRect(draw, r, paint); 2268 } else { 2269 SkPaint p(paint); 2270 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); 2271 draw.fDevice->drawRect(draw, r, p); 2272 } 2273} 2274 2275void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, 2276 const char text[], size_t byteLength, 2277 SkScalar x, SkScalar y) { 2278 SkASSERT(byteLength == 0 || text != NULL); 2279 2280 // nothing to draw 2281 if (text == NULL || byteLength == 0 || 2282 draw.fClip->isEmpty() || 2283 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 2284 return; 2285 } 2286 2287 SkScalar width = 0; 2288 SkPoint start; 2289 2290 start.set(0, 0); // to avoid warning 2291 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | 2292 SkPaint::kStrikeThruText_Flag)) { 2293 width = paint.measureText(text, byteLength); 2294 2295 SkScalar offsetX = 0; 2296 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 2297 offsetX = SkScalarHalf(width); 2298 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { 2299 offsetX = width; 2300 } 2301 start.set(x - offsetX, y); 2302 } 2303 2304 if (0 == width) { 2305 return; 2306 } 2307 2308 uint32_t flags = paint.getFlags(); 2309 2310 if (flags & (SkPaint::kUnderlineText_Flag | 2311 SkPaint::kStrikeThruText_Flag)) { 2312 SkScalar textSize = paint.getTextSize(); 2313 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 2314 SkRect r; 2315 2316 r.fLeft = start.fX; 2317 r.fRight = start.fX + width; 2318 2319 if (flags & SkPaint::kUnderlineText_Flag) { 2320 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, 2321 start.fY); 2322 r.fTop = offset; 2323 r.fBottom = offset + height; 2324 DrawRect(draw, paint, r, textSize); 2325 } 2326 if (flags & SkPaint::kStrikeThruText_Flag) { 2327 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, 2328 start.fY); 2329 r.fTop = offset; 2330 r.fBottom = offset + height; 2331 DrawRect(draw, paint, r, textSize); 2332 } 2333 } 2334} 2335 2336void SkCanvas::drawText(const void* text, size_t byteLength, 2337 SkScalar x, SkScalar y, const SkPaint& paint) { 2338 CHECK_SHADER_NOSETCONTEXT(paint); 2339 2340 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2341 2342 while (iter.next()) { 2343 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2344 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 2345 DrawTextDecorations(iter, dfp.paint(), 2346 static_cast<const char*>(text), byteLength, x, y); 2347 } 2348 2349 LOOPER_END 2350} 2351 2352void SkCanvas::drawPosText(const void* text, size_t byteLength, 2353 const SkPoint pos[], const SkPaint& paint) { 2354 CHECK_SHADER_NOSETCONTEXT(paint); 2355 2356 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2357 2358 while (iter.next()) { 2359 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2360 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 2361 dfp.paint()); 2362 } 2363 2364 LOOPER_END 2365} 2366 2367void SkCanvas::drawPosTextH(const void* text, size_t byteLength, 2368 const SkScalar xpos[], SkScalar constY, 2369 const SkPaint& paint) { 2370 CHECK_SHADER_NOSETCONTEXT(paint); 2371 2372 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2373 2374 while (iter.next()) { 2375 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2376 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 2377 dfp.paint()); 2378 } 2379 2380 LOOPER_END 2381} 2382 2383void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, 2384 const SkPath& path, const SkMatrix* matrix, 2385 const SkPaint& paint) { 2386 CHECK_SHADER_NOSETCONTEXT(paint); 2387 2388 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2389 2390 while (iter.next()) { 2391 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 2392 matrix, looper.paint()); 2393 } 2394 2395 LOOPER_END 2396} 2397 2398void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 2399 const SkPoint verts[], const SkPoint texs[], 2400 const SkColor colors[], SkXfermode* xmode, 2401 const uint16_t indices[], int indexCount, 2402 const SkPaint& paint) { 2403 CHECK_SHADER_NOSETCONTEXT(paint); 2404 2405 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL) 2406 2407 while (iter.next()) { 2408 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 2409 colors, xmode, indices, indexCount, 2410 looper.paint()); 2411 } 2412 2413 LOOPER_END 2414} 2415 2416////////////////////////////////////////////////////////////////////////////// 2417// These methods are NOT virtual, and therefore must call back into virtual 2418// methods, rather than actually drawing themselves. 2419////////////////////////////////////////////////////////////////////////////// 2420 2421void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 2422 SkXfermode::Mode mode) { 2423 SkPaint paint; 2424 2425 paint.setARGB(a, r, g, b); 2426 if (SkXfermode::kSrcOver_Mode != mode) { 2427 paint.setXfermodeMode(mode); 2428 } 2429 this->drawPaint(paint); 2430} 2431 2432void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 2433 SkPaint paint; 2434 2435 paint.setColor(c); 2436 if (SkXfermode::kSrcOver_Mode != mode) { 2437 paint.setXfermodeMode(mode); 2438 } 2439 this->drawPaint(paint); 2440} 2441 2442void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 2443 SkPoint pt; 2444 2445 pt.set(x, y); 2446 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2447} 2448 2449void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 2450 SkPoint pt; 2451 SkPaint paint; 2452 2453 pt.set(x, y); 2454 paint.setColor(color); 2455 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2456} 2457 2458void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 2459 const SkPaint& paint) { 2460 SkPoint pts[2]; 2461 2462 pts[0].set(x0, y0); 2463 pts[1].set(x1, y1); 2464 this->drawPoints(kLines_PointMode, 2, pts, paint); 2465} 2466 2467void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 2468 SkScalar right, SkScalar bottom, 2469 const SkPaint& paint) { 2470 SkRect r; 2471 2472 r.set(left, top, right, bottom); 2473 this->drawRect(r, paint); 2474} 2475 2476void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 2477 const SkPaint& paint) { 2478 if (radius < 0) { 2479 radius = 0; 2480 } 2481 2482 SkRect r; 2483 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 2484 this->drawOval(r, paint); 2485} 2486 2487void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 2488 const SkPaint& paint) { 2489 if (rx > 0 && ry > 0) { 2490 if (paint.canComputeFastBounds()) { 2491 SkRect storage; 2492 if (this->quickReject(paint.computeFastBounds(r, &storage))) { 2493 return; 2494 } 2495 } 2496 SkRRect rrect; 2497 rrect.setRectXY(r, rx, ry); 2498 this->drawRRect(rrect, paint); 2499 } else { 2500 this->drawRect(r, paint); 2501 } 2502} 2503 2504void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 2505 SkScalar sweepAngle, bool useCenter, 2506 const SkPaint& paint) { 2507 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 2508 this->drawOval(oval, paint); 2509 } else { 2510 SkPath path; 2511 if (useCenter) { 2512 path.moveTo(oval.centerX(), oval.centerY()); 2513 } 2514 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 2515 if (useCenter) { 2516 path.close(); 2517 } 2518 this->drawPath(path, paint); 2519 } 2520} 2521 2522void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 2523 const SkPath& path, SkScalar hOffset, 2524 SkScalar vOffset, const SkPaint& paint) { 2525 SkMatrix matrix; 2526 2527 matrix.setTranslate(hOffset, vOffset); 2528 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 2529} 2530 2531/////////////////////////////////////////////////////////////////////////////// 2532void SkCanvas::EXPERIMENTAL_optimize(SkPicture* picture) { 2533 SkBaseDevice* device = this->getDevice(); 2534 if (NULL != device) { 2535 device->EXPERIMENTAL_optimize(picture); 2536 } 2537} 2538 2539void SkCanvas::drawPicture(SkPicture& picture) { 2540 SkBaseDevice* device = this->getTopDevice(); 2541 if (NULL != device) { 2542 // Canvas has to first give the device the opportunity to render 2543 // the picture itself. 2544 if (device->EXPERIMENTAL_drawPicture(picture)) { 2545 return; // the device has rendered the entire picture 2546 } 2547 } 2548 2549 picture.draw(this); 2550} 2551 2552/////////////////////////////////////////////////////////////////////////////// 2553/////////////////////////////////////////////////////////////////////////////// 2554 2555SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 2556 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); 2557 2558 SkASSERT(canvas); 2559 2560 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 2561 fDone = !fImpl->next(); 2562} 2563 2564SkCanvas::LayerIter::~LayerIter() { 2565 fImpl->~SkDrawIter(); 2566} 2567 2568void SkCanvas::LayerIter::next() { 2569 fDone = !fImpl->next(); 2570} 2571 2572SkBaseDevice* SkCanvas::LayerIter::device() const { 2573 return fImpl->getDevice(); 2574} 2575 2576const SkMatrix& SkCanvas::LayerIter::matrix() const { 2577 return fImpl->getMatrix(); 2578} 2579 2580const SkPaint& SkCanvas::LayerIter::paint() const { 2581 const SkPaint* paint = fImpl->getPaint(); 2582 if (NULL == paint) { 2583 paint = &fDefaultPaint; 2584 } 2585 return *paint; 2586} 2587 2588const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 2589int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 2590int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 2591 2592/////////////////////////////////////////////////////////////////////////////// 2593 2594SkCanvas::ClipVisitor::~ClipVisitor() { } 2595 2596/////////////////////////////////////////////////////////////////////////////// 2597 2598static bool supported_for_raster_canvas(const SkImageInfo& info) { 2599 switch (info.alphaType()) { 2600 case kPremul_SkAlphaType: 2601 case kOpaque_SkAlphaType: 2602 break; 2603 default: 2604 return false; 2605 } 2606 2607 switch (info.colorType()) { 2608 case kAlpha_8_SkColorType: 2609 case kRGB_565_SkColorType: 2610 case kPMColor_SkColorType: 2611 break; 2612 default: 2613 return false; 2614 } 2615 2616 return true; 2617} 2618 2619SkCanvas* SkCanvas::NewRaster(const SkImageInfo& info) { 2620 if (!supported_for_raster_canvas(info)) { 2621 return NULL; 2622 } 2623 2624 SkBitmap bitmap; 2625 if (!bitmap.allocPixels(info)) { 2626 return NULL; 2627 } 2628 2629 // should this functionality be moved into allocPixels()? 2630 if (!bitmap.info().isOpaque()) { 2631 bitmap.eraseColor(0); 2632 } 2633 return SkNEW_ARGS(SkCanvas, (bitmap)); 2634} 2635 2636SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) { 2637 if (!supported_for_raster_canvas(info)) { 2638 return NULL; 2639 } 2640 2641 SkBitmap bitmap; 2642 if (!bitmap.installPixels(info, pixels, rowBytes)) { 2643 return NULL; 2644 } 2645 2646 // should this functionality be moved into allocPixels()? 2647 if (!bitmap.info().isOpaque()) { 2648 bitmap.eraseColor(0); 2649 } 2650 return SkNEW_ARGS(SkCanvas, (bitmap)); 2651} 2652