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