SkCanvas.cpp revision 6c157640c27ee2ed6f9a484d21691b7b19dfecde
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 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 SkDevice* 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 485SkDevice* SkCanvas::init(SkDevice* 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(SkDevice* 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(SkDevice, (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 SkDevice* device = this->getDevice(); 568 if (device) { 569 device->flush(); 570 } 571} 572 573SkISize SkCanvas::getDeviceSize() const { 574 SkDevice* d = this->getDevice(); 575 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0); 576} 577 578SkDevice* 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 585SkDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const { 586 if (updateMatrixClip) { 587 const_cast<SkCanvas*>(this)->updateDeviceCMCache(); 588 } 589 return fMCRec->fTopLayer->fDevice; 590} 591 592SkDevice* SkCanvas::setDevice(SkDevice* device) { 593 // return root device 594 SkDeque::F2BIter iter(fMCStack); 595 MCRec* rec = (MCRec*)iter.next(); 596 SkASSERT(rec && rec->fLayer); 597 SkDevice* 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 SkDevice* 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 SkDevice* 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 SkDevice* 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 SkDevice* 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 SkDevice* 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 SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1); 934} 935 936int SkCanvas::getSaveCount() const { 937 return fMCStack.count(); 938} 939 940void SkCanvas::restoreToCount(int count) { 941 // sanity check 942 if (count < 1) { 943 count = 1; 944 } 945 946 int n = this->getSaveCount() - count; 947 for (int i = 0; i < n; ++i) { 948 this->restore(); 949 } 950} 951 952bool SkCanvas::isDrawingToLayer() const { 953 return fSaveLayerCount > 0; 954} 955 956///////////////////////////////////////////////////////////////////////////// 957 958// can't draw it if its empty, or its too big for a fixed-point width or height 959static bool reject_bitmap(const SkBitmap& bitmap) { 960 return bitmap.width() <= 0 || bitmap.height() <= 0; 961} 962 963void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, 964 const SkMatrix& matrix, const SkPaint* paint) { 965 if (reject_bitmap(bitmap)) { 966 return; 967 } 968 969 SkLazyPaint lazy; 970 if (NULL == paint) { 971 paint = lazy.init(); 972 } 973 974 SkDEBUGCODE(bitmap.validate();) 975 CHECK_LOCKCOUNT_BALANCE(bitmap); 976 977 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type) 978 979 while (iter.next()) { 980 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint()); 981 } 982 983 LOOPER_END 984} 985 986void SkCanvas::internalDrawDevice(SkDevice* srcDev, int x, int y, 987 const SkPaint* paint) { 988 SkPaint tmp; 989 if (NULL == paint) { 990 tmp.setDither(true); 991 paint = &tmp; 992 } 993 994 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 995 while (iter.next()) { 996 SkDevice* dstDev = iter.fDevice; 997 paint = &looper.paint(); 998 SkImageFilter* filter = paint->getImageFilter(); 999 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 1000 if (filter && !dstDev->canHandleImageFilter(filter)) { 1001 SkDeviceImageFilterProxy proxy(dstDev); 1002 SkBitmap dst; 1003 const SkBitmap& src = srcDev->accessBitmap(false); 1004 if (filter->filterImage(&proxy, src, *iter.fMatrix, &dst, &pos)) { 1005 SkPaint tmpUnfiltered(*paint); 1006 tmpUnfiltered.setImageFilter(NULL); 1007 dstDev->drawSprite(iter, dst, pos.x(), pos.y(), tmpUnfiltered); 1008 } 1009 } else { 1010 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint); 1011 } 1012 } 1013 LOOPER_END 1014} 1015 1016void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, 1017 const SkPaint* paint) { 1018 SkDEBUGCODE(bitmap.validate();) 1019 CHECK_LOCKCOUNT_BALANCE(bitmap); 1020 1021 if (reject_bitmap(bitmap)) { 1022 return; 1023 } 1024 1025 SkPaint tmp; 1026 if (NULL == paint) { 1027 paint = &tmp; 1028 } 1029 1030 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 1031 1032 while (iter.next()) { 1033 paint = &looper.paint(); 1034 SkImageFilter* filter = paint->getImageFilter(); 1035 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 1036 if (filter && !iter.fDevice->canHandleImageFilter(filter)) { 1037 SkDeviceImageFilterProxy proxy(iter.fDevice); 1038 SkBitmap dst; 1039 if (filter->filterImage(&proxy, bitmap, *iter.fMatrix, 1040 &dst, &pos)) { 1041 SkPaint tmpUnfiltered(*paint); 1042 tmpUnfiltered.setImageFilter(NULL); 1043 iter.fDevice->drawSprite(iter, dst, pos.x(), pos.y(), 1044 tmpUnfiltered); 1045 } 1046 } else { 1047 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint); 1048 } 1049 } 1050 LOOPER_END 1051} 1052 1053///////////////////////////////////////////////////////////////////////////// 1054 1055bool SkCanvas::translate(SkScalar dx, SkScalar dy) { 1056 fDeviceCMDirty = true; 1057 fLocalBoundsCompareTypeDirty = true; 1058 return fMCRec->fMatrix->preTranslate(dx, dy); 1059} 1060 1061bool SkCanvas::scale(SkScalar sx, SkScalar sy) { 1062 fDeviceCMDirty = true; 1063 fLocalBoundsCompareTypeDirty = true; 1064 return fMCRec->fMatrix->preScale(sx, sy); 1065} 1066 1067bool SkCanvas::rotate(SkScalar degrees) { 1068 fDeviceCMDirty = true; 1069 fLocalBoundsCompareTypeDirty = true; 1070 return fMCRec->fMatrix->preRotate(degrees); 1071} 1072 1073bool SkCanvas::skew(SkScalar sx, SkScalar sy) { 1074 fDeviceCMDirty = true; 1075 fLocalBoundsCompareTypeDirty = true; 1076 return fMCRec->fMatrix->preSkew(sx, sy); 1077} 1078 1079bool SkCanvas::concat(const SkMatrix& matrix) { 1080 fDeviceCMDirty = true; 1081 fLocalBoundsCompareTypeDirty = true; 1082 return fMCRec->fMatrix->preConcat(matrix); 1083} 1084 1085void SkCanvas::setMatrix(const SkMatrix& matrix) { 1086 fDeviceCMDirty = true; 1087 fLocalBoundsCompareTypeDirty = true; 1088 *fMCRec->fMatrix = matrix; 1089} 1090 1091// this is not virtual, so it must call a virtual method so that subclasses 1092// will see its action 1093void SkCanvas::resetMatrix() { 1094 SkMatrix matrix; 1095 1096 matrix.reset(); 1097 this->setMatrix(matrix); 1098} 1099 1100////////////////////////////////////////////////////////////////////////////// 1101 1102bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 1103#ifdef SK_ENABLE_CLIP_QUICKREJECT 1104 if (SkRegion::kIntersect_Op == op) { 1105 if (fMCRec->fRasterClip->isEmpty()) { 1106 return false; 1107 } 1108 1109 if (this->quickReject(rect)) { 1110 fDeviceCMDirty = true; 1111 fLocalBoundsCompareTypeDirty = true; 1112 1113 fClipStack.clipEmpty(); 1114 return fMCRec->fRasterClip->setEmpty(); 1115 } 1116 } 1117#endif 1118 1119 AutoValidateClip avc(this); 1120 1121 fDeviceCMDirty = true; 1122 fLocalBoundsCompareTypeDirty = true; 1123 doAA &= fAllowSoftClip; 1124 1125 if (fMCRec->fMatrix->rectStaysRect()) { 1126 // for these simpler matrices, we can stay a rect ever after applying 1127 // the matrix. This means we don't have to a) make a path, and b) tell 1128 // the region code to scan-convert the path, only to discover that it 1129 // is really just a rect. 1130 SkRect r; 1131 1132 fMCRec->fMatrix->mapRect(&r, rect); 1133 fClipStack.clipDevRect(r, op, doAA); 1134 return fMCRec->fRasterClip->op(r, op, doAA); 1135 } else { 1136 // since we're rotate or some such thing, we convert the rect to a path 1137 // and clip against that, since it can handle any matrix. However, to 1138 // avoid recursion in the case where we are subclassed (e.g. Pictures) 1139 // we explicitly call "our" version of clipPath. 1140 SkPath path; 1141 1142 path.addRect(rect); 1143 return this->SkCanvas::clipPath(path, op, doAA); 1144 } 1145} 1146 1147static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip, 1148 const SkPath& devPath, SkRegion::Op op, bool doAA) { 1149 // base is used to limit the size (and therefore memory allocation) of the 1150 // region that results from scan converting devPath. 1151 SkRegion base; 1152 1153 if (SkRegion::kIntersect_Op == op) { 1154 // since we are intersect, we can do better (tighter) with currRgn's 1155 // bounds, than just using the device. However, if currRgn is complex, 1156 // our region blitter may hork, so we do that case in two steps. 1157 if (currClip->isRect()) { 1158 // FIXME: we should also be able to do this when currClip->isBW(), 1159 // but relaxing the test above triggers GM asserts in 1160 // SkRgnBuilder::blitH(). We need to investigate what's going on. 1161 return currClip->setPath(devPath, currClip->bwRgn(), doAA); 1162 } else { 1163 base.setRect(currClip->getBounds()); 1164 SkRasterClip clip; 1165 clip.setPath(devPath, base, doAA); 1166 return currClip->op(clip, op); 1167 } 1168 } else { 1169 const SkDevice* device = canvas->getDevice(); 1170 if (!device) { 1171 return currClip->setEmpty(); 1172 } 1173 1174 base.setRect(0, 0, device->width(), device->height()); 1175 1176 if (SkRegion::kReplace_Op == op) { 1177 return currClip->setPath(devPath, base, doAA); 1178 } else { 1179 SkRasterClip clip; 1180 clip.setPath(devPath, base, doAA); 1181 return currClip->op(clip, op); 1182 } 1183 } 1184} 1185 1186bool SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 1187 if (rrect.isRect()) { 1188 // call the non-virtual version 1189 return this->SkCanvas::clipRect(rrect.getBounds(), op, doAA); 1190 } else { 1191 SkPath path; 1192 path.addRRect(rrect); 1193 // call the non-virtual version 1194 return this->SkCanvas::clipPath(path, op, doAA); 1195 } 1196} 1197 1198bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 1199#ifdef SK_ENABLE_CLIP_QUICKREJECT 1200 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { 1201 if (fMCRec->fRasterClip->isEmpty()) { 1202 return false; 1203 } 1204 1205 if (this->quickReject(path.getBounds())) { 1206 fDeviceCMDirty = true; 1207 fLocalBoundsCompareTypeDirty = true; 1208 1209 fClipStack.clipEmpty(); 1210 return fMCRec->fRasterClip->setEmpty(); 1211 } 1212 } 1213#endif 1214 1215 AutoValidateClip avc(this); 1216 1217 fDeviceCMDirty = true; 1218 fLocalBoundsCompareTypeDirty = true; 1219 doAA &= fAllowSoftClip; 1220 1221 SkPath devPath; 1222 path.transform(*fMCRec->fMatrix, &devPath); 1223 1224 // Check if the transfomation, or the original path itself 1225 // made us empty. Note this can also happen if we contained NaN 1226 // values. computing the bounds detects this, and will set our 1227 // bounds to empty if that is the case. (see SkRect::set(pts, count)) 1228 if (devPath.getBounds().isEmpty()) { 1229 // resetting the path will remove any NaN or other wanky values 1230 // that might upset our scan converter. 1231 devPath.reset(); 1232 } 1233 1234 // if we called path.swap() we could avoid a deep copy of this path 1235 fClipStack.clipDevPath(devPath, op, doAA); 1236 1237 if (fAllowSimplifyClip) { 1238 devPath.reset(); 1239 devPath.setFillType(SkPath::kInverseEvenOdd_FillType); 1240 const SkClipStack* clipStack = getClipStack(); 1241 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart); 1242 const SkClipStack::Element* element; 1243 while ((element = iter.next())) { 1244 SkClipStack::Element::Type type = element->getType(); 1245 if (type == SkClipStack::Element::kEmpty_Type) { 1246 continue; 1247 } 1248 SkPath operand; 1249 if (type == SkClipStack::Element::kRect_Type) { 1250 operand.addRect(element->getRect()); 1251 } else if (type == SkClipStack::Element::kPath_Type) { 1252 operand = element->getPath(); 1253 } else { 1254 SkDEBUGFAIL("Unexpected type."); 1255 } 1256 SkRegion::Op elementOp = element->getOp(); 1257 if (elementOp == SkRegion::kReplace_Op) { 1258 devPath = operand; 1259 } else { 1260 Op(devPath, operand, (SkPathOp) elementOp, &devPath); 1261 } 1262 // if the prev and curr clips disagree about aa -vs- not, favor the aa request. 1263 // perhaps we need an API change to avoid this sort of mixed-signals about 1264 // clipping. 1265 doAA |= element->isAA(); 1266 } 1267 op = SkRegion::kReplace_Op; 1268 } 1269 1270 return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA); 1271} 1272 1273bool SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op, 1274 bool inverseFilled) { 1275 // This is for updating the clip conservatively using only bounds 1276 // information. 1277 // Contract: 1278 // The current clip must contain the true clip. The true 1279 // clip is the clip that would have normally been computed 1280 // by calls to clipPath and clipRRect 1281 // Objective: 1282 // Keep the current clip as small as possible without 1283 // breaking the contract, using only clip bounding rectangles 1284 // (for performance). 1285 1286 // N.B.: This *never* calls back through a virtual on canvas, so subclasses 1287 // don't have to worry about getting caught in a loop. Thus anywhere 1288 // we call a virtual method, we explicitly prefix it with 1289 // SkCanvas:: to be sure to call the base-class. 1290 1291 if (inverseFilled) { 1292 switch (op) { 1293 case SkRegion::kIntersect_Op: 1294 case SkRegion::kDifference_Op: 1295 // These ops can only shrink the current clip. So leaving 1296 // the clip unchanges conservatively respects the contract. 1297 return this->getClipDeviceBounds(NULL); 1298 case SkRegion::kUnion_Op: 1299 case SkRegion::kReplace_Op: 1300 case SkRegion::kReverseDifference_Op: 1301 case SkRegion::kXOR_Op: 1302 { 1303 // These ops can grow the current clip up to the extents of 1304 // the input clip, which is inverse filled, so we just set 1305 // the current clip to the device bounds. 1306 SkRect deviceBounds; 1307 SkIRect deviceIBounds; 1308 this->getDevice()->getGlobalBounds(&deviceIBounds); 1309 deviceBounds = SkRect::MakeFromIRect(deviceIBounds); 1310 this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag); 1311 // set the clip in device space 1312 this->SkCanvas::setMatrix(SkMatrix::I()); 1313 bool result = this->SkCanvas::clipRect(deviceBounds, 1314 SkRegion::kReplace_Op, false); 1315 this->SkCanvas::restore(); //pop the matrix, but keep the clip 1316 return result; 1317 } 1318 default: 1319 SkASSERT(0); // unhandled op? 1320 } 1321 } else { 1322 // Not inverse filled 1323 switch (op) { 1324 case SkRegion::kIntersect_Op: 1325 case SkRegion::kUnion_Op: 1326 case SkRegion::kReplace_Op: 1327 return this->SkCanvas::clipRect(bounds, op, false); 1328 case SkRegion::kDifference_Op: 1329 // Difference can only shrink the current clip. 1330 // Leaving clip unchanged conservatively fullfills the contract. 1331 return this->getClipDeviceBounds(NULL); 1332 case SkRegion::kReverseDifference_Op: 1333 // To reverse, we swap in the bounds with a replace op. 1334 // As with difference, leave it unchanged. 1335 return this->SkCanvas::clipRect(bounds, SkRegion::kReplace_Op, false); 1336 case SkRegion::kXOR_Op: 1337 // Be conservative, based on (A XOR B) always included in (A union B), 1338 // which is always included in (bounds(A) union bounds(B)) 1339 return this->SkCanvas::clipRect(bounds, SkRegion::kUnion_Op, false); 1340 default: 1341 SkASSERT(0); // unhandled op? 1342 } 1343 } 1344 return true; 1345} 1346 1347bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1348 AutoValidateClip avc(this); 1349 1350 fDeviceCMDirty = true; 1351 fLocalBoundsCompareTypeDirty = true; 1352 1353 // todo: signal fClipStack that we have a region, and therefore (I guess) 1354 // we have to ignore it, and use the region directly? 1355 fClipStack.clipDevRect(rgn.getBounds(), op); 1356 1357 return fMCRec->fRasterClip->op(rgn, op); 1358} 1359 1360#ifdef SK_DEBUG 1361void SkCanvas::validateClip() const { 1362 // construct clipRgn from the clipstack 1363 const SkDevice* device = this->getDevice(); 1364 if (!device) { 1365 SkASSERT(this->getTotalClip().isEmpty()); 1366 return; 1367 } 1368 1369 SkIRect ir; 1370 ir.set(0, 0, device->width(), device->height()); 1371 SkRasterClip tmpClip(ir); 1372 1373 SkClipStack::B2TIter iter(fClipStack); 1374 const SkClipStack::Element* element; 1375 while ((element = iter.next()) != NULL) { 1376 switch (element->getType()) { 1377 case SkClipStack::Element::kPath_Type: 1378 clipPathHelper(this, 1379 &tmpClip, 1380 element->getPath(), 1381 element->getOp(), 1382 element->isAA()); 1383 break; 1384 case SkClipStack::Element::kRect_Type: 1385 element->getRect().round(&ir); 1386 tmpClip.op(ir, element->getOp()); 1387 break; 1388 case SkClipStack::Element::kEmpty_Type: 1389 tmpClip.setEmpty(); 1390 break; 1391 } 1392 } 1393 1394#if 0 // enable this locally for testing 1395 // now compare against the current rgn 1396 const SkRegion& rgn = this->getTotalClip(); 1397 SkASSERT(rgn == tmpClip); 1398#endif 1399} 1400#endif 1401 1402void SkCanvas::replayClips(ClipVisitor* visitor) const { 1403 SkClipStack::B2TIter iter(fClipStack); 1404 const SkClipStack::Element* element; 1405 1406 static const SkRect kEmpty = { 0, 0, 0, 0 }; 1407 while ((element = iter.next()) != NULL) { 1408 switch (element->getType()) { 1409 case SkClipStack::Element::kPath_Type: 1410 visitor->clipPath(element->getPath(), element->getOp(), element->isAA()); 1411 break; 1412 case SkClipStack::Element::kRect_Type: 1413 visitor->clipRect(element->getRect(), element->getOp(), element->isAA()); 1414 break; 1415 case SkClipStack::Element::kEmpty_Type: 1416 visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false); 1417 break; 1418 } 1419 } 1420} 1421 1422/////////////////////////////////////////////////////////////////////////////// 1423 1424void SkCanvas::computeLocalClipBoundsCompareType() const { 1425 SkRect r; 1426 1427 if (!this->getClipBounds(&r)) { 1428 fLocalBoundsCompareType.setEmpty(); 1429 } else { 1430 fLocalBoundsCompareType.set(SkScalarToCompareType(r.fLeft), 1431 SkScalarToCompareType(r.fTop), 1432 SkScalarToCompareType(r.fRight), 1433 SkScalarToCompareType(r.fBottom)); 1434 } 1435} 1436 1437bool SkCanvas::quickReject(const SkRect& rect) const { 1438 1439 if (!rect.isFinite()) 1440 return true; 1441 1442 if (fMCRec->fRasterClip->isEmpty()) { 1443 return true; 1444 } 1445 1446 if (fMCRec->fMatrix->hasPerspective()) { 1447 SkRect dst; 1448 fMCRec->fMatrix->mapRect(&dst, rect); 1449 SkIRect idst; 1450 dst.roundOut(&idst); 1451 return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds()); 1452 } else { 1453 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(); 1454 1455 // for speed, do the most likely reject compares first 1456 SkScalarCompareType userT = SkScalarToCompareType(rect.fTop); 1457 SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom); 1458 if (userT >= clipR.fBottom || userB <= clipR.fTop) { 1459 return true; 1460 } 1461 SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft); 1462 SkScalarCompareType userR = SkScalarToCompareType(rect.fRight); 1463 if (userL >= clipR.fRight || userR <= clipR.fLeft) { 1464 return true; 1465 } 1466 return false; 1467 } 1468} 1469 1470bool SkCanvas::quickReject(const SkPath& path) const { 1471 return path.isEmpty() || this->quickReject(path.getBounds()); 1472} 1473 1474static inline int pinIntForScalar(int x) { 1475#ifdef SK_SCALAR_IS_FIXED 1476 if (x < SK_MinS16) { 1477 x = SK_MinS16; 1478 } else if (x > SK_MaxS16) { 1479 x = SK_MaxS16; 1480 } 1481#endif 1482 return x; 1483} 1484 1485bool SkCanvas::getClipBounds(SkRect* bounds) const { 1486 SkIRect ibounds; 1487 if (!getClipDeviceBounds(&ibounds)) { 1488 return false; 1489 } 1490 1491 SkMatrix inverse; 1492 // if we can't invert the CTM, we can't return local clip bounds 1493 if (!fMCRec->fMatrix->invert(&inverse)) { 1494 if (bounds) { 1495 bounds->setEmpty(); 1496 } 1497 return false; 1498 } 1499 1500 if (NULL != bounds) { 1501 SkRect r; 1502 // adjust it outwards in case we are antialiasing 1503 const int inset = 1; 1504 1505 // SkRect::iset() will correctly assert if we pass a value out of range 1506 // (when SkScalar==fixed), so we pin to legal values. This does not 1507 // really returnt the correct answer, but its the best we can do given 1508 // that we've promised to return SkRect (even though we support devices 1509 // that can be larger than 32K in width or height). 1510 r.iset(pinIntForScalar(ibounds.fLeft - inset), 1511 pinIntForScalar(ibounds.fTop - inset), 1512 pinIntForScalar(ibounds.fRight + inset), 1513 pinIntForScalar(ibounds.fBottom + inset)); 1514 inverse.mapRect(bounds, r); 1515 } 1516 return true; 1517} 1518 1519bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const { 1520 const SkRasterClip& clip = *fMCRec->fRasterClip; 1521 if (clip.isEmpty()) { 1522 if (bounds) { 1523 bounds->setEmpty(); 1524 } 1525 return false; 1526 } 1527 1528 if (NULL != bounds) { 1529 *bounds = clip.getBounds(); 1530 } 1531 return true; 1532} 1533 1534const SkMatrix& SkCanvas::getTotalMatrix() const { 1535 return *fMCRec->fMatrix; 1536} 1537 1538SkCanvas::ClipType SkCanvas::getClipType() const { 1539 if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType; 1540 if (fMCRec->fRasterClip->isRect()) return kRect_ClipType; 1541 return kComplex_ClipType; 1542} 1543 1544const SkRegion& SkCanvas::getTotalClip() const { 1545 return fMCRec->fRasterClip->forceGetBW(); 1546} 1547 1548SkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config, 1549 int width, int height, 1550 bool isOpaque) { 1551 SkDevice* device = this->getTopDevice(); 1552 if (device) { 1553 return device->createCompatibleDeviceForSaveLayer(config, width, height, 1554 isOpaque); 1555 } else { 1556 return NULL; 1557 } 1558} 1559 1560SkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config, 1561 int width, int height, 1562 bool isOpaque) { 1563 SkDevice* device = this->getDevice(); 1564 if (device) { 1565 return device->createCompatibleDevice(config, width, height, isOpaque); 1566 } else { 1567 return NULL; 1568 } 1569} 1570 1571 1572////////////////////////////////////////////////////////////////////////////// 1573// These are the virtual drawing methods 1574////////////////////////////////////////////////////////////////////////////// 1575 1576void SkCanvas::clear(SkColor color) { 1577 SkDrawIter iter(this); 1578 this->predrawNotify(); 1579 while (iter.next()) { 1580 iter.fDevice->clear(color); 1581 } 1582} 1583 1584void SkCanvas::drawPaint(const SkPaint& paint) { 1585 this->internalDrawPaint(paint); 1586} 1587 1588void SkCanvas::internalDrawPaint(const SkPaint& paint) { 1589 CHECK_SHADER_NOSETCONTEXT(paint); 1590 1591 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type) 1592 1593 while (iter.next()) { 1594 iter.fDevice->drawPaint(iter, looper.paint()); 1595 } 1596 1597 LOOPER_END 1598} 1599 1600void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1601 const SkPaint& paint) { 1602 if ((long)count <= 0) { 1603 return; 1604 } 1605 1606 CHECK_SHADER_NOSETCONTEXT(paint); 1607 1608 if (paint.canComputeFastBounds()) { 1609 SkRect r; 1610 // special-case 2 points (common for drawing a single line) 1611 if (2 == count) { 1612 r.set(pts[0], pts[1]); 1613 } else { 1614 r.set(pts, count); 1615 } 1616 SkRect storage; 1617 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) { 1618 return; 1619 } 1620 } 1621 1622 SkASSERT(pts != NULL); 1623 1624 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type) 1625 1626 while (iter.next()) { 1627 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); 1628 } 1629 1630 LOOPER_END 1631} 1632 1633void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1634 CHECK_SHADER_NOSETCONTEXT(paint); 1635 1636 if (paint.canComputeFastBounds()) { 1637 SkRect storage; 1638 if (this->quickReject(paint.computeFastBounds(r, &storage))) { 1639 return; 1640 } 1641 } 1642 1643 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type) 1644 1645 while (iter.next()) { 1646 iter.fDevice->drawRect(iter, r, looper.paint()); 1647 } 1648 1649 LOOPER_END 1650} 1651 1652void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1653 CHECK_SHADER_NOSETCONTEXT(paint); 1654 1655 if (paint.canComputeFastBounds()) { 1656 SkRect storage; 1657 if (this->quickReject(paint.computeFastBounds(oval, &storage))) { 1658 return; 1659 } 1660 } 1661 1662 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type) 1663 1664 while (iter.next()) { 1665 iter.fDevice->drawOval(iter, oval, looper.paint()); 1666 } 1667 1668 LOOPER_END 1669} 1670 1671void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 1672 CHECK_SHADER_NOSETCONTEXT(paint); 1673 1674 if (paint.canComputeFastBounds()) { 1675 SkRect storage; 1676 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) { 1677 return; 1678 } 1679 } 1680 1681 if (rrect.isRect()) { 1682 // call the non-virtual version 1683 this->SkCanvas::drawRect(rrect.getBounds(), paint); 1684 return; 1685 } else if (rrect.isOval()) { 1686 // call the non-virtual version 1687 this->SkCanvas::drawOval(rrect.getBounds(), paint); 1688 return; 1689 } 1690 1691 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type) 1692 1693 while (iter.next()) { 1694 iter.fDevice->drawRRect(iter, rrect, looper.paint()); 1695 } 1696 1697 LOOPER_END 1698} 1699 1700 1701void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 1702 CHECK_SHADER_NOSETCONTEXT(paint); 1703 1704 if (!path.isFinite()) { 1705 return; 1706 } 1707 1708 if (!path.isInverseFillType() && paint.canComputeFastBounds()) { 1709 SkRect storage; 1710 const SkRect& bounds = path.getBounds(); 1711 if (this->quickReject(paint.computeFastBounds(bounds, &storage))) { 1712 return; 1713 } 1714 } 1715 if (path.isEmpty()) { 1716 if (path.isInverseFillType()) { 1717 this->internalDrawPaint(paint); 1718 } 1719 return; 1720 } 1721 1722 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 1723 1724 while (iter.next()) { 1725 iter.fDevice->drawPath(iter, path, looper.paint()); 1726 } 1727 1728 LOOPER_END 1729} 1730 1731void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, 1732 const SkPaint* paint) { 1733 SkDEBUGCODE(bitmap.validate();) 1734 1735 if (NULL == paint || paint->canComputeFastBounds()) { 1736 SkRect bounds = { 1737 x, y, 1738 x + SkIntToScalar(bitmap.width()), 1739 y + SkIntToScalar(bitmap.height()) 1740 }; 1741 if (paint) { 1742 (void)paint->computeFastBounds(bounds, &bounds); 1743 } 1744 if (this->quickReject(bounds)) { 1745 return; 1746 } 1747 } 1748 1749 SkMatrix matrix; 1750 matrix.setTranslate(x, y); 1751 this->internalDrawBitmap(bitmap, matrix, paint); 1752} 1753 1754// this one is non-virtual, so it can be called safely by other canvas apis 1755void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, 1756 const SkRect& dst, const SkPaint* paint) { 1757 if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) { 1758 return; 1759 } 1760 1761 CHECK_LOCKCOUNT_BALANCE(bitmap); 1762 1763 if (NULL == paint || paint->canComputeFastBounds()) { 1764 SkRect storage; 1765 const SkRect* bounds = &dst; 1766 if (paint) { 1767 bounds = &paint->computeFastBounds(dst, &storage); 1768 } 1769 if (this->quickReject(*bounds)) { 1770 return; 1771 } 1772 } 1773 1774 SkLazyPaint lazy; 1775 if (NULL == paint) { 1776 paint = lazy.init(); 1777 } 1778 1779 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type) 1780 1781 while (iter.next()) { 1782 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint()); 1783 } 1784 1785 LOOPER_END 1786} 1787 1788void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, 1789 const SkRect& dst, const SkPaint* paint) { 1790 SkDEBUGCODE(bitmap.validate();) 1791 this->internalDrawBitmapRect(bitmap, src, dst, paint); 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 } 1863 } 1864} 1865 1866void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 1867 const SkRect& dst, const SkPaint* paint) { 1868 SkDEBUGCODE(bitmap.validate();) 1869 1870 // Need a device entry-point, so gpu can use a mesh 1871 this->internalDrawBitmapNine(bitmap, center, dst, paint); 1872} 1873 1874class SkDeviceFilteredPaint { 1875public: 1876 SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) { 1877 SkDevice::TextFlags flags; 1878 if (device->filterTextFlags(paint, &flags)) { 1879 SkPaint* newPaint = fLazy.set(paint); 1880 newPaint->setFlags(flags.fFlags); 1881 newPaint->setHinting(flags.fHinting); 1882 fPaint = newPaint; 1883 } else { 1884 fPaint = &paint; 1885 } 1886 } 1887 1888 const SkPaint& paint() const { return *fPaint; } 1889 1890private: 1891 const SkPaint* fPaint; 1892 SkLazyPaint fLazy; 1893}; 1894 1895void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, 1896 const SkRect& r, SkScalar textSize) { 1897 if (paint.getStyle() == SkPaint::kFill_Style) { 1898 draw.fDevice->drawRect(draw, r, paint); 1899 } else { 1900 SkPaint p(paint); 1901 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); 1902 draw.fDevice->drawRect(draw, r, p); 1903 } 1904} 1905 1906void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, 1907 const char text[], size_t byteLength, 1908 SkScalar x, SkScalar y) { 1909 SkASSERT(byteLength == 0 || text != NULL); 1910 1911 // nothing to draw 1912 if (text == NULL || byteLength == 0 || 1913 draw.fClip->isEmpty() || 1914 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 1915 return; 1916 } 1917 1918 SkScalar width = 0; 1919 SkPoint start; 1920 1921 start.set(0, 0); // to avoid warning 1922 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | 1923 SkPaint::kStrikeThruText_Flag)) { 1924 width = paint.measureText(text, byteLength); 1925 1926 SkScalar offsetX = 0; 1927 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 1928 offsetX = SkScalarHalf(width); 1929 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { 1930 offsetX = width; 1931 } 1932 start.set(x - offsetX, y); 1933 } 1934 1935 if (0 == width) { 1936 return; 1937 } 1938 1939 uint32_t flags = paint.getFlags(); 1940 1941 if (flags & (SkPaint::kUnderlineText_Flag | 1942 SkPaint::kStrikeThruText_Flag)) { 1943 SkScalar textSize = paint.getTextSize(); 1944 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 1945 SkRect r; 1946 1947 r.fLeft = start.fX; 1948 r.fRight = start.fX + width; 1949 1950 if (flags & SkPaint::kUnderlineText_Flag) { 1951 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, 1952 start.fY); 1953 r.fTop = offset; 1954 r.fBottom = offset + height; 1955 DrawRect(draw, paint, r, textSize); 1956 } 1957 if (flags & SkPaint::kStrikeThruText_Flag) { 1958 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, 1959 start.fY); 1960 r.fTop = offset; 1961 r.fBottom = offset + height; 1962 DrawRect(draw, paint, r, textSize); 1963 } 1964 } 1965} 1966 1967void SkCanvas::drawText(const void* text, size_t byteLength, 1968 SkScalar x, SkScalar y, const SkPaint& paint) { 1969 CHECK_SHADER_NOSETCONTEXT(paint); 1970 1971 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1972 1973 while (iter.next()) { 1974 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1975 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 1976 DrawTextDecorations(iter, dfp.paint(), 1977 static_cast<const char*>(text), byteLength, x, y); 1978 } 1979 1980 LOOPER_END 1981} 1982 1983void SkCanvas::drawPosText(const void* text, size_t byteLength, 1984 const SkPoint pos[], const SkPaint& paint) { 1985 CHECK_SHADER_NOSETCONTEXT(paint); 1986 1987 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1988 1989 while (iter.next()) { 1990 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1991 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 1992 dfp.paint()); 1993 } 1994 1995 LOOPER_END 1996} 1997 1998void SkCanvas::drawPosTextH(const void* text, size_t byteLength, 1999 const SkScalar xpos[], SkScalar constY, 2000 const SkPaint& paint) { 2001 CHECK_SHADER_NOSETCONTEXT(paint); 2002 2003 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 2004 2005 while (iter.next()) { 2006 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2007 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 2008 dfp.paint()); 2009 } 2010 2011 LOOPER_END 2012} 2013 2014void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, 2015 const SkPath& path, const SkMatrix* matrix, 2016 const SkPaint& paint) { 2017 CHECK_SHADER_NOSETCONTEXT(paint); 2018 2019 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 2020 2021 while (iter.next()) { 2022 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 2023 matrix, looper.paint()); 2024 } 2025 2026 LOOPER_END 2027} 2028 2029#ifdef SK_BUILD_FOR_ANDROID 2030void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength, 2031 const SkPoint pos[], const SkPaint& paint, 2032 const SkPath& path, const SkMatrix* matrix) { 2033 CHECK_SHADER_NOSETCONTEXT(paint); 2034 2035 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 2036 2037 while (iter.next()) { 2038 iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos, 2039 looper.paint(), path, matrix); 2040 } 2041 2042 LOOPER_END 2043} 2044#endif 2045 2046void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 2047 const SkPoint verts[], const SkPoint texs[], 2048 const SkColor colors[], SkXfermode* xmode, 2049 const uint16_t indices[], int indexCount, 2050 const SkPaint& paint) { 2051 CHECK_SHADER_NOSETCONTEXT(paint); 2052 2053 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 2054 2055 while (iter.next()) { 2056 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 2057 colors, xmode, indices, indexCount, 2058 looper.paint()); 2059 } 2060 2061 LOOPER_END 2062} 2063 2064////////////////////////////////////////////////////////////////////////////// 2065// These methods are NOT virtual, and therefore must call back into virtual 2066// methods, rather than actually drawing themselves. 2067////////////////////////////////////////////////////////////////////////////// 2068 2069void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 2070 SkXfermode::Mode mode) { 2071 SkPaint paint; 2072 2073 paint.setARGB(a, r, g, b); 2074 if (SkXfermode::kSrcOver_Mode != mode) { 2075 paint.setXfermodeMode(mode); 2076 } 2077 this->drawPaint(paint); 2078} 2079 2080void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 2081 SkPaint paint; 2082 2083 paint.setColor(c); 2084 if (SkXfermode::kSrcOver_Mode != mode) { 2085 paint.setXfermodeMode(mode); 2086 } 2087 this->drawPaint(paint); 2088} 2089 2090void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 2091 SkPoint pt; 2092 2093 pt.set(x, y); 2094 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2095} 2096 2097void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 2098 SkPoint pt; 2099 SkPaint paint; 2100 2101 pt.set(x, y); 2102 paint.setColor(color); 2103 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2104} 2105 2106void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 2107 const SkPaint& paint) { 2108 SkPoint pts[2]; 2109 2110 pts[0].set(x0, y0); 2111 pts[1].set(x1, y1); 2112 this->drawPoints(kLines_PointMode, 2, pts, paint); 2113} 2114 2115void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 2116 SkScalar right, SkScalar bottom, 2117 const SkPaint& paint) { 2118 SkRect r; 2119 2120 r.set(left, top, right, bottom); 2121 this->drawRect(r, paint); 2122} 2123 2124void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 2125 const SkPaint& paint) { 2126 if (radius < 0) { 2127 radius = 0; 2128 } 2129 2130 SkRect r; 2131 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 2132 this->drawOval(r, paint); 2133} 2134 2135void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 2136 const SkPaint& paint) { 2137 if (rx > 0 && ry > 0) { 2138 if (paint.canComputeFastBounds()) { 2139 SkRect storage; 2140 if (this->quickReject(paint.computeFastBounds(r, &storage))) { 2141 return; 2142 } 2143 } 2144 SkRRect rrect; 2145 rrect.setRectXY(r, rx, ry); 2146 this->drawRRect(rrect, paint); 2147 } else { 2148 this->drawRect(r, paint); 2149 } 2150} 2151 2152void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 2153 SkScalar sweepAngle, bool useCenter, 2154 const SkPaint& paint) { 2155 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 2156 this->drawOval(oval, paint); 2157 } else { 2158 SkPath path; 2159 if (useCenter) { 2160 path.moveTo(oval.centerX(), oval.centerY()); 2161 } 2162 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 2163 if (useCenter) { 2164 path.close(); 2165 } 2166 this->drawPath(path, paint); 2167 } 2168} 2169 2170void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 2171 const SkPath& path, SkScalar hOffset, 2172 SkScalar vOffset, const SkPaint& paint) { 2173 SkMatrix matrix; 2174 2175 matrix.setTranslate(hOffset, vOffset); 2176 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 2177} 2178 2179/////////////////////////////////////////////////////////////////////////////// 2180 2181void SkCanvas::drawPicture(SkPicture& picture) { 2182 picture.draw(this); 2183} 2184 2185/////////////////////////////////////////////////////////////////////////////// 2186/////////////////////////////////////////////////////////////////////////////// 2187 2188SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 2189 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); 2190 2191 SkASSERT(canvas); 2192 2193 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 2194 fDone = !fImpl->next(); 2195} 2196 2197SkCanvas::LayerIter::~LayerIter() { 2198 fImpl->~SkDrawIter(); 2199} 2200 2201void SkCanvas::LayerIter::next() { 2202 fDone = !fImpl->next(); 2203} 2204 2205SkDevice* SkCanvas::LayerIter::device() const { 2206 return fImpl->getDevice(); 2207} 2208 2209const SkMatrix& SkCanvas::LayerIter::matrix() const { 2210 return fImpl->getMatrix(); 2211} 2212 2213const SkPaint& SkCanvas::LayerIter::paint() const { 2214 const SkPaint* paint = fImpl->getPaint(); 2215 if (NULL == paint) { 2216 paint = &fDefaultPaint; 2217 } 2218 return *paint; 2219} 2220 2221const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 2222int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 2223int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 2224 2225/////////////////////////////////////////////////////////////////////////////// 2226 2227SkCanvas::ClipVisitor::~ClipVisitor() { } 2228