SkCanvas.cpp revision d642329293cce602ac24df8f585c14a98795da87
1/* 2 * Copyright (C) 2006-2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "SkCanvas.h" 18#include "SkBounder.h" 19#include "SkDevice.h" 20#include "SkDraw.h" 21#include "SkDrawFilter.h" 22#include "SkDrawLooper.h" 23#include "SkPicture.h" 24#include "SkScalarCompare.h" 25#include "SkShape.h" 26#include "SkTemplates.h" 27#include "SkUtils.h" 28#include <new> 29 30//#define SK_TRACE_SAVERESTORE 31 32#ifdef SK_TRACE_SAVERESTORE 33 static int gLayerCounter; 34 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); } 35 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); } 36 37 static int gRecCounter; 38 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); } 39 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); } 40 41 static int gCanvasCounter; 42 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); } 43 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); } 44#else 45 #define inc_layer() 46 #define dec_layer() 47 #define inc_rec() 48 #define dec_rec() 49 #define inc_canvas() 50 #define dec_canvas() 51#endif 52 53/////////////////////////////////////////////////////////////////////////////// 54// Helpers for computing fast bounds for quickReject tests 55 56static SkCanvas::EdgeType paint2EdgeType(const SkPaint* paint) { 57 return paint != NULL && paint->isAntiAlias() ? 58 SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType; 59} 60 61/////////////////////////////////////////////////////////////////////////////// 62 63/* This is the record we keep for each SkDevice that the user installs. 64 The clip/matrix/proc are fields that reflect the top of the save/restore 65 stack. Whenever the canvas changes, it marks a dirty flag, and then before 66 these are used (assuming we're not on a layer) we rebuild these cache 67 values: they reflect the top of the save stack, but translated and clipped 68 by the device's XY offset and bitmap-bounds. 69*/ 70struct DeviceCM { 71 DeviceCM* fNext; 72 SkDevice* fDevice; 73 SkRegion fClip; 74 const SkMatrix* fMatrix; 75 SkPaint* fPaint; // may be null (in the future) 76 int16_t fX, fY; // relative to base matrix/clip 77 // optional, related to canvas' external matrix 78 const SkMatrix* fMVMatrix; 79 const SkMatrix* fExtMatrix; 80 81 DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint) 82 : fNext(NULL) { 83 if (NULL != device) { 84 device->ref(); 85 device->lockPixels(); 86 } 87 fDevice = device; 88 fX = SkToS16(x); 89 fY = SkToS16(y); 90 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL; 91 } 92 93 ~DeviceCM() { 94 if (NULL != fDevice) { 95 fDevice->unlockPixels(); 96 fDevice->unref(); 97 } 98 SkDELETE(fPaint); 99 } 100 101 void updateMC(const SkMatrix& totalMatrix, const SkRegion& totalClip, 102 SkRegion* updateClip) { 103 int x = fX; 104 int y = fY; 105 int width = fDevice->width(); 106 int height = fDevice->height(); 107 108 if ((x | y) == 0) { 109 fMatrix = &totalMatrix; 110 fClip = totalClip; 111 } else { 112 fMatrixStorage = totalMatrix; 113 fMatrixStorage.postTranslate(SkIntToScalar(-x), 114 SkIntToScalar(-y)); 115 fMatrix = &fMatrixStorage; 116 117 totalClip.translate(-x, -y, &fClip); 118 } 119 120 fClip.op(0, 0, width, height, SkRegion::kIntersect_Op); 121 122 // intersect clip, but don't translate it (yet) 123 124 if (updateClip) { 125 updateClip->op(x, y, x + width, y + height, 126 SkRegion::kDifference_Op); 127 } 128 129 fDevice->setMatrixClip(*fMatrix, fClip); 130 131#ifdef SK_DEBUG 132 if (!fClip.isEmpty()) { 133 SkIRect deviceR; 134 deviceR.set(0, 0, width, height); 135 SkASSERT(deviceR.contains(fClip.getBounds())); 136 } 137#endif 138 // default is to assume no external matrix 139 fMVMatrix = NULL; 140 fExtMatrix = NULL; 141 } 142 143 // can only be called after calling updateMC() 144 void updateExternalMatrix(const SkMatrix& extM, const SkMatrix& extI) { 145 fMVMatrixStorage.setConcat(extI, *fMatrix); 146 fMVMatrix = &fMVMatrixStorage; 147 fExtMatrix = &extM; // assumes extM has long life-time (owned by canvas) 148 } 149 150 void translateClip() { 151 if (fX | fY) { 152 fClip.translate(fX, fY); 153 } 154 } 155 156private: 157 SkMatrix fMatrixStorage, fMVMatrixStorage; 158}; 159 160/* This is the record we keep for each save/restore level in the stack. 161 Since a level optionally copies the matrix and/or stack, we have pointers 162 for these fields. If the value is copied for this level, the copy is 163 stored in the ...Storage field, and the pointer points to that. If the 164 value is not copied for this level, we ignore ...Storage, and just point 165 at the corresponding value in the previous level in the stack. 166*/ 167class SkCanvas::MCRec { 168public: 169 MCRec* fNext; 170 SkMatrix* fMatrix; // points to either fMatrixStorage or prev MCRec 171 SkRegion* fRegion; // points to either fRegionStorage or prev MCRec 172 SkDrawFilter* fFilter; // the current filter (or null) 173 174 DeviceCM* fLayer; 175 /* If there are any layers in the stack, this points to the top-most 176 one that is at or below this level in the stack (so we know what 177 bitmap/device to draw into from this level. This value is NOT 178 reference counted, since the real owner is either our fLayer field, 179 or a previous one in a lower level.) 180 */ 181 DeviceCM* fTopLayer; 182 183 MCRec(const MCRec* prev, int flags) { 184 if (NULL != prev) { 185 if (flags & SkCanvas::kMatrix_SaveFlag) { 186 fMatrixStorage = *prev->fMatrix; 187 fMatrix = &fMatrixStorage; 188 } else { 189 fMatrix = prev->fMatrix; 190 } 191 192 if (flags & SkCanvas::kClip_SaveFlag) { 193 fRegionStorage = *prev->fRegion; 194 fRegion = &fRegionStorage; 195 } else { 196 fRegion = prev->fRegion; 197 } 198 199 fFilter = prev->fFilter; 200 fFilter->safeRef(); 201 202 fTopLayer = prev->fTopLayer; 203 } else { // no prev 204 fMatrixStorage.reset(); 205 206 fMatrix = &fMatrixStorage; 207 fRegion = &fRegionStorage; 208 fFilter = NULL; 209 fTopLayer = NULL; 210 } 211 fLayer = NULL; 212 213 // don't bother initializing fNext 214 inc_rec(); 215 } 216 ~MCRec() { 217 fFilter->safeUnref(); 218 SkDELETE(fLayer); 219 dec_rec(); 220 } 221 222private: 223 SkMatrix fMatrixStorage; 224 SkRegion fRegionStorage; 225}; 226 227class SkDrawIter : public SkDraw { 228public: 229 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) { 230 fCanvas = canvas; 231 canvas->updateDeviceCMCache(); 232 233 fBounder = canvas->getBounder(); 234 fCurrLayer = canvas->fMCRec->fTopLayer; 235 fSkipEmptyClips = skipEmptyClips; 236 } 237 238 bool next() { 239 // skip over recs with empty clips 240 if (fSkipEmptyClips) { 241 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) { 242 fCurrLayer = fCurrLayer->fNext; 243 } 244 } 245 246 if (NULL != fCurrLayer) { 247 const DeviceCM* rec = fCurrLayer; 248 249 fMatrix = rec->fMatrix; 250 fClip = &rec->fClip; 251 fDevice = rec->fDevice; 252 fBitmap = &fDevice->accessBitmap(true); 253 fLayerX = rec->fX; 254 fLayerY = rec->fY; 255 fPaint = rec->fPaint; 256 fMVMatrix = rec->fMVMatrix; 257 fExtMatrix = rec->fExtMatrix; 258 SkDEBUGCODE(this->validate();) 259 260 fCurrLayer = rec->fNext; 261 if (fBounder) { 262 fBounder->setClip(fClip); 263 } 264 // fCurrLayer may be NULL now 265 266 fCanvas->prepareForDeviceDraw(fDevice, *fMatrix, *fClip); 267 return true; 268 } 269 return false; 270 } 271 272 int getX() const { return fLayerX; } 273 int getY() const { return fLayerY; } 274 SkDevice* getDevice() const { return fDevice; } 275 const SkMatrix& getMatrix() const { return *fMatrix; } 276 const SkRegion& getClip() const { return *fClip; } 277 const SkPaint* getPaint() const { return fPaint; } 278private: 279 SkCanvas* fCanvas; 280 const DeviceCM* fCurrLayer; 281 const SkPaint* fPaint; // May be null. 282 int fLayerX; 283 int fLayerY; 284 SkBool8 fSkipEmptyClips; 285 286 typedef SkDraw INHERITED; 287}; 288 289///////////////////////////////////////////////////////////////////////////// 290 291class AutoDrawLooper { 292public: 293 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, SkDrawFilter::Type t) 294 : fCanvas(canvas), fPaint((SkPaint*)&paint), fType(t) { 295 if ((fLooper = paint.getLooper()) != NULL) { 296 fLooper->init(canvas, (SkPaint*)&paint); 297 } else { 298 fOnce = true; 299 } 300 fFilter = canvas->getDrawFilter(); 301 fNeedFilterRestore = false; 302 } 303 304 ~AutoDrawLooper() { 305 if (fNeedFilterRestore) { 306 SkASSERT(fFilter); 307 fFilter->restore(fCanvas, fPaint, fType); 308 } 309 if (NULL != fLooper) { 310 fLooper->restore(); 311 } 312 } 313 314 bool next() { 315 SkDrawFilter* filter = fFilter; 316 317 // if we drew earlier with a filter, then we need to restore first 318 if (fNeedFilterRestore) { 319 SkASSERT(filter); 320 filter->restore(fCanvas, fPaint, fType); 321 fNeedFilterRestore = false; 322 } 323 324 bool result; 325 326 if (NULL != fLooper) { 327 result = fLooper->next(); 328 } else { 329 result = fOnce; 330 fOnce = false; 331 } 332 333 // if we're gonna draw, give the filter a chance to do its work 334 if (result && NULL != filter) { 335 fNeedFilterRestore = result = filter->filter(fCanvas, fPaint, 336 fType); 337 } 338 return result; 339 } 340 341private: 342 SkDrawLooper* fLooper; 343 SkDrawFilter* fFilter; 344 SkCanvas* fCanvas; 345 SkPaint* fPaint; 346 SkDrawFilter::Type fType; 347 bool fOnce; 348 bool fNeedFilterRestore; 349 350}; 351 352/* Stack helper for managing a SkBounder. In the destructor, if we were 353 given a bounder, we call its commit() method, signifying that we are 354 done accumulating bounds for that draw. 355*/ 356class SkAutoBounderCommit { 357public: 358 SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {} 359 ~SkAutoBounderCommit() { 360 if (NULL != fBounder) { 361 fBounder->commit(); 362 } 363 } 364private: 365 SkBounder* fBounder; 366}; 367 368#include "SkColorPriv.h" 369 370class AutoValidator { 371public: 372 AutoValidator(SkDevice* device) : fDevice(device) {} 373 ~AutoValidator() { 374#ifdef SK_DEBUG 375 const SkBitmap& bm = fDevice->accessBitmap(false); 376 if (bm.config() == SkBitmap::kARGB_4444_Config) { 377 for (int y = 0; y < bm.height(); y++) { 378 const SkPMColor16* p = bm.getAddr16(0, y); 379 for (int x = 0; x < bm.width(); x++) { 380 SkPMColor16 c = p[x]; 381 SkPMColor16Assert(c); 382 } 383 } 384 } 385#endif 386 } 387private: 388 SkDevice* fDevice; 389}; 390 391////////// macros to place around the internal draw calls ////////////////// 392 393#define ITER_BEGIN(paint, type) \ 394/* AutoValidator validator(fMCRec->fTopLayer->fDevice); */ \ 395 AutoDrawLooper looper(this, paint, type); \ 396 while (looper.next()) { \ 397 SkAutoBounderCommit ac(fBounder); \ 398 SkDrawIter iter(this); 399 400#define ITER_END } 401 402//////////////////////////////////////////////////////////////////////////// 403 404SkDevice* SkCanvas::init(SkDevice* device) { 405 fBounder = NULL; 406 fLocalBoundsCompareTypeDirty = true; 407 fLocalBoundsCompareTypeDirtyBW = true; 408 fLastDeviceToGainFocus = NULL; 409 fDeviceCMDirty = false; 410 411 fMCRec = (MCRec*)fMCStack.push_back(); 412 new (fMCRec) MCRec(NULL, 0); 413 414 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL)); 415 fMCRec->fTopLayer = fMCRec->fLayer; 416 fMCRec->fNext = NULL; 417 418 fUseExternalMatrix = false; 419 420 return this->setDevice(device); 421} 422 423SkCanvas::SkCanvas(SkDeviceFactory* factory) 424 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), 425 fDeviceFactory(factory) { 426 inc_canvas(); 427 428 if (!factory) 429 fDeviceFactory = SkNEW(SkRasterDeviceFactory); 430 431 this->init(NULL); 432} 433 434SkCanvas::SkCanvas(SkDevice* device) 435 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), 436 fDeviceFactory(device->getDeviceFactory()) { 437 inc_canvas(); 438 439 this->init(device); 440} 441 442SkCanvas::SkCanvas(const SkBitmap& bitmap) 443 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 444 inc_canvas(); 445 446 SkDevice* device = SkNEW_ARGS(SkDevice, (this, bitmap, false)); 447 fDeviceFactory = device->getDeviceFactory(); 448 this->init(device)->unref(); 449} 450 451SkCanvas::~SkCanvas() { 452 // free up the contents of our deque 453 this->restoreToCount(1); // restore everything but the last 454 this->internalRestore(); // restore the last, since we're going away 455 456 SkSafeUnref(fBounder); 457 SkDELETE(fDeviceFactory); 458 459 dec_canvas(); 460} 461 462SkBounder* SkCanvas::setBounder(SkBounder* bounder) { 463 SkRefCnt_SafeAssign(fBounder, bounder); 464 return bounder; 465} 466 467SkDrawFilter* SkCanvas::getDrawFilter() const { 468 return fMCRec->fFilter; 469} 470 471SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) { 472 SkRefCnt_SafeAssign(fMCRec->fFilter, filter); 473 return filter; 474} 475 476/////////////////////////////////////////////////////////////////////////////// 477 478SkDevice* SkCanvas::getDevice() const { 479 // return root device 480 SkDeque::Iter iter(fMCStack); 481 MCRec* rec = (MCRec*)iter.next(); 482 SkASSERT(rec && rec->fLayer); 483 return rec->fLayer->fDevice; 484} 485 486SkDevice* SkCanvas::setDevice(SkDevice* device) { 487 // return root device 488 SkDeque::Iter iter(fMCStack); 489 MCRec* rec = (MCRec*)iter.next(); 490 SkASSERT(rec && rec->fLayer); 491 SkDevice* rootDevice = rec->fLayer->fDevice; 492 493 if (rootDevice == device) { 494 return device; 495 } 496 497 /* Notify the devices that they are going in/out of scope, so they can do 498 things like lock/unlock their pixels, etc. 499 */ 500 if (device) { 501 device->lockPixels(); 502 } 503 if (rootDevice) { 504 rootDevice->unlockPixels(); 505 } 506 507 SkRefCnt_SafeAssign(rec->fLayer->fDevice, device); 508 rootDevice = device; 509 510 fDeviceCMDirty = true; 511 512 /* Now we update our initial region to have the bounds of the new device, 513 and then intersect all of the clips in our stack with these bounds, 514 to ensure that we can't draw outside of the device's bounds (and trash 515 memory). 516 517 NOTE: this is only a partial-fix, since if the new device is larger than 518 the previous one, we don't know how to "enlarge" the clips in our stack, 519 so drawing may be artificially restricted. Without keeping a history of 520 all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly 521 reconstruct the correct clips, so this approximation will have to do. 522 The caller really needs to restore() back to the base if they want to 523 accurately take advantage of the new device bounds. 524 */ 525 526 if (NULL == device) { 527 rec->fRegion->setEmpty(); 528 while ((rec = (MCRec*)iter.next()) != NULL) { 529 (void)rec->fRegion->setEmpty(); 530 } 531 } else { 532 // compute our total bounds for all devices 533 SkIRect bounds; 534 535 bounds.set(0, 0, device->width(), device->height()); 536 537 // now jam our 1st clip to be bounds, and intersect the rest with that 538 rec->fRegion->setRect(bounds); 539 while ((rec = (MCRec*)iter.next()) != NULL) { 540 (void)rec->fRegion->op(bounds, SkRegion::kIntersect_Op); 541 } 542 } 543 return device; 544} 545 546SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap, bool forLayer) { 547 SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (this, bitmap, forLayer))); 548 device->unref(); 549 return device; 550} 551 552////////////////////////////////////////////////////////////////////////////// 553 554bool SkCanvas::getViewport(SkIPoint* size) const { 555 if ((getDevice()->getDeviceCapabilities() & SkDevice::kGL_Capability) == 0) 556 return false; 557 if (size) 558 size->set(getDevice()->width(), getDevice()->height()); 559 return true; 560} 561 562bool SkCanvas::setViewport(int width, int height) { 563 if ((getDevice()->getDeviceCapabilities() & SkDevice::kGL_Capability) == 0) 564 return false; 565 566 this->setDevice(this->createDevice(SkBitmap::kARGB_8888_Config, width, height, 567 false, false))->unref(); 568 return true; 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, 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, &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 SkASSERT(device); 601 if (fLastDeviceToGainFocus != device) { 602 device->gainFocus(this, matrix, clip); 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 return saveCount; 619} 620 621int SkCanvas::save(SaveFlags flags) { 622 // call shared impl 623 return this->internalSave(flags); 624} 625 626#define C32MASK (1 << SkBitmap::kARGB_8888_Config) 627#define C16MASK (1 << SkBitmap::kRGB_565_Config) 628#define C8MASK (1 << SkBitmap::kA8_Config) 629 630static SkBitmap::Config resolve_config(SkCanvas* canvas, 631 const SkIRect& bounds, 632 SkCanvas::SaveFlags flags, 633 bool* isOpaque) { 634 *isOpaque = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) == 0; 635 636#if 0 637 // loop through and union all the configs we may draw into 638 uint32_t configMask = 0; 639 for (int i = canvas->countLayerDevices() - 1; i >= 0; --i) 640 { 641 SkDevice* device = canvas->getLayerDevice(i); 642 if (device->intersects(bounds)) 643 configMask |= 1 << device->config(); 644 } 645 646 // if the caller wants alpha or fullcolor, we can't return 565 647 if (flags & (SkCanvas::kFullColorLayer_SaveFlag | 648 SkCanvas::kHasAlphaLayer_SaveFlag)) 649 configMask &= ~C16MASK; 650 651 switch (configMask) { 652 case C8MASK: // if we only have A8, return that 653 return SkBitmap::kA8_Config; 654 655 case C16MASK: // if we only have 565, return that 656 return SkBitmap::kRGB_565_Config; 657 658 default: 659 return SkBitmap::kARGB_8888_Config; // default answer 660 } 661#else 662 return SkBitmap::kARGB_8888_Config; // default answer 663#endif 664} 665 666static bool bounds_affects_clip(SkCanvas::SaveFlags flags) { 667 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0; 668} 669 670int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, 671 SaveFlags flags) { 672 // do this before we create the layer. We don't call the public save() since 673 // that would invoke a possibly overridden virtual 674 int count = this->internalSave(flags); 675 676 fDeviceCMDirty = true; 677 678 SkIRect ir; 679 const SkIRect& clipBounds = this->getTotalClip().getBounds(); 680 if (clipBounds.isEmpty()) { 681 return count; 682 } 683 684 if (NULL != bounds) { 685 SkRect r; 686 687 this->getTotalMatrix().mapRect(&r, *bounds); 688 r.roundOut(&ir); 689 // early exit if the layer's bounds are clipped out 690 if (!ir.intersect(clipBounds)) { 691 if (bounds_affects_clip(flags)) 692 fMCRec->fRegion->setEmpty(); 693 return count; 694 } 695 } else { // no user bounds, so just use the clip 696 ir = clipBounds; 697 } 698 699 // early exit if the clip is now empty 700 if (bounds_affects_clip(flags) && 701 !fMCRec->fRegion->op(ir, SkRegion::kIntersect_Op)) { 702 return count; 703 } 704 705 bool isOpaque; 706 SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque); 707 708 SkDevice* device = this->createDevice(config, ir.width(), ir.height(), 709 isOpaque, true); 710 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint)); 711 device->unref(); 712 713 layer->fNext = fMCRec->fTopLayer; 714 fMCRec->fLayer = layer; 715 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer 716 717 return count; 718} 719 720int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha, 721 SaveFlags flags) { 722 if (0xFF == alpha) { 723 return this->saveLayer(bounds, NULL, flags); 724 } else { 725 SkPaint tmpPaint; 726 tmpPaint.setAlpha(alpha); 727 return this->saveLayer(bounds, &tmpPaint, flags); 728 } 729} 730 731void SkCanvas::restore() { 732 // check for underflow 733 if (fMCStack.count() > 1) { 734 this->internalRestore(); 735 } 736} 737 738void SkCanvas::internalRestore() { 739 SkASSERT(fMCStack.count() != 0); 740 741 fDeviceCMDirty = true; 742 fLocalBoundsCompareTypeDirty = true; 743 fLocalBoundsCompareTypeDirtyBW = true; 744 745 // reserve our layer (if any) 746 DeviceCM* layer = fMCRec->fLayer; // may be null 747 // now detach it from fMCRec so we can pop(). Gets freed after its drawn 748 fMCRec->fLayer = NULL; 749 750 // now do the normal restore() 751 fMCRec->~MCRec(); // balanced in save() 752 fMCStack.pop_back(); 753 fMCRec = (MCRec*)fMCStack.back(); 754 755 /* Time to draw the layer's offscreen. We can't call the public drawSprite, 756 since if we're being recorded, we don't want to record this (the 757 recorder will have already recorded the restore). 758 */ 759 if (NULL != layer) { 760 if (layer->fNext) { 761 this->drawDevice(layer->fDevice, layer->fX, layer->fY, 762 layer->fPaint); 763 // reset this, since drawDevice will have set it to true 764 fDeviceCMDirty = true; 765 } 766 SkDELETE(layer); 767 } 768} 769 770int SkCanvas::getSaveCount() const { 771 return fMCStack.count(); 772} 773 774void SkCanvas::restoreToCount(int count) { 775 // sanity check 776 if (count < 1) { 777 count = 1; 778 } 779 while (fMCStack.count() > count) { 780 this->restore(); 781 } 782} 783 784///////////////////////////////////////////////////////////////////////////// 785 786// can't draw it if its empty, or its too big for a fixed-point width or height 787static bool reject_bitmap(const SkBitmap& bitmap) { 788 return bitmap.width() <= 0 || bitmap.height() <= 0 || 789 bitmap.width() > 32767 || bitmap.height() > 32767; 790} 791 792void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect, 793 const SkMatrix& matrix, const SkPaint* paint) { 794 if (reject_bitmap(bitmap)) { 795 return; 796 } 797 798 if (NULL == paint) { 799 SkPaint tmpPaint; 800 this->commonDrawBitmap(bitmap, srcRect, matrix, tmpPaint); 801 } else { 802 this->commonDrawBitmap(bitmap, srcRect, matrix, *paint); 803 } 804} 805 806void SkCanvas::drawDevice(SkDevice* device, int x, int y, 807 const SkPaint* paint) { 808 SkPaint tmp; 809 if (NULL == paint) { 810 tmp.setDither(true); 811 paint = &tmp; 812 } 813 814 ITER_BEGIN(*paint, SkDrawFilter::kBitmap_Type) 815 while (iter.next()) { 816 iter.fDevice->drawDevice(iter, device, x - iter.getX(), y - iter.getY(), 817 *paint); 818 } 819 ITER_END 820} 821 822///////////////////////////////////////////////////////////////////////////// 823 824bool SkCanvas::translate(SkScalar dx, SkScalar dy) { 825 fDeviceCMDirty = true; 826 fLocalBoundsCompareTypeDirty = true; 827 fLocalBoundsCompareTypeDirtyBW = true; 828 return fMCRec->fMatrix->preTranslate(dx, dy); 829} 830 831bool SkCanvas::scale(SkScalar sx, SkScalar sy) { 832 fDeviceCMDirty = true; 833 fLocalBoundsCompareTypeDirty = true; 834 fLocalBoundsCompareTypeDirtyBW = true; 835 return fMCRec->fMatrix->preScale(sx, sy); 836} 837 838bool SkCanvas::rotate(SkScalar degrees) { 839 fDeviceCMDirty = true; 840 fLocalBoundsCompareTypeDirty = true; 841 fLocalBoundsCompareTypeDirtyBW = true; 842 return fMCRec->fMatrix->preRotate(degrees); 843} 844 845bool SkCanvas::skew(SkScalar sx, SkScalar sy) { 846 fDeviceCMDirty = true; 847 fLocalBoundsCompareTypeDirty = true; 848 fLocalBoundsCompareTypeDirtyBW = true; 849 return fMCRec->fMatrix->preSkew(sx, sy); 850} 851 852bool SkCanvas::concat(const SkMatrix& matrix) { 853 fDeviceCMDirty = true; 854 fLocalBoundsCompareTypeDirty = true; 855 fLocalBoundsCompareTypeDirtyBW = true; 856 return fMCRec->fMatrix->preConcat(matrix); 857} 858 859void SkCanvas::setMatrix(const SkMatrix& matrix) { 860 fDeviceCMDirty = true; 861 fLocalBoundsCompareTypeDirty = true; 862 fLocalBoundsCompareTypeDirtyBW = true; 863 *fMCRec->fMatrix = matrix; 864} 865 866// this is not virtual, so it must call a virtual method so that subclasses 867// will see its action 868void SkCanvas::resetMatrix() { 869 SkMatrix matrix; 870 871 matrix.reset(); 872 this->setMatrix(matrix); 873} 874 875////////////////////////////////////////////////////////////////////////////// 876 877bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) { 878 fDeviceCMDirty = true; 879 fLocalBoundsCompareTypeDirty = true; 880 fLocalBoundsCompareTypeDirtyBW = true; 881 882 if (fMCRec->fMatrix->rectStaysRect()) { 883 // for these simpler matrices, we can stay a rect ever after applying 884 // the matrix. This means we don't have to a) make a path, and b) tell 885 // the region code to scan-convert the path, only to discover that it 886 // is really just a rect. 887 SkRect r; 888 SkIRect ir; 889 890 fMCRec->fMatrix->mapRect(&r, rect); 891 r.round(&ir); 892 return fMCRec->fRegion->op(ir, op); 893 } else { 894 // since we're rotate or some such thing, we convert the rect to a path 895 // and clip against that, since it can handle any matrix. However, to 896 // avoid recursion in the case where we are subclassed (e.g. Pictures) 897 // we explicitly call "our" version of clipPath. 898 SkPath path; 899 900 path.addRect(rect); 901 return this->SkCanvas::clipPath(path, op); 902 } 903} 904 905bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op) { 906 fDeviceCMDirty = true; 907 fLocalBoundsCompareTypeDirty = true; 908 fLocalBoundsCompareTypeDirtyBW = true; 909 910 SkPath devPath; 911 path.transform(*fMCRec->fMatrix, &devPath); 912 913 if (SkRegion::kIntersect_Op == op) { 914 return fMCRec->fRegion->setPath(devPath, *fMCRec->fRegion); 915 } else { 916 SkRegion base; 917 const SkBitmap& bm = this->getDevice()->accessBitmap(false); 918 base.setRect(0, 0, bm.width(), bm.height()); 919 920 if (SkRegion::kReplace_Op == op) { 921 return fMCRec->fRegion->setPath(devPath, base); 922 } else { 923 SkRegion rgn; 924 rgn.setPath(devPath, base); 925 return fMCRec->fRegion->op(rgn, op); 926 } 927 } 928} 929 930bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 931 fDeviceCMDirty = true; 932 fLocalBoundsCompareTypeDirty = true; 933 fLocalBoundsCompareTypeDirtyBW = true; 934 935 return fMCRec->fRegion->op(rgn, op); 936} 937 938void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const { 939 SkRect r; 940 SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType : 941 fLocalBoundsCompareTypeBW; 942 943 if (!this->getClipBounds(&r, et)) { 944 rCompare.setEmpty(); 945 } else { 946 rCompare.set(SkScalarToCompareType(r.fLeft), 947 SkScalarToCompareType(r.fTop), 948 SkScalarToCompareType(r.fRight), 949 SkScalarToCompareType(r.fBottom)); 950 } 951} 952 953/* current impl ignores edgetype, and relies on 954 getLocalClipBoundsCompareType(), which always returns a value assuming 955 antialiasing (worst case) 956 */ 957bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const { 958 if (fMCRec->fRegion->isEmpty()) { 959 return true; 960 } 961 962 if (fMCRec->fMatrix->getType() & SkMatrix::kPerspective_Mask) { 963 SkRect dst; 964 fMCRec->fMatrix->mapRect(&dst, rect); 965 SkIRect idst; 966 dst.roundOut(&idst); 967 return !SkIRect::Intersects(idst, fMCRec->fRegion->getBounds()); 968 } else { 969 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et); 970 971 // for speed, do the most likely reject compares first 972 SkScalarCompareType userT = SkScalarToCompareType(rect.fTop); 973 SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom); 974 if (userT >= clipR.fBottom || userB <= clipR.fTop) { 975 return true; 976 } 977 SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft); 978 SkScalarCompareType userR = SkScalarToCompareType(rect.fRight); 979 if (userL >= clipR.fRight || userR <= clipR.fLeft) { 980 return true; 981 } 982 return false; 983 } 984} 985 986bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const { 987 return path.isEmpty() || this->quickReject(path.getBounds(), et); 988} 989 990bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const { 991 /* current impl ignores edgetype, and relies on 992 getLocalClipBoundsCompareType(), which always returns a value assuming 993 antialiasing (worst case) 994 */ 995 996 if (fMCRec->fRegion->isEmpty()) { 997 return true; 998 } 999 1000 SkScalarCompareType userT = SkScalarToCompareType(top); 1001 SkScalarCompareType userB = SkScalarToCompareType(bottom); 1002 1003 // check for invalid user Y coordinates (i.e. empty) 1004 // reed: why do we need to do this check, since it slows us down? 1005 if (userT >= userB) { 1006 return true; 1007 } 1008 1009 // check if we are above or below the local clip bounds 1010 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(); 1011 return userT >= clipR.fBottom || userB <= clipR.fTop; 1012} 1013 1014bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const { 1015 const SkRegion& clip = *fMCRec->fRegion; 1016 if (clip.isEmpty()) { 1017 if (bounds) { 1018 bounds->setEmpty(); 1019 } 1020 return false; 1021 } 1022 1023 SkMatrix inverse; 1024 // if we can't invert the CTM, we can't return local clip bounds 1025 if (!fMCRec->fMatrix->invert(&inverse)) { 1026 if (bounds) { 1027 bounds->setEmpty(); 1028 } 1029 return false; 1030 } 1031 1032 if (NULL != bounds) { 1033 SkRect r; 1034 // get the clip's bounds 1035 const SkIRect& ibounds = clip.getBounds(); 1036 // adjust it outwards if we are antialiasing 1037 int inset = (kAA_EdgeType == et); 1038 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset, 1039 ibounds.fRight + inset, ibounds.fBottom + inset); 1040 1041 // invert into local coordinates 1042 inverse.mapRect(bounds, r); 1043 } 1044 return true; 1045} 1046 1047const SkMatrix& SkCanvas::getTotalMatrix() const { 1048 return *fMCRec->fMatrix; 1049} 1050 1051const SkRegion& SkCanvas::getTotalClip() const { 1052 return *fMCRec->fRegion; 1053} 1054 1055void SkCanvas::setExternalMatrix(const SkMatrix* matrix) { 1056 if (NULL == matrix || matrix->isIdentity()) { 1057 if (fUseExternalMatrix) { 1058 fDeviceCMDirty = true; 1059 } 1060 fUseExternalMatrix = false; 1061 } else { 1062 fUseExternalMatrix = true; 1063 fDeviceCMDirty = true; // |= (fExternalMatrix != *matrix) 1064 1065 fExternalMatrix = *matrix; 1066 matrix->invert(&fExternalInverse); 1067 } 1068 1069 static bool gUseExt; 1070 if (gUseExt != fUseExternalMatrix && false) { 1071 gUseExt = fUseExternalMatrix; 1072 printf("---- fUseExternalMatrix = %d\n", fUseExternalMatrix); 1073 } 1074} 1075 1076SkDevice* SkCanvas::createDevice(SkBitmap::Config config, int width, int height, 1077 bool isOpaque, bool forLayer) { 1078 return fDeviceFactory->newDevice(this, config, width, height, isOpaque, forLayer); 1079} 1080 1081////////////////////////////////////////////////////////////////////////////// 1082// These are the virtual drawing methods 1083////////////////////////////////////////////////////////////////////////////// 1084 1085void SkCanvas::drawPaint(const SkPaint& paint) { 1086 ITER_BEGIN(paint, SkDrawFilter::kPaint_Type) 1087 1088 while (iter.next()) { 1089 iter.fDevice->drawPaint(iter, paint); 1090 } 1091 1092 ITER_END 1093} 1094 1095void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1096 const SkPaint& paint) { 1097 if ((long)count <= 0) { 1098 return; 1099 } 1100 1101 SkASSERT(pts != NULL); 1102 1103 ITER_BEGIN(paint, SkDrawFilter::kPoint_Type) 1104 1105 while (iter.next()) { 1106 iter.fDevice->drawPoints(iter, mode, count, pts, paint); 1107 } 1108 1109 ITER_END 1110} 1111 1112void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1113 if (paint.canComputeFastBounds()) { 1114 SkRect storage; 1115 if (this->quickReject(paint.computeFastBounds(r, &storage), 1116 paint2EdgeType(&paint))) { 1117 return; 1118 } 1119 } 1120 1121 ITER_BEGIN(paint, SkDrawFilter::kRect_Type) 1122 1123 while (iter.next()) { 1124 iter.fDevice->drawRect(iter, r, paint); 1125 } 1126 1127 ITER_END 1128} 1129 1130void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 1131 if (paint.canComputeFastBounds()) { 1132 SkRect storage; 1133 const SkRect& bounds = path.getBounds(); 1134 if (this->quickReject(paint.computeFastBounds(bounds, &storage), 1135 paint2EdgeType(&paint))) { 1136 return; 1137 } 1138 } 1139 1140 ITER_BEGIN(paint, SkDrawFilter::kPath_Type) 1141 1142 while (iter.next()) { 1143 iter.fDevice->drawPath(iter, path, paint); 1144 } 1145 1146 ITER_END 1147} 1148 1149void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, 1150 const SkPaint* paint) { 1151 SkDEBUGCODE(bitmap.validate();) 1152 1153 if (NULL == paint || (paint->getMaskFilter() == NULL)) { 1154 SkRect fastBounds; 1155 fastBounds.set(x, y, 1156 x + SkIntToScalar(bitmap.width()), 1157 y + SkIntToScalar(bitmap.height())); 1158 if (this->quickReject(fastBounds, paint2EdgeType(paint))) { 1159 return; 1160 } 1161 } 1162 1163 SkMatrix matrix; 1164 matrix.setTranslate(x, y); 1165 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1166} 1167 1168void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, 1169 const SkRect& dst, const SkPaint* paint) { 1170 if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) { 1171 return; 1172 } 1173 1174 // do this now, to avoid the cost of calling extract for RLE bitmaps 1175 if (this->quickReject(dst, paint2EdgeType(paint))) { 1176 return; 1177 } 1178 1179 const SkBitmap* bitmapPtr = &bitmap; 1180 1181 SkMatrix matrix; 1182 SkRect tmpSrc; 1183 if (src) { 1184 tmpSrc.set(*src); 1185 // if the extract process clipped off the top or left of the 1186 // original, we adjust for that here to get the position right. 1187 if (tmpSrc.fLeft > 0) { 1188 tmpSrc.fRight -= tmpSrc.fLeft; 1189 tmpSrc.fLeft = 0; 1190 } 1191 if (tmpSrc.fTop > 0) { 1192 tmpSrc.fBottom -= tmpSrc.fTop; 1193 tmpSrc.fTop = 0; 1194 } 1195 } else { 1196 tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()), 1197 SkIntToScalar(bitmap.height())); 1198 } 1199 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 1200 1201 // ensure that src is "valid" before we pass it to our internal routines 1202 // and to SkDevice. i.e. sure it is contained inside the original bitmap. 1203 SkIRect tmpISrc; 1204 if (src) { 1205 tmpISrc.set(0, 0, bitmap.width(), bitmap.height()); 1206 tmpISrc.intersect(*src); 1207 src = &tmpISrc; 1208 } 1209 this->internalDrawBitmap(*bitmapPtr, src, matrix, paint); 1210} 1211 1212void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 1213 const SkPaint* paint) { 1214 SkDEBUGCODE(bitmap.validate();) 1215 this->internalDrawBitmap(bitmap, NULL, matrix, paint); 1216} 1217 1218void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect, 1219 const SkMatrix& matrix, const SkPaint& paint) { 1220 SkDEBUGCODE(bitmap.validate();) 1221 1222 ITER_BEGIN(paint, SkDrawFilter::kBitmap_Type) 1223 1224 while (iter.next()) { 1225 iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, paint); 1226 } 1227 1228 ITER_END 1229} 1230 1231void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, 1232 const SkPaint* paint) { 1233 SkDEBUGCODE(bitmap.validate();) 1234 1235 if (reject_bitmap(bitmap)) { 1236 return; 1237 } 1238 1239 SkPaint tmp; 1240 if (NULL == paint) { 1241 paint = &tmp; 1242 } 1243 1244 ITER_BEGIN(*paint, SkDrawFilter::kBitmap_Type) 1245 1246 while (iter.next()) { 1247 iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(), 1248 *paint); 1249 } 1250 ITER_END 1251} 1252 1253void SkCanvas::drawText(const void* text, size_t byteLength, 1254 SkScalar x, SkScalar y, const SkPaint& paint) { 1255 ITER_BEGIN(paint, SkDrawFilter::kText_Type) 1256 1257 while (iter.next()) { 1258 iter.fDevice->drawText(iter, text, byteLength, x, y, paint); 1259 } 1260 1261 ITER_END 1262} 1263 1264void SkCanvas::drawPosText(const void* text, size_t byteLength, 1265 const SkPoint pos[], const SkPaint& paint) { 1266 ITER_BEGIN(paint, SkDrawFilter::kText_Type) 1267 1268 while (iter.next()) { 1269 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 1270 paint); 1271 } 1272 1273 ITER_END 1274} 1275 1276void SkCanvas::drawPosTextH(const void* text, size_t byteLength, 1277 const SkScalar xpos[], SkScalar constY, 1278 const SkPaint& paint) { 1279 ITER_BEGIN(paint, SkDrawFilter::kText_Type) 1280 1281 while (iter.next()) { 1282 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 1283 paint); 1284 } 1285 1286 ITER_END 1287} 1288 1289void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, 1290 const SkPath& path, const SkMatrix* matrix, 1291 const SkPaint& paint) { 1292 ITER_BEGIN(paint, SkDrawFilter::kText_Type) 1293 1294 while (iter.next()) { 1295 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 1296 matrix, paint); 1297 } 1298 1299 ITER_END 1300} 1301 1302void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 1303 const SkPoint verts[], const SkPoint texs[], 1304 const SkColor colors[], SkXfermode* xmode, 1305 const uint16_t indices[], int indexCount, 1306 const SkPaint& paint) { 1307 ITER_BEGIN(paint, SkDrawFilter::kPath_Type) 1308 1309 while (iter.next()) { 1310 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 1311 colors, xmode, indices, indexCount, paint); 1312 } 1313 1314 ITER_END 1315} 1316 1317void SkCanvas::drawData(const void* data, size_t length) { 1318 // do nothing. Subclasses may do something with the data 1319} 1320 1321////////////////////////////////////////////////////////////////////////////// 1322// These methods are NOT virtual, and therefore must call back into virtual 1323// methods, rather than actually drawing themselves. 1324////////////////////////////////////////////////////////////////////////////// 1325 1326void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 1327 SkXfermode::Mode mode) { 1328 SkPaint paint; 1329 1330 paint.setARGB(a, r, g, b); 1331 if (SkXfermode::kSrcOver_Mode != mode) { 1332 paint.setXfermodeMode(mode); 1333 } 1334 this->drawPaint(paint); 1335} 1336 1337void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 1338 SkPaint paint; 1339 1340 paint.setColor(c); 1341 if (SkXfermode::kSrcOver_Mode != mode) { 1342 paint.setXfermodeMode(mode); 1343 } 1344 this->drawPaint(paint); 1345} 1346 1347void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 1348 SkPoint pt; 1349 1350 pt.set(x, y); 1351 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1352} 1353 1354void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 1355 SkPoint pt; 1356 SkPaint paint; 1357 1358 pt.set(x, y); 1359 paint.setColor(color); 1360 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1361} 1362 1363void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 1364 const SkPaint& paint) { 1365 SkPoint pts[2]; 1366 1367 pts[0].set(x0, y0); 1368 pts[1].set(x1, y1); 1369 this->drawPoints(kLines_PointMode, 2, pts, paint); 1370} 1371 1372void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 1373 SkScalar right, SkScalar bottom, 1374 const SkPaint& paint) { 1375 SkRect r; 1376 1377 r.set(left, top, right, bottom); 1378 this->drawRect(r, paint); 1379} 1380 1381void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 1382 const SkPaint& paint) { 1383 if (radius < 0) { 1384 radius = 0; 1385 } 1386 1387 SkRect r; 1388 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 1389 1390 if (paint.canComputeFastBounds()) { 1391 SkRect storage; 1392 if (this->quickReject(paint.computeFastBounds(r, &storage), 1393 paint2EdgeType(&paint))) { 1394 return; 1395 } 1396 } 1397 1398 SkPath path; 1399 path.addOval(r); 1400 this->drawPath(path, paint); 1401} 1402 1403void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 1404 const SkPaint& paint) { 1405 if (rx > 0 && ry > 0) { 1406 if (paint.canComputeFastBounds()) { 1407 SkRect storage; 1408 if (this->quickReject(paint.computeFastBounds(r, &storage), 1409 paint2EdgeType(&paint))) { 1410 return; 1411 } 1412 } 1413 1414 SkPath path; 1415 path.addRoundRect(r, rx, ry, SkPath::kCW_Direction); 1416 this->drawPath(path, paint); 1417 } else { 1418 this->drawRect(r, paint); 1419 } 1420} 1421 1422void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1423 if (paint.canComputeFastBounds()) { 1424 SkRect storage; 1425 if (this->quickReject(paint.computeFastBounds(oval, &storage), 1426 paint2EdgeType(&paint))) { 1427 return; 1428 } 1429 } 1430 1431 SkPath path; 1432 path.addOval(oval); 1433 this->drawPath(path, paint); 1434} 1435 1436void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 1437 SkScalar sweepAngle, bool useCenter, 1438 const SkPaint& paint) { 1439 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 1440 this->drawOval(oval, paint); 1441 } else { 1442 SkPath path; 1443 if (useCenter) { 1444 path.moveTo(oval.centerX(), oval.centerY()); 1445 } 1446 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 1447 if (useCenter) { 1448 path.close(); 1449 } 1450 this->drawPath(path, paint); 1451 } 1452} 1453 1454void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 1455 const SkPath& path, SkScalar hOffset, 1456 SkScalar vOffset, const SkPaint& paint) { 1457 SkMatrix matrix; 1458 1459 matrix.setTranslate(hOffset, vOffset); 1460 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 1461} 1462 1463/////////////////////////////////////////////////////////////////////////////// 1464 1465void SkCanvas::drawPicture(SkPicture& picture) { 1466 int saveCount = save(); 1467 picture.draw(this); 1468 restoreToCount(saveCount); 1469} 1470 1471void SkCanvas::drawShape(SkShape* shape) { 1472 // shape baseclass takes care of save/restore 1473 shape->draw(this); 1474} 1475 1476/////////////////////////////////////////////////////////////////////////////// 1477/////////////////////////////////////////////////////////////////////////////// 1478 1479SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 1480 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); 1481 1482 SkASSERT(canvas); 1483 1484 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 1485 fDone = !fImpl->next(); 1486} 1487 1488SkCanvas::LayerIter::~LayerIter() { 1489 fImpl->~SkDrawIter(); 1490} 1491 1492void SkCanvas::LayerIter::next() { 1493 fDone = !fImpl->next(); 1494} 1495 1496SkDevice* SkCanvas::LayerIter::device() const { 1497 return fImpl->getDevice(); 1498} 1499 1500const SkMatrix& SkCanvas::LayerIter::matrix() const { 1501 return fImpl->getMatrix(); 1502} 1503 1504const SkPaint& SkCanvas::LayerIter::paint() const { 1505 const SkPaint* paint = fImpl->getPaint(); 1506 if (NULL == paint) { 1507 paint = &fDefaultPaint; 1508 } 1509 return *paint; 1510} 1511 1512const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 1513int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 1514int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 1515 1516