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