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