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