SkCanvas.cpp revision de358a9946fb6cffa905c7aa0e5f29cf6960b927
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 "SkCanvasDrawable.h" 10#include "SkCanvasPriv.h" 11#include "SkBitmapDevice.h" 12#include "SkDeviceImageFilterProxy.h" 13#include "SkDraw.h" 14#include "SkDrawFilter.h" 15#include "SkDrawLooper.h" 16#include "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 bounds = &paint.computeFastBounds(r, &storage); 1780 if (this->quickReject(*bounds)) { 1781 return; 1782 } 1783 } 1784 1785 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds) 1786 1787 while (iter.next()) { 1788 iter.fDevice->drawRect(iter, r, looper.paint()); 1789 } 1790 1791 LOOPER_END 1792} 1793 1794void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) { 1795 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()"); 1796 SkRect storage; 1797 const SkRect* bounds = NULL; 1798 if (paint.canComputeFastBounds()) { 1799 bounds = &paint.computeFastBounds(oval, &storage); 1800 if (this->quickReject(*bounds)) { 1801 return; 1802 } 1803 } 1804 1805 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds) 1806 1807 while (iter.next()) { 1808 iter.fDevice->drawOval(iter, oval, looper.paint()); 1809 } 1810 1811 LOOPER_END 1812} 1813 1814void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { 1815 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()"); 1816 SkRect storage; 1817 const SkRect* bounds = NULL; 1818 if (paint.canComputeFastBounds()) { 1819 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage); 1820 if (this->quickReject(*bounds)) { 1821 return; 1822 } 1823 } 1824 1825 if (rrect.isRect()) { 1826 // call the non-virtual version 1827 this->SkCanvas::drawRect(rrect.getBounds(), paint); 1828 return; 1829 } else if (rrect.isOval()) { 1830 // call the non-virtual version 1831 this->SkCanvas::drawOval(rrect.getBounds(), paint); 1832 return; 1833 } 1834 1835 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) 1836 1837 while (iter.next()) { 1838 iter.fDevice->drawRRect(iter, rrect, looper.paint()); 1839 } 1840 1841 LOOPER_END 1842} 1843 1844void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, 1845 const SkPaint& paint) { 1846 SkRect storage; 1847 const SkRect* bounds = NULL; 1848 if (paint.canComputeFastBounds()) { 1849 bounds = &paint.computeFastBounds(outer.getBounds(), &storage); 1850 if (this->quickReject(*bounds)) { 1851 return; 1852 } 1853 } 1854 1855 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) 1856 1857 while (iter.next()) { 1858 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint()); 1859 } 1860 1861 LOOPER_END 1862} 1863 1864void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { 1865 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()"); 1866 if (!path.isFinite()) { 1867 return; 1868 } 1869 1870 SkRect storage; 1871 const SkRect* bounds = NULL; 1872 if (!path.isInverseFillType() && paint.canComputeFastBounds()) { 1873 const SkRect& pathBounds = path.getBounds(); 1874 bounds = &paint.computeFastBounds(pathBounds, &storage); 1875 if (this->quickReject(*bounds)) { 1876 return; 1877 } 1878 } 1879 1880 const SkRect& r = path.getBounds(); 1881 if (r.width() <= 0 && r.height() <= 0) { 1882 if (path.isInverseFillType()) { 1883 this->internalDrawPaint(paint); 1884 } 1885 return; 1886 } 1887 1888 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds) 1889 1890 while (iter.next()) { 1891 iter.fDevice->drawPath(iter, path, looper.paint()); 1892 } 1893 1894 LOOPER_END 1895} 1896 1897void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) { 1898 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()"); 1899 image->draw(this, dx, dy, paint); 1900} 1901 1902void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, 1903 const SkPaint* paint) { 1904 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()"); 1905 image->drawRect(this, src, dst, paint); 1906} 1907 1908void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) { 1909 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()"); 1910 SkDEBUGCODE(bitmap.validate();) 1911 1912 if (NULL == paint || paint->canComputeFastBounds()) { 1913 SkRect bounds = { 1914 x, y, 1915 x + SkIntToScalar(bitmap.width()), 1916 y + SkIntToScalar(bitmap.height()) 1917 }; 1918 if (paint) { 1919 (void)paint->computeFastBounds(bounds, &bounds); 1920 } 1921 if (this->quickReject(bounds)) { 1922 return; 1923 } 1924 } 1925 1926 SkMatrix matrix; 1927 matrix.setTranslate(x, y); 1928 this->internalDrawBitmap(bitmap, matrix, paint); 1929} 1930 1931// this one is non-virtual, so it can be called safely by other canvas apis 1932void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, 1933 const SkRect& dst, const SkPaint* paint, 1934 DrawBitmapRectFlags flags) { 1935 if (bitmap.drawsNothing() || dst.isEmpty()) { 1936 return; 1937 } 1938 1939 SkRect storage; 1940 const SkRect* bounds = &dst; 1941 if (NULL == paint || paint->canComputeFastBounds()) { 1942 if (paint) { 1943 bounds = &paint->computeFastBounds(dst, &storage); 1944 } 1945 if (this->quickReject(*bounds)) { 1946 return; 1947 } 1948 } 1949 1950 SkLazyPaint lazy; 1951 if (NULL == paint) { 1952 paint = lazy.init(); 1953 } 1954 1955 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) 1956 1957 while (iter.next()) { 1958 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags); 1959 } 1960 1961 LOOPER_END 1962} 1963 1964void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, 1965 const SkPaint* paint, DrawBitmapRectFlags flags) { 1966 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()"); 1967 SkDEBUGCODE(bitmap.validate();) 1968 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags); 1969} 1970 1971void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap, 1972 const SkIRect& center, const SkRect& dst, 1973 const SkPaint* paint) { 1974 if (bitmap.drawsNothing()) { 1975 return; 1976 } 1977 if (NULL == paint || paint->canComputeFastBounds()) { 1978 SkRect storage; 1979 const SkRect* bounds = &dst; 1980 if (paint) { 1981 bounds = &paint->computeFastBounds(dst, &storage); 1982 } 1983 if (this->quickReject(*bounds)) { 1984 return; 1985 } 1986 } 1987 1988 const int32_t w = bitmap.width(); 1989 const int32_t h = bitmap.height(); 1990 1991 SkIRect c = center; 1992 // pin center to the bounds of the bitmap 1993 c.fLeft = SkMax32(0, center.fLeft); 1994 c.fTop = SkMax32(0, center.fTop); 1995 c.fRight = SkPin32(center.fRight, c.fLeft, w); 1996 c.fBottom = SkPin32(center.fBottom, c.fTop, h); 1997 1998 const SkScalar srcX[4] = { 1999 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w) 2000 }; 2001 const SkScalar srcY[4] = { 2002 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h) 2003 }; 2004 SkScalar dstX[4] = { 2005 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft), 2006 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight 2007 }; 2008 SkScalar dstY[4] = { 2009 dst.fTop, dst.fTop + SkIntToScalar(c.fTop), 2010 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom 2011 }; 2012 2013 if (dstX[1] > dstX[2]) { 2014 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width()); 2015 dstX[2] = dstX[1]; 2016 } 2017 2018 if (dstY[1] > dstY[2]) { 2019 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height()); 2020 dstY[2] = dstY[1]; 2021 } 2022 2023 for (int y = 0; y < 3; y++) { 2024 SkRect s, d; 2025 2026 s.fTop = srcY[y]; 2027 s.fBottom = srcY[y+1]; 2028 d.fTop = dstY[y]; 2029 d.fBottom = dstY[y+1]; 2030 for (int x = 0; x < 3; x++) { 2031 s.fLeft = srcX[x]; 2032 s.fRight = srcX[x+1]; 2033 d.fLeft = dstX[x]; 2034 d.fRight = dstX[x+1]; 2035 this->internalDrawBitmapRect(bitmap, &s, d, paint, 2036 kNone_DrawBitmapRectFlag); 2037 } 2038 } 2039} 2040 2041void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, 2042 const SkPaint* paint) { 2043 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()"); 2044 SkDEBUGCODE(bitmap.validate();) 2045 2046 // Need a device entry-point, so gpu can use a mesh 2047 this->internalDrawBitmapNine(bitmap, center, dst, paint); 2048} 2049 2050class SkDeviceFilteredPaint { 2051public: 2052 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) { 2053 uint32_t filteredFlags = device->filterTextFlags(paint); 2054 if (filteredFlags != paint.getFlags()) { 2055 SkPaint* newPaint = fLazy.set(paint); 2056 newPaint->setFlags(filteredFlags); 2057 fPaint = newPaint; 2058 } else { 2059 fPaint = &paint; 2060 } 2061 } 2062 2063 const SkPaint& paint() const { return *fPaint; } 2064 2065private: 2066 const SkPaint* fPaint; 2067 SkLazyPaint fLazy; 2068}; 2069 2070void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, 2071 const SkRect& r, SkScalar textSize) { 2072 if (paint.getStyle() == SkPaint::kFill_Style) { 2073 draw.fDevice->drawRect(draw, r, paint); 2074 } else { 2075 SkPaint p(paint); 2076 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); 2077 draw.fDevice->drawRect(draw, r, p); 2078 } 2079} 2080 2081void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, 2082 const char text[], size_t byteLength, 2083 SkScalar x, SkScalar y) { 2084 SkASSERT(byteLength == 0 || text != NULL); 2085 2086 // nothing to draw 2087 if (text == NULL || byteLength == 0 || 2088 draw.fClip->isEmpty() || 2089 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 2090 return; 2091 } 2092 2093 SkScalar width = 0; 2094 SkPoint start; 2095 2096 start.set(0, 0); // to avoid warning 2097 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | 2098 SkPaint::kStrikeThruText_Flag)) { 2099 width = paint.measureText(text, byteLength); 2100 2101 SkScalar offsetX = 0; 2102 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 2103 offsetX = SkScalarHalf(width); 2104 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { 2105 offsetX = width; 2106 } 2107 start.set(x - offsetX, y); 2108 } 2109 2110 if (0 == width) { 2111 return; 2112 } 2113 2114 uint32_t flags = paint.getFlags(); 2115 2116 if (flags & (SkPaint::kUnderlineText_Flag | 2117 SkPaint::kStrikeThruText_Flag)) { 2118 SkScalar textSize = paint.getTextSize(); 2119 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 2120 SkRect r; 2121 2122 r.fLeft = start.fX; 2123 r.fRight = start.fX + width; 2124 2125 if (flags & SkPaint::kUnderlineText_Flag) { 2126 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, 2127 start.fY); 2128 r.fTop = offset; 2129 r.fBottom = offset + height; 2130 DrawRect(draw, paint, r, textSize); 2131 } 2132 if (flags & SkPaint::kStrikeThruText_Flag) { 2133 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, 2134 start.fY); 2135 r.fTop = offset; 2136 r.fBottom = offset + height; 2137 DrawRect(draw, paint, r, textSize); 2138 } 2139 } 2140} 2141 2142void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, 2143 const SkPaint& paint) { 2144 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2145 2146 while (iter.next()) { 2147 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2148 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 2149 DrawTextDecorations(iter, dfp.paint(), 2150 static_cast<const char*>(text), byteLength, x, y); 2151 } 2152 2153 LOOPER_END 2154} 2155 2156void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], 2157 const SkPaint& paint) { 2158 SkPoint textOffset = SkPoint::Make(0, 0); 2159 2160 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2161 2162 while (iter.next()) { 2163 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2164 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset, 2165 dfp.paint()); 2166 } 2167 2168 LOOPER_END 2169} 2170 2171void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], 2172 SkScalar constY, const SkPaint& paint) { 2173 2174 SkPoint textOffset = SkPoint::Make(0, constY); 2175 2176 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2177 2178 while (iter.next()) { 2179 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2180 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset, 2181 dfp.paint()); 2182 } 2183 2184 LOOPER_END 2185} 2186 2187void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, 2188 const SkMatrix* matrix, const SkPaint& paint) { 2189 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2190 2191 while (iter.next()) { 2192 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 2193 matrix, looper.paint()); 2194 } 2195 2196 LOOPER_END 2197} 2198 2199void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 2200 const SkPaint& paint) { 2201 2202 if (paint.canComputeFastBounds()) { 2203 SkRect storage; 2204 2205 if (this->quickReject(paint.computeFastBounds(blob->bounds().makeOffset(x, y), &storage))) { 2206 return; 2207 } 2208 } 2209 2210 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2211 2212 while (iter.next()) { 2213 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2214 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint()); 2215 } 2216 2217 LOOPER_END 2218} 2219 2220// These will become non-virtual, so they always call the (virtual) onDraw... method 2221void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, 2222 const SkPaint& paint) { 2223 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()"); 2224 this->onDrawText(text, byteLength, x, y, paint); 2225} 2226void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[], 2227 const SkPaint& paint) { 2228 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()"); 2229 this->onDrawPosText(text, byteLength, pos, paint); 2230} 2231void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], 2232 SkScalar constY, const SkPaint& paint) { 2233 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()"); 2234 this->onDrawPosTextH(text, byteLength, xpos, constY, paint); 2235} 2236void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path, 2237 const SkMatrix* matrix, const SkPaint& paint) { 2238 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()"); 2239 this->onDrawTextOnPath(text, byteLength, path, matrix, paint); 2240} 2241void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 2242 const SkPaint& paint) { 2243 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()"); 2244 if (blob) { 2245 this->onDrawTextBlob(blob, x, y, paint); 2246 } 2247} 2248 2249void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount, 2250 const SkPoint verts[], const SkPoint texs[], 2251 const SkColor colors[], SkXfermode* xmode, 2252 const uint16_t indices[], int indexCount, 2253 const SkPaint& paint) { 2254 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()"); 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 2266void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4], 2267 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { 2268 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()"); 2269 if (NULL == cubics) { 2270 return; 2271 } 2272 2273 // Since a patch is always within the convex hull of the control points, we discard it when its 2274 // bounding rectangle is completely outside the current clip. 2275 SkRect bounds; 2276 bounds.set(cubics, SkPatchUtils::kNumCtrlPts); 2277 if (this->quickReject(bounds)) { 2278 return; 2279 } 2280 2281 this->onDrawPatch(cubics, colors, texCoords, xmode, paint); 2282} 2283 2284void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], 2285 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { 2286 2287 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL) 2288 2289 while (iter.next()) { 2290 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint); 2291 } 2292 2293 LOOPER_END 2294} 2295 2296void SkCanvas::EXPERIMENTAL_drawDrawable(SkCanvasDrawable* dr) { 2297 if (dr && !this->quickReject(dr->getBounds())) { 2298 this->onDrawDrawable(dr); 2299 } 2300} 2301 2302void SkCanvas::onDrawDrawable(SkCanvasDrawable* dr) { 2303 dr->draw(this); 2304} 2305 2306////////////////////////////////////////////////////////////////////////////// 2307// These methods are NOT virtual, and therefore must call back into virtual 2308// methods, rather than actually drawing themselves. 2309////////////////////////////////////////////////////////////////////////////// 2310 2311void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 2312 SkXfermode::Mode mode) { 2313 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()"); 2314 SkPaint paint; 2315 2316 paint.setARGB(a, r, g, b); 2317 if (SkXfermode::kSrcOver_Mode != mode) { 2318 paint.setXfermodeMode(mode); 2319 } 2320 this->drawPaint(paint); 2321} 2322 2323void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 2324 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()"); 2325 SkPaint paint; 2326 2327 paint.setColor(c); 2328 if (SkXfermode::kSrcOver_Mode != mode) { 2329 paint.setXfermodeMode(mode); 2330 } 2331 this->drawPaint(paint); 2332} 2333 2334void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 2335 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)"); 2336 SkPoint pt; 2337 2338 pt.set(x, y); 2339 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2340} 2341 2342void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 2343 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)"); 2344 SkPoint pt; 2345 SkPaint paint; 2346 2347 pt.set(x, y); 2348 paint.setColor(color); 2349 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2350} 2351 2352void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 2353 const SkPaint& paint) { 2354 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()"); 2355 SkPoint pts[2]; 2356 2357 pts[0].set(x0, y0); 2358 pts[1].set(x1, y1); 2359 this->drawPoints(kLines_PointMode, 2, pts, paint); 2360} 2361 2362void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 2363 SkScalar right, SkScalar bottom, 2364 const SkPaint& paint) { 2365 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()"); 2366 SkRect r; 2367 2368 r.set(left, top, right, bottom); 2369 this->drawRect(r, paint); 2370} 2371 2372void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 2373 const SkPaint& paint) { 2374 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()"); 2375 if (radius < 0) { 2376 radius = 0; 2377 } 2378 2379 SkRect r; 2380 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 2381 this->drawOval(r, paint); 2382} 2383 2384void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 2385 const SkPaint& paint) { 2386 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()"); 2387 if (rx > 0 && ry > 0) { 2388 if (paint.canComputeFastBounds()) { 2389 SkRect storage; 2390 if (this->quickReject(paint.computeFastBounds(r, &storage))) { 2391 return; 2392 } 2393 } 2394 SkRRect rrect; 2395 rrect.setRectXY(r, rx, ry); 2396 this->drawRRect(rrect, paint); 2397 } else { 2398 this->drawRect(r, paint); 2399 } 2400} 2401 2402void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 2403 SkScalar sweepAngle, bool useCenter, 2404 const SkPaint& paint) { 2405 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()"); 2406 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 2407 this->drawOval(oval, paint); 2408 } else { 2409 SkPath path; 2410 if (useCenter) { 2411 path.moveTo(oval.centerX(), oval.centerY()); 2412 } 2413 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 2414 if (useCenter) { 2415 path.close(); 2416 } 2417 this->drawPath(path, paint); 2418 } 2419} 2420 2421void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 2422 const SkPath& path, SkScalar hOffset, 2423 SkScalar vOffset, const SkPaint& paint) { 2424 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()"); 2425 SkMatrix matrix; 2426 2427 matrix.setTranslate(hOffset, vOffset); 2428 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 2429} 2430 2431/////////////////////////////////////////////////////////////////////////////// 2432void SkCanvas::drawPicture(const SkPicture* picture) { 2433 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()"); 2434 if (picture) { 2435 this->onDrawPicture(picture, NULL, NULL); 2436 } 2437} 2438 2439void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) { 2440 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)"); 2441 if (picture) { 2442 if (matrix && matrix->isIdentity()) { 2443 matrix = NULL; 2444 } 2445 this->onDrawPicture(picture, matrix, paint); 2446 } 2447} 2448 2449void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, 2450 const SkPaint* paint) { 2451 SkBaseDevice* device = this->getTopDevice(); 2452 if (device) { 2453 // Canvas has to first give the device the opportunity to render 2454 // the picture itself. 2455 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) { 2456 return; // the device has rendered the entire picture 2457 } 2458 } 2459 2460 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); 2461 2462 picture->playback(this); 2463} 2464 2465/////////////////////////////////////////////////////////////////////////////// 2466/////////////////////////////////////////////////////////////////////////////// 2467 2468SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 2469 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); 2470 2471 SkASSERT(canvas); 2472 2473 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 2474 fDone = !fImpl->next(); 2475} 2476 2477SkCanvas::LayerIter::~LayerIter() { 2478 fImpl->~SkDrawIter(); 2479} 2480 2481void SkCanvas::LayerIter::next() { 2482 fDone = !fImpl->next(); 2483} 2484 2485SkBaseDevice* SkCanvas::LayerIter::device() const { 2486 return fImpl->getDevice(); 2487} 2488 2489const SkMatrix& SkCanvas::LayerIter::matrix() const { 2490 return fImpl->getMatrix(); 2491} 2492 2493const SkPaint& SkCanvas::LayerIter::paint() const { 2494 const SkPaint* paint = fImpl->getPaint(); 2495 if (NULL == paint) { 2496 paint = &fDefaultPaint; 2497 } 2498 return *paint; 2499} 2500 2501const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 2502int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 2503int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 2504 2505/////////////////////////////////////////////////////////////////////////////// 2506 2507SkCanvasClipVisitor::~SkCanvasClipVisitor() { } 2508 2509/////////////////////////////////////////////////////////////////////////////// 2510 2511static bool supported_for_raster_canvas(const SkImageInfo& info) { 2512 switch (info.alphaType()) { 2513 case kPremul_SkAlphaType: 2514 case kOpaque_SkAlphaType: 2515 break; 2516 default: 2517 return false; 2518 } 2519 2520 switch (info.colorType()) { 2521 case kAlpha_8_SkColorType: 2522 case kRGB_565_SkColorType: 2523 case kN32_SkColorType: 2524 break; 2525 default: 2526 return false; 2527 } 2528 2529 return true; 2530} 2531 2532SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) { 2533 if (!supported_for_raster_canvas(info)) { 2534 return NULL; 2535 } 2536 2537 SkBitmap bitmap; 2538 if (!bitmap.installPixels(info, pixels, rowBytes)) { 2539 return NULL; 2540 } 2541 return SkNEW_ARGS(SkCanvas, (bitmap)); 2542} 2543 2544/////////////////////////////////////////////////////////////////////////////// 2545 2546SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix, 2547 const SkPaint* paint, const SkRect& bounds) 2548 : fCanvas(canvas) 2549 , fSaveCount(canvas->getSaveCount()) 2550{ 2551 if (paint) { 2552 SkRect newBounds = bounds; 2553 if (matrix) { 2554 matrix->mapRect(&newBounds); 2555 } 2556 canvas->saveLayer(&newBounds, paint); 2557 } else if (matrix) { 2558 canvas->save(); 2559 } 2560 2561 if (matrix) { 2562 canvas->concat(*matrix); 2563 } 2564} 2565 2566SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() { 2567 fCanvas->restoreToCount(fSaveCount); 2568} 2569