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