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