SkCanvas.cpp revision 17b78946096265d80215a6c946286ecaa35ea7ed
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 1276void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, 1277 const SkRect& dst, const SkPaint* paint) { 1278 if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) { 1279 return; 1280 } 1281 1282 // do this now, to avoid the cost of calling extract for RLE bitmaps 1283 if (this->quickReject(dst, paint2EdgeType(paint))) { 1284 return; 1285 } 1286 1287 const SkBitmap* bitmapPtr = &bitmap; 1288 1289 SkMatrix matrix; 1290 SkRect tmpSrc; 1291 if (src) { 1292 tmpSrc.set(*src); 1293 // if the extract process clipped off the top or left of the 1294 // original, we adjust for that here to get the position right. 1295 if (tmpSrc.fLeft > 0) { 1296 tmpSrc.fRight -= tmpSrc.fLeft; 1297 tmpSrc.fLeft = 0; 1298 } 1299 if (tmpSrc.fTop > 0) { 1300 tmpSrc.fBottom -= tmpSrc.fTop; 1301 tmpSrc.fTop = 0; 1302 } 1303 } else { 1304 tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()), 1305 SkIntToScalar(bitmap.height())); 1306 } 1307 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 1308 1309 // ensure that src is "valid" before we pass it to our internal routines 1310 // and to SkDevice. i.e. sure it is contained inside the original bitmap. 1311 SkIRect tmpISrc; 1312 if (src) { 1313 tmpISrc.set(0, 0, bitmap.width(), bitmap.height()); 1314 if (!tmpISrc.intersect(*src)) { 1315 return; 1316 } 1317 src = &tmpISrc; 1318 } 1319 this->internalDrawBitmap(*bitmapPtr, src, matrix, paint); 1320} 1321 1322void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 1323 const SkPaint* paint) { 1324 SkDEBUGCODE(bitmap.validate();) 1325 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1326} 1327 1328void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect, 1329 const SkMatrix& matrix, const SkPaint& paint) { 1330 SkDEBUGCODE(bitmap.validate();) 1331 1332 LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type) 1333 1334 while (iter.next()) { 1335 iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint()); 1336 } 1337 1338 LOOPER_END 1339} 1340 1341void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, 1342 const SkPaint* paint) { 1343 SkDEBUGCODE(bitmap.validate();) 1344 1345 if (reject_bitmap(bitmap)) { 1346 return; 1347 } 1348 1349 SkPaint tmp; 1350 if (NULL == paint) { 1351 paint = &tmp; 1352 } 1353 1354 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type) 1355 1356 while (iter.next()) { 1357 iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(), 1358 looper.paint()); 1359 } 1360 LOOPER_END 1361} 1362 1363class SkDeviceFilteredPaint { 1364public: 1365 SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) { 1366 SkDevice::TextFlags flags; 1367 if (device->filterTextFlags(paint, &flags)) { 1368 SkPaint* newPaint = fLazy.set(paint); 1369 newPaint->setFlags(flags.fFlags); 1370 newPaint->setHinting(flags.fHinting); 1371 fPaint = newPaint; 1372 } else { 1373 fPaint = &paint; 1374 } 1375 } 1376 1377 const SkPaint& paint() const { return *fPaint; } 1378 1379private: 1380 const SkPaint* fPaint; 1381 SkLazyPaint fLazy; 1382}; 1383 1384void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, 1385 const SkRect& r, SkScalar textSize) { 1386 if (paint.getStyle() == SkPaint::kFill_Style) { 1387 draw.fDevice->drawRect(draw, r, paint); 1388 } else { 1389 SkPaint p(paint); 1390 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); 1391 draw.fDevice->drawRect(draw, r, p); 1392 } 1393} 1394 1395void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, 1396 const char text[], size_t byteLength, 1397 SkScalar x, SkScalar y) { 1398 SkASSERT(byteLength == 0 || text != NULL); 1399 1400 // nothing to draw 1401 if (text == NULL || byteLength == 0 || 1402 draw.fClip->isEmpty() || 1403 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 1404 return; 1405 } 1406 1407 SkScalar width = 0; 1408 SkPoint start; 1409 1410 start.set(0, 0); // to avoid warning 1411 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | 1412 SkPaint::kStrikeThruText_Flag)) { 1413 width = paint.measureText(text, byteLength); 1414 1415 SkScalar offsetX = 0; 1416 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 1417 offsetX = SkScalarHalf(width); 1418 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { 1419 offsetX = width; 1420 } 1421 start.set(x - offsetX, y); 1422 } 1423 1424 if (0 == width) { 1425 return; 1426 } 1427 1428 uint32_t flags = paint.getFlags(); 1429 1430 if (flags & (SkPaint::kUnderlineText_Flag | 1431 SkPaint::kStrikeThruText_Flag)) { 1432 SkScalar textSize = paint.getTextSize(); 1433 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 1434 SkRect r; 1435 1436 r.fLeft = start.fX; 1437 r.fRight = start.fX + width; 1438 1439 if (flags & SkPaint::kUnderlineText_Flag) { 1440 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, 1441 start.fY); 1442 r.fTop = offset; 1443 r.fBottom = offset + height; 1444 DrawRect(draw, paint, r, textSize); 1445 } 1446 if (flags & SkPaint::kStrikeThruText_Flag) { 1447 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, 1448 start.fY); 1449 r.fTop = offset; 1450 r.fBottom = offset + height; 1451 DrawRect(draw, paint, r, textSize); 1452 } 1453 } 1454} 1455 1456void SkCanvas::drawText(const void* text, size_t byteLength, 1457 SkScalar x, SkScalar y, const SkPaint& paint) { 1458 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1459 1460 while (iter.next()) { 1461 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1462 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 1463 DrawTextDecorations(iter, dfp.paint(), 1464 static_cast<const char*>(text), byteLength, x, y); 1465 } 1466 1467 LOOPER_END 1468} 1469 1470void SkCanvas::drawPosText(const void* text, size_t byteLength, 1471 const SkPoint pos[], const SkPaint& paint) { 1472 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1473 1474 while (iter.next()) { 1475 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1476 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 1477 dfp.paint()); 1478 } 1479 1480 LOOPER_END 1481} 1482 1483void SkCanvas::drawPosTextH(const void* text, size_t byteLength, 1484 const SkScalar xpos[], SkScalar constY, 1485 const SkPaint& paint) { 1486 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1487 1488 while (iter.next()) { 1489 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1490 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 1491 dfp.paint()); 1492 } 1493 1494 LOOPER_END 1495} 1496 1497void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, 1498 const SkPath& path, const SkMatrix* matrix, 1499 const SkPaint& paint) { 1500 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1501 1502 while (iter.next()) { 1503 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 1504 matrix, looper.paint()); 1505 } 1506 1507 LOOPER_END 1508} 1509 1510#ifdef ANDROID 1511void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength, 1512 const SkPoint pos[], const SkPaint& paint, 1513 const SkPath& path, const SkMatrix* matrix) { 1514 1515 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type) 1516 1517 while (iter.next()) { 1518 iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos, 1519 looper.paint(), path, matrix); 1520 } 1521 1522 LOOPER_END 1523} 1524#endif 1525 1526void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 1527 const SkPoint verts[], const SkPoint texs[], 1528 const SkColor colors[], SkXfermode* xmode, 1529 const uint16_t indices[], int indexCount, 1530 const SkPaint& paint) { 1531 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type) 1532 1533 while (iter.next()) { 1534 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 1535 colors, xmode, indices, indexCount, 1536 looper.paint()); 1537 } 1538 1539 LOOPER_END 1540} 1541 1542void SkCanvas::drawData(const void* data, size_t length) { 1543 // do nothing. Subclasses may do something with the data 1544} 1545 1546////////////////////////////////////////////////////////////////////////////// 1547// These methods are NOT virtual, and therefore must call back into virtual 1548// methods, rather than actually drawing themselves. 1549////////////////////////////////////////////////////////////////////////////// 1550 1551void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 1552 SkXfermode::Mode mode) { 1553 SkPaint paint; 1554 1555 paint.setARGB(a, r, g, b); 1556 if (SkXfermode::kSrcOver_Mode != mode) { 1557 paint.setXfermodeMode(mode); 1558 } 1559 this->drawPaint(paint); 1560} 1561 1562void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 1563 SkPaint paint; 1564 1565 paint.setColor(c); 1566 if (SkXfermode::kSrcOver_Mode != mode) { 1567 paint.setXfermodeMode(mode); 1568 } 1569 this->drawPaint(paint); 1570} 1571 1572void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 1573 SkPoint pt; 1574 1575 pt.set(x, y); 1576 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1577} 1578 1579void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 1580 SkPoint pt; 1581 SkPaint paint; 1582 1583 pt.set(x, y); 1584 paint.setColor(color); 1585 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1586} 1587 1588void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 1589 const SkPaint& paint) { 1590 SkPoint pts[2]; 1591 1592 pts[0].set(x0, y0); 1593 pts[1].set(x1, y1); 1594 this->drawPoints(kLines_PointMode, 2, pts, paint); 1595} 1596 1597void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 1598 SkScalar right, SkScalar bottom, 1599 const SkPaint& paint) { 1600 SkRect r; 1601 1602 r.set(left, top, right, bottom); 1603 this->drawRect(r, paint); 1604} 1605 1606void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 1607 const SkPaint& paint) { 1608 if (radius < 0) { 1609 radius = 0; 1610 } 1611 1612 SkRect r; 1613 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 1614 1615 if (paint.canComputeFastBounds()) { 1616 SkRect storage; 1617 if (this->quickReject(paint.computeFastBounds(r, &storage), 1618 paint2EdgeType(&paint))) { 1619 return; 1620 } 1621 } 1622 1623 SkPath path; 1624 path.addOval(r); 1625 this->drawPath(path, paint); 1626} 1627 1628void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 1629 const SkPaint& paint) { 1630 if (rx > 0 && ry > 0) { 1631 if (paint.canComputeFastBounds()) { 1632 SkRect storage; 1633 if (this->quickReject(paint.computeFastBounds(r, &storage), 1634 paint2EdgeType(&paint))) { 1635 return; 1636 } 1637 } 1638 1639 SkPath path; 1640 path.addRoundRect(r, rx, ry, SkPath::kCW_Direction); 1641 this->drawPath(path, paint); 1642 } else { 1643 this->drawRect(r, paint); 1644 } 1645} 1646 1647void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1648 if (paint.canComputeFastBounds()) { 1649 SkRect storage; 1650 if (this->quickReject(paint.computeFastBounds(oval, &storage), 1651 paint2EdgeType(&paint))) { 1652 return; 1653 } 1654 } 1655 1656 SkPath path; 1657 path.addOval(oval); 1658 this->drawPath(path, paint); 1659} 1660 1661void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 1662 SkScalar sweepAngle, bool useCenter, 1663 const SkPaint& paint) { 1664 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 1665 this->drawOval(oval, paint); 1666 } else { 1667 SkPath path; 1668 if (useCenter) { 1669 path.moveTo(oval.centerX(), oval.centerY()); 1670 } 1671 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 1672 if (useCenter) { 1673 path.close(); 1674 } 1675 this->drawPath(path, paint); 1676 } 1677} 1678 1679void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 1680 const SkPath& path, SkScalar hOffset, 1681 SkScalar vOffset, const SkPaint& paint) { 1682 SkMatrix matrix; 1683 1684 matrix.setTranslate(hOffset, vOffset); 1685 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 1686} 1687 1688/////////////////////////////////////////////////////////////////////////////// 1689 1690void SkCanvas::drawPicture(SkPicture& picture) { 1691 int saveCount = save(); 1692 picture.draw(this); 1693 restoreToCount(saveCount); 1694} 1695 1696/////////////////////////////////////////////////////////////////////////////// 1697/////////////////////////////////////////////////////////////////////////////// 1698 1699SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 1700 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); 1701 1702 SkASSERT(canvas); 1703 1704 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 1705 fDone = !fImpl->next(); 1706} 1707 1708SkCanvas::LayerIter::~LayerIter() { 1709 fImpl->~SkDrawIter(); 1710} 1711 1712void SkCanvas::LayerIter::next() { 1713 fDone = !fImpl->next(); 1714} 1715 1716SkDevice* SkCanvas::LayerIter::device() const { 1717 return fImpl->getDevice(); 1718} 1719 1720const SkMatrix& SkCanvas::LayerIter::matrix() const { 1721 return fImpl->getMatrix(); 1722} 1723 1724const SkPaint& SkCanvas::LayerIter::paint() const { 1725 const SkPaint* paint = fImpl->getPaint(); 1726 if (NULL == paint) { 1727 paint = &fDefaultPaint; 1728 } 1729 return *paint; 1730} 1731 1732const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 1733int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 1734int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 1735