SkCanvas.cpp revision 87fcd950198a16211b3988610beebb5ca5bcf323
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, SkIPoint* origin) { 1088 void* pixels = this->onAccessTopLayerPixels(info, rowBytes); 1089 if (pixels && origin) { 1090 *origin = this->getTopDevice(false)->getOrigin(); 1091 } 1092 return pixels; 1093} 1094 1095void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) { 1096 SkBaseDevice* dev = this->getTopDevice(); 1097 return dev ? dev->accessPixels(info, rowBytes) : NULL; 1098} 1099 1100SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) { 1101 fAddr = canvas->peekPixels(&fInfo, &fRowBytes); 1102 if (NULL == fAddr) { 1103 fInfo = canvas->imageInfo(); 1104 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.allocPixels(fInfo)) { 1105 return; // failure, fAddr is NULL 1106 } 1107 if (!canvas->readPixels(&fBitmap, 0, 0)) { 1108 return; // failure, fAddr is NULL 1109 } 1110 fAddr = fBitmap.getPixels(); 1111 fRowBytes = fBitmap.rowBytes(); 1112 } 1113 SkASSERT(fAddr); // success 1114} 1115 1116bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const { 1117 if (fAddr) { 1118 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes, 1119 NULL, NULL); 1120 } else { 1121 bitmap->reset(); 1122 return false; 1123 } 1124} 1125 1126void SkCanvas::onPushCull(const SkRect& cullRect) { 1127 // do nothing. Subclasses may do something 1128} 1129 1130void SkCanvas::onPopCull() { 1131 // do nothing. Subclasses may do something 1132} 1133 1134///////////////////////////////////////////////////////////////////////////// 1135#ifdef SK_DEBUG 1136// Ensure that cull rects are monotonically nested in device space. 1137void SkCanvas::validateCull(const SkIRect& devCull) { 1138 if (fCullStack.isEmpty() 1139 || devCull.isEmpty() 1140 || fCullStack.top().contains(devCull)) { 1141 return; 1142 } 1143 1144 SkDEBUGF(("Invalid cull: [%d %d %d %d] (previous cull: [%d %d %d %d])\n", 1145 devCull.x(), devCull.y(), devCull.right(), devCull.bottom(), 1146 fCullStack.top().x(), fCullStack.top().y(), 1147 fCullStack.top().right(), fCullStack.top().bottom())); 1148 1149#ifdef ASSERT_NESTED_CULLING 1150 SkDEBUGFAIL("Invalid cull."); 1151#endif 1152} 1153#endif 1154 1155void SkCanvas::pushCull(const SkRect& cullRect) { 1156 ++fCullCount; 1157 this->onPushCull(cullRect); 1158 1159#ifdef SK_DEBUG 1160 // Map the cull rect into device space. 1161 SkRect mappedCull; 1162 this->getTotalMatrix().mapRect(&mappedCull, cullRect); 1163 1164 // Take clipping into account. 1165 SkIRect devClip, devCull; 1166 mappedCull.roundOut(&devCull); 1167 this->getClipDeviceBounds(&devClip); 1168 if (!devCull.intersect(devClip)) { 1169 devCull.setEmpty(); 1170 } 1171 1172 this->validateCull(devCull); 1173 fCullStack.push(devCull); // balanced in popCull 1174#endif 1175} 1176 1177void SkCanvas::popCull() { 1178 SkASSERT(fCullStack.count() == fCullCount); 1179 1180 if (fCullCount > 0) { 1181 --fCullCount; 1182 this->onPopCull(); 1183 1184 SkDEBUGCODE(fCullStack.pop()); 1185 } 1186} 1187 1188///////////////////////////////////////////////////////////////////////////// 1189 1190void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, 1191 const SkMatrix& matrix, const SkPaint* paint) { 1192 if (bitmap.drawsNothing()) { 1193 return; 1194 } 1195 1196 SkLazyPaint lazy; 1197 if (NULL == paint) { 1198 paint = lazy.init(); 1199 } 1200 1201 SkDEBUGCODE(bitmap.validate();) 1202 CHECK_LOCKCOUNT_BALANCE(bitmap); 1203 1204 SkRect storage; 1205 const SkRect* bounds = NULL; 1206 if (paint && paint->canComputeFastBounds()) { 1207 bitmap.getBounds(&storage); 1208 matrix.mapRect(&storage); 1209 bounds = &paint->computeFastBounds(storage, &storage); 1210 } 1211 1212 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) 1213 1214 while (iter.next()) { 1215 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint()); 1216 } 1217 1218 LOOPER_END 1219} 1220 1221void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, 1222 const SkPaint* paint) { 1223 SkPaint tmp; 1224 if (NULL == paint) { 1225 tmp.setDither(true); 1226 paint = &tmp; 1227 } 1228 1229 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 1230 while (iter.next()) { 1231 SkBaseDevice* dstDev = iter.fDevice; 1232 paint = &looper.paint(); 1233 SkImageFilter* filter = paint->getImageFilter(); 1234 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 1235 if (filter && !dstDev->canHandleImageFilter(filter)) { 1236 SkDeviceImageFilterProxy proxy(dstDev); 1237 SkBitmap dst; 1238 SkIPoint offset = SkIPoint::Make(0, 0); 1239 const SkBitmap& src = srcDev->accessBitmap(false); 1240 SkMatrix matrix = *iter.fMatrix; 1241 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y())); 1242 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height()); 1243 SkImageFilter::Cache* cache = SkImageFilter::GetExternalCache(); 1244 SkAutoUnref aur(NULL); 1245 if (!cache) { 1246 cache = SkImageFilter::Cache::Create(); 1247 aur.reset(cache); 1248 } 1249 SkImageFilter::Context ctx(matrix, clipBounds, cache); 1250 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) { 1251 SkPaint tmpUnfiltered(*paint); 1252 tmpUnfiltered.setImageFilter(NULL); 1253 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(), 1254 tmpUnfiltered); 1255 } 1256 } else { 1257 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint); 1258 } 1259 } 1260 LOOPER_END 1261} 1262 1263void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, 1264 const SkPaint* paint) { 1265 if (bitmap.drawsNothing()) { 1266 return; 1267 } 1268 SkDEBUGCODE(bitmap.validate();) 1269 CHECK_LOCKCOUNT_BALANCE(bitmap); 1270 1271 SkPaint tmp; 1272 if (NULL == paint) { 1273 paint = &tmp; 1274 } 1275 1276 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 1277 1278 while (iter.next()) { 1279 paint = &looper.paint(); 1280 SkImageFilter* filter = paint->getImageFilter(); 1281 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 1282 if (filter && !iter.fDevice->canHandleImageFilter(filter)) { 1283 SkDeviceImageFilterProxy proxy(iter.fDevice); 1284 SkBitmap dst; 1285 SkIPoint offset = SkIPoint::Make(0, 0); 1286 SkMatrix matrix = *iter.fMatrix; 1287 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y())); 1288 SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height()); 1289 SkImageFilter::Cache* cache = SkImageFilter::GetExternalCache(); 1290 SkAutoUnref aur(NULL); 1291 if (!cache) { 1292 cache = SkImageFilter::Cache::Create(); 1293 aur.reset(cache); 1294 } 1295 SkImageFilter::Context ctx(matrix, clipBounds, cache); 1296 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) { 1297 SkPaint tmpUnfiltered(*paint); 1298 tmpUnfiltered.setImageFilter(NULL); 1299 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(), 1300 tmpUnfiltered); 1301 } 1302 } else { 1303 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint); 1304 } 1305 } 1306 LOOPER_END 1307} 1308 1309///////////////////////////////////////////////////////////////////////////// 1310void SkCanvas::translate(SkScalar dx, SkScalar dy) { 1311 SkMatrix m; 1312 m.setTranslate(dx, dy); 1313 this->concat(m); 1314} 1315 1316void SkCanvas::scale(SkScalar sx, SkScalar sy) { 1317 SkMatrix m; 1318 m.setScale(sx, sy); 1319 this->concat(m); 1320} 1321 1322void SkCanvas::rotate(SkScalar degrees) { 1323 SkMatrix m; 1324 m.setRotate(degrees); 1325 this->concat(m); 1326} 1327 1328void SkCanvas::skew(SkScalar sx, SkScalar sy) { 1329 SkMatrix m; 1330 m.setSkew(sx, sy); 1331 this->concat(m); 1332} 1333 1334void SkCanvas::didConcat(const SkMatrix&) { 1335 // Do nothing. Subclasses may do something. 1336} 1337 1338void SkCanvas::concat(const SkMatrix& matrix) { 1339 if (matrix.isIdentity()) { 1340 return; 1341 } 1342 1343 fDeviceCMDirty = true; 1344 fCachedLocalClipBoundsDirty = true; 1345 fMCRec->fMatrix->preConcat(matrix); 1346 1347 this->didConcat(matrix); 1348} 1349 1350void SkCanvas::didSetMatrix(const SkMatrix&) { 1351 // Do nothing. Subclasses may do something. 1352} 1353 1354void SkCanvas::setMatrix(const SkMatrix& matrix) { 1355 fDeviceCMDirty = true; 1356 fCachedLocalClipBoundsDirty = true; 1357 *fMCRec->fMatrix = matrix; 1358 this->didSetMatrix(matrix); 1359} 1360 1361void SkCanvas::resetMatrix() { 1362 SkMatrix matrix; 1363 1364 matrix.reset(); 1365 this->setMatrix(matrix); 1366} 1367 1368////////////////////////////////////////////////////////////////////////////// 1369 1370void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 1371 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1372 this->onClipRect(rect, op, edgeStyle); 1373} 1374 1375void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1376#ifdef SK_ENABLE_CLIP_QUICKREJECT 1377 if (SkRegion::kIntersect_Op == op) { 1378 if (fMCRec->fRasterClip->isEmpty()) { 1379 return false; 1380 } 1381 1382 if (this->quickReject(rect)) { 1383 fDeviceCMDirty = true; 1384 fCachedLocalClipBoundsDirty = true; 1385 1386 fClipStack.clipEmpty(); 1387 return fMCRec->fRasterClip->setEmpty(); 1388 } 1389 } 1390#endif 1391 1392 AutoValidateClip avc(this); 1393 1394 fDeviceCMDirty = true; 1395 fCachedLocalClipBoundsDirty = true; 1396 if (!fAllowSoftClip) { 1397 edgeStyle = kHard_ClipEdgeStyle; 1398 } 1399 1400 if (fMCRec->fMatrix->rectStaysRect()) { 1401 // for these simpler matrices, we can stay a rect even after applying 1402 // the matrix. This means we don't have to a) make a path, and b) tell 1403 // the region code to scan-convert the path, only to discover that it 1404 // is really just a rect. 1405 SkRect r; 1406 1407 fMCRec->fMatrix->mapRect(&r, rect); 1408 fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle); 1409 fMCRec->fRasterClip->op(r, op, kSoft_ClipEdgeStyle == edgeStyle); 1410 } else { 1411 // since we're rotated or some such thing, we convert the rect to a path 1412 // and clip against that, since it can handle any matrix. However, to 1413 // avoid recursion in the case where we are subclassed (e.g. Pictures) 1414 // we explicitly call "our" version of clipPath. 1415 SkPath path; 1416 1417 path.addRect(rect); 1418 this->SkCanvas::onClipPath(path, op, edgeStyle); 1419 } 1420} 1421 1422static void clip_path_helper(const SkCanvas* canvas, SkRasterClip* currClip, 1423 const SkPath& devPath, SkRegion::Op op, bool doAA) { 1424 // base is used to limit the size (and therefore memory allocation) of the 1425 // region that results from scan converting devPath. 1426 SkRegion base; 1427 1428 if (SkRegion::kIntersect_Op == op) { 1429 // since we are intersect, we can do better (tighter) with currRgn's 1430 // bounds, than just using the device. However, if currRgn is complex, 1431 // our region blitter may hork, so we do that case in two steps. 1432 if (currClip->isRect()) { 1433 // FIXME: we should also be able to do this when currClip->isBW(), 1434 // but relaxing the test above triggers GM asserts in 1435 // SkRgnBuilder::blitH(). We need to investigate what's going on. 1436 currClip->setPath(devPath, currClip->bwRgn(), doAA); 1437 } else { 1438 base.setRect(currClip->getBounds()); 1439 SkRasterClip clip; 1440 clip.setPath(devPath, base, doAA); 1441 currClip->op(clip, op); 1442 } 1443 } else { 1444 const SkBaseDevice* device = canvas->getDevice(); 1445 if (!device) { 1446 currClip->setEmpty(); 1447 return; 1448 } 1449 1450 base.setRect(0, 0, device->width(), device->height()); 1451 1452 if (SkRegion::kReplace_Op == op) { 1453 currClip->setPath(devPath, base, doAA); 1454 } else { 1455 SkRasterClip clip; 1456 clip.setPath(devPath, base, doAA); 1457 currClip->op(clip, op); 1458 } 1459 } 1460} 1461 1462void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 1463 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1464 if (rrect.isRect()) { 1465 this->onClipRect(rrect.getBounds(), op, edgeStyle); 1466 } else { 1467 this->onClipRRect(rrect, op, edgeStyle); 1468 } 1469} 1470 1471void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1472 SkRRect transformedRRect; 1473 if (rrect.transform(*fMCRec->fMatrix, &transformedRRect)) { 1474 AutoValidateClip avc(this); 1475 1476 fDeviceCMDirty = true; 1477 fCachedLocalClipBoundsDirty = true; 1478 if (!fAllowSoftClip) { 1479 edgeStyle = kHard_ClipEdgeStyle; 1480 } 1481 1482 fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle); 1483 1484 SkPath devPath; 1485 devPath.addRRect(transformedRRect); 1486 1487 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, kSoft_ClipEdgeStyle == edgeStyle); 1488 return; 1489 } 1490 1491 SkPath path; 1492 path.addRRect(rrect); 1493 // call the non-virtual version 1494 this->SkCanvas::onClipPath(path, op, edgeStyle); 1495} 1496 1497void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 1498 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1499 SkRect r; 1500 if (!path.isInverseFillType() && path.isRect(&r)) { 1501 this->onClipRect(r, op, edgeStyle); 1502 } else { 1503 this->onClipPath(path, op, edgeStyle); 1504 } 1505} 1506 1507void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1508#ifdef SK_ENABLE_CLIP_QUICKREJECT 1509 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { 1510 if (fMCRec->fRasterClip->isEmpty()) { 1511 return false; 1512 } 1513 1514 if (this->quickReject(path.getBounds())) { 1515 fDeviceCMDirty = true; 1516 fCachedLocalClipBoundsDirty = true; 1517 1518 fClipStack.clipEmpty(); 1519 return fMCRec->fRasterClip->setEmpty(); 1520 } 1521 } 1522#endif 1523 1524 AutoValidateClip avc(this); 1525 1526 fDeviceCMDirty = true; 1527 fCachedLocalClipBoundsDirty = true; 1528 if (!fAllowSoftClip) { 1529 edgeStyle = kHard_ClipEdgeStyle; 1530 } 1531 1532 SkPath devPath; 1533 path.transform(*fMCRec->fMatrix, &devPath); 1534 1535 // Check if the transfomation, or the original path itself 1536 // made us empty. Note this can also happen if we contained NaN 1537 // values. computing the bounds detects this, and will set our 1538 // bounds to empty if that is the case. (see SkRect::set(pts, count)) 1539 if (devPath.getBounds().isEmpty()) { 1540 // resetting the path will remove any NaN or other wanky values 1541 // that might upset our scan converter. 1542 devPath.reset(); 1543 } 1544 1545 // if we called path.swap() we could avoid a deep copy of this path 1546 fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle); 1547 1548 if (fAllowSimplifyClip) { 1549 devPath.reset(); 1550 devPath.setFillType(SkPath::kInverseEvenOdd_FillType); 1551 const SkClipStack* clipStack = getClipStack(); 1552 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart); 1553 const SkClipStack::Element* element; 1554 while ((element = iter.next())) { 1555 SkClipStack::Element::Type type = element->getType(); 1556 if (type == SkClipStack::Element::kEmpty_Type) { 1557 continue; 1558 } 1559 SkPath operand; 1560 element->asPath(&operand); 1561 SkRegion::Op elementOp = element->getOp(); 1562 if (elementOp == SkRegion::kReplace_Op) { 1563 devPath = operand; 1564 } else { 1565 Op(devPath, operand, (SkPathOp) elementOp, &devPath); 1566 } 1567 // if the prev and curr clips disagree about aa -vs- not, favor the aa request. 1568 // perhaps we need an API change to avoid this sort of mixed-signals about 1569 // clipping. 1570 if (element->isAA()) { 1571 edgeStyle = kSoft_ClipEdgeStyle; 1572 } 1573 } 1574 op = SkRegion::kReplace_Op; 1575 } 1576 1577 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, edgeStyle); 1578} 1579 1580void SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op, 1581 bool inverseFilled) { 1582 // This is for updating the clip conservatively using only bounds 1583 // information. 1584 // Contract: 1585 // The current clip must contain the true clip. The true 1586 // clip is the clip that would have normally been computed 1587 // by calls to clipPath and clipRRect 1588 // Objective: 1589 // Keep the current clip as small as possible without 1590 // breaking the contract, using only clip bounding rectangles 1591 // (for performance). 1592 1593 // N.B.: This *never* calls back through a virtual on canvas, so subclasses 1594 // don't have to worry about getting caught in a loop. Thus anywhere 1595 // we call a virtual method, we explicitly prefix it with 1596 // SkCanvas:: to be sure to call the base-class. 1597 1598 if (inverseFilled) { 1599 switch (op) { 1600 case SkRegion::kIntersect_Op: 1601 case SkRegion::kDifference_Op: 1602 // These ops can only shrink the current clip. So leaving 1603 // the clip unchanged conservatively respects the contract. 1604 break; 1605 case SkRegion::kUnion_Op: 1606 case SkRegion::kReplace_Op: 1607 case SkRegion::kReverseDifference_Op: 1608 case SkRegion::kXOR_Op: { 1609 // These ops can grow the current clip up to the extents of 1610 // the input clip, which is inverse filled, so we just set 1611 // the current clip to the device bounds. 1612 SkRect deviceBounds; 1613 SkIRect deviceIBounds; 1614 this->getDevice()->getGlobalBounds(&deviceIBounds); 1615 deviceBounds = SkRect::Make(deviceIBounds); 1616 1617 // set the clip in device space 1618 SkMatrix savedMatrix = this->getTotalMatrix(); 1619 this->SkCanvas::setMatrix(SkMatrix::I()); 1620 this->SkCanvas::onClipRect(deviceBounds, SkRegion::kReplace_Op, 1621 kHard_ClipEdgeStyle); 1622 this->setMatrix(savedMatrix); 1623 break; 1624 } 1625 default: 1626 SkASSERT(0); // unhandled op? 1627 } 1628 } else { 1629 // Not inverse filled 1630 switch (op) { 1631 case SkRegion::kIntersect_Op: 1632 case SkRegion::kUnion_Op: 1633 case SkRegion::kReplace_Op: 1634 this->SkCanvas::onClipRect(bounds, op, kHard_ClipEdgeStyle); 1635 break; 1636 case SkRegion::kDifference_Op: 1637 // Difference can only shrink the current clip. 1638 // Leaving clip unchanged conservatively fullfills the contract. 1639 break; 1640 case SkRegion::kReverseDifference_Op: 1641 // To reverse, we swap in the bounds with a replace op. 1642 // As with difference, leave it unchanged. 1643 this->SkCanvas::onClipRect(bounds, SkRegion::kReplace_Op, kHard_ClipEdgeStyle); 1644 break; 1645 case SkRegion::kXOR_Op: 1646 // Be conservative, based on (A XOR B) always included in (A union B), 1647 // which is always included in (bounds(A) union bounds(B)) 1648 this->SkCanvas::onClipRect(bounds, SkRegion::kUnion_Op, kHard_ClipEdgeStyle); 1649 break; 1650 default: 1651 SkASSERT(0); // unhandled op? 1652 } 1653 } 1654} 1655 1656void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1657 this->onClipRegion(rgn, op); 1658} 1659 1660void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { 1661 AutoValidateClip avc(this); 1662 1663 fDeviceCMDirty = true; 1664 fCachedLocalClipBoundsDirty = true; 1665 1666 // todo: signal fClipStack that we have a region, and therefore (I guess) 1667 // we have to ignore it, and use the region directly? 1668 fClipStack.clipDevRect(rgn.getBounds(), op); 1669 1670 fMCRec->fRasterClip->op(rgn, op); 1671} 1672 1673#ifdef SK_DEBUG 1674void SkCanvas::validateClip() const { 1675 // construct clipRgn from the clipstack 1676 const SkBaseDevice* device = this->getDevice(); 1677 if (!device) { 1678 SkASSERT(this->isClipEmpty()); 1679 return; 1680 } 1681 1682 SkIRect ir; 1683 ir.set(0, 0, device->width(), device->height()); 1684 SkRasterClip tmpClip(ir); 1685 1686 SkClipStack::B2TIter iter(fClipStack); 1687 const SkClipStack::Element* element; 1688 while ((element = iter.next()) != NULL) { 1689 switch (element->getType()) { 1690 case SkClipStack::Element::kRect_Type: 1691 element->getRect().round(&ir); 1692 tmpClip.op(ir, element->getOp()); 1693 break; 1694 case SkClipStack::Element::kEmpty_Type: 1695 tmpClip.setEmpty(); 1696 break; 1697 default: { 1698 SkPath path; 1699 element->asPath(&path); 1700 clip_path_helper(this, &tmpClip, path, element->getOp(), element->isAA()); 1701 break; 1702 } 1703 } 1704 } 1705} 1706#endif 1707 1708void SkCanvas::replayClips(ClipVisitor* visitor) const { 1709 SkClipStack::B2TIter iter(fClipStack); 1710 const SkClipStack::Element* element; 1711 1712 static const SkRect kEmpty = { 0, 0, 0, 0 }; 1713 while ((element = iter.next()) != NULL) { 1714 switch (element->getType()) { 1715 case SkClipStack::Element::kPath_Type: 1716 visitor->clipPath(element->getPath(), element->getOp(), element->isAA()); 1717 break; 1718 case SkClipStack::Element::kRRect_Type: 1719 visitor->clipRRect(element->getRRect(), element->getOp(), element->isAA()); 1720 break; 1721 case SkClipStack::Element::kRect_Type: 1722 visitor->clipRect(element->getRect(), element->getOp(), element->isAA()); 1723 break; 1724 case SkClipStack::Element::kEmpty_Type: 1725 visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false); 1726 break; 1727 } 1728 } 1729} 1730 1731/////////////////////////////////////////////////////////////////////////////// 1732 1733bool SkCanvas::isClipEmpty() const { 1734 return fMCRec->fRasterClip->isEmpty(); 1735} 1736 1737bool SkCanvas::isClipRect() const { 1738 return fMCRec->fRasterClip->isRect(); 1739} 1740 1741bool SkCanvas::quickReject(const SkRect& rect) const { 1742 1743 if (!rect.isFinite()) 1744 return true; 1745 1746 if (fMCRec->fRasterClip->isEmpty()) { 1747 return true; 1748 } 1749 1750 if (fMCRec->fMatrix->hasPerspective()) { 1751 SkRect dst; 1752 fMCRec->fMatrix->mapRect(&dst, rect); 1753 SkIRect idst; 1754 dst.roundOut(&idst); 1755 return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds()); 1756 } else { 1757 const SkRect& clipR = this->getLocalClipBounds(); 1758 1759 // for speed, do the most likely reject compares first 1760 // TODO: should we use | instead, or compare all 4 at once? 1761 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) { 1762 return true; 1763 } 1764 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) { 1765 return true; 1766 } 1767 return false; 1768 } 1769} 1770 1771bool SkCanvas::quickReject(const SkPath& path) const { 1772 return path.isEmpty() || this->quickReject(path.getBounds()); 1773} 1774 1775bool SkCanvas::getClipBounds(SkRect* bounds) const { 1776 SkIRect ibounds; 1777 if (!this->getClipDeviceBounds(&ibounds)) { 1778 return false; 1779 } 1780 1781 SkMatrix inverse; 1782 // if we can't invert the CTM, we can't return local clip bounds 1783 if (!fMCRec->fMatrix->invert(&inverse)) { 1784 if (bounds) { 1785 bounds->setEmpty(); 1786 } 1787 return false; 1788 } 1789 1790 if (NULL != bounds) { 1791 SkRect r; 1792 // adjust it outwards in case we are antialiasing 1793 const int inset = 1; 1794 1795 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset, 1796 ibounds.fRight + inset, ibounds.fBottom + inset); 1797 inverse.mapRect(bounds, r); 1798 } 1799 return true; 1800} 1801 1802bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const { 1803 const SkRasterClip& clip = *fMCRec->fRasterClip; 1804 if (clip.isEmpty()) { 1805 if (bounds) { 1806 bounds->setEmpty(); 1807 } 1808 return false; 1809 } 1810 1811 if (NULL != bounds) { 1812 *bounds = clip.getBounds(); 1813 } 1814 return true; 1815} 1816 1817const SkMatrix& SkCanvas::getTotalMatrix() const { 1818 return *fMCRec->fMatrix; 1819} 1820 1821#ifdef SK_SUPPORT_LEGACY_GETCLIPTYPE 1822SkCanvas::ClipType SkCanvas::getClipType() const { 1823 if (fMCRec->fRasterClip->isEmpty()) { 1824 return kEmpty_ClipType; 1825 } 1826 if (fMCRec->fRasterClip->isRect()) { 1827 return kRect_ClipType; 1828 } 1829 return kComplex_ClipType; 1830} 1831#endif 1832 1833#ifdef SK_SUPPORT_LEGACY_GETTOTALCLIP 1834const SkRegion& SkCanvas::getTotalClip() const { 1835 return fMCRec->fRasterClip->forceGetBW(); 1836} 1837#endif 1838 1839const SkRegion& SkCanvas::internal_private_getTotalClip() const { 1840 return fMCRec->fRasterClip->forceGetBW(); 1841} 1842 1843void SkCanvas::internal_private_getTotalClipAsPath(SkPath* path) const { 1844 path->reset(); 1845 1846 const SkRegion& rgn = fMCRec->fRasterClip->forceGetBW(); 1847 if (rgn.isEmpty()) { 1848 return; 1849 } 1850 (void)rgn.getBoundaryPath(path); 1851} 1852 1853GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() { 1854 SkBaseDevice* dev = this->getTopDevice(); 1855 return dev ? dev->accessRenderTarget() : NULL; 1856} 1857 1858SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) { 1859 SkBaseDevice* device = this->getTopDevice(); 1860 return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL; 1861} 1862 1863GrContext* SkCanvas::getGrContext() { 1864#if SK_SUPPORT_GPU 1865 SkBaseDevice* device = this->getTopDevice(); 1866 if (NULL != device) { 1867 GrRenderTarget* renderTarget = device->accessRenderTarget(); 1868 if (NULL != renderTarget) { 1869 return renderTarget->getContext(); 1870 } 1871 } 1872#endif 1873 1874 return NULL; 1875 1876} 1877 1878void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner, 1879 const SkPaint& paint) { 1880 if (outer.isEmpty()) { 1881 return; 1882 } 1883 if (inner.isEmpty()) { 1884 this->drawRRect(outer, paint); 1885 return; 1886 } 1887 1888 // We don't have this method (yet), but technically this is what we should 1889 // be able to assert... 1890 // SkASSERT(outer.contains(inner)); 1891 // 1892 // For now at least check for containment of bounds 1893 SkASSERT(outer.getBounds().contains(inner.getBounds())); 1894 1895 this->onDrawDRRect(outer, inner, paint); 1896} 1897 1898////////////////////////////////////////////////////////////////////////////// 1899// These are the virtual drawing methods 1900////////////////////////////////////////////////////////////////////////////// 1901 1902void SkCanvas::clear(SkColor color) { 1903 SkDrawIter iter(this); 1904 this->predrawNotify(); 1905 while (iter.next()) { 1906 iter.fDevice->clear(color); 1907 } 1908} 1909 1910void SkCanvas::onDiscard() { 1911 if (NULL != fSurfaceBase) { 1912 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode); 1913 } 1914} 1915 1916void SkCanvas::drawPaint(const SkPaint& paint) { 1917 this->internalDrawPaint(paint); 1918} 1919 1920void SkCanvas::internalDrawPaint(const SkPaint& paint) { 1921 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL) 1922 1923 while (iter.next()) { 1924 iter.fDevice->drawPaint(iter, looper.paint()); 1925 } 1926 1927 LOOPER_END 1928} 1929 1930void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1931 const SkPaint& paint) { 1932 if ((long)count <= 0) { 1933 return; 1934 } 1935 1936 SkRect r, storage; 1937 const SkRect* bounds = NULL; 1938 if (paint.canComputeFastBounds()) { 1939 // special-case 2 points (common for drawing a single line) 1940 if (2 == count) { 1941 r.set(pts[0], pts[1]); 1942 } else { 1943 r.set(pts, SkToInt(count)); 1944 } 1945 bounds = &paint.computeFastStrokeBounds(r, &storage); 1946 if (this->quickReject(*bounds)) { 1947 return; 1948 } 1949 } 1950 1951 SkASSERT(pts != NULL); 1952 1953 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds) 1954 1955 while (iter.next()) { 1956 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); 1957 } 1958 1959 LOOPER_END 1960} 1961 1962void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1963 SkRect storage; 1964 const SkRect* bounds = NULL; 1965 if (paint.canComputeFastBounds()) { 1966 bounds = &paint.computeFastBounds(r, &storage); 1967 if (this->quickReject(*bounds)) { 1968 return; 1969 } 1970 } 1971 1972 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds) 1973 1974 while (iter.next()) { 1975 iter.fDevice->drawRect(iter, r, looper.paint()); 1976 } 1977 1978 LOOPER_END 1979} 1980 1981void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1982 SkRect storage; 1983 const SkRect* bounds = NULL; 1984 if (paint.canComputeFastBounds()) { 1985 bounds = &paint.computeFastBounds(oval, &storage); 1986 if (this->quickReject(*bounds)) { 1987 return; 1988 } 1989 } 1990 1991 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds) 1992 1993 while (iter.next()) { 1994 iter.fDevice->drawOval(iter, oval, looper.paint()); 1995 } 1996 1997 LOOPER_END 1998} 1999 2000void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 2001 SkRect storage; 2002 const SkRect* bounds = NULL; 2003 if (paint.canComputeFastBounds()) { 2004 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage); 2005 if (this->quickReject(*bounds)) { 2006 return; 2007 } 2008 } 2009 2010 if (rrect.isRect()) { 2011 // call the non-virtual version 2012 this->SkCanvas::drawRect(rrect.getBounds(), paint); 2013 return; 2014 } else if (rrect.isOval()) { 2015 // call the non-virtual version 2016 this->SkCanvas::drawOval(rrect.getBounds(), paint); 2017 return; 2018 } 2019 2020 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) 2021 2022 while (iter.next()) { 2023 iter.fDevice->drawRRect(iter, rrect, looper.paint()); 2024 } 2025 2026 LOOPER_END 2027} 2028 2029void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, 2030 const SkPaint& paint) { 2031 SkRect storage; 2032 const SkRect* bounds = NULL; 2033 if (paint.canComputeFastBounds()) { 2034 bounds = &paint.computeFastBounds(outer.getBounds(), &storage); 2035 if (this->quickReject(*bounds)) { 2036 return; 2037 } 2038 } 2039 2040 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) 2041 2042 while (iter.next()) { 2043 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint()); 2044 } 2045 2046 LOOPER_END 2047} 2048 2049void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 2050 if (!path.isFinite()) { 2051 return; 2052 } 2053 2054 SkRect storage; 2055 const SkRect* bounds = NULL; 2056 if (!path.isInverseFillType() && paint.canComputeFastBounds()) { 2057 const SkRect& pathBounds = path.getBounds(); 2058 bounds = &paint.computeFastBounds(pathBounds, &storage); 2059 if (this->quickReject(*bounds)) { 2060 return; 2061 } 2062 } 2063 2064 const SkRect& r = path.getBounds(); 2065 if (r.width() <= 0 && r.height() <= 0) { 2066 if (path.isInverseFillType()) { 2067 this->internalDrawPaint(paint); 2068 } 2069 return; 2070 } 2071 2072 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds) 2073 2074 while (iter.next()) { 2075 iter.fDevice->drawPath(iter, path, looper.paint()); 2076 } 2077 2078 LOOPER_END 2079} 2080 2081void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, 2082 const SkPaint* paint) { 2083 SkDEBUGCODE(bitmap.validate();) 2084 2085 if (NULL == paint || paint->canComputeFastBounds()) { 2086 SkRect bounds = { 2087 x, y, 2088 x + SkIntToScalar(bitmap.width()), 2089 y + SkIntToScalar(bitmap.height()) 2090 }; 2091 if (paint) { 2092 (void)paint->computeFastBounds(bounds, &bounds); 2093 } 2094 if (this->quickReject(bounds)) { 2095 return; 2096 } 2097 } 2098 2099 SkMatrix matrix; 2100 matrix.setTranslate(x, y); 2101 this->internalDrawBitmap(bitmap, matrix, paint); 2102} 2103 2104// this one is non-virtual, so it can be called safely by other canvas apis 2105void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, 2106 const SkRect& dst, const SkPaint* paint, 2107 DrawBitmapRectFlags flags) { 2108 if (bitmap.drawsNothing() || dst.isEmpty()) { 2109 return; 2110 } 2111 2112 CHECK_LOCKCOUNT_BALANCE(bitmap); 2113 2114 SkRect storage; 2115 const SkRect* bounds = &dst; 2116 if (NULL == paint || paint->canComputeFastBounds()) { 2117 if (paint) { 2118 bounds = &paint->computeFastBounds(dst, &storage); 2119 } 2120 if (this->quickReject(*bounds)) { 2121 return; 2122 } 2123 } 2124 2125 SkLazyPaint lazy; 2126 if (NULL == paint) { 2127 paint = lazy.init(); 2128 } 2129 2130 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) 2131 2132 while (iter.next()) { 2133 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags); 2134 } 2135 2136 LOOPER_END 2137} 2138 2139void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, 2140 const SkRect& dst, const SkPaint* paint, 2141 DrawBitmapRectFlags flags) { 2142 SkDEBUGCODE(bitmap.validate();) 2143 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags); 2144} 2145 2146void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 2147 const SkPaint* paint) { 2148 SkDEBUGCODE(bitmap.validate();) 2149 this->internalDrawBitmap(bitmap, matrix, paint); 2150} 2151 2152void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap, 2153 const SkIRect& center, const SkRect& dst, 2154 const SkPaint* paint) { 2155 if (bitmap.drawsNothing()) { 2156 return; 2157 } 2158 if (NULL == paint || paint->canComputeFastBounds()) { 2159 SkRect storage; 2160 const SkRect* bounds = &dst; 2161 if (paint) { 2162 bounds = &paint->computeFastBounds(dst, &storage); 2163 } 2164 if (this->quickReject(*bounds)) { 2165 return; 2166 } 2167 } 2168 2169 const int32_t w = bitmap.width(); 2170 const int32_t h = bitmap.height(); 2171 2172 SkIRect c = center; 2173 // pin center to the bounds of the bitmap 2174 c.fLeft = SkMax32(0, center.fLeft); 2175 c.fTop = SkMax32(0, center.fTop); 2176 c.fRight = SkPin32(center.fRight, c.fLeft, w); 2177 c.fBottom = SkPin32(center.fBottom, c.fTop, h); 2178 2179 const SkScalar srcX[4] = { 2180 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w) 2181 }; 2182 const SkScalar srcY[4] = { 2183 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h) 2184 }; 2185 SkScalar dstX[4] = { 2186 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft), 2187 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight 2188 }; 2189 SkScalar dstY[4] = { 2190 dst.fTop, dst.fTop + SkIntToScalar(c.fTop), 2191 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom 2192 }; 2193 2194 if (dstX[1] > dstX[2]) { 2195 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width()); 2196 dstX[2] = dstX[1]; 2197 } 2198 2199 if (dstY[1] > dstY[2]) { 2200 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height()); 2201 dstY[2] = dstY[1]; 2202 } 2203 2204 for (int y = 0; y < 3; y++) { 2205 SkRect s, d; 2206 2207 s.fTop = srcY[y]; 2208 s.fBottom = srcY[y+1]; 2209 d.fTop = dstY[y]; 2210 d.fBottom = dstY[y+1]; 2211 for (int x = 0; x < 3; x++) { 2212 s.fLeft = srcX[x]; 2213 s.fRight = srcX[x+1]; 2214 d.fLeft = dstX[x]; 2215 d.fRight = dstX[x+1]; 2216 this->internalDrawBitmapRect(bitmap, &s, d, paint, 2217 kNone_DrawBitmapRectFlag); 2218 } 2219 } 2220} 2221 2222void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 2223 const SkRect& dst, const SkPaint* paint) { 2224 SkDEBUGCODE(bitmap.validate();) 2225 2226 // Need a device entry-point, so gpu can use a mesh 2227 this->internalDrawBitmapNine(bitmap, center, dst, paint); 2228} 2229 2230class SkDeviceFilteredPaint { 2231public: 2232 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) { 2233 SkBaseDevice::TextFlags flags; 2234 if (device->filterTextFlags(paint, &flags)) { 2235 SkPaint* newPaint = fLazy.set(paint); 2236 newPaint->setFlags(flags.fFlags); 2237 newPaint->setHinting(flags.fHinting); 2238 fPaint = newPaint; 2239 } else { 2240 fPaint = &paint; 2241 } 2242 } 2243 2244 const SkPaint& paint() const { return *fPaint; } 2245 2246private: 2247 const SkPaint* fPaint; 2248 SkLazyPaint fLazy; 2249}; 2250 2251void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, 2252 const SkRect& r, SkScalar textSize) { 2253 if (paint.getStyle() == SkPaint::kFill_Style) { 2254 draw.fDevice->drawRect(draw, r, paint); 2255 } else { 2256 SkPaint p(paint); 2257 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); 2258 draw.fDevice->drawRect(draw, r, p); 2259 } 2260} 2261 2262void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, 2263 const char text[], size_t byteLength, 2264 SkScalar x, SkScalar y) { 2265 SkASSERT(byteLength == 0 || text != NULL); 2266 2267 // nothing to draw 2268 if (text == NULL || byteLength == 0 || 2269 draw.fClip->isEmpty() || 2270 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 2271 return; 2272 } 2273 2274 SkScalar width = 0; 2275 SkPoint start; 2276 2277 start.set(0, 0); // to avoid warning 2278 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | 2279 SkPaint::kStrikeThruText_Flag)) { 2280 width = paint.measureText(text, byteLength); 2281 2282 SkScalar offsetX = 0; 2283 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 2284 offsetX = SkScalarHalf(width); 2285 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { 2286 offsetX = width; 2287 } 2288 start.set(x - offsetX, y); 2289 } 2290 2291 if (0 == width) { 2292 return; 2293 } 2294 2295 uint32_t flags = paint.getFlags(); 2296 2297 if (flags & (SkPaint::kUnderlineText_Flag | 2298 SkPaint::kStrikeThruText_Flag)) { 2299 SkScalar textSize = paint.getTextSize(); 2300 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 2301 SkRect r; 2302 2303 r.fLeft = start.fX; 2304 r.fRight = start.fX + width; 2305 2306 if (flags & SkPaint::kUnderlineText_Flag) { 2307 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, 2308 start.fY); 2309 r.fTop = offset; 2310 r.fBottom = offset + height; 2311 DrawRect(draw, paint, r, textSize); 2312 } 2313 if (flags & SkPaint::kStrikeThruText_Flag) { 2314 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, 2315 start.fY); 2316 r.fTop = offset; 2317 r.fBottom = offset + height; 2318 DrawRect(draw, paint, r, textSize); 2319 } 2320 } 2321} 2322 2323void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, 2324 const SkPaint& paint) { 2325 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2326 2327 while (iter.next()) { 2328 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2329 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 2330 DrawTextDecorations(iter, dfp.paint(), 2331 static_cast<const char*>(text), byteLength, x, y); 2332 } 2333 2334 LOOPER_END 2335} 2336 2337void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], 2338 const SkPaint& paint) { 2339 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2340 2341 while (iter.next()) { 2342 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2343 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 2344 dfp.paint()); 2345 } 2346 2347 LOOPER_END 2348} 2349 2350void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], 2351 SkScalar constY, const SkPaint& paint) { 2352 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2353 2354 while (iter.next()) { 2355 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2356 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 2357 dfp.paint()); 2358 } 2359 2360 LOOPER_END 2361} 2362 2363void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, 2364 const SkMatrix* matrix, const SkPaint& paint) { 2365 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2366 2367 while (iter.next()) { 2368 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 2369 matrix, looper.paint()); 2370 } 2371 2372 LOOPER_END 2373} 2374 2375// These will become non-virtual, so they always call the (virtual) onDraw... method 2376void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, 2377 const SkPaint& paint) { 2378 this->onDrawText(text, byteLength, x, y, paint); 2379} 2380void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[], 2381 const SkPaint& paint) { 2382 this->onDrawPosText(text, byteLength, pos, paint); 2383} 2384void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], 2385 SkScalar constY, const SkPaint& paint) { 2386 this->onDrawPosTextH(text, byteLength, xpos, constY, paint); 2387} 2388void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path, 2389 const SkMatrix* matrix, const SkPaint& paint) { 2390 this->onDrawTextOnPath(text, byteLength, path, matrix, paint); 2391} 2392 2393void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 2394 const SkPoint verts[], const SkPoint texs[], 2395 const SkColor colors[], SkXfermode* xmode, 2396 const uint16_t indices[], int indexCount, 2397 const SkPaint& paint) { 2398 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL) 2399 2400 while (iter.next()) { 2401 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 2402 colors, xmode, indices, indexCount, 2403 looper.paint()); 2404 } 2405 2406 LOOPER_END 2407} 2408 2409////////////////////////////////////////////////////////////////////////////// 2410// These methods are NOT virtual, and therefore must call back into virtual 2411// methods, rather than actually drawing themselves. 2412////////////////////////////////////////////////////////////////////////////// 2413 2414void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 2415 SkXfermode::Mode mode) { 2416 SkPaint paint; 2417 2418 paint.setARGB(a, r, g, b); 2419 if (SkXfermode::kSrcOver_Mode != mode) { 2420 paint.setXfermodeMode(mode); 2421 } 2422 this->drawPaint(paint); 2423} 2424 2425void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 2426 SkPaint paint; 2427 2428 paint.setColor(c); 2429 if (SkXfermode::kSrcOver_Mode != mode) { 2430 paint.setXfermodeMode(mode); 2431 } 2432 this->drawPaint(paint); 2433} 2434 2435void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 2436 SkPoint pt; 2437 2438 pt.set(x, y); 2439 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2440} 2441 2442void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 2443 SkPoint pt; 2444 SkPaint paint; 2445 2446 pt.set(x, y); 2447 paint.setColor(color); 2448 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2449} 2450 2451void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 2452 const SkPaint& paint) { 2453 SkPoint pts[2]; 2454 2455 pts[0].set(x0, y0); 2456 pts[1].set(x1, y1); 2457 this->drawPoints(kLines_PointMode, 2, pts, paint); 2458} 2459 2460void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 2461 SkScalar right, SkScalar bottom, 2462 const SkPaint& paint) { 2463 SkRect r; 2464 2465 r.set(left, top, right, bottom); 2466 this->drawRect(r, paint); 2467} 2468 2469void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 2470 const SkPaint& paint) { 2471 if (radius < 0) { 2472 radius = 0; 2473 } 2474 2475 SkRect r; 2476 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 2477 this->drawOval(r, paint); 2478} 2479 2480void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 2481 const SkPaint& paint) { 2482 if (rx > 0 && ry > 0) { 2483 if (paint.canComputeFastBounds()) { 2484 SkRect storage; 2485 if (this->quickReject(paint.computeFastBounds(r, &storage))) { 2486 return; 2487 } 2488 } 2489 SkRRect rrect; 2490 rrect.setRectXY(r, rx, ry); 2491 this->drawRRect(rrect, paint); 2492 } else { 2493 this->drawRect(r, paint); 2494 } 2495} 2496 2497void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 2498 SkScalar sweepAngle, bool useCenter, 2499 const SkPaint& paint) { 2500 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 2501 this->drawOval(oval, paint); 2502 } else { 2503 SkPath path; 2504 if (useCenter) { 2505 path.moveTo(oval.centerX(), oval.centerY()); 2506 } 2507 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 2508 if (useCenter) { 2509 path.close(); 2510 } 2511 this->drawPath(path, paint); 2512 } 2513} 2514 2515void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 2516 const SkPath& path, SkScalar hOffset, 2517 SkScalar vOffset, const SkPaint& paint) { 2518 SkMatrix matrix; 2519 2520 matrix.setTranslate(hOffset, vOffset); 2521 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 2522} 2523 2524/////////////////////////////////////////////////////////////////////////////// 2525void SkCanvas::EXPERIMENTAL_optimize(SkPicture* picture) { 2526 SkBaseDevice* device = this->getDevice(); 2527 if (NULL != device) { 2528 device->EXPERIMENTAL_optimize(picture); 2529 } 2530} 2531 2532void SkCanvas::EXPERIMENTAL_purge(SkPicture* picture) { 2533 SkBaseDevice* device = this->getTopDevice(); 2534 if (NULL != device) { 2535 device->EXPERIMENTAL_purge(picture); 2536 } 2537} 2538 2539void SkCanvas::drawPicture(SkPicture& picture) { 2540 SkBaseDevice* device = this->getTopDevice(); 2541 if (NULL != device) { 2542 // Canvas has to first give the device the opportunity to render 2543 // the picture itself. 2544 if (device->EXPERIMENTAL_drawPicture(this, &picture)) { 2545 return; // the device has rendered the entire picture 2546 } 2547 } 2548 2549 picture.draw(this); 2550} 2551 2552/////////////////////////////////////////////////////////////////////////////// 2553/////////////////////////////////////////////////////////////////////////////// 2554 2555SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 2556 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); 2557 2558 SkASSERT(canvas); 2559 2560 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 2561 fDone = !fImpl->next(); 2562} 2563 2564SkCanvas::LayerIter::~LayerIter() { 2565 fImpl->~SkDrawIter(); 2566} 2567 2568void SkCanvas::LayerIter::next() { 2569 fDone = !fImpl->next(); 2570} 2571 2572SkBaseDevice* SkCanvas::LayerIter::device() const { 2573 return fImpl->getDevice(); 2574} 2575 2576const SkMatrix& SkCanvas::LayerIter::matrix() const { 2577 return fImpl->getMatrix(); 2578} 2579 2580const SkPaint& SkCanvas::LayerIter::paint() const { 2581 const SkPaint* paint = fImpl->getPaint(); 2582 if (NULL == paint) { 2583 paint = &fDefaultPaint; 2584 } 2585 return *paint; 2586} 2587 2588const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 2589int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 2590int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 2591 2592/////////////////////////////////////////////////////////////////////////////// 2593 2594SkCanvas::ClipVisitor::~ClipVisitor() { } 2595 2596/////////////////////////////////////////////////////////////////////////////// 2597 2598static bool supported_for_raster_canvas(const SkImageInfo& info) { 2599 switch (info.alphaType()) { 2600 case kPremul_SkAlphaType: 2601 case kOpaque_SkAlphaType: 2602 break; 2603 default: 2604 return false; 2605 } 2606 2607 switch (info.colorType()) { 2608 case kAlpha_8_SkColorType: 2609 case kRGB_565_SkColorType: 2610 case kN32_SkColorType: 2611 break; 2612 default: 2613 return false; 2614 } 2615 2616 return true; 2617} 2618 2619SkCanvas* SkCanvas::NewRaster(const SkImageInfo& info) { 2620 if (!supported_for_raster_canvas(info)) { 2621 return NULL; 2622 } 2623 2624 SkBitmap bitmap; 2625 if (!bitmap.allocPixels(info)) { 2626 return NULL; 2627 } 2628 2629 // should this functionality be moved into allocPixels()? 2630 if (!bitmap.info().isOpaque()) { 2631 bitmap.eraseColor(0); 2632 } 2633 return SkNEW_ARGS(SkCanvas, (bitmap)); 2634} 2635 2636SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) { 2637 if (!supported_for_raster_canvas(info)) { 2638 return NULL; 2639 } 2640 2641 SkBitmap bitmap; 2642 if (!bitmap.installPixels(info, pixels, rowBytes)) { 2643 return NULL; 2644 } 2645 return SkNEW_ARGS(SkCanvas, (bitmap)); 2646} 2647