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