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