SkCanvas.cpp revision f2bfd54de32ffbcf90ddcd0e249aaebb1559d9c2
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 } 1272 op = SkRegion::kReplace_Op; 1273 } 1274 1275 return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA); 1276} 1277 1278bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1279 AutoValidateClip avc(this); 1280 1281 fDeviceCMDirty = true; 1282 fLocalBoundsCompareTypeDirty = true; 1283 1284 // todo: signal fClipStack that we have a region, and therefore (I guess) 1285 // we have to ignore it, and use the region directly? 1286 fClipStack.clipDevRect(rgn.getBounds(), op); 1287 1288 return fMCRec->fRasterClip->op(rgn, op); 1289} 1290 1291#ifdef SK_DEBUG 1292void SkCanvas::validateClip() const { 1293 // construct clipRgn from the clipstack 1294 const SkDevice* device = this->getDevice(); 1295 if (!device) { 1296 SkASSERT(this->getTotalClip().isEmpty()); 1297 return; 1298 } 1299 1300 SkIRect ir; 1301 ir.set(0, 0, device->width(), device->height()); 1302 SkRasterClip tmpClip(ir); 1303 1304 SkClipStack::B2TIter iter(fClipStack); 1305 const SkClipStack::Element* element; 1306 while ((element = iter.next()) != NULL) { 1307 switch (element->getType()) { 1308 case SkClipStack::Element::kPath_Type: 1309 clipPathHelper(this, 1310 &tmpClip, 1311 element->getPath(), 1312 element->getOp(), 1313 element->isAA()); 1314 break; 1315 case SkClipStack::Element::kRect_Type: 1316 element->getRect().round(&ir); 1317 tmpClip.op(ir, element->getOp()); 1318 break; 1319 case SkClipStack::Element::kEmpty_Type: 1320 tmpClip.setEmpty(); 1321 break; 1322 } 1323 } 1324 1325#if 0 // enable this locally for testing 1326 // now compare against the current rgn 1327 const SkRegion& rgn = this->getTotalClip(); 1328 SkASSERT(rgn == tmpClip); 1329#endif 1330} 1331#endif 1332 1333void SkCanvas::replayClips(ClipVisitor* visitor) const { 1334 SkClipStack::B2TIter iter(fClipStack); 1335 const SkClipStack::Element* element; 1336 1337 static const SkRect kEmpty = { 0, 0, 0, 0 }; 1338 while ((element = iter.next()) != NULL) { 1339 switch (element->getType()) { 1340 case SkClipStack::Element::kPath_Type: 1341 visitor->clipPath(element->getPath(), element->getOp(), element->isAA()); 1342 break; 1343 case SkClipStack::Element::kRect_Type: 1344 visitor->clipRect(element->getRect(), element->getOp(), element->isAA()); 1345 break; 1346 case SkClipStack::Element::kEmpty_Type: 1347 visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false); 1348 break; 1349 } 1350 } 1351} 1352 1353/////////////////////////////////////////////////////////////////////////////// 1354 1355void SkCanvas::computeLocalClipBoundsCompareType() const { 1356 SkRect r; 1357 1358 if (!this->getClipBounds(&r)) { 1359 fLocalBoundsCompareType.setEmpty(); 1360 } else { 1361 fLocalBoundsCompareType.set(SkScalarToCompareType(r.fLeft), 1362 SkScalarToCompareType(r.fTop), 1363 SkScalarToCompareType(r.fRight), 1364 SkScalarToCompareType(r.fBottom)); 1365 } 1366} 1367 1368bool SkCanvas::quickReject(const SkRect& rect) const { 1369 1370 if (!rect.isFinite()) 1371 return true; 1372 1373 if (fMCRec->fRasterClip->isEmpty()) { 1374 return true; 1375 } 1376 1377 if (fMCRec->fMatrix->hasPerspective()) { 1378 SkRect dst; 1379 fMCRec->fMatrix->mapRect(&dst, rect); 1380 SkIRect idst; 1381 dst.roundOut(&idst); 1382 return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds()); 1383 } else { 1384 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(); 1385 1386 // for speed, do the most likely reject compares first 1387 SkScalarCompareType userT = SkScalarToCompareType(rect.fTop); 1388 SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom); 1389 if (userT >= clipR.fBottom || userB <= clipR.fTop) { 1390 return true; 1391 } 1392 SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft); 1393 SkScalarCompareType userR = SkScalarToCompareType(rect.fRight); 1394 if (userL >= clipR.fRight || userR <= clipR.fLeft) { 1395 return true; 1396 } 1397 return false; 1398 } 1399} 1400 1401bool SkCanvas::quickReject(const SkPath& path) const { 1402 return path.isEmpty() || this->quickReject(path.getBounds()); 1403} 1404 1405static inline int pinIntForScalar(int x) { 1406#ifdef SK_SCALAR_IS_FIXED 1407 if (x < SK_MinS16) { 1408 x = SK_MinS16; 1409 } else if (x > SK_MaxS16) { 1410 x = SK_MaxS16; 1411 } 1412#endif 1413 return x; 1414} 1415 1416bool SkCanvas::getClipBounds(SkRect* bounds) const { 1417 SkIRect ibounds; 1418 if (!getClipDeviceBounds(&ibounds)) { 1419 return false; 1420 } 1421 1422 SkMatrix inverse; 1423 // if we can't invert the CTM, we can't return local clip bounds 1424 if (!fMCRec->fMatrix->invert(&inverse)) { 1425 if (bounds) { 1426 bounds->setEmpty(); 1427 } 1428 return false; 1429 } 1430 1431 if (NULL != bounds) { 1432 SkRect r; 1433 // adjust it outwards in case we are antialiasing 1434 const int inset = 1; 1435 1436 // SkRect::iset() will correctly assert if we pass a value out of range 1437 // (when SkScalar==fixed), so we pin to legal values. This does not 1438 // really returnt the correct answer, but its the best we can do given 1439 // that we've promised to return SkRect (even though we support devices 1440 // that can be larger than 32K in width or height). 1441 r.iset(pinIntForScalar(ibounds.fLeft - inset), 1442 pinIntForScalar(ibounds.fTop - inset), 1443 pinIntForScalar(ibounds.fRight + inset), 1444 pinIntForScalar(ibounds.fBottom + inset)); 1445 inverse.mapRect(bounds, r); 1446 } 1447 return true; 1448} 1449 1450bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const { 1451 const SkRasterClip& clip = *fMCRec->fRasterClip; 1452 if (clip.isEmpty()) { 1453 if (bounds) { 1454 bounds->setEmpty(); 1455 } 1456 return false; 1457 } 1458 1459 if (NULL != bounds) { 1460 *bounds = clip.getBounds(); 1461 } 1462 return true; 1463} 1464 1465const SkMatrix& SkCanvas::getTotalMatrix() const { 1466 return *fMCRec->fMatrix; 1467} 1468 1469SkCanvas::ClipType SkCanvas::getClipType() const { 1470 if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType; 1471 if (fMCRec->fRasterClip->isRect()) return kRect_ClipType; 1472 return kComplex_ClipType; 1473} 1474 1475const SkRegion& SkCanvas::getTotalClip() const { 1476 return fMCRec->fRasterClip->forceGetBW(); 1477} 1478 1479SkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config, 1480 int width, int height, 1481 bool isOpaque) { 1482 SkDevice* device = this->getTopDevice(); 1483 if (device) { 1484 return device->createCompatibleDeviceForSaveLayer(config, width, height, 1485 isOpaque); 1486 } else { 1487 return NULL; 1488 } 1489} 1490 1491SkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config, 1492 int width, int height, 1493 bool isOpaque) { 1494 SkDevice* device = this->getDevice(); 1495 if (device) { 1496 return device->createCompatibleDevice(config, width, height, isOpaque); 1497 } else { 1498 return NULL; 1499 } 1500} 1501 1502 1503////////////////////////////////////////////////////////////////////////////// 1504// These are the virtual drawing methods 1505////////////////////////////////////////////////////////////////////////////// 1506 1507void SkCanvas::clear(SkColor color) { 1508 SkDrawIter iter(this); 1509 this->predrawNotify(); 1510 while (iter.next()) { 1511 iter.fDevice->clear(color); 1512 } 1513} 1514 1515void SkCanvas::drawPaint(const SkPaint& paint) { 1516 this->internalDrawPaint(paint); 1517} 1518 1519void SkCanvas::internalDrawPaint(const SkPaint& paint) { 1520 CHECK_SHADER_NOSETCONTEXT(paint); 1521 1522 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type) 1523 1524 while (iter.next()) { 1525 iter.fDevice->drawPaint(iter, looper.paint()); 1526 } 1527 1528 LOOPER_END 1529} 1530 1531void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1532 const SkPaint& paint) { 1533 if ((long)count <= 0) { 1534 return; 1535 } 1536 1537 CHECK_SHADER_NOSETCONTEXT(paint); 1538 1539 if (paint.canComputeFastBounds()) { 1540 SkRect r; 1541 // special-case 2 points (common for drawing a single line) 1542 if (2 == count) { 1543 r.set(pts[0], pts[1]); 1544 } else { 1545 r.set(pts, count); 1546 } 1547 SkRect storage; 1548 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) { 1549 return; 1550 } 1551 } 1552 1553 SkASSERT(pts != NULL); 1554 1555 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type) 1556 1557 while (iter.next()) { 1558 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); 1559 } 1560 1561 LOOPER_END 1562} 1563 1564void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1565 CHECK_SHADER_NOSETCONTEXT(paint); 1566 1567 if (paint.canComputeFastBounds()) { 1568 SkRect storage; 1569 if (this->quickReject(paint.computeFastBounds(r, &storage))) { 1570 return; 1571 } 1572 } 1573 1574 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type) 1575 1576 while (iter.next()) { 1577 iter.fDevice->drawRect(iter, r, looper.paint()); 1578 } 1579 1580 LOOPER_END 1581} 1582 1583void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1584 CHECK_SHADER_NOSETCONTEXT(paint); 1585 1586 if (paint.canComputeFastBounds()) { 1587 SkRect storage; 1588 if (this->quickReject(paint.computeFastBounds(oval, &storage))) { 1589 return; 1590 } 1591 } 1592 1593 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type) 1594 1595 while (iter.next()) { 1596 iter.fDevice->drawOval(iter, oval, looper.paint()); 1597 } 1598 1599 LOOPER_END 1600} 1601 1602void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 1603 CHECK_SHADER_NOSETCONTEXT(paint); 1604 1605 if (paint.canComputeFastBounds()) { 1606 SkRect storage; 1607 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) { 1608 return; 1609 } 1610 } 1611 1612 if (rrect.isRect()) { 1613 // call the non-virtual version 1614 this->SkCanvas::drawRect(rrect.getBounds(), paint); 1615 return; 1616 } else if (rrect.isOval()) { 1617 // call the non-virtual version 1618 this->SkCanvas::drawOval(rrect.getBounds(), paint); 1619 return; 1620 } 1621 1622 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type) 1623 1624 while (iter.next()) { 1625 iter.fDevice->drawRRect(iter, rrect, looper.paint()); 1626 } 1627 1628 LOOPER_END 1629} 1630 1631 1632void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 1633 CHECK_SHADER_NOSETCONTEXT(paint); 1634 1635 if (!path.isFinite()) { 1636 return; 1637 } 1638 1639 if (!path.isInverseFillType() && paint.canComputeFastBounds()) { 1640 SkRect storage; 1641 const SkRect& bounds = path.getBounds(); 1642 if (this->quickReject(paint.computeFastBounds(bounds, &storage))) { 1643 return; 1644 } 1645 } 1646 if (path.isEmpty()) { 1647 if (path.isInverseFillType()) { 1648 this->internalDrawPaint(paint); 1649 } 1650 return; 1651 } 1652 1653 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 1654 1655 while (iter.next()) { 1656 iter.fDevice->drawPath(iter, path, looper.paint()); 1657 } 1658 1659 LOOPER_END 1660} 1661 1662void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, 1663 const SkPaint* paint) { 1664 SkDEBUGCODE(bitmap.validate();) 1665 1666 if (NULL == paint || paint->canComputeFastBounds()) { 1667 SkRect bounds = { 1668 x, y, 1669 x + SkIntToScalar(bitmap.width()), 1670 y + SkIntToScalar(bitmap.height()) 1671 }; 1672 if (paint) { 1673 (void)paint->computeFastBounds(bounds, &bounds); 1674 } 1675 if (this->quickReject(bounds)) { 1676 return; 1677 } 1678 } 1679 1680 SkMatrix matrix; 1681 matrix.setTranslate(x, y); 1682 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1683} 1684 1685// this one is non-virtual, so it can be called safely by other canvas apis 1686void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, 1687 const SkRect& dst, const SkPaint* paint) { 1688 if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) { 1689 return; 1690 } 1691 1692 CHECK_LOCKCOUNT_BALANCE(bitmap); 1693 1694 if (NULL == paint || paint->canComputeFastBounds()) { 1695 SkRect storage; 1696 const SkRect* bounds = &dst; 1697 if (paint) { 1698 bounds = &paint->computeFastBounds(dst, &storage); 1699 } 1700 if (this->quickReject(*bounds)) { 1701 return; 1702 } 1703 } 1704 1705 SkLazyPaint lazy; 1706 if (NULL == paint) { 1707 paint = lazy.init(); 1708 } 1709 1710 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type) 1711 1712 while (iter.next()) { 1713 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint()); 1714 } 1715 1716 LOOPER_END 1717} 1718 1719void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, 1720 const SkRect& dst, const SkPaint* paint) { 1721 SkDEBUGCODE(bitmap.validate();) 1722 this->internalDrawBitmapRect(bitmap, src, dst, paint); 1723} 1724 1725void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 1726 const SkPaint* paint) { 1727 SkDEBUGCODE(bitmap.validate();) 1728 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1729} 1730 1731void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect, 1732 const SkMatrix& matrix, const SkPaint& paint) { 1733 SkDEBUGCODE(bitmap.validate();) 1734 CHECK_LOCKCOUNT_BALANCE(bitmap); 1735 1736 LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type) 1737 1738 while (iter.next()) { 1739 iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint()); 1740 } 1741 1742 LOOPER_END 1743} 1744 1745void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap, 1746 const SkIRect& center, const SkRect& dst, 1747 const SkPaint* paint) { 1748 if (NULL == paint || paint->canComputeFastBounds()) { 1749 SkRect storage; 1750 const SkRect* bounds = &dst; 1751 if (paint) { 1752 bounds = &paint->computeFastBounds(dst, &storage); 1753 } 1754 if (this->quickReject(*bounds)) { 1755 return; 1756 } 1757 } 1758 1759 const int32_t w = bitmap.width(); 1760 const int32_t h = bitmap.height(); 1761 1762 SkIRect c = center; 1763 // pin center to the bounds of the bitmap 1764 c.fLeft = SkMax32(0, center.fLeft); 1765 c.fTop = SkMax32(0, center.fTop); 1766 c.fRight = SkPin32(center.fRight, c.fLeft, w); 1767 c.fBottom = SkPin32(center.fBottom, c.fTop, h); 1768 1769 const SkScalar srcX[4] = { 1770 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w) 1771 }; 1772 const SkScalar srcY[4] = { 1773 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h) 1774 }; 1775 SkScalar dstX[4] = { 1776 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft), 1777 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight 1778 }; 1779 SkScalar dstY[4] = { 1780 dst.fTop, dst.fTop + SkIntToScalar(c.fTop), 1781 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom 1782 }; 1783 1784 if (dstX[1] > dstX[2]) { 1785 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width()); 1786 dstX[2] = dstX[1]; 1787 } 1788 1789 if (dstY[1] > dstY[2]) { 1790 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height()); 1791 dstY[2] = dstY[1]; 1792 } 1793 1794 for (int y = 0; y < 3; y++) { 1795 SkRect s, d; 1796 1797 s.fTop = srcY[y]; 1798 s.fBottom = srcY[y+1]; 1799 d.fTop = dstY[y]; 1800 d.fBottom = dstY[y+1]; 1801 for (int x = 0; x < 3; x++) { 1802 s.fLeft = srcX[x]; 1803 s.fRight = srcX[x+1]; 1804 d.fLeft = dstX[x]; 1805 d.fRight = dstX[x+1]; 1806 this->internalDrawBitmapRect(bitmap, &s, d, paint); 1807 } 1808 } 1809} 1810 1811void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 1812 const SkRect& dst, const SkPaint* paint) { 1813 SkDEBUGCODE(bitmap.validate();) 1814 1815 // Need a device entry-point, so gpu can use a mesh 1816 this->internalDrawBitmapNine(bitmap, center, dst, paint); 1817} 1818 1819class SkDeviceFilteredPaint { 1820public: 1821 SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) { 1822 SkDevice::TextFlags flags; 1823 if (device->filterTextFlags(paint, &flags)) { 1824 SkPaint* newPaint = fLazy.set(paint); 1825 newPaint->setFlags(flags.fFlags); 1826 newPaint->setHinting(flags.fHinting); 1827 fPaint = newPaint; 1828 } else { 1829 fPaint = &paint; 1830 } 1831 } 1832 1833 const SkPaint& paint() const { return *fPaint; } 1834 1835private: 1836 const SkPaint* fPaint; 1837 SkLazyPaint fLazy; 1838}; 1839 1840void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, 1841 const SkRect& r, SkScalar textSize) { 1842 if (paint.getStyle() == SkPaint::kFill_Style) { 1843 draw.fDevice->drawRect(draw, r, paint); 1844 } else { 1845 SkPaint p(paint); 1846 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); 1847 draw.fDevice->drawRect(draw, r, p); 1848 } 1849} 1850 1851void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, 1852 const char text[], size_t byteLength, 1853 SkScalar x, SkScalar y) { 1854 SkASSERT(byteLength == 0 || text != NULL); 1855 1856 // nothing to draw 1857 if (text == NULL || byteLength == 0 || 1858 draw.fClip->isEmpty() || 1859 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 1860 return; 1861 } 1862 1863 SkScalar width = 0; 1864 SkPoint start; 1865 1866 start.set(0, 0); // to avoid warning 1867 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | 1868 SkPaint::kStrikeThruText_Flag)) { 1869 width = paint.measureText(text, byteLength); 1870 1871 SkScalar offsetX = 0; 1872 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 1873 offsetX = SkScalarHalf(width); 1874 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { 1875 offsetX = width; 1876 } 1877 start.set(x - offsetX, y); 1878 } 1879 1880 if (0 == width) { 1881 return; 1882 } 1883 1884 uint32_t flags = paint.getFlags(); 1885 1886 if (flags & (SkPaint::kUnderlineText_Flag | 1887 SkPaint::kStrikeThruText_Flag)) { 1888 SkScalar textSize = paint.getTextSize(); 1889 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 1890 SkRect r; 1891 1892 r.fLeft = start.fX; 1893 r.fRight = start.fX + width; 1894 1895 if (flags & SkPaint::kUnderlineText_Flag) { 1896 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, 1897 start.fY); 1898 r.fTop = offset; 1899 r.fBottom = offset + height; 1900 DrawRect(draw, paint, r, textSize); 1901 } 1902 if (flags & SkPaint::kStrikeThruText_Flag) { 1903 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, 1904 start.fY); 1905 r.fTop = offset; 1906 r.fBottom = offset + height; 1907 DrawRect(draw, paint, r, textSize); 1908 } 1909 } 1910} 1911 1912void SkCanvas::drawText(const void* text, size_t byteLength, 1913 SkScalar x, SkScalar y, const SkPaint& paint) { 1914 CHECK_SHADER_NOSETCONTEXT(paint); 1915 1916 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1917 1918 while (iter.next()) { 1919 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1920 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 1921 DrawTextDecorations(iter, dfp.paint(), 1922 static_cast<const char*>(text), byteLength, x, y); 1923 } 1924 1925 LOOPER_END 1926} 1927 1928void SkCanvas::drawPosText(const void* text, size_t byteLength, 1929 const SkPoint pos[], const SkPaint& paint) { 1930 CHECK_SHADER_NOSETCONTEXT(paint); 1931 1932 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1933 1934 while (iter.next()) { 1935 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1936 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 1937 dfp.paint()); 1938 } 1939 1940 LOOPER_END 1941} 1942 1943void SkCanvas::drawPosTextH(const void* text, size_t byteLength, 1944 const SkScalar xpos[], SkScalar constY, 1945 const SkPaint& paint) { 1946 CHECK_SHADER_NOSETCONTEXT(paint); 1947 1948 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1949 1950 while (iter.next()) { 1951 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1952 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 1953 dfp.paint()); 1954 } 1955 1956 LOOPER_END 1957} 1958 1959void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, 1960 const SkPath& path, const SkMatrix* matrix, 1961 const SkPaint& paint) { 1962 CHECK_SHADER_NOSETCONTEXT(paint); 1963 1964 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1965 1966 while (iter.next()) { 1967 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 1968 matrix, looper.paint()); 1969 } 1970 1971 LOOPER_END 1972} 1973 1974#ifdef SK_BUILD_FOR_ANDROID 1975void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength, 1976 const SkPoint pos[], const SkPaint& paint, 1977 const SkPath& path, const SkMatrix* matrix) { 1978 CHECK_SHADER_NOSETCONTEXT(paint); 1979 1980 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1981 1982 while (iter.next()) { 1983 iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos, 1984 looper.paint(), path, matrix); 1985 } 1986 1987 LOOPER_END 1988} 1989#endif 1990 1991void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 1992 const SkPoint verts[], const SkPoint texs[], 1993 const SkColor colors[], SkXfermode* xmode, 1994 const uint16_t indices[], int indexCount, 1995 const SkPaint& paint) { 1996 CHECK_SHADER_NOSETCONTEXT(paint); 1997 1998 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 1999 2000 while (iter.next()) { 2001 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 2002 colors, xmode, indices, indexCount, 2003 looper.paint()); 2004 } 2005 2006 LOOPER_END 2007} 2008 2009void SkCanvas::drawData(const void* data, size_t length) { 2010 // do nothing. Subclasses may do something with the data 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