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