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