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