SkCanvas.cpp revision a907ac3e3e3458fbb5d673c3feafb31fd7647b38
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 const DeviceCM* rec = fCurrLayer; 236 if (rec && rec->fDevice) { 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 710bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, 711 SkIRect* intersection) { 712 SkIRect clipBounds; 713 if (!this->getClipDeviceBounds(&clipBounds)) { 714 return false; 715 } 716 SkIRect ir; 717 if (NULL != bounds) { 718 SkRect r; 719 720 this->getTotalMatrix().mapRect(&r, *bounds); 721 r.roundOut(&ir); 722 // early exit if the layer's bounds are clipped out 723 if (!ir.intersect(clipBounds)) { 724 if (bounds_affects_clip(flags)) { 725 fMCRec->fRasterClip->setEmpty(); 726 } 727 return false; 728 } 729 } else { // no user bounds, so just use the clip 730 ir = clipBounds; 731 } 732 733 fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op); 734 735 // early exit if the clip is now empty 736 if (bounds_affects_clip(flags) && 737 !fMCRec->fRasterClip->op(ir, SkRegion::kIntersect_Op)) { 738 return false; 739 } 740 741 if (intersection) { 742 *intersection = ir; 743 } 744 return true; 745} 746 747int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, 748 SaveFlags flags) { 749 // do this before we create the layer. We don't call the public save() since 750 // that would invoke a possibly overridden virtual 751 int count = this->internalSave(flags); 752 753 fDeviceCMDirty = true; 754 755 SkIRect ir; 756 if (!this->clipRectBounds(bounds, flags, &ir)) { 757 return count; 758 } 759 760 // Kill the imagefilter if our device doesn't allow it 761 SkLazyPaint lazyP; 762 if (paint && paint->getImageFilter()) { 763 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) { 764 SkPaint* p = lazyP.set(*paint); 765 p->setImageFilter(NULL); 766 paint = p; 767 } 768 } 769 770 bool isOpaque; 771 SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque); 772 773 SkDevice* device; 774 if (paint && paint->getImageFilter()) { 775 device = this->createCompatibleDevice(config, ir.width(), ir.height(), 776 isOpaque); 777 } else { 778 device = this->createLayerDevice(config, ir.width(), ir.height(), 779 isOpaque); 780 } 781 if (NULL == device) { 782 SkDebugf("Unable to create device for layer."); 783 return count; 784 } 785 786 device->setOrigin(ir.fLeft, ir.fTop); 787 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint)); 788 device->unref(); 789 790 layer->fNext = fMCRec->fTopLayer; 791 fMCRec->fLayer = layer; 792 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer 793 794 fLayerCount += 1; 795 return count; 796} 797 798int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha, 799 SaveFlags flags) { 800 if (0xFF == alpha) { 801 return this->saveLayer(bounds, NULL, flags); 802 } else { 803 SkPaint tmpPaint; 804 tmpPaint.setAlpha(alpha); 805 return this->saveLayer(bounds, &tmpPaint, flags); 806 } 807} 808 809void SkCanvas::restore() { 810 // check for underflow 811 if (fMCStack.count() > 1) { 812 this->internalRestore(); 813 } 814} 815 816void SkCanvas::internalRestore() { 817 SkASSERT(fMCStack.count() != 0); 818 819 fDeviceCMDirty = true; 820 fLocalBoundsCompareTypeDirty = true; 821 fLocalBoundsCompareTypeDirtyBW = true; 822 823 fClipStack.restore(); 824 // reserve our layer (if any) 825 DeviceCM* layer = fMCRec->fLayer; // may be null 826 // now detach it from fMCRec so we can pop(). Gets freed after its drawn 827 fMCRec->fLayer = NULL; 828 829 // now do the normal restore() 830 fMCRec->~MCRec(); // balanced in save() 831 fMCStack.pop_back(); 832 fMCRec = (MCRec*)fMCStack.back(); 833 834 /* Time to draw the layer's offscreen. We can't call the public drawSprite, 835 since if we're being recorded, we don't want to record this (the 836 recorder will have already recorded the restore). 837 */ 838 if (NULL != layer) { 839 if (layer->fNext) { 840 const SkIPoint& origin = layer->fDevice->getOrigin(); 841 this->drawDevice(layer->fDevice, origin.x(), origin.y(), 842 layer->fPaint); 843 // reset this, since drawDevice will have set it to true 844 fDeviceCMDirty = true; 845 846 SkASSERT(fLayerCount > 0); 847 fLayerCount -= 1; 848 } 849 SkDELETE(layer); 850 } 851 852 SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1); 853} 854 855int SkCanvas::getSaveCount() const { 856 return fMCStack.count(); 857} 858 859void SkCanvas::restoreToCount(int count) { 860 // sanity check 861 if (count < 1) { 862 count = 1; 863 } 864 865 int n = this->getSaveCount() - count; 866 for (int i = 0; i < n; ++i) { 867 this->restore(); 868 } 869} 870 871bool SkCanvas::isDrawingToLayer() const { 872 return fLayerCount > 0; 873} 874 875///////////////////////////////////////////////////////////////////////////// 876 877// can't draw it if its empty, or its too big for a fixed-point width or height 878static bool reject_bitmap(const SkBitmap& bitmap) { 879 return bitmap.width() <= 0 || bitmap.height() <= 0 880#ifndef SK_ALLOW_OVER_32K_BITMAPS 881 || bitmap.width() > 32767 || bitmap.height() > 32767 882#endif 883 ; 884} 885 886void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect, 887 const SkMatrix& matrix, const SkPaint* paint) { 888 if (reject_bitmap(bitmap)) { 889 return; 890 } 891 892 SkLazyPaint lazy; 893 if (NULL == paint) { 894 paint = lazy.init(); 895 } 896 this->commonDrawBitmap(bitmap, srcRect, matrix, *paint); 897} 898 899#include "SkImageFilter.h" 900 901class DeviceImageFilterProxy : public SkImageFilter::Proxy { 902public: 903 DeviceImageFilterProxy(SkDevice* device) : fDevice(device) {} 904 905 virtual SkDevice* createDevice(int w, int h) SK_OVERRIDE; 906 virtual bool filterImage(SkImageFilter*, const SkBitmap& src, 907 const SkMatrix& ctm, 908 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE; 909 910private: 911 SkDevice* fDevice; 912}; 913 914SkDevice* DeviceImageFilterProxy::createDevice(int w, int h) { 915 return fDevice->createCompatibleDevice(SkBitmap::kARGB_8888_Config, 916 w, h, false); 917} 918 919bool DeviceImageFilterProxy::filterImage(SkImageFilter* filter, 920 const SkBitmap& src, 921 const SkMatrix& ctm, 922 SkBitmap* result, 923 SkIPoint* offset) { 924 return fDevice->filterImage(filter, src, ctm, result, offset); 925} 926 927void SkCanvas::drawDevice(SkDevice* srcDev, int x, int y, 928 const SkPaint* paint) { 929 SkPaint tmp; 930 if (NULL == paint) { 931 tmp.setDither(true); 932 paint = &tmp; 933 } 934 935 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type) 936 while (iter.next()) { 937 SkDevice* dstDev = iter.fDevice; 938 paint = &looper.paint(); 939 SkImageFilter* filter = paint->getImageFilter(); 940 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 941 if (filter) { 942 DeviceImageFilterProxy proxy(dstDev); 943 SkBitmap dst; 944 const SkBitmap& src = srcDev->accessBitmap(false); 945 if (filter->filterImage(&proxy, src, *iter.fMatrix, &dst, &pos)) { 946 SkPaint tmp(*paint); 947 tmp.setImageFilter(NULL); 948 dstDev->drawSprite(iter, dst, pos.x(), pos.y(), tmp); 949 } 950 } else { 951 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint); 952 } 953 } 954 LOOPER_END 955} 956 957///////////////////////////////////////////////////////////////////////////// 958 959bool SkCanvas::translate(SkScalar dx, SkScalar dy) { 960 fDeviceCMDirty = true; 961 fLocalBoundsCompareTypeDirty = true; 962 fLocalBoundsCompareTypeDirtyBW = true; 963 return fMCRec->fMatrix->preTranslate(dx, dy); 964} 965 966bool SkCanvas::scale(SkScalar sx, SkScalar sy) { 967 fDeviceCMDirty = true; 968 fLocalBoundsCompareTypeDirty = true; 969 fLocalBoundsCompareTypeDirtyBW = true; 970 return fMCRec->fMatrix->preScale(sx, sy); 971} 972 973bool SkCanvas::rotate(SkScalar degrees) { 974 fDeviceCMDirty = true; 975 fLocalBoundsCompareTypeDirty = true; 976 fLocalBoundsCompareTypeDirtyBW = true; 977 return fMCRec->fMatrix->preRotate(degrees); 978} 979 980bool SkCanvas::skew(SkScalar sx, SkScalar sy) { 981 fDeviceCMDirty = true; 982 fLocalBoundsCompareTypeDirty = true; 983 fLocalBoundsCompareTypeDirtyBW = true; 984 return fMCRec->fMatrix->preSkew(sx, sy); 985} 986 987bool SkCanvas::concat(const SkMatrix& matrix) { 988 fDeviceCMDirty = true; 989 fLocalBoundsCompareTypeDirty = true; 990 fLocalBoundsCompareTypeDirtyBW = true; 991 return fMCRec->fMatrix->preConcat(matrix); 992} 993 994void SkCanvas::setMatrix(const SkMatrix& matrix) { 995 fDeviceCMDirty = true; 996 fLocalBoundsCompareTypeDirty = true; 997 fLocalBoundsCompareTypeDirtyBW = true; 998 *fMCRec->fMatrix = matrix; 999} 1000 1001// this is not virtual, so it must call a virtual method so that subclasses 1002// will see its action 1003void SkCanvas::resetMatrix() { 1004 SkMatrix matrix; 1005 1006 matrix.reset(); 1007 this->setMatrix(matrix); 1008} 1009 1010////////////////////////////////////////////////////////////////////////////// 1011 1012bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 1013 AutoValidateClip avc(this); 1014 1015 fDeviceCMDirty = true; 1016 fLocalBoundsCompareTypeDirty = true; 1017 fLocalBoundsCompareTypeDirtyBW = true; 1018 1019 if (fMCRec->fMatrix->rectStaysRect()) { 1020 // for these simpler matrices, we can stay a rect ever after applying 1021 // the matrix. This means we don't have to a) make a path, and b) tell 1022 // the region code to scan-convert the path, only to discover that it 1023 // is really just a rect. 1024 SkRect r; 1025 1026 fMCRec->fMatrix->mapRect(&r, rect); 1027 fClipStack.clipDevRect(r, op, doAA); 1028 return fMCRec->fRasterClip->op(r, op, doAA); 1029 } else { 1030 // since we're rotate or some such thing, we convert the rect to a path 1031 // and clip against that, since it can handle any matrix. However, to 1032 // avoid recursion in the case where we are subclassed (e.g. Pictures) 1033 // we explicitly call "our" version of clipPath. 1034 SkPath path; 1035 1036 path.addRect(rect); 1037 return this->SkCanvas::clipPath(path, op, doAA); 1038 } 1039} 1040 1041static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip, 1042 const SkPath& devPath, SkRegion::Op op, bool doAA) { 1043 // base is used to limit the size (and therefore memory allocation) of the 1044 // region that results from scan converting devPath. 1045 SkRegion base; 1046 1047 if (SkRegion::kIntersect_Op == op) { 1048 // since we are intersect, we can do better (tighter) with currRgn's 1049 // bounds, than just using the device. However, if currRgn is complex, 1050 // our region blitter may hork, so we do that case in two steps. 1051 if (currClip->isRect()) { 1052 return currClip->setPath(devPath, *currClip, doAA); 1053 } else { 1054 base.setRect(currClip->getBounds()); 1055 SkRasterClip clip; 1056 clip.setPath(devPath, base, doAA); 1057 return currClip->op(clip, op); 1058 } 1059 } else { 1060 const SkDevice* device = canvas->getDevice(); 1061 base.setRect(0, 0, device->width(), device->height()); 1062 1063 if (SkRegion::kReplace_Op == op) { 1064 return currClip->setPath(devPath, base, doAA); 1065 } else { 1066 SkRasterClip clip; 1067 clip.setPath(devPath, base, doAA); 1068 return currClip->op(clip, op); 1069 } 1070 } 1071} 1072 1073bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 1074 AutoValidateClip avc(this); 1075 1076 fDeviceCMDirty = true; 1077 fLocalBoundsCompareTypeDirty = true; 1078 fLocalBoundsCompareTypeDirtyBW = true; 1079 1080 SkPath devPath; 1081 path.transform(*fMCRec->fMatrix, &devPath); 1082 1083 // Check if the transfomation, or the original path itself 1084 // made us empty. Note this can also happen if we contained NaN 1085 // values. computing the bounds detects this, and will set our 1086 // bounds to empty if that is the case. (see SkRect::set(pts, count)) 1087 if (devPath.getBounds().isEmpty()) { 1088 // resetting the path will remove any NaN or other wanky values 1089 // that might upset our scan converter. 1090 devPath.reset(); 1091 } 1092 1093 // if we called path.swap() we could avoid a deep copy of this path 1094 fClipStack.clipDevPath(devPath, op, doAA); 1095 1096 return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA); 1097} 1098 1099bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1100 AutoValidateClip avc(this); 1101 1102 fDeviceCMDirty = true; 1103 fLocalBoundsCompareTypeDirty = true; 1104 fLocalBoundsCompareTypeDirtyBW = true; 1105 1106 // todo: signal fClipStack that we have a region, and therefore (I guess) 1107 // we have to ignore it, and use the region directly? 1108 fClipStack.clipDevRect(rgn.getBounds()); 1109 1110 return fMCRec->fRasterClip->op(rgn, op); 1111} 1112 1113#ifdef SK_DEBUG 1114void SkCanvas::validateClip() const { 1115 // construct clipRgn from the clipstack 1116 const SkDevice* device = this->getDevice(); 1117 SkIRect ir; 1118 ir.set(0, 0, device->width(), device->height()); 1119 SkRasterClip tmpClip(ir); 1120 1121 SkClipStack::B2FIter iter(fClipStack); 1122 const SkClipStack::B2FIter::Clip* clip; 1123 while ((clip = iter.next()) != NULL) { 1124 if (clip->fPath) { 1125 clipPathHelper(this, &tmpClip, *clip->fPath, clip->fOp, clip->fDoAA); 1126 } else if (clip->fRect) { 1127 clip->fRect->round(&ir); 1128 tmpClip.op(ir, clip->fOp); 1129 } else { 1130 tmpClip.setEmpty(); 1131 } 1132 } 1133 1134#if 0 // enable this locally for testing 1135 // now compare against the current rgn 1136 const SkRegion& rgn = this->getTotalClip(); 1137 SkASSERT(rgn == tmpClip); 1138#endif 1139} 1140#endif 1141 1142/////////////////////////////////////////////////////////////////////////////// 1143 1144void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const { 1145 SkRect r; 1146 SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType : 1147 fLocalBoundsCompareTypeBW; 1148 1149 if (!this->getClipBounds(&r, et)) { 1150 rCompare.setEmpty(); 1151 } else { 1152 rCompare.set(SkScalarToCompareType(r.fLeft), 1153 SkScalarToCompareType(r.fTop), 1154 SkScalarToCompareType(r.fRight), 1155 SkScalarToCompareType(r.fBottom)); 1156 } 1157} 1158 1159/* current impl ignores edgetype, and relies on 1160 getLocalClipBoundsCompareType(), which always returns a value assuming 1161 antialiasing (worst case) 1162 */ 1163bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const { 1164 1165 if (!rect.isFinite()) 1166 return true; 1167 1168 if (fMCRec->fRasterClip->isEmpty()) { 1169 return true; 1170 } 1171 1172 if (fMCRec->fMatrix->hasPerspective()) { 1173 SkRect dst; 1174 fMCRec->fMatrix->mapRect(&dst, rect); 1175 SkIRect idst; 1176 dst.roundOut(&idst); 1177 return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds()); 1178 } else { 1179 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et); 1180 1181 // for speed, do the most likely reject compares first 1182 SkScalarCompareType userT = SkScalarToCompareType(rect.fTop); 1183 SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom); 1184 if (userT >= clipR.fBottom || userB <= clipR.fTop) { 1185 return true; 1186 } 1187 SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft); 1188 SkScalarCompareType userR = SkScalarToCompareType(rect.fRight); 1189 if (userL >= clipR.fRight || userR <= clipR.fLeft) { 1190 return true; 1191 } 1192 return false; 1193 } 1194} 1195 1196bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const { 1197 return path.isEmpty() || this->quickReject(path.getBounds(), et); 1198} 1199 1200bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const { 1201 /* current impl ignores edgetype, and relies on 1202 getLocalClipBoundsCompareType(), which always returns a value assuming 1203 antialiasing (worst case) 1204 */ 1205 1206 if (fMCRec->fRasterClip->isEmpty()) { 1207 return true; 1208 } 1209 1210 SkScalarCompareType userT = SkScalarToCompareType(top); 1211 SkScalarCompareType userB = SkScalarToCompareType(bottom); 1212 1213 // check for invalid user Y coordinates (i.e. empty) 1214 // reed: why do we need to do this check, since it slows us down? 1215 if (userT >= userB) { 1216 return true; 1217 } 1218 1219 // check if we are above or below the local clip bounds 1220 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(); 1221 return userT >= clipR.fBottom || userB <= clipR.fTop; 1222} 1223 1224static inline int pinIntForScalar(int x) { 1225#ifdef SK_SCALAR_IS_FIXED 1226 if (x < SK_MinS16) { 1227 x = SK_MinS16; 1228 } else if (x > SK_MaxS16) { 1229 x = SK_MaxS16; 1230 } 1231#endif 1232 return x; 1233} 1234 1235bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const { 1236 SkIRect ibounds; 1237 if (!getClipDeviceBounds(&ibounds)) { 1238 return false; 1239 } 1240 1241 SkMatrix inverse; 1242 // if we can't invert the CTM, we can't return local clip bounds 1243 if (!fMCRec->fMatrix->invert(&inverse)) { 1244 if (bounds) { 1245 bounds->setEmpty(); 1246 } 1247 return false; 1248 } 1249 1250 if (NULL != bounds) { 1251 SkRect r; 1252 // adjust it outwards if we are antialiasing 1253 int inset = (kAA_EdgeType == et); 1254 1255 // SkRect::iset() will correctly assert if we pass a value out of range 1256 // (when SkScalar==fixed), so we pin to legal values. This does not 1257 // really returnt the correct answer, but its the best we can do given 1258 // that we've promised to return SkRect (even though we support devices 1259 // that can be larger than 32K in width or height). 1260 r.iset(pinIntForScalar(ibounds.fLeft - inset), 1261 pinIntForScalar(ibounds.fTop - inset), 1262 pinIntForScalar(ibounds.fRight + inset), 1263 pinIntForScalar(ibounds.fBottom + inset)); 1264 inverse.mapRect(bounds, r); 1265 } 1266 return true; 1267} 1268 1269bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const { 1270 const SkRasterClip& clip = *fMCRec->fRasterClip; 1271 if (clip.isEmpty()) { 1272 if (bounds) { 1273 bounds->setEmpty(); 1274 } 1275 return false; 1276 } 1277 1278 if (NULL != bounds) { 1279 *bounds = clip.getBounds(); 1280 } 1281 return true; 1282} 1283 1284const SkMatrix& SkCanvas::getTotalMatrix() const { 1285 return *fMCRec->fMatrix; 1286} 1287 1288SkCanvas::ClipType SkCanvas::getClipType() const { 1289 if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType; 1290 if (fMCRec->fRasterClip->isRect()) return kRect_ClipType; 1291 return kComplex_ClipType; 1292} 1293 1294const SkRegion& SkCanvas::getTotalClip() const { 1295 return fMCRec->fRasterClip->forceGetBW(); 1296} 1297 1298const SkClipStack& SkCanvas::getTotalClipStack() const { 1299 return fClipStack; 1300} 1301 1302void SkCanvas::setExternalMatrix(const SkMatrix* matrix) { 1303 if (NULL == matrix || matrix->isIdentity()) { 1304 if (fUseExternalMatrix) { 1305 fDeviceCMDirty = true; 1306 } 1307 fUseExternalMatrix = false; 1308 } else { 1309 fUseExternalMatrix = true; 1310 fDeviceCMDirty = true; // |= (fExternalMatrix != *matrix) 1311 1312 fExternalMatrix = *matrix; 1313 matrix->invert(&fExternalInverse); 1314 } 1315} 1316 1317SkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config, 1318 int width, int height, 1319 bool isOpaque) { 1320 SkDevice* device = this->getTopDevice(); 1321 if (device) { 1322 return device->createCompatibleDeviceForSaveLayer(config, width, height, 1323 isOpaque); 1324 } else { 1325 return NULL; 1326 } 1327} 1328 1329SkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config, 1330 int width, int height, 1331 bool isOpaque) { 1332 SkDevice* device = this->getDevice(); 1333 if (device) { 1334 return device->createCompatibleDevice(config, width, height, isOpaque); 1335 } else { 1336 return NULL; 1337 } 1338} 1339 1340 1341////////////////////////////////////////////////////////////////////////////// 1342// These are the virtual drawing methods 1343////////////////////////////////////////////////////////////////////////////// 1344 1345void SkCanvas::clear(SkColor color) { 1346 SkDrawIter iter(this); 1347 1348 while (iter.next()) { 1349 iter.fDevice->clear(color); 1350 } 1351} 1352 1353void SkCanvas::drawPaint(const SkPaint& paint) { 1354 this->internalDrawPaint(paint); 1355} 1356 1357void SkCanvas::internalDrawPaint(const SkPaint& paint) { 1358 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type) 1359 1360 while (iter.next()) { 1361 iter.fDevice->drawPaint(iter, looper.paint()); 1362 } 1363 1364 LOOPER_END 1365} 1366 1367void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1368 const SkPaint& paint) { 1369 if ((long)count <= 0) { 1370 return; 1371 } 1372 1373 SkASSERT(pts != NULL); 1374 1375 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type) 1376 1377 while (iter.next()) { 1378 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); 1379 } 1380 1381 LOOPER_END 1382} 1383 1384void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1385 if (paint.canComputeFastBounds()) { 1386 SkRect storage; 1387 if (this->quickReject(paint.computeFastBounds(r, &storage), 1388 paint2EdgeType(&paint))) { 1389 return; 1390 } 1391 } 1392 1393 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type) 1394 1395 while (iter.next()) { 1396 iter.fDevice->drawRect(iter, r, looper.paint()); 1397 } 1398 1399 LOOPER_END 1400} 1401 1402void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 1403 if (!path.isInverseFillType() && paint.canComputeFastBounds()) { 1404 SkRect storage; 1405 const SkRect& bounds = path.getBounds(); 1406 if (this->quickReject(paint.computeFastBounds(bounds, &storage), 1407 paint2EdgeType(&paint))) { 1408 return; 1409 } 1410 } 1411 if (path.isEmpty()) { 1412 if (path.isInverseFillType()) { 1413 this->internalDrawPaint(paint); 1414 } 1415 return; 1416 } 1417 1418 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 1419 1420 while (iter.next()) { 1421 iter.fDevice->drawPath(iter, path, looper.paint()); 1422 } 1423 1424 LOOPER_END 1425} 1426 1427void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, 1428 const SkPaint* paint) { 1429 SkDEBUGCODE(bitmap.validate();) 1430 1431 if (NULL == paint || paint->canComputeFastBounds()) { 1432 SkRect bounds = { 1433 x, y, 1434 x + SkIntToScalar(bitmap.width()), 1435 y + SkIntToScalar(bitmap.height()) 1436 }; 1437 if (paint) { 1438 (void)paint->computeFastBounds(bounds, &bounds); 1439 } 1440 if (this->quickReject(bounds, paint2EdgeType(paint))) { 1441 return; 1442 } 1443 } 1444 1445 SkMatrix matrix; 1446 matrix.setTranslate(x, y); 1447 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1448} 1449 1450// this one is non-virtual, so it can be called safely by other canvas apis 1451void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, 1452 const SkRect& dst, const SkPaint* paint) { 1453 if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) { 1454 return; 1455 } 1456 1457 // do this now, to avoid the cost of calling extract for RLE bitmaps 1458 if (NULL == paint || paint->canComputeFastBounds()) { 1459 SkRect storage; 1460 const SkRect* bounds = &dst; 1461 if (paint) { 1462 bounds = &paint->computeFastBounds(dst, &storage); 1463 } 1464 if (this->quickReject(*bounds, paint2EdgeType(paint))) { 1465 return; 1466 } 1467 } 1468 1469 const SkBitmap* bitmapPtr = &bitmap; 1470 1471 SkMatrix matrix; 1472 SkRect tmpSrc; 1473 if (src) { 1474 tmpSrc.set(*src); 1475 // if the extract process clipped off the top or left of the 1476 // original, we adjust for that here to get the position right. 1477 if (tmpSrc.fLeft > 0) { 1478 tmpSrc.fRight -= tmpSrc.fLeft; 1479 tmpSrc.fLeft = 0; 1480 } 1481 if (tmpSrc.fTop > 0) { 1482 tmpSrc.fBottom -= tmpSrc.fTop; 1483 tmpSrc.fTop = 0; 1484 } 1485 } else { 1486 tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()), 1487 SkIntToScalar(bitmap.height())); 1488 } 1489 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 1490 1491 // ensure that src is "valid" before we pass it to our internal routines 1492 // and to SkDevice. i.e. sure it is contained inside the original bitmap. 1493 SkIRect tmpISrc; 1494 if (src) { 1495 tmpISrc.set(0, 0, bitmap.width(), bitmap.height()); 1496 if (!tmpISrc.intersect(*src)) { 1497 return; 1498 } 1499 src = &tmpISrc; 1500 } 1501 this->internalDrawBitmap(*bitmapPtr, src, matrix, paint); 1502} 1503 1504void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, 1505 const SkRect& dst, const SkPaint* paint) { 1506 SkDEBUGCODE(bitmap.validate();) 1507 this->internalDrawBitmapRect(bitmap, src, dst, paint); 1508} 1509 1510void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 1511 const SkPaint* paint) { 1512 SkDEBUGCODE(bitmap.validate();) 1513 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1514} 1515 1516void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect, 1517 const SkMatrix& matrix, const SkPaint& paint) { 1518 SkDEBUGCODE(bitmap.validate();) 1519 1520 LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type) 1521 1522 while (iter.next()) { 1523 iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint()); 1524 } 1525 1526 LOOPER_END 1527} 1528 1529void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap, 1530 const SkIRect& center, const SkRect& dst, 1531 const SkPaint* paint) { 1532 if (NULL == paint || paint->canComputeFastBounds()) { 1533 SkRect storage; 1534 const SkRect* bounds = &dst; 1535 if (paint) { 1536 bounds = &paint->computeFastBounds(dst, &storage); 1537 } 1538 if (this->quickReject(*bounds, paint2EdgeType(paint))) { 1539 return; 1540 } 1541 } 1542 1543 const int32_t w = bitmap.width(); 1544 const int32_t h = bitmap.height(); 1545 1546 SkIRect c = center; 1547 // pin center to the bounds of the bitmap 1548 c.fLeft = SkMax32(0, center.fLeft); 1549 c.fTop = SkMax32(0, center.fTop); 1550 c.fRight = SkPin32(center.fRight, c.fLeft, w); 1551 c.fBottom = SkPin32(center.fBottom, c.fTop, h); 1552 1553 const int32_t srcX[4] = { 0, c.fLeft, c.fRight, w }; 1554 const int32_t srcY[4] = { 0, c.fTop, c.fBottom, h }; 1555 SkScalar dstX[4] = { 1556 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft), 1557 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight 1558 }; 1559 SkScalar dstY[4] = { 1560 dst.fTop, dst.fTop + SkIntToScalar(c.fTop), 1561 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom 1562 }; 1563 1564 if (dstX[1] > dstX[2]) { 1565 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width()); 1566 dstX[2] = dstX[1]; 1567 } 1568 1569 if (dstY[1] > dstY[2]) { 1570 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height()); 1571 dstY[2] = dstY[1]; 1572 } 1573 1574 SkIRect s; 1575 SkRect d; 1576 for (int y = 0; y < 3; y++) { 1577 s.fTop = srcY[y]; 1578 s.fBottom = srcY[y+1]; 1579 d.fTop = dstY[y]; 1580 d.fBottom = dstY[y+1]; 1581 for (int x = 0; x < 3; x++) { 1582 s.fLeft = srcX[x]; 1583 s.fRight = srcX[x+1]; 1584 d.fLeft = dstX[x]; 1585 d.fRight = dstX[x+1]; 1586 this->internalDrawBitmapRect(bitmap, &s, d, paint); 1587 } 1588 } 1589} 1590 1591void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 1592 const SkRect& dst, const SkPaint* paint) { 1593 SkDEBUGCODE(bitmap.validate();) 1594 1595 // Need a device entry-point, so gpu can use a mesh 1596 this->internalDrawBitmapNine(bitmap, center, dst, paint); 1597} 1598 1599void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, 1600 const SkPaint* paint) { 1601 SkDEBUGCODE(bitmap.validate();) 1602 1603 if (reject_bitmap(bitmap)) { 1604 return; 1605 } 1606 1607 SkPaint tmp; 1608 if (NULL == paint) { 1609 paint = &tmp; 1610 } 1611 1612 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type) 1613 1614 while (iter.next()) { 1615 iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(), 1616 looper.paint()); 1617 } 1618 LOOPER_END 1619} 1620 1621class SkDeviceFilteredPaint { 1622public: 1623 SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) { 1624 SkDevice::TextFlags flags; 1625 if (device->filterTextFlags(paint, &flags)) { 1626 SkPaint* newPaint = fLazy.set(paint); 1627 newPaint->setFlags(flags.fFlags); 1628 newPaint->setHinting(flags.fHinting); 1629 fPaint = newPaint; 1630 } else { 1631 fPaint = &paint; 1632 } 1633 } 1634 1635 const SkPaint& paint() const { return *fPaint; } 1636 1637private: 1638 const SkPaint* fPaint; 1639 SkLazyPaint fLazy; 1640}; 1641 1642void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, 1643 const SkRect& r, SkScalar textSize) { 1644 if (paint.getStyle() == SkPaint::kFill_Style) { 1645 draw.fDevice->drawRect(draw, r, paint); 1646 } else { 1647 SkPaint p(paint); 1648 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); 1649 draw.fDevice->drawRect(draw, r, p); 1650 } 1651} 1652 1653void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, 1654 const char text[], size_t byteLength, 1655 SkScalar x, SkScalar y) { 1656 SkASSERT(byteLength == 0 || text != NULL); 1657 1658 // nothing to draw 1659 if (text == NULL || byteLength == 0 || 1660 draw.fClip->isEmpty() || 1661 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 1662 return; 1663 } 1664 1665 SkScalar width = 0; 1666 SkPoint start; 1667 1668 start.set(0, 0); // to avoid warning 1669 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | 1670 SkPaint::kStrikeThruText_Flag)) { 1671 width = paint.measureText(text, byteLength); 1672 1673 SkScalar offsetX = 0; 1674 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 1675 offsetX = SkScalarHalf(width); 1676 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { 1677 offsetX = width; 1678 } 1679 start.set(x - offsetX, y); 1680 } 1681 1682 if (0 == width) { 1683 return; 1684 } 1685 1686 uint32_t flags = paint.getFlags(); 1687 1688 if (flags & (SkPaint::kUnderlineText_Flag | 1689 SkPaint::kStrikeThruText_Flag)) { 1690 SkScalar textSize = paint.getTextSize(); 1691 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 1692 SkRect r; 1693 1694 r.fLeft = start.fX; 1695 r.fRight = start.fX + width; 1696 1697 if (flags & SkPaint::kUnderlineText_Flag) { 1698 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, 1699 start.fY); 1700 r.fTop = offset; 1701 r.fBottom = offset + height; 1702 DrawRect(draw, paint, r, textSize); 1703 } 1704 if (flags & SkPaint::kStrikeThruText_Flag) { 1705 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, 1706 start.fY); 1707 r.fTop = offset; 1708 r.fBottom = offset + height; 1709 DrawRect(draw, paint, r, textSize); 1710 } 1711 } 1712} 1713 1714void SkCanvas::drawText(const void* text, size_t byteLength, 1715 SkScalar x, SkScalar y, const SkPaint& paint) { 1716 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1717 1718 while (iter.next()) { 1719 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1720 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 1721 DrawTextDecorations(iter, dfp.paint(), 1722 static_cast<const char*>(text), byteLength, x, y); 1723 } 1724 1725 LOOPER_END 1726} 1727 1728void SkCanvas::drawPosText(const void* text, size_t byteLength, 1729 const SkPoint pos[], const SkPaint& paint) { 1730 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1731 1732 while (iter.next()) { 1733 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1734 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 1735 dfp.paint()); 1736 } 1737 1738 LOOPER_END 1739} 1740 1741void SkCanvas::drawPosTextH(const void* text, size_t byteLength, 1742 const SkScalar xpos[], SkScalar constY, 1743 const SkPaint& paint) { 1744 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1745 1746 while (iter.next()) { 1747 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1748 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 1749 dfp.paint()); 1750 } 1751 1752 LOOPER_END 1753} 1754 1755void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, 1756 const SkPath& path, const SkMatrix* matrix, 1757 const SkPaint& paint) { 1758 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1759 1760 while (iter.next()) { 1761 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 1762 matrix, looper.paint()); 1763 } 1764 1765 LOOPER_END 1766} 1767 1768#ifdef SK_BUILD_FOR_ANDROID 1769void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength, 1770 const SkPoint pos[], const SkPaint& paint, 1771 const SkPath& path, const SkMatrix* matrix) { 1772 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1773 1774 while (iter.next()) { 1775 iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos, 1776 looper.paint(), path, matrix); 1777 } 1778 1779 LOOPER_END 1780} 1781#endif 1782 1783void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 1784 const SkPoint verts[], const SkPoint texs[], 1785 const SkColor colors[], SkXfermode* xmode, 1786 const uint16_t indices[], int indexCount, 1787 const SkPaint& paint) { 1788 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 1789 1790 while (iter.next()) { 1791 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 1792 colors, xmode, indices, indexCount, 1793 looper.paint()); 1794 } 1795 1796 LOOPER_END 1797} 1798 1799void SkCanvas::drawData(const void* data, size_t length) { 1800 // do nothing. Subclasses may do something with the data 1801} 1802 1803////////////////////////////////////////////////////////////////////////////// 1804// These methods are NOT virtual, and therefore must call back into virtual 1805// methods, rather than actually drawing themselves. 1806////////////////////////////////////////////////////////////////////////////// 1807 1808void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 1809 SkXfermode::Mode mode) { 1810 SkPaint paint; 1811 1812 paint.setARGB(a, r, g, b); 1813 if (SkXfermode::kSrcOver_Mode != mode) { 1814 paint.setXfermodeMode(mode); 1815 } 1816 this->drawPaint(paint); 1817} 1818 1819void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 1820 SkPaint paint; 1821 1822 paint.setColor(c); 1823 if (SkXfermode::kSrcOver_Mode != mode) { 1824 paint.setXfermodeMode(mode); 1825 } 1826 this->drawPaint(paint); 1827} 1828 1829void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 1830 SkPoint pt; 1831 1832 pt.set(x, y); 1833 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1834} 1835 1836void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 1837 SkPoint pt; 1838 SkPaint paint; 1839 1840 pt.set(x, y); 1841 paint.setColor(color); 1842 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1843} 1844 1845void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 1846 const SkPaint& paint) { 1847 SkPoint pts[2]; 1848 1849 pts[0].set(x0, y0); 1850 pts[1].set(x1, y1); 1851 this->drawPoints(kLines_PointMode, 2, pts, paint); 1852} 1853 1854void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 1855 SkScalar right, SkScalar bottom, 1856 const SkPaint& paint) { 1857 SkRect r; 1858 1859 r.set(left, top, right, bottom); 1860 this->drawRect(r, paint); 1861} 1862 1863void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 1864 const SkPaint& paint) { 1865 if (radius < 0) { 1866 radius = 0; 1867 } 1868 1869 SkRect r; 1870 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 1871 1872 if (paint.canComputeFastBounds()) { 1873 SkRect storage; 1874 if (this->quickReject(paint.computeFastBounds(r, &storage), 1875 paint2EdgeType(&paint))) { 1876 return; 1877 } 1878 } 1879 1880 SkPath path; 1881 path.addOval(r); 1882 this->drawPath(path, paint); 1883} 1884 1885void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 1886 const SkPaint& paint) { 1887 if (rx > 0 && ry > 0) { 1888 if (paint.canComputeFastBounds()) { 1889 SkRect storage; 1890 if (this->quickReject(paint.computeFastBounds(r, &storage), 1891 paint2EdgeType(&paint))) { 1892 return; 1893 } 1894 } 1895 1896 SkPath path; 1897 path.addRoundRect(r, rx, ry, SkPath::kCW_Direction); 1898 this->drawPath(path, paint); 1899 } else { 1900 this->drawRect(r, paint); 1901 } 1902} 1903 1904void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1905 if (paint.canComputeFastBounds()) { 1906 SkRect storage; 1907 if (this->quickReject(paint.computeFastBounds(oval, &storage), 1908 paint2EdgeType(&paint))) { 1909 return; 1910 } 1911 } 1912 1913 SkPath path; 1914 path.addOval(oval); 1915 this->drawPath(path, paint); 1916} 1917 1918void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 1919 SkScalar sweepAngle, bool useCenter, 1920 const SkPaint& paint) { 1921 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 1922 this->drawOval(oval, paint); 1923 } else { 1924 SkPath path; 1925 if (useCenter) { 1926 path.moveTo(oval.centerX(), oval.centerY()); 1927 } 1928 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 1929 if (useCenter) { 1930 path.close(); 1931 } 1932 this->drawPath(path, paint); 1933 } 1934} 1935 1936void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 1937 const SkPath& path, SkScalar hOffset, 1938 SkScalar vOffset, const SkPaint& paint) { 1939 SkMatrix matrix; 1940 1941 matrix.setTranslate(hOffset, vOffset); 1942 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 1943} 1944 1945/////////////////////////////////////////////////////////////////////////////// 1946 1947void SkCanvas::drawPicture(SkPicture& picture) { 1948 int saveCount = save(); 1949 picture.draw(this); 1950 restoreToCount(saveCount); 1951} 1952 1953/////////////////////////////////////////////////////////////////////////////// 1954/////////////////////////////////////////////////////////////////////////////// 1955 1956SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 1957 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); 1958 1959 SkASSERT(canvas); 1960 1961 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 1962 fDone = !fImpl->next(); 1963} 1964 1965SkCanvas::LayerIter::~LayerIter() { 1966 fImpl->~SkDrawIter(); 1967} 1968 1969void SkCanvas::LayerIter::next() { 1970 fDone = !fImpl->next(); 1971} 1972 1973SkDevice* SkCanvas::LayerIter::device() const { 1974 return fImpl->getDevice(); 1975} 1976 1977const SkMatrix& SkCanvas::LayerIter::matrix() const { 1978 return fImpl->getMatrix(); 1979} 1980 1981const SkPaint& SkCanvas::LayerIter::paint() const { 1982 const SkPaint* paint = fImpl->getPaint(); 1983 if (NULL == paint) { 1984 paint = &fDefaultPaint; 1985 } 1986 return *paint; 1987} 1988 1989const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 1990int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 1991int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 1992