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