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