SkCanvas.cpp revision a5d3e77420621c912383c3b22e542d9413d68278
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::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op, 1283 bool inverseFilled) { 1284 // This is for updating the clip conservatively using only bounds 1285 // information. 1286 // Contract: 1287 // The current clip must contain the true clip. The true 1288 // clip is the clip that would have normally been computed 1289 // by calls to clipPath and clipRRect 1290 // Objective: 1291 // Keep the current clip as small as possible without 1292 // breaking the contract, using only clip bounding rectangles 1293 // (for performance). 1294 1295 // N.B.: This *never* calls back through a virtual on canvas, so subclasses 1296 // don't have to worry about getting caught in a loop. Thus anywhere 1297 // we call a virtual method, we explicitly prefix it with 1298 // SkCanvas:: to be sure to call the base-class. 1299 1300 if (inverseFilled) { 1301 switch (op) { 1302 case SkRegion::kIntersect_Op: 1303 case SkRegion::kDifference_Op: 1304 // These ops can only shrink the current clip. So leaving 1305 // the clip unchanges conservatively respects the contract. 1306 return this->getClipDeviceBounds(NULL); 1307 case SkRegion::kUnion_Op: 1308 case SkRegion::kReplace_Op: 1309 case SkRegion::kReverseDifference_Op: 1310 case SkRegion::kXOR_Op: 1311 { 1312 // These ops can grow the current clip up to the extents of 1313 // the input clip, which is inverse filled, so we just set 1314 // the current clip to the device bounds. 1315 SkRect deviceBounds; 1316 SkIRect deviceIBounds; 1317 this->getDevice()->getGlobalBounds(&deviceIBounds); 1318 deviceBounds = SkRect::MakeFromIRect(deviceIBounds); 1319 this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag); 1320 // set the clip in device space 1321 this->SkCanvas::setMatrix(SkMatrix::I()); 1322 bool result = this->SkCanvas::clipRect(deviceBounds, 1323 SkRegion::kReplace_Op, false); 1324 this->SkCanvas::restore(); //pop the matrix, but keep the clip 1325 return result; 1326 } 1327 default: 1328 SkASSERT(0); // unhandled op? 1329 } 1330 } else { 1331 // Not inverse filled 1332 switch (op) { 1333 case SkRegion::kIntersect_Op: 1334 case SkRegion::kUnion_Op: 1335 case SkRegion::kReplace_Op: 1336 return this->SkCanvas::clipRect(bounds, op, false); 1337 case SkRegion::kDifference_Op: 1338 // Difference can only shrink the current clip. 1339 // Leaving clip unchanged conservatively fullfills the contract. 1340 return this->getClipDeviceBounds(NULL); 1341 case SkRegion::kReverseDifference_Op: 1342 // To reverse, we swap in the bounds with a replace op. 1343 // As with difference, leave it unchanged. 1344 return this->SkCanvas::clipRect(bounds, SkRegion::kReplace_Op, false); 1345 case SkRegion::kXOR_Op: 1346 // Be conservative, based on (A XOR B) always included in (A union B), 1347 // which is always included in (bounds(A) union bounds(B)) 1348 return this->SkCanvas::clipRect(bounds, SkRegion::kUnion_Op, false); 1349 default: 1350 SkASSERT(0); // unhandled op? 1351 } 1352 } 1353 return true; 1354} 1355 1356bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1357 AutoValidateClip avc(this); 1358 1359 fDeviceCMDirty = true; 1360 fLocalBoundsCompareTypeDirty = true; 1361 1362 // todo: signal fClipStack that we have a region, and therefore (I guess) 1363 // we have to ignore it, and use the region directly? 1364 fClipStack.clipDevRect(rgn.getBounds(), op); 1365 1366 return fMCRec->fRasterClip->op(rgn, op); 1367} 1368 1369#ifdef SK_DEBUG 1370void SkCanvas::validateClip() const { 1371 // construct clipRgn from the clipstack 1372 const SkDevice* device = this->getDevice(); 1373 if (!device) { 1374 SkASSERT(this->getTotalClip().isEmpty()); 1375 return; 1376 } 1377 1378 SkIRect ir; 1379 ir.set(0, 0, device->width(), device->height()); 1380 SkRasterClip tmpClip(ir); 1381 1382 SkClipStack::B2TIter iter(fClipStack); 1383 const SkClipStack::Element* element; 1384 while ((element = iter.next()) != NULL) { 1385 switch (element->getType()) { 1386 case SkClipStack::Element::kPath_Type: 1387 clipPathHelper(this, 1388 &tmpClip, 1389 element->getPath(), 1390 element->getOp(), 1391 element->isAA()); 1392 break; 1393 case SkClipStack::Element::kRect_Type: 1394 element->getRect().round(&ir); 1395 tmpClip.op(ir, element->getOp()); 1396 break; 1397 case SkClipStack::Element::kEmpty_Type: 1398 tmpClip.setEmpty(); 1399 break; 1400 } 1401 } 1402 1403#if 0 // enable this locally for testing 1404 // now compare against the current rgn 1405 const SkRegion& rgn = this->getTotalClip(); 1406 SkASSERT(rgn == tmpClip); 1407#endif 1408} 1409#endif 1410 1411void SkCanvas::replayClips(ClipVisitor* visitor) const { 1412 SkClipStack::B2TIter iter(fClipStack); 1413 const SkClipStack::Element* element; 1414 1415 static const SkRect kEmpty = { 0, 0, 0, 0 }; 1416 while ((element = iter.next()) != NULL) { 1417 switch (element->getType()) { 1418 case SkClipStack::Element::kPath_Type: 1419 visitor->clipPath(element->getPath(), element->getOp(), element->isAA()); 1420 break; 1421 case SkClipStack::Element::kRect_Type: 1422 visitor->clipRect(element->getRect(), element->getOp(), element->isAA()); 1423 break; 1424 case SkClipStack::Element::kEmpty_Type: 1425 visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false); 1426 break; 1427 } 1428 } 1429} 1430 1431/////////////////////////////////////////////////////////////////////////////// 1432 1433void SkCanvas::computeLocalClipBoundsCompareType() const { 1434 SkRect r; 1435 1436 if (!this->getClipBounds(&r)) { 1437 fLocalBoundsCompareType.setEmpty(); 1438 } else { 1439 fLocalBoundsCompareType.set(SkScalarToCompareType(r.fLeft), 1440 SkScalarToCompareType(r.fTop), 1441 SkScalarToCompareType(r.fRight), 1442 SkScalarToCompareType(r.fBottom)); 1443 } 1444} 1445 1446bool SkCanvas::quickReject(const SkRect& rect) const { 1447 1448 if (!rect.isFinite()) 1449 return true; 1450 1451 if (fMCRec->fRasterClip->isEmpty()) { 1452 return true; 1453 } 1454 1455 if (fMCRec->fMatrix->hasPerspective()) { 1456 SkRect dst; 1457 fMCRec->fMatrix->mapRect(&dst, rect); 1458 SkIRect idst; 1459 dst.roundOut(&idst); 1460 return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds()); 1461 } else { 1462 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(); 1463 1464 // for speed, do the most likely reject compares first 1465 SkScalarCompareType userT = SkScalarToCompareType(rect.fTop); 1466 SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom); 1467 if (userT >= clipR.fBottom || userB <= clipR.fTop) { 1468 return true; 1469 } 1470 SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft); 1471 SkScalarCompareType userR = SkScalarToCompareType(rect.fRight); 1472 if (userL >= clipR.fRight || userR <= clipR.fLeft) { 1473 return true; 1474 } 1475 return false; 1476 } 1477} 1478 1479bool SkCanvas::quickReject(const SkPath& path) const { 1480 return path.isEmpty() || this->quickReject(path.getBounds()); 1481} 1482 1483static inline int pinIntForScalar(int x) { 1484#ifdef SK_SCALAR_IS_FIXED 1485 if (x < SK_MinS16) { 1486 x = SK_MinS16; 1487 } else if (x > SK_MaxS16) { 1488 x = SK_MaxS16; 1489 } 1490#endif 1491 return x; 1492} 1493 1494bool SkCanvas::getClipBounds(SkRect* bounds) const { 1495 SkIRect ibounds; 1496 if (!getClipDeviceBounds(&ibounds)) { 1497 return false; 1498 } 1499 1500 SkMatrix inverse; 1501 // if we can't invert the CTM, we can't return local clip bounds 1502 if (!fMCRec->fMatrix->invert(&inverse)) { 1503 if (bounds) { 1504 bounds->setEmpty(); 1505 } 1506 return false; 1507 } 1508 1509 if (NULL != bounds) { 1510 SkRect r; 1511 // adjust it outwards in case we are antialiasing 1512 const int inset = 1; 1513 1514 // SkRect::iset() will correctly assert if we pass a value out of range 1515 // (when SkScalar==fixed), so we pin to legal values. This does not 1516 // really returnt the correct answer, but its the best we can do given 1517 // that we've promised to return SkRect (even though we support devices 1518 // that can be larger than 32K in width or height). 1519 r.iset(pinIntForScalar(ibounds.fLeft - inset), 1520 pinIntForScalar(ibounds.fTop - inset), 1521 pinIntForScalar(ibounds.fRight + inset), 1522 pinIntForScalar(ibounds.fBottom + inset)); 1523 inverse.mapRect(bounds, r); 1524 } 1525 return true; 1526} 1527 1528bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const { 1529 const SkRasterClip& clip = *fMCRec->fRasterClip; 1530 if (clip.isEmpty()) { 1531 if (bounds) { 1532 bounds->setEmpty(); 1533 } 1534 return false; 1535 } 1536 1537 if (NULL != bounds) { 1538 *bounds = clip.getBounds(); 1539 } 1540 return true; 1541} 1542 1543const SkMatrix& SkCanvas::getTotalMatrix() const { 1544 return *fMCRec->fMatrix; 1545} 1546 1547SkCanvas::ClipType SkCanvas::getClipType() const { 1548 if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType; 1549 if (fMCRec->fRasterClip->isRect()) return kRect_ClipType; 1550 return kComplex_ClipType; 1551} 1552 1553const SkRegion& SkCanvas::getTotalClip() const { 1554 return fMCRec->fRasterClip->forceGetBW(); 1555} 1556 1557SkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config, 1558 int width, int height, 1559 bool isOpaque) { 1560 SkDevice* device = this->getTopDevice(); 1561 if (device) { 1562 return device->createCompatibleDeviceForSaveLayer(config, width, height, 1563 isOpaque); 1564 } else { 1565 return NULL; 1566 } 1567} 1568 1569SkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config, 1570 int width, int height, 1571 bool isOpaque) { 1572 SkDevice* device = this->getDevice(); 1573 if (device) { 1574 return device->createCompatibleDevice(config, width, height, isOpaque); 1575 } else { 1576 return NULL; 1577 } 1578} 1579 1580 1581////////////////////////////////////////////////////////////////////////////// 1582// These are the virtual drawing methods 1583////////////////////////////////////////////////////////////////////////////// 1584 1585void SkCanvas::clear(SkColor color) { 1586 SkDrawIter iter(this); 1587 this->predrawNotify(); 1588 while (iter.next()) { 1589 iter.fDevice->clear(color); 1590 } 1591} 1592 1593void SkCanvas::drawPaint(const SkPaint& paint) { 1594 this->internalDrawPaint(paint); 1595} 1596 1597void SkCanvas::internalDrawPaint(const SkPaint& paint) { 1598 CHECK_SHADER_NOSETCONTEXT(paint); 1599 1600 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type) 1601 1602 while (iter.next()) { 1603 iter.fDevice->drawPaint(iter, looper.paint()); 1604 } 1605 1606 LOOPER_END 1607} 1608 1609void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1610 const SkPaint& paint) { 1611 if ((long)count <= 0) { 1612 return; 1613 } 1614 1615 CHECK_SHADER_NOSETCONTEXT(paint); 1616 1617 if (paint.canComputeFastBounds()) { 1618 SkRect r; 1619 // special-case 2 points (common for drawing a single line) 1620 if (2 == count) { 1621 r.set(pts[0], pts[1]); 1622 } else { 1623 r.set(pts, count); 1624 } 1625 SkRect storage; 1626 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) { 1627 return; 1628 } 1629 } 1630 1631 SkASSERT(pts != NULL); 1632 1633 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type) 1634 1635 while (iter.next()) { 1636 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); 1637 } 1638 1639 LOOPER_END 1640} 1641 1642void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1643 CHECK_SHADER_NOSETCONTEXT(paint); 1644 1645 if (paint.canComputeFastBounds()) { 1646 SkRect storage; 1647 if (this->quickReject(paint.computeFastBounds(r, &storage))) { 1648 return; 1649 } 1650 } 1651 1652 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type) 1653 1654 while (iter.next()) { 1655 iter.fDevice->drawRect(iter, r, looper.paint()); 1656 } 1657 1658 LOOPER_END 1659} 1660 1661void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1662 CHECK_SHADER_NOSETCONTEXT(paint); 1663 1664 if (paint.canComputeFastBounds()) { 1665 SkRect storage; 1666 if (this->quickReject(paint.computeFastBounds(oval, &storage))) { 1667 return; 1668 } 1669 } 1670 1671 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type) 1672 1673 while (iter.next()) { 1674 iter.fDevice->drawOval(iter, oval, looper.paint()); 1675 } 1676 1677 LOOPER_END 1678} 1679 1680void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 1681 CHECK_SHADER_NOSETCONTEXT(paint); 1682 1683 if (paint.canComputeFastBounds()) { 1684 SkRect storage; 1685 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) { 1686 return; 1687 } 1688 } 1689 1690 if (rrect.isRect()) { 1691 // call the non-virtual version 1692 this->SkCanvas::drawRect(rrect.getBounds(), paint); 1693 return; 1694 } else if (rrect.isOval()) { 1695 // call the non-virtual version 1696 this->SkCanvas::drawOval(rrect.getBounds(), paint); 1697 return; 1698 } 1699 1700 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type) 1701 1702 while (iter.next()) { 1703 iter.fDevice->drawRRect(iter, rrect, looper.paint()); 1704 } 1705 1706 LOOPER_END 1707} 1708 1709 1710void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 1711 CHECK_SHADER_NOSETCONTEXT(paint); 1712 1713 if (!path.isFinite()) { 1714 return; 1715 } 1716 1717 if (!path.isInverseFillType() && paint.canComputeFastBounds()) { 1718 SkRect storage; 1719 const SkRect& bounds = path.getBounds(); 1720 if (this->quickReject(paint.computeFastBounds(bounds, &storage))) { 1721 return; 1722 } 1723 } 1724 if (path.isEmpty()) { 1725 if (path.isInverseFillType()) { 1726 this->internalDrawPaint(paint); 1727 } 1728 return; 1729 } 1730 1731 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 1732 1733 while (iter.next()) { 1734 iter.fDevice->drawPath(iter, path, looper.paint()); 1735 } 1736 1737 LOOPER_END 1738} 1739 1740void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, 1741 const SkPaint* paint) { 1742 SkDEBUGCODE(bitmap.validate();) 1743 1744 if (NULL == paint || paint->canComputeFastBounds()) { 1745 SkRect bounds = { 1746 x, y, 1747 x + SkIntToScalar(bitmap.width()), 1748 y + SkIntToScalar(bitmap.height()) 1749 }; 1750 if (paint) { 1751 (void)paint->computeFastBounds(bounds, &bounds); 1752 } 1753 if (this->quickReject(bounds)) { 1754 return; 1755 } 1756 } 1757 1758 SkMatrix matrix; 1759 matrix.setTranslate(x, y); 1760 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1761} 1762 1763// this one is non-virtual, so it can be called safely by other canvas apis 1764void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, 1765 const SkRect& dst, const SkPaint* paint) { 1766 if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) { 1767 return; 1768 } 1769 1770 CHECK_LOCKCOUNT_BALANCE(bitmap); 1771 1772 if (NULL == paint || paint->canComputeFastBounds()) { 1773 SkRect storage; 1774 const SkRect* bounds = &dst; 1775 if (paint) { 1776 bounds = &paint->computeFastBounds(dst, &storage); 1777 } 1778 if (this->quickReject(*bounds)) { 1779 return; 1780 } 1781 } 1782 1783 SkLazyPaint lazy; 1784 if (NULL == paint) { 1785 paint = lazy.init(); 1786 } 1787 1788 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type) 1789 1790 while (iter.next()) { 1791 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint()); 1792 } 1793 1794 LOOPER_END 1795} 1796 1797void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, 1798 const SkRect& dst, const SkPaint* paint) { 1799 SkDEBUGCODE(bitmap.validate();) 1800 this->internalDrawBitmapRect(bitmap, src, dst, paint); 1801} 1802 1803void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 1804 const SkPaint* paint) { 1805 SkDEBUGCODE(bitmap.validate();) 1806 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1807} 1808 1809void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect, 1810 const SkMatrix& matrix, const SkPaint& paint) { 1811 SkDEBUGCODE(bitmap.validate();) 1812 CHECK_LOCKCOUNT_BALANCE(bitmap); 1813 1814 LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type) 1815 1816 while (iter.next()) { 1817 iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint()); 1818 } 1819 1820 LOOPER_END 1821} 1822 1823void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap, 1824 const SkIRect& center, const SkRect& dst, 1825 const SkPaint* paint) { 1826 if (NULL == paint || paint->canComputeFastBounds()) { 1827 SkRect storage; 1828 const SkRect* bounds = &dst; 1829 if (paint) { 1830 bounds = &paint->computeFastBounds(dst, &storage); 1831 } 1832 if (this->quickReject(*bounds)) { 1833 return; 1834 } 1835 } 1836 1837 const int32_t w = bitmap.width(); 1838 const int32_t h = bitmap.height(); 1839 1840 SkIRect c = center; 1841 // pin center to the bounds of the bitmap 1842 c.fLeft = SkMax32(0, center.fLeft); 1843 c.fTop = SkMax32(0, center.fTop); 1844 c.fRight = SkPin32(center.fRight, c.fLeft, w); 1845 c.fBottom = SkPin32(center.fBottom, c.fTop, h); 1846 1847 const SkScalar srcX[4] = { 1848 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w) 1849 }; 1850 const SkScalar srcY[4] = { 1851 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h) 1852 }; 1853 SkScalar dstX[4] = { 1854 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft), 1855 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight 1856 }; 1857 SkScalar dstY[4] = { 1858 dst.fTop, dst.fTop + SkIntToScalar(c.fTop), 1859 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom 1860 }; 1861 1862 if (dstX[1] > dstX[2]) { 1863 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width()); 1864 dstX[2] = dstX[1]; 1865 } 1866 1867 if (dstY[1] > dstY[2]) { 1868 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height()); 1869 dstY[2] = dstY[1]; 1870 } 1871 1872 for (int y = 0; y < 3; y++) { 1873 SkRect s, d; 1874 1875 s.fTop = srcY[y]; 1876 s.fBottom = srcY[y+1]; 1877 d.fTop = dstY[y]; 1878 d.fBottom = dstY[y+1]; 1879 for (int x = 0; x < 3; x++) { 1880 s.fLeft = srcX[x]; 1881 s.fRight = srcX[x+1]; 1882 d.fLeft = dstX[x]; 1883 d.fRight = dstX[x+1]; 1884 this->internalDrawBitmapRect(bitmap, &s, d, paint); 1885 } 1886 } 1887} 1888 1889void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 1890 const SkRect& dst, const SkPaint* paint) { 1891 SkDEBUGCODE(bitmap.validate();) 1892 1893 // Need a device entry-point, so gpu can use a mesh 1894 this->internalDrawBitmapNine(bitmap, center, dst, paint); 1895} 1896 1897class SkDeviceFilteredPaint { 1898public: 1899 SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) { 1900 SkDevice::TextFlags flags; 1901 if (device->filterTextFlags(paint, &flags)) { 1902 SkPaint* newPaint = fLazy.set(paint); 1903 newPaint->setFlags(flags.fFlags); 1904 newPaint->setHinting(flags.fHinting); 1905 fPaint = newPaint; 1906 } else { 1907 fPaint = &paint; 1908 } 1909 } 1910 1911 const SkPaint& paint() const { return *fPaint; } 1912 1913private: 1914 const SkPaint* fPaint; 1915 SkLazyPaint fLazy; 1916}; 1917 1918void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, 1919 const SkRect& r, SkScalar textSize) { 1920 if (paint.getStyle() == SkPaint::kFill_Style) { 1921 draw.fDevice->drawRect(draw, r, paint); 1922 } else { 1923 SkPaint p(paint); 1924 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); 1925 draw.fDevice->drawRect(draw, r, p); 1926 } 1927} 1928 1929void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, 1930 const char text[], size_t byteLength, 1931 SkScalar x, SkScalar y) { 1932 SkASSERT(byteLength == 0 || text != NULL); 1933 1934 // nothing to draw 1935 if (text == NULL || byteLength == 0 || 1936 draw.fClip->isEmpty() || 1937 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 1938 return; 1939 } 1940 1941 SkScalar width = 0; 1942 SkPoint start; 1943 1944 start.set(0, 0); // to avoid warning 1945 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | 1946 SkPaint::kStrikeThruText_Flag)) { 1947 width = paint.measureText(text, byteLength); 1948 1949 SkScalar offsetX = 0; 1950 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 1951 offsetX = SkScalarHalf(width); 1952 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { 1953 offsetX = width; 1954 } 1955 start.set(x - offsetX, y); 1956 } 1957 1958 if (0 == width) { 1959 return; 1960 } 1961 1962 uint32_t flags = paint.getFlags(); 1963 1964 if (flags & (SkPaint::kUnderlineText_Flag | 1965 SkPaint::kStrikeThruText_Flag)) { 1966 SkScalar textSize = paint.getTextSize(); 1967 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 1968 SkRect r; 1969 1970 r.fLeft = start.fX; 1971 r.fRight = start.fX + width; 1972 1973 if (flags & SkPaint::kUnderlineText_Flag) { 1974 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, 1975 start.fY); 1976 r.fTop = offset; 1977 r.fBottom = offset + height; 1978 DrawRect(draw, paint, r, textSize); 1979 } 1980 if (flags & SkPaint::kStrikeThruText_Flag) { 1981 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, 1982 start.fY); 1983 r.fTop = offset; 1984 r.fBottom = offset + height; 1985 DrawRect(draw, paint, r, textSize); 1986 } 1987 } 1988} 1989 1990void SkCanvas::drawText(const void* text, size_t byteLength, 1991 SkScalar x, SkScalar y, const SkPaint& paint) { 1992 CHECK_SHADER_NOSETCONTEXT(paint); 1993 1994 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1995 1996 while (iter.next()) { 1997 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1998 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 1999 DrawTextDecorations(iter, dfp.paint(), 2000 static_cast<const char*>(text), byteLength, x, y); 2001 } 2002 2003 LOOPER_END 2004} 2005 2006void SkCanvas::drawPosText(const void* text, size_t byteLength, 2007 const SkPoint pos[], const SkPaint& paint) { 2008 CHECK_SHADER_NOSETCONTEXT(paint); 2009 2010 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 2011 2012 while (iter.next()) { 2013 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2014 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 2015 dfp.paint()); 2016 } 2017 2018 LOOPER_END 2019} 2020 2021void SkCanvas::drawPosTextH(const void* text, size_t byteLength, 2022 const SkScalar xpos[], SkScalar constY, 2023 const SkPaint& paint) { 2024 CHECK_SHADER_NOSETCONTEXT(paint); 2025 2026 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 2027 2028 while (iter.next()) { 2029 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2030 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 2031 dfp.paint()); 2032 } 2033 2034 LOOPER_END 2035} 2036 2037void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, 2038 const SkPath& path, const SkMatrix* matrix, 2039 const SkPaint& paint) { 2040 CHECK_SHADER_NOSETCONTEXT(paint); 2041 2042 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 2043 2044 while (iter.next()) { 2045 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 2046 matrix, looper.paint()); 2047 } 2048 2049 LOOPER_END 2050} 2051 2052#ifdef SK_BUILD_FOR_ANDROID 2053void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength, 2054 const SkPoint pos[], const SkPaint& paint, 2055 const SkPath& path, const SkMatrix* matrix) { 2056 CHECK_SHADER_NOSETCONTEXT(paint); 2057 2058 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 2059 2060 while (iter.next()) { 2061 iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos, 2062 looper.paint(), path, matrix); 2063 } 2064 2065 LOOPER_END 2066} 2067#endif 2068 2069void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 2070 const SkPoint verts[], const SkPoint texs[], 2071 const SkColor colors[], SkXfermode* xmode, 2072 const uint16_t indices[], int indexCount, 2073 const SkPaint& paint) { 2074 CHECK_SHADER_NOSETCONTEXT(paint); 2075 2076 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 2077 2078 while (iter.next()) { 2079 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 2080 colors, xmode, indices, indexCount, 2081 looper.paint()); 2082 } 2083 2084 LOOPER_END 2085} 2086 2087////////////////////////////////////////////////////////////////////////////// 2088// These methods are NOT virtual, and therefore must call back into virtual 2089// methods, rather than actually drawing themselves. 2090////////////////////////////////////////////////////////////////////////////// 2091 2092void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 2093 SkXfermode::Mode mode) { 2094 SkPaint paint; 2095 2096 paint.setARGB(a, r, g, b); 2097 if (SkXfermode::kSrcOver_Mode != mode) { 2098 paint.setXfermodeMode(mode); 2099 } 2100 this->drawPaint(paint); 2101} 2102 2103void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 2104 SkPaint paint; 2105 2106 paint.setColor(c); 2107 if (SkXfermode::kSrcOver_Mode != mode) { 2108 paint.setXfermodeMode(mode); 2109 } 2110 this->drawPaint(paint); 2111} 2112 2113void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 2114 SkPoint pt; 2115 2116 pt.set(x, y); 2117 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2118} 2119 2120void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 2121 SkPoint pt; 2122 SkPaint paint; 2123 2124 pt.set(x, y); 2125 paint.setColor(color); 2126 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2127} 2128 2129void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 2130 const SkPaint& paint) { 2131 SkPoint pts[2]; 2132 2133 pts[0].set(x0, y0); 2134 pts[1].set(x1, y1); 2135 this->drawPoints(kLines_PointMode, 2, pts, paint); 2136} 2137 2138void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 2139 SkScalar right, SkScalar bottom, 2140 const SkPaint& paint) { 2141 SkRect r; 2142 2143 r.set(left, top, right, bottom); 2144 this->drawRect(r, paint); 2145} 2146 2147void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 2148 const SkPaint& paint) { 2149 if (radius < 0) { 2150 radius = 0; 2151 } 2152 2153 SkRect r; 2154 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 2155 this->drawOval(r, paint); 2156} 2157 2158void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 2159 const SkPaint& paint) { 2160 if (rx > 0 && ry > 0) { 2161 if (paint.canComputeFastBounds()) { 2162 SkRect storage; 2163 if (this->quickReject(paint.computeFastBounds(r, &storage))) { 2164 return; 2165 } 2166 } 2167 SkRRect rrect; 2168 rrect.setRectXY(r, rx, ry); 2169 this->drawRRect(rrect, paint); 2170 } else { 2171 this->drawRect(r, paint); 2172 } 2173} 2174 2175void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 2176 SkScalar sweepAngle, bool useCenter, 2177 const SkPaint& paint) { 2178 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 2179 this->drawOval(oval, paint); 2180 } else { 2181 SkPath path; 2182 if (useCenter) { 2183 path.moveTo(oval.centerX(), oval.centerY()); 2184 } 2185 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 2186 if (useCenter) { 2187 path.close(); 2188 } 2189 this->drawPath(path, paint); 2190 } 2191} 2192 2193void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 2194 const SkPath& path, SkScalar hOffset, 2195 SkScalar vOffset, const SkPaint& paint) { 2196 SkMatrix matrix; 2197 2198 matrix.setTranslate(hOffset, vOffset); 2199 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 2200} 2201 2202/////////////////////////////////////////////////////////////////////////////// 2203 2204void SkCanvas::drawPicture(SkPicture& picture) { 2205 picture.draw(this); 2206} 2207 2208/////////////////////////////////////////////////////////////////////////////// 2209/////////////////////////////////////////////////////////////////////////////// 2210 2211SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 2212 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); 2213 2214 SkASSERT(canvas); 2215 2216 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 2217 fDone = !fImpl->next(); 2218} 2219 2220SkCanvas::LayerIter::~LayerIter() { 2221 fImpl->~SkDrawIter(); 2222} 2223 2224void SkCanvas::LayerIter::next() { 2225 fDone = !fImpl->next(); 2226} 2227 2228SkDevice* SkCanvas::LayerIter::device() const { 2229 return fImpl->getDevice(); 2230} 2231 2232const SkMatrix& SkCanvas::LayerIter::matrix() const { 2233 return fImpl->getMatrix(); 2234} 2235 2236const SkPaint& SkCanvas::LayerIter::paint() const { 2237 const SkPaint* paint = fImpl->getPaint(); 2238 if (NULL == paint) { 2239 paint = &fDefaultPaint; 2240 } 2241 return *paint; 2242} 2243 2244const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 2245int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 2246int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 2247 2248/////////////////////////////////////////////////////////////////////////////// 2249 2250SkCanvas::ClipVisitor::~ClipVisitor() { } 2251