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