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