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