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