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