SkCanvas.cpp revision b81be7a7809fb0c24ff7d589d537c38b04b772f1
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 "SkScalarCompare.h" 18#include "SkTemplates.h" 19#include "SkTLazy.h" 20#include "SkUtils.h" 21 22//#define SK_TRACE_SAVERESTORE 23 24#ifdef SK_TRACE_SAVERESTORE 25 static int gLayerCounter; 26 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); } 27 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); } 28 29 static int gRecCounter; 30 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); } 31 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); } 32 33 static int gCanvasCounter; 34 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); } 35 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); } 36#else 37 #define inc_layer() 38 #define dec_layer() 39 #define inc_rec() 40 #define dec_rec() 41 #define inc_canvas() 42 #define dec_canvas() 43#endif 44 45typedef SkTLazy<SkPaint> SkLazyPaint; 46 47/////////////////////////////////////////////////////////////////////////////// 48// Helpers for computing fast bounds for quickReject tests 49 50static SkCanvas::EdgeType paint2EdgeType(const SkPaint* paint) { 51 return paint != NULL && paint->isAntiAlias() ? 52 SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType; 53} 54 55/////////////////////////////////////////////////////////////////////////////// 56 57/* This is the record we keep for each SkDevice that the user installs. 58 The clip/matrix/proc are fields that reflect the top of the save/restore 59 stack. Whenever the canvas changes, it marks a dirty flag, and then before 60 these are used (assuming we're not on a layer) we rebuild these cache 61 values: they reflect the top of the save stack, but translated and clipped 62 by the device's XY offset and bitmap-bounds. 63*/ 64struct DeviceCM { 65 DeviceCM* fNext; 66 SkDevice* fDevice; 67 SkRegion fClip; 68 const SkMatrix* fMatrix; 69 SkPaint* fPaint; // may be null (in the future) 70 // optional, related to canvas' external matrix 71 const SkMatrix* fMVMatrix; 72 const SkMatrix* fExtMatrix; 73 74 DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint) 75 : fNext(NULL) { 76 if (NULL != device) { 77 device->ref(); 78 device->lockPixels(); 79 } 80 fDevice = device; 81 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL; 82 } 83 84 ~DeviceCM() { 85 if (NULL != fDevice) { 86 fDevice->unlockPixels(); 87 fDevice->unref(); 88 } 89 SkDELETE(fPaint); 90 } 91 92 void updateMC(const SkMatrix& totalMatrix, const SkRegion& totalClip, 93 const SkClipStack& clipStack, SkRegion* updateClip) { 94 int x = fDevice->getOrigin().x(); 95 int y = fDevice->getOrigin().y(); 96 int width = fDevice->width(); 97 int height = fDevice->height(); 98 99 if ((x | y) == 0) { 100 fMatrix = &totalMatrix; 101 fClip = totalClip; 102 } else { 103 fMatrixStorage = totalMatrix; 104 fMatrixStorage.postTranslate(SkIntToScalar(-x), 105 SkIntToScalar(-y)); 106 fMatrix = &fMatrixStorage; 107 108 totalClip.translate(-x, -y, &fClip); 109 } 110 111 fClip.op(0, 0, width, height, SkRegion::kIntersect_Op); 112 113 // intersect clip, but don't translate it (yet) 114 115 if (updateClip) { 116 updateClip->op(x, y, x + width, y + height, 117 SkRegion::kDifference_Op); 118 } 119 120 fDevice->setMatrixClip(*fMatrix, fClip, clipStack); 121 122#ifdef SK_DEBUG 123 if (!fClip.isEmpty()) { 124 SkIRect deviceR; 125 deviceR.set(0, 0, width, height); 126 SkASSERT(deviceR.contains(fClip.getBounds())); 127 } 128#endif 129 // default is to assume no external matrix 130 fMVMatrix = NULL; 131 fExtMatrix = NULL; 132 } 133 134 // can only be called after calling updateMC() 135 void updateExternalMatrix(const SkMatrix& extM, const SkMatrix& extI) { 136 fMVMatrixStorage.setConcat(extI, *fMatrix); 137 fMVMatrix = &fMVMatrixStorage; 138 fExtMatrix = &extM; // assumes extM has long life-time (owned by canvas) 139 } 140 141private: 142 SkMatrix fMatrixStorage, fMVMatrixStorage; 143}; 144 145/* This is the record we keep for each save/restore level in the stack. 146 Since a level optionally copies the matrix and/or stack, we have pointers 147 for these fields. If the value is copied for this level, the copy is 148 stored in the ...Storage field, and the pointer points to that. If the 149 value is not copied for this level, we ignore ...Storage, and just point 150 at the corresponding value in the previous level in the stack. 151*/ 152class SkCanvas::MCRec { 153public: 154 MCRec* fNext; 155 SkMatrix* fMatrix; // points to either fMatrixStorage or prev MCRec 156 SkRegion* fRegion; // points to either fRegionStorage or prev MCRec 157 SkDrawFilter* fFilter; // the current filter (or null) 158 159 DeviceCM* fLayer; 160 /* If there are any layers in the stack, this points to the top-most 161 one that is at or below this level in the stack (so we know what 162 bitmap/device to draw into from this level. This value is NOT 163 reference counted, since the real owner is either our fLayer field, 164 or a previous one in a lower level.) 165 */ 166 DeviceCM* fTopLayer; 167 168 MCRec(const MCRec* prev, int flags) { 169 if (NULL != prev) { 170 if (flags & SkCanvas::kMatrix_SaveFlag) { 171 fMatrixStorage = *prev->fMatrix; 172 fMatrix = &fMatrixStorage; 173 } else { 174 fMatrix = prev->fMatrix; 175 } 176 177 if (flags & SkCanvas::kClip_SaveFlag) { 178 fRegionStorage = *prev->fRegion; 179 fRegion = &fRegionStorage; 180 } else { 181 fRegion = prev->fRegion; 182 } 183 184 fFilter = prev->fFilter; 185 SkSafeRef(fFilter); 186 187 fTopLayer = prev->fTopLayer; 188 } else { // no prev 189 fMatrixStorage.reset(); 190 191 fMatrix = &fMatrixStorage; 192 fRegion = &fRegionStorage; 193 fFilter = NULL; 194 fTopLayer = NULL; 195 } 196 fLayer = NULL; 197 198 // don't bother initializing fNext 199 inc_rec(); 200 } 201 ~MCRec() { 202 SkSafeUnref(fFilter); 203 SkDELETE(fLayer); 204 dec_rec(); 205 } 206 207private: 208 SkMatrix fMatrixStorage; 209 SkRegion fRegionStorage; 210}; 211 212class SkDrawIter : public SkDraw { 213public: 214 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) { 215 fCanvas = canvas; 216 canvas->updateDeviceCMCache(); 217 218 fClipStack = &canvas->getTotalClipStack(); 219 fBounder = canvas->getBounder(); 220 fCurrLayer = canvas->fMCRec->fTopLayer; 221 fSkipEmptyClips = skipEmptyClips; 222 } 223 224 bool next() { 225 // skip over recs with empty clips 226 if (fSkipEmptyClips) { 227 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) { 228 fCurrLayer = fCurrLayer->fNext; 229 } 230 } 231 232 if (NULL != fCurrLayer) { 233 const DeviceCM* rec = fCurrLayer; 234 235 fMatrix = rec->fMatrix; 236 fClip = &rec->fClip; 237 fDevice = rec->fDevice; 238 fBitmap = &fDevice->accessBitmap(true); 239 fPaint = rec->fPaint; 240 fMVMatrix = rec->fMVMatrix; 241 fExtMatrix = rec->fExtMatrix; 242 SkDEBUGCODE(this->validate();) 243 244 fCurrLayer = rec->fNext; 245 if (fBounder) { 246 fBounder->setClip(fClip); 247 } 248 // fCurrLayer may be NULL now 249 250 fCanvas->prepareForDeviceDraw(fDevice, *fMatrix, *fClip, *fClipStack); 251 return true; 252 } 253 return false; 254 } 255 256 SkDevice* getDevice() const { return fDevice; } 257 int getX() const { return fDevice->getOrigin().x(); } 258 int getY() const { return fDevice->getOrigin().y(); } 259 const SkMatrix& getMatrix() const { return *fMatrix; } 260 const SkRegion& getClip() const { return *fClip; } 261 const SkPaint* getPaint() const { return fPaint; } 262 263private: 264 SkCanvas* fCanvas; 265 const DeviceCM* fCurrLayer; 266 const SkPaint* fPaint; // May be null. 267 SkBool8 fSkipEmptyClips; 268 269 typedef SkDraw INHERITED; 270}; 271 272///////////////////////////////////////////////////////////////////////////// 273 274class AutoDrawLooper { 275public: 276 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint) : fOrigPaint(paint) { 277 fCanvas = canvas; 278 fLooper = paint.getLooper(); 279 fFilter = canvas->getDrawFilter(); 280 fPaint = NULL; 281 fSaveCount = canvas->getSaveCount(); 282 fDone = false; 283 284 if (fLooper) { 285 fLooper->init(canvas); 286 } 287 } 288 289 ~AutoDrawLooper() { 290 SkASSERT(fCanvas->getSaveCount() == fSaveCount); 291 } 292 293 const SkPaint& paint() const { 294 SkASSERT(fPaint); 295 return *fPaint; 296 } 297 298 bool next(SkDrawFilter::Type drawType); 299 300private: 301 SkLazyPaint fLazyPaint; 302 SkCanvas* fCanvas; 303 const SkPaint& fOrigPaint; 304 SkDrawLooper* fLooper; 305 SkDrawFilter* fFilter; 306 const SkPaint* fPaint; 307 int fSaveCount; 308 bool fDone; 309}; 310 311bool AutoDrawLooper::next(SkDrawFilter::Type drawType) { 312 if (fDone) { 313 fPaint = NULL; 314 return false; 315 } 316 if (!fLooper && !fFilter) { 317 fDone = true; 318 fPaint = &fOrigPaint; 319 return true; 320 } 321 322 SkPaint* paint = fLazyPaint.set(fOrigPaint); 323 if (fLooper && !fLooper->next(fCanvas, paint)) { 324 fDone = true; 325 fPaint = NULL; 326 return false; 327 } 328 if (fFilter) { 329 fFilter->filter(paint, drawType); 330 if (NULL == fLooper) { 331 // no looper means we only draw once 332 fDone = true; 333 } 334 } 335 fPaint = paint; 336 return true; 337} 338 339/* Stack helper for managing a SkBounder. In the destructor, if we were 340 given a bounder, we call its commit() method, signifying that we are 341 done accumulating bounds for that draw. 342*/ 343class SkAutoBounderCommit { 344public: 345 SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {} 346 ~SkAutoBounderCommit() { 347 if (NULL != fBounder) { 348 fBounder->commit(); 349 } 350 } 351private: 352 SkBounder* fBounder; 353}; 354 355#include "SkColorPriv.h" 356 357class AutoValidator { 358public: 359 AutoValidator(SkDevice* device) : fDevice(device) {} 360 ~AutoValidator() { 361#ifdef SK_DEBUG 362 const SkBitmap& bm = fDevice->accessBitmap(false); 363 if (bm.config() == SkBitmap::kARGB_4444_Config) { 364 for (int y = 0; y < bm.height(); y++) { 365 const SkPMColor16* p = bm.getAddr16(0, y); 366 for (int x = 0; x < bm.width(); x++) { 367 SkPMColor16 c = p[x]; 368 SkPMColor16Assert(c); 369 } 370 } 371 } 372#endif 373 } 374private: 375 SkDevice* fDevice; 376}; 377 378////////// macros to place around the internal draw calls ////////////////// 379 380#define LOOPER_BEGIN(paint, type) \ 381/* AutoValidator validator(fMCRec->fTopLayer->fDevice); */ \ 382 AutoDrawLooper looper(this, paint); \ 383 while (looper.next(type)) { \ 384 SkAutoBounderCommit ac(fBounder); \ 385 SkDrawIter iter(this); 386 387#define LOOPER_END } 388 389//////////////////////////////////////////////////////////////////////////// 390 391SkDevice* SkCanvas::init(SkDevice* device) { 392 fBounder = NULL; 393 fLocalBoundsCompareType.setEmpty(); 394 fLocalBoundsCompareTypeDirty = true; 395 fLocalBoundsCompareTypeBW.setEmpty(); 396 fLocalBoundsCompareTypeDirtyBW = true; 397 fLastDeviceToGainFocus = NULL; 398 fDeviceCMDirty = false; 399 400 fMCRec = (MCRec*)fMCStack.push_back(); 401 new (fMCRec) MCRec(NULL, 0); 402 403 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL)); 404 fMCRec->fTopLayer = fMCRec->fLayer; 405 fMCRec->fNext = NULL; 406 407 fExternalMatrix.reset(); 408 fExternalInverse.reset(); 409 fUseExternalMatrix = false; 410 411 return this->setDevice(device); 412} 413 414SkCanvas::SkCanvas() 415: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 416 inc_canvas(); 417 418 this->init(NULL); 419} 420 421SkCanvas::SkCanvas(SkDevice* device) 422 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 423 inc_canvas(); 424 425 this->init(device); 426} 427 428SkCanvas::SkCanvas(const SkBitmap& bitmap) 429 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 430 inc_canvas(); 431 432 this->init(SkNEW_ARGS(SkDevice, (bitmap)))->unref(); 433} 434 435SkCanvas::~SkCanvas() { 436 // free up the contents of our deque 437 this->restoreToCount(1); // restore everything but the last 438 this->internalRestore(); // restore the last, since we're going away 439 440 SkSafeUnref(fBounder); 441 442 dec_canvas(); 443} 444 445SkBounder* SkCanvas::setBounder(SkBounder* bounder) { 446 SkRefCnt_SafeAssign(fBounder, bounder); 447 return bounder; 448} 449 450SkDrawFilter* SkCanvas::getDrawFilter() const { 451 return fMCRec->fFilter; 452} 453 454SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) { 455 SkRefCnt_SafeAssign(fMCRec->fFilter, filter); 456 return filter; 457} 458 459/////////////////////////////////////////////////////////////////////////////// 460 461SkDevice* SkCanvas::getDevice() const { 462 // return root device 463 SkDeque::F2BIter iter(fMCStack); 464 MCRec* rec = (MCRec*)iter.next(); 465 SkASSERT(rec && rec->fLayer); 466 return rec->fLayer->fDevice; 467} 468 469SkDevice* SkCanvas::getTopDevice() const { 470 return fMCRec->fTopLayer->fDevice; 471} 472 473SkDevice* SkCanvas::setDevice(SkDevice* device) { 474 // return root device 475 SkDeque::F2BIter iter(fMCStack); 476 MCRec* rec = (MCRec*)iter.next(); 477 SkASSERT(rec && rec->fLayer); 478 SkDevice* rootDevice = rec->fLayer->fDevice; 479 480 if (rootDevice == device) { 481 return device; 482 } 483 484 /* Notify the devices that they are going in/out of scope, so they can do 485 things like lock/unlock their pixels, etc. 486 */ 487 if (device) { 488 device->lockPixels(); 489 } 490 if (rootDevice) { 491 rootDevice->unlockPixels(); 492 } 493 494 SkRefCnt_SafeAssign(rec->fLayer->fDevice, device); 495 rootDevice = device; 496 497 fDeviceCMDirty = true; 498 499 /* Now we update our initial region to have the bounds of the new device, 500 and then intersect all of the clips in our stack with these bounds, 501 to ensure that we can't draw outside of the device's bounds (and trash 502 memory). 503 504 NOTE: this is only a partial-fix, since if the new device is larger than 505 the previous one, we don't know how to "enlarge" the clips in our stack, 506 so drawing may be artificially restricted. Without keeping a history of 507 all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly 508 reconstruct the correct clips, so this approximation will have to do. 509 The caller really needs to restore() back to the base if they want to 510 accurately take advantage of the new device bounds. 511 */ 512 513 if (NULL == device) { 514 rec->fRegion->setEmpty(); 515 while ((rec = (MCRec*)iter.next()) != NULL) { 516 (void)rec->fRegion->setEmpty(); 517 } 518 fClipStack.reset(); 519 } else { 520 // compute our total bounds for all devices 521 SkIRect bounds; 522 523 bounds.set(0, 0, device->width(), device->height()); 524 525 // now jam our 1st clip to be bounds, and intersect the rest with that 526 rec->fRegion->setRect(bounds); 527 while ((rec = (MCRec*)iter.next()) != NULL) { 528 (void)rec->fRegion->op(bounds, SkRegion::kIntersect_Op); 529 } 530 fClipStack.clipDevRect(bounds, SkRegion::kIntersect_Op); 531 } 532 return device; 533} 534 535SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) { 536 SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap))); 537 device->unref(); 538 return device; 539} 540 541bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) { 542 SkDevice* device = this->getDevice(); 543 if (!device) { 544 return false; 545 } 546 return device->readPixels(srcRect, bitmap); 547} 548 549////////////////////////////////////////////////////////////////////////////// 550 551bool SkCanvas::readPixels(SkBitmap* bitmap) { 552 SkDevice* device = this->getDevice(); 553 if (!device) { 554 return false; 555 } 556 SkIRect bounds; 557 bounds.set(0, 0, device->width(), device->height()); 558 return this->readPixels(bounds, bitmap); 559} 560 561void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) { 562 SkDevice* device = this->getDevice(); 563 if (device) { 564 device->writePixels(bitmap, x, y); 565 } 566} 567 568////////////////////////////////////////////////////////////////////////////// 569 570void SkCanvas::updateDeviceCMCache() { 571 if (fDeviceCMDirty) { 572 const SkMatrix& totalMatrix = this->getTotalMatrix(); 573 const SkRegion& totalClip = this->getTotalClip(); 574 DeviceCM* layer = fMCRec->fTopLayer; 575 576 if (NULL == layer->fNext) { // only one layer 577 layer->updateMC(totalMatrix, totalClip, fClipStack, NULL); 578 if (fUseExternalMatrix) { 579 layer->updateExternalMatrix(fExternalMatrix, 580 fExternalInverse); 581 } 582 } else { 583 SkRegion clip; 584 clip = totalClip; // make a copy 585 do { 586 layer->updateMC(totalMatrix, clip, fClipStack, &clip); 587 if (fUseExternalMatrix) { 588 layer->updateExternalMatrix(fExternalMatrix, 589 fExternalInverse); 590 } 591 } while ((layer = layer->fNext) != NULL); 592 } 593 fDeviceCMDirty = false; 594 } 595} 596 597void SkCanvas::prepareForDeviceDraw(SkDevice* device, const SkMatrix& matrix, 598 const SkRegion& clip, 599 const SkClipStack& clipStack) { 600 SkASSERT(device); 601 if (fLastDeviceToGainFocus != device) { 602 device->gainFocus(this, matrix, clip, clipStack); 603 fLastDeviceToGainFocus = device; 604 } 605} 606 607/////////////////////////////////////////////////////////////////////////////// 608 609int SkCanvas::internalSave(SaveFlags flags) { 610 int saveCount = this->getSaveCount(); // record this before the actual save 611 612 MCRec* newTop = (MCRec*)fMCStack.push_back(); 613 new (newTop) MCRec(fMCRec, flags); // balanced in restore() 614 615 newTop->fNext = fMCRec; 616 fMCRec = newTop; 617 618 fClipStack.save(); 619 SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1); 620 621 return saveCount; 622} 623 624int SkCanvas::save(SaveFlags flags) { 625 // call shared impl 626 return this->internalSave(flags); 627} 628 629#define C32MASK (1 << SkBitmap::kARGB_8888_Config) 630#define C16MASK (1 << SkBitmap::kRGB_565_Config) 631#define C8MASK (1 << SkBitmap::kA8_Config) 632 633static SkBitmap::Config resolve_config(SkCanvas* canvas, 634 const SkIRect& bounds, 635 SkCanvas::SaveFlags flags, 636 bool* isOpaque) { 637 *isOpaque = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) == 0; 638 639#if 0 640 // loop through and union all the configs we may draw into 641 uint32_t configMask = 0; 642 for (int i = canvas->countLayerDevices() - 1; i >= 0; --i) 643 { 644 SkDevice* device = canvas->getLayerDevice(i); 645 if (device->intersects(bounds)) 646 configMask |= 1 << device->config(); 647 } 648 649 // if the caller wants alpha or fullcolor, we can't return 565 650 if (flags & (SkCanvas::kFullColorLayer_SaveFlag | 651 SkCanvas::kHasAlphaLayer_SaveFlag)) 652 configMask &= ~C16MASK; 653 654 switch (configMask) { 655 case C8MASK: // if we only have A8, return that 656 return SkBitmap::kA8_Config; 657 658 case C16MASK: // if we only have 565, return that 659 return SkBitmap::kRGB_565_Config; 660 661 default: 662 return SkBitmap::kARGB_8888_Config; // default answer 663 } 664#else 665 return SkBitmap::kARGB_8888_Config; // default answer 666#endif 667} 668 669static bool bounds_affects_clip(SkCanvas::SaveFlags flags) { 670 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0; 671} 672 673int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, 674 SaveFlags flags) { 675 // do this before we create the layer. We don't call the public save() since 676 // that would invoke a possibly overridden virtual 677 int count = this->internalSave(flags); 678 679 fDeviceCMDirty = true; 680 681 SkIRect ir; 682 const SkIRect& clipBounds = this->getTotalClip().getBounds(); 683 if (clipBounds.isEmpty()) { 684 return count; 685 } 686 687 if (NULL != bounds) { 688 SkRect r; 689 690 this->getTotalMatrix().mapRect(&r, *bounds); 691 r.roundOut(&ir); 692 // early exit if the layer's bounds are clipped out 693 if (!ir.intersect(clipBounds)) { 694 if (bounds_affects_clip(flags)) 695 fMCRec->fRegion->setEmpty(); 696 return count; 697 } 698 } else { // no user bounds, so just use the clip 699 ir = clipBounds; 700 } 701 702 fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op); 703 // early exit if the clip is now empty 704 if (bounds_affects_clip(flags) && 705 !fMCRec->fRegion->op(ir, SkRegion::kIntersect_Op)) { 706 return count; 707 } 708 709 bool isOpaque; 710 SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque); 711 712 SkDevice* device = this->createLayerDevice(config, ir.width(), ir.height(), 713 isOpaque); 714 715 device->setOrigin(ir.fLeft, ir.fTop); 716 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint)); 717 device->unref(); 718 719 layer->fNext = fMCRec->fTopLayer; 720 fMCRec->fLayer = layer; 721 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer 722 723 return count; 724} 725 726int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha, 727 SaveFlags flags) { 728 if (0xFF == alpha) { 729 return this->saveLayer(bounds, NULL, flags); 730 } else { 731 SkPaint tmpPaint; 732 tmpPaint.setAlpha(alpha); 733 return this->saveLayer(bounds, &tmpPaint, flags); 734 } 735} 736 737void SkCanvas::restore() { 738 // check for underflow 739 if (fMCStack.count() > 1) { 740 this->internalRestore(); 741 } 742} 743 744void SkCanvas::internalRestore() { 745 SkASSERT(fMCStack.count() != 0); 746 747 fDeviceCMDirty = true; 748 fLocalBoundsCompareTypeDirty = true; 749 fLocalBoundsCompareTypeDirtyBW = true; 750 751 fClipStack.restore(); 752 // reserve our layer (if any) 753 DeviceCM* layer = fMCRec->fLayer; // may be null 754 // now detach it from fMCRec so we can pop(). Gets freed after its drawn 755 fMCRec->fLayer = NULL; 756 757 // now do the normal restore() 758 fMCRec->~MCRec(); // balanced in save() 759 fMCStack.pop_back(); 760 fMCRec = (MCRec*)fMCStack.back(); 761 762 /* Time to draw the layer's offscreen. We can't call the public drawSprite, 763 since if we're being recorded, we don't want to record this (the 764 recorder will have already recorded the restore). 765 */ 766 if (NULL != layer) { 767 if (layer->fNext) { 768 const SkIPoint& origin = layer->fDevice->getOrigin(); 769 this->drawDevice(layer->fDevice, origin.x(), origin.y(), 770 layer->fPaint); 771 // reset this, since drawDevice will have set it to true 772 fDeviceCMDirty = true; 773 } 774 SkDELETE(layer); 775 } 776 777 SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1); 778} 779 780int SkCanvas::getSaveCount() const { 781 return fMCStack.count(); 782} 783 784void SkCanvas::restoreToCount(int count) { 785 // sanity check 786 if (count < 1) { 787 count = 1; 788 } 789 while (fMCStack.count() > count) { 790 this->restore(); 791 } 792} 793 794///////////////////////////////////////////////////////////////////////////// 795 796// can't draw it if its empty, or its too big for a fixed-point width or height 797static bool reject_bitmap(const SkBitmap& bitmap) { 798 return bitmap.width() <= 0 || bitmap.height() <= 0 799#ifndef SK_ALLOW_OVER_32K_BITMAPS 800 || bitmap.width() > 32767 || bitmap.height() > 32767 801#endif 802 ; 803} 804 805void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect, 806 const SkMatrix& matrix, const SkPaint* paint) { 807 if (reject_bitmap(bitmap)) { 808 return; 809 } 810 811 SkLazyPaint lazy; 812 if (NULL == paint) { 813 paint = lazy.init(); 814 } 815 this->commonDrawBitmap(bitmap, srcRect, matrix, *paint); 816} 817 818void SkCanvas::drawDevice(SkDevice* device, int x, int y, 819 const SkPaint* paint) { 820 SkPaint tmp; 821 if (NULL == paint) { 822 tmp.setDither(true); 823 paint = &tmp; 824 } 825 826 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type) 827 while (iter.next()) { 828 iter.fDevice->drawDevice(iter, device, x - iter.getX(), y - iter.getY(), 829 looper.paint()); 830 } 831 LOOPER_END 832} 833 834///////////////////////////////////////////////////////////////////////////// 835 836bool SkCanvas::translate(SkScalar dx, SkScalar dy) { 837 fDeviceCMDirty = true; 838 fLocalBoundsCompareTypeDirty = true; 839 fLocalBoundsCompareTypeDirtyBW = true; 840 return fMCRec->fMatrix->preTranslate(dx, dy); 841} 842 843bool SkCanvas::scale(SkScalar sx, SkScalar sy) { 844 fDeviceCMDirty = true; 845 fLocalBoundsCompareTypeDirty = true; 846 fLocalBoundsCompareTypeDirtyBW = true; 847 return fMCRec->fMatrix->preScale(sx, sy); 848} 849 850bool SkCanvas::rotate(SkScalar degrees) { 851 fDeviceCMDirty = true; 852 fLocalBoundsCompareTypeDirty = true; 853 fLocalBoundsCompareTypeDirtyBW = true; 854 return fMCRec->fMatrix->preRotate(degrees); 855} 856 857bool SkCanvas::skew(SkScalar sx, SkScalar sy) { 858 fDeviceCMDirty = true; 859 fLocalBoundsCompareTypeDirty = true; 860 fLocalBoundsCompareTypeDirtyBW = true; 861 return fMCRec->fMatrix->preSkew(sx, sy); 862} 863 864bool SkCanvas::concat(const SkMatrix& matrix) { 865 fDeviceCMDirty = true; 866 fLocalBoundsCompareTypeDirty = true; 867 fLocalBoundsCompareTypeDirtyBW = true; 868 return fMCRec->fMatrix->preConcat(matrix); 869} 870 871void SkCanvas::setMatrix(const SkMatrix& matrix) { 872 fDeviceCMDirty = true; 873 fLocalBoundsCompareTypeDirty = true; 874 fLocalBoundsCompareTypeDirtyBW = true; 875 *fMCRec->fMatrix = matrix; 876} 877 878// this is not virtual, so it must call a virtual method so that subclasses 879// will see its action 880void SkCanvas::resetMatrix() { 881 SkMatrix matrix; 882 883 matrix.reset(); 884 this->setMatrix(matrix); 885} 886 887////////////////////////////////////////////////////////////////////////////// 888 889bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) { 890 AutoValidateClip avc(this); 891 892 fDeviceCMDirty = true; 893 fLocalBoundsCompareTypeDirty = true; 894 fLocalBoundsCompareTypeDirtyBW = true; 895 896 if (fMCRec->fMatrix->rectStaysRect()) { 897 // for these simpler matrices, we can stay a rect ever after applying 898 // the matrix. This means we don't have to a) make a path, and b) tell 899 // the region code to scan-convert the path, only to discover that it 900 // is really just a rect. 901 SkRect r; 902 SkIRect ir; 903 904 fMCRec->fMatrix->mapRect(&r, rect); 905 fClipStack.clipDevRect(r, op); 906 r.round(&ir); 907 return fMCRec->fRegion->op(ir, op); 908 } else { 909 // since we're rotate or some such thing, we convert the rect to a path 910 // and clip against that, since it can handle any matrix. However, to 911 // avoid recursion in the case where we are subclassed (e.g. Pictures) 912 // we explicitly call "our" version of clipPath. 913 SkPath path; 914 915 path.addRect(rect); 916 return this->SkCanvas::clipPath(path, op); 917 } 918} 919 920static bool clipPathHelper(const SkCanvas* canvas, SkRegion* currRgn, 921 const SkPath& devPath, SkRegion::Op op) { 922 // base is used to limit the size (and therefore memory allocation) of the 923 // region that results from scan converting devPath. 924 SkRegion base; 925 926 if (SkRegion::kIntersect_Op == op) { 927 // since we are intersect, we can do better (tighter) with currRgn's 928 // bounds, than just using the device. However, if currRgn is complex, 929 // our region blitter may hork, so we do that case in two steps. 930 if (currRgn->isRect()) { 931 return currRgn->setPath(devPath, *currRgn); 932 } else { 933 base.setRect(currRgn->getBounds()); 934 SkRegion rgn; 935 rgn.setPath(devPath, base); 936 return currRgn->op(rgn, op); 937 } 938 } else { 939 const SkBitmap& bm = canvas->getDevice()->accessBitmap(false); 940 base.setRect(0, 0, bm.width(), bm.height()); 941 942 if (SkRegion::kReplace_Op == op) { 943 return currRgn->setPath(devPath, base); 944 } else { 945 SkRegion rgn; 946 rgn.setPath(devPath, base); 947 return currRgn->op(rgn, op); 948 } 949 } 950} 951 952bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op) { 953 AutoValidateClip avc(this); 954 955 fDeviceCMDirty = true; 956 fLocalBoundsCompareTypeDirty = true; 957 fLocalBoundsCompareTypeDirtyBW = true; 958 959 SkPath devPath; 960 path.transform(*fMCRec->fMatrix, &devPath); 961 962 // if we called path.swap() we could avoid a deep copy of this path 963 fClipStack.clipDevPath(devPath, op); 964 965 return clipPathHelper(this, fMCRec->fRegion, devPath, op); 966} 967 968bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 969 AutoValidateClip avc(this); 970 971 fDeviceCMDirty = true; 972 fLocalBoundsCompareTypeDirty = true; 973 fLocalBoundsCompareTypeDirtyBW = true; 974 975 // todo: signal fClipStack that we have a region, and therefore (I guess) 976 // we have to ignore it, and use the region directly? 977 fClipStack.clipDevRect(rgn.getBounds()); 978 979 return fMCRec->fRegion->op(rgn, op); 980} 981 982#ifdef SK_DEBUG 983void SkCanvas::validateClip() const { 984 // construct clipRgn from the clipstack 985 const SkDevice* device = this->getDevice(); 986 SkIRect ir; 987 ir.set(0, 0, device->width(), device->height()); 988 SkRegion clipRgn(ir); 989 990 SkClipStack::B2FIter iter(fClipStack); 991 const SkClipStack::B2FIter::Clip* clip; 992 while ((clip = iter.next()) != NULL) { 993 if (clip->fPath) { 994 clipPathHelper(this, &clipRgn, *clip->fPath, clip->fOp); 995 } else if (clip->fRect) { 996 clip->fRect->round(&ir); 997 clipRgn.op(ir, clip->fOp); 998 } else { 999 clipRgn.setEmpty(); 1000 } 1001 } 1002 1003#if 0 // enable this locally for testing 1004 // now compare against the current rgn 1005 const SkRegion& rgn = this->getTotalClip(); 1006 SkASSERT(rgn == clipRgn); 1007#endif 1008} 1009#endif 1010 1011/////////////////////////////////////////////////////////////////////////////// 1012 1013void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const { 1014 SkRect r; 1015 SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType : 1016 fLocalBoundsCompareTypeBW; 1017 1018 if (!this->getClipBounds(&r, et)) { 1019 rCompare.setEmpty(); 1020 } else { 1021 rCompare.set(SkScalarToCompareType(r.fLeft), 1022 SkScalarToCompareType(r.fTop), 1023 SkScalarToCompareType(r.fRight), 1024 SkScalarToCompareType(r.fBottom)); 1025 } 1026} 1027 1028/* current impl ignores edgetype, and relies on 1029 getLocalClipBoundsCompareType(), which always returns a value assuming 1030 antialiasing (worst case) 1031 */ 1032bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const { 1033 1034 if (!rect.hasValidCoordinates()) 1035 return true; 1036 1037 if (fMCRec->fRegion->isEmpty()) { 1038 return true; 1039 } 1040 1041 if (fMCRec->fMatrix->hasPerspective()) { 1042 SkRect dst; 1043 fMCRec->fMatrix->mapRect(&dst, rect); 1044 SkIRect idst; 1045 dst.roundOut(&idst); 1046 return !SkIRect::Intersects(idst, fMCRec->fRegion->getBounds()); 1047 } else { 1048 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et); 1049 1050 // for speed, do the most likely reject compares first 1051 SkScalarCompareType userT = SkScalarToCompareType(rect.fTop); 1052 SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom); 1053 if (userT >= clipR.fBottom || userB <= clipR.fTop) { 1054 return true; 1055 } 1056 SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft); 1057 SkScalarCompareType userR = SkScalarToCompareType(rect.fRight); 1058 if (userL >= clipR.fRight || userR <= clipR.fLeft) { 1059 return true; 1060 } 1061 return false; 1062 } 1063} 1064 1065bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const { 1066 return path.isEmpty() || this->quickReject(path.getBounds(), et); 1067} 1068 1069bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const { 1070 /* current impl ignores edgetype, and relies on 1071 getLocalClipBoundsCompareType(), which always returns a value assuming 1072 antialiasing (worst case) 1073 */ 1074 1075 if (fMCRec->fRegion->isEmpty()) { 1076 return true; 1077 } 1078 1079 SkScalarCompareType userT = SkScalarToCompareType(top); 1080 SkScalarCompareType userB = SkScalarToCompareType(bottom); 1081 1082 // check for invalid user Y coordinates (i.e. empty) 1083 // reed: why do we need to do this check, since it slows us down? 1084 if (userT >= userB) { 1085 return true; 1086 } 1087 1088 // check if we are above or below the local clip bounds 1089 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(); 1090 return userT >= clipR.fBottom || userB <= clipR.fTop; 1091} 1092 1093bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const { 1094 const SkRegion& clip = *fMCRec->fRegion; 1095 if (clip.isEmpty()) { 1096 if (bounds) { 1097 bounds->setEmpty(); 1098 } 1099 return false; 1100 } 1101 1102 SkMatrix inverse; 1103 // if we can't invert the CTM, we can't return local clip bounds 1104 if (!fMCRec->fMatrix->invert(&inverse)) { 1105 if (bounds) { 1106 bounds->setEmpty(); 1107 } 1108 return false; 1109 } 1110 1111 if (NULL != bounds) { 1112 SkRect r; 1113 // get the clip's bounds 1114 const SkIRect& ibounds = clip.getBounds(); 1115 // adjust it outwards if we are antialiasing 1116 int inset = (kAA_EdgeType == et); 1117 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset, 1118 ibounds.fRight + inset, ibounds.fBottom + inset); 1119 1120 // invert into local coordinates 1121 inverse.mapRect(bounds, r); 1122 } 1123 return true; 1124} 1125 1126const SkMatrix& SkCanvas::getTotalMatrix() const { 1127 return *fMCRec->fMatrix; 1128} 1129 1130const SkRegion& SkCanvas::getTotalClip() const { 1131 return *fMCRec->fRegion; 1132} 1133 1134const SkClipStack& SkCanvas::getTotalClipStack() const { 1135 return fClipStack; 1136} 1137 1138void SkCanvas::setExternalMatrix(const SkMatrix* matrix) { 1139 if (NULL == matrix || matrix->isIdentity()) { 1140 if (fUseExternalMatrix) { 1141 fDeviceCMDirty = true; 1142 } 1143 fUseExternalMatrix = false; 1144 } else { 1145 fUseExternalMatrix = true; 1146 fDeviceCMDirty = true; // |= (fExternalMatrix != *matrix) 1147 1148 fExternalMatrix = *matrix; 1149 matrix->invert(&fExternalInverse); 1150 } 1151} 1152 1153SkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config, 1154 int width, int height, 1155 bool isOpaque) { 1156 SkDevice* device = this->getDevice(); 1157 if (device) { 1158 return device->createCompatibleDeviceForSaveLayer(config, width, height, 1159 isOpaque); 1160 } else { 1161 return NULL; 1162 } 1163} 1164 1165SkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config, 1166 int width, int height, 1167 bool isOpaque) { 1168 SkDevice* device = this->getDevice(); 1169 if (device) { 1170 return device->createCompatibleDevice(config, width, height, isOpaque); 1171 } else { 1172 return NULL; 1173 } 1174} 1175 1176 1177////////////////////////////////////////////////////////////////////////////// 1178// These are the virtual drawing methods 1179////////////////////////////////////////////////////////////////////////////// 1180 1181void SkCanvas::clear(SkColor color) { 1182 SkDrawIter iter(this); 1183 1184 while (iter.next()) { 1185 iter.fDevice->clear(color); 1186 } 1187} 1188 1189void SkCanvas::drawPaint(const SkPaint& paint) { 1190 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type) 1191 1192 while (iter.next()) { 1193 iter.fDevice->drawPaint(iter, looper.paint()); 1194 } 1195 1196 LOOPER_END 1197} 1198 1199void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1200 const SkPaint& paint) { 1201 if ((long)count <= 0) { 1202 return; 1203 } 1204 1205 SkASSERT(pts != NULL); 1206 1207 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type) 1208 1209 while (iter.next()) { 1210 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); 1211 } 1212 1213 LOOPER_END 1214} 1215 1216void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1217 if (paint.canComputeFastBounds()) { 1218 SkRect storage; 1219 if (this->quickReject(paint.computeFastBounds(r, &storage), 1220 paint2EdgeType(&paint))) { 1221 return; 1222 } 1223 } 1224 1225 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type) 1226 1227 while (iter.next()) { 1228 iter.fDevice->drawRect(iter, r, looper.paint()); 1229 } 1230 1231 LOOPER_END 1232} 1233 1234void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 1235 if (paint.canComputeFastBounds()) { 1236 SkRect storage; 1237 const SkRect& bounds = path.getBounds(); 1238 if (this->quickReject(paint.computeFastBounds(bounds, &storage), 1239 paint2EdgeType(&paint))) { 1240 return; 1241 } 1242 } 1243 1244 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 1245 1246 while (iter.next()) { 1247 iter.fDevice->drawPath(iter, path, looper.paint()); 1248 } 1249 1250 LOOPER_END 1251} 1252 1253void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, 1254 const SkPaint* paint) { 1255 SkDEBUGCODE(bitmap.validate();) 1256 1257 if (NULL == paint || (paint->getMaskFilter() == NULL)) { 1258 SkRect fastBounds; 1259 fastBounds.set(x, y, 1260 x + SkIntToScalar(bitmap.width()), 1261 y + SkIntToScalar(bitmap.height())); 1262 if (this->quickReject(fastBounds, paint2EdgeType(paint))) { 1263 return; 1264 } 1265 } 1266 1267 SkMatrix matrix; 1268 matrix.setTranslate(x, y); 1269 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1270} 1271 1272void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, 1273 const SkRect& dst, const SkPaint* paint) { 1274 if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) { 1275 return; 1276 } 1277 1278 // do this now, to avoid the cost of calling extract for RLE bitmaps 1279 if (this->quickReject(dst, paint2EdgeType(paint))) { 1280 return; 1281 } 1282 1283 const SkBitmap* bitmapPtr = &bitmap; 1284 1285 SkMatrix matrix; 1286 SkRect tmpSrc; 1287 if (src) { 1288 tmpSrc.set(*src); 1289 // if the extract process clipped off the top or left of the 1290 // original, we adjust for that here to get the position right. 1291 if (tmpSrc.fLeft > 0) { 1292 tmpSrc.fRight -= tmpSrc.fLeft; 1293 tmpSrc.fLeft = 0; 1294 } 1295 if (tmpSrc.fTop > 0) { 1296 tmpSrc.fBottom -= tmpSrc.fTop; 1297 tmpSrc.fTop = 0; 1298 } 1299 } else { 1300 tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()), 1301 SkIntToScalar(bitmap.height())); 1302 } 1303 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 1304 1305 // ensure that src is "valid" before we pass it to our internal routines 1306 // and to SkDevice. i.e. sure it is contained inside the original bitmap. 1307 SkIRect tmpISrc; 1308 if (src) { 1309 tmpISrc.set(0, 0, bitmap.width(), bitmap.height()); 1310 if (!tmpISrc.intersect(*src)) { 1311 return; 1312 } 1313 src = &tmpISrc; 1314 } 1315 this->internalDrawBitmap(*bitmapPtr, src, matrix, paint); 1316} 1317 1318void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 1319 const SkPaint* paint) { 1320 SkDEBUGCODE(bitmap.validate();) 1321 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1322} 1323 1324void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect, 1325 const SkMatrix& matrix, const SkPaint& paint) { 1326 SkDEBUGCODE(bitmap.validate();) 1327 1328 LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type) 1329 1330 while (iter.next()) { 1331 iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint()); 1332 } 1333 1334 LOOPER_END 1335} 1336 1337void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, 1338 const SkPaint* paint) { 1339 SkDEBUGCODE(bitmap.validate();) 1340 1341 if (reject_bitmap(bitmap)) { 1342 return; 1343 } 1344 1345 SkPaint tmp; 1346 if (NULL == paint) { 1347 paint = &tmp; 1348 } 1349 1350 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type) 1351 1352 while (iter.next()) { 1353 iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(), 1354 looper.paint()); 1355 } 1356 LOOPER_END 1357} 1358 1359class SkDeviceFilteredPaint { 1360public: 1361 SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) { 1362 SkDevice::TextFlags flags; 1363 if (device->filterTextFlags(paint, &flags)) { 1364 SkPaint* newPaint = fLazy.set(paint); 1365 newPaint->setFlags(flags.fFlags); 1366 newPaint->setHinting(flags.fHinting); 1367 fPaint = newPaint; 1368 } else { 1369 fPaint = &paint; 1370 } 1371 } 1372 1373 const SkPaint& paint() const { return *fPaint; } 1374 1375private: 1376 const SkPaint* fPaint; 1377 SkLazyPaint fLazy; 1378}; 1379 1380void SkCanvas::drawText(const void* text, size_t byteLength, 1381 SkScalar x, SkScalar y, const SkPaint& paint) { 1382 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1383 1384 while (iter.next()) { 1385 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1386 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 1387 } 1388 1389 LOOPER_END 1390} 1391 1392void SkCanvas::drawPosText(const void* text, size_t byteLength, 1393 const SkPoint pos[], const SkPaint& paint) { 1394 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1395 1396 while (iter.next()) { 1397 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1398 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 1399 dfp.paint()); 1400 } 1401 1402 LOOPER_END 1403} 1404 1405void SkCanvas::drawPosTextH(const void* text, size_t byteLength, 1406 const SkScalar xpos[], SkScalar constY, 1407 const SkPaint& paint) { 1408 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1409 1410 while (iter.next()) { 1411 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1412 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 1413 dfp.paint()); 1414 } 1415 1416 LOOPER_END 1417} 1418 1419void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, 1420 const SkPath& path, const SkMatrix* matrix, 1421 const SkPaint& paint) { 1422 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1423 1424 while (iter.next()) { 1425 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 1426 matrix, looper.paint()); 1427 } 1428 1429 LOOPER_END 1430} 1431 1432#ifdef ANDROID 1433void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength, 1434 const SkPoint pos[], const SkPaint& paint, 1435 const SkPath& path, const SkMatrix* matrix) { 1436 1437 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1438 1439 while (iter.next()) { 1440 iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos, 1441 looper.paint(), path, matrix); 1442 } 1443 1444 LOOPER_END 1445} 1446#endif 1447 1448void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 1449 const SkPoint verts[], const SkPoint texs[], 1450 const SkColor colors[], SkXfermode* xmode, 1451 const uint16_t indices[], int indexCount, 1452 const SkPaint& paint) { 1453 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 1454 1455 while (iter.next()) { 1456 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 1457 colors, xmode, indices, indexCount, 1458 looper.paint()); 1459 } 1460 1461 LOOPER_END 1462} 1463 1464void SkCanvas::drawData(const void* data, size_t length) { 1465 // do nothing. Subclasses may do something with the data 1466} 1467 1468////////////////////////////////////////////////////////////////////////////// 1469// These methods are NOT virtual, and therefore must call back into virtual 1470// methods, rather than actually drawing themselves. 1471////////////////////////////////////////////////////////////////////////////// 1472 1473void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 1474 SkXfermode::Mode mode) { 1475 SkPaint paint; 1476 1477 paint.setARGB(a, r, g, b); 1478 if (SkXfermode::kSrcOver_Mode != mode) { 1479 paint.setXfermodeMode(mode); 1480 } 1481 this->drawPaint(paint); 1482} 1483 1484void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 1485 SkPaint paint; 1486 1487 paint.setColor(c); 1488 if (SkXfermode::kSrcOver_Mode != mode) { 1489 paint.setXfermodeMode(mode); 1490 } 1491 this->drawPaint(paint); 1492} 1493 1494void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 1495 SkPoint pt; 1496 1497 pt.set(x, y); 1498 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1499} 1500 1501void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 1502 SkPoint pt; 1503 SkPaint paint; 1504 1505 pt.set(x, y); 1506 paint.setColor(color); 1507 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1508} 1509 1510void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 1511 const SkPaint& paint) { 1512 SkPoint pts[2]; 1513 1514 pts[0].set(x0, y0); 1515 pts[1].set(x1, y1); 1516 this->drawPoints(kLines_PointMode, 2, pts, paint); 1517} 1518 1519void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 1520 SkScalar right, SkScalar bottom, 1521 const SkPaint& paint) { 1522 SkRect r; 1523 1524 r.set(left, top, right, bottom); 1525 this->drawRect(r, paint); 1526} 1527 1528void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 1529 const SkPaint& paint) { 1530 if (radius < 0) { 1531 radius = 0; 1532 } 1533 1534 SkRect r; 1535 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 1536 1537 if (paint.canComputeFastBounds()) { 1538 SkRect storage; 1539 if (this->quickReject(paint.computeFastBounds(r, &storage), 1540 paint2EdgeType(&paint))) { 1541 return; 1542 } 1543 } 1544 1545 SkPath path; 1546 path.addOval(r); 1547 this->drawPath(path, paint); 1548} 1549 1550void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 1551 const SkPaint& paint) { 1552 if (rx > 0 && ry > 0) { 1553 if (paint.canComputeFastBounds()) { 1554 SkRect storage; 1555 if (this->quickReject(paint.computeFastBounds(r, &storage), 1556 paint2EdgeType(&paint))) { 1557 return; 1558 } 1559 } 1560 1561 SkPath path; 1562 path.addRoundRect(r, rx, ry, SkPath::kCW_Direction); 1563 this->drawPath(path, paint); 1564 } else { 1565 this->drawRect(r, paint); 1566 } 1567} 1568 1569void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1570 if (paint.canComputeFastBounds()) { 1571 SkRect storage; 1572 if (this->quickReject(paint.computeFastBounds(oval, &storage), 1573 paint2EdgeType(&paint))) { 1574 return; 1575 } 1576 } 1577 1578 SkPath path; 1579 path.addOval(oval); 1580 this->drawPath(path, paint); 1581} 1582 1583void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 1584 SkScalar sweepAngle, bool useCenter, 1585 const SkPaint& paint) { 1586 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 1587 this->drawOval(oval, paint); 1588 } else { 1589 SkPath path; 1590 if (useCenter) { 1591 path.moveTo(oval.centerX(), oval.centerY()); 1592 } 1593 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 1594 if (useCenter) { 1595 path.close(); 1596 } 1597 this->drawPath(path, paint); 1598 } 1599} 1600 1601void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 1602 const SkPath& path, SkScalar hOffset, 1603 SkScalar vOffset, const SkPaint& paint) { 1604 SkMatrix matrix; 1605 1606 matrix.setTranslate(hOffset, vOffset); 1607 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 1608} 1609 1610/////////////////////////////////////////////////////////////////////////////// 1611 1612void SkCanvas::drawPicture(SkPicture& picture) { 1613 int saveCount = save(); 1614 picture.draw(this); 1615 restoreToCount(saveCount); 1616} 1617 1618/////////////////////////////////////////////////////////////////////////////// 1619/////////////////////////////////////////////////////////////////////////////// 1620 1621SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 1622 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); 1623 1624 SkASSERT(canvas); 1625 1626 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 1627 fDone = !fImpl->next(); 1628} 1629 1630SkCanvas::LayerIter::~LayerIter() { 1631 fImpl->~SkDrawIter(); 1632} 1633 1634void SkCanvas::LayerIter::next() { 1635 fDone = !fImpl->next(); 1636} 1637 1638SkDevice* SkCanvas::LayerIter::device() const { 1639 return fImpl->getDevice(); 1640} 1641 1642const SkMatrix& SkCanvas::LayerIter::matrix() const { 1643 return fImpl->getMatrix(); 1644} 1645 1646const SkPaint& SkCanvas::LayerIter::paint() const { 1647 const SkPaint* paint = fImpl->getPaint(); 1648 if (NULL == paint) { 1649 paint = &fDefaultPaint; 1650 } 1651 return *paint; 1652} 1653 1654const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 1655int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 1656int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 1657