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