SkCanvas.cpp revision 54823c227d383308fb1732e83b566df6272d4bfb
1 2/* 3 * Copyright 2008 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10#include "SkCanvas.h" 11#include "SkBounder.h" 12#include "SkDevice.h" 13#include "SkDraw.h" 14#include "SkDrawFilter.h" 15#include "SkDrawLooper.h" 16#include "SkPicture.h" 17#include "SkRasterClip.h" 18#include "SkScalarCompare.h" 19#include "SkTemplates.h" 20#include "SkTextFormatParams.h" 21#include "SkTLazy.h" 22#include "SkUtils.h" 23 24SK_DEFINE_INST_COUNT(SkBounder) 25SK_DEFINE_INST_COUNT(SkCanvas) 26SK_DEFINE_INST_COUNT(SkDrawFilter) 27 28 29//#define SK_TRACE_SAVERESTORE 30 31#ifdef SK_TRACE_SAVERESTORE 32 static int gLayerCounter; 33 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); } 34 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); } 35 36 static int gRecCounter; 37 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); } 38 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); } 39 40 static int gCanvasCounter; 41 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); } 42 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); } 43#else 44 #define inc_layer() 45 #define dec_layer() 46 #define inc_rec() 47 #define dec_rec() 48 #define inc_canvas() 49 #define dec_canvas() 50#endif 51 52typedef SkTLazy<SkPaint> SkLazyPaint; 53 54/////////////////////////////////////////////////////////////////////////////// 55// Helpers for computing fast bounds for quickReject tests 56 57static SkCanvas::EdgeType paint2EdgeType(const SkPaint* paint) { 58 return paint != NULL && paint->isAntiAlias() ? 59 SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType; 60} 61 62/////////////////////////////////////////////////////////////////////////////// 63 64/* This is the record we keep for each SkDevice that the user installs. 65 The clip/matrix/proc are fields that reflect the top of the save/restore 66 stack. Whenever the canvas changes, it marks a dirty flag, and then before 67 these are used (assuming we're not on a layer) we rebuild these cache 68 values: they reflect the top of the save stack, but translated and clipped 69 by the device's XY offset and bitmap-bounds. 70*/ 71struct DeviceCM { 72 DeviceCM* fNext; 73 SkDevice* fDevice; 74 SkRasterClip fClip; 75 const SkMatrix* fMatrix; 76 SkPaint* fPaint; // may be null (in the future) 77 // optional, related to canvas' external matrix 78 const SkMatrix* fMVMatrix; 79 const SkMatrix* fExtMatrix; 80 81 DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint) 82 : fNext(NULL) { 83 if (NULL != device) { 84 device->ref(); 85 device->lockPixels(); 86 } 87 fDevice = device; 88 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL; 89 } 90 91 ~DeviceCM() { 92 if (NULL != fDevice) { 93 fDevice->unlockPixels(); 94 fDevice->unref(); 95 } 96 SkDELETE(fPaint); 97 } 98 99 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip, 100 const SkClipStack& clipStack, SkRasterClip* updateClip) { 101 int x = fDevice->getOrigin().x(); 102 int y = fDevice->getOrigin().y(); 103 int width = fDevice->width(); 104 int height = fDevice->height(); 105 106 if ((x | y) == 0) { 107 fMatrix = &totalMatrix; 108 fClip = totalClip; 109 } else { 110 fMatrixStorage = totalMatrix; 111 fMatrixStorage.postTranslate(SkIntToScalar(-x), 112 SkIntToScalar(-y)); 113 fMatrix = &fMatrixStorage; 114 115 totalClip.translate(-x, -y, &fClip); 116 } 117 118 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op); 119 120 // intersect clip, but don't translate it (yet) 121 122 if (updateClip) { 123 updateClip->op(SkIRect::MakeXYWH(x, y, width, height), 124 SkRegion::kDifference_Op); 125 } 126 127 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack); 128 129#ifdef SK_DEBUG 130 if (!fClip.isEmpty()) { 131 SkIRect deviceR; 132 deviceR.set(0, 0, width, height); 133 SkASSERT(deviceR.contains(fClip.getBounds())); 134 } 135#endif 136 // default is to assume no external matrix 137 fMVMatrix = NULL; 138 fExtMatrix = NULL; 139 } 140 141 // can only be called after calling updateMC() 142 void updateExternalMatrix(const SkMatrix& extM, const SkMatrix& extI) { 143 fMVMatrixStorage.setConcat(extI, *fMatrix); 144 fMVMatrix = &fMVMatrixStorage; 145 fExtMatrix = &extM; // assumes extM has long life-time (owned by canvas) 146 } 147 148private: 149 SkMatrix fMatrixStorage, fMVMatrixStorage; 150}; 151 152/* This is the record we keep for each save/restore level in the stack. 153 Since a level optionally copies the matrix and/or stack, we have pointers 154 for these fields. If the value is copied for this level, the copy is 155 stored in the ...Storage field, and the pointer points to that. If the 156 value is not copied for this level, we ignore ...Storage, and just point 157 at the corresponding value in the previous level in the stack. 158*/ 159class SkCanvas::MCRec { 160public: 161 MCRec* fNext; 162 SkMatrix* fMatrix; // points to either fMatrixStorage or prev MCRec 163 SkRasterClip* fRasterClip; // points to either fRegionStorage or prev MCRec 164 SkDrawFilter* fFilter; // the current filter (or null) 165 166 DeviceCM* fLayer; 167 /* If there are any layers in the stack, this points to the top-most 168 one that is at or below this level in the stack (so we know what 169 bitmap/device to draw into from this level. This value is NOT 170 reference counted, since the real owner is either our fLayer field, 171 or a previous one in a lower level.) 172 */ 173 DeviceCM* fTopLayer; 174 175 MCRec(const MCRec* prev, int flags) { 176 if (NULL != prev) { 177 if (flags & SkCanvas::kMatrix_SaveFlag) { 178 fMatrixStorage = *prev->fMatrix; 179 fMatrix = &fMatrixStorage; 180 } else { 181 fMatrix = prev->fMatrix; 182 } 183 184 if (flags & SkCanvas::kClip_SaveFlag) { 185 fRasterClipStorage = *prev->fRasterClip; 186 fRasterClip = &fRasterClipStorage; 187 } else { 188 fRasterClip = prev->fRasterClip; 189 } 190 191 fFilter = prev->fFilter; 192 SkSafeRef(fFilter); 193 194 fTopLayer = prev->fTopLayer; 195 } else { // no prev 196 fMatrixStorage.reset(); 197 198 fMatrix = &fMatrixStorage; 199 fRasterClip = &fRasterClipStorage; 200 fFilter = NULL; 201 fTopLayer = NULL; 202 } 203 fLayer = NULL; 204 205 // don't bother initializing fNext 206 inc_rec(); 207 } 208 ~MCRec() { 209 SkSafeUnref(fFilter); 210 SkDELETE(fLayer); 211 dec_rec(); 212 } 213 214private: 215 SkMatrix fMatrixStorage; 216 SkRasterClip fRasterClipStorage; 217}; 218 219class SkDrawIter : public SkDraw { 220public: 221 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) { 222 canvas = canvas->canvasForDrawIter(); 223 fCanvas = canvas; 224 canvas->updateDeviceCMCache(); 225 226 fClipStack = &canvas->fClipStack; 227 fBounder = canvas->getBounder(); 228 fCurrLayer = canvas->fMCRec->fTopLayer; 229 fSkipEmptyClips = skipEmptyClips; 230 } 231 232 bool next() { 233 // skip over recs with empty clips 234 if (fSkipEmptyClips) { 235 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) { 236 fCurrLayer = fCurrLayer->fNext; 237 } 238 } 239 240 const DeviceCM* rec = fCurrLayer; 241 if (rec && rec->fDevice) { 242 243 fMatrix = rec->fMatrix; 244 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW(); 245 fRC = &rec->fClip; 246 fDevice = rec->fDevice; 247 fBitmap = &fDevice->accessBitmap(true); 248 fPaint = rec->fPaint; 249 fMVMatrix = rec->fMVMatrix; 250 fExtMatrix = rec->fExtMatrix; 251 SkDEBUGCODE(this->validate();) 252 253 fCurrLayer = rec->fNext; 254 if (fBounder) { 255 fBounder->setClip(fClip); 256 } 257 // fCurrLayer may be NULL now 258 259 fCanvas->prepareForDeviceDraw(fDevice, *fMatrix, *fClip, *fClipStack); 260 return true; 261 } 262 return false; 263 } 264 265 SkDevice* getDevice() const { return fDevice; } 266 int getX() const { return fDevice->getOrigin().x(); } 267 int getY() const { return fDevice->getOrigin().y(); } 268 const SkMatrix& getMatrix() const { return *fMatrix; } 269 const SkRegion& getClip() const { return *fClip; } 270 const SkPaint* getPaint() const { return fPaint; } 271 272private: 273 SkCanvas* fCanvas; 274 const DeviceCM* fCurrLayer; 275 const SkPaint* fPaint; // May be null. 276 SkBool8 fSkipEmptyClips; 277 278 typedef SkDraw INHERITED; 279}; 280 281///////////////////////////////////////////////////////////////////////////// 282 283class AutoDrawLooper { 284public: 285 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, 286 bool skipLayerForImageFilter = false) : fOrigPaint(paint) { 287 fCanvas = canvas; 288 fLooper = paint.getLooper(); 289 fFilter = canvas->getDrawFilter(); 290 fPaint = NULL; 291 fSaveCount = canvas->getSaveCount(); 292 fDoClearImageFilter = false; 293 fDone = false; 294 295 if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) { 296 SkPaint tmp; 297 tmp.setImageFilter(fOrigPaint.getImageFilter()); 298 // it would be nice if we had a guess at the bounds, instead of null 299 (void)canvas->internalSaveLayer(NULL, &tmp, 300 SkCanvas::kARGB_ClipLayer_SaveFlag, true); 301 // we'll clear the imageFilter for the actual draws in next(), so 302 // it will only be applied during the restore(). 303 fDoClearImageFilter = true; 304 } 305 306 if (fLooper) { 307 fLooper->init(canvas); 308 fIsSimple = false; 309 } else { 310 // can we be marked as simple? 311 fIsSimple = !fFilter && !fDoClearImageFilter; 312 } 313 } 314 315 ~AutoDrawLooper() { 316 if (fDoClearImageFilter) { 317 fCanvas->internalRestore(); 318 } 319 SkASSERT(fCanvas->getSaveCount() == fSaveCount); 320 } 321 322 const SkPaint& paint() const { 323 SkASSERT(fPaint); 324 return *fPaint; 325 } 326 327 bool next(SkDrawFilter::Type drawType) { 328 if (fDone) { 329 return false; 330 } else if (fIsSimple) { 331 fDone = true; 332 fPaint = &fOrigPaint; 333 return !fPaint->nothingToDraw(); 334 } else { 335 return this->doNext(drawType); 336 } 337 } 338 339private: 340 SkLazyPaint fLazyPaint; 341 SkCanvas* fCanvas; 342 const SkPaint& fOrigPaint; 343 SkDrawLooper* fLooper; 344 SkDrawFilter* fFilter; 345 const SkPaint* fPaint; 346 int fSaveCount; 347 bool fDoClearImageFilter; 348 bool fDone; 349 bool fIsSimple; 350 351 bool doNext(SkDrawFilter::Type drawType); 352}; 353 354bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) { 355 fPaint = NULL; 356 SkASSERT(!fIsSimple); 357 SkASSERT(fLooper || fFilter || fDoClearImageFilter); 358 359 SkPaint* paint = fLazyPaint.set(fOrigPaint); 360 361 if (fDoClearImageFilter) { 362 paint->setImageFilter(NULL); 363 } 364 365 if (fLooper && !fLooper->next(fCanvas, paint)) { 366 fDone = true; 367 return false; 368 } 369 if (fFilter) { 370 fFilter->filter(paint, drawType); 371 if (NULL == fLooper) { 372 // no looper means we only draw once 373 fDone = true; 374 } 375 } 376 fPaint = paint; 377 378 // if we only came in here for the imagefilter, mark us as done 379 if (!fLooper && !fFilter) { 380 fDone = true; 381 } 382 383 // call this after any possible paint modifiers 384 if (fPaint->nothingToDraw()) { 385 fPaint = NULL; 386 return false; 387 } 388 return true; 389} 390 391/* Stack helper for managing a SkBounder. In the destructor, if we were 392 given a bounder, we call its commit() method, signifying that we are 393 done accumulating bounds for that draw. 394*/ 395class SkAutoBounderCommit { 396public: 397 SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {} 398 ~SkAutoBounderCommit() { 399 if (NULL != fBounder) { 400 fBounder->commit(); 401 } 402 } 403private: 404 SkBounder* fBounder; 405}; 406 407#include "SkColorPriv.h" 408 409class AutoValidator { 410public: 411 AutoValidator(SkDevice* device) : fDevice(device) {} 412 ~AutoValidator() { 413#ifdef SK_DEBUG 414 const SkBitmap& bm = fDevice->accessBitmap(false); 415 if (bm.config() == SkBitmap::kARGB_4444_Config) { 416 for (int y = 0; y < bm.height(); y++) { 417 const SkPMColor16* p = bm.getAddr16(0, y); 418 for (int x = 0; x < bm.width(); x++) { 419 SkPMColor16 c = p[x]; 420 SkPMColor16Assert(c); 421 } 422 } 423 } 424#endif 425 } 426private: 427 SkDevice* fDevice; 428}; 429 430////////// macros to place around the internal draw calls ////////////////// 431 432#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \ 433/* AutoValidator validator(fMCRec->fTopLayer->fDevice); */ \ 434 AutoDrawLooper looper(this, paint, true); \ 435 while (looper.next(type)) { \ 436 SkAutoBounderCommit ac(fBounder); \ 437 SkDrawIter iter(this); 438 439#define LOOPER_BEGIN(paint, type) \ 440/* AutoValidator validator(fMCRec->fTopLayer->fDevice); */ \ 441 AutoDrawLooper looper(this, paint); \ 442 while (looper.next(type)) { \ 443 SkAutoBounderCommit ac(fBounder); \ 444 SkDrawIter iter(this); 445 446#define LOOPER_END } 447 448//////////////////////////////////////////////////////////////////////////// 449 450SkDevice* SkCanvas::init(SkDevice* device) { 451 fBounder = NULL; 452 fLocalBoundsCompareType.setEmpty(); 453 fLocalBoundsCompareTypeDirty = true; 454 fLocalBoundsCompareTypeBW.setEmpty(); 455 fLocalBoundsCompareTypeDirtyBW = true; 456 fLastDeviceToGainFocus = NULL; 457 fDeviceCMDirty = false; 458 fSaveLayerCount = 0; 459 460 fMCRec = (MCRec*)fMCStack.push_back(); 461 new (fMCRec) MCRec(NULL, 0); 462 463 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL)); 464 fMCRec->fTopLayer = fMCRec->fLayer; 465 fMCRec->fNext = NULL; 466 467 fExternalMatrix.reset(); 468 fExternalInverse.reset(); 469 fUseExternalMatrix = false; 470 471 return this->setDevice(device); 472} 473 474SkCanvas::SkCanvas() 475: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 476 inc_canvas(); 477 478 this->init(NULL); 479} 480 481SkCanvas::SkCanvas(SkDevice* device) 482 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 483 inc_canvas(); 484 485 this->init(device); 486} 487 488SkCanvas::SkCanvas(const SkBitmap& bitmap) 489 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 490 inc_canvas(); 491 492 this->init(SkNEW_ARGS(SkDevice, (bitmap)))->unref(); 493} 494 495SkCanvas::~SkCanvas() { 496 // free up the contents of our deque 497 this->restoreToCount(1); // restore everything but the last 498 SkASSERT(0 == fSaveLayerCount); 499 500 this->internalRestore(); // restore the last, since we're going away 501 502 SkSafeUnref(fBounder); 503 504 dec_canvas(); 505} 506 507SkBounder* SkCanvas::setBounder(SkBounder* bounder) { 508 SkRefCnt_SafeAssign(fBounder, bounder); 509 return bounder; 510} 511 512SkDrawFilter* SkCanvas::getDrawFilter() const { 513 return fMCRec->fFilter; 514} 515 516SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) { 517 SkRefCnt_SafeAssign(fMCRec->fFilter, filter); 518 return filter; 519} 520 521/////////////////////////////////////////////////////////////////////////////// 522 523void SkCanvas::flush() { 524 SkDevice* device = this->getDevice(); 525 if (device) { 526 device->flush(); 527 } 528} 529 530SkISize SkCanvas::getDeviceSize() const { 531 SkDevice* d = this->getDevice(); 532 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0); 533} 534 535SkDevice* SkCanvas::getDevice() const { 536 // return root device 537 SkDeque::F2BIter iter(fMCStack); 538 MCRec* rec = (MCRec*)iter.next(); 539 SkASSERT(rec && rec->fLayer); 540 return rec->fLayer->fDevice; 541} 542 543SkDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const { 544 if (updateMatrixClip) { 545 const_cast<SkCanvas*>(this)->updateDeviceCMCache(); 546 } 547 return fMCRec->fTopLayer->fDevice; 548} 549 550SkDevice* SkCanvas::setDevice(SkDevice* device) { 551 // return root device 552 SkDeque::F2BIter iter(fMCStack); 553 MCRec* rec = (MCRec*)iter.next(); 554 SkASSERT(rec && rec->fLayer); 555 SkDevice* rootDevice = rec->fLayer->fDevice; 556 557 if (rootDevice == device) { 558 return device; 559 } 560 561 /* Notify the devices that they are going in/out of scope, so they can do 562 things like lock/unlock their pixels, etc. 563 */ 564 if (device) { 565 device->lockPixels(); 566 } 567 if (rootDevice) { 568 rootDevice->unlockPixels(); 569 } 570 571 SkRefCnt_SafeAssign(rec->fLayer->fDevice, device); 572 rootDevice = device; 573 574 fDeviceCMDirty = true; 575 576 /* Now we update our initial region to have the bounds of the new device, 577 and then intersect all of the clips in our stack with these bounds, 578 to ensure that we can't draw outside of the device's bounds (and trash 579 memory). 580 581 NOTE: this is only a partial-fix, since if the new device is larger than 582 the previous one, we don't know how to "enlarge" the clips in our stack, 583 so drawing may be artificially restricted. Without keeping a history of 584 all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly 585 reconstruct the correct clips, so this approximation will have to do. 586 The caller really needs to restore() back to the base if they want to 587 accurately take advantage of the new device bounds. 588 */ 589 590 SkIRect bounds; 591 if (device) { 592 bounds.set(0, 0, device->width(), device->height()); 593 } else { 594 bounds.setEmpty(); 595 } 596 // now jam our 1st clip to be bounds, and intersect the rest with that 597 rec->fRasterClip->setRect(bounds); 598 while ((rec = (MCRec*)iter.next()) != NULL) { 599 (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op); 600 } 601 602 return device; 603} 604 605SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) { 606 SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap))); 607 device->unref(); 608 return device; 609} 610 611bool SkCanvas::readPixels(SkBitmap* bitmap, 612 int x, int y, 613 Config8888 config8888) { 614 SkDevice* device = this->getDevice(); 615 if (!device) { 616 return false; 617 } 618 return device->readPixels(bitmap, x, y, config8888); 619} 620 621bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) { 622 SkDevice* device = this->getDevice(); 623 if (!device) { 624 return false; 625 } 626 627 SkIRect bounds; 628 bounds.set(0, 0, device->width(), device->height()); 629 if (!bounds.intersect(srcRect)) { 630 return false; 631 } 632 633 SkBitmap tmp; 634 tmp.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(), 635 bounds.height()); 636 if (this->readPixels(&tmp, bounds.fLeft, bounds.fTop)) { 637 bitmap->swap(tmp); 638 return true; 639 } else { 640 return false; 641 } 642} 643 644void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y, 645 Config8888 config8888) { 646 SkDevice* device = this->getDevice(); 647 if (device) { 648 device->writePixels(bitmap, x, y, config8888); 649 } 650} 651 652SkCanvas* SkCanvas::canvasForDrawIter() { 653 return this; 654} 655 656////////////////////////////////////////////////////////////////////////////// 657 658void SkCanvas::updateDeviceCMCache() { 659 if (fDeviceCMDirty) { 660 const SkMatrix& totalMatrix = this->getTotalMatrix(); 661 const SkRasterClip& totalClip = *fMCRec->fRasterClip; 662 DeviceCM* layer = fMCRec->fTopLayer; 663 664 if (NULL == layer->fNext) { // only one layer 665 layer->updateMC(totalMatrix, totalClip, fClipStack, NULL); 666 if (fUseExternalMatrix) { 667 layer->updateExternalMatrix(fExternalMatrix, 668 fExternalInverse); 669 } 670 } else { 671 SkRasterClip clip(totalClip); 672 do { 673 layer->updateMC(totalMatrix, clip, fClipStack, &clip); 674 if (fUseExternalMatrix) { 675 layer->updateExternalMatrix(fExternalMatrix, 676 fExternalInverse); 677 } 678 } while ((layer = layer->fNext) != NULL); 679 } 680 fDeviceCMDirty = false; 681 } 682} 683 684void SkCanvas::prepareForDeviceDraw(SkDevice* device, const SkMatrix& matrix, 685 const SkRegion& clip, 686 const SkClipStack& clipStack) { 687 SkASSERT(device); 688 if (fLastDeviceToGainFocus != device) { 689 device->gainFocus(this, matrix, clip, clipStack); 690 fLastDeviceToGainFocus = device; 691 } 692} 693 694/////////////////////////////////////////////////////////////////////////////// 695 696int SkCanvas::internalSave(SaveFlags flags) { 697 int saveCount = this->getSaveCount(); // record this before the actual save 698 699 MCRec* newTop = (MCRec*)fMCStack.push_back(); 700 new (newTop) MCRec(fMCRec, flags); // balanced in restore() 701 702 newTop->fNext = fMCRec; 703 fMCRec = newTop; 704 705 fClipStack.save(); 706 SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1); 707 708 return saveCount; 709} 710 711int SkCanvas::save(SaveFlags flags) { 712 // call shared impl 713 return this->internalSave(flags); 714} 715 716#define C32MASK (1 << SkBitmap::kARGB_8888_Config) 717#define C16MASK (1 << SkBitmap::kRGB_565_Config) 718#define C8MASK (1 << SkBitmap::kA8_Config) 719 720static SkBitmap::Config resolve_config(SkCanvas* canvas, 721 const SkIRect& bounds, 722 SkCanvas::SaveFlags flags, 723 bool* isOpaque) { 724 *isOpaque = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) == 0; 725 726#if 0 727 // loop through and union all the configs we may draw into 728 uint32_t configMask = 0; 729 for (int i = canvas->countLayerDevices() - 1; i >= 0; --i) 730 { 731 SkDevice* device = canvas->getLayerDevice(i); 732 if (device->intersects(bounds)) 733 configMask |= 1 << device->config(); 734 } 735 736 // if the caller wants alpha or fullcolor, we can't return 565 737 if (flags & (SkCanvas::kFullColorLayer_SaveFlag | 738 SkCanvas::kHasAlphaLayer_SaveFlag)) 739 configMask &= ~C16MASK; 740 741 switch (configMask) { 742 case C8MASK: // if we only have A8, return that 743 return SkBitmap::kA8_Config; 744 745 case C16MASK: // if we only have 565, return that 746 return SkBitmap::kRGB_565_Config; 747 748 default: 749 return SkBitmap::kARGB_8888_Config; // default answer 750 } 751#else 752 return SkBitmap::kARGB_8888_Config; // default answer 753#endif 754} 755 756static bool bounds_affects_clip(SkCanvas::SaveFlags flags) { 757 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0; 758} 759 760bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, 761 SkIRect* intersection) { 762 SkIRect clipBounds; 763 if (!this->getClipDeviceBounds(&clipBounds)) { 764 return false; 765 } 766 SkIRect ir; 767 if (NULL != bounds) { 768 SkRect r; 769 770 this->getTotalMatrix().mapRect(&r, *bounds); 771 r.roundOut(&ir); 772 // early exit if the layer's bounds are clipped out 773 if (!ir.intersect(clipBounds)) { 774 if (bounds_affects_clip(flags)) { 775 fMCRec->fRasterClip->setEmpty(); 776 } 777 return false; 778 } 779 } else { // no user bounds, so just use the clip 780 ir = clipBounds; 781 } 782 783 fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op); 784 785 // early exit if the clip is now empty 786 if (bounds_affects_clip(flags) && 787 !fMCRec->fRasterClip->op(ir, SkRegion::kIntersect_Op)) { 788 return false; 789 } 790 791 if (intersection) { 792 *intersection = ir; 793 } 794 return true; 795} 796 797int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, 798 SaveFlags flags) { 799 return this->internalSaveLayer(bounds, paint, flags, false); 800} 801 802int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, 803 SaveFlags flags, bool justForImageFilter) { 804 // do this before we create the layer. We don't call the public save() since 805 // that would invoke a possibly overridden virtual 806 int count = this->internalSave(flags); 807 808 fDeviceCMDirty = true; 809 810 SkIRect ir; 811 if (!this->clipRectBounds(bounds, flags, &ir)) { 812 return count; 813 } 814 815 // Kill the imagefilter if our device doesn't allow it 816 SkLazyPaint lazyP; 817 if (paint && paint->getImageFilter()) { 818 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) { 819 if (justForImageFilter) { 820 // early exit if the layer was just for the imageFilter 821 return count; 822 } 823 SkPaint* p = lazyP.set(*paint); 824 p->setImageFilter(NULL); 825 paint = p; 826 } 827 } 828 829 bool isOpaque; 830 SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque); 831 832 SkDevice* device; 833 if (paint && paint->getImageFilter()) { 834 device = this->createCompatibleDevice(config, ir.width(), ir.height(), 835 isOpaque); 836 } else { 837 device = this->createLayerDevice(config, ir.width(), ir.height(), 838 isOpaque); 839 } 840 if (NULL == device) { 841 SkDebugf("Unable to create device for layer."); 842 return count; 843 } 844 845 device->setOrigin(ir.fLeft, ir.fTop); 846 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint)); 847 device->unref(); 848 849 layer->fNext = fMCRec->fTopLayer; 850 fMCRec->fLayer = layer; 851 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer 852 853 fSaveLayerCount += 1; 854 return count; 855} 856 857int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha, 858 SaveFlags flags) { 859 if (0xFF == alpha) { 860 return this->saveLayer(bounds, NULL, flags); 861 } else { 862 SkPaint tmpPaint; 863 tmpPaint.setAlpha(alpha); 864 return this->saveLayer(bounds, &tmpPaint, flags); 865 } 866} 867 868void SkCanvas::restore() { 869 // check for underflow 870 if (fMCStack.count() > 1) { 871 this->internalRestore(); 872 } 873} 874 875void SkCanvas::internalRestore() { 876 SkASSERT(fMCStack.count() != 0); 877 878 fDeviceCMDirty = true; 879 fLocalBoundsCompareTypeDirty = true; 880 fLocalBoundsCompareTypeDirtyBW = true; 881 882 fClipStack.restore(); 883 // reserve our layer (if any) 884 DeviceCM* layer = fMCRec->fLayer; // may be null 885 // now detach it from fMCRec so we can pop(). Gets freed after its drawn 886 fMCRec->fLayer = NULL; 887 888 // now do the normal restore() 889 fMCRec->~MCRec(); // balanced in save() 890 fMCStack.pop_back(); 891 fMCRec = (MCRec*)fMCStack.back(); 892 893 /* Time to draw the layer's offscreen. We can't call the public drawSprite, 894 since if we're being recorded, we don't want to record this (the 895 recorder will have already recorded the restore). 896 */ 897 if (NULL != layer) { 898 if (layer->fNext) { 899 const SkIPoint& origin = layer->fDevice->getOrigin(); 900 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), 901 layer->fPaint); 902 // reset this, since internalDrawDevice will have set it to true 903 fDeviceCMDirty = true; 904 905 SkASSERT(fSaveLayerCount > 0); 906 fSaveLayerCount -= 1; 907 } 908 SkDELETE(layer); 909 } 910 911 SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1); 912} 913 914int SkCanvas::getSaveCount() const { 915 return fMCStack.count(); 916} 917 918void SkCanvas::restoreToCount(int count) { 919 // sanity check 920 if (count < 1) { 921 count = 1; 922 } 923 924 int n = this->getSaveCount() - count; 925 for (int i = 0; i < n; ++i) { 926 this->restore(); 927 } 928} 929 930bool SkCanvas::isDrawingToLayer() const { 931 return fSaveLayerCount > 0; 932} 933 934///////////////////////////////////////////////////////////////////////////// 935 936// can't draw it if its empty, or its too big for a fixed-point width or height 937static bool reject_bitmap(const SkBitmap& bitmap) { 938 return bitmap.width() <= 0 || bitmap.height() <= 0 939#ifndef SK_ALLOW_OVER_32K_BITMAPS 940 || bitmap.width() > 32767 || bitmap.height() > 32767 941#endif 942 ; 943} 944 945void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect, 946 const SkMatrix& matrix, const SkPaint* paint) { 947 if (reject_bitmap(bitmap)) { 948 return; 949 } 950 951 SkLazyPaint lazy; 952 if (NULL == paint) { 953 paint = lazy.init(); 954 } 955 this->commonDrawBitmap(bitmap, srcRect, matrix, *paint); 956} 957 958#include "SkImageFilter.h" 959 960class DeviceImageFilterProxy : public SkImageFilter::Proxy { 961public: 962 DeviceImageFilterProxy(SkDevice* device) : fDevice(device) {} 963 964 virtual SkDevice* createDevice(int w, int h) SK_OVERRIDE { 965 return fDevice->createCompatibleDevice(SkBitmap::kARGB_8888_Config, 966 w, h, false); 967 } 968 virtual bool canHandleImageFilter(SkImageFilter* filter) SK_OVERRIDE { 969 return fDevice->canHandleImageFilter(filter); 970 } 971 virtual bool filterImage(SkImageFilter* filter, const SkBitmap& src, 972 const SkMatrix& ctm, 973 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE { 974 return fDevice->filterImage(filter, src, ctm, result, offset); 975 } 976 977private: 978 SkDevice* fDevice; 979}; 980 981void SkCanvas::internalDrawDevice(SkDevice* srcDev, int x, int y, 982 const SkPaint* paint) { 983 SkPaint tmp; 984 if (NULL == paint) { 985 tmp.setDither(true); 986 paint = &tmp; 987 } 988 989 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 990 while (iter.next()) { 991 SkDevice* dstDev = iter.fDevice; 992 paint = &looper.paint(); 993 SkImageFilter* filter = paint->getImageFilter(); 994 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 995 if (filter && !dstDev->canHandleImageFilter(filter)) { 996 DeviceImageFilterProxy proxy(dstDev); 997 SkBitmap dst; 998 const SkBitmap& src = srcDev->accessBitmap(false); 999 if (filter->filterImage(&proxy, src, *iter.fMatrix, &dst, &pos)) { 1000 SkPaint tmpUnfiltered(*paint); 1001 tmpUnfiltered.setImageFilter(NULL); 1002 dstDev->drawSprite(iter, dst, pos.x(), pos.y(), tmpUnfiltered); 1003 } 1004 } else { 1005 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint); 1006 } 1007 } 1008 LOOPER_END 1009} 1010 1011void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, 1012 const SkPaint* paint) { 1013 SkDEBUGCODE(bitmap.validate();) 1014 1015 if (reject_bitmap(bitmap)) { 1016 return; 1017 } 1018 1019 SkPaint tmp; 1020 if (NULL == paint) { 1021 paint = &tmp; 1022 } 1023 1024 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 1025 1026 while (iter.next()) { 1027 paint = &looper.paint(); 1028 SkImageFilter* filter = paint->getImageFilter(); 1029 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 1030 if (filter && !iter.fDevice->canHandleImageFilter(filter)) { 1031 DeviceImageFilterProxy proxy(iter.fDevice); 1032 SkBitmap dst; 1033 if (filter->filterImage(&proxy, bitmap, *iter.fMatrix, 1034 &dst, &pos)) { 1035 SkPaint tmpUnfiltered(*paint); 1036 tmpUnfiltered.setImageFilter(NULL); 1037 iter.fDevice->drawSprite(iter, dst, pos.x(), pos.y(), 1038 tmpUnfiltered); 1039 } 1040 } else { 1041 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint); 1042 } 1043 } 1044 LOOPER_END 1045} 1046 1047///////////////////////////////////////////////////////////////////////////// 1048 1049bool SkCanvas::translate(SkScalar dx, SkScalar dy) { 1050 fDeviceCMDirty = true; 1051 fLocalBoundsCompareTypeDirty = true; 1052 fLocalBoundsCompareTypeDirtyBW = true; 1053 return fMCRec->fMatrix->preTranslate(dx, dy); 1054} 1055 1056bool SkCanvas::scale(SkScalar sx, SkScalar sy) { 1057 fDeviceCMDirty = true; 1058 fLocalBoundsCompareTypeDirty = true; 1059 fLocalBoundsCompareTypeDirtyBW = true; 1060 return fMCRec->fMatrix->preScale(sx, sy); 1061} 1062 1063bool SkCanvas::rotate(SkScalar degrees) { 1064 fDeviceCMDirty = true; 1065 fLocalBoundsCompareTypeDirty = true; 1066 fLocalBoundsCompareTypeDirtyBW = true; 1067 return fMCRec->fMatrix->preRotate(degrees); 1068} 1069 1070bool SkCanvas::skew(SkScalar sx, SkScalar sy) { 1071 fDeviceCMDirty = true; 1072 fLocalBoundsCompareTypeDirty = true; 1073 fLocalBoundsCompareTypeDirtyBW = true; 1074 return fMCRec->fMatrix->preSkew(sx, sy); 1075} 1076 1077bool SkCanvas::concat(const SkMatrix& matrix) { 1078 fDeviceCMDirty = true; 1079 fLocalBoundsCompareTypeDirty = true; 1080 fLocalBoundsCompareTypeDirtyBW = true; 1081 return fMCRec->fMatrix->preConcat(matrix); 1082} 1083 1084void SkCanvas::setMatrix(const SkMatrix& matrix) { 1085 fDeviceCMDirty = true; 1086 fLocalBoundsCompareTypeDirty = true; 1087 fLocalBoundsCompareTypeDirtyBW = true; 1088 *fMCRec->fMatrix = matrix; 1089} 1090 1091// this is not virtual, so it must call a virtual method so that subclasses 1092// will see its action 1093void SkCanvas::resetMatrix() { 1094 SkMatrix matrix; 1095 1096 matrix.reset(); 1097 this->setMatrix(matrix); 1098} 1099 1100////////////////////////////////////////////////////////////////////////////// 1101 1102bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 1103 AutoValidateClip avc(this); 1104 1105 fDeviceCMDirty = true; 1106 fLocalBoundsCompareTypeDirty = true; 1107 fLocalBoundsCompareTypeDirtyBW = true; 1108 1109 if (fMCRec->fMatrix->rectStaysRect()) { 1110 // for these simpler matrices, we can stay a rect ever after applying 1111 // the matrix. This means we don't have to a) make a path, and b) tell 1112 // the region code to scan-convert the path, only to discover that it 1113 // is really just a rect. 1114 SkRect r; 1115 1116 fMCRec->fMatrix->mapRect(&r, rect); 1117 fClipStack.clipDevRect(r, op, doAA); 1118 return fMCRec->fRasterClip->op(r, op, doAA); 1119 } else { 1120 // since we're rotate or some such thing, we convert the rect to a path 1121 // and clip against that, since it can handle any matrix. However, to 1122 // avoid recursion in the case where we are subclassed (e.g. Pictures) 1123 // we explicitly call "our" version of clipPath. 1124 SkPath path; 1125 1126 path.addRect(rect); 1127 return this->SkCanvas::clipPath(path, op, doAA); 1128 } 1129} 1130 1131static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip, 1132 const SkPath& devPath, SkRegion::Op op, bool doAA) { 1133 // base is used to limit the size (and therefore memory allocation) of the 1134 // region that results from scan converting devPath. 1135 SkRegion base; 1136 1137 if (SkRegion::kIntersect_Op == op) { 1138 // since we are intersect, we can do better (tighter) with currRgn's 1139 // bounds, than just using the device. However, if currRgn is complex, 1140 // our region blitter may hork, so we do that case in two steps. 1141 if (currClip->isRect()) { 1142 return currClip->setPath(devPath, *currClip, doAA); 1143 } else { 1144 base.setRect(currClip->getBounds()); 1145 SkRasterClip clip; 1146 clip.setPath(devPath, base, doAA); 1147 return currClip->op(clip, op); 1148 } 1149 } else { 1150 const SkDevice* device = canvas->getDevice(); 1151 if (!device) { 1152 return currClip->setEmpty(); 1153 } 1154 1155 base.setRect(0, 0, device->width(), device->height()); 1156 1157 if (SkRegion::kReplace_Op == op) { 1158 return currClip->setPath(devPath, base, doAA); 1159 } else { 1160 SkRasterClip clip; 1161 clip.setPath(devPath, base, doAA); 1162 return currClip->op(clip, op); 1163 } 1164 } 1165} 1166 1167bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 1168 AutoValidateClip avc(this); 1169 1170 fDeviceCMDirty = true; 1171 fLocalBoundsCompareTypeDirty = true; 1172 fLocalBoundsCompareTypeDirtyBW = true; 1173 1174 SkPath devPath; 1175 path.transform(*fMCRec->fMatrix, &devPath); 1176 1177 // Check if the transfomation, or the original path itself 1178 // made us empty. Note this can also happen if we contained NaN 1179 // values. computing the bounds detects this, and will set our 1180 // bounds to empty if that is the case. (see SkRect::set(pts, count)) 1181 if (devPath.getBounds().isEmpty()) { 1182 // resetting the path will remove any NaN or other wanky values 1183 // that might upset our scan converter. 1184 devPath.reset(); 1185 } 1186 1187 // if we called path.swap() we could avoid a deep copy of this path 1188 fClipStack.clipDevPath(devPath, op, doAA); 1189 1190 return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA); 1191} 1192 1193bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1194 AutoValidateClip avc(this); 1195 1196 fDeviceCMDirty = true; 1197 fLocalBoundsCompareTypeDirty = true; 1198 fLocalBoundsCompareTypeDirtyBW = true; 1199 1200 // todo: signal fClipStack that we have a region, and therefore (I guess) 1201 // we have to ignore it, and use the region directly? 1202 fClipStack.clipDevRect(rgn.getBounds(), op); 1203 1204 return fMCRec->fRasterClip->op(rgn, op); 1205} 1206 1207#ifdef SK_DEBUG 1208void SkCanvas::validateClip() const { 1209 // construct clipRgn from the clipstack 1210 const SkDevice* device = this->getDevice(); 1211 if (!device) { 1212 SkASSERT(this->getTotalClip().isEmpty()); 1213 return; 1214 } 1215 1216 SkIRect ir; 1217 ir.set(0, 0, device->width(), device->height()); 1218 SkRasterClip tmpClip(ir); 1219 1220 SkClipStack::B2FIter iter(fClipStack); 1221 const SkClipStack::B2FIter::Clip* clip; 1222 while ((clip = iter.next()) != NULL) { 1223 if (clip->fPath) { 1224 clipPathHelper(this, &tmpClip, *clip->fPath, clip->fOp, clip->fDoAA); 1225 } else if (clip->fRect) { 1226 clip->fRect->round(&ir); 1227 tmpClip.op(ir, clip->fOp); 1228 } else { 1229 tmpClip.setEmpty(); 1230 } 1231 } 1232 1233#if 0 // enable this locally for testing 1234 // now compare against the current rgn 1235 const SkRegion& rgn = this->getTotalClip(); 1236 SkASSERT(rgn == tmpClip); 1237#endif 1238} 1239#endif 1240 1241void SkCanvas::replayClips(ClipVisitor* visitor) const { 1242 SkClipStack::B2FIter iter(fClipStack); 1243 const SkClipStack::B2FIter::Clip* clip; 1244 1245 SkRect empty = { 0, 0, 0, 0 }; 1246 while ((clip = iter.next()) != NULL) { 1247 if (clip->fPath) { 1248 visitor->clipPath(*clip->fPath, clip->fOp, clip->fDoAA); 1249 } else if (clip->fRect) { 1250 visitor->clipRect(*clip->fRect, clip->fOp, clip->fDoAA); 1251 } else { 1252 visitor->clipRect(empty, SkRegion::kIntersect_Op, false); 1253 } 1254 } 1255} 1256 1257/////////////////////////////////////////////////////////////////////////////// 1258 1259void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const { 1260 SkRect r; 1261 SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType : 1262 fLocalBoundsCompareTypeBW; 1263 1264 if (!this->getClipBounds(&r, et)) { 1265 rCompare.setEmpty(); 1266 } else { 1267 rCompare.set(SkScalarToCompareType(r.fLeft), 1268 SkScalarToCompareType(r.fTop), 1269 SkScalarToCompareType(r.fRight), 1270 SkScalarToCompareType(r.fBottom)); 1271 } 1272} 1273 1274/* current impl ignores edgetype, and relies on 1275 getLocalClipBoundsCompareType(), which always returns a value assuming 1276 antialiasing (worst case) 1277 */ 1278bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const { 1279 1280 if (!rect.isFinite()) 1281 return true; 1282 1283 if (fMCRec->fRasterClip->isEmpty()) { 1284 return true; 1285 } 1286 1287 if (fMCRec->fMatrix->hasPerspective()) { 1288 SkRect dst; 1289 fMCRec->fMatrix->mapRect(&dst, rect); 1290 SkIRect idst; 1291 dst.roundOut(&idst); 1292 return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds()); 1293 } else { 1294 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et); 1295 1296 // for speed, do the most likely reject compares first 1297 SkScalarCompareType userT = SkScalarToCompareType(rect.fTop); 1298 SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom); 1299 if (userT >= clipR.fBottom || userB <= clipR.fTop) { 1300 return true; 1301 } 1302 SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft); 1303 SkScalarCompareType userR = SkScalarToCompareType(rect.fRight); 1304 if (userL >= clipR.fRight || userR <= clipR.fLeft) { 1305 return true; 1306 } 1307 return false; 1308 } 1309} 1310 1311bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const { 1312 return path.isEmpty() || this->quickReject(path.getBounds(), et); 1313} 1314 1315static inline int pinIntForScalar(int x) { 1316#ifdef SK_SCALAR_IS_FIXED 1317 if (x < SK_MinS16) { 1318 x = SK_MinS16; 1319 } else if (x > SK_MaxS16) { 1320 x = SK_MaxS16; 1321 } 1322#endif 1323 return x; 1324} 1325 1326bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const { 1327 SkIRect ibounds; 1328 if (!getClipDeviceBounds(&ibounds)) { 1329 return false; 1330 } 1331 1332 SkMatrix inverse; 1333 // if we can't invert the CTM, we can't return local clip bounds 1334 if (!fMCRec->fMatrix->invert(&inverse)) { 1335 if (bounds) { 1336 bounds->setEmpty(); 1337 } 1338 return false; 1339 } 1340 1341 if (NULL != bounds) { 1342 SkRect r; 1343 // adjust it outwards if we are antialiasing 1344 int inset = (kAA_EdgeType == et); 1345 1346 // SkRect::iset() will correctly assert if we pass a value out of range 1347 // (when SkScalar==fixed), so we pin to legal values. This does not 1348 // really returnt the correct answer, but its the best we can do given 1349 // that we've promised to return SkRect (even though we support devices 1350 // that can be larger than 32K in width or height). 1351 r.iset(pinIntForScalar(ibounds.fLeft - inset), 1352 pinIntForScalar(ibounds.fTop - inset), 1353 pinIntForScalar(ibounds.fRight + inset), 1354 pinIntForScalar(ibounds.fBottom + inset)); 1355 inverse.mapRect(bounds, r); 1356 } 1357 return true; 1358} 1359 1360bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const { 1361 const SkRasterClip& clip = *fMCRec->fRasterClip; 1362 if (clip.isEmpty()) { 1363 if (bounds) { 1364 bounds->setEmpty(); 1365 } 1366 return false; 1367 } 1368 1369 if (NULL != bounds) { 1370 *bounds = clip.getBounds(); 1371 } 1372 return true; 1373} 1374 1375const SkMatrix& SkCanvas::getTotalMatrix() const { 1376 return *fMCRec->fMatrix; 1377} 1378 1379SkCanvas::ClipType SkCanvas::getClipType() const { 1380 if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType; 1381 if (fMCRec->fRasterClip->isRect()) return kRect_ClipType; 1382 return kComplex_ClipType; 1383} 1384 1385const SkRegion& SkCanvas::getTotalClip() const { 1386 return fMCRec->fRasterClip->forceGetBW(); 1387} 1388 1389void SkCanvas::setExternalMatrix(const SkMatrix* matrix) { 1390 if (NULL == matrix || matrix->isIdentity()) { 1391 if (fUseExternalMatrix) { 1392 fDeviceCMDirty = true; 1393 } 1394 fUseExternalMatrix = false; 1395 } else { 1396 if (matrix->invert(&fExternalInverse)) { 1397 fExternalMatrix = *matrix; 1398 fUseExternalMatrix = true; 1399 fDeviceCMDirty = true; // |= (fExternalMatrix != *matrix) 1400 } 1401 } 1402} 1403 1404SkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config, 1405 int width, int height, 1406 bool isOpaque) { 1407 SkDevice* device = this->getTopDevice(); 1408 if (device) { 1409 return device->createCompatibleDeviceForSaveLayer(config, width, height, 1410 isOpaque); 1411 } else { 1412 return NULL; 1413 } 1414} 1415 1416SkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config, 1417 int width, int height, 1418 bool isOpaque) { 1419 SkDevice* device = this->getDevice(); 1420 if (device) { 1421 return device->createCompatibleDevice(config, width, height, isOpaque); 1422 } else { 1423 return NULL; 1424 } 1425} 1426 1427 1428////////////////////////////////////////////////////////////////////////////// 1429// These are the virtual drawing methods 1430////////////////////////////////////////////////////////////////////////////// 1431 1432void SkCanvas::clear(SkColor color) { 1433 SkDrawIter iter(this); 1434 1435 while (iter.next()) { 1436 iter.fDevice->clear(color); 1437 } 1438} 1439 1440void SkCanvas::drawPaint(const SkPaint& paint) { 1441 this->internalDrawPaint(paint); 1442} 1443 1444void SkCanvas::internalDrawPaint(const SkPaint& paint) { 1445 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type) 1446 1447 while (iter.next()) { 1448 iter.fDevice->drawPaint(iter, looper.paint()); 1449 } 1450 1451 LOOPER_END 1452} 1453 1454void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1455 const SkPaint& paint) { 1456 if ((long)count <= 0) { 1457 return; 1458 } 1459 1460 if (paint.canComputeFastBounds()) { 1461 SkRect r; 1462 // special-case 2 points (common for drawing a single line) 1463 if (2 == count) { 1464 r.set(pts[0], pts[1]); 1465 } else { 1466 r.set(pts, count); 1467 } 1468 SkRect storage; 1469 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage), 1470 paint2EdgeType(&paint))) { 1471 return; 1472 } 1473 } 1474 1475 SkASSERT(pts != NULL); 1476 1477 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type) 1478 1479 while (iter.next()) { 1480 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); 1481 } 1482 1483 LOOPER_END 1484} 1485 1486void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1487 if (paint.canComputeFastBounds()) { 1488 SkRect storage; 1489 if (this->quickReject(paint.computeFastBounds(r, &storage), 1490 paint2EdgeType(&paint))) { 1491 return; 1492 } 1493 } 1494 1495 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type) 1496 1497 while (iter.next()) { 1498 iter.fDevice->drawRect(iter, r, looper.paint()); 1499 } 1500 1501 LOOPER_END 1502} 1503 1504void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 1505 if (!path.isInverseFillType() && paint.canComputeFastBounds()) { 1506 SkRect storage; 1507 const SkRect& bounds = path.getBounds(); 1508 if (this->quickReject(paint.computeFastBounds(bounds, &storage), 1509 paint2EdgeType(&paint))) { 1510 return; 1511 } 1512 } 1513 if (path.isEmpty()) { 1514 if (path.isInverseFillType()) { 1515 this->internalDrawPaint(paint); 1516 } 1517 return; 1518 } 1519 1520 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 1521 1522 while (iter.next()) { 1523 iter.fDevice->drawPath(iter, path, looper.paint()); 1524 } 1525 1526 LOOPER_END 1527} 1528 1529void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, 1530 const SkPaint* paint) { 1531 SkDEBUGCODE(bitmap.validate();) 1532 1533 if (NULL == paint || paint->canComputeFastBounds()) { 1534 SkRect bounds = { 1535 x, y, 1536 x + SkIntToScalar(bitmap.width()), 1537 y + SkIntToScalar(bitmap.height()) 1538 }; 1539 if (paint) { 1540 (void)paint->computeFastBounds(bounds, &bounds); 1541 } 1542 if (this->quickReject(bounds, paint2EdgeType(paint))) { 1543 return; 1544 } 1545 } 1546 1547 SkMatrix matrix; 1548 matrix.setTranslate(x, y); 1549 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1550} 1551 1552// this one is non-virtual, so it can be called safely by other canvas apis 1553void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, 1554 const SkRect& dst, const SkPaint* paint) { 1555 if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) { 1556 return; 1557 } 1558 1559 // do this now, to avoid the cost of calling extract for RLE bitmaps 1560 if (NULL == paint || paint->canComputeFastBounds()) { 1561 SkRect storage; 1562 const SkRect* bounds = &dst; 1563 if (paint) { 1564 bounds = &paint->computeFastBounds(dst, &storage); 1565 } 1566 if (this->quickReject(*bounds, paint2EdgeType(paint))) { 1567 return; 1568 } 1569 } 1570 1571 const SkBitmap* bitmapPtr = &bitmap; 1572 1573 SkMatrix matrix; 1574 SkRect tmpSrc; 1575 if (src) { 1576 tmpSrc.set(*src); 1577 // if the extract process clipped off the top or left of the 1578 // original, we adjust for that here to get the position right. 1579 if (tmpSrc.fLeft > 0) { 1580 tmpSrc.fRight -= tmpSrc.fLeft; 1581 tmpSrc.fLeft = 0; 1582 } 1583 if (tmpSrc.fTop > 0) { 1584 tmpSrc.fBottom -= tmpSrc.fTop; 1585 tmpSrc.fTop = 0; 1586 } 1587 } else { 1588 tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()), 1589 SkIntToScalar(bitmap.height())); 1590 } 1591 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 1592 1593 // ensure that src is "valid" before we pass it to our internal routines 1594 // and to SkDevice. i.e. sure it is contained inside the original bitmap. 1595 SkIRect tmpISrc; 1596 if (src) { 1597 tmpISrc.set(0, 0, bitmap.width(), bitmap.height()); 1598 if (!tmpISrc.intersect(*src)) { 1599 return; 1600 } 1601 src = &tmpISrc; 1602 } 1603 this->internalDrawBitmap(*bitmapPtr, src, matrix, paint); 1604} 1605 1606void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, 1607 const SkRect& dst, const SkPaint* paint) { 1608 SkDEBUGCODE(bitmap.validate();) 1609 this->internalDrawBitmapRect(bitmap, src, dst, paint); 1610} 1611 1612void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 1613 const SkPaint* paint) { 1614 SkDEBUGCODE(bitmap.validate();) 1615 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1616} 1617 1618void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect, 1619 const SkMatrix& matrix, const SkPaint& paint) { 1620 SkDEBUGCODE(bitmap.validate();) 1621 1622 LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type) 1623 1624 while (iter.next()) { 1625 iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint()); 1626 } 1627 1628 LOOPER_END 1629} 1630 1631void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap, 1632 const SkIRect& center, const SkRect& dst, 1633 const SkPaint* paint) { 1634 if (NULL == paint || paint->canComputeFastBounds()) { 1635 SkRect storage; 1636 const SkRect* bounds = &dst; 1637 if (paint) { 1638 bounds = &paint->computeFastBounds(dst, &storage); 1639 } 1640 if (this->quickReject(*bounds, paint2EdgeType(paint))) { 1641 return; 1642 } 1643 } 1644 1645 const int32_t w = bitmap.width(); 1646 const int32_t h = bitmap.height(); 1647 1648 SkIRect c = center; 1649 // pin center to the bounds of the bitmap 1650 c.fLeft = SkMax32(0, center.fLeft); 1651 c.fTop = SkMax32(0, center.fTop); 1652 c.fRight = SkPin32(center.fRight, c.fLeft, w); 1653 c.fBottom = SkPin32(center.fBottom, c.fTop, h); 1654 1655 const int32_t srcX[4] = { 0, c.fLeft, c.fRight, w }; 1656 const int32_t srcY[4] = { 0, c.fTop, c.fBottom, h }; 1657 SkScalar dstX[4] = { 1658 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft), 1659 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight 1660 }; 1661 SkScalar dstY[4] = { 1662 dst.fTop, dst.fTop + SkIntToScalar(c.fTop), 1663 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom 1664 }; 1665 1666 if (dstX[1] > dstX[2]) { 1667 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width()); 1668 dstX[2] = dstX[1]; 1669 } 1670 1671 if (dstY[1] > dstY[2]) { 1672 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height()); 1673 dstY[2] = dstY[1]; 1674 } 1675 1676 SkIRect s; 1677 SkRect d; 1678 for (int y = 0; y < 3; y++) { 1679 s.fTop = srcY[y]; 1680 s.fBottom = srcY[y+1]; 1681 d.fTop = dstY[y]; 1682 d.fBottom = dstY[y+1]; 1683 for (int x = 0; x < 3; x++) { 1684 s.fLeft = srcX[x]; 1685 s.fRight = srcX[x+1]; 1686 d.fLeft = dstX[x]; 1687 d.fRight = dstX[x+1]; 1688 this->internalDrawBitmapRect(bitmap, &s, d, paint); 1689 } 1690 } 1691} 1692 1693void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 1694 const SkRect& dst, const SkPaint* paint) { 1695 SkDEBUGCODE(bitmap.validate();) 1696 1697 // Need a device entry-point, so gpu can use a mesh 1698 this->internalDrawBitmapNine(bitmap, center, dst, paint); 1699} 1700 1701class SkDeviceFilteredPaint { 1702public: 1703 SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) { 1704 SkDevice::TextFlags flags; 1705 if (device->filterTextFlags(paint, &flags)) { 1706 SkPaint* newPaint = fLazy.set(paint); 1707 newPaint->setFlags(flags.fFlags); 1708 newPaint->setHinting(flags.fHinting); 1709 fPaint = newPaint; 1710 } else { 1711 fPaint = &paint; 1712 } 1713 } 1714 1715 const SkPaint& paint() const { return *fPaint; } 1716 1717private: 1718 const SkPaint* fPaint; 1719 SkLazyPaint fLazy; 1720}; 1721 1722void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, 1723 const SkRect& r, SkScalar textSize) { 1724 if (paint.getStyle() == SkPaint::kFill_Style) { 1725 draw.fDevice->drawRect(draw, r, paint); 1726 } else { 1727 SkPaint p(paint); 1728 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); 1729 draw.fDevice->drawRect(draw, r, p); 1730 } 1731} 1732 1733void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, 1734 const char text[], size_t byteLength, 1735 SkScalar x, SkScalar y) { 1736 SkASSERT(byteLength == 0 || text != NULL); 1737 1738 // nothing to draw 1739 if (text == NULL || byteLength == 0 || 1740 draw.fClip->isEmpty() || 1741 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 1742 return; 1743 } 1744 1745 SkScalar width = 0; 1746 SkPoint start; 1747 1748 start.set(0, 0); // to avoid warning 1749 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | 1750 SkPaint::kStrikeThruText_Flag)) { 1751 width = paint.measureText(text, byteLength); 1752 1753 SkScalar offsetX = 0; 1754 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 1755 offsetX = SkScalarHalf(width); 1756 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { 1757 offsetX = width; 1758 } 1759 start.set(x - offsetX, y); 1760 } 1761 1762 if (0 == width) { 1763 return; 1764 } 1765 1766 uint32_t flags = paint.getFlags(); 1767 1768 if (flags & (SkPaint::kUnderlineText_Flag | 1769 SkPaint::kStrikeThruText_Flag)) { 1770 SkScalar textSize = paint.getTextSize(); 1771 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 1772 SkRect r; 1773 1774 r.fLeft = start.fX; 1775 r.fRight = start.fX + width; 1776 1777 if (flags & SkPaint::kUnderlineText_Flag) { 1778 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, 1779 start.fY); 1780 r.fTop = offset; 1781 r.fBottom = offset + height; 1782 DrawRect(draw, paint, r, textSize); 1783 } 1784 if (flags & SkPaint::kStrikeThruText_Flag) { 1785 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, 1786 start.fY); 1787 r.fTop = offset; 1788 r.fBottom = offset + height; 1789 DrawRect(draw, paint, r, textSize); 1790 } 1791 } 1792} 1793 1794void SkCanvas::drawText(const void* text, size_t byteLength, 1795 SkScalar x, SkScalar y, const SkPaint& paint) { 1796 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1797 1798 while (iter.next()) { 1799 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1800 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 1801 DrawTextDecorations(iter, dfp.paint(), 1802 static_cast<const char*>(text), byteLength, x, y); 1803 } 1804 1805 LOOPER_END 1806} 1807 1808void SkCanvas::drawPosText(const void* text, size_t byteLength, 1809 const SkPoint pos[], const SkPaint& paint) { 1810 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1811 1812 while (iter.next()) { 1813 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1814 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 1815 dfp.paint()); 1816 } 1817 1818 LOOPER_END 1819} 1820 1821void SkCanvas::drawPosTextH(const void* text, size_t byteLength, 1822 const SkScalar xpos[], SkScalar constY, 1823 const SkPaint& paint) { 1824 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1825 1826 while (iter.next()) { 1827 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1828 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 1829 dfp.paint()); 1830 } 1831 1832 LOOPER_END 1833} 1834 1835void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, 1836 const SkPath& path, const SkMatrix* matrix, 1837 const SkPaint& paint) { 1838 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1839 1840 while (iter.next()) { 1841 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 1842 matrix, looper.paint()); 1843 } 1844 1845 LOOPER_END 1846} 1847 1848#ifdef SK_BUILD_FOR_ANDROID 1849void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength, 1850 const SkPoint pos[], const SkPaint& paint, 1851 const SkPath& path, const SkMatrix* matrix) { 1852 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1853 1854 while (iter.next()) { 1855 iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos, 1856 looper.paint(), path, matrix); 1857 } 1858 1859 LOOPER_END 1860} 1861#endif 1862 1863void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 1864 const SkPoint verts[], const SkPoint texs[], 1865 const SkColor colors[], SkXfermode* xmode, 1866 const uint16_t indices[], int indexCount, 1867 const SkPaint& paint) { 1868 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 1869 1870 while (iter.next()) { 1871 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 1872 colors, xmode, indices, indexCount, 1873 looper.paint()); 1874 } 1875 1876 LOOPER_END 1877} 1878 1879void SkCanvas::drawData(const void* data, size_t length) { 1880 // do nothing. Subclasses may do something with the data 1881} 1882 1883////////////////////////////////////////////////////////////////////////////// 1884// These methods are NOT virtual, and therefore must call back into virtual 1885// methods, rather than actually drawing themselves. 1886////////////////////////////////////////////////////////////////////////////// 1887 1888void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 1889 SkXfermode::Mode mode) { 1890 SkPaint paint; 1891 1892 paint.setARGB(a, r, g, b); 1893 if (SkXfermode::kSrcOver_Mode != mode) { 1894 paint.setXfermodeMode(mode); 1895 } 1896 this->drawPaint(paint); 1897} 1898 1899void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 1900 SkPaint paint; 1901 1902 paint.setColor(c); 1903 if (SkXfermode::kSrcOver_Mode != mode) { 1904 paint.setXfermodeMode(mode); 1905 } 1906 this->drawPaint(paint); 1907} 1908 1909void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 1910 SkPoint pt; 1911 1912 pt.set(x, y); 1913 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1914} 1915 1916void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 1917 SkPoint pt; 1918 SkPaint paint; 1919 1920 pt.set(x, y); 1921 paint.setColor(color); 1922 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1923} 1924 1925void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 1926 const SkPaint& paint) { 1927 SkPoint pts[2]; 1928 1929 pts[0].set(x0, y0); 1930 pts[1].set(x1, y1); 1931 this->drawPoints(kLines_PointMode, 2, pts, paint); 1932} 1933 1934void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 1935 SkScalar right, SkScalar bottom, 1936 const SkPaint& paint) { 1937 SkRect r; 1938 1939 r.set(left, top, right, bottom); 1940 this->drawRect(r, paint); 1941} 1942 1943void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 1944 const SkPaint& paint) { 1945 if (radius < 0) { 1946 radius = 0; 1947 } 1948 1949 SkRect r; 1950 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 1951 1952 if (paint.canComputeFastBounds()) { 1953 SkRect storage; 1954 if (this->quickReject(paint.computeFastBounds(r, &storage), 1955 paint2EdgeType(&paint))) { 1956 return; 1957 } 1958 } 1959 1960 SkPath path; 1961 path.addOval(r); 1962 this->drawPath(path, paint); 1963} 1964 1965void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 1966 const SkPaint& paint) { 1967 if (rx > 0 && ry > 0) { 1968 if (paint.canComputeFastBounds()) { 1969 SkRect storage; 1970 if (this->quickReject(paint.computeFastBounds(r, &storage), 1971 paint2EdgeType(&paint))) { 1972 return; 1973 } 1974 } 1975 1976 SkPath path; 1977 path.addRoundRect(r, rx, ry, SkPath::kCW_Direction); 1978 this->drawPath(path, paint); 1979 } else { 1980 this->drawRect(r, paint); 1981 } 1982} 1983 1984void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1985 if (paint.canComputeFastBounds()) { 1986 SkRect storage; 1987 if (this->quickReject(paint.computeFastBounds(oval, &storage), 1988 paint2EdgeType(&paint))) { 1989 return; 1990 } 1991 } 1992 1993 SkPath path; 1994 path.addOval(oval); 1995 this->drawPath(path, paint); 1996} 1997 1998void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 1999 SkScalar sweepAngle, bool useCenter, 2000 const SkPaint& paint) { 2001 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 2002 this->drawOval(oval, paint); 2003 } else { 2004 SkPath path; 2005 if (useCenter) { 2006 path.moveTo(oval.centerX(), oval.centerY()); 2007 } 2008 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 2009 if (useCenter) { 2010 path.close(); 2011 } 2012 this->drawPath(path, paint); 2013 } 2014} 2015 2016void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 2017 const SkPath& path, SkScalar hOffset, 2018 SkScalar vOffset, const SkPaint& paint) { 2019 SkMatrix matrix; 2020 2021 matrix.setTranslate(hOffset, vOffset); 2022 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 2023} 2024 2025/////////////////////////////////////////////////////////////////////////////// 2026 2027void SkCanvas::drawPicture(SkPicture& picture) { 2028 int saveCount = save(); 2029 picture.draw(this); 2030 restoreToCount(saveCount); 2031} 2032 2033/////////////////////////////////////////////////////////////////////////////// 2034/////////////////////////////////////////////////////////////////////////////// 2035 2036SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 2037 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); 2038 2039 SkASSERT(canvas); 2040 2041 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 2042 fDone = !fImpl->next(); 2043} 2044 2045SkCanvas::LayerIter::~LayerIter() { 2046 fImpl->~SkDrawIter(); 2047} 2048 2049void SkCanvas::LayerIter::next() { 2050 fDone = !fImpl->next(); 2051} 2052 2053SkDevice* SkCanvas::LayerIter::device() const { 2054 return fImpl->getDevice(); 2055} 2056 2057const SkMatrix& SkCanvas::LayerIter::matrix() const { 2058 return fImpl->getMatrix(); 2059} 2060 2061const SkPaint& SkCanvas::LayerIter::paint() const { 2062 const SkPaint* paint = fImpl->getPaint(); 2063 if (NULL == paint) { 2064 paint = &fDefaultPaint; 2065 } 2066 return *paint; 2067} 2068 2069const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 2070int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 2071int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 2072