SkCanvas.cpp revision 20a550c6ea947f0ab239da1d4ecba209d76a98fd
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, SkCanvas* canvas) 82 : fNext(NULL) { 83 if (NULL != device) { 84 device->ref(); 85 device->onAttachToCanvas(canvas); 86 } 87 fDevice = device; 88 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL; 89 } 90 91 ~DeviceCM() { 92 if (NULL != fDevice) { 93 fDevice->onDetachFromCanvas(); 94 fDevice->unref(); 95 } 96 SkDELETE(fPaint); 97 } 98 99 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip, 100 const SkClipStack& clipStack, SkRasterClip* updateClip) { 101 int x = fDevice->getOrigin().x(); 102 int y = fDevice->getOrigin().y(); 103 int width = fDevice->width(); 104 int height = fDevice->height(); 105 106 if ((x | y) == 0) { 107 fMatrix = &totalMatrix; 108 fClip = totalClip; 109 } else { 110 fMatrixStorage = totalMatrix; 111 fMatrixStorage.postTranslate(SkIntToScalar(-x), 112 SkIntToScalar(-y)); 113 fMatrix = &fMatrixStorage; 114 115 totalClip.translate(-x, -y, &fClip); 116 } 117 118 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op); 119 120 // intersect clip, but don't translate it (yet) 121 122 if (updateClip) { 123 updateClip->op(SkIRect::MakeXYWH(x, y, width, height), 124 SkRegion::kDifference_Op); 125 } 126 127 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack); 128 129#ifdef SK_DEBUG 130 if (!fClip.isEmpty()) { 131 SkIRect deviceR; 132 deviceR.set(0, 0, width, height); 133 SkASSERT(deviceR.contains(fClip.getBounds())); 134 } 135#endif 136 // 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); 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, 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 MCRec* rec = (MCRec*) fMCStack.front(); 538 SkASSERT(rec && rec->fLayer); 539 return rec->fLayer->fDevice; 540} 541 542SkDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const { 543 if (updateMatrixClip) { 544 const_cast<SkCanvas*>(this)->updateDeviceCMCache(); 545 } 546 return fMCRec->fTopLayer->fDevice; 547} 548 549SkDevice* SkCanvas::setDevice(SkDevice* device) { 550 // return root device 551 SkDeque::F2BIter iter(fMCStack); 552 MCRec* rec = (MCRec*)iter.next(); 553 SkASSERT(rec && rec->fLayer); 554 SkDevice* rootDevice = rec->fLayer->fDevice; 555 556 if (rootDevice == device) { 557 return device; 558 } 559 560 if (device) { 561 device->onAttachToCanvas(this); 562 } 563 if (rootDevice) { 564 rootDevice->onDetachFromCanvas(); 565 } 566 567 SkRefCnt_SafeAssign(rec->fLayer->fDevice, device); 568 rootDevice = device; 569 570 fDeviceCMDirty = true; 571 572 /* Now we update our initial region to have the bounds of the new device, 573 and then intersect all of the clips in our stack with these bounds, 574 to ensure that we can't draw outside of the device's bounds (and trash 575 memory). 576 577 NOTE: this is only a partial-fix, since if the new device is larger than 578 the previous one, we don't know how to "enlarge" the clips in our stack, 579 so drawing may be artificially restricted. Without keeping a history of 580 all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly 581 reconstruct the correct clips, so this approximation will have to do. 582 The caller really needs to restore() back to the base if they want to 583 accurately take advantage of the new device bounds. 584 */ 585 586 SkIRect bounds; 587 if (device) { 588 bounds.set(0, 0, device->width(), device->height()); 589 } else { 590 bounds.setEmpty(); 591 } 592 // now jam our 1st clip to be bounds, and intersect the rest with that 593 rec->fRasterClip->setRect(bounds); 594 while ((rec = (MCRec*)iter.next()) != NULL) { 595 (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op); 596 } 597 598 return device; 599} 600 601SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) { 602 SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap))); 603 device->unref(); 604 return device; 605} 606 607bool SkCanvas::readPixels(SkBitmap* bitmap, 608 int x, int y, 609 Config8888 config8888) { 610 SkDevice* device = this->getDevice(); 611 if (!device) { 612 return false; 613 } 614 return device->readPixels(bitmap, x, y, config8888); 615} 616 617bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) { 618 SkDevice* device = this->getDevice(); 619 if (!device) { 620 return false; 621 } 622 623 SkIRect bounds; 624 bounds.set(0, 0, device->width(), device->height()); 625 if (!bounds.intersect(srcRect)) { 626 return false; 627 } 628 629 SkBitmap tmp; 630 tmp.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(), 631 bounds.height()); 632 if (this->readPixels(&tmp, bounds.fLeft, bounds.fTop)) { 633 bitmap->swap(tmp); 634 return true; 635 } else { 636 return false; 637 } 638} 639 640void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y, 641 Config8888 config8888) { 642 SkDevice* device = this->getDevice(); 643 if (device) { 644 device->writePixels(bitmap, x, y, config8888); 645 } 646} 647 648SkCanvas* SkCanvas::canvasForDrawIter() { 649 return this; 650} 651 652////////////////////////////////////////////////////////////////////////////// 653 654void SkCanvas::updateDeviceCMCache() { 655 if (fDeviceCMDirty) { 656 const SkMatrix& totalMatrix = this->getTotalMatrix(); 657 const SkRasterClip& totalClip = *fMCRec->fRasterClip; 658 DeviceCM* layer = fMCRec->fTopLayer; 659 660 if (NULL == layer->fNext) { // only one layer 661 layer->updateMC(totalMatrix, totalClip, fClipStack, NULL); 662 if (fUseExternalMatrix) { 663 layer->updateExternalMatrix(fExternalMatrix, 664 fExternalInverse); 665 } 666 } else { 667 SkRasterClip clip(totalClip); 668 do { 669 layer->updateMC(totalMatrix, clip, fClipStack, &clip); 670 if (fUseExternalMatrix) { 671 layer->updateExternalMatrix(fExternalMatrix, 672 fExternalInverse); 673 } 674 } while ((layer = layer->fNext) != NULL); 675 } 676 fDeviceCMDirty = false; 677 } 678} 679 680void SkCanvas::prepareForDeviceDraw(SkDevice* device, const SkMatrix& matrix, 681 const SkRegion& clip) { 682 SkASSERT(device); 683 if (fLastDeviceToGainFocus != device) { 684 device->gainFocus(matrix, clip); 685 fLastDeviceToGainFocus = device; 686 } 687} 688 689/////////////////////////////////////////////////////////////////////////////// 690 691int SkCanvas::internalSave(SaveFlags flags) { 692 int saveCount = this->getSaveCount(); // record this before the actual save 693 694 MCRec* newTop = (MCRec*)fMCStack.push_back(); 695 new (newTop) MCRec(fMCRec, flags); // balanced in restore() 696 697 newTop->fNext = fMCRec; 698 fMCRec = newTop; 699 700 fClipStack.save(); 701 SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1); 702 703 return saveCount; 704} 705 706int SkCanvas::save(SaveFlags flags) { 707 // call shared impl 708 return this->internalSave(flags); 709} 710 711#define C32MASK (1 << SkBitmap::kARGB_8888_Config) 712#define C16MASK (1 << SkBitmap::kRGB_565_Config) 713#define C8MASK (1 << SkBitmap::kA8_Config) 714 715static SkBitmap::Config resolve_config(SkCanvas* canvas, 716 const SkIRect& bounds, 717 SkCanvas::SaveFlags flags, 718 bool* isOpaque) { 719 *isOpaque = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) == 0; 720 721#if 0 722 // loop through and union all the configs we may draw into 723 uint32_t configMask = 0; 724 for (int i = canvas->countLayerDevices() - 1; i >= 0; --i) 725 { 726 SkDevice* device = canvas->getLayerDevice(i); 727 if (device->intersects(bounds)) 728 configMask |= 1 << device->config(); 729 } 730 731 // if the caller wants alpha or fullcolor, we can't return 565 732 if (flags & (SkCanvas::kFullColorLayer_SaveFlag | 733 SkCanvas::kHasAlphaLayer_SaveFlag)) 734 configMask &= ~C16MASK; 735 736 switch (configMask) { 737 case C8MASK: // if we only have A8, return that 738 return SkBitmap::kA8_Config; 739 740 case C16MASK: // if we only have 565, return that 741 return SkBitmap::kRGB_565_Config; 742 743 default: 744 return SkBitmap::kARGB_8888_Config; // default answer 745 } 746#else 747 return SkBitmap::kARGB_8888_Config; // default answer 748#endif 749} 750 751static bool bounds_affects_clip(SkCanvas::SaveFlags flags) { 752 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0; 753} 754 755bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, 756 SkIRect* intersection) { 757 SkIRect clipBounds; 758 if (!this->getClipDeviceBounds(&clipBounds)) { 759 return false; 760 } 761 SkIRect ir; 762 if (NULL != bounds) { 763 SkRect r; 764 765 this->getTotalMatrix().mapRect(&r, *bounds); 766 r.roundOut(&ir); 767 // early exit if the layer's bounds are clipped out 768 if (!ir.intersect(clipBounds)) { 769 if (bounds_affects_clip(flags)) { 770 fMCRec->fRasterClip->setEmpty(); 771 } 772 return false; 773 } 774 } else { // no user bounds, so just use the clip 775 ir = clipBounds; 776 } 777 778 fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op); 779 780 // early exit if the clip is now empty 781 if (bounds_affects_clip(flags) && 782 !fMCRec->fRasterClip->op(ir, SkRegion::kIntersect_Op)) { 783 return false; 784 } 785 786 if (intersection) { 787 *intersection = ir; 788 } 789 return true; 790} 791 792int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, 793 SaveFlags flags) { 794 return this->internalSaveLayer(bounds, paint, flags, false); 795} 796 797int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, 798 SaveFlags flags, bool justForImageFilter) { 799 // do this before we create the layer. We don't call the public save() since 800 // that would invoke a possibly overridden virtual 801 int count = this->internalSave(flags); 802 803 fDeviceCMDirty = true; 804 805 SkIRect ir; 806 if (!this->clipRectBounds(bounds, flags, &ir)) { 807 return count; 808 } 809 810 // Kill the imagefilter if our device doesn't allow it 811 SkLazyPaint lazyP; 812 if (paint && paint->getImageFilter()) { 813 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) { 814 if (justForImageFilter) { 815 // early exit if the layer was just for the imageFilter 816 return count; 817 } 818 SkPaint* p = lazyP.set(*paint); 819 p->setImageFilter(NULL); 820 paint = p; 821 } 822 } 823 824 bool isOpaque; 825 SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque); 826 827 SkDevice* device; 828 if (paint && paint->getImageFilter()) { 829 device = this->createCompatibleDevice(config, ir.width(), ir.height(), 830 isOpaque); 831 } else { 832 device = this->createLayerDevice(config, ir.width(), ir.height(), 833 isOpaque); 834 } 835 if (NULL == device) { 836 SkDebugf("Unable to create device for layer."); 837 return count; 838 } 839 840 device->setOrigin(ir.fLeft, ir.fTop); 841 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint, this)); 842 device->unref(); 843 844 layer->fNext = fMCRec->fTopLayer; 845 fMCRec->fLayer = layer; 846 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer 847 848 fSaveLayerCount += 1; 849 return count; 850} 851 852int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha, 853 SaveFlags flags) { 854 if (0xFF == alpha) { 855 return this->saveLayer(bounds, NULL, flags); 856 } else { 857 SkPaint tmpPaint; 858 tmpPaint.setAlpha(alpha); 859 return this->saveLayer(bounds, &tmpPaint, flags); 860 } 861} 862 863void SkCanvas::restore() { 864 // check for underflow 865 if (fMCStack.count() > 1) { 866 this->internalRestore(); 867 } 868} 869 870void SkCanvas::internalRestore() { 871 SkASSERT(fMCStack.count() != 0); 872 873 fDeviceCMDirty = true; 874 fLocalBoundsCompareTypeDirty = true; 875 fLocalBoundsCompareTypeDirtyBW = true; 876 877 fClipStack.restore(); 878 // reserve our layer (if any) 879 DeviceCM* layer = fMCRec->fLayer; // may be null 880 // now detach it from fMCRec so we can pop(). Gets freed after its drawn 881 fMCRec->fLayer = NULL; 882 883 // now do the normal restore() 884 fMCRec->~MCRec(); // balanced in save() 885 fMCStack.pop_back(); 886 fMCRec = (MCRec*)fMCStack.back(); 887 888 /* Time to draw the layer's offscreen. We can't call the public drawSprite, 889 since if we're being recorded, we don't want to record this (the 890 recorder will have already recorded the restore). 891 */ 892 if (NULL != layer) { 893 if (layer->fNext) { 894 const SkIPoint& origin = layer->fDevice->getOrigin(); 895 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), 896 layer->fPaint); 897 // reset this, since internalDrawDevice will have set it to true 898 fDeviceCMDirty = true; 899 900 SkASSERT(fSaveLayerCount > 0); 901 fSaveLayerCount -= 1; 902 } 903 SkDELETE(layer); 904 } 905 906 SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1); 907} 908 909int SkCanvas::getSaveCount() const { 910 return fMCStack.count(); 911} 912 913void SkCanvas::restoreToCount(int count) { 914 // sanity check 915 if (count < 1) { 916 count = 1; 917 } 918 919 int n = this->getSaveCount() - count; 920 for (int i = 0; i < n; ++i) { 921 this->restore(); 922 } 923} 924 925bool SkCanvas::isDrawingToLayer() const { 926 return fSaveLayerCount > 0; 927} 928 929///////////////////////////////////////////////////////////////////////////// 930 931// can't draw it if its empty, or its too big for a fixed-point width or height 932static bool reject_bitmap(const SkBitmap& bitmap) { 933 return bitmap.width() <= 0 || bitmap.height() <= 0 934#ifndef SK_ALLOW_OVER_32K_BITMAPS 935 || bitmap.width() > 32767 || bitmap.height() > 32767 936#endif 937 ; 938} 939 940void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect, 941 const SkMatrix& matrix, const SkPaint* paint) { 942 if (reject_bitmap(bitmap)) { 943 return; 944 } 945 946 SkLazyPaint lazy; 947 if (NULL == paint) { 948 paint = lazy.init(); 949 } 950 this->commonDrawBitmap(bitmap, srcRect, matrix, *paint); 951} 952 953#include "SkImageFilter.h" 954 955class DeviceImageFilterProxy : public SkImageFilter::Proxy { 956public: 957 DeviceImageFilterProxy(SkDevice* device) : fDevice(device) {} 958 959 virtual SkDevice* createDevice(int w, int h) SK_OVERRIDE { 960 return fDevice->createCompatibleDevice(SkBitmap::kARGB_8888_Config, 961 w, h, false); 962 } 963 virtual bool canHandleImageFilter(SkImageFilter* filter) SK_OVERRIDE { 964 return fDevice->canHandleImageFilter(filter); 965 } 966 virtual bool filterImage(SkImageFilter* filter, const SkBitmap& src, 967 const SkMatrix& ctm, 968 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE { 969 return fDevice->filterImage(filter, src, ctm, result, offset); 970 } 971 972private: 973 SkDevice* fDevice; 974}; 975 976void SkCanvas::internalDrawDevice(SkDevice* srcDev, int x, int y, 977 const SkPaint* paint) { 978 SkPaint tmp; 979 if (NULL == paint) { 980 tmp.setDither(true); 981 paint = &tmp; 982 } 983 984 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 985 while (iter.next()) { 986 SkDevice* dstDev = iter.fDevice; 987 paint = &looper.paint(); 988 SkImageFilter* filter = paint->getImageFilter(); 989 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 990 if (filter && !dstDev->canHandleImageFilter(filter)) { 991 DeviceImageFilterProxy proxy(dstDev); 992 SkBitmap dst; 993 const SkBitmap& src = srcDev->accessBitmap(false); 994 if (filter->filterImage(&proxy, src, *iter.fMatrix, &dst, &pos)) { 995 SkPaint tmpUnfiltered(*paint); 996 tmpUnfiltered.setImageFilter(NULL); 997 dstDev->drawSprite(iter, dst, pos.x(), pos.y(), tmpUnfiltered); 998 } 999 } else { 1000 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint); 1001 } 1002 } 1003 LOOPER_END 1004} 1005 1006void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, 1007 const SkPaint* paint) { 1008 SkDEBUGCODE(bitmap.validate();) 1009 1010 if (reject_bitmap(bitmap)) { 1011 return; 1012 } 1013 1014 SkPaint tmp; 1015 if (NULL == paint) { 1016 paint = &tmp; 1017 } 1018 1019 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 1020 1021 while (iter.next()) { 1022 paint = &looper.paint(); 1023 SkImageFilter* filter = paint->getImageFilter(); 1024 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 1025 if (filter && !iter.fDevice->canHandleImageFilter(filter)) { 1026 DeviceImageFilterProxy proxy(iter.fDevice); 1027 SkBitmap dst; 1028 if (filter->filterImage(&proxy, bitmap, *iter.fMatrix, 1029 &dst, &pos)) { 1030 SkPaint tmpUnfiltered(*paint); 1031 tmpUnfiltered.setImageFilter(NULL); 1032 iter.fDevice->drawSprite(iter, dst, pos.x(), pos.y(), 1033 tmpUnfiltered); 1034 } 1035 } else { 1036 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint); 1037 } 1038 } 1039 LOOPER_END 1040} 1041 1042///////////////////////////////////////////////////////////////////////////// 1043 1044bool SkCanvas::translate(SkScalar dx, SkScalar dy) { 1045 fDeviceCMDirty = true; 1046 fLocalBoundsCompareTypeDirty = true; 1047 fLocalBoundsCompareTypeDirtyBW = true; 1048 return fMCRec->fMatrix->preTranslate(dx, dy); 1049} 1050 1051bool SkCanvas::scale(SkScalar sx, SkScalar sy) { 1052 fDeviceCMDirty = true; 1053 fLocalBoundsCompareTypeDirty = true; 1054 fLocalBoundsCompareTypeDirtyBW = true; 1055 return fMCRec->fMatrix->preScale(sx, sy); 1056} 1057 1058bool SkCanvas::rotate(SkScalar degrees) { 1059 fDeviceCMDirty = true; 1060 fLocalBoundsCompareTypeDirty = true; 1061 fLocalBoundsCompareTypeDirtyBW = true; 1062 return fMCRec->fMatrix->preRotate(degrees); 1063} 1064 1065bool SkCanvas::skew(SkScalar sx, SkScalar sy) { 1066 fDeviceCMDirty = true; 1067 fLocalBoundsCompareTypeDirty = true; 1068 fLocalBoundsCompareTypeDirtyBW = true; 1069 return fMCRec->fMatrix->preSkew(sx, sy); 1070} 1071 1072bool SkCanvas::concat(const SkMatrix& matrix) { 1073 fDeviceCMDirty = true; 1074 fLocalBoundsCompareTypeDirty = true; 1075 fLocalBoundsCompareTypeDirtyBW = true; 1076 return fMCRec->fMatrix->preConcat(matrix); 1077} 1078 1079void SkCanvas::setMatrix(const SkMatrix& matrix) { 1080 fDeviceCMDirty = true; 1081 fLocalBoundsCompareTypeDirty = true; 1082 fLocalBoundsCompareTypeDirtyBW = true; 1083 *fMCRec->fMatrix = matrix; 1084} 1085 1086// this is not virtual, so it must call a virtual method so that subclasses 1087// will see its action 1088void SkCanvas::resetMatrix() { 1089 SkMatrix matrix; 1090 1091 matrix.reset(); 1092 this->setMatrix(matrix); 1093} 1094 1095////////////////////////////////////////////////////////////////////////////// 1096 1097bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 1098 AutoValidateClip avc(this); 1099 1100 fDeviceCMDirty = true; 1101 fLocalBoundsCompareTypeDirty = true; 1102 fLocalBoundsCompareTypeDirtyBW = true; 1103 1104 if (fMCRec->fMatrix->rectStaysRect()) { 1105 // for these simpler matrices, we can stay a rect ever after applying 1106 // the matrix. This means we don't have to a) make a path, and b) tell 1107 // the region code to scan-convert the path, only to discover that it 1108 // is really just a rect. 1109 SkRect r; 1110 1111 fMCRec->fMatrix->mapRect(&r, rect); 1112 fClipStack.clipDevRect(r, op, doAA); 1113 return fMCRec->fRasterClip->op(r, op, doAA); 1114 } else { 1115 // since we're rotate or some such thing, we convert the rect to a path 1116 // and clip against that, since it can handle any matrix. However, to 1117 // avoid recursion in the case where we are subclassed (e.g. Pictures) 1118 // we explicitly call "our" version of clipPath. 1119 SkPath path; 1120 1121 path.addRect(rect); 1122 return this->SkCanvas::clipPath(path, op, doAA); 1123 } 1124} 1125 1126static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip, 1127 const SkPath& devPath, SkRegion::Op op, bool doAA) { 1128 // base is used to limit the size (and therefore memory allocation) of the 1129 // region that results from scan converting devPath. 1130 SkRegion base; 1131 1132 if (SkRegion::kIntersect_Op == op) { 1133 // since we are intersect, we can do better (tighter) with currRgn's 1134 // bounds, than just using the device. However, if currRgn is complex, 1135 // our region blitter may hork, so we do that case in two steps. 1136 if (currClip->isRect()) { 1137 return currClip->setPath(devPath, *currClip, doAA); 1138 } else { 1139 base.setRect(currClip->getBounds()); 1140 SkRasterClip clip; 1141 clip.setPath(devPath, base, doAA); 1142 return currClip->op(clip, op); 1143 } 1144 } else { 1145 const SkDevice* device = canvas->getDevice(); 1146 if (!device) { 1147 return currClip->setEmpty(); 1148 } 1149 1150 base.setRect(0, 0, device->width(), device->height()); 1151 1152 if (SkRegion::kReplace_Op == op) { 1153 return currClip->setPath(devPath, base, doAA); 1154 } else { 1155 SkRasterClip clip; 1156 clip.setPath(devPath, base, doAA); 1157 return currClip->op(clip, op); 1158 } 1159 } 1160} 1161 1162bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 1163 AutoValidateClip avc(this); 1164 1165 fDeviceCMDirty = true; 1166 fLocalBoundsCompareTypeDirty = true; 1167 fLocalBoundsCompareTypeDirtyBW = true; 1168 1169 SkPath devPath; 1170 path.transform(*fMCRec->fMatrix, &devPath); 1171 1172 // Check if the transfomation, or the original path itself 1173 // made us empty. Note this can also happen if we contained NaN 1174 // values. computing the bounds detects this, and will set our 1175 // bounds to empty if that is the case. (see SkRect::set(pts, count)) 1176 if (devPath.getBounds().isEmpty()) { 1177 // resetting the path will remove any NaN or other wanky values 1178 // that might upset our scan converter. 1179 devPath.reset(); 1180 } 1181 1182 // if we called path.swap() we could avoid a deep copy of this path 1183 fClipStack.clipDevPath(devPath, op, doAA); 1184 1185 return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA); 1186} 1187 1188bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1189 AutoValidateClip avc(this); 1190 1191 fDeviceCMDirty = true; 1192 fLocalBoundsCompareTypeDirty = true; 1193 fLocalBoundsCompareTypeDirtyBW = true; 1194 1195 // todo: signal fClipStack that we have a region, and therefore (I guess) 1196 // we have to ignore it, and use the region directly? 1197 fClipStack.clipDevRect(rgn.getBounds(), op); 1198 1199 return fMCRec->fRasterClip->op(rgn, op); 1200} 1201 1202#ifdef SK_DEBUG 1203void SkCanvas::validateClip() const { 1204 // construct clipRgn from the clipstack 1205 const SkDevice* device = this->getDevice(); 1206 if (!device) { 1207 SkASSERT(this->getTotalClip().isEmpty()); 1208 return; 1209 } 1210 1211 SkIRect ir; 1212 ir.set(0, 0, device->width(), device->height()); 1213 SkRasterClip tmpClip(ir); 1214 1215 SkClipStack::B2TIter iter(fClipStack); 1216 const SkClipStack::B2TIter::Clip* clip; 1217 while ((clip = iter.next()) != NULL) { 1218 if (clip->fPath) { 1219 clipPathHelper(this, &tmpClip, *clip->fPath, clip->fOp, clip->fDoAA); 1220 } else if (clip->fRect) { 1221 clip->fRect->round(&ir); 1222 tmpClip.op(ir, clip->fOp); 1223 } else { 1224 tmpClip.setEmpty(); 1225 } 1226 } 1227 1228#if 0 // enable this locally for testing 1229 // now compare against the current rgn 1230 const SkRegion& rgn = this->getTotalClip(); 1231 SkASSERT(rgn == tmpClip); 1232#endif 1233} 1234#endif 1235 1236void SkCanvas::replayClips(ClipVisitor* visitor) const { 1237 SkClipStack::B2TIter iter(fClipStack); 1238 const SkClipStack::B2TIter::Clip* clip; 1239 1240 SkRect empty = { 0, 0, 0, 0 }; 1241 while ((clip = iter.next()) != NULL) { 1242 if (clip->fPath) { 1243 visitor->clipPath(*clip->fPath, clip->fOp, clip->fDoAA); 1244 } else if (clip->fRect) { 1245 visitor->clipRect(*clip->fRect, clip->fOp, clip->fDoAA); 1246 } else { 1247 visitor->clipRect(empty, SkRegion::kIntersect_Op, false); 1248 } 1249 } 1250} 1251 1252/////////////////////////////////////////////////////////////////////////////// 1253 1254void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const { 1255 SkRect r; 1256 SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType : 1257 fLocalBoundsCompareTypeBW; 1258 1259 if (!this->getClipBounds(&r, et)) { 1260 rCompare.setEmpty(); 1261 } else { 1262 rCompare.set(SkScalarToCompareType(r.fLeft), 1263 SkScalarToCompareType(r.fTop), 1264 SkScalarToCompareType(r.fRight), 1265 SkScalarToCompareType(r.fBottom)); 1266 } 1267} 1268 1269/* current impl ignores edgetype, and relies on 1270 getLocalClipBoundsCompareType(), which always returns a value assuming 1271 antialiasing (worst case) 1272 */ 1273bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const { 1274 1275 if (!rect.isFinite()) 1276 return true; 1277 1278 if (fMCRec->fRasterClip->isEmpty()) { 1279 return true; 1280 } 1281 1282 if (fMCRec->fMatrix->hasPerspective()) { 1283 SkRect dst; 1284 fMCRec->fMatrix->mapRect(&dst, rect); 1285 SkIRect idst; 1286 dst.roundOut(&idst); 1287 return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds()); 1288 } else { 1289 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et); 1290 1291 // for speed, do the most likely reject compares first 1292 SkScalarCompareType userT = SkScalarToCompareType(rect.fTop); 1293 SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom); 1294 if (userT >= clipR.fBottom || userB <= clipR.fTop) { 1295 return true; 1296 } 1297 SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft); 1298 SkScalarCompareType userR = SkScalarToCompareType(rect.fRight); 1299 if (userL >= clipR.fRight || userR <= clipR.fLeft) { 1300 return true; 1301 } 1302 return false; 1303 } 1304} 1305 1306bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const { 1307 return path.isEmpty() || this->quickReject(path.getBounds(), et); 1308} 1309 1310static inline int pinIntForScalar(int x) { 1311#ifdef SK_SCALAR_IS_FIXED 1312 if (x < SK_MinS16) { 1313 x = SK_MinS16; 1314 } else if (x > SK_MaxS16) { 1315 x = SK_MaxS16; 1316 } 1317#endif 1318 return x; 1319} 1320 1321bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const { 1322 SkIRect ibounds; 1323 if (!getClipDeviceBounds(&ibounds)) { 1324 return false; 1325 } 1326 1327 SkMatrix inverse; 1328 // if we can't invert the CTM, we can't return local clip bounds 1329 if (!fMCRec->fMatrix->invert(&inverse)) { 1330 if (bounds) { 1331 bounds->setEmpty(); 1332 } 1333 return false; 1334 } 1335 1336 if (NULL != bounds) { 1337 SkRect r; 1338 // adjust it outwards if we are antialiasing 1339 int inset = (kAA_EdgeType == et); 1340 1341 // SkRect::iset() will correctly assert if we pass a value out of range 1342 // (when SkScalar==fixed), so we pin to legal values. This does not 1343 // really returnt the correct answer, but its the best we can do given 1344 // that we've promised to return SkRect (even though we support devices 1345 // that can be larger than 32K in width or height). 1346 r.iset(pinIntForScalar(ibounds.fLeft - inset), 1347 pinIntForScalar(ibounds.fTop - inset), 1348 pinIntForScalar(ibounds.fRight + inset), 1349 pinIntForScalar(ibounds.fBottom + inset)); 1350 inverse.mapRect(bounds, r); 1351 } 1352 return true; 1353} 1354 1355bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const { 1356 const SkRasterClip& clip = *fMCRec->fRasterClip; 1357 if (clip.isEmpty()) { 1358 if (bounds) { 1359 bounds->setEmpty(); 1360 } 1361 return false; 1362 } 1363 1364 if (NULL != bounds) { 1365 *bounds = clip.getBounds(); 1366 } 1367 return true; 1368} 1369 1370const SkMatrix& SkCanvas::getTotalMatrix() const { 1371 return *fMCRec->fMatrix; 1372} 1373 1374SkCanvas::ClipType SkCanvas::getClipType() const { 1375 if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType; 1376 if (fMCRec->fRasterClip->isRect()) return kRect_ClipType; 1377 return kComplex_ClipType; 1378} 1379 1380const SkRegion& SkCanvas::getTotalClip() const { 1381 return fMCRec->fRasterClip->forceGetBW(); 1382} 1383 1384void SkCanvas::setExternalMatrix(const SkMatrix* matrix) { 1385 if (NULL == matrix || matrix->isIdentity()) { 1386 if (fUseExternalMatrix) { 1387 fDeviceCMDirty = true; 1388 } 1389 fUseExternalMatrix = false; 1390 } else { 1391 if (matrix->invert(&fExternalInverse)) { 1392 fExternalMatrix = *matrix; 1393 fUseExternalMatrix = true; 1394 fDeviceCMDirty = true; // |= (fExternalMatrix != *matrix) 1395 } 1396 } 1397} 1398 1399SkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config, 1400 int width, int height, 1401 bool isOpaque) { 1402 SkDevice* device = this->getTopDevice(); 1403 if (device) { 1404 return device->createCompatibleDeviceForSaveLayer(config, width, height, 1405 isOpaque); 1406 } else { 1407 return NULL; 1408 } 1409} 1410 1411SkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config, 1412 int width, int height, 1413 bool isOpaque) { 1414 SkDevice* device = this->getDevice(); 1415 if (device) { 1416 return device->createCompatibleDevice(config, width, height, isOpaque); 1417 } else { 1418 return NULL; 1419 } 1420} 1421 1422 1423////////////////////////////////////////////////////////////////////////////// 1424// These are the virtual drawing methods 1425////////////////////////////////////////////////////////////////////////////// 1426 1427void SkCanvas::clear(SkColor color) { 1428 SkDrawIter iter(this); 1429 1430 while (iter.next()) { 1431 iter.fDevice->clear(color); 1432 } 1433} 1434 1435void SkCanvas::drawPaint(const SkPaint& paint) { 1436 this->internalDrawPaint(paint); 1437} 1438 1439void SkCanvas::internalDrawPaint(const SkPaint& paint) { 1440 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type) 1441 1442 while (iter.next()) { 1443 iter.fDevice->drawPaint(iter, looper.paint()); 1444 } 1445 1446 LOOPER_END 1447} 1448 1449void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1450 const SkPaint& paint) { 1451 if ((long)count <= 0) { 1452 return; 1453 } 1454 1455 if (paint.canComputeFastBounds()) { 1456 SkRect r; 1457 // special-case 2 points (common for drawing a single line) 1458 if (2 == count) { 1459 r.set(pts[0], pts[1]); 1460 } else { 1461 r.set(pts, count); 1462 } 1463 SkRect storage; 1464 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage), 1465 paint2EdgeType(&paint))) { 1466 return; 1467 } 1468 } 1469 1470 SkASSERT(pts != NULL); 1471 1472 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type) 1473 1474 while (iter.next()) { 1475 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); 1476 } 1477 1478 LOOPER_END 1479} 1480 1481void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1482 if (paint.canComputeFastBounds()) { 1483 SkRect storage; 1484 if (this->quickReject(paint.computeFastBounds(r, &storage), 1485 paint2EdgeType(&paint))) { 1486 return; 1487 } 1488 } 1489 1490 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type) 1491 1492 while (iter.next()) { 1493 iter.fDevice->drawRect(iter, r, looper.paint()); 1494 } 1495 1496 LOOPER_END 1497} 1498 1499void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 1500 if (!path.isFinite()) { 1501 return; 1502 } 1503 1504 if (!path.isInverseFillType() && paint.canComputeFastBounds()) { 1505 SkRect storage; 1506 const SkRect& bounds = path.getBounds(); 1507 if (this->quickReject(paint.computeFastBounds(bounds, &storage), 1508 paint2EdgeType(&paint))) { 1509 return; 1510 } 1511 } 1512 if (path.isEmpty()) { 1513 if (path.isInverseFillType()) { 1514 this->internalDrawPaint(paint); 1515 } 1516 return; 1517 } 1518 1519 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 1520 1521 while (iter.next()) { 1522 iter.fDevice->drawPath(iter, path, looper.paint()); 1523 } 1524 1525 LOOPER_END 1526} 1527 1528void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, 1529 const SkPaint* paint) { 1530 SkDEBUGCODE(bitmap.validate();) 1531 1532 if (NULL == paint || paint->canComputeFastBounds()) { 1533 SkRect bounds = { 1534 x, y, 1535 x + SkIntToScalar(bitmap.width()), 1536 y + SkIntToScalar(bitmap.height()) 1537 }; 1538 if (paint) { 1539 (void)paint->computeFastBounds(bounds, &bounds); 1540 } 1541 if (this->quickReject(bounds, paint2EdgeType(paint))) { 1542 return; 1543 } 1544 } 1545 1546 SkMatrix matrix; 1547 matrix.setTranslate(x, y); 1548 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1549} 1550 1551// this one is non-virtual, so it can be called safely by other canvas apis 1552void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, 1553 const SkRect& dst, const SkPaint* paint) { 1554 if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) { 1555 return; 1556 } 1557 1558 // do this now, to avoid the cost of calling extract for RLE bitmaps 1559 if (NULL == paint || paint->canComputeFastBounds()) { 1560 SkRect storage; 1561 const SkRect* bounds = &dst; 1562 if (paint) { 1563 bounds = &paint->computeFastBounds(dst, &storage); 1564 } 1565 if (this->quickReject(*bounds, paint2EdgeType(paint))) { 1566 return; 1567 } 1568 } 1569 1570 const SkBitmap* bitmapPtr = &bitmap; 1571 1572 SkMatrix matrix; 1573 SkRect tmpSrc; 1574 if (src) { 1575 tmpSrc.set(*src); 1576 // if the extract process clipped off the top or left of the 1577 // original, we adjust for that here to get the position right. 1578 if (tmpSrc.fLeft > 0) { 1579 tmpSrc.fRight -= tmpSrc.fLeft; 1580 tmpSrc.fLeft = 0; 1581 } 1582 if (tmpSrc.fTop > 0) { 1583 tmpSrc.fBottom -= tmpSrc.fTop; 1584 tmpSrc.fTop = 0; 1585 } 1586 } else { 1587 tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()), 1588 SkIntToScalar(bitmap.height())); 1589 } 1590 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 1591 1592 // ensure that src is "valid" before we pass it to our internal routines 1593 // and to SkDevice. i.e. sure it is contained inside the original bitmap. 1594 SkIRect tmpISrc; 1595 if (src) { 1596 tmpISrc.set(0, 0, bitmap.width(), bitmap.height()); 1597 if (!tmpISrc.intersect(*src)) { 1598 return; 1599 } 1600 src = &tmpISrc; 1601 } 1602 this->internalDrawBitmap(*bitmapPtr, src, matrix, paint); 1603} 1604 1605void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, 1606 const SkRect& dst, const SkPaint* paint) { 1607 SkDEBUGCODE(bitmap.validate();) 1608 this->internalDrawBitmapRect(bitmap, src, dst, paint); 1609} 1610 1611void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 1612 const SkPaint* paint) { 1613 SkDEBUGCODE(bitmap.validate();) 1614 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1615} 1616 1617void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect, 1618 const SkMatrix& matrix, const SkPaint& paint) { 1619 SkDEBUGCODE(bitmap.validate();) 1620 1621 LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type) 1622 1623 while (iter.next()) { 1624 iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint()); 1625 } 1626 1627 LOOPER_END 1628} 1629 1630void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap, 1631 const SkIRect& center, const SkRect& dst, 1632 const SkPaint* paint) { 1633 if (NULL == paint || paint->canComputeFastBounds()) { 1634 SkRect storage; 1635 const SkRect* bounds = &dst; 1636 if (paint) { 1637 bounds = &paint->computeFastBounds(dst, &storage); 1638 } 1639 if (this->quickReject(*bounds, paint2EdgeType(paint))) { 1640 return; 1641 } 1642 } 1643 1644 const int32_t w = bitmap.width(); 1645 const int32_t h = bitmap.height(); 1646 1647 SkIRect c = center; 1648 // pin center to the bounds of the bitmap 1649 c.fLeft = SkMax32(0, center.fLeft); 1650 c.fTop = SkMax32(0, center.fTop); 1651 c.fRight = SkPin32(center.fRight, c.fLeft, w); 1652 c.fBottom = SkPin32(center.fBottom, c.fTop, h); 1653 1654 const int32_t srcX[4] = { 0, c.fLeft, c.fRight, w }; 1655 const int32_t srcY[4] = { 0, c.fTop, c.fBottom, h }; 1656 SkScalar dstX[4] = { 1657 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft), 1658 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight 1659 }; 1660 SkScalar dstY[4] = { 1661 dst.fTop, dst.fTop + SkIntToScalar(c.fTop), 1662 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom 1663 }; 1664 1665 if (dstX[1] > dstX[2]) { 1666 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width()); 1667 dstX[2] = dstX[1]; 1668 } 1669 1670 if (dstY[1] > dstY[2]) { 1671 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height()); 1672 dstY[2] = dstY[1]; 1673 } 1674 1675 SkIRect s; 1676 SkRect d; 1677 for (int y = 0; y < 3; y++) { 1678 s.fTop = srcY[y]; 1679 s.fBottom = srcY[y+1]; 1680 d.fTop = dstY[y]; 1681 d.fBottom = dstY[y+1]; 1682 for (int x = 0; x < 3; x++) { 1683 s.fLeft = srcX[x]; 1684 s.fRight = srcX[x+1]; 1685 d.fLeft = dstX[x]; 1686 d.fRight = dstX[x+1]; 1687 this->internalDrawBitmapRect(bitmap, &s, d, paint); 1688 } 1689 } 1690} 1691 1692void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 1693 const SkRect& dst, const SkPaint* paint) { 1694 SkDEBUGCODE(bitmap.validate();) 1695 1696 // Need a device entry-point, so gpu can use a mesh 1697 this->internalDrawBitmapNine(bitmap, center, dst, paint); 1698} 1699 1700class SkDeviceFilteredPaint { 1701public: 1702 SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) { 1703 SkDevice::TextFlags flags; 1704 if (device->filterTextFlags(paint, &flags)) { 1705 SkPaint* newPaint = fLazy.set(paint); 1706 newPaint->setFlags(flags.fFlags); 1707 newPaint->setHinting(flags.fHinting); 1708 fPaint = newPaint; 1709 } else { 1710 fPaint = &paint; 1711 } 1712 } 1713 1714 const SkPaint& paint() const { return *fPaint; } 1715 1716private: 1717 const SkPaint* fPaint; 1718 SkLazyPaint fLazy; 1719}; 1720 1721void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, 1722 const SkRect& r, SkScalar textSize) { 1723 if (paint.getStyle() == SkPaint::kFill_Style) { 1724 draw.fDevice->drawRect(draw, r, paint); 1725 } else { 1726 SkPaint p(paint); 1727 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); 1728 draw.fDevice->drawRect(draw, r, p); 1729 } 1730} 1731 1732void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, 1733 const char text[], size_t byteLength, 1734 SkScalar x, SkScalar y) { 1735 SkASSERT(byteLength == 0 || text != NULL); 1736 1737 // nothing to draw 1738 if (text == NULL || byteLength == 0 || 1739 draw.fClip->isEmpty() || 1740 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 1741 return; 1742 } 1743 1744 SkScalar width = 0; 1745 SkPoint start; 1746 1747 start.set(0, 0); // to avoid warning 1748 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | 1749 SkPaint::kStrikeThruText_Flag)) { 1750 width = paint.measureText(text, byteLength); 1751 1752 SkScalar offsetX = 0; 1753 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 1754 offsetX = SkScalarHalf(width); 1755 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { 1756 offsetX = width; 1757 } 1758 start.set(x - offsetX, y); 1759 } 1760 1761 if (0 == width) { 1762 return; 1763 } 1764 1765 uint32_t flags = paint.getFlags(); 1766 1767 if (flags & (SkPaint::kUnderlineText_Flag | 1768 SkPaint::kStrikeThruText_Flag)) { 1769 SkScalar textSize = paint.getTextSize(); 1770 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 1771 SkRect r; 1772 1773 r.fLeft = start.fX; 1774 r.fRight = start.fX + width; 1775 1776 if (flags & SkPaint::kUnderlineText_Flag) { 1777 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, 1778 start.fY); 1779 r.fTop = offset; 1780 r.fBottom = offset + height; 1781 DrawRect(draw, paint, r, textSize); 1782 } 1783 if (flags & SkPaint::kStrikeThruText_Flag) { 1784 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, 1785 start.fY); 1786 r.fTop = offset; 1787 r.fBottom = offset + height; 1788 DrawRect(draw, paint, r, textSize); 1789 } 1790 } 1791} 1792 1793void SkCanvas::drawText(const void* text, size_t byteLength, 1794 SkScalar x, SkScalar y, const SkPaint& paint) { 1795 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1796 1797 while (iter.next()) { 1798 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1799 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 1800 DrawTextDecorations(iter, dfp.paint(), 1801 static_cast<const char*>(text), byteLength, x, y); 1802 } 1803 1804 LOOPER_END 1805} 1806 1807void SkCanvas::drawPosText(const void* text, size_t byteLength, 1808 const SkPoint pos[], const SkPaint& paint) { 1809 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1810 1811 while (iter.next()) { 1812 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1813 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 1814 dfp.paint()); 1815 } 1816 1817 LOOPER_END 1818} 1819 1820void SkCanvas::drawPosTextH(const void* text, size_t byteLength, 1821 const SkScalar xpos[], SkScalar constY, 1822 const SkPaint& paint) { 1823 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1824 1825 while (iter.next()) { 1826 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1827 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 1828 dfp.paint()); 1829 } 1830 1831 LOOPER_END 1832} 1833 1834void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, 1835 const SkPath& path, const SkMatrix* matrix, 1836 const SkPaint& paint) { 1837 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1838 1839 while (iter.next()) { 1840 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 1841 matrix, looper.paint()); 1842 } 1843 1844 LOOPER_END 1845} 1846 1847#ifdef SK_BUILD_FOR_ANDROID 1848void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength, 1849 const SkPoint pos[], const SkPaint& paint, 1850 const SkPath& path, const SkMatrix* matrix) { 1851 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1852 1853 while (iter.next()) { 1854 iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos, 1855 looper.paint(), path, matrix); 1856 } 1857 1858 LOOPER_END 1859} 1860#endif 1861 1862void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 1863 const SkPoint verts[], const SkPoint texs[], 1864 const SkColor colors[], SkXfermode* xmode, 1865 const uint16_t indices[], int indexCount, 1866 const SkPaint& paint) { 1867 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 1868 1869 while (iter.next()) { 1870 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 1871 colors, xmode, indices, indexCount, 1872 looper.paint()); 1873 } 1874 1875 LOOPER_END 1876} 1877 1878void SkCanvas::drawData(const void* data, size_t length) { 1879 // do nothing. Subclasses may do something with the data 1880} 1881 1882////////////////////////////////////////////////////////////////////////////// 1883// These methods are NOT virtual, and therefore must call back into virtual 1884// methods, rather than actually drawing themselves. 1885////////////////////////////////////////////////////////////////////////////// 1886 1887void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 1888 SkXfermode::Mode mode) { 1889 SkPaint paint; 1890 1891 paint.setARGB(a, r, g, b); 1892 if (SkXfermode::kSrcOver_Mode != mode) { 1893 paint.setXfermodeMode(mode); 1894 } 1895 this->drawPaint(paint); 1896} 1897 1898void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 1899 SkPaint paint; 1900 1901 paint.setColor(c); 1902 if (SkXfermode::kSrcOver_Mode != mode) { 1903 paint.setXfermodeMode(mode); 1904 } 1905 this->drawPaint(paint); 1906} 1907 1908void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 1909 SkPoint pt; 1910 1911 pt.set(x, y); 1912 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1913} 1914 1915void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 1916 SkPoint pt; 1917 SkPaint paint; 1918 1919 pt.set(x, y); 1920 paint.setColor(color); 1921 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1922} 1923 1924void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 1925 const SkPaint& paint) { 1926 SkPoint pts[2]; 1927 1928 pts[0].set(x0, y0); 1929 pts[1].set(x1, y1); 1930 this->drawPoints(kLines_PointMode, 2, pts, paint); 1931} 1932 1933void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 1934 SkScalar right, SkScalar bottom, 1935 const SkPaint& paint) { 1936 SkRect r; 1937 1938 r.set(left, top, right, bottom); 1939 this->drawRect(r, paint); 1940} 1941 1942void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 1943 const SkPaint& paint) { 1944 if (radius < 0) { 1945 radius = 0; 1946 } 1947 1948 SkRect r; 1949 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 1950 1951 if (paint.canComputeFastBounds()) { 1952 SkRect storage; 1953 if (this->quickReject(paint.computeFastBounds(r, &storage), 1954 paint2EdgeType(&paint))) { 1955 return; 1956 } 1957 } 1958 1959 SkPath path; 1960 path.addOval(r); 1961 this->drawPath(path, paint); 1962} 1963 1964void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 1965 const SkPaint& paint) { 1966 if (rx > 0 && ry > 0) { 1967 if (paint.canComputeFastBounds()) { 1968 SkRect storage; 1969 if (this->quickReject(paint.computeFastBounds(r, &storage), 1970 paint2EdgeType(&paint))) { 1971 return; 1972 } 1973 } 1974 1975 SkPath path; 1976 path.addRoundRect(r, rx, ry, SkPath::kCW_Direction); 1977 this->drawPath(path, paint); 1978 } else { 1979 this->drawRect(r, paint); 1980 } 1981} 1982 1983void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1984 if (paint.canComputeFastBounds()) { 1985 SkRect storage; 1986 if (this->quickReject(paint.computeFastBounds(oval, &storage), 1987 paint2EdgeType(&paint))) { 1988 return; 1989 } 1990 } 1991 1992 SkPath path; 1993 path.addOval(oval); 1994 this->drawPath(path, paint); 1995} 1996 1997void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 1998 SkScalar sweepAngle, bool useCenter, 1999 const SkPaint& paint) { 2000 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 2001 this->drawOval(oval, paint); 2002 } else { 2003 SkPath path; 2004 if (useCenter) { 2005 path.moveTo(oval.centerX(), oval.centerY()); 2006 } 2007 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 2008 if (useCenter) { 2009 path.close(); 2010 } 2011 this->drawPath(path, paint); 2012 } 2013} 2014 2015void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 2016 const SkPath& path, SkScalar hOffset, 2017 SkScalar vOffset, const SkPaint& paint) { 2018 SkMatrix matrix; 2019 2020 matrix.setTranslate(hOffset, vOffset); 2021 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 2022} 2023 2024/////////////////////////////////////////////////////////////////////////////// 2025 2026void SkCanvas::drawPicture(SkPicture& picture) { 2027 picture.draw(this); 2028} 2029 2030/////////////////////////////////////////////////////////////////////////////// 2031/////////////////////////////////////////////////////////////////////////////// 2032 2033SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 2034 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); 2035 2036 SkASSERT(canvas); 2037 2038 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 2039 fDone = !fImpl->next(); 2040} 2041 2042SkCanvas::LayerIter::~LayerIter() { 2043 fImpl->~SkDrawIter(); 2044} 2045 2046void SkCanvas::LayerIter::next() { 2047 fDone = !fImpl->next(); 2048} 2049 2050SkDevice* SkCanvas::LayerIter::device() const { 2051 return fImpl->getDevice(); 2052} 2053 2054const SkMatrix& SkCanvas::LayerIter::matrix() const { 2055 return fImpl->getMatrix(); 2056} 2057 2058const SkPaint& SkCanvas::LayerIter::paint() const { 2059 const SkPaint* paint = fImpl->getPaint(); 2060 if (NULL == paint) { 2061 paint = &fDefaultPaint; 2062 } 2063 return *paint; 2064} 2065 2066const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 2067int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 2068int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 2069 2070/////////////////////////////////////////////////////////////////////////////// 2071 2072SkCanvas::ClipVisitor::~ClipVisitor() { } 2073