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