SkCanvas.cpp revision 8d84fac294682647694b0d2d8a87ac2bd19b6aab
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();) 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 SkSafeRef(factory); 413 if (!factory) 414 fDeviceFactory = SkNEW(SkRasterDeviceFactory); 415 416 this->init(NULL); 417} 418 419SkCanvas::SkCanvas(SkDevice* device) 420 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), 421 fDeviceFactory(device->getDeviceFactory()) { 422 inc_canvas(); 423 424 this->init(device); 425} 426 427SkCanvas::SkCanvas(const SkBitmap& bitmap) 428 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 429 inc_canvas(); 430 431 SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap)); 432 fDeviceFactory = device->getDeviceFactory(); 433 this->init(device)->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 SkSafeUnref(fDeviceFactory); 443 444 dec_canvas(); 445} 446 447SkBounder* SkCanvas::setBounder(SkBounder* bounder) { 448 SkRefCnt_SafeAssign(fBounder, bounder); 449 return bounder; 450} 451 452SkDrawFilter* SkCanvas::getDrawFilter() const { 453 return fMCRec->fFilter; 454} 455 456SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) { 457 SkRefCnt_SafeAssign(fMCRec->fFilter, filter); 458 return filter; 459} 460 461/////////////////////////////////////////////////////////////////////////////// 462 463SkDevice* SkCanvas::getDevice() const { 464 // return root device 465 SkDeque::Iter iter(fMCStack); 466 MCRec* rec = (MCRec*)iter.next(); 467 SkASSERT(rec && rec->fLayer); 468 return rec->fLayer->fDevice; 469} 470 471SkDevice* SkCanvas::setDevice(SkDevice* device) { 472 // return root device 473 SkDeque::Iter iter(fMCStack); 474 MCRec* rec = (MCRec*)iter.next(); 475 SkASSERT(rec && rec->fLayer); 476 SkDevice* rootDevice = rec->fLayer->fDevice; 477 478 if (rootDevice == device) { 479 return device; 480 } 481 482 /* Notify the devices that they are going in/out of scope, so they can do 483 things like lock/unlock their pixels, etc. 484 */ 485 if (device) { 486 device->lockPixels(); 487 } 488 if (rootDevice) { 489 rootDevice->unlockPixels(); 490 } 491 492 SkRefCnt_SafeAssign(rec->fLayer->fDevice, device); 493 rootDevice = device; 494 495 fDeviceCMDirty = true; 496 497 /* Now we update our initial region to have the bounds of the new device, 498 and then intersect all of the clips in our stack with these bounds, 499 to ensure that we can't draw outside of the device's bounds (and trash 500 memory). 501 502 NOTE: this is only a partial-fix, since if the new device is larger than 503 the previous one, we don't know how to "enlarge" the clips in our stack, 504 so drawing may be artificially restricted. Without keeping a history of 505 all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly 506 reconstruct the correct clips, so this approximation will have to do. 507 The caller really needs to restore() back to the base if they want to 508 accurately take advantage of the new device bounds. 509 */ 510 511 if (NULL == device) { 512 rec->fRegion->setEmpty(); 513 while ((rec = (MCRec*)iter.next()) != NULL) { 514 (void)rec->fRegion->setEmpty(); 515 } 516 } else { 517 // compute our total bounds for all devices 518 SkIRect bounds; 519 520 bounds.set(0, 0, device->width(), device->height()); 521 522 // now jam our 1st clip to be bounds, and intersect the rest with that 523 rec->fRegion->setRect(bounds); 524 while ((rec = (MCRec*)iter.next()) != NULL) { 525 (void)rec->fRegion->op(bounds, SkRegion::kIntersect_Op); 526 } 527 } 528 return device; 529} 530 531SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) { 532 SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap))); 533 device->unref(); 534 return device; 535} 536 537////////////////////////////////////////////////////////////////////////////// 538 539bool SkCanvas::getViewport(SkIPoint* size) const { 540 if ((fDeviceFactory->getDeviceCapabilities() 541 & SkDeviceFactory::kGL_Capability) == 0) 542 return false; 543 if (size) 544 size->set(getDevice()->width(), getDevice()->height()); 545 return true; 546} 547 548bool SkCanvas::setViewport(int width, int height) { 549 if ((fDeviceFactory->getDeviceCapabilities() 550 & SkDeviceFactory::kGL_Capability) == 0) 551 return false; 552 this->setDevice(createDevice(SkBitmap::kARGB_8888_Config, width, height, 553 false, false))->unref(); 554 return true; 555} 556 557void SkCanvas::updateDeviceCMCache() { 558 if (fDeviceCMDirty) { 559 const SkMatrix& totalMatrix = this->getTotalMatrix(); 560 const SkRegion& totalClip = this->getTotalClip(); 561 DeviceCM* layer = fMCRec->fTopLayer; 562 563 if (NULL == layer->fNext) { // only one layer 564 layer->updateMC(totalMatrix, totalClip, NULL); 565 } else { 566 SkRegion clip; 567 clip = totalClip; // make a copy 568 do { 569 layer->updateMC(totalMatrix, clip, &clip); 570 } while ((layer = layer->fNext) != NULL); 571 } 572 fDeviceCMDirty = false; 573 } 574} 575 576void SkCanvas::prepareForDeviceDraw(SkDevice* device) { 577 SkASSERT(device); 578 if (fLastDeviceToGainFocus != device) { 579 device->gainFocus(this); 580 fLastDeviceToGainFocus = device; 581 } 582} 583 584/////////////////////////////////////////////////////////////////////////////// 585 586int SkCanvas::internalSave(SaveFlags flags) { 587 int saveCount = this->getSaveCount(); // record this before the actual save 588 589 MCRec* newTop = (MCRec*)fMCStack.push_back(); 590 new (newTop) MCRec(fMCRec, flags); // balanced in restore() 591 592 newTop->fNext = fMCRec; 593 fMCRec = newTop; 594 595 return saveCount; 596} 597 598int SkCanvas::save(SaveFlags flags) { 599 // call shared impl 600 return this->internalSave(flags); 601} 602 603#define C32MASK (1 << SkBitmap::kARGB_8888_Config) 604#define C16MASK (1 << SkBitmap::kRGB_565_Config) 605#define C8MASK (1 << SkBitmap::kA8_Config) 606 607static SkBitmap::Config resolve_config(SkCanvas* canvas, 608 const SkIRect& bounds, 609 SkCanvas::SaveFlags flags, 610 bool* isOpaque) { 611 *isOpaque = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) == 0; 612 613#if 0 614 // loop through and union all the configs we may draw into 615 uint32_t configMask = 0; 616 for (int i = canvas->countLayerDevices() - 1; i >= 0; --i) 617 { 618 SkDevice* device = canvas->getLayerDevice(i); 619 if (device->intersects(bounds)) 620 configMask |= 1 << device->config(); 621 } 622 623 // if the caller wants alpha or fullcolor, we can't return 565 624 if (flags & (SkCanvas::kFullColorLayer_SaveFlag | 625 SkCanvas::kHasAlphaLayer_SaveFlag)) 626 configMask &= ~C16MASK; 627 628 switch (configMask) { 629 case C8MASK: // if we only have A8, return that 630 return SkBitmap::kA8_Config; 631 632 case C16MASK: // if we only have 565, return that 633 return SkBitmap::kRGB_565_Config; 634 635 default: 636 return SkBitmap::kARGB_8888_Config; // default answer 637 } 638#else 639 return SkBitmap::kARGB_8888_Config; // default answer 640#endif 641} 642 643static bool bounds_affects_clip(SkCanvas::SaveFlags flags) { 644 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0; 645} 646 647int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, 648 SaveFlags flags) { 649 // do this before we create the layer. We don't call the public save() since 650 // that would invoke a possibly overridden virtual 651 int count = this->internalSave(flags); 652 653 fDeviceCMDirty = true; 654 655 SkIRect ir; 656 const SkIRect& clipBounds = this->getTotalClip().getBounds(); 657 658 if (NULL != bounds) { 659 SkRect r; 660 661 this->getTotalMatrix().mapRect(&r, *bounds); 662 r.roundOut(&ir); 663 // early exit if the layer's bounds are clipped out 664 if (!ir.intersect(clipBounds)) { 665 if (bounds_affects_clip(flags)) 666 fMCRec->fRegion->setEmpty(); 667 return count; 668 } 669 } else { // no user bounds, so just use the clip 670 ir = clipBounds; 671 } 672 673 // early exit if the clip is now empty 674 if (bounds_affects_clip(flags) && 675 !fMCRec->fRegion->op(ir, SkRegion::kIntersect_Op)) { 676 return count; 677 } 678 679 bool isOpaque; 680 SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque); 681 682 SkDevice* device = this->createDevice(config, ir.width(), ir.height(), 683 isOpaque, true); 684 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint)); 685 device->unref(); 686 687 layer->fNext = fMCRec->fTopLayer; 688 fMCRec->fLayer = layer; 689 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer 690 691 return count; 692} 693 694int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha, 695 SaveFlags flags) { 696 if (0xFF == alpha) { 697 return this->saveLayer(bounds, NULL, flags); 698 } else { 699 SkPaint tmpPaint; 700 tmpPaint.setAlpha(alpha); 701 return this->saveLayer(bounds, &tmpPaint, flags); 702 } 703} 704 705void SkCanvas::restore() { 706 // check for underflow 707 if (fMCStack.count() > 1) { 708 this->internalRestore(); 709 } 710} 711 712void SkCanvas::internalRestore() { 713 SkASSERT(fMCStack.count() != 0); 714 715 fDeviceCMDirty = true; 716 fLocalBoundsCompareTypeDirty = true; 717 fLocalBoundsCompareTypeDirtyBW = true; 718 719 // reserve our layer (if any) 720 DeviceCM* layer = fMCRec->fLayer; // may be null 721 // now detach it from fMCRec so we can pop(). Gets freed after its drawn 722 fMCRec->fLayer = NULL; 723 724 // now do the normal restore() 725 fMCRec->~MCRec(); // balanced in save() 726 fMCStack.pop_back(); 727 fMCRec = (MCRec*)fMCStack.back(); 728 729 /* Time to draw the layer's offscreen. We can't call the public drawSprite, 730 since if we're being recorded, we don't want to record this (the 731 recorder will have already recorded the restore). 732 */ 733 if (NULL != layer) { 734 if (layer->fNext) { 735 this->drawDevice(layer->fDevice, layer->fX, layer->fY, 736 layer->fPaint); 737 // reset this, since drawDevice will have set it to true 738 fDeviceCMDirty = true; 739 } 740 SkDELETE(layer); 741 } 742} 743 744int SkCanvas::getSaveCount() const { 745 return fMCStack.count(); 746} 747 748void SkCanvas::restoreToCount(int count) { 749 // sanity check 750 if (count < 1) { 751 count = 1; 752 } 753 while (fMCStack.count() > count) { 754 this->restore(); 755 } 756} 757 758///////////////////////////////////////////////////////////////////////////// 759 760// can't draw it if its empty, or its too big for a fixed-point width or height 761static bool reject_bitmap(const SkBitmap& bitmap) { 762 return bitmap.width() <= 0 || bitmap.height() <= 0 || 763 bitmap.width() > 32767 || bitmap.height() > 32767; 764} 765 766void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, 767 const SkMatrix& matrix, const SkPaint* paint) { 768 if (reject_bitmap(bitmap)) { 769 return; 770 } 771 772 if (NULL == paint) { 773 SkPaint tmpPaint; 774 this->commonDrawBitmap(bitmap, matrix, tmpPaint); 775 } else { 776 this->commonDrawBitmap(bitmap, matrix, *paint); 777 } 778} 779 780void SkCanvas::drawDevice(SkDevice* device, int x, int y, 781 const SkPaint* paint) { 782 SkPaint tmp; 783 if (NULL == paint) { 784 tmp.setDither(true); 785 paint = &tmp; 786 } 787 788 ITER_BEGIN(*paint, SkDrawFilter::kBitmap_Type) 789 while (iter.next()) { 790 iter.fDevice->drawDevice(iter, device, x - iter.getX(), y - iter.getY(), 791 *paint); 792 } 793 ITER_END 794} 795 796///////////////////////////////////////////////////////////////////////////// 797 798bool SkCanvas::translate(SkScalar dx, SkScalar dy) { 799 fDeviceCMDirty = true; 800 fLocalBoundsCompareTypeDirty = true; 801 fLocalBoundsCompareTypeDirtyBW = true; 802 return fMCRec->fMatrix->preTranslate(dx, dy); 803} 804 805bool SkCanvas::scale(SkScalar sx, SkScalar sy) { 806 fDeviceCMDirty = true; 807 fLocalBoundsCompareTypeDirty = true; 808 fLocalBoundsCompareTypeDirtyBW = true; 809 return fMCRec->fMatrix->preScale(sx, sy); 810} 811 812bool SkCanvas::rotate(SkScalar degrees) { 813 fDeviceCMDirty = true; 814 fLocalBoundsCompareTypeDirty = true; 815 fLocalBoundsCompareTypeDirtyBW = true; 816 return fMCRec->fMatrix->preRotate(degrees); 817} 818 819bool SkCanvas::skew(SkScalar sx, SkScalar sy) { 820 fDeviceCMDirty = true; 821 fLocalBoundsCompareTypeDirty = true; 822 fLocalBoundsCompareTypeDirtyBW = true; 823 return fMCRec->fMatrix->preSkew(sx, sy); 824} 825 826bool SkCanvas::concat(const SkMatrix& matrix) { 827 fDeviceCMDirty = true; 828 fLocalBoundsCompareTypeDirty = true; 829 fLocalBoundsCompareTypeDirtyBW = true; 830 return fMCRec->fMatrix->preConcat(matrix); 831} 832 833void SkCanvas::setMatrix(const SkMatrix& matrix) { 834 fDeviceCMDirty = true; 835 fLocalBoundsCompareTypeDirty = true; 836 fLocalBoundsCompareTypeDirtyBW = true; 837 *fMCRec->fMatrix = matrix; 838} 839 840// this is not virtual, so it must call a virtual method so that subclasses 841// will see its action 842void SkCanvas::resetMatrix() { 843 SkMatrix matrix; 844 845 matrix.reset(); 846 this->setMatrix(matrix); 847} 848 849////////////////////////////////////////////////////////////////////////////// 850 851bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) { 852 fDeviceCMDirty = true; 853 fLocalBoundsCompareTypeDirty = true; 854 fLocalBoundsCompareTypeDirtyBW = true; 855 856 if (fMCRec->fMatrix->rectStaysRect()) { 857 // for these simpler matrices, we can stay a rect ever after applying 858 // the matrix. This means we don't have to a) make a path, and b) tell 859 // the region code to scan-convert the path, only to discover that it 860 // is really just a rect. 861 SkRect r; 862 SkIRect ir; 863 864 fMCRec->fMatrix->mapRect(&r, rect); 865 r.round(&ir); 866 return fMCRec->fRegion->op(ir, op); 867 } else { 868 // since we're rotate or some such thing, we convert the rect to a path 869 // and clip against that, since it can handle any matrix. However, to 870 // avoid recursion in the case where we are subclassed (e.g. Pictures) 871 // we explicitly call "our" version of clipPath. 872 SkPath path; 873 874 path.addRect(rect); 875 return this->SkCanvas::clipPath(path, op); 876 } 877} 878 879bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op) { 880 fDeviceCMDirty = true; 881 fLocalBoundsCompareTypeDirty = true; 882 fLocalBoundsCompareTypeDirtyBW = true; 883 884 SkPath devPath; 885 path.transform(*fMCRec->fMatrix, &devPath); 886 887 if (SkRegion::kIntersect_Op == op) { 888 return fMCRec->fRegion->setPath(devPath, *fMCRec->fRegion); 889 } else { 890 SkRegion base; 891 const SkBitmap& bm = this->getDevice()->accessBitmap(false); 892 base.setRect(0, 0, bm.width(), bm.height()); 893 894 if (SkRegion::kReplace_Op == op) { 895 return fMCRec->fRegion->setPath(devPath, base); 896 } else { 897 SkRegion rgn; 898 rgn.setPath(devPath, base); 899 return fMCRec->fRegion->op(rgn, op); 900 } 901 } 902} 903 904bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 905 fDeviceCMDirty = true; 906 fLocalBoundsCompareTypeDirty = true; 907 fLocalBoundsCompareTypeDirtyBW = true; 908 909 return fMCRec->fRegion->op(rgn, op); 910} 911 912void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const { 913 SkRect r; 914 SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType : 915 fLocalBoundsCompareTypeBW; 916 917 if (!this->getClipBounds(&r, et)) { 918 rCompare.setEmpty(); 919 } else { 920 rCompare.set(SkScalarToCompareType(r.fLeft), 921 SkScalarToCompareType(r.fTop), 922 SkScalarToCompareType(r.fRight), 923 SkScalarToCompareType(r.fBottom)); 924 } 925} 926 927/* current impl ignores edgetype, and relies on 928 getLocalClipBoundsCompareType(), which always returns a value assuming 929 antialiasing (worst case) 930 */ 931bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const { 932 if (fMCRec->fRegion->isEmpty()) { 933 return true; 934 } 935 936 if (fMCRec->fMatrix->getType() & SkMatrix::kPerspective_Mask) { 937 SkRect dst; 938 fMCRec->fMatrix->mapRect(&dst, rect); 939 SkIRect idst; 940 dst.roundOut(&idst); 941 return !SkIRect::Intersects(idst, fMCRec->fRegion->getBounds()); 942 } else { 943 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et); 944 945 // for speed, do the most likely reject compares first 946 SkScalarCompareType userT = SkScalarToCompareType(rect.fTop); 947 SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom); 948 if (userT >= clipR.fBottom || userB <= clipR.fTop) { 949 return true; 950 } 951 SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft); 952 SkScalarCompareType userR = SkScalarToCompareType(rect.fRight); 953 if (userL >= clipR.fRight || userR <= clipR.fLeft) { 954 return true; 955 } 956 return false; 957 } 958} 959 960bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const { 961 return path.isEmpty() || this->quickReject(path.getBounds(), et); 962} 963 964bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const { 965 /* current impl ignores edgetype, and relies on 966 getLocalClipBoundsCompareType(), which always returns a value assuming 967 antialiasing (worst case) 968 */ 969 970 if (fMCRec->fRegion->isEmpty()) { 971 return true; 972 } 973 974 SkScalarCompareType userT = SkScalarToCompareType(top); 975 SkScalarCompareType userB = SkScalarToCompareType(bottom); 976 977 // check for invalid user Y coordinates (i.e. empty) 978 // reed: why do we need to do this check, since it slows us down? 979 if (userT >= userB) { 980 return true; 981 } 982 983 // check if we are above or below the local clip bounds 984 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(); 985 return userT >= clipR.fBottom || userB <= clipR.fTop; 986} 987 988bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const { 989 const SkRegion& clip = *fMCRec->fRegion; 990 if (clip.isEmpty()) { 991 if (bounds) { 992 bounds->setEmpty(); 993 } 994 return false; 995 } 996 997 SkMatrix inverse; 998 // if we can't invert the CTM, we can't return local clip bounds 999 if (!fMCRec->fMatrix->invert(&inverse)) { 1000 if (bounds) { 1001 bounds->setEmpty(); 1002 } 1003 return false; 1004 } 1005 1006 if (NULL != bounds) { 1007 SkRect r; 1008 // get the clip's bounds 1009 const SkIRect& ibounds = clip.getBounds(); 1010 // adjust it outwards if we are antialiasing 1011 int inset = (kAA_EdgeType == et); 1012 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset, 1013 ibounds.fRight + inset, ibounds.fBottom + inset); 1014 1015 // invert into local coordinates 1016 inverse.mapRect(bounds, r); 1017 } 1018 return true; 1019} 1020 1021const SkMatrix& SkCanvas::getTotalMatrix() const { 1022 return *fMCRec->fMatrix; 1023} 1024 1025const SkRegion& SkCanvas::getTotalClip() const { 1026 return *fMCRec->fRegion; 1027} 1028 1029/////////////////////////////////////////////////////////////////////////////// 1030 1031SkDevice* SkCanvas::createDevice(SkBitmap::Config config, int width, 1032 int height, bool isOpaque, bool isForLayer) { 1033 1034 return fDeviceFactory->newDevice(config, width, height, isOpaque, 1035 isForLayer); 1036} 1037 1038////////////////////////////////////////////////////////////////////////////// 1039// These are the virtual drawing methods 1040////////////////////////////////////////////////////////////////////////////// 1041 1042void SkCanvas::drawPaint(const SkPaint& paint) { 1043 ITER_BEGIN(paint, SkDrawFilter::kPaint_Type) 1044 1045 while (iter.next()) { 1046 iter.fDevice->drawPaint(iter, paint); 1047 } 1048 1049 ITER_END 1050} 1051 1052void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1053 const SkPaint& paint) { 1054 if ((long)count <= 0) { 1055 return; 1056 } 1057 1058 SkASSERT(pts != NULL); 1059 1060 ITER_BEGIN(paint, SkDrawFilter::kPoint_Type) 1061 1062 while (iter.next()) { 1063 iter.fDevice->drawPoints(iter, mode, count, pts, paint); 1064 } 1065 1066 ITER_END 1067} 1068 1069void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1070 if (paint.canComputeFastBounds()) { 1071 SkRect storage; 1072 if (this->quickReject(paint.computeFastBounds(r, &storage), 1073 paint2EdgeType(&paint))) { 1074 return; 1075 } 1076 } 1077 1078 ITER_BEGIN(paint, SkDrawFilter::kRect_Type) 1079 1080 while (iter.next()) { 1081 iter.fDevice->drawRect(iter, r, paint); 1082 } 1083 1084 ITER_END 1085} 1086 1087void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 1088 if (paint.canComputeFastBounds()) { 1089 SkRect storage; 1090 const SkRect& bounds = path.getBounds(); 1091 if (this->quickReject(paint.computeFastBounds(bounds, &storage), 1092 paint2EdgeType(&paint))) { 1093 return; 1094 } 1095 } 1096 1097 ITER_BEGIN(paint, SkDrawFilter::kPath_Type) 1098 1099 while (iter.next()) { 1100 iter.fDevice->drawPath(iter, path, paint); 1101 } 1102 1103 ITER_END 1104} 1105 1106void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, 1107 const SkPaint* paint) { 1108 SkDEBUGCODE(bitmap.validate();) 1109 1110 if (NULL == paint || (paint->getMaskFilter() == NULL)) { 1111 SkRect fastBounds; 1112 fastBounds.set(x, y, 1113 x + SkIntToScalar(bitmap.width()), 1114 y + SkIntToScalar(bitmap.height())); 1115 if (this->quickReject(fastBounds, paint2EdgeType(paint))) { 1116 return; 1117 } 1118 } 1119 1120 SkMatrix matrix; 1121 matrix.setTranslate(x, y); 1122 this->internalDrawBitmap(bitmap, matrix, paint); 1123} 1124 1125void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, 1126 const SkRect& dst, const SkPaint* paint) { 1127 if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) { 1128 return; 1129 } 1130 1131 // do this now, to avoid the cost of calling extract for RLE bitmaps 1132 if (this->quickReject(dst, paint2EdgeType(paint))) { 1133 return; 1134 } 1135 1136 SkBitmap tmp; // storage if we need a subset of bitmap 1137 const SkBitmap* bitmapPtr = &bitmap; 1138 1139 if (NULL != src) { 1140 if (!bitmap.extractSubset(&tmp, *src)) { 1141 return; // extraction failed 1142 } 1143 bitmapPtr = &tmp; 1144 } 1145 1146 SkMatrix matrix; 1147 SkRect tmpSrc; 1148 if (src) { 1149 tmpSrc.set(*src); 1150 // if the extract process clipped off the top or left of the 1151 // original, we adjust for that here to get the position right. 1152 if (tmpSrc.fLeft > 0) { 1153 tmpSrc.fRight -= tmpSrc.fLeft; 1154 tmpSrc.fLeft = 0; 1155 } 1156 if (tmpSrc.fTop > 0) { 1157 tmpSrc.fBottom -= tmpSrc.fTop; 1158 tmpSrc.fTop = 0; 1159 } 1160 } else { 1161 tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()), 1162 SkIntToScalar(bitmap.height())); 1163 } 1164 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 1165 this->internalDrawBitmap(*bitmapPtr, matrix, paint); 1166} 1167 1168void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 1169 const SkPaint* paint) { 1170 SkDEBUGCODE(bitmap.validate();) 1171 this->internalDrawBitmap(bitmap, matrix, paint); 1172} 1173 1174void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, 1175 const SkPaint& paint) { 1176 SkDEBUGCODE(bitmap.validate();) 1177 1178 ITER_BEGIN(paint, SkDrawFilter::kBitmap_Type) 1179 1180 while (iter.next()) { 1181 iter.fDevice->drawBitmap(iter, bitmap, matrix, paint); 1182 } 1183 1184 ITER_END 1185} 1186 1187void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, 1188 const SkPaint* paint) { 1189 SkDEBUGCODE(bitmap.validate();) 1190 1191 if (reject_bitmap(bitmap)) { 1192 return; 1193 } 1194 1195 SkPaint tmp; 1196 if (NULL == paint) { 1197 paint = &tmp; 1198 } 1199 1200 ITER_BEGIN(*paint, SkDrawFilter::kBitmap_Type) 1201 1202 while (iter.next()) { 1203 iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(), 1204 *paint); 1205 } 1206 ITER_END 1207} 1208 1209void SkCanvas::drawText(const void* text, size_t byteLength, 1210 SkScalar x, SkScalar y, const SkPaint& paint) { 1211 ITER_BEGIN(paint, SkDrawFilter::kText_Type) 1212 1213 while (iter.next()) { 1214 iter.fDevice->drawText(iter, text, byteLength, x, y, paint); 1215 } 1216 1217 ITER_END 1218} 1219 1220void SkCanvas::drawPosText(const void* text, size_t byteLength, 1221 const SkPoint pos[], const SkPaint& paint) { 1222 ITER_BEGIN(paint, SkDrawFilter::kText_Type) 1223 1224 while (iter.next()) { 1225 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 1226 paint); 1227 } 1228 1229 ITER_END 1230} 1231 1232void SkCanvas::drawPosTextH(const void* text, size_t byteLength, 1233 const SkScalar xpos[], SkScalar constY, 1234 const SkPaint& paint) { 1235 ITER_BEGIN(paint, SkDrawFilter::kText_Type) 1236 1237 while (iter.next()) { 1238 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 1239 paint); 1240 } 1241 1242 ITER_END 1243} 1244 1245void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, 1246 const SkPath& path, const SkMatrix* matrix, 1247 const SkPaint& paint) { 1248 ITER_BEGIN(paint, SkDrawFilter::kText_Type) 1249 1250 while (iter.next()) { 1251 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 1252 matrix, paint); 1253 } 1254 1255 ITER_END 1256} 1257 1258void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 1259 const SkPoint verts[], const SkPoint texs[], 1260 const SkColor colors[], SkXfermode* xmode, 1261 const uint16_t indices[], int indexCount, 1262 const SkPaint& paint) { 1263 ITER_BEGIN(paint, SkDrawFilter::kPath_Type) 1264 1265 while (iter.next()) { 1266 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 1267 colors, xmode, indices, indexCount, paint); 1268 } 1269 1270 ITER_END 1271} 1272 1273void SkCanvas::drawData(const void* data, size_t length) { 1274 // do nothing. Subclasses may do something with the data 1275} 1276 1277////////////////////////////////////////////////////////////////////////////// 1278// These methods are NOT virtual, and therefore must call back into virtual 1279// methods, rather than actually drawing themselves. 1280////////////////////////////////////////////////////////////////////////////// 1281 1282void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 1283 SkXfermode::Mode mode) { 1284 SkPaint paint; 1285 1286 paint.setARGB(a, r, g, b); 1287 if (SkXfermode::kSrcOver_Mode != mode) { 1288 paint.setXfermodeMode(mode); 1289 } 1290 this->drawPaint(paint); 1291} 1292 1293void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 1294 SkPaint paint; 1295 1296 paint.setColor(c); 1297 if (SkXfermode::kSrcOver_Mode != mode) { 1298 paint.setXfermodeMode(mode); 1299 } 1300 this->drawPaint(paint); 1301} 1302 1303void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 1304 SkPoint pt; 1305 1306 pt.set(x, y); 1307 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1308} 1309 1310void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 1311 SkPoint pt; 1312 SkPaint paint; 1313 1314 pt.set(x, y); 1315 paint.setColor(color); 1316 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1317} 1318 1319void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 1320 const SkPaint& paint) { 1321 SkPoint pts[2]; 1322 1323 pts[0].set(x0, y0); 1324 pts[1].set(x1, y1); 1325 this->drawPoints(kLines_PointMode, 2, pts, paint); 1326} 1327 1328void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 1329 SkScalar right, SkScalar bottom, 1330 const SkPaint& paint) { 1331 SkRect r; 1332 1333 r.set(left, top, right, bottom); 1334 this->drawRect(r, paint); 1335} 1336 1337void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 1338 const SkPaint& paint) { 1339 if (radius < 0) { 1340 radius = 0; 1341 } 1342 1343 SkRect r; 1344 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 1345 1346 if (paint.canComputeFastBounds()) { 1347 SkRect storage; 1348 if (this->quickReject(paint.computeFastBounds(r, &storage), 1349 paint2EdgeType(&paint))) { 1350 return; 1351 } 1352 } 1353 1354 SkPath path; 1355 path.addOval(r); 1356 this->drawPath(path, paint); 1357} 1358 1359void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 1360 const SkPaint& paint) { 1361 if (rx > 0 && ry > 0) { 1362 if (paint.canComputeFastBounds()) { 1363 SkRect storage; 1364 if (this->quickReject(paint.computeFastBounds(r, &storage), 1365 paint2EdgeType(&paint))) { 1366 return; 1367 } 1368 } 1369 1370 SkPath path; 1371 path.addRoundRect(r, rx, ry, SkPath::kCW_Direction); 1372 this->drawPath(path, paint); 1373 } else { 1374 this->drawRect(r, paint); 1375 } 1376} 1377 1378void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1379 if (paint.canComputeFastBounds()) { 1380 SkRect storage; 1381 if (this->quickReject(paint.computeFastBounds(oval, &storage), 1382 paint2EdgeType(&paint))) { 1383 return; 1384 } 1385 } 1386 1387 SkPath path; 1388 path.addOval(oval); 1389 this->drawPath(path, paint); 1390} 1391 1392void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 1393 SkScalar sweepAngle, bool useCenter, 1394 const SkPaint& paint) { 1395 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 1396 this->drawOval(oval, paint); 1397 } else { 1398 SkPath path; 1399 if (useCenter) { 1400 path.moveTo(oval.centerX(), oval.centerY()); 1401 } 1402 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 1403 if (useCenter) { 1404 path.close(); 1405 } 1406 this->drawPath(path, paint); 1407 } 1408} 1409 1410void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 1411 const SkPath& path, SkScalar hOffset, 1412 SkScalar vOffset, const SkPaint& paint) { 1413 SkMatrix matrix; 1414 1415 matrix.setTranslate(hOffset, vOffset); 1416 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 1417} 1418 1419/////////////////////////////////////////////////////////////////////////////// 1420 1421void SkCanvas::drawPicture(SkPicture& picture) { 1422 int saveCount = save(); 1423 picture.draw(this); 1424 restoreToCount(saveCount); 1425} 1426 1427void SkCanvas::drawShape(SkShape* shape) { 1428 // shape baseclass takes care of save/restore 1429 shape->draw(this); 1430} 1431 1432/////////////////////////////////////////////////////////////////////////////// 1433/////////////////////////////////////////////////////////////////////////////// 1434 1435SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 1436 // need COMPILE_TIME_ASSERT 1437 SkASSERT(sizeof(fStorage) >= sizeof(SkDrawIter)); 1438 1439 SkASSERT(canvas); 1440 1441 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 1442 fDone = !fImpl->next(); 1443} 1444 1445SkCanvas::LayerIter::~LayerIter() { 1446 fImpl->~SkDrawIter(); 1447} 1448 1449void SkCanvas::LayerIter::next() { 1450 fDone = !fImpl->next(); 1451} 1452 1453SkDevice* SkCanvas::LayerIter::device() const { 1454 return fImpl->getDevice(); 1455} 1456 1457const SkMatrix& SkCanvas::LayerIter::matrix() const { 1458 return fImpl->getMatrix(); 1459} 1460 1461const SkPaint& SkCanvas::LayerIter::paint() const { 1462 const SkPaint* paint = fImpl->getPaint(); 1463 if (NULL == paint) { 1464 paint = &fDefaultPaint; 1465 } 1466 return *paint; 1467} 1468 1469const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 1470int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 1471int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 1472 1473