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