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