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