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