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