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