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