SkCanvas.cpp revision d58a1cd00b969a7755c375f55cf80f4d49d3047b
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 408 fMCRec = (MCRec*)fMCStack.push_back(); 409 new (fMCRec) MCRec(NULL, 0); 410 411 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL)); 412 fMCRec->fTopLayer = fMCRec->fLayer; 413 fMCRec->fNext = NULL; 414 415 fExternalMatrix.reset(); 416 fExternalInverse.reset(); 417 fUseExternalMatrix = false; 418 419 return this->setDevice(device); 420} 421 422SkCanvas::SkCanvas() 423: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 424 inc_canvas(); 425 426 this->init(NULL); 427} 428 429SkCanvas::SkCanvas(SkDevice* device) 430 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 431 inc_canvas(); 432 433 this->init(device); 434} 435 436SkCanvas::SkCanvas(const SkBitmap& bitmap) 437 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 438 inc_canvas(); 439 440 this->init(SkNEW_ARGS(SkDevice, (bitmap)))->unref(); 441} 442 443SkCanvas::~SkCanvas() { 444 // free up the contents of our deque 445 this->restoreToCount(1); // restore everything but the last 446 this->internalRestore(); // restore the last, since we're going away 447 448 SkSafeUnref(fBounder); 449 450 dec_canvas(); 451} 452 453SkBounder* SkCanvas::setBounder(SkBounder* bounder) { 454 SkRefCnt_SafeAssign(fBounder, bounder); 455 return bounder; 456} 457 458SkDrawFilter* SkCanvas::getDrawFilter() const { 459 return fMCRec->fFilter; 460} 461 462SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) { 463 SkRefCnt_SafeAssign(fMCRec->fFilter, filter); 464 return filter; 465} 466 467/////////////////////////////////////////////////////////////////////////////// 468 469SkISize SkCanvas::getDeviceSize() const { 470 SkDevice* d = this->getDevice(); 471 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0); 472} 473 474SkDevice* SkCanvas::getDevice() const { 475 // return root device 476 SkDeque::F2BIter iter(fMCStack); 477 MCRec* rec = (MCRec*)iter.next(); 478 SkASSERT(rec && rec->fLayer); 479 return rec->fLayer->fDevice; 480} 481 482SkDevice* SkCanvas::getTopDevice() const { 483 return fMCRec->fTopLayer->fDevice; 484} 485 486SkDevice* SkCanvas::setDevice(SkDevice* device) { 487 // return root device 488 SkDeque::F2BIter iter(fMCStack); 489 MCRec* rec = (MCRec*)iter.next(); 490 SkASSERT(rec && rec->fLayer); 491 SkDevice* rootDevice = rec->fLayer->fDevice; 492 493 if (rootDevice == device) { 494 return device; 495 } 496 497 /* Notify the devices that they are going in/out of scope, so they can do 498 things like lock/unlock their pixels, etc. 499 */ 500 if (device) { 501 device->lockPixels(); 502 } 503 if (rootDevice) { 504 rootDevice->unlockPixels(); 505 } 506 507 SkRefCnt_SafeAssign(rec->fLayer->fDevice, device); 508 rootDevice = device; 509 510 fDeviceCMDirty = true; 511 512 /* Now we update our initial region to have the bounds of the new device, 513 and then intersect all of the clips in our stack with these bounds, 514 to ensure that we can't draw outside of the device's bounds (and trash 515 memory). 516 517 NOTE: this is only a partial-fix, since if the new device is larger than 518 the previous one, we don't know how to "enlarge" the clips in our stack, 519 so drawing may be artificially restricted. Without keeping a history of 520 all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly 521 reconstruct the correct clips, so this approximation will have to do. 522 The caller really needs to restore() back to the base if they want to 523 accurately take advantage of the new device bounds. 524 */ 525 526 if (NULL == device) { 527 rec->fRasterClip->setEmpty(); 528 while ((rec = (MCRec*)iter.next()) != NULL) { 529 (void)rec->fRasterClip->setEmpty(); 530 } 531 fClipStack.reset(); 532 } else { 533 // compute our total bounds for all devices 534 SkIRect bounds; 535 536 bounds.set(0, 0, device->width(), device->height()); 537 538 // now jam our 1st clip to be bounds, and intersect the rest with that 539 rec->fRasterClip->setRect(bounds); 540 while ((rec = (MCRec*)iter.next()) != NULL) { 541 (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op); 542 } 543 } 544 return device; 545} 546 547SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) { 548 SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap))); 549 device->unref(); 550 return device; 551} 552 553bool SkCanvas::readPixels(SkBitmap* bitmap, 554 int x, int y, 555 Config8888 config8888) { 556 SkDevice* device = this->getDevice(); 557 if (!device) { 558 return false; 559 } 560 return device->readPixels(bitmap, x, y, config8888); 561} 562 563bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) { 564 SkDevice* device = this->getDevice(); 565 566 SkIRect bounds; 567 bounds.set(0, 0, device->width(), device->height()); 568 if (!bounds.intersect(srcRect)) { 569 return false; 570 } 571 572 SkBitmap tmp; 573 tmp.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(), 574 bounds.height()); 575 if (this->readPixels(&tmp, bounds.fLeft, bounds.fTop)) { 576 bitmap->swap(tmp); 577 return true; 578 } else { 579 return false; 580 } 581} 582 583void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y, 584 Config8888 config8888) { 585 SkDevice* device = this->getDevice(); 586 if (device) { 587 device->writePixels(bitmap, x, y, config8888); 588 } 589} 590 591////////////////////////////////////////////////////////////////////////////// 592 593void SkCanvas::updateDeviceCMCache() { 594 if (fDeviceCMDirty) { 595 const SkMatrix& totalMatrix = this->getTotalMatrix(); 596 const SkRasterClip& totalClip = *fMCRec->fRasterClip; 597 DeviceCM* layer = fMCRec->fTopLayer; 598 599 if (NULL == layer->fNext) { // only one layer 600 layer->updateMC(totalMatrix, totalClip, fClipStack, NULL); 601 if (fUseExternalMatrix) { 602 layer->updateExternalMatrix(fExternalMatrix, 603 fExternalInverse); 604 } 605 } else { 606 SkRasterClip clip(totalClip); 607 do { 608 layer->updateMC(totalMatrix, clip, fClipStack, &clip); 609 if (fUseExternalMatrix) { 610 layer->updateExternalMatrix(fExternalMatrix, 611 fExternalInverse); 612 } 613 } while ((layer = layer->fNext) != NULL); 614 } 615 fDeviceCMDirty = false; 616 } 617} 618 619void SkCanvas::prepareForDeviceDraw(SkDevice* device, const SkMatrix& matrix, 620 const SkRegion& clip, 621 const SkClipStack& clipStack) { 622 SkASSERT(device); 623 if (fLastDeviceToGainFocus != device) { 624 device->gainFocus(this, matrix, clip, clipStack); 625 fLastDeviceToGainFocus = device; 626 } 627} 628 629/////////////////////////////////////////////////////////////////////////////// 630 631int SkCanvas::internalSave(SaveFlags flags) { 632 int saveCount = this->getSaveCount(); // record this before the actual save 633 634 MCRec* newTop = (MCRec*)fMCStack.push_back(); 635 new (newTop) MCRec(fMCRec, flags); // balanced in restore() 636 637 newTop->fNext = fMCRec; 638 fMCRec = newTop; 639 640 fClipStack.save(); 641 SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1); 642 643 return saveCount; 644} 645 646int SkCanvas::save(SaveFlags flags) { 647 // call shared impl 648 return this->internalSave(flags); 649} 650 651#define C32MASK (1 << SkBitmap::kARGB_8888_Config) 652#define C16MASK (1 << SkBitmap::kRGB_565_Config) 653#define C8MASK (1 << SkBitmap::kA8_Config) 654 655static SkBitmap::Config resolve_config(SkCanvas* canvas, 656 const SkIRect& bounds, 657 SkCanvas::SaveFlags flags, 658 bool* isOpaque) { 659 *isOpaque = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) == 0; 660 661#if 0 662 // loop through and union all the configs we may draw into 663 uint32_t configMask = 0; 664 for (int i = canvas->countLayerDevices() - 1; i >= 0; --i) 665 { 666 SkDevice* device = canvas->getLayerDevice(i); 667 if (device->intersects(bounds)) 668 configMask |= 1 << device->config(); 669 } 670 671 // if the caller wants alpha or fullcolor, we can't return 565 672 if (flags & (SkCanvas::kFullColorLayer_SaveFlag | 673 SkCanvas::kHasAlphaLayer_SaveFlag)) 674 configMask &= ~C16MASK; 675 676 switch (configMask) { 677 case C8MASK: // if we only have A8, return that 678 return SkBitmap::kA8_Config; 679 680 case C16MASK: // if we only have 565, return that 681 return SkBitmap::kRGB_565_Config; 682 683 default: 684 return SkBitmap::kARGB_8888_Config; // default answer 685 } 686#else 687 return SkBitmap::kARGB_8888_Config; // default answer 688#endif 689} 690 691static bool bounds_affects_clip(SkCanvas::SaveFlags flags) { 692 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0; 693} 694 695int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, 696 SaveFlags flags) { 697 // do this before we create the layer. We don't call the public save() since 698 // that would invoke a possibly overridden virtual 699 int count = this->internalSave(flags); 700 701 fDeviceCMDirty = true; 702 703 SkIRect clipBounds; 704 if (!this->getClipDeviceBounds(&clipBounds)) { 705 return count; 706 } 707 708 SkIRect ir; 709 if (NULL != bounds) { 710 SkRect r; 711 712 this->getTotalMatrix().mapRect(&r, *bounds); 713 r.roundOut(&ir); 714 // early exit if the layer's bounds are clipped out 715 if (!ir.intersect(clipBounds)) { 716 if (bounds_affects_clip(flags)) { 717 fMCRec->fRasterClip->setEmpty(); 718 } 719 return count; 720 } 721 } else { // no user bounds, so just use the clip 722 ir = clipBounds; 723 } 724 725 fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op); 726 // early exit if the clip is now empty 727 if (bounds_affects_clip(flags) && 728 !fMCRec->fRasterClip->op(ir, SkRegion::kIntersect_Op)) { 729 return count; 730 } 731 732 bool isOpaque; 733 SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque); 734 735 SkDevice* device = this->createLayerDevice(config, ir.width(), ir.height(), 736 isOpaque); 737 if (NULL == device) { 738 SkDebugf("Unable to create device for layer."); 739 return count; 740 } 741 742 device->setOrigin(ir.fLeft, ir.fTop); 743 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint)); 744 device->unref(); 745 746 layer->fNext = fMCRec->fTopLayer; 747 fMCRec->fLayer = layer; 748 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer 749 750 return count; 751} 752 753int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha, 754 SaveFlags flags) { 755 if (0xFF == alpha) { 756 return this->saveLayer(bounds, NULL, flags); 757 } else { 758 SkPaint tmpPaint; 759 tmpPaint.setAlpha(alpha); 760 return this->saveLayer(bounds, &tmpPaint, flags); 761 } 762} 763 764void SkCanvas::restore() { 765 // check for underflow 766 if (fMCStack.count() > 1) { 767 this->internalRestore(); 768 } 769} 770 771void SkCanvas::internalRestore() { 772 SkASSERT(fMCStack.count() != 0); 773 774 fDeviceCMDirty = true; 775 fLocalBoundsCompareTypeDirty = true; 776 fLocalBoundsCompareTypeDirtyBW = true; 777 778 fClipStack.restore(); 779 // reserve our layer (if any) 780 DeviceCM* layer = fMCRec->fLayer; // may be null 781 // now detach it from fMCRec so we can pop(). Gets freed after its drawn 782 fMCRec->fLayer = NULL; 783 784 // now do the normal restore() 785 fMCRec->~MCRec(); // balanced in save() 786 fMCStack.pop_back(); 787 fMCRec = (MCRec*)fMCStack.back(); 788 789 /* Time to draw the layer's offscreen. We can't call the public drawSprite, 790 since if we're being recorded, we don't want to record this (the 791 recorder will have already recorded the restore). 792 */ 793 if (NULL != layer) { 794 if (layer->fNext) { 795 const SkIPoint& origin = layer->fDevice->getOrigin(); 796 this->drawDevice(layer->fDevice, origin.x(), origin.y(), 797 layer->fPaint); 798 // reset this, since drawDevice will have set it to true 799 fDeviceCMDirty = true; 800 } 801 SkDELETE(layer); 802 } 803 804 SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1); 805} 806 807int SkCanvas::getSaveCount() const { 808 return fMCStack.count(); 809} 810 811void SkCanvas::restoreToCount(int count) { 812 // sanity check 813 if (count < 1) { 814 count = 1; 815 } 816 while (fMCStack.count() > count) { 817 this->restore(); 818 } 819} 820 821///////////////////////////////////////////////////////////////////////////// 822 823// can't draw it if its empty, or its too big for a fixed-point width or height 824static bool reject_bitmap(const SkBitmap& bitmap) { 825 return bitmap.width() <= 0 || bitmap.height() <= 0 826#ifndef SK_ALLOW_OVER_32K_BITMAPS 827 || bitmap.width() > 32767 || bitmap.height() > 32767 828#endif 829 ; 830} 831 832void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect, 833 const SkMatrix& matrix, const SkPaint* paint) { 834 if (reject_bitmap(bitmap)) { 835 return; 836 } 837 838 SkLazyPaint lazy; 839 if (NULL == paint) { 840 paint = lazy.init(); 841 } 842 this->commonDrawBitmap(bitmap, srcRect, matrix, *paint); 843} 844 845void SkCanvas::drawDevice(SkDevice* device, int x, int y, 846 const SkPaint* paint) { 847 SkPaint tmp; 848 if (NULL == paint) { 849 tmp.setDither(true); 850 paint = &tmp; 851 } 852 853 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type) 854 while (iter.next()) { 855 iter.fDevice->drawDevice(iter, device, x - iter.getX(), y - iter.getY(), 856 looper.paint()); 857 } 858 LOOPER_END 859} 860 861///////////////////////////////////////////////////////////////////////////// 862 863bool SkCanvas::translate(SkScalar dx, SkScalar dy) { 864 fDeviceCMDirty = true; 865 fLocalBoundsCompareTypeDirty = true; 866 fLocalBoundsCompareTypeDirtyBW = true; 867 return fMCRec->fMatrix->preTranslate(dx, dy); 868} 869 870bool SkCanvas::scale(SkScalar sx, SkScalar sy) { 871 fDeviceCMDirty = true; 872 fLocalBoundsCompareTypeDirty = true; 873 fLocalBoundsCompareTypeDirtyBW = true; 874 return fMCRec->fMatrix->preScale(sx, sy); 875} 876 877bool SkCanvas::rotate(SkScalar degrees) { 878 fDeviceCMDirty = true; 879 fLocalBoundsCompareTypeDirty = true; 880 fLocalBoundsCompareTypeDirtyBW = true; 881 return fMCRec->fMatrix->preRotate(degrees); 882} 883 884bool SkCanvas::skew(SkScalar sx, SkScalar sy) { 885 fDeviceCMDirty = true; 886 fLocalBoundsCompareTypeDirty = true; 887 fLocalBoundsCompareTypeDirtyBW = true; 888 return fMCRec->fMatrix->preSkew(sx, sy); 889} 890 891bool SkCanvas::concat(const SkMatrix& matrix) { 892 fDeviceCMDirty = true; 893 fLocalBoundsCompareTypeDirty = true; 894 fLocalBoundsCompareTypeDirtyBW = true; 895 return fMCRec->fMatrix->preConcat(matrix); 896} 897 898void SkCanvas::setMatrix(const SkMatrix& matrix) { 899 fDeviceCMDirty = true; 900 fLocalBoundsCompareTypeDirty = true; 901 fLocalBoundsCompareTypeDirtyBW = true; 902 *fMCRec->fMatrix = matrix; 903} 904 905// this is not virtual, so it must call a virtual method so that subclasses 906// will see its action 907void SkCanvas::resetMatrix() { 908 SkMatrix matrix; 909 910 matrix.reset(); 911 this->setMatrix(matrix); 912} 913 914////////////////////////////////////////////////////////////////////////////// 915 916bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 917 AutoValidateClip avc(this); 918 919 fDeviceCMDirty = true; 920 fLocalBoundsCompareTypeDirty = true; 921 fLocalBoundsCompareTypeDirtyBW = true; 922 923 if (fMCRec->fMatrix->rectStaysRect()) { 924 // for these simpler matrices, we can stay a rect ever after applying 925 // the matrix. This means we don't have to a) make a path, and b) tell 926 // the region code to scan-convert the path, only to discover that it 927 // is really just a rect. 928 SkRect r; 929 930 fMCRec->fMatrix->mapRect(&r, rect); 931 fClipStack.clipDevRect(r, op, doAA); 932 return fMCRec->fRasterClip->op(r, op, doAA); 933 } else { 934 // since we're rotate or some such thing, we convert the rect to a path 935 // and clip against that, since it can handle any matrix. However, to 936 // avoid recursion in the case where we are subclassed (e.g. Pictures) 937 // we explicitly call "our" version of clipPath. 938 SkPath path; 939 940 path.addRect(rect); 941 return this->SkCanvas::clipPath(path, op, doAA); 942 } 943} 944 945static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip, 946 const SkPath& devPath, SkRegion::Op op, bool doAA) { 947 // base is used to limit the size (and therefore memory allocation) of the 948 // region that results from scan converting devPath. 949 SkRegion base; 950 951 if (SkRegion::kIntersect_Op == op) { 952 // since we are intersect, we can do better (tighter) with currRgn's 953 // bounds, than just using the device. However, if currRgn is complex, 954 // our region blitter may hork, so we do that case in two steps. 955 if (currClip->isRect()) { 956 return currClip->setPath(devPath, *currClip, doAA); 957 } else { 958 base.setRect(currClip->getBounds()); 959 SkRasterClip clip; 960 clip.setPath(devPath, base, doAA); 961 return currClip->op(clip, op); 962 } 963 } else { 964 const SkBitmap& bm = canvas->getDevice()->accessBitmap(false); 965 base.setRect(0, 0, bm.width(), bm.height()); 966 967 if (SkRegion::kReplace_Op == op) { 968 return currClip->setPath(devPath, base, doAA); 969 } else { 970 SkRasterClip clip; 971 clip.setPath(devPath, base, doAA); 972 return currClip->op(clip, op); 973 } 974 } 975} 976 977bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 978 AutoValidateClip avc(this); 979 980 fDeviceCMDirty = true; 981 fLocalBoundsCompareTypeDirty = true; 982 fLocalBoundsCompareTypeDirtyBW = true; 983 984 SkPath devPath; 985 path.transform(*fMCRec->fMatrix, &devPath); 986 987 // Check if the transfomation, or the original path itself 988 // made us empty. Note this can also happen if we contained NaN 989 // values. computing the bounds detects this, and will set our 990 // bounds to empty if that is the case. (see SkRect::set(pts, count)) 991 if (devPath.getBounds().isEmpty()) { 992 // resetting the path will remove any NaN or other wanky values 993 // that might upset our scan converter. 994 devPath.reset(); 995 } 996 997 // if we called path.swap() we could avoid a deep copy of this path 998 fClipStack.clipDevPath(devPath, op, doAA); 999 1000 return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA); 1001} 1002 1003bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1004 AutoValidateClip avc(this); 1005 1006 fDeviceCMDirty = true; 1007 fLocalBoundsCompareTypeDirty = true; 1008 fLocalBoundsCompareTypeDirtyBW = true; 1009 1010 // todo: signal fClipStack that we have a region, and therefore (I guess) 1011 // we have to ignore it, and use the region directly? 1012 fClipStack.clipDevRect(rgn.getBounds()); 1013 1014 return fMCRec->fRasterClip->op(rgn, op); 1015} 1016 1017#ifdef SK_DEBUG 1018void SkCanvas::validateClip() const { 1019 // construct clipRgn from the clipstack 1020 const SkDevice* device = this->getDevice(); 1021 SkIRect ir; 1022 ir.set(0, 0, device->width(), device->height()); 1023 SkRasterClip tmpClip(ir); 1024 1025 SkClipStack::B2FIter iter(fClipStack); 1026 const SkClipStack::B2FIter::Clip* clip; 1027 while ((clip = iter.next()) != NULL) { 1028 if (clip->fPath) { 1029 clipPathHelper(this, &tmpClip, *clip->fPath, clip->fOp, clip->fDoAA); 1030 } else if (clip->fRect) { 1031 clip->fRect->round(&ir); 1032 tmpClip.op(ir, clip->fOp); 1033 } else { 1034 tmpClip.setEmpty(); 1035 } 1036 } 1037 1038#if 0 // enable this locally for testing 1039 // now compare against the current rgn 1040 const SkRegion& rgn = this->getTotalClip(); 1041 SkASSERT(rgn == tmpClip); 1042#endif 1043} 1044#endif 1045 1046/////////////////////////////////////////////////////////////////////////////// 1047 1048void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const { 1049 SkRect r; 1050 SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType : 1051 fLocalBoundsCompareTypeBW; 1052 1053 if (!this->getClipBounds(&r, et)) { 1054 rCompare.setEmpty(); 1055 } else { 1056 rCompare.set(SkScalarToCompareType(r.fLeft), 1057 SkScalarToCompareType(r.fTop), 1058 SkScalarToCompareType(r.fRight), 1059 SkScalarToCompareType(r.fBottom)); 1060 } 1061} 1062 1063/* current impl ignores edgetype, and relies on 1064 getLocalClipBoundsCompareType(), which always returns a value assuming 1065 antialiasing (worst case) 1066 */ 1067bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const { 1068 1069 if (!rect.hasValidCoordinates()) 1070 return true; 1071 1072 if (fMCRec->fRasterClip->isEmpty()) { 1073 return true; 1074 } 1075 1076 if (fMCRec->fMatrix->hasPerspective()) { 1077 SkRect dst; 1078 fMCRec->fMatrix->mapRect(&dst, rect); 1079 SkIRect idst; 1080 dst.roundOut(&idst); 1081 return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds()); 1082 } else { 1083 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et); 1084 1085 // for speed, do the most likely reject compares first 1086 SkScalarCompareType userT = SkScalarToCompareType(rect.fTop); 1087 SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom); 1088 if (userT >= clipR.fBottom || userB <= clipR.fTop) { 1089 return true; 1090 } 1091 SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft); 1092 SkScalarCompareType userR = SkScalarToCompareType(rect.fRight); 1093 if (userL >= clipR.fRight || userR <= clipR.fLeft) { 1094 return true; 1095 } 1096 return false; 1097 } 1098} 1099 1100bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const { 1101 return path.isEmpty() || this->quickReject(path.getBounds(), et); 1102} 1103 1104bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const { 1105 /* current impl ignores edgetype, and relies on 1106 getLocalClipBoundsCompareType(), which always returns a value assuming 1107 antialiasing (worst case) 1108 */ 1109 1110 if (fMCRec->fRasterClip->isEmpty()) { 1111 return true; 1112 } 1113 1114 SkScalarCompareType userT = SkScalarToCompareType(top); 1115 SkScalarCompareType userB = SkScalarToCompareType(bottom); 1116 1117 // check for invalid user Y coordinates (i.e. empty) 1118 // reed: why do we need to do this check, since it slows us down? 1119 if (userT >= userB) { 1120 return true; 1121 } 1122 1123 // check if we are above or below the local clip bounds 1124 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(); 1125 return userT >= clipR.fBottom || userB <= clipR.fTop; 1126} 1127 1128bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const { 1129 SkIRect ibounds; 1130 if (!getClipDeviceBounds(&ibounds)) { 1131 return false; 1132 } 1133 1134 SkMatrix inverse; 1135 // if we can't invert the CTM, we can't return local clip bounds 1136 if (!fMCRec->fMatrix->invert(&inverse)) { 1137 if (bounds) { 1138 bounds->setEmpty(); 1139 } 1140 return false; 1141 } 1142 1143 if (NULL != bounds) { 1144 SkRect r; 1145 // adjust it outwards if we are antialiasing 1146 int inset = (kAA_EdgeType == et); 1147 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset, 1148 ibounds.fRight + inset, ibounds.fBottom + inset); 1149 inverse.mapRect(bounds, r); 1150 } 1151 return true; 1152} 1153 1154bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const { 1155 const SkRasterClip& clip = *fMCRec->fRasterClip; 1156 if (clip.isEmpty()) { 1157 if (bounds) { 1158 bounds->setEmpty(); 1159 } 1160 return false; 1161 } 1162 1163 if (NULL != bounds) { 1164 *bounds = clip.getBounds(); 1165 } 1166 return true; 1167} 1168 1169const SkMatrix& SkCanvas::getTotalMatrix() const { 1170 return *fMCRec->fMatrix; 1171} 1172 1173SkCanvas::ClipType SkCanvas::getClipType() const { 1174 if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType; 1175 if (fMCRec->fRasterClip->isRect()) return kRect_ClipType; 1176 return kComplex_ClipType; 1177} 1178 1179const SkRegion& SkCanvas::getTotalClip() const { 1180 return fMCRec->fRasterClip->forceGetBW(); 1181} 1182 1183const SkClipStack& SkCanvas::getTotalClipStack() const { 1184 return fClipStack; 1185} 1186 1187void SkCanvas::setExternalMatrix(const SkMatrix* matrix) { 1188 if (NULL == matrix || matrix->isIdentity()) { 1189 if (fUseExternalMatrix) { 1190 fDeviceCMDirty = true; 1191 } 1192 fUseExternalMatrix = false; 1193 } else { 1194 fUseExternalMatrix = true; 1195 fDeviceCMDirty = true; // |= (fExternalMatrix != *matrix) 1196 1197 fExternalMatrix = *matrix; 1198 matrix->invert(&fExternalInverse); 1199 } 1200} 1201 1202SkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config, 1203 int width, int height, 1204 bool isOpaque) { 1205 SkDevice* device = this->getTopDevice(); 1206 if (device) { 1207 return device->createCompatibleDeviceForSaveLayer(config, width, height, 1208 isOpaque); 1209 } else { 1210 return NULL; 1211 } 1212} 1213 1214SkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config, 1215 int width, int height, 1216 bool isOpaque) { 1217 SkDevice* device = this->getDevice(); 1218 if (device) { 1219 return device->createCompatibleDevice(config, width, height, isOpaque); 1220 } else { 1221 return NULL; 1222 } 1223} 1224 1225 1226////////////////////////////////////////////////////////////////////////////// 1227// These are the virtual drawing methods 1228////////////////////////////////////////////////////////////////////////////// 1229 1230void SkCanvas::clear(SkColor color) { 1231 SkDrawIter iter(this); 1232 1233 while (iter.next()) { 1234 iter.fDevice->clear(color); 1235 } 1236} 1237 1238void SkCanvas::drawPaint(const SkPaint& paint) { 1239 this->internalDrawPaint(paint); 1240} 1241 1242void SkCanvas::internalDrawPaint(const SkPaint& paint) { 1243 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type) 1244 1245 while (iter.next()) { 1246 iter.fDevice->drawPaint(iter, looper.paint()); 1247 } 1248 1249 LOOPER_END 1250} 1251 1252void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1253 const SkPaint& paint) { 1254 if ((long)count <= 0) { 1255 return; 1256 } 1257 1258 SkASSERT(pts != NULL); 1259 1260 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type) 1261 1262 while (iter.next()) { 1263 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); 1264 } 1265 1266 LOOPER_END 1267} 1268 1269void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1270 if (paint.canComputeFastBounds()) { 1271 SkRect storage; 1272 if (this->quickReject(paint.computeFastBounds(r, &storage), 1273 paint2EdgeType(&paint))) { 1274 return; 1275 } 1276 } 1277 1278 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type) 1279 1280 while (iter.next()) { 1281 iter.fDevice->drawRect(iter, r, looper.paint()); 1282 } 1283 1284 LOOPER_END 1285} 1286 1287void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 1288 if (!path.isInverseFillType() && paint.canComputeFastBounds()) { 1289 SkRect storage; 1290 const SkRect& bounds = path.getBounds(); 1291 if (this->quickReject(paint.computeFastBounds(bounds, &storage), 1292 paint2EdgeType(&paint))) { 1293 return; 1294 } 1295 } 1296 if (path.isEmpty()) { 1297 if (path.isInverseFillType()) { 1298 this->internalDrawPaint(paint); 1299 } 1300 return; 1301 } 1302 1303 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 1304 1305 while (iter.next()) { 1306 iter.fDevice->drawPath(iter, path, looper.paint()); 1307 } 1308 1309 LOOPER_END 1310} 1311 1312void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, 1313 const SkPaint* paint) { 1314 SkDEBUGCODE(bitmap.validate();) 1315 1316 if (NULL == paint || (paint->getMaskFilter() == NULL)) { 1317 SkRect fastBounds; 1318 fastBounds.set(x, y, 1319 x + SkIntToScalar(bitmap.width()), 1320 y + SkIntToScalar(bitmap.height())); 1321 if (this->quickReject(fastBounds, paint2EdgeType(paint))) { 1322 return; 1323 } 1324 } 1325 1326 SkMatrix matrix; 1327 matrix.setTranslate(x, y); 1328 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1329} 1330 1331// this one is non-virtual, so it can be called safely by other canvas apis 1332void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, 1333 const SkRect& dst, const SkPaint* paint) { 1334 if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) { 1335 return; 1336 } 1337 1338 // do this now, to avoid the cost of calling extract for RLE bitmaps 1339 if (this->quickReject(dst, paint2EdgeType(paint))) { 1340 return; 1341 } 1342 1343 const SkBitmap* bitmapPtr = &bitmap; 1344 1345 SkMatrix matrix; 1346 SkRect tmpSrc; 1347 if (src) { 1348 tmpSrc.set(*src); 1349 // if the extract process clipped off the top or left of the 1350 // original, we adjust for that here to get the position right. 1351 if (tmpSrc.fLeft > 0) { 1352 tmpSrc.fRight -= tmpSrc.fLeft; 1353 tmpSrc.fLeft = 0; 1354 } 1355 if (tmpSrc.fTop > 0) { 1356 tmpSrc.fBottom -= tmpSrc.fTop; 1357 tmpSrc.fTop = 0; 1358 } 1359 } else { 1360 tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()), 1361 SkIntToScalar(bitmap.height())); 1362 } 1363 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 1364 1365 // ensure that src is "valid" before we pass it to our internal routines 1366 // and to SkDevice. i.e. sure it is contained inside the original bitmap. 1367 SkIRect tmpISrc; 1368 if (src) { 1369 tmpISrc.set(0, 0, bitmap.width(), bitmap.height()); 1370 if (!tmpISrc.intersect(*src)) { 1371 return; 1372 } 1373 src = &tmpISrc; 1374 } 1375 this->internalDrawBitmap(*bitmapPtr, src, matrix, paint); 1376} 1377 1378void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, 1379 const SkRect& dst, const SkPaint* paint) { 1380 SkDEBUGCODE(bitmap.validate();) 1381 this->internalDrawBitmapRect(bitmap, src, dst, paint); 1382} 1383 1384void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 1385 const SkPaint* paint) { 1386 SkDEBUGCODE(bitmap.validate();) 1387 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1388} 1389 1390void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect, 1391 const SkMatrix& matrix, const SkPaint& paint) { 1392 SkDEBUGCODE(bitmap.validate();) 1393 1394 LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type) 1395 1396 while (iter.next()) { 1397 iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint()); 1398 } 1399 1400 LOOPER_END 1401} 1402 1403void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap, 1404 const SkIRect& center, const SkRect& dst, 1405 const SkPaint* paint) { 1406 const int32_t w = bitmap.width(); 1407 const int32_t h = bitmap.height(); 1408 1409 SkIRect c = center; 1410 // pin center to the bounds of the bitmap 1411 c.fLeft = SkMax32(0, center.fLeft); 1412 c.fTop = SkMax32(0, center.fTop); 1413 c.fRight = SkPin32(center.fRight, c.fLeft, w); 1414 c.fBottom = SkPin32(center.fBottom, c.fTop, h); 1415 1416 const int32_t srcX[4] = { 0, c.fLeft, c.fRight, w }; 1417 const int32_t srcY[4] = { 0, c.fTop, c.fBottom, h }; 1418 SkScalar dstX[4] = { 1419 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft), 1420 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight 1421 }; 1422 SkScalar dstY[4] = { 1423 dst.fTop, dst.fTop + SkIntToScalar(c.fTop), 1424 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom 1425 }; 1426 1427 if (dstX[1] > dstX[2]) { 1428 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width()); 1429 dstX[2] = dstX[1]; 1430 } 1431 1432 if (dstY[1] > dstY[2]) { 1433 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height()); 1434 dstY[2] = dstY[1]; 1435 } 1436 1437 SkIRect s; 1438 SkRect d; 1439 for (int y = 0; y < 3; y++) { 1440 s.fTop = srcY[y]; 1441 s.fBottom = srcY[y+1]; 1442 d.fTop = dstY[y]; 1443 d.fBottom = dstY[y+1]; 1444 for (int x = 0; x < 3; x++) { 1445 s.fLeft = srcX[x]; 1446 s.fRight = srcX[x+1]; 1447 d.fLeft = dstX[x]; 1448 d.fRight = dstX[x+1]; 1449 this->internalDrawBitmapRect(bitmap, &s, d, paint); 1450 } 1451 } 1452} 1453 1454void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 1455 const SkRect& dst, const SkPaint* paint) { 1456 SkDEBUGCODE(bitmap.validate();) 1457 1458 // Need a device entry-point, so gpu can use a mesh 1459 this->internalDrawBitmapNine(bitmap, center, dst, paint); 1460} 1461 1462void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, 1463 const SkPaint* paint) { 1464 SkDEBUGCODE(bitmap.validate();) 1465 1466 if (reject_bitmap(bitmap)) { 1467 return; 1468 } 1469 1470 SkPaint tmp; 1471 if (NULL == paint) { 1472 paint = &tmp; 1473 } 1474 1475 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type) 1476 1477 while (iter.next()) { 1478 iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(), 1479 looper.paint()); 1480 } 1481 LOOPER_END 1482} 1483 1484class SkDeviceFilteredPaint { 1485public: 1486 SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) { 1487 SkDevice::TextFlags flags; 1488 if (device->filterTextFlags(paint, &flags)) { 1489 SkPaint* newPaint = fLazy.set(paint); 1490 newPaint->setFlags(flags.fFlags); 1491 newPaint->setHinting(flags.fHinting); 1492 fPaint = newPaint; 1493 } else { 1494 fPaint = &paint; 1495 } 1496 } 1497 1498 const SkPaint& paint() const { return *fPaint; } 1499 1500private: 1501 const SkPaint* fPaint; 1502 SkLazyPaint fLazy; 1503}; 1504 1505void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, 1506 const SkRect& r, SkScalar textSize) { 1507 if (paint.getStyle() == SkPaint::kFill_Style) { 1508 draw.fDevice->drawRect(draw, r, paint); 1509 } else { 1510 SkPaint p(paint); 1511 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); 1512 draw.fDevice->drawRect(draw, r, p); 1513 } 1514} 1515 1516void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, 1517 const char text[], size_t byteLength, 1518 SkScalar x, SkScalar y) { 1519 SkASSERT(byteLength == 0 || text != NULL); 1520 1521 // nothing to draw 1522 if (text == NULL || byteLength == 0 || 1523 draw.fClip->isEmpty() || 1524 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 1525 return; 1526 } 1527 1528 SkScalar width = 0; 1529 SkPoint start; 1530 1531 start.set(0, 0); // to avoid warning 1532 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | 1533 SkPaint::kStrikeThruText_Flag)) { 1534 width = paint.measureText(text, byteLength); 1535 1536 SkScalar offsetX = 0; 1537 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 1538 offsetX = SkScalarHalf(width); 1539 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { 1540 offsetX = width; 1541 } 1542 start.set(x - offsetX, y); 1543 } 1544 1545 if (0 == width) { 1546 return; 1547 } 1548 1549 uint32_t flags = paint.getFlags(); 1550 1551 if (flags & (SkPaint::kUnderlineText_Flag | 1552 SkPaint::kStrikeThruText_Flag)) { 1553 SkScalar textSize = paint.getTextSize(); 1554 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 1555 SkRect r; 1556 1557 r.fLeft = start.fX; 1558 r.fRight = start.fX + width; 1559 1560 if (flags & SkPaint::kUnderlineText_Flag) { 1561 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, 1562 start.fY); 1563 r.fTop = offset; 1564 r.fBottom = offset + height; 1565 DrawRect(draw, paint, r, textSize); 1566 } 1567 if (flags & SkPaint::kStrikeThruText_Flag) { 1568 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, 1569 start.fY); 1570 r.fTop = offset; 1571 r.fBottom = offset + height; 1572 DrawRect(draw, paint, r, textSize); 1573 } 1574 } 1575} 1576 1577void SkCanvas::drawText(const void* text, size_t byteLength, 1578 SkScalar x, SkScalar y, const SkPaint& paint) { 1579 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1580 1581 while (iter.next()) { 1582 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1583 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 1584 DrawTextDecorations(iter, dfp.paint(), 1585 static_cast<const char*>(text), byteLength, x, y); 1586 } 1587 1588 LOOPER_END 1589} 1590 1591void SkCanvas::drawPosText(const void* text, size_t byteLength, 1592 const SkPoint pos[], const SkPaint& paint) { 1593 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1594 1595 while (iter.next()) { 1596 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1597 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 1598 dfp.paint()); 1599 } 1600 1601 LOOPER_END 1602} 1603 1604void SkCanvas::drawPosTextH(const void* text, size_t byteLength, 1605 const SkScalar xpos[], SkScalar constY, 1606 const SkPaint& paint) { 1607 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1608 1609 while (iter.next()) { 1610 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1611 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 1612 dfp.paint()); 1613 } 1614 1615 LOOPER_END 1616} 1617 1618void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, 1619 const SkPath& path, const SkMatrix* matrix, 1620 const SkPaint& paint) { 1621 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1622 1623 while (iter.next()) { 1624 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 1625 matrix, looper.paint()); 1626 } 1627 1628 LOOPER_END 1629} 1630 1631#ifdef SK_BUILD_FOR_ANDROID 1632void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength, 1633 const SkPoint pos[], const SkPaint& paint, 1634 const SkPath& path, const SkMatrix* matrix) { 1635 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1636 1637 while (iter.next()) { 1638 iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos, 1639 looper.paint(), path, matrix); 1640 } 1641 1642 LOOPER_END 1643} 1644#endif 1645 1646void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 1647 const SkPoint verts[], const SkPoint texs[], 1648 const SkColor colors[], SkXfermode* xmode, 1649 const uint16_t indices[], int indexCount, 1650 const SkPaint& paint) { 1651 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 1652 1653 while (iter.next()) { 1654 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 1655 colors, xmode, indices, indexCount, 1656 looper.paint()); 1657 } 1658 1659 LOOPER_END 1660} 1661 1662void SkCanvas::drawData(const void* data, size_t length) { 1663 // do nothing. Subclasses may do something with the data 1664} 1665 1666////////////////////////////////////////////////////////////////////////////// 1667// These methods are NOT virtual, and therefore must call back into virtual 1668// methods, rather than actually drawing themselves. 1669////////////////////////////////////////////////////////////////////////////// 1670 1671void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 1672 SkXfermode::Mode mode) { 1673 SkPaint paint; 1674 1675 paint.setARGB(a, r, g, b); 1676 if (SkXfermode::kSrcOver_Mode != mode) { 1677 paint.setXfermodeMode(mode); 1678 } 1679 this->drawPaint(paint); 1680} 1681 1682void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 1683 SkPaint paint; 1684 1685 paint.setColor(c); 1686 if (SkXfermode::kSrcOver_Mode != mode) { 1687 paint.setXfermodeMode(mode); 1688 } 1689 this->drawPaint(paint); 1690} 1691 1692void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 1693 SkPoint pt; 1694 1695 pt.set(x, y); 1696 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1697} 1698 1699void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 1700 SkPoint pt; 1701 SkPaint paint; 1702 1703 pt.set(x, y); 1704 paint.setColor(color); 1705 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1706} 1707 1708void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 1709 const SkPaint& paint) { 1710 SkPoint pts[2]; 1711 1712 pts[0].set(x0, y0); 1713 pts[1].set(x1, y1); 1714 this->drawPoints(kLines_PointMode, 2, pts, paint); 1715} 1716 1717void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 1718 SkScalar right, SkScalar bottom, 1719 const SkPaint& paint) { 1720 SkRect r; 1721 1722 r.set(left, top, right, bottom); 1723 this->drawRect(r, paint); 1724} 1725 1726void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 1727 const SkPaint& paint) { 1728 if (radius < 0) { 1729 radius = 0; 1730 } 1731 1732 SkRect r; 1733 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 1734 1735 if (paint.canComputeFastBounds()) { 1736 SkRect storage; 1737 if (this->quickReject(paint.computeFastBounds(r, &storage), 1738 paint2EdgeType(&paint))) { 1739 return; 1740 } 1741 } 1742 1743 SkPath path; 1744 path.addOval(r); 1745 this->drawPath(path, paint); 1746} 1747 1748void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 1749 const SkPaint& paint) { 1750 if (rx > 0 && ry > 0) { 1751 if (paint.canComputeFastBounds()) { 1752 SkRect storage; 1753 if (this->quickReject(paint.computeFastBounds(r, &storage), 1754 paint2EdgeType(&paint))) { 1755 return; 1756 } 1757 } 1758 1759 SkPath path; 1760 path.addRoundRect(r, rx, ry, SkPath::kCW_Direction); 1761 this->drawPath(path, paint); 1762 } else { 1763 this->drawRect(r, paint); 1764 } 1765} 1766 1767void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1768 if (paint.canComputeFastBounds()) { 1769 SkRect storage; 1770 if (this->quickReject(paint.computeFastBounds(oval, &storage), 1771 paint2EdgeType(&paint))) { 1772 return; 1773 } 1774 } 1775 1776 SkPath path; 1777 path.addOval(oval); 1778 this->drawPath(path, paint); 1779} 1780 1781void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 1782 SkScalar sweepAngle, bool useCenter, 1783 const SkPaint& paint) { 1784 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 1785 this->drawOval(oval, paint); 1786 } else { 1787 SkPath path; 1788 if (useCenter) { 1789 path.moveTo(oval.centerX(), oval.centerY()); 1790 } 1791 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 1792 if (useCenter) { 1793 path.close(); 1794 } 1795 this->drawPath(path, paint); 1796 } 1797} 1798 1799void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 1800 const SkPath& path, SkScalar hOffset, 1801 SkScalar vOffset, const SkPaint& paint) { 1802 SkMatrix matrix; 1803 1804 matrix.setTranslate(hOffset, vOffset); 1805 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 1806} 1807 1808/////////////////////////////////////////////////////////////////////////////// 1809 1810void SkCanvas::drawPicture(SkPicture& picture) { 1811 int saveCount = save(); 1812 picture.draw(this); 1813 restoreToCount(saveCount); 1814} 1815 1816/////////////////////////////////////////////////////////////////////////////// 1817/////////////////////////////////////////////////////////////////////////////// 1818 1819SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 1820 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); 1821 1822 SkASSERT(canvas); 1823 1824 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 1825 fDone = !fImpl->next(); 1826} 1827 1828SkCanvas::LayerIter::~LayerIter() { 1829 fImpl->~SkDrawIter(); 1830} 1831 1832void SkCanvas::LayerIter::next() { 1833 fDone = !fImpl->next(); 1834} 1835 1836SkDevice* SkCanvas::LayerIter::device() const { 1837 return fImpl->getDevice(); 1838} 1839 1840const SkMatrix& SkCanvas::LayerIter::matrix() const { 1841 return fImpl->getMatrix(); 1842} 1843 1844const SkPaint& SkCanvas::LayerIter::paint() const { 1845 const SkPaint* paint = fImpl->getPaint(); 1846 if (NULL == paint) { 1847 paint = &fDefaultPaint; 1848 } 1849 return *paint; 1850} 1851 1852const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 1853int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 1854int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 1855