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