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