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