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