SkCanvas.cpp revision d9ea09e1f29b303e6fa36079e99729d2951925b9
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 670#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG 671bool SkCanvas::readPixels(SkBitmap* bitmap, 672 int x, int y, 673 Config8888 config8888) { 674 SkBaseDevice* device = this->getDevice(); 675 if (!device) { 676 return false; 677 } 678 return device->readPixels(bitmap, x, y, config8888); 679} 680#endif 681 682bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) { 683 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) { 684 return false; 685 } 686 687 bool weAllocated = false; 688 if (NULL == bitmap->pixelRef()) { 689 if (!bitmap->allocPixels()) { 690 return false; 691 } 692 weAllocated = true; 693 } 694 695 SkBitmap bm(*bitmap); 696 bm.lockPixels(); 697 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) { 698 return true; 699 } 700 701 if (weAllocated) { 702 bitmap->setPixelRef(NULL); 703 } 704 return false; 705} 706 707bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) { 708 SkIRect r = srcRect; 709 const SkISize size = this->getBaseLayerSize(); 710 if (!r.intersect(0, 0, size.width(), size.height())) { 711 bitmap->reset(); 712 return false; 713 } 714 715 if (!bitmap->allocN32Pixels(r.width(), r.height())) { 716 // bitmap will already be reset. 717 return false; 718 } 719 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) { 720 bitmap->reset(); 721 return false; 722 } 723 return true; 724} 725 726bool SkCanvas::readPixels(const SkImageInfo& origInfo, void* dstP, size_t rowBytes, int x, int y) { 727 switch (origInfo.colorType()) { 728 case kUnknown_SkColorType: 729 case kIndex_8_SkColorType: 730 return false; 731 default: 732 break; 733 } 734 if (NULL == dstP || rowBytes < origInfo.minRowBytes()) { 735 return false; 736 } 737 if (0 == origInfo.width() || 0 == origInfo.height()) { 738 return false; 739 } 740 741 SkBaseDevice* device = this->getDevice(); 742 if (!device) { 743 return false; 744 } 745 746 const SkISize size = this->getBaseLayerSize(); 747 SkIRect srcR = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height()); 748 if (!srcR.intersect(0, 0, size.width(), size.height())) { 749 return false; 750 } 751 752 SkImageInfo info = origInfo; 753 // the intersect may have shrunk info's logical size 754 info.fWidth = srcR.width(); 755 info.fHeight = srcR.height(); 756 757 // if x or y are negative, then we have to adjust pixels 758 if (x > 0) { 759 x = 0; 760 } 761 if (y > 0) { 762 y = 0; 763 } 764 // here x,y are either 0 or negative 765 dstP = ((char*)dstP - y * rowBytes - x * info.bytesPerPixel()); 766 767 // The device can assert that the requested area is always contained in its bounds 768 return device->readPixels(info, dstP, rowBytes, srcR.x(), srcR.y()); 769} 770 771bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) { 772 if (bitmap.getTexture()) { 773 return false; 774 } 775 SkBitmap bm(bitmap); 776 bm.lockPixels(); 777 if (bm.getPixels()) { 778 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y); 779 } 780 return false; 781} 782 783bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes, 784 int x, int y) { 785 switch (origInfo.colorType()) { 786 case kUnknown_SkColorType: 787 case kIndex_8_SkColorType: 788 return false; 789 default: 790 break; 791 } 792 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) { 793 return false; 794 } 795 796 const SkISize size = this->getBaseLayerSize(); 797 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height()); 798 if (!target.intersect(0, 0, size.width(), size.height())) { 799 return false; 800 } 801 802 SkBaseDevice* device = this->getDevice(); 803 if (!device) { 804 return false; 805 } 806 807 SkImageInfo info = origInfo; 808 // the intersect may have shrunk info's logical size 809 info.fWidth = target.width(); 810 info.fHeight = target.height(); 811 812 // if x or y are negative, then we have to adjust pixels 813 if (x > 0) { 814 x = 0; 815 } 816 if (y > 0) { 817 y = 0; 818 } 819 // here x,y are either 0 or negative 820 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel()); 821 822 // The device can assert that the requested area is always contained in its bounds 823 return device->writePixels(info, pixels, rowBytes, target.x(), target.y()); 824} 825 826SkCanvas* SkCanvas::canvasForDrawIter() { 827 return this; 828} 829 830////////////////////////////////////////////////////////////////////////////// 831 832void SkCanvas::updateDeviceCMCache() { 833 if (fDeviceCMDirty) { 834 const SkMatrix& totalMatrix = this->getTotalMatrix(); 835 const SkRasterClip& totalClip = *fMCRec->fRasterClip; 836 DeviceCM* layer = fMCRec->fTopLayer; 837 838 if (NULL == layer->fNext) { // only one layer 839 layer->updateMC(totalMatrix, totalClip, fClipStack, NULL); 840 } else { 841 SkRasterClip clip(totalClip); 842 do { 843 layer->updateMC(totalMatrix, clip, fClipStack, &clip); 844 } while ((layer = layer->fNext) != NULL); 845 } 846 fDeviceCMDirty = false; 847 } 848} 849 850/////////////////////////////////////////////////////////////////////////////// 851 852int SkCanvas::internalSave(SaveFlags flags) { 853 int saveCount = this->getSaveCount(); // record this before the actual save 854 855 MCRec* newTop = (MCRec*)fMCStack.push_back(); 856 new (newTop) MCRec(fMCRec, flags); // balanced in restore() 857 858 fMCRec = newTop; 859 860 if (SkCanvas::kClip_SaveFlag & flags) { 861 fClipStack.save(); 862 } 863 864 return saveCount; 865} 866 867void SkCanvas::willSave(SaveFlags) { 868 // Do nothing. Subclasses may do something. 869} 870 871int SkCanvas::save(SaveFlags flags) { 872 this->willSave(flags); 873 // call shared impl 874 return this->internalSave(flags); 875} 876 877static bool bounds_affects_clip(SkCanvas::SaveFlags flags) { 878#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG 879 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0; 880#else 881 return true; 882#endif 883} 884 885bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, 886 SkIRect* intersection, const SkImageFilter* imageFilter) { 887 SkIRect clipBounds; 888 SkRegion::Op op = SkRegion::kIntersect_Op; 889 if (!this->getClipDeviceBounds(&clipBounds)) { 890 return false; 891 } 892 893 if (imageFilter) { 894 imageFilter->filterBounds(clipBounds, *fMCRec->fMatrix, &clipBounds); 895 // Filters may grow the bounds beyond the device bounds. 896 op = SkRegion::kReplace_Op; 897 } 898 SkIRect ir; 899 if (NULL != bounds) { 900 SkRect r; 901 902 this->getTotalMatrix().mapRect(&r, *bounds); 903 r.roundOut(&ir); 904 // early exit if the layer's bounds are clipped out 905 if (!ir.intersect(clipBounds)) { 906 if (bounds_affects_clip(flags)) { 907 fMCRec->fRasterClip->setEmpty(); 908 } 909 return false; 910 } 911 } else { // no user bounds, so just use the clip 912 ir = clipBounds; 913 } 914 915 if (bounds_affects_clip(flags)) { 916 fClipStack.clipDevRect(ir, op); 917 // early exit if the clip is now empty 918 if (!fMCRec->fRasterClip->op(ir, op)) { 919 return false; 920 } 921 } 922 923 if (intersection) { 924 *intersection = ir; 925 } 926 return true; 927} 928 929SkCanvas::SaveLayerStrategy SkCanvas::willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) { 930 931 // Do nothing. Subclasses may do something. 932 return kFullLayer_SaveLayerStrategy; 933} 934 935int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, 936 SaveFlags flags) { 937 // Overriding classes may return false to signal that we don't need to create a layer. 938 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags); 939 return this->internalSaveLayer(bounds, paint, flags, false, strategy); 940} 941 942static SkBaseDevice* createCompatibleDevice(SkCanvas* canvas, 943 const SkImageInfo& info) { 944 SkBaseDevice* device = canvas->getDevice(); 945 return device ? device->createCompatibleDevice(info) : NULL; 946} 947 948int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags, 949 bool justForImageFilter, SaveLayerStrategy strategy) { 950#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG 951 flags = (SaveFlags)(flags | kClipToLayer_SaveFlag); 952#endif 953 954 // do this before we create the layer. We don't call the public save() since 955 // that would invoke a possibly overridden virtual 956 int count = this->internalSave(flags); 957 958 fDeviceCMDirty = true; 959 960 SkIRect ir; 961 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) { 962 return count; 963 } 964 965 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about 966 // the clipRectBounds() call above? 967 if (kNoLayer_SaveLayerStrategy == strategy) { 968 return count; 969 } 970 971 // Kill the imagefilter if our device doesn't allow it 972 SkLazyPaint lazyP; 973 if (paint && paint->getImageFilter()) { 974 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) { 975 if (justForImageFilter) { 976 // early exit if the layer was just for the imageFilter 977 return count; 978 } 979 SkPaint* p = lazyP.set(*paint); 980 p->setImageFilter(NULL); 981 paint = p; 982 } 983 } 984 985 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag); 986 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(), 987 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); 988 989 SkBaseDevice* device; 990 if (paint && paint->getImageFilter()) { 991 device = createCompatibleDevice(this, info); 992 } else { 993 device = this->createLayerDevice(info); 994 } 995 if (NULL == device) { 996 SkDebugf("Unable to create device for layer."); 997 return count; 998 } 999 1000 device->setOrigin(ir.fLeft, ir.fTop); 1001 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint, this)); 1002 device->unref(); 1003 1004 layer->fNext = fMCRec->fTopLayer; 1005 fMCRec->fLayer = layer; 1006 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer 1007 1008 fSaveLayerCount += 1; 1009 return count; 1010} 1011 1012int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha, 1013 SaveFlags flags) { 1014 if (0xFF == alpha) { 1015 return this->saveLayer(bounds, NULL, flags); 1016 } else { 1017 SkPaint tmpPaint; 1018 tmpPaint.setAlpha(alpha); 1019 return this->saveLayer(bounds, &tmpPaint, flags); 1020 } 1021} 1022 1023void SkCanvas::willRestore() { 1024 // Do nothing. Subclasses may do something. 1025} 1026 1027void SkCanvas::restore() { 1028 // check for underflow 1029 if (fMCStack.count() > 1) { 1030 this->willRestore(); 1031 this->internalRestore(); 1032 } 1033} 1034 1035void SkCanvas::internalRestore() { 1036 SkASSERT(fMCStack.count() != 0); 1037 1038 fDeviceCMDirty = true; 1039 fCachedLocalClipBoundsDirty = true; 1040 1041 if (SkCanvas::kClip_SaveFlag & fMCRec->fFlags) { 1042 fClipStack.restore(); 1043 } 1044 1045 // reserve our layer (if any) 1046 DeviceCM* layer = fMCRec->fLayer; // may be null 1047 // now detach it from fMCRec so we can pop(). Gets freed after its drawn 1048 fMCRec->fLayer = NULL; 1049 1050 // now do the normal restore() 1051 fMCRec->~MCRec(); // balanced in save() 1052 fMCStack.pop_back(); 1053 fMCRec = (MCRec*)fMCStack.back(); 1054 1055 /* Time to draw the layer's offscreen. We can't call the public drawSprite, 1056 since if we're being recorded, we don't want to record this (the 1057 recorder will have already recorded the restore). 1058 */ 1059 if (NULL != layer) { 1060 if (layer->fNext) { 1061 const SkIPoint& origin = layer->fDevice->getOrigin(); 1062 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), 1063 layer->fPaint); 1064 // reset this, since internalDrawDevice will have set it to true 1065 fDeviceCMDirty = true; 1066 1067 SkASSERT(fSaveLayerCount > 0); 1068 fSaveLayerCount -= 1; 1069 } 1070 SkDELETE(layer); 1071 } 1072} 1073 1074int SkCanvas::getSaveCount() const { 1075 return fMCStack.count(); 1076} 1077 1078void SkCanvas::restoreToCount(int count) { 1079 // sanity check 1080 if (count < 1) { 1081 count = 1; 1082 } 1083 1084 int n = this->getSaveCount() - count; 1085 for (int i = 0; i < n; ++i) { 1086 this->restore(); 1087 } 1088} 1089 1090bool SkCanvas::isDrawingToLayer() const { 1091 return fSaveLayerCount > 0; 1092} 1093 1094SkSurface* SkCanvas::newSurface(const SkImageInfo& info) { 1095 return this->onNewSurface(info); 1096} 1097 1098SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info) { 1099 SkBaseDevice* dev = this->getDevice(); 1100 return dev ? dev->newSurface(info) : NULL; 1101} 1102 1103SkImageInfo SkCanvas::imageInfo() const { 1104 SkBaseDevice* dev = this->getDevice(); 1105 if (dev) { 1106 return dev->imageInfo(); 1107 } else { 1108 return SkImageInfo::MakeUnknown(0, 0); 1109 } 1110} 1111 1112const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) { 1113 return this->onPeekPixels(info, rowBytes); 1114} 1115 1116const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) { 1117 SkBaseDevice* dev = this->getDevice(); 1118 return dev ? dev->peekPixels(info, rowBytes) : NULL; 1119} 1120 1121void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) { 1122 return this->onAccessTopLayerPixels(info, rowBytes); 1123} 1124 1125void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) { 1126 SkBaseDevice* dev = this->getTopDevice(); 1127 return dev ? dev->accessPixels(info, rowBytes) : NULL; 1128} 1129 1130SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) { 1131 fAddr = canvas->peekPixels(&fInfo, &fRowBytes); 1132 if (NULL == fAddr) { 1133 fInfo = canvas->imageInfo(); 1134 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.allocPixels(fInfo)) { 1135 return; // failure, fAddr is NULL 1136 } 1137 if (!canvas->readPixels(&fBitmap, 0, 0)) { 1138 return; // failure, fAddr is NULL 1139 } 1140 fAddr = fBitmap.getPixels(); 1141 fRowBytes = fBitmap.rowBytes(); 1142 } 1143 SkASSERT(fAddr); // success 1144} 1145 1146bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const { 1147 if (fAddr) { 1148 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes, 1149 NULL, NULL); 1150 } else { 1151 bitmap->reset(); 1152 return false; 1153 } 1154} 1155 1156void SkCanvas::onPushCull(const SkRect& cullRect) { 1157 // do nothing. Subclasses may do something 1158} 1159 1160void SkCanvas::onPopCull() { 1161 // do nothing. Subclasses may do something 1162} 1163 1164///////////////////////////////////////////////////////////////////////////// 1165#ifdef SK_DEBUG 1166// Ensure that cull rects are monotonically nested in device space. 1167void SkCanvas::validateCull(const SkIRect& devCull) { 1168 if (fCullStack.isEmpty() 1169 || devCull.isEmpty() 1170 || fCullStack.top().contains(devCull)) { 1171 return; 1172 } 1173 1174 SkDEBUGF(("Invalid cull: [%d %d %d %d] (previous cull: [%d %d %d %d])\n", 1175 devCull.x(), devCull.y(), devCull.right(), devCull.bottom(), 1176 fCullStack.top().x(), fCullStack.top().y(), 1177 fCullStack.top().right(), fCullStack.top().bottom())); 1178 1179#ifdef ASSERT_NESTED_CULLING 1180 SkDEBUGFAIL("Invalid cull."); 1181#endif 1182} 1183#endif 1184 1185void SkCanvas::pushCull(const SkRect& cullRect) { 1186 ++fCullCount; 1187 this->onPushCull(cullRect); 1188 1189#ifdef SK_DEBUG 1190 // Map the cull rect into device space. 1191 SkRect mappedCull; 1192 this->getTotalMatrix().mapRect(&mappedCull, cullRect); 1193 1194 // Take clipping into account. 1195 SkIRect devClip, devCull; 1196 mappedCull.roundOut(&devCull); 1197 this->getClipDeviceBounds(&devClip); 1198 if (!devCull.intersect(devClip)) { 1199 devCull.setEmpty(); 1200 } 1201 1202 this->validateCull(devCull); 1203 fCullStack.push(devCull); // balanced in popCull 1204#endif 1205} 1206 1207void SkCanvas::popCull() { 1208 SkASSERT(fCullStack.count() == fCullCount); 1209 1210 if (fCullCount > 0) { 1211 --fCullCount; 1212 this->onPopCull(); 1213 1214 SkDEBUGCODE(fCullStack.pop()); 1215 } 1216} 1217 1218///////////////////////////////////////////////////////////////////////////// 1219 1220void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, 1221 const SkMatrix& matrix, const SkPaint* paint) { 1222 if (bitmap.drawsNothing()) { 1223 return; 1224 } 1225 1226 SkLazyPaint lazy; 1227 if (NULL == paint) { 1228 paint = lazy.init(); 1229 } 1230 1231 SkDEBUGCODE(bitmap.validate();) 1232 CHECK_LOCKCOUNT_BALANCE(bitmap); 1233 1234 SkRect storage; 1235 const SkRect* bounds = NULL; 1236 if (paint && paint->canComputeFastBounds()) { 1237 bitmap.getBounds(&storage); 1238 matrix.mapRect(&storage); 1239 bounds = &paint->computeFastBounds(storage, &storage); 1240 } 1241 1242 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) 1243 1244 while (iter.next()) { 1245 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint()); 1246 } 1247 1248 LOOPER_END 1249} 1250 1251void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, 1252 const SkPaint* paint) { 1253 SkPaint tmp; 1254 if (NULL == paint) { 1255 tmp.setDither(true); 1256 paint = &tmp; 1257 } 1258 1259 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 1260 while (iter.next()) { 1261 SkBaseDevice* dstDev = iter.fDevice; 1262 paint = &looper.paint(); 1263 SkImageFilter* filter = paint->getImageFilter(); 1264 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 1265 if (filter && !dstDev->canHandleImageFilter(filter)) { 1266 SkDeviceImageFilterProxy proxy(dstDev); 1267 SkBitmap dst; 1268 SkIPoint offset = SkIPoint::Make(0, 0); 1269 const SkBitmap& src = srcDev->accessBitmap(false); 1270 SkMatrix matrix = *iter.fMatrix; 1271 matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); 1272 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height()); 1273 SkImageFilter::Context ctx(matrix, clipBounds); 1274 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) { 1275 SkPaint tmpUnfiltered(*paint); 1276 tmpUnfiltered.setImageFilter(NULL); 1277 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(), 1278 tmpUnfiltered); 1279 } 1280 } else { 1281 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint); 1282 } 1283 } 1284 LOOPER_END 1285} 1286 1287void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, 1288 const SkPaint* paint) { 1289 if (bitmap.drawsNothing()) { 1290 return; 1291 } 1292 SkDEBUGCODE(bitmap.validate();) 1293 CHECK_LOCKCOUNT_BALANCE(bitmap); 1294 1295 SkPaint tmp; 1296 if (NULL == paint) { 1297 paint = &tmp; 1298 } 1299 1300 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 1301 1302 while (iter.next()) { 1303 paint = &looper.paint(); 1304 SkImageFilter* filter = paint->getImageFilter(); 1305 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 1306 if (filter && !iter.fDevice->canHandleImageFilter(filter)) { 1307 SkDeviceImageFilterProxy proxy(iter.fDevice); 1308 SkBitmap dst; 1309 SkIPoint offset = SkIPoint::Make(0, 0); 1310 SkMatrix matrix = *iter.fMatrix; 1311 matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); 1312 SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height()); 1313 SkImageFilter::Context ctx(matrix, clipBounds); 1314 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) { 1315 SkPaint tmpUnfiltered(*paint); 1316 tmpUnfiltered.setImageFilter(NULL); 1317 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(), 1318 tmpUnfiltered); 1319 } 1320 } else { 1321 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint); 1322 } 1323 } 1324 LOOPER_END 1325} 1326 1327///////////////////////////////////////////////////////////////////////////// 1328void SkCanvas::translate(SkScalar dx, SkScalar dy) { 1329 SkMatrix m; 1330 m.setTranslate(dx, dy); 1331 this->concat(m); 1332} 1333 1334void SkCanvas::scale(SkScalar sx, SkScalar sy) { 1335 SkMatrix m; 1336 m.setScale(sx, sy); 1337 this->concat(m); 1338} 1339 1340void SkCanvas::rotate(SkScalar degrees) { 1341 SkMatrix m; 1342 m.setRotate(degrees); 1343 this->concat(m); 1344} 1345 1346void SkCanvas::skew(SkScalar sx, SkScalar sy) { 1347 SkMatrix m; 1348 m.setSkew(sx, sy); 1349 this->concat(m); 1350} 1351 1352void SkCanvas::didConcat(const SkMatrix&) { 1353 // Do nothing. Subclasses may do something. 1354} 1355 1356void SkCanvas::concat(const SkMatrix& matrix) { 1357 if (matrix.isIdentity()) { 1358 return; 1359 } 1360 1361 fDeviceCMDirty = true; 1362 fCachedLocalClipBoundsDirty = true; 1363 fMCRec->fMatrix->preConcat(matrix); 1364 1365 this->didConcat(matrix); 1366} 1367 1368void SkCanvas::didSetMatrix(const SkMatrix&) { 1369 // Do nothing. Subclasses may do something. 1370} 1371 1372void SkCanvas::setMatrix(const SkMatrix& matrix) { 1373 fDeviceCMDirty = true; 1374 fCachedLocalClipBoundsDirty = true; 1375 *fMCRec->fMatrix = matrix; 1376 this->didSetMatrix(matrix); 1377} 1378 1379void SkCanvas::resetMatrix() { 1380 SkMatrix matrix; 1381 1382 matrix.reset(); 1383 this->setMatrix(matrix); 1384} 1385 1386////////////////////////////////////////////////////////////////////////////// 1387 1388void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 1389 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1390 this->onClipRect(rect, op, edgeStyle); 1391} 1392 1393void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1394#ifdef SK_ENABLE_CLIP_QUICKREJECT 1395 if (SkRegion::kIntersect_Op == op) { 1396 if (fMCRec->fRasterClip->isEmpty()) { 1397 return false; 1398 } 1399 1400 if (this->quickReject(rect)) { 1401 fDeviceCMDirty = true; 1402 fCachedLocalClipBoundsDirty = true; 1403 1404 fClipStack.clipEmpty(); 1405 return fMCRec->fRasterClip->setEmpty(); 1406 } 1407 } 1408#endif 1409 1410 AutoValidateClip avc(this); 1411 1412 fDeviceCMDirty = true; 1413 fCachedLocalClipBoundsDirty = true; 1414 if (!fAllowSoftClip) { 1415 edgeStyle = kHard_ClipEdgeStyle; 1416 } 1417 1418 if (fMCRec->fMatrix->rectStaysRect()) { 1419 // for these simpler matrices, we can stay a rect even after applying 1420 // the matrix. This means we don't have to a) make a path, and b) tell 1421 // the region code to scan-convert the path, only to discover that it 1422 // is really just a rect. 1423 SkRect r; 1424 1425 fMCRec->fMatrix->mapRect(&r, rect); 1426 fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle); 1427 fMCRec->fRasterClip->op(r, op, kSoft_ClipEdgeStyle == edgeStyle); 1428 } else { 1429 // since we're rotated or some such thing, we convert the rect to a path 1430 // and clip against that, since it can handle any matrix. However, to 1431 // avoid recursion in the case where we are subclassed (e.g. Pictures) 1432 // we explicitly call "our" version of clipPath. 1433 SkPath path; 1434 1435 path.addRect(rect); 1436 this->SkCanvas::onClipPath(path, op, edgeStyle); 1437 } 1438} 1439 1440static void clip_path_helper(const SkCanvas* canvas, SkRasterClip* currClip, 1441 const SkPath& devPath, SkRegion::Op op, bool doAA) { 1442 // base is used to limit the size (and therefore memory allocation) of the 1443 // region that results from scan converting devPath. 1444 SkRegion base; 1445 1446 if (SkRegion::kIntersect_Op == op) { 1447 // since we are intersect, we can do better (tighter) with currRgn's 1448 // bounds, than just using the device. However, if currRgn is complex, 1449 // our region blitter may hork, so we do that case in two steps. 1450 if (currClip->isRect()) { 1451 // FIXME: we should also be able to do this when currClip->isBW(), 1452 // but relaxing the test above triggers GM asserts in 1453 // SkRgnBuilder::blitH(). We need to investigate what's going on. 1454 currClip->setPath(devPath, currClip->bwRgn(), doAA); 1455 } else { 1456 base.setRect(currClip->getBounds()); 1457 SkRasterClip clip; 1458 clip.setPath(devPath, base, doAA); 1459 currClip->op(clip, op); 1460 } 1461 } else { 1462 const SkBaseDevice* device = canvas->getDevice(); 1463 if (!device) { 1464 currClip->setEmpty(); 1465 return; 1466 } 1467 1468 base.setRect(0, 0, device->width(), device->height()); 1469 1470 if (SkRegion::kReplace_Op == op) { 1471 currClip->setPath(devPath, base, doAA); 1472 } else { 1473 SkRasterClip clip; 1474 clip.setPath(devPath, base, doAA); 1475 currClip->op(clip, op); 1476 } 1477 } 1478} 1479 1480void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 1481 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1482 if (rrect.isRect()) { 1483 this->onClipRect(rrect.getBounds(), op, edgeStyle); 1484 } else { 1485 this->onClipRRect(rrect, op, edgeStyle); 1486 } 1487} 1488 1489void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1490 SkRRect transformedRRect; 1491 if (rrect.transform(*fMCRec->fMatrix, &transformedRRect)) { 1492 AutoValidateClip avc(this); 1493 1494 fDeviceCMDirty = true; 1495 fCachedLocalClipBoundsDirty = true; 1496 if (!fAllowSoftClip) { 1497 edgeStyle = kHard_ClipEdgeStyle; 1498 } 1499 1500 fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle); 1501 1502 SkPath devPath; 1503 devPath.addRRect(transformedRRect); 1504 1505 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, kSoft_ClipEdgeStyle == edgeStyle); 1506 return; 1507 } 1508 1509 SkPath path; 1510 path.addRRect(rrect); 1511 // call the non-virtual version 1512 this->SkCanvas::onClipPath(path, op, edgeStyle); 1513} 1514 1515void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 1516 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1517 SkRect r; 1518 if (!path.isInverseFillType() && path.isRect(&r)) { 1519 this->onClipRect(r, op, edgeStyle); 1520 } else { 1521 this->onClipPath(path, op, edgeStyle); 1522 } 1523} 1524 1525void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1526#ifdef SK_ENABLE_CLIP_QUICKREJECT 1527 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { 1528 if (fMCRec->fRasterClip->isEmpty()) { 1529 return false; 1530 } 1531 1532 if (this->quickReject(path.getBounds())) { 1533 fDeviceCMDirty = true; 1534 fCachedLocalClipBoundsDirty = true; 1535 1536 fClipStack.clipEmpty(); 1537 return fMCRec->fRasterClip->setEmpty(); 1538 } 1539 } 1540#endif 1541 1542 AutoValidateClip avc(this); 1543 1544 fDeviceCMDirty = true; 1545 fCachedLocalClipBoundsDirty = true; 1546 if (!fAllowSoftClip) { 1547 edgeStyle = kHard_ClipEdgeStyle; 1548 } 1549 1550 SkPath devPath; 1551 path.transform(*fMCRec->fMatrix, &devPath); 1552 1553 // Check if the transfomation, or the original path itself 1554 // made us empty. Note this can also happen if we contained NaN 1555 // values. computing the bounds detects this, and will set our 1556 // bounds to empty if that is the case. (see SkRect::set(pts, count)) 1557 if (devPath.getBounds().isEmpty()) { 1558 // resetting the path will remove any NaN or other wanky values 1559 // that might upset our scan converter. 1560 devPath.reset(); 1561 } 1562 1563 // if we called path.swap() we could avoid a deep copy of this path 1564 fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle); 1565 1566 if (fAllowSimplifyClip) { 1567 devPath.reset(); 1568 devPath.setFillType(SkPath::kInverseEvenOdd_FillType); 1569 const SkClipStack* clipStack = getClipStack(); 1570 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart); 1571 const SkClipStack::Element* element; 1572 while ((element = iter.next())) { 1573 SkClipStack::Element::Type type = element->getType(); 1574 if (type == SkClipStack::Element::kEmpty_Type) { 1575 continue; 1576 } 1577 SkPath operand; 1578 element->asPath(&operand); 1579 SkRegion::Op elementOp = element->getOp(); 1580 if (elementOp == SkRegion::kReplace_Op) { 1581 devPath = operand; 1582 } else { 1583 Op(devPath, operand, (SkPathOp) elementOp, &devPath); 1584 } 1585 // if the prev and curr clips disagree about aa -vs- not, favor the aa request. 1586 // perhaps we need an API change to avoid this sort of mixed-signals about 1587 // clipping. 1588 if (element->isAA()) { 1589 edgeStyle = kSoft_ClipEdgeStyle; 1590 } 1591 } 1592 op = SkRegion::kReplace_Op; 1593 } 1594 1595 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, edgeStyle); 1596} 1597 1598void SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op, 1599 bool inverseFilled) { 1600 // This is for updating the clip conservatively using only bounds 1601 // information. 1602 // Contract: 1603 // The current clip must contain the true clip. The true 1604 // clip is the clip that would have normally been computed 1605 // by calls to clipPath and clipRRect 1606 // Objective: 1607 // Keep the current clip as small as possible without 1608 // breaking the contract, using only clip bounding rectangles 1609 // (for performance). 1610 1611 // N.B.: This *never* calls back through a virtual on canvas, so subclasses 1612 // don't have to worry about getting caught in a loop. Thus anywhere 1613 // we call a virtual method, we explicitly prefix it with 1614 // SkCanvas:: to be sure to call the base-class. 1615 1616 if (inverseFilled) { 1617 switch (op) { 1618 case SkRegion::kIntersect_Op: 1619 case SkRegion::kDifference_Op: 1620 // These ops can only shrink the current clip. So leaving 1621 // the clip unchanged conservatively respects the contract. 1622 break; 1623 case SkRegion::kUnion_Op: 1624 case SkRegion::kReplace_Op: 1625 case SkRegion::kReverseDifference_Op: 1626 case SkRegion::kXOR_Op: { 1627 // These ops can grow the current clip up to the extents of 1628 // the input clip, which is inverse filled, so we just set 1629 // the current clip to the device bounds. 1630 SkRect deviceBounds; 1631 SkIRect deviceIBounds; 1632 this->getDevice()->getGlobalBounds(&deviceIBounds); 1633 deviceBounds = SkRect::Make(deviceIBounds); 1634 this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag); 1635 // set the clip in device space 1636 this->SkCanvas::setMatrix(SkMatrix::I()); 1637 this->SkCanvas::onClipRect(deviceBounds, SkRegion::kReplace_Op, 1638 kHard_ClipEdgeStyle); 1639 this->SkCanvas::restore(); //pop the matrix, but keep the clip 1640 break; 1641 } 1642 default: 1643 SkASSERT(0); // unhandled op? 1644 } 1645 } else { 1646 // Not inverse filled 1647 switch (op) { 1648 case SkRegion::kIntersect_Op: 1649 case SkRegion::kUnion_Op: 1650 case SkRegion::kReplace_Op: 1651 this->SkCanvas::onClipRect(bounds, op, kHard_ClipEdgeStyle); 1652 break; 1653 case SkRegion::kDifference_Op: 1654 // Difference can only shrink the current clip. 1655 // Leaving clip unchanged conservatively fullfills the contract. 1656 break; 1657 case SkRegion::kReverseDifference_Op: 1658 // To reverse, we swap in the bounds with a replace op. 1659 // As with difference, leave it unchanged. 1660 this->SkCanvas::onClipRect(bounds, SkRegion::kReplace_Op, kHard_ClipEdgeStyle); 1661 break; 1662 case SkRegion::kXOR_Op: 1663 // Be conservative, based on (A XOR B) always included in (A union B), 1664 // which is always included in (bounds(A) union bounds(B)) 1665 this->SkCanvas::onClipRect(bounds, SkRegion::kUnion_Op, kHard_ClipEdgeStyle); 1666 break; 1667 default: 1668 SkASSERT(0); // unhandled op? 1669 } 1670 } 1671} 1672 1673void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1674 this->onClipRegion(rgn, op); 1675} 1676 1677void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { 1678 AutoValidateClip avc(this); 1679 1680 fDeviceCMDirty = true; 1681 fCachedLocalClipBoundsDirty = true; 1682 1683 // todo: signal fClipStack that we have a region, and therefore (I guess) 1684 // we have to ignore it, and use the region directly? 1685 fClipStack.clipDevRect(rgn.getBounds(), op); 1686 1687 fMCRec->fRasterClip->op(rgn, op); 1688} 1689 1690#ifdef SK_DEBUG 1691void SkCanvas::validateClip() const { 1692 // construct clipRgn from the clipstack 1693 const SkBaseDevice* device = this->getDevice(); 1694 if (!device) { 1695 SkASSERT(this->isClipEmpty()); 1696 return; 1697 } 1698 1699 SkIRect ir; 1700 ir.set(0, 0, device->width(), device->height()); 1701 SkRasterClip tmpClip(ir); 1702 1703 SkClipStack::B2TIter iter(fClipStack); 1704 const SkClipStack::Element* element; 1705 while ((element = iter.next()) != NULL) { 1706 switch (element->getType()) { 1707 case SkClipStack::Element::kRect_Type: 1708 element->getRect().round(&ir); 1709 tmpClip.op(ir, element->getOp()); 1710 break; 1711 case SkClipStack::Element::kEmpty_Type: 1712 tmpClip.setEmpty(); 1713 break; 1714 default: { 1715 SkPath path; 1716 element->asPath(&path); 1717 clip_path_helper(this, &tmpClip, path, element->getOp(), element->isAA()); 1718 break; 1719 } 1720 } 1721 } 1722} 1723#endif 1724 1725void SkCanvas::replayClips(ClipVisitor* visitor) const { 1726 SkClipStack::B2TIter iter(fClipStack); 1727 const SkClipStack::Element* element; 1728 1729 static const SkRect kEmpty = { 0, 0, 0, 0 }; 1730 while ((element = iter.next()) != NULL) { 1731 switch (element->getType()) { 1732 case SkClipStack::Element::kPath_Type: 1733 visitor->clipPath(element->getPath(), element->getOp(), element->isAA()); 1734 break; 1735 case SkClipStack::Element::kRRect_Type: 1736 visitor->clipRRect(element->getRRect(), element->getOp(), element->isAA()); 1737 break; 1738 case SkClipStack::Element::kRect_Type: 1739 visitor->clipRect(element->getRect(), element->getOp(), element->isAA()); 1740 break; 1741 case SkClipStack::Element::kEmpty_Type: 1742 visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false); 1743 break; 1744 } 1745 } 1746} 1747 1748/////////////////////////////////////////////////////////////////////////////// 1749 1750bool SkCanvas::isClipEmpty() const { 1751 return fMCRec->fRasterClip->isEmpty(); 1752} 1753 1754bool SkCanvas::isClipRect() const { 1755 return fMCRec->fRasterClip->isRect(); 1756} 1757 1758bool SkCanvas::quickReject(const SkRect& rect) const { 1759 1760 if (!rect.isFinite()) 1761 return true; 1762 1763 if (fMCRec->fRasterClip->isEmpty()) { 1764 return true; 1765 } 1766 1767 if (fMCRec->fMatrix->hasPerspective()) { 1768 SkRect dst; 1769 fMCRec->fMatrix->mapRect(&dst, rect); 1770 SkIRect idst; 1771 dst.roundOut(&idst); 1772 return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds()); 1773 } else { 1774 const SkRect& clipR = this->getLocalClipBounds(); 1775 1776 // for speed, do the most likely reject compares first 1777 // TODO: should we use | instead, or compare all 4 at once? 1778 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) { 1779 return true; 1780 } 1781 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) { 1782 return true; 1783 } 1784 return false; 1785 } 1786} 1787 1788bool SkCanvas::quickReject(const SkPath& path) const { 1789 return path.isEmpty() || this->quickReject(path.getBounds()); 1790} 1791 1792bool SkCanvas::getClipBounds(SkRect* bounds) const { 1793 SkIRect ibounds; 1794 if (!this->getClipDeviceBounds(&ibounds)) { 1795 return false; 1796 } 1797 1798 SkMatrix inverse; 1799 // if we can't invert the CTM, we can't return local clip bounds 1800 if (!fMCRec->fMatrix->invert(&inverse)) { 1801 if (bounds) { 1802 bounds->setEmpty(); 1803 } 1804 return false; 1805 } 1806 1807 if (NULL != bounds) { 1808 SkRect r; 1809 // adjust it outwards in case we are antialiasing 1810 const int inset = 1; 1811 1812 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset, 1813 ibounds.fRight + inset, ibounds.fBottom + inset); 1814 inverse.mapRect(bounds, r); 1815 } 1816 return true; 1817} 1818 1819bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const { 1820 const SkRasterClip& clip = *fMCRec->fRasterClip; 1821 if (clip.isEmpty()) { 1822 if (bounds) { 1823 bounds->setEmpty(); 1824 } 1825 return false; 1826 } 1827 1828 if (NULL != bounds) { 1829 *bounds = clip.getBounds(); 1830 } 1831 return true; 1832} 1833 1834const SkMatrix& SkCanvas::getTotalMatrix() const { 1835 return *fMCRec->fMatrix; 1836} 1837 1838#ifdef SK_SUPPORT_LEGACY_GETCLIPTYPE 1839SkCanvas::ClipType SkCanvas::getClipType() const { 1840 if (fMCRec->fRasterClip->isEmpty()) { 1841 return kEmpty_ClipType; 1842 } 1843 if (fMCRec->fRasterClip->isRect()) { 1844 return kRect_ClipType; 1845 } 1846 return kComplex_ClipType; 1847} 1848#endif 1849 1850#ifdef SK_SUPPORT_LEGACY_GETTOTALCLIP 1851const SkRegion& SkCanvas::getTotalClip() const { 1852 return fMCRec->fRasterClip->forceGetBW(); 1853} 1854#endif 1855 1856const SkRegion& SkCanvas::internal_private_getTotalClip() const { 1857 return fMCRec->fRasterClip->forceGetBW(); 1858} 1859 1860void SkCanvas::internal_private_getTotalClipAsPath(SkPath* path) const { 1861 path->reset(); 1862 1863 const SkRegion& rgn = fMCRec->fRasterClip->forceGetBW(); 1864 if (rgn.isEmpty()) { 1865 return; 1866 } 1867 (void)rgn.getBoundaryPath(path); 1868} 1869 1870GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() { 1871 SkBaseDevice* dev = this->getTopDevice(); 1872 return dev ? dev->accessRenderTarget() : NULL; 1873} 1874 1875SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) { 1876 SkBaseDevice* device = this->getTopDevice(); 1877 return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL; 1878} 1879 1880GrContext* SkCanvas::getGrContext() { 1881#if SK_SUPPORT_GPU 1882 SkBaseDevice* device = this->getTopDevice(); 1883 if (NULL != device) { 1884 GrRenderTarget* renderTarget = device->accessRenderTarget(); 1885 if (NULL != renderTarget) { 1886 return renderTarget->getContext(); 1887 } 1888 } 1889#endif 1890 1891 return NULL; 1892 1893} 1894 1895void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner, 1896 const SkPaint& paint) { 1897 if (outer.isEmpty()) { 1898 return; 1899 } 1900 if (inner.isEmpty()) { 1901 this->drawRRect(outer, paint); 1902 return; 1903 } 1904 1905 // We don't have this method (yet), but technically this is what we should 1906 // be able to assert... 1907 // SkASSERT(outer.contains(inner)); 1908 // 1909 // For now at least check for containment of bounds 1910 SkASSERT(outer.getBounds().contains(inner.getBounds())); 1911 1912 this->onDrawDRRect(outer, inner, paint); 1913} 1914 1915////////////////////////////////////////////////////////////////////////////// 1916// These are the virtual drawing methods 1917////////////////////////////////////////////////////////////////////////////// 1918 1919void SkCanvas::clear(SkColor color) { 1920 SkDrawIter iter(this); 1921 this->predrawNotify(); 1922 while (iter.next()) { 1923 iter.fDevice->clear(color); 1924 } 1925} 1926 1927void SkCanvas::drawPaint(const SkPaint& paint) { 1928 this->internalDrawPaint(paint); 1929} 1930 1931void SkCanvas::internalDrawPaint(const SkPaint& paint) { 1932 CHECK_SHADER_NOSETCONTEXT(paint); 1933 1934 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL) 1935 1936 while (iter.next()) { 1937 iter.fDevice->drawPaint(iter, looper.paint()); 1938 } 1939 1940 LOOPER_END 1941} 1942 1943void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1944 const SkPaint& paint) { 1945 if ((long)count <= 0) { 1946 return; 1947 } 1948 1949 CHECK_SHADER_NOSETCONTEXT(paint); 1950 1951 SkRect r, storage; 1952 const SkRect* bounds = NULL; 1953 if (paint.canComputeFastBounds()) { 1954 // special-case 2 points (common for drawing a single line) 1955 if (2 == count) { 1956 r.set(pts[0], pts[1]); 1957 } else { 1958 r.set(pts, SkToInt(count)); 1959 } 1960 bounds = &paint.computeFastStrokeBounds(r, &storage); 1961 if (this->quickReject(*bounds)) { 1962 return; 1963 } 1964 } 1965 1966 SkASSERT(pts != NULL); 1967 1968 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds) 1969 1970 while (iter.next()) { 1971 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); 1972 } 1973 1974 LOOPER_END 1975} 1976 1977void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1978 CHECK_SHADER_NOSETCONTEXT(paint); 1979 1980 SkRect storage; 1981 const SkRect* bounds = NULL; 1982 if (paint.canComputeFastBounds()) { 1983 bounds = &paint.computeFastBounds(r, &storage); 1984 if (this->quickReject(*bounds)) { 1985 return; 1986 } 1987 } 1988 1989 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds) 1990 1991 while (iter.next()) { 1992 iter.fDevice->drawRect(iter, r, looper.paint()); 1993 } 1994 1995 LOOPER_END 1996} 1997 1998void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1999 CHECK_SHADER_NOSETCONTEXT(paint); 2000 2001 SkRect storage; 2002 const SkRect* bounds = NULL; 2003 if (paint.canComputeFastBounds()) { 2004 bounds = &paint.computeFastBounds(oval, &storage); 2005 if (this->quickReject(*bounds)) { 2006 return; 2007 } 2008 } 2009 2010 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds) 2011 2012 while (iter.next()) { 2013 iter.fDevice->drawOval(iter, oval, looper.paint()); 2014 } 2015 2016 LOOPER_END 2017} 2018 2019void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 2020 CHECK_SHADER_NOSETCONTEXT(paint); 2021 2022 SkRect storage; 2023 const SkRect* bounds = NULL; 2024 if (paint.canComputeFastBounds()) { 2025 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage); 2026 if (this->quickReject(*bounds)) { 2027 return; 2028 } 2029 } 2030 2031 if (rrect.isRect()) { 2032 // call the non-virtual version 2033 this->SkCanvas::drawRect(rrect.getBounds(), paint); 2034 return; 2035 } else if (rrect.isOval()) { 2036 // call the non-virtual version 2037 this->SkCanvas::drawOval(rrect.getBounds(), paint); 2038 return; 2039 } 2040 2041 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) 2042 2043 while (iter.next()) { 2044 iter.fDevice->drawRRect(iter, rrect, looper.paint()); 2045 } 2046 2047 LOOPER_END 2048} 2049 2050void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, 2051 const SkPaint& paint) { 2052 CHECK_SHADER_NOSETCONTEXT(paint); 2053 2054 SkRect storage; 2055 const SkRect* bounds = NULL; 2056 if (paint.canComputeFastBounds()) { 2057 bounds = &paint.computeFastBounds(outer.getBounds(), &storage); 2058 if (this->quickReject(*bounds)) { 2059 return; 2060 } 2061 } 2062 2063 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) 2064 2065 while (iter.next()) { 2066 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint()); 2067 } 2068 2069 LOOPER_END 2070} 2071 2072void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 2073 CHECK_SHADER_NOSETCONTEXT(paint); 2074 2075 if (!path.isFinite()) { 2076 return; 2077 } 2078 2079 SkRect storage; 2080 const SkRect* bounds = NULL; 2081 if (!path.isInverseFillType() && paint.canComputeFastBounds()) { 2082 const SkRect& pathBounds = path.getBounds(); 2083 bounds = &paint.computeFastBounds(pathBounds, &storage); 2084 if (this->quickReject(*bounds)) { 2085 return; 2086 } 2087 } 2088 2089 const SkRect& r = path.getBounds(); 2090 if (r.width() <= 0 && r.height() <= 0) { 2091 if (path.isInverseFillType()) { 2092 this->internalDrawPaint(paint); 2093 } 2094 return; 2095 } 2096 2097 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds) 2098 2099 while (iter.next()) { 2100 iter.fDevice->drawPath(iter, path, looper.paint()); 2101 } 2102 2103 LOOPER_END 2104} 2105 2106void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, 2107 const SkPaint* paint) { 2108 SkDEBUGCODE(bitmap.validate();) 2109 2110 if (NULL == paint || paint->canComputeFastBounds()) { 2111 SkRect bounds = { 2112 x, y, 2113 x + SkIntToScalar(bitmap.width()), 2114 y + SkIntToScalar(bitmap.height()) 2115 }; 2116 if (paint) { 2117 (void)paint->computeFastBounds(bounds, &bounds); 2118 } 2119 if (this->quickReject(bounds)) { 2120 return; 2121 } 2122 } 2123 2124 SkMatrix matrix; 2125 matrix.setTranslate(x, y); 2126 this->internalDrawBitmap(bitmap, matrix, paint); 2127} 2128 2129// this one is non-virtual, so it can be called safely by other canvas apis 2130void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, 2131 const SkRect& dst, const SkPaint* paint, 2132 DrawBitmapRectFlags flags) { 2133 if (bitmap.drawsNothing() || dst.isEmpty()) { 2134 return; 2135 } 2136 2137 CHECK_LOCKCOUNT_BALANCE(bitmap); 2138 2139 SkRect storage; 2140 const SkRect* bounds = &dst; 2141 if (NULL == paint || paint->canComputeFastBounds()) { 2142 if (paint) { 2143 bounds = &paint->computeFastBounds(dst, &storage); 2144 } 2145 if (this->quickReject(*bounds)) { 2146 return; 2147 } 2148 } 2149 2150 SkLazyPaint lazy; 2151 if (NULL == paint) { 2152 paint = lazy.init(); 2153 } 2154 2155 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) 2156 2157 while (iter.next()) { 2158 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags); 2159 } 2160 2161 LOOPER_END 2162} 2163 2164void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, 2165 const SkRect& dst, const SkPaint* paint, 2166 DrawBitmapRectFlags flags) { 2167 SkDEBUGCODE(bitmap.validate();) 2168 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags); 2169} 2170 2171void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 2172 const SkPaint* paint) { 2173 SkDEBUGCODE(bitmap.validate();) 2174 this->internalDrawBitmap(bitmap, matrix, paint); 2175} 2176 2177void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap, 2178 const SkIRect& center, const SkRect& dst, 2179 const SkPaint* paint) { 2180 if (bitmap.drawsNothing()) { 2181 return; 2182 } 2183 if (NULL == paint || paint->canComputeFastBounds()) { 2184 SkRect storage; 2185 const SkRect* bounds = &dst; 2186 if (paint) { 2187 bounds = &paint->computeFastBounds(dst, &storage); 2188 } 2189 if (this->quickReject(*bounds)) { 2190 return; 2191 } 2192 } 2193 2194 const int32_t w = bitmap.width(); 2195 const int32_t h = bitmap.height(); 2196 2197 SkIRect c = center; 2198 // pin center to the bounds of the bitmap 2199 c.fLeft = SkMax32(0, center.fLeft); 2200 c.fTop = SkMax32(0, center.fTop); 2201 c.fRight = SkPin32(center.fRight, c.fLeft, w); 2202 c.fBottom = SkPin32(center.fBottom, c.fTop, h); 2203 2204 const SkScalar srcX[4] = { 2205 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w) 2206 }; 2207 const SkScalar srcY[4] = { 2208 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h) 2209 }; 2210 SkScalar dstX[4] = { 2211 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft), 2212 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight 2213 }; 2214 SkScalar dstY[4] = { 2215 dst.fTop, dst.fTop + SkIntToScalar(c.fTop), 2216 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom 2217 }; 2218 2219 if (dstX[1] > dstX[2]) { 2220 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width()); 2221 dstX[2] = dstX[1]; 2222 } 2223 2224 if (dstY[1] > dstY[2]) { 2225 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height()); 2226 dstY[2] = dstY[1]; 2227 } 2228 2229 for (int y = 0; y < 3; y++) { 2230 SkRect s, d; 2231 2232 s.fTop = srcY[y]; 2233 s.fBottom = srcY[y+1]; 2234 d.fTop = dstY[y]; 2235 d.fBottom = dstY[y+1]; 2236 for (int x = 0; x < 3; x++) { 2237 s.fLeft = srcX[x]; 2238 s.fRight = srcX[x+1]; 2239 d.fLeft = dstX[x]; 2240 d.fRight = dstX[x+1]; 2241 this->internalDrawBitmapRect(bitmap, &s, d, paint, 2242 kNone_DrawBitmapRectFlag); 2243 } 2244 } 2245} 2246 2247void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 2248 const SkRect& dst, const SkPaint* paint) { 2249 SkDEBUGCODE(bitmap.validate();) 2250 2251 // Need a device entry-point, so gpu can use a mesh 2252 this->internalDrawBitmapNine(bitmap, center, dst, paint); 2253} 2254 2255class SkDeviceFilteredPaint { 2256public: 2257 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) { 2258 SkBaseDevice::TextFlags flags; 2259 if (device->filterTextFlags(paint, &flags)) { 2260 SkPaint* newPaint = fLazy.set(paint); 2261 newPaint->setFlags(flags.fFlags); 2262 newPaint->setHinting(flags.fHinting); 2263 fPaint = newPaint; 2264 } else { 2265 fPaint = &paint; 2266 } 2267 } 2268 2269 const SkPaint& paint() const { return *fPaint; } 2270 2271private: 2272 const SkPaint* fPaint; 2273 SkLazyPaint fLazy; 2274}; 2275 2276void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, 2277 const SkRect& r, SkScalar textSize) { 2278 if (paint.getStyle() == SkPaint::kFill_Style) { 2279 draw.fDevice->drawRect(draw, r, paint); 2280 } else { 2281 SkPaint p(paint); 2282 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); 2283 draw.fDevice->drawRect(draw, r, p); 2284 } 2285} 2286 2287void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, 2288 const char text[], size_t byteLength, 2289 SkScalar x, SkScalar y) { 2290 SkASSERT(byteLength == 0 || text != NULL); 2291 2292 // nothing to draw 2293 if (text == NULL || byteLength == 0 || 2294 draw.fClip->isEmpty() || 2295 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 2296 return; 2297 } 2298 2299 SkScalar width = 0; 2300 SkPoint start; 2301 2302 start.set(0, 0); // to avoid warning 2303 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | 2304 SkPaint::kStrikeThruText_Flag)) { 2305 width = paint.measureText(text, byteLength); 2306 2307 SkScalar offsetX = 0; 2308 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 2309 offsetX = SkScalarHalf(width); 2310 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { 2311 offsetX = width; 2312 } 2313 start.set(x - offsetX, y); 2314 } 2315 2316 if (0 == width) { 2317 return; 2318 } 2319 2320 uint32_t flags = paint.getFlags(); 2321 2322 if (flags & (SkPaint::kUnderlineText_Flag | 2323 SkPaint::kStrikeThruText_Flag)) { 2324 SkScalar textSize = paint.getTextSize(); 2325 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 2326 SkRect r; 2327 2328 r.fLeft = start.fX; 2329 r.fRight = start.fX + width; 2330 2331 if (flags & SkPaint::kUnderlineText_Flag) { 2332 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, 2333 start.fY); 2334 r.fTop = offset; 2335 r.fBottom = offset + height; 2336 DrawRect(draw, paint, r, textSize); 2337 } 2338 if (flags & SkPaint::kStrikeThruText_Flag) { 2339 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, 2340 start.fY); 2341 r.fTop = offset; 2342 r.fBottom = offset + height; 2343 DrawRect(draw, paint, r, textSize); 2344 } 2345 } 2346} 2347 2348void SkCanvas::drawText(const void* text, size_t byteLength, 2349 SkScalar x, SkScalar y, const SkPaint& paint) { 2350 CHECK_SHADER_NOSETCONTEXT(paint); 2351 2352 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2353 2354 while (iter.next()) { 2355 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2356 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 2357 DrawTextDecorations(iter, dfp.paint(), 2358 static_cast<const char*>(text), byteLength, x, y); 2359 } 2360 2361 LOOPER_END 2362} 2363 2364void SkCanvas::drawPosText(const void* text, size_t byteLength, 2365 const SkPoint pos[], const SkPaint& paint) { 2366 CHECK_SHADER_NOSETCONTEXT(paint); 2367 2368 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2369 2370 while (iter.next()) { 2371 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2372 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 2373 dfp.paint()); 2374 } 2375 2376 LOOPER_END 2377} 2378 2379void SkCanvas::drawPosTextH(const void* text, size_t byteLength, 2380 const SkScalar xpos[], SkScalar constY, 2381 const SkPaint& paint) { 2382 CHECK_SHADER_NOSETCONTEXT(paint); 2383 2384 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2385 2386 while (iter.next()) { 2387 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2388 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 2389 dfp.paint()); 2390 } 2391 2392 LOOPER_END 2393} 2394 2395void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, 2396 const SkPath& path, const SkMatrix* matrix, 2397 const SkPaint& paint) { 2398 CHECK_SHADER_NOSETCONTEXT(paint); 2399 2400 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2401 2402 while (iter.next()) { 2403 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 2404 matrix, looper.paint()); 2405 } 2406 2407 LOOPER_END 2408} 2409 2410void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 2411 const SkPoint verts[], const SkPoint texs[], 2412 const SkColor colors[], SkXfermode* xmode, 2413 const uint16_t indices[], int indexCount, 2414 const SkPaint& paint) { 2415 CHECK_SHADER_NOSETCONTEXT(paint); 2416 2417 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL) 2418 2419 while (iter.next()) { 2420 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 2421 colors, xmode, indices, indexCount, 2422 looper.paint()); 2423 } 2424 2425 LOOPER_END 2426} 2427 2428////////////////////////////////////////////////////////////////////////////// 2429// These methods are NOT virtual, and therefore must call back into virtual 2430// methods, rather than actually drawing themselves. 2431////////////////////////////////////////////////////////////////////////////// 2432 2433void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 2434 SkXfermode::Mode mode) { 2435 SkPaint paint; 2436 2437 paint.setARGB(a, r, g, b); 2438 if (SkXfermode::kSrcOver_Mode != mode) { 2439 paint.setXfermodeMode(mode); 2440 } 2441 this->drawPaint(paint); 2442} 2443 2444void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 2445 SkPaint paint; 2446 2447 paint.setColor(c); 2448 if (SkXfermode::kSrcOver_Mode != mode) { 2449 paint.setXfermodeMode(mode); 2450 } 2451 this->drawPaint(paint); 2452} 2453 2454void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 2455 SkPoint pt; 2456 2457 pt.set(x, y); 2458 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2459} 2460 2461void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 2462 SkPoint pt; 2463 SkPaint paint; 2464 2465 pt.set(x, y); 2466 paint.setColor(color); 2467 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2468} 2469 2470void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 2471 const SkPaint& paint) { 2472 SkPoint pts[2]; 2473 2474 pts[0].set(x0, y0); 2475 pts[1].set(x1, y1); 2476 this->drawPoints(kLines_PointMode, 2, pts, paint); 2477} 2478 2479void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 2480 SkScalar right, SkScalar bottom, 2481 const SkPaint& paint) { 2482 SkRect r; 2483 2484 r.set(left, top, right, bottom); 2485 this->drawRect(r, paint); 2486} 2487 2488void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 2489 const SkPaint& paint) { 2490 if (radius < 0) { 2491 radius = 0; 2492 } 2493 2494 SkRect r; 2495 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 2496 this->drawOval(r, paint); 2497} 2498 2499void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 2500 const SkPaint& paint) { 2501 if (rx > 0 && ry > 0) { 2502 if (paint.canComputeFastBounds()) { 2503 SkRect storage; 2504 if (this->quickReject(paint.computeFastBounds(r, &storage))) { 2505 return; 2506 } 2507 } 2508 SkRRect rrect; 2509 rrect.setRectXY(r, rx, ry); 2510 this->drawRRect(rrect, paint); 2511 } else { 2512 this->drawRect(r, paint); 2513 } 2514} 2515 2516void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 2517 SkScalar sweepAngle, bool useCenter, 2518 const SkPaint& paint) { 2519 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 2520 this->drawOval(oval, paint); 2521 } else { 2522 SkPath path; 2523 if (useCenter) { 2524 path.moveTo(oval.centerX(), oval.centerY()); 2525 } 2526 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 2527 if (useCenter) { 2528 path.close(); 2529 } 2530 this->drawPath(path, paint); 2531 } 2532} 2533 2534void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 2535 const SkPath& path, SkScalar hOffset, 2536 SkScalar vOffset, const SkPaint& paint) { 2537 SkMatrix matrix; 2538 2539 matrix.setTranslate(hOffset, vOffset); 2540 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 2541} 2542 2543/////////////////////////////////////////////////////////////////////////////// 2544void SkCanvas::EXPERIMENTAL_optimize(SkPicture* picture) { 2545 SkBaseDevice* device = this->getDevice(); 2546 if (NULL != device) { 2547 device->EXPERIMENTAL_optimize(picture); 2548 } 2549} 2550 2551void SkCanvas::drawPicture(SkPicture& picture) { 2552 SkBaseDevice* device = this->getTopDevice(); 2553 if (NULL != device) { 2554 // Canvas has to first give the device the opportunity to render 2555 // the picture itself. 2556 if (device->EXPERIMENTAL_drawPicture(picture)) { 2557 return; // the device has rendered the entire picture 2558 } 2559 } 2560 2561 picture.draw(this); 2562} 2563 2564/////////////////////////////////////////////////////////////////////////////// 2565/////////////////////////////////////////////////////////////////////////////// 2566 2567SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 2568 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); 2569 2570 SkASSERT(canvas); 2571 2572 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 2573 fDone = !fImpl->next(); 2574} 2575 2576SkCanvas::LayerIter::~LayerIter() { 2577 fImpl->~SkDrawIter(); 2578} 2579 2580void SkCanvas::LayerIter::next() { 2581 fDone = !fImpl->next(); 2582} 2583 2584SkBaseDevice* SkCanvas::LayerIter::device() const { 2585 return fImpl->getDevice(); 2586} 2587 2588const SkMatrix& SkCanvas::LayerIter::matrix() const { 2589 return fImpl->getMatrix(); 2590} 2591 2592const SkPaint& SkCanvas::LayerIter::paint() const { 2593 const SkPaint* paint = fImpl->getPaint(); 2594 if (NULL == paint) { 2595 paint = &fDefaultPaint; 2596 } 2597 return *paint; 2598} 2599 2600const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 2601int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 2602int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 2603 2604/////////////////////////////////////////////////////////////////////////////// 2605 2606SkCanvas::ClipVisitor::~ClipVisitor() { } 2607 2608/////////////////////////////////////////////////////////////////////////////// 2609 2610static bool supported_for_raster_canvas(const SkImageInfo& info) { 2611 switch (info.alphaType()) { 2612 case kPremul_SkAlphaType: 2613 case kOpaque_SkAlphaType: 2614 break; 2615 default: 2616 return false; 2617 } 2618 2619 switch (info.colorType()) { 2620 case kAlpha_8_SkColorType: 2621 case kRGB_565_SkColorType: 2622 case kPMColor_SkColorType: 2623 break; 2624 default: 2625 return false; 2626 } 2627 2628 return true; 2629} 2630 2631SkCanvas* SkCanvas::NewRaster(const SkImageInfo& info) { 2632 if (!supported_for_raster_canvas(info)) { 2633 return NULL; 2634 } 2635 2636 SkBitmap bitmap; 2637 if (!bitmap.allocPixels(info)) { 2638 return NULL; 2639 } 2640 2641 // should this functionality be moved into allocPixels()? 2642 if (!bitmap.info().isOpaque()) { 2643 bitmap.eraseColor(0); 2644 } 2645 return SkNEW_ARGS(SkCanvas, (bitmap)); 2646} 2647 2648SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) { 2649 if (!supported_for_raster_canvas(info)) { 2650 return NULL; 2651 } 2652 2653 SkBitmap bitmap; 2654 if (!bitmap.installPixels(info, pixels, rowBytes)) { 2655 return NULL; 2656 } 2657 2658 // should this functionality be moved into allocPixels()? 2659 if (!bitmap.info().isOpaque()) { 2660 bitmap.eraseColor(0); 2661 } 2662 return SkNEW_ARGS(SkCanvas, (bitmap)); 2663} 2664