SkCanvas.cpp revision 6f09709519b79a1159f3826645f1c5fbc101ee11
1/* 2 * Copyright 2008 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 9#include "SkCanvas.h" 10#include "SkCanvasPriv.h" 11#include "SkBitmapDevice.h" 12#include "SkDeviceImageFilterProxy.h" 13#include "SkDraw.h" 14#include "SkDrawFilter.h" 15#include "SkDrawLooper.h" 16#include "SkMetaData.h" 17#include "SkPathOps.h" 18#include "SkPatchUtils.h" 19#include "SkPicture.h" 20#include "SkRasterClip.h" 21#include "SkRRect.h" 22#include "SkSmallAllocator.h" 23#include "SkSurface_Base.h" 24#include "SkTemplates.h" 25#include "SkTextBlob.h" 26#include "SkTextFormatParams.h" 27#include "SkTLazy.h" 28#include "SkUtils.h" 29 30#if SK_SUPPORT_GPU 31#include "GrRenderTarget.h" 32#endif 33 34// experimental for faster tiled drawing... 35//#define SK_ENABLE_CLIP_QUICKREJECT 36 37//#define SK_TRACE_SAVERESTORE 38 39#ifdef SK_TRACE_SAVERESTORE 40 static int gLayerCounter; 41 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); } 42 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); } 43 44 static int gRecCounter; 45 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); } 46 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); } 47 48 static int gCanvasCounter; 49 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); } 50 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); } 51#else 52 #define inc_layer() 53 #define dec_layer() 54 #define inc_rec() 55 #define dec_rec() 56 #define inc_canvas() 57 #define dec_canvas() 58#endif 59 60typedef SkTLazy<SkPaint> SkLazyPaint; 61 62void SkCanvas::predrawNotify() { 63 if (fSurfaceBase) { 64 fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode); 65 } 66} 67 68/////////////////////////////////////////////////////////////////////////////// 69 70/* This is the record we keep for each SkBaseDevice that the user installs. 71 The clip/matrix/proc are fields that reflect the top of the save/restore 72 stack. Whenever the canvas changes, it marks a dirty flag, and then before 73 these are used (assuming we're not on a layer) we rebuild these cache 74 values: they reflect the top of the save stack, but translated and clipped 75 by the device's XY offset and bitmap-bounds. 76*/ 77struct DeviceCM { 78 DeviceCM* fNext; 79 SkBaseDevice* fDevice; 80 SkRasterClip fClip; 81 const SkMatrix* fMatrix; 82 SkPaint* fPaint; // may be null (in the future) 83 84 DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas) 85 : fNext(NULL) { 86 if (device) { 87 device->ref(); 88 device->onAttachToCanvas(canvas); 89 } 90 fDevice = device; 91 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL; 92 } 93 94 ~DeviceCM() { 95 if (fDevice) { 96 fDevice->onDetachFromCanvas(); 97 fDevice->unref(); 98 } 99 SkDELETE(fPaint); 100 } 101 102 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip, 103 const SkClipStack& clipStack, SkRasterClip* updateClip) { 104 int x = fDevice->getOrigin().x(); 105 int y = fDevice->getOrigin().y(); 106 int width = fDevice->width(); 107 int height = fDevice->height(); 108 109 if ((x | y) == 0) { 110 fMatrix = &totalMatrix; 111 fClip = totalClip; 112 } else { 113 fMatrixStorage = totalMatrix; 114 fMatrixStorage.postTranslate(SkIntToScalar(-x), 115 SkIntToScalar(-y)); 116 fMatrix = &fMatrixStorage; 117 118 totalClip.translate(-x, -y, &fClip); 119 } 120 121 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op); 122 123 // intersect clip, but don't translate it (yet) 124 125 if (updateClip) { 126 updateClip->op(SkIRect::MakeXYWH(x, y, width, height), 127 SkRegion::kDifference_Op); 128 } 129 130 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack); 131 132#ifdef SK_DEBUG 133 if (!fClip.isEmpty()) { 134 SkIRect deviceR; 135 deviceR.set(0, 0, width, height); 136 SkASSERT(deviceR.contains(fClip.getBounds())); 137 } 138#endif 139 } 140 141private: 142 SkMatrix fMatrixStorage; 143}; 144 145/* This is the record we keep for each save/restore level in the stack. 146 Since a level optionally copies the matrix and/or stack, we have pointers 147 for these fields. If the value is copied for this level, the copy is 148 stored in the ...Storage field, and the pointer points to that. If the 149 value is not copied for this level, we ignore ...Storage, and just point 150 at the corresponding value in the previous level in the stack. 151*/ 152class SkCanvas::MCRec { 153public: 154 SkMatrix fMatrix; 155 SkRasterClip fRasterClip; 156 SkDrawFilter* fFilter; // the current filter (or null) 157 158 DeviceCM* fLayer; 159 /* If there are any layers in the stack, this points to the top-most 160 one that is at or below this level in the stack (so we know what 161 bitmap/device to draw into from this level. This value is NOT 162 reference counted, since the real owner is either our fLayer field, 163 or a previous one in a lower level.) 164 */ 165 DeviceCM* fTopLayer; 166 167 MCRec(const MCRec* prev) { 168 if (prev) { 169 fMatrix = prev->fMatrix; 170 fRasterClip = prev->fRasterClip; 171 172 fFilter = prev->fFilter; 173 SkSafeRef(fFilter); 174 175 fTopLayer = prev->fTopLayer; 176 } else { // no prev 177 fMatrix.reset(); 178 fFilter = NULL; 179 fTopLayer = NULL; 180 } 181 fLayer = NULL; 182 183 // don't bother initializing fNext 184 inc_rec(); 185 } 186 ~MCRec() { 187 SkSafeUnref(fFilter); 188 SkDELETE(fLayer); 189 dec_rec(); 190 } 191}; 192 193class SkDrawIter : public SkDraw { 194public: 195 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) { 196 canvas = canvas->canvasForDrawIter(); 197 fCanvas = canvas; 198 canvas->updateDeviceCMCache(); 199 200 fClipStack = &canvas->fClipStack; 201 fCurrLayer = canvas->fMCRec->fTopLayer; 202 fSkipEmptyClips = skipEmptyClips; 203 } 204 205 bool next() { 206 // skip over recs with empty clips 207 if (fSkipEmptyClips) { 208 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) { 209 fCurrLayer = fCurrLayer->fNext; 210 } 211 } 212 213 const DeviceCM* rec = fCurrLayer; 214 if (rec && rec->fDevice) { 215 216 fMatrix = rec->fMatrix; 217 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW(); 218 fRC = &rec->fClip; 219 fDevice = rec->fDevice; 220 fBitmap = &fDevice->accessBitmap(true); 221 fPaint = rec->fPaint; 222 SkDEBUGCODE(this->validate();) 223 224 fCurrLayer = rec->fNext; 225 // fCurrLayer may be NULL now 226 227 return true; 228 } 229 return false; 230 } 231 232 SkBaseDevice* getDevice() const { return fDevice; } 233 int getX() const { return fDevice->getOrigin().x(); } 234 int getY() const { return fDevice->getOrigin().y(); } 235 const SkMatrix& getMatrix() const { return *fMatrix; } 236 const SkRegion& getClip() const { return *fClip; } 237 const SkPaint* getPaint() const { return fPaint; } 238 239private: 240 SkCanvas* fCanvas; 241 const DeviceCM* fCurrLayer; 242 const SkPaint* fPaint; // May be null. 243 SkBool8 fSkipEmptyClips; 244 245 typedef SkDraw INHERITED; 246}; 247 248///////////////////////////////////////////////////////////////////////////// 249 250class AutoDrawLooper { 251public: 252 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, 253 bool skipLayerForImageFilter = false, 254 const SkRect* bounds = NULL) : fOrigPaint(paint) { 255 fCanvas = canvas; 256 fFilter = canvas->getDrawFilter(); 257 fPaint = NULL; 258 fSaveCount = canvas->getSaveCount(); 259 fDoClearImageFilter = false; 260 fDone = false; 261 262 if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) { 263 SkPaint tmp; 264 tmp.setImageFilter(fOrigPaint.getImageFilter()); 265 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag, 266 true, SkCanvas::kFullLayer_SaveLayerStrategy); 267 // we'll clear the imageFilter for the actual draws in next(), so 268 // it will only be applied during the restore(). 269 fDoClearImageFilter = true; 270 } 271 272 if (SkDrawLooper* looper = paint.getLooper()) { 273 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>( 274 looper->contextSize()); 275 fLooperContext = looper->createContext(canvas, buffer); 276 fIsSimple = false; 277 } else { 278 fLooperContext = NULL; 279 // can we be marked as simple? 280 fIsSimple = !fFilter && !fDoClearImageFilter; 281 } 282 } 283 284 ~AutoDrawLooper() { 285 if (fDoClearImageFilter) { 286 fCanvas->internalRestore(); 287 } 288 SkASSERT(fCanvas->getSaveCount() == fSaveCount); 289 } 290 291 const SkPaint& paint() const { 292 SkASSERT(fPaint); 293 return *fPaint; 294 } 295 296 bool next(SkDrawFilter::Type drawType) { 297 if (fDone) { 298 return false; 299 } else if (fIsSimple) { 300 fDone = true; 301 fPaint = &fOrigPaint; 302 return !fPaint->nothingToDraw(); 303 } else { 304 return this->doNext(drawType); 305 } 306 } 307 308private: 309 SkLazyPaint fLazyPaint; 310 SkCanvas* fCanvas; 311 const SkPaint& fOrigPaint; 312 SkDrawFilter* fFilter; 313 const SkPaint* fPaint; 314 int fSaveCount; 315 bool fDoClearImageFilter; 316 bool fDone; 317 bool fIsSimple; 318 SkDrawLooper::Context* fLooperContext; 319 SkSmallAllocator<1, 32> fLooperContextAllocator; 320 321 bool doNext(SkDrawFilter::Type drawType); 322}; 323 324bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) { 325 fPaint = NULL; 326 SkASSERT(!fIsSimple); 327 SkASSERT(fLooperContext || fFilter || fDoClearImageFilter); 328 329 SkPaint* paint = fLazyPaint.set(fOrigPaint); 330 331 if (fDoClearImageFilter) { 332 paint->setImageFilter(NULL); 333 } 334 335 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) { 336 fDone = true; 337 return false; 338 } 339 if (fFilter) { 340 if (!fFilter->filter(paint, drawType)) { 341 fDone = true; 342 return false; 343 } 344 if (NULL == fLooperContext) { 345 // no looper means we only draw once 346 fDone = true; 347 } 348 } 349 fPaint = paint; 350 351 // if we only came in here for the imagefilter, mark us as done 352 if (!fLooperContext && !fFilter) { 353 fDone = true; 354 } 355 356 // call this after any possible paint modifiers 357 if (fPaint->nothingToDraw()) { 358 fPaint = NULL; 359 return false; 360 } 361 return true; 362} 363 364#include "SkColorPriv.h" 365 366////////// macros to place around the internal draw calls ////////////////// 367 368#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \ 369 this->predrawNotify(); \ 370 AutoDrawLooper looper(this, paint, true); \ 371 while (looper.next(type)) { \ 372 SkDrawIter iter(this); 373 374#define LOOPER_BEGIN(paint, type, bounds) \ 375 this->predrawNotify(); \ 376 AutoDrawLooper looper(this, paint, false, bounds); \ 377 while (looper.next(type)) { \ 378 SkDrawIter iter(this); 379 380#define LOOPER_END } 381 382//////////////////////////////////////////////////////////////////////////// 383 384SkBaseDevice* SkCanvas::init(SkBaseDevice* device) { 385 fCachedLocalClipBounds.setEmpty(); 386 fCachedLocalClipBoundsDirty = true; 387 fAllowSoftClip = true; 388 fAllowSimplifyClip = false; 389 fDeviceCMDirty = true; 390 fSaveLayerCount = 0; 391 fCullCount = 0; 392 fMetaData = NULL; 393 394 fMCRec = (MCRec*)fMCStack.push_back(); 395 new (fMCRec) MCRec(NULL); 396 397 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL)); 398 fMCRec->fTopLayer = fMCRec->fLayer; 399 400 fSurfaceBase = NULL; 401 402 if (device) { 403 device->onAttachToCanvas(this); 404 fMCRec->fLayer->fDevice = SkRef(device); 405 fMCRec->fRasterClip.setRect(SkIRect::MakeWH(device->width(), device->height())); 406 } 407 return device; 408} 409 410SkCanvas::SkCanvas() 411 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 412{ 413 inc_canvas(); 414 415 this->init(NULL); 416} 417 418SkCanvas::SkCanvas(int width, int height) 419 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 420{ 421 inc_canvas(); 422 423 SkBitmap bitmap; 424 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height)); 425 this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref(); 426} 427 428SkCanvas::SkCanvas(SkBaseDevice* device) 429 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 430{ 431 inc_canvas(); 432 433 this->init(device); 434} 435 436SkCanvas::SkCanvas(const SkBitmap& bitmap) 437 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 438{ 439 inc_canvas(); 440 441 this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref(); 442} 443 444SkCanvas::~SkCanvas() { 445 // free up the contents of our deque 446 this->restoreToCount(1); // restore everything but the last 447 SkASSERT(0 == fSaveLayerCount); 448 449 this->internalRestore(); // restore the last, since we're going away 450 451 SkDELETE(fMetaData); 452 453 dec_canvas(); 454} 455 456SkDrawFilter* SkCanvas::getDrawFilter() const { 457 return fMCRec->fFilter; 458} 459 460SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) { 461 SkRefCnt_SafeAssign(fMCRec->fFilter, filter); 462 return filter; 463} 464 465SkMetaData& SkCanvas::getMetaData() { 466 // metadata users are rare, so we lazily allocate it. If that changes we 467 // can decide to just make it a field in the device (rather than a ptr) 468 if (NULL == fMetaData) { 469 fMetaData = new SkMetaData; 470 } 471 return *fMetaData; 472} 473 474/////////////////////////////////////////////////////////////////////////////// 475 476void SkCanvas::flush() { 477 SkBaseDevice* device = this->getDevice(); 478 if (device) { 479 device->flush(); 480 } 481} 482 483SkISize SkCanvas::getTopLayerSize() const { 484 SkBaseDevice* d = this->getTopDevice(); 485 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0); 486} 487 488SkIPoint SkCanvas::getTopLayerOrigin() const { 489 SkBaseDevice* d = this->getTopDevice(); 490 return d ? d->getOrigin() : SkIPoint::Make(0, 0); 491} 492 493SkISize SkCanvas::getBaseLayerSize() const { 494 SkBaseDevice* d = this->getDevice(); 495 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0); 496} 497 498SkBaseDevice* SkCanvas::getDevice() const { 499 // return root device 500 MCRec* rec = (MCRec*) fMCStack.front(); 501 SkASSERT(rec && rec->fLayer); 502 return rec->fLayer->fDevice; 503} 504 505SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const { 506 if (updateMatrixClip) { 507 const_cast<SkCanvas*>(this)->updateDeviceCMCache(); 508 } 509 return fMCRec->fTopLayer->fDevice; 510} 511 512SkBaseDevice* SkCanvas::setRootDevice(SkBaseDevice* device) { 513 // return root device 514 SkDeque::F2BIter iter(fMCStack); 515 MCRec* rec = (MCRec*)iter.next(); 516 SkASSERT(rec && rec->fLayer); 517 SkBaseDevice* rootDevice = rec->fLayer->fDevice; 518 519 if (rootDevice == device) { 520 return device; 521 } 522 523 if (device) { 524 device->onAttachToCanvas(this); 525 } 526 if (rootDevice) { 527 rootDevice->onDetachFromCanvas(); 528 } 529 530 SkRefCnt_SafeAssign(rec->fLayer->fDevice, device); 531 rootDevice = device; 532 533 fDeviceCMDirty = true; 534 535 /* Now we update our initial region to have the bounds of the new device, 536 and then intersect all of the clips in our stack with these bounds, 537 to ensure that we can't draw outside of the device's bounds (and trash 538 memory). 539 540 NOTE: this is only a partial-fix, since if the new device is larger than 541 the previous one, we don't know how to "enlarge" the clips in our stack, 542 so drawing may be artificially restricted. Without keeping a history of 543 all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly 544 reconstruct the correct clips, so this approximation will have to do. 545 The caller really needs to restore() back to the base if they want to 546 accurately take advantage of the new device bounds. 547 */ 548 549 SkIRect bounds; 550 if (device) { 551 bounds.set(0, 0, device->width(), device->height()); 552 } else { 553 bounds.setEmpty(); 554 } 555 // now jam our 1st clip to be bounds, and intersect the rest with that 556 rec->fRasterClip.setRect(bounds); 557 while ((rec = (MCRec*)iter.next()) != NULL) { 558 (void)rec->fRasterClip.op(bounds, SkRegion::kIntersect_Op); 559 } 560 561 return device; 562} 563 564bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) { 565 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) { 566 return false; 567 } 568 569 bool weAllocated = false; 570 if (NULL == bitmap->pixelRef()) { 571 if (!bitmap->tryAllocPixels()) { 572 return false; 573 } 574 weAllocated = true; 575 } 576 577 SkBitmap bm(*bitmap); 578 bm.lockPixels(); 579 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) { 580 return true; 581 } 582 583 if (weAllocated) { 584 bitmap->setPixelRef(NULL); 585 } 586 return false; 587} 588 589bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) { 590 SkIRect r = srcRect; 591 const SkISize size = this->getBaseLayerSize(); 592 if (!r.intersect(0, 0, size.width(), size.height())) { 593 bitmap->reset(); 594 return false; 595 } 596 597 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) { 598 // bitmap will already be reset. 599 return false; 600 } 601 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) { 602 bitmap->reset(); 603 return false; 604 } 605 return true; 606} 607 608bool SkCanvas::readPixels(const SkImageInfo& origInfo, void* dstP, size_t rowBytes, int x, int y) { 609 switch (origInfo.colorType()) { 610 case kUnknown_SkColorType: 611 case kIndex_8_SkColorType: 612 return false; 613 default: 614 break; 615 } 616 if (NULL == dstP || rowBytes < origInfo.minRowBytes()) { 617 return false; 618 } 619 if (0 == origInfo.width() || 0 == origInfo.height()) { 620 return false; 621 } 622 623 SkBaseDevice* device = this->getDevice(); 624 if (!device) { 625 return false; 626 } 627 628 const SkISize size = this->getBaseLayerSize(); 629 SkIRect srcR = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height()); 630 if (!srcR.intersect(0, 0, size.width(), size.height())) { 631 return false; 632 } 633 634 // the intersect may have shrunk info's logical size 635 const SkImageInfo info = origInfo.makeWH(srcR.width(), srcR.height()); 636 637 // if x or y are negative, then we have to adjust pixels 638 if (x > 0) { 639 x = 0; 640 } 641 if (y > 0) { 642 y = 0; 643 } 644 // here x,y are either 0 or negative 645 dstP = ((char*)dstP - y * rowBytes - x * info.bytesPerPixel()); 646 647 // The device can assert that the requested area is always contained in its bounds 648 return device->readPixels(info, dstP, rowBytes, srcR.x(), srcR.y()); 649} 650 651bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) { 652 if (bitmap.getTexture()) { 653 return false; 654 } 655 SkBitmap bm(bitmap); 656 bm.lockPixels(); 657 if (bm.getPixels()) { 658 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y); 659 } 660 return false; 661} 662 663bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes, 664 int x, int y) { 665 switch (origInfo.colorType()) { 666 case kUnknown_SkColorType: 667 case kIndex_8_SkColorType: 668 return false; 669 default: 670 break; 671 } 672 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) { 673 return false; 674 } 675 676 const SkISize size = this->getBaseLayerSize(); 677 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height()); 678 if (!target.intersect(0, 0, size.width(), size.height())) { 679 return false; 680 } 681 682 SkBaseDevice* device = this->getDevice(); 683 if (!device) { 684 return false; 685 } 686 687 // the intersect may have shrunk info's logical size 688 const SkImageInfo info = origInfo.makeWH(target.width(), target.height()); 689 690 // if x or y are negative, then we have to adjust pixels 691 if (x > 0) { 692 x = 0; 693 } 694 if (y > 0) { 695 y = 0; 696 } 697 // here x,y are either 0 or negative 698 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel()); 699 700 // Tell our owning surface to bump its generation ID 701 this->predrawNotify(); 702 703 // The device can assert that the requested area is always contained in its bounds 704 return device->writePixels(info, pixels, rowBytes, target.x(), target.y()); 705} 706 707SkCanvas* SkCanvas::canvasForDrawIter() { 708 return this; 709} 710 711////////////////////////////////////////////////////////////////////////////// 712 713void SkCanvas::updateDeviceCMCache() { 714 if (fDeviceCMDirty) { 715 const SkMatrix& totalMatrix = this->getTotalMatrix(); 716 const SkRasterClip& totalClip = fMCRec->fRasterClip; 717 DeviceCM* layer = fMCRec->fTopLayer; 718 719 if (NULL == layer->fNext) { // only one layer 720 layer->updateMC(totalMatrix, totalClip, fClipStack, NULL); 721 } else { 722 SkRasterClip clip(totalClip); 723 do { 724 layer->updateMC(totalMatrix, clip, fClipStack, &clip); 725 } while ((layer = layer->fNext) != NULL); 726 } 727 fDeviceCMDirty = false; 728 } 729} 730 731/////////////////////////////////////////////////////////////////////////////// 732 733int SkCanvas::internalSave() { 734 int saveCount = this->getSaveCount(); // record this before the actual save 735 736 MCRec* newTop = (MCRec*)fMCStack.push_back(); 737 new (newTop) MCRec(fMCRec); // balanced in restore() 738 fMCRec = newTop; 739 740 fClipStack.save(); 741 742 return saveCount; 743} 744 745int SkCanvas::save() { 746 this->willSave(); 747 return this->internalSave(); 748} 749 750static bool bounds_affects_clip(SkCanvas::SaveFlags flags) { 751#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG 752 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0; 753#else 754 return true; 755#endif 756} 757 758bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, 759 SkIRect* intersection, const SkImageFilter* imageFilter) { 760 SkIRect clipBounds; 761 SkRegion::Op op = SkRegion::kIntersect_Op; 762 if (!this->getClipDeviceBounds(&clipBounds)) { 763 return false; 764 } 765 766 if (imageFilter) { 767 imageFilter->filterBounds(clipBounds, fMCRec->fMatrix, &clipBounds); 768 // Filters may grow the bounds beyond the device bounds. 769 op = SkRegion::kReplace_Op; 770 } 771 SkIRect ir; 772 if (bounds) { 773 SkRect r; 774 775 this->getTotalMatrix().mapRect(&r, *bounds); 776 r.roundOut(&ir); 777 // early exit if the layer's bounds are clipped out 778 if (!ir.intersect(clipBounds)) { 779 if (bounds_affects_clip(flags)) { 780 fMCRec->fRasterClip.setEmpty(); 781 } 782 return false; 783 } 784 } else { // no user bounds, so just use the clip 785 ir = clipBounds; 786 } 787 788 if (bounds_affects_clip(flags)) { 789 fClipStack.clipDevRect(ir, op); 790 // early exit if the clip is now empty 791 if (!fMCRec->fRasterClip.op(ir, op)) { 792 return false; 793 } 794 } 795 796 if (intersection) { 797 *intersection = ir; 798 } 799 return true; 800} 801 802int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) { 803 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag); 804 return this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, false, strategy); 805} 806 807int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, 808 SaveFlags flags) { 809 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags); 810 return this->internalSaveLayer(bounds, paint, flags, false, strategy); 811} 812 813int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags, 814 bool justForImageFilter, SaveLayerStrategy strategy) { 815#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG 816 flags |= kClipToLayer_SaveFlag; 817#endif 818 819 // do this before we create the layer. We don't call the public save() since 820 // that would invoke a possibly overridden virtual 821 int count = this->internalSave(); 822 823 fDeviceCMDirty = true; 824 825 SkIRect ir; 826 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) { 827 return count; 828 } 829 830 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about 831 // the clipRectBounds() call above? 832 if (kNoLayer_SaveLayerStrategy == strategy) { 833 return count; 834 } 835 836 // Kill the imagefilter if our device doesn't allow it 837 SkLazyPaint lazyP; 838 if (paint && paint->getImageFilter()) { 839 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) { 840 if (justForImageFilter) { 841 // early exit if the layer was just for the imageFilter 842 return count; 843 } 844 SkPaint* p = lazyP.set(*paint); 845 p->setImageFilter(NULL); 846 paint = p; 847 } 848 } 849 850 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag); 851 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(), 852 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); 853 854 SkBaseDevice* device; 855 if (paint && paint->getImageFilter()) { 856 device = this->getDevice(); 857 if (device) { 858 device = device->createCompatibleDevice(info); 859 } 860 } else { 861 device = this->createLayerDevice(info); 862 } 863 if (NULL == device) { 864 SkDebugf("Unable to create device for layer."); 865 return count; 866 } 867 868 device->setOrigin(ir.fLeft, ir.fTop); 869 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint, this)); 870 device->unref(); 871 872 layer->fNext = fMCRec->fTopLayer; 873 fMCRec->fLayer = layer; 874 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer 875 876 fSaveLayerCount += 1; 877 return count; 878} 879 880int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) { 881 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag); 882} 883 884int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha, 885 SaveFlags flags) { 886 if (0xFF == alpha) { 887 return this->saveLayer(bounds, NULL, flags); 888 } else { 889 SkPaint tmpPaint; 890 tmpPaint.setAlpha(alpha); 891 return this->saveLayer(bounds, &tmpPaint, flags); 892 } 893} 894 895void SkCanvas::restore() { 896 // check for underflow 897 if (fMCStack.count() > 1) { 898 this->willRestore(); 899 this->internalRestore(); 900 this->didRestore(); 901 } 902} 903 904void SkCanvas::internalRestore() { 905 SkASSERT(fMCStack.count() != 0); 906 907 fDeviceCMDirty = true; 908 fCachedLocalClipBoundsDirty = true; 909 910 fClipStack.restore(); 911 912 // reserve our layer (if any) 913 DeviceCM* layer = fMCRec->fLayer; // may be null 914 // now detach it from fMCRec so we can pop(). Gets freed after its drawn 915 fMCRec->fLayer = NULL; 916 917 // now do the normal restore() 918 fMCRec->~MCRec(); // balanced in save() 919 fMCStack.pop_back(); 920 fMCRec = (MCRec*)fMCStack.back(); 921 922 /* Time to draw the layer's offscreen. We can't call the public drawSprite, 923 since if we're being recorded, we don't want to record this (the 924 recorder will have already recorded the restore). 925 */ 926 if (layer) { 927 if (layer->fNext) { 928 const SkIPoint& origin = layer->fDevice->getOrigin(); 929 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), 930 layer->fPaint); 931 // reset this, since internalDrawDevice will have set it to true 932 fDeviceCMDirty = true; 933 934 SkASSERT(fSaveLayerCount > 0); 935 fSaveLayerCount -= 1; 936 } 937 SkDELETE(layer); 938 } 939} 940 941int SkCanvas::getSaveCount() const { 942 return fMCStack.count(); 943} 944 945void SkCanvas::restoreToCount(int count) { 946 // sanity check 947 if (count < 1) { 948 count = 1; 949 } 950 951 int n = this->getSaveCount() - count; 952 for (int i = 0; i < n; ++i) { 953 this->restore(); 954 } 955} 956 957bool SkCanvas::isDrawingToLayer() const { 958 return fSaveLayerCount > 0; 959} 960 961SkSurface* SkCanvas::newSurface(const SkImageInfo& info) { 962 return this->onNewSurface(info); 963} 964 965SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info) { 966 SkBaseDevice* dev = this->getDevice(); 967 return dev ? dev->newSurface(info) : NULL; 968} 969 970SkImageInfo SkCanvas::imageInfo() const { 971 SkBaseDevice* dev = this->getDevice(); 972 if (dev) { 973 return dev->imageInfo(); 974 } else { 975 return SkImageInfo::MakeUnknown(0, 0); 976 } 977} 978 979const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) { 980 return this->onPeekPixels(info, rowBytes); 981} 982 983const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) { 984 SkBaseDevice* dev = this->getDevice(); 985 return dev ? dev->peekPixels(info, rowBytes) : NULL; 986} 987 988void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) { 989 void* pixels = this->onAccessTopLayerPixels(info, rowBytes); 990 if (pixels && origin) { 991 *origin = this->getTopDevice(false)->getOrigin(); 992 } 993 return pixels; 994} 995 996void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) { 997 SkBaseDevice* dev = this->getTopDevice(); 998 return dev ? dev->accessPixels(info, rowBytes) : NULL; 999} 1000 1001SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) { 1002 fAddr = canvas->peekPixels(&fInfo, &fRowBytes); 1003 if (NULL == fAddr) { 1004 fInfo = canvas->imageInfo(); 1005 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) { 1006 return; // failure, fAddr is NULL 1007 } 1008 if (!canvas->readPixels(&fBitmap, 0, 0)) { 1009 return; // failure, fAddr is NULL 1010 } 1011 fAddr = fBitmap.getPixels(); 1012 fRowBytes = fBitmap.rowBytes(); 1013 } 1014 SkASSERT(fAddr); // success 1015} 1016 1017bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const { 1018 if (fAddr) { 1019 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes); 1020 } else { 1021 bitmap->reset(); 1022 return false; 1023 } 1024} 1025 1026void SkCanvas::onPushCull(const SkRect& cullRect) { 1027 // do nothing. Subclasses may do something 1028} 1029 1030void SkCanvas::onPopCull() { 1031 // do nothing. Subclasses may do something 1032} 1033 1034///////////////////////////////////////////////////////////////////////////// 1035#ifdef SK_DEBUG 1036// Ensure that cull rects are monotonically nested in device space. 1037void SkCanvas::validateCull(const SkIRect& devCull) { 1038 if (fCullStack.isEmpty() 1039 || devCull.isEmpty() 1040 || fCullStack.top().contains(devCull)) { 1041 return; 1042 } 1043 1044 SkDEBUGF(("Invalid cull: [%d %d %d %d] (previous cull: [%d %d %d %d])\n", 1045 devCull.x(), devCull.y(), devCull.right(), devCull.bottom(), 1046 fCullStack.top().x(), fCullStack.top().y(), 1047 fCullStack.top().right(), fCullStack.top().bottom())); 1048 1049#ifdef ASSERT_NESTED_CULLING 1050 SkDEBUGFAIL("Invalid cull."); 1051#endif 1052} 1053#endif 1054 1055void SkCanvas::pushCull(const SkRect& cullRect) { 1056 ++fCullCount; 1057 this->onPushCull(cullRect); 1058 1059#ifdef SK_DEBUG 1060 // Map the cull rect into device space. 1061 SkRect mappedCull; 1062 this->getTotalMatrix().mapRect(&mappedCull, cullRect); 1063 1064 // Take clipping into account. 1065 SkIRect devClip, devCull; 1066 mappedCull.roundOut(&devCull); 1067 this->getClipDeviceBounds(&devClip); 1068 if (!devCull.intersect(devClip)) { 1069 devCull.setEmpty(); 1070 } 1071 1072 this->validateCull(devCull); 1073 fCullStack.push(devCull); // balanced in popCull 1074#endif 1075} 1076 1077void SkCanvas::popCull() { 1078 SkASSERT(fCullStack.count() == fCullCount); 1079 1080 if (fCullCount > 0) { 1081 --fCullCount; 1082 this->onPopCull(); 1083 1084 SkDEBUGCODE(fCullStack.pop()); 1085 } 1086} 1087 1088///////////////////////////////////////////////////////////////////////////// 1089 1090void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, 1091 const SkMatrix& matrix, const SkPaint* paint) { 1092 if (bitmap.drawsNothing()) { 1093 return; 1094 } 1095 1096 SkLazyPaint lazy; 1097 if (NULL == paint) { 1098 paint = lazy.init(); 1099 } 1100 1101 SkDEBUGCODE(bitmap.validate();) 1102 1103 SkRect storage; 1104 const SkRect* bounds = NULL; 1105 if (paint && paint->canComputeFastBounds()) { 1106 bitmap.getBounds(&storage); 1107 matrix.mapRect(&storage); 1108 bounds = &paint->computeFastBounds(storage, &storage); 1109 } 1110 1111 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) 1112 1113 while (iter.next()) { 1114 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint()); 1115 } 1116 1117 LOOPER_END 1118} 1119 1120void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, 1121 const SkPaint* paint) { 1122 SkPaint tmp; 1123 if (NULL == paint) { 1124 tmp.setDither(true); 1125 paint = &tmp; 1126 } 1127 1128 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 1129 while (iter.next()) { 1130 SkBaseDevice* dstDev = iter.fDevice; 1131 paint = &looper.paint(); 1132 SkImageFilter* filter = paint->getImageFilter(); 1133 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 1134 if (filter && !dstDev->canHandleImageFilter(filter)) { 1135 SkDeviceImageFilterProxy proxy(dstDev); 1136 SkBitmap dst; 1137 SkIPoint offset = SkIPoint::Make(0, 0); 1138 const SkBitmap& src = srcDev->accessBitmap(false); 1139 SkMatrix matrix = *iter.fMatrix; 1140 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y())); 1141 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height()); 1142 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache()); 1143 SkImageFilter::Context ctx(matrix, clipBounds, cache.get()); 1144 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) { 1145 SkPaint tmpUnfiltered(*paint); 1146 tmpUnfiltered.setImageFilter(NULL); 1147 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(), 1148 tmpUnfiltered); 1149 } 1150 } else { 1151 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint); 1152 } 1153 } 1154 LOOPER_END 1155} 1156 1157void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, 1158 const SkPaint* paint) { 1159 if (bitmap.drawsNothing()) { 1160 return; 1161 } 1162 SkDEBUGCODE(bitmap.validate();) 1163 1164 SkPaint tmp; 1165 if (NULL == paint) { 1166 paint = &tmp; 1167 } 1168 1169 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 1170 1171 while (iter.next()) { 1172 paint = &looper.paint(); 1173 SkImageFilter* filter = paint->getImageFilter(); 1174 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 1175 if (filter && !iter.fDevice->canHandleImageFilter(filter)) { 1176 SkDeviceImageFilterProxy proxy(iter.fDevice); 1177 SkBitmap dst; 1178 SkIPoint offset = SkIPoint::Make(0, 0); 1179 SkMatrix matrix = *iter.fMatrix; 1180 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y())); 1181 SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height()); 1182 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache()); 1183 SkImageFilter::Context ctx(matrix, clipBounds, cache.get()); 1184 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) { 1185 SkPaint tmpUnfiltered(*paint); 1186 tmpUnfiltered.setImageFilter(NULL); 1187 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(), 1188 tmpUnfiltered); 1189 } 1190 } else { 1191 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint); 1192 } 1193 } 1194 LOOPER_END 1195} 1196 1197///////////////////////////////////////////////////////////////////////////// 1198void SkCanvas::translate(SkScalar dx, SkScalar dy) { 1199 SkMatrix m; 1200 m.setTranslate(dx, dy); 1201 this->concat(m); 1202} 1203 1204void SkCanvas::scale(SkScalar sx, SkScalar sy) { 1205 SkMatrix m; 1206 m.setScale(sx, sy); 1207 this->concat(m); 1208} 1209 1210void SkCanvas::rotate(SkScalar degrees) { 1211 SkMatrix m; 1212 m.setRotate(degrees); 1213 this->concat(m); 1214} 1215 1216void SkCanvas::skew(SkScalar sx, SkScalar sy) { 1217 SkMatrix m; 1218 m.setSkew(sx, sy); 1219 this->concat(m); 1220} 1221 1222void SkCanvas::concat(const SkMatrix& matrix) { 1223 if (matrix.isIdentity()) { 1224 return; 1225 } 1226 1227 fDeviceCMDirty = true; 1228 fCachedLocalClipBoundsDirty = true; 1229 fMCRec->fMatrix.preConcat(matrix); 1230 1231 this->didConcat(matrix); 1232} 1233 1234void SkCanvas::setMatrix(const SkMatrix& matrix) { 1235 fDeviceCMDirty = true; 1236 fCachedLocalClipBoundsDirty = true; 1237 fMCRec->fMatrix = matrix; 1238 this->didSetMatrix(matrix); 1239} 1240 1241void SkCanvas::resetMatrix() { 1242 SkMatrix matrix; 1243 1244 matrix.reset(); 1245 this->setMatrix(matrix); 1246} 1247 1248////////////////////////////////////////////////////////////////////////////// 1249 1250void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 1251 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1252 this->onClipRect(rect, op, edgeStyle); 1253} 1254 1255void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1256#ifdef SK_ENABLE_CLIP_QUICKREJECT 1257 if (SkRegion::kIntersect_Op == op) { 1258 if (fMCRec->fRasterClip.isEmpty()) { 1259 return false; 1260 } 1261 1262 if (this->quickReject(rect)) { 1263 fDeviceCMDirty = true; 1264 fCachedLocalClipBoundsDirty = true; 1265 1266 fClipStack.clipEmpty(); 1267 return fMCRec->fRasterClip.setEmpty(); 1268 } 1269 } 1270#endif 1271 1272 AutoValidateClip avc(this); 1273 1274 fDeviceCMDirty = true; 1275 fCachedLocalClipBoundsDirty = true; 1276 if (!fAllowSoftClip) { 1277 edgeStyle = kHard_ClipEdgeStyle; 1278 } 1279 1280 if (fMCRec->fMatrix.rectStaysRect()) { 1281 // for these simpler matrices, we can stay a rect even after applying 1282 // the matrix. This means we don't have to a) make a path, and b) tell 1283 // the region code to scan-convert the path, only to discover that it 1284 // is really just a rect. 1285 SkRect r; 1286 1287 fMCRec->fMatrix.mapRect(&r, rect); 1288 fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle); 1289 fMCRec->fRasterClip.op(r, op, kSoft_ClipEdgeStyle == edgeStyle); 1290 } else { 1291 // since we're rotated or some such thing, we convert the rect to a path 1292 // and clip against that, since it can handle any matrix. However, to 1293 // avoid recursion in the case where we are subclassed (e.g. Pictures) 1294 // we explicitly call "our" version of clipPath. 1295 SkPath path; 1296 1297 path.addRect(rect); 1298 this->SkCanvas::onClipPath(path, op, edgeStyle); 1299 } 1300} 1301 1302static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath, 1303 SkRegion::Op op, bool doAA) { 1304 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA); 1305} 1306 1307void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 1308 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1309 if (rrect.isRect()) { 1310 this->onClipRect(rrect.getBounds(), op, edgeStyle); 1311 } else { 1312 this->onClipRRect(rrect, op, edgeStyle); 1313 } 1314} 1315 1316void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1317 SkRRect transformedRRect; 1318 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) { 1319 AutoValidateClip avc(this); 1320 1321 fDeviceCMDirty = true; 1322 fCachedLocalClipBoundsDirty = true; 1323 if (!fAllowSoftClip) { 1324 edgeStyle = kHard_ClipEdgeStyle; 1325 } 1326 1327 fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle); 1328 1329 SkPath devPath; 1330 devPath.addRRect(transformedRRect); 1331 1332 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle); 1333 return; 1334 } 1335 1336 SkPath path; 1337 path.addRRect(rrect); 1338 // call the non-virtual version 1339 this->SkCanvas::onClipPath(path, op, edgeStyle); 1340} 1341 1342void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 1343 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1344 SkRect r; 1345 if (!path.isInverseFillType() && path.isRect(&r)) { 1346 this->onClipRect(r, op, edgeStyle); 1347 } else { 1348 this->onClipPath(path, op, edgeStyle); 1349 } 1350} 1351 1352void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1353#ifdef SK_ENABLE_CLIP_QUICKREJECT 1354 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { 1355 if (fMCRec->fRasterClip.isEmpty()) { 1356 return false; 1357 } 1358 1359 if (this->quickReject(path.getBounds())) { 1360 fDeviceCMDirty = true; 1361 fCachedLocalClipBoundsDirty = true; 1362 1363 fClipStack.clipEmpty(); 1364 return fMCRec->fRasterClip.setEmpty(); 1365 } 1366 } 1367#endif 1368 1369 AutoValidateClip avc(this); 1370 1371 fDeviceCMDirty = true; 1372 fCachedLocalClipBoundsDirty = true; 1373 if (!fAllowSoftClip) { 1374 edgeStyle = kHard_ClipEdgeStyle; 1375 } 1376 1377 SkPath devPath; 1378 path.transform(fMCRec->fMatrix, &devPath); 1379 1380 // Check if the transfomation, or the original path itself 1381 // made us empty. Note this can also happen if we contained NaN 1382 // values. computing the bounds detects this, and will set our 1383 // bounds to empty if that is the case. (see SkRect::set(pts, count)) 1384 if (devPath.getBounds().isEmpty()) { 1385 // resetting the path will remove any NaN or other wanky values 1386 // that might upset our scan converter. 1387 devPath.reset(); 1388 } 1389 1390 // if we called path.swap() we could avoid a deep copy of this path 1391 fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle); 1392 1393 if (fAllowSimplifyClip) { 1394 devPath.reset(); 1395 devPath.setFillType(SkPath::kInverseEvenOdd_FillType); 1396 const SkClipStack* clipStack = getClipStack(); 1397 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart); 1398 const SkClipStack::Element* element; 1399 while ((element = iter.next())) { 1400 SkClipStack::Element::Type type = element->getType(); 1401 SkPath operand; 1402 if (type != SkClipStack::Element::kEmpty_Type) { 1403 element->asPath(&operand); 1404 } 1405 SkRegion::Op elementOp = element->getOp(); 1406 if (elementOp == SkRegion::kReplace_Op) { 1407 devPath = operand; 1408 } else { 1409 Op(devPath, operand, (SkPathOp) elementOp, &devPath); 1410 } 1411 // if the prev and curr clips disagree about aa -vs- not, favor the aa request. 1412 // perhaps we need an API change to avoid this sort of mixed-signals about 1413 // clipping. 1414 if (element->isAA()) { 1415 edgeStyle = kSoft_ClipEdgeStyle; 1416 } 1417 } 1418 op = SkRegion::kReplace_Op; 1419 } 1420 1421 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle); 1422} 1423 1424void SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op, 1425 bool inverseFilled) { 1426 // This is for updating the clip conservatively using only bounds 1427 // information. 1428 // Contract: 1429 // The current clip must contain the true clip. The true 1430 // clip is the clip that would have normally been computed 1431 // by calls to clipPath and clipRRect 1432 // Objective: 1433 // Keep the current clip as small as possible without 1434 // breaking the contract, using only clip bounding rectangles 1435 // (for performance). 1436 1437 // N.B.: This *never* calls back through a virtual on canvas, so subclasses 1438 // don't have to worry about getting caught in a loop. Thus anywhere 1439 // we call a virtual method, we explicitly prefix it with 1440 // SkCanvas:: to be sure to call the base-class. 1441 1442 if (inverseFilled) { 1443 switch (op) { 1444 case SkRegion::kIntersect_Op: 1445 case SkRegion::kDifference_Op: 1446 // These ops can only shrink the current clip. So leaving 1447 // the clip unchanged conservatively respects the contract. 1448 break; 1449 case SkRegion::kUnion_Op: 1450 case SkRegion::kReplace_Op: 1451 case SkRegion::kReverseDifference_Op: 1452 case SkRegion::kXOR_Op: { 1453 // These ops can grow the current clip up to the extents of 1454 // the input clip, which is inverse filled, so we just set 1455 // the current clip to the device bounds. 1456 SkRect deviceBounds; 1457 SkIRect deviceIBounds; 1458 this->getDevice()->getGlobalBounds(&deviceIBounds); 1459 deviceBounds = SkRect::Make(deviceIBounds); 1460 1461 // set the clip in device space 1462 SkMatrix savedMatrix = this->getTotalMatrix(); 1463 this->SkCanvas::setMatrix(SkMatrix::I()); 1464 this->SkCanvas::onClipRect(deviceBounds, SkRegion::kReplace_Op, 1465 kHard_ClipEdgeStyle); 1466 this->setMatrix(savedMatrix); 1467 break; 1468 } 1469 default: 1470 SkASSERT(0); // unhandled op? 1471 } 1472 } else { 1473 // Not inverse filled 1474 switch (op) { 1475 case SkRegion::kIntersect_Op: 1476 case SkRegion::kUnion_Op: 1477 case SkRegion::kReplace_Op: 1478 this->SkCanvas::onClipRect(bounds, op, kHard_ClipEdgeStyle); 1479 break; 1480 case SkRegion::kDifference_Op: 1481 // Difference can only shrink the current clip. 1482 // Leaving clip unchanged conservatively fullfills the contract. 1483 break; 1484 case SkRegion::kReverseDifference_Op: 1485 // To reverse, we swap in the bounds with a replace op. 1486 // As with difference, leave it unchanged. 1487 this->SkCanvas::onClipRect(bounds, SkRegion::kReplace_Op, kHard_ClipEdgeStyle); 1488 break; 1489 case SkRegion::kXOR_Op: 1490 // Be conservative, based on (A XOR B) always included in (A union B), 1491 // which is always included in (bounds(A) union bounds(B)) 1492 this->SkCanvas::onClipRect(bounds, SkRegion::kUnion_Op, kHard_ClipEdgeStyle); 1493 break; 1494 default: 1495 SkASSERT(0); // unhandled op? 1496 } 1497 } 1498} 1499 1500void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1501 this->onClipRegion(rgn, op); 1502} 1503 1504void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { 1505 AutoValidateClip avc(this); 1506 1507 fDeviceCMDirty = true; 1508 fCachedLocalClipBoundsDirty = true; 1509 1510 // todo: signal fClipStack that we have a region, and therefore (I guess) 1511 // we have to ignore it, and use the region directly? 1512 fClipStack.clipDevRect(rgn.getBounds(), op); 1513 1514 fMCRec->fRasterClip.op(rgn, op); 1515} 1516 1517#ifdef SK_DEBUG 1518void SkCanvas::validateClip() const { 1519 // construct clipRgn from the clipstack 1520 const SkBaseDevice* device = this->getDevice(); 1521 if (!device) { 1522 SkASSERT(this->isClipEmpty()); 1523 return; 1524 } 1525 1526 SkIRect ir; 1527 ir.set(0, 0, device->width(), device->height()); 1528 SkRasterClip tmpClip(ir); 1529 1530 SkClipStack::B2TIter iter(fClipStack); 1531 const SkClipStack::Element* element; 1532 while ((element = iter.next()) != NULL) { 1533 switch (element->getType()) { 1534 case SkClipStack::Element::kRect_Type: 1535 element->getRect().round(&ir); 1536 tmpClip.op(ir, element->getOp()); 1537 break; 1538 case SkClipStack::Element::kEmpty_Type: 1539 tmpClip.setEmpty(); 1540 break; 1541 default: { 1542 SkPath path; 1543 element->asPath(&path); 1544 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA()); 1545 break; 1546 } 1547 } 1548 } 1549} 1550#endif 1551 1552void SkCanvas::replayClips(ClipVisitor* visitor) const { 1553 SkClipStack::B2TIter iter(fClipStack); 1554 const SkClipStack::Element* element; 1555 1556 while ((element = iter.next()) != NULL) { 1557 element->replay(visitor); 1558 } 1559} 1560 1561/////////////////////////////////////////////////////////////////////////////// 1562 1563bool SkCanvas::isClipEmpty() const { 1564 return fMCRec->fRasterClip.isEmpty(); 1565} 1566 1567bool SkCanvas::isClipRect() const { 1568 return fMCRec->fRasterClip.isRect(); 1569} 1570 1571bool SkCanvas::quickReject(const SkRect& rect) const { 1572 1573 if (!rect.isFinite()) 1574 return true; 1575 1576 if (fMCRec->fRasterClip.isEmpty()) { 1577 return true; 1578 } 1579 1580 if (fMCRec->fMatrix.hasPerspective()) { 1581 SkRect dst; 1582 fMCRec->fMatrix.mapRect(&dst, rect); 1583 SkIRect idst; 1584 dst.roundOut(&idst); 1585 return !SkIRect::Intersects(idst, fMCRec->fRasterClip.getBounds()); 1586 } else { 1587 const SkRect& clipR = this->getLocalClipBounds(); 1588 1589 // for speed, do the most likely reject compares first 1590 // TODO: should we use | instead, or compare all 4 at once? 1591 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) { 1592 return true; 1593 } 1594 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) { 1595 return true; 1596 } 1597 return false; 1598 } 1599} 1600 1601bool SkCanvas::quickReject(const SkPath& path) const { 1602 return path.isEmpty() || this->quickReject(path.getBounds()); 1603} 1604 1605bool SkCanvas::getClipBounds(SkRect* bounds) const { 1606 SkIRect ibounds; 1607 if (!this->getClipDeviceBounds(&ibounds)) { 1608 return false; 1609 } 1610 1611 SkMatrix inverse; 1612 // if we can't invert the CTM, we can't return local clip bounds 1613 if (!fMCRec->fMatrix.invert(&inverse)) { 1614 if (bounds) { 1615 bounds->setEmpty(); 1616 } 1617 return false; 1618 } 1619 1620 if (bounds) { 1621 SkRect r; 1622 // adjust it outwards in case we are antialiasing 1623 const int inset = 1; 1624 1625 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset, 1626 ibounds.fRight + inset, ibounds.fBottom + inset); 1627 inverse.mapRect(bounds, r); 1628 } 1629 return true; 1630} 1631 1632bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const { 1633 const SkRasterClip& clip = fMCRec->fRasterClip; 1634 if (clip.isEmpty()) { 1635 if (bounds) { 1636 bounds->setEmpty(); 1637 } 1638 return false; 1639 } 1640 1641 if (bounds) { 1642 *bounds = clip.getBounds(); 1643 } 1644 return true; 1645} 1646 1647const SkMatrix& SkCanvas::getTotalMatrix() const { 1648 return fMCRec->fMatrix; 1649} 1650 1651const SkRegion& SkCanvas::internal_private_getTotalClip() const { 1652 return fMCRec->fRasterClip.forceGetBW(); 1653} 1654 1655GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() { 1656 SkBaseDevice* dev = this->getTopDevice(); 1657 return dev ? dev->accessRenderTarget() : NULL; 1658} 1659 1660SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) { 1661 SkBaseDevice* device = this->getTopDevice(); 1662 return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL; 1663} 1664 1665GrContext* SkCanvas::getGrContext() { 1666#if SK_SUPPORT_GPU 1667 SkBaseDevice* device = this->getTopDevice(); 1668 if (device) { 1669 GrRenderTarget* renderTarget = device->accessRenderTarget(); 1670 if (renderTarget) { 1671 return renderTarget->getContext(); 1672 } 1673 } 1674#endif 1675 1676 return NULL; 1677 1678} 1679 1680void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner, 1681 const SkPaint& paint) { 1682 if (outer.isEmpty()) { 1683 return; 1684 } 1685 if (inner.isEmpty()) { 1686 this->drawRRect(outer, paint); 1687 return; 1688 } 1689 1690 // We don't have this method (yet), but technically this is what we should 1691 // be able to assert... 1692 // SkASSERT(outer.contains(inner)); 1693 // 1694 // For now at least check for containment of bounds 1695 SkASSERT(outer.getBounds().contains(inner.getBounds())); 1696 1697 this->onDrawDRRect(outer, inner, paint); 1698} 1699 1700////////////////////////////////////////////////////////////////////////////// 1701// These are the virtual drawing methods 1702////////////////////////////////////////////////////////////////////////////// 1703 1704void SkCanvas::clear(SkColor color) { 1705 SkDrawIter iter(this); 1706 this->predrawNotify(); 1707 while (iter.next()) { 1708 iter.fDevice->clear(color); 1709 } 1710} 1711 1712void SkCanvas::onDiscard() { 1713 if (fSurfaceBase) { 1714 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode); 1715 } 1716} 1717 1718void SkCanvas::drawPaint(const SkPaint& paint) { 1719 this->internalDrawPaint(paint); 1720} 1721 1722void SkCanvas::internalDrawPaint(const SkPaint& paint) { 1723 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL) 1724 1725 while (iter.next()) { 1726 iter.fDevice->drawPaint(iter, looper.paint()); 1727 } 1728 1729 LOOPER_END 1730} 1731 1732void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1733 const SkPaint& paint) { 1734 if ((long)count <= 0) { 1735 return; 1736 } 1737 1738 SkRect r, storage; 1739 const SkRect* bounds = NULL; 1740 if (paint.canComputeFastBounds()) { 1741 // special-case 2 points (common for drawing a single line) 1742 if (2 == count) { 1743 r.set(pts[0], pts[1]); 1744 } else { 1745 r.set(pts, SkToInt(count)); 1746 } 1747 bounds = &paint.computeFastStrokeBounds(r, &storage); 1748 if (this->quickReject(*bounds)) { 1749 return; 1750 } 1751 } 1752 1753 SkASSERT(pts != NULL); 1754 1755 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds) 1756 1757 while (iter.next()) { 1758 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); 1759 } 1760 1761 LOOPER_END 1762} 1763 1764void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1765 SkRect storage; 1766 const SkRect* bounds = NULL; 1767 if (paint.canComputeFastBounds()) { 1768 bounds = &paint.computeFastBounds(r, &storage); 1769 if (this->quickReject(*bounds)) { 1770 return; 1771 } 1772 } 1773 1774 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds) 1775 1776 while (iter.next()) { 1777 iter.fDevice->drawRect(iter, r, looper.paint()); 1778 } 1779 1780 LOOPER_END 1781} 1782 1783void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1784 SkRect storage; 1785 const SkRect* bounds = NULL; 1786 if (paint.canComputeFastBounds()) { 1787 bounds = &paint.computeFastBounds(oval, &storage); 1788 if (this->quickReject(*bounds)) { 1789 return; 1790 } 1791 } 1792 1793 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds) 1794 1795 while (iter.next()) { 1796 iter.fDevice->drawOval(iter, oval, looper.paint()); 1797 } 1798 1799 LOOPER_END 1800} 1801 1802void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 1803 SkRect storage; 1804 const SkRect* bounds = NULL; 1805 if (paint.canComputeFastBounds()) { 1806 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage); 1807 if (this->quickReject(*bounds)) { 1808 return; 1809 } 1810 } 1811 1812 if (rrect.isRect()) { 1813 // call the non-virtual version 1814 this->SkCanvas::drawRect(rrect.getBounds(), paint); 1815 return; 1816 } else if (rrect.isOval()) { 1817 // call the non-virtual version 1818 this->SkCanvas::drawOval(rrect.getBounds(), paint); 1819 return; 1820 } 1821 1822 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) 1823 1824 while (iter.next()) { 1825 iter.fDevice->drawRRect(iter, rrect, looper.paint()); 1826 } 1827 1828 LOOPER_END 1829} 1830 1831void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, 1832 const SkPaint& paint) { 1833 SkRect storage; 1834 const SkRect* bounds = NULL; 1835 if (paint.canComputeFastBounds()) { 1836 bounds = &paint.computeFastBounds(outer.getBounds(), &storage); 1837 if (this->quickReject(*bounds)) { 1838 return; 1839 } 1840 } 1841 1842 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) 1843 1844 while (iter.next()) { 1845 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint()); 1846 } 1847 1848 LOOPER_END 1849} 1850 1851void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 1852 if (!path.isFinite()) { 1853 return; 1854 } 1855 1856 SkRect storage; 1857 const SkRect* bounds = NULL; 1858 if (!path.isInverseFillType() && paint.canComputeFastBounds()) { 1859 const SkRect& pathBounds = path.getBounds(); 1860 bounds = &paint.computeFastBounds(pathBounds, &storage); 1861 if (this->quickReject(*bounds)) { 1862 return; 1863 } 1864 } 1865 1866 const SkRect& r = path.getBounds(); 1867 if (r.width() <= 0 && r.height() <= 0) { 1868 if (path.isInverseFillType()) { 1869 this->internalDrawPaint(paint); 1870 } 1871 return; 1872 } 1873 1874 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds) 1875 1876 while (iter.next()) { 1877 iter.fDevice->drawPath(iter, path, looper.paint()); 1878 } 1879 1880 LOOPER_END 1881} 1882 1883void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, 1884 const SkPaint* paint) { 1885 SkDEBUGCODE(bitmap.validate();) 1886 1887 if (NULL == paint || paint->canComputeFastBounds()) { 1888 SkRect bounds = { 1889 x, y, 1890 x + SkIntToScalar(bitmap.width()), 1891 y + SkIntToScalar(bitmap.height()) 1892 }; 1893 if (paint) { 1894 (void)paint->computeFastBounds(bounds, &bounds); 1895 } 1896 if (this->quickReject(bounds)) { 1897 return; 1898 } 1899 } 1900 1901 SkMatrix matrix; 1902 matrix.setTranslate(x, y); 1903 this->internalDrawBitmap(bitmap, matrix, paint); 1904} 1905 1906// this one is non-virtual, so it can be called safely by other canvas apis 1907void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, 1908 const SkRect& dst, const SkPaint* paint, 1909 DrawBitmapRectFlags flags) { 1910 if (bitmap.drawsNothing() || dst.isEmpty()) { 1911 return; 1912 } 1913 1914 SkRect storage; 1915 const SkRect* bounds = &dst; 1916 if (NULL == paint || paint->canComputeFastBounds()) { 1917 if (paint) { 1918 bounds = &paint->computeFastBounds(dst, &storage); 1919 } 1920 if (this->quickReject(*bounds)) { 1921 return; 1922 } 1923 } 1924 1925 SkLazyPaint lazy; 1926 if (NULL == paint) { 1927 paint = lazy.init(); 1928 } 1929 1930 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) 1931 1932 while (iter.next()) { 1933 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags); 1934 } 1935 1936 LOOPER_END 1937} 1938 1939void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, 1940 const SkRect& dst, const SkPaint* paint, 1941 DrawBitmapRectFlags flags) { 1942 SkDEBUGCODE(bitmap.validate();) 1943 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags); 1944} 1945 1946void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 1947 const SkPaint* paint) { 1948 SkDEBUGCODE(bitmap.validate();) 1949 this->internalDrawBitmap(bitmap, matrix, paint); 1950} 1951 1952void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap, 1953 const SkIRect& center, const SkRect& dst, 1954 const SkPaint* paint) { 1955 if (bitmap.drawsNothing()) { 1956 return; 1957 } 1958 if (NULL == paint || paint->canComputeFastBounds()) { 1959 SkRect storage; 1960 const SkRect* bounds = &dst; 1961 if (paint) { 1962 bounds = &paint->computeFastBounds(dst, &storage); 1963 } 1964 if (this->quickReject(*bounds)) { 1965 return; 1966 } 1967 } 1968 1969 const int32_t w = bitmap.width(); 1970 const int32_t h = bitmap.height(); 1971 1972 SkIRect c = center; 1973 // pin center to the bounds of the bitmap 1974 c.fLeft = SkMax32(0, center.fLeft); 1975 c.fTop = SkMax32(0, center.fTop); 1976 c.fRight = SkPin32(center.fRight, c.fLeft, w); 1977 c.fBottom = SkPin32(center.fBottom, c.fTop, h); 1978 1979 const SkScalar srcX[4] = { 1980 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w) 1981 }; 1982 const SkScalar srcY[4] = { 1983 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h) 1984 }; 1985 SkScalar dstX[4] = { 1986 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft), 1987 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight 1988 }; 1989 SkScalar dstY[4] = { 1990 dst.fTop, dst.fTop + SkIntToScalar(c.fTop), 1991 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom 1992 }; 1993 1994 if (dstX[1] > dstX[2]) { 1995 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width()); 1996 dstX[2] = dstX[1]; 1997 } 1998 1999 if (dstY[1] > dstY[2]) { 2000 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height()); 2001 dstY[2] = dstY[1]; 2002 } 2003 2004 for (int y = 0; y < 3; y++) { 2005 SkRect s, d; 2006 2007 s.fTop = srcY[y]; 2008 s.fBottom = srcY[y+1]; 2009 d.fTop = dstY[y]; 2010 d.fBottom = dstY[y+1]; 2011 for (int x = 0; x < 3; x++) { 2012 s.fLeft = srcX[x]; 2013 s.fRight = srcX[x+1]; 2014 d.fLeft = dstX[x]; 2015 d.fRight = dstX[x+1]; 2016 this->internalDrawBitmapRect(bitmap, &s, d, paint, 2017 kNone_DrawBitmapRectFlag); 2018 } 2019 } 2020} 2021 2022void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 2023 const SkRect& dst, const SkPaint* paint) { 2024 SkDEBUGCODE(bitmap.validate();) 2025 2026 // Need a device entry-point, so gpu can use a mesh 2027 this->internalDrawBitmapNine(bitmap, center, dst, paint); 2028} 2029 2030class SkDeviceFilteredPaint { 2031public: 2032 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) { 2033 SkBaseDevice::TextFlags flags; 2034 if (device->filterTextFlags(paint, &flags)) { 2035 SkPaint* newPaint = fLazy.set(paint); 2036 newPaint->setFlags(flags.fFlags); 2037 newPaint->setHinting(flags.fHinting); 2038 fPaint = newPaint; 2039 } else { 2040 fPaint = &paint; 2041 } 2042 } 2043 2044 const SkPaint& paint() const { return *fPaint; } 2045 2046private: 2047 const SkPaint* fPaint; 2048 SkLazyPaint fLazy; 2049}; 2050 2051void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, 2052 const SkRect& r, SkScalar textSize) { 2053 if (paint.getStyle() == SkPaint::kFill_Style) { 2054 draw.fDevice->drawRect(draw, r, paint); 2055 } else { 2056 SkPaint p(paint); 2057 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); 2058 draw.fDevice->drawRect(draw, r, p); 2059 } 2060} 2061 2062void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, 2063 const char text[], size_t byteLength, 2064 SkScalar x, SkScalar y) { 2065 SkASSERT(byteLength == 0 || text != NULL); 2066 2067 // nothing to draw 2068 if (text == NULL || byteLength == 0 || 2069 draw.fClip->isEmpty() || 2070 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 2071 return; 2072 } 2073 2074 SkScalar width = 0; 2075 SkPoint start; 2076 2077 start.set(0, 0); // to avoid warning 2078 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | 2079 SkPaint::kStrikeThruText_Flag)) { 2080 width = paint.measureText(text, byteLength); 2081 2082 SkScalar offsetX = 0; 2083 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 2084 offsetX = SkScalarHalf(width); 2085 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { 2086 offsetX = width; 2087 } 2088 start.set(x - offsetX, y); 2089 } 2090 2091 if (0 == width) { 2092 return; 2093 } 2094 2095 uint32_t flags = paint.getFlags(); 2096 2097 if (flags & (SkPaint::kUnderlineText_Flag | 2098 SkPaint::kStrikeThruText_Flag)) { 2099 SkScalar textSize = paint.getTextSize(); 2100 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 2101 SkRect r; 2102 2103 r.fLeft = start.fX; 2104 r.fRight = start.fX + width; 2105 2106 if (flags & SkPaint::kUnderlineText_Flag) { 2107 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, 2108 start.fY); 2109 r.fTop = offset; 2110 r.fBottom = offset + height; 2111 DrawRect(draw, paint, r, textSize); 2112 } 2113 if (flags & SkPaint::kStrikeThruText_Flag) { 2114 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, 2115 start.fY); 2116 r.fTop = offset; 2117 r.fBottom = offset + height; 2118 DrawRect(draw, paint, r, textSize); 2119 } 2120 } 2121} 2122 2123void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, 2124 const SkPaint& paint) { 2125 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2126 2127 while (iter.next()) { 2128 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2129 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 2130 DrawTextDecorations(iter, dfp.paint(), 2131 static_cast<const char*>(text), byteLength, x, y); 2132 } 2133 2134 LOOPER_END 2135} 2136 2137void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], 2138 const SkPaint& paint) { 2139 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2140 2141 while (iter.next()) { 2142 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2143 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 2144 dfp.paint()); 2145 } 2146 2147 LOOPER_END 2148} 2149 2150void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], 2151 SkScalar constY, const SkPaint& paint) { 2152 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2153 2154 while (iter.next()) { 2155 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2156 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 2157 dfp.paint()); 2158 } 2159 2160 LOOPER_END 2161} 2162 2163void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, 2164 const SkMatrix* matrix, const SkPaint& paint) { 2165 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2166 2167 while (iter.next()) { 2168 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 2169 matrix, looper.paint()); 2170 } 2171 2172 LOOPER_END 2173} 2174 2175void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 2176 const SkPaint& paint) { 2177 2178 // FIXME: temporarily disable quickreject for empty bounds, 2179 // pending implicit blob bounds implementation. 2180 if (!blob->bounds().isEmpty() && paint.canComputeFastBounds()) { 2181 SkRect storage; 2182 2183 if (this->quickReject(paint.computeFastBounds(blob->bounds().makeOffset(x, y), &storage))) { 2184 return; 2185 } 2186 } 2187 2188 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 2189 2190 while (iter.next()) { 2191 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2192 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint()); 2193 } 2194 2195 LOOPER_END 2196} 2197 2198// These will become non-virtual, so they always call the (virtual) onDraw... method 2199void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, 2200 const SkPaint& paint) { 2201 this->onDrawText(text, byteLength, x, y, paint); 2202} 2203void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[], 2204 const SkPaint& paint) { 2205 this->onDrawPosText(text, byteLength, pos, paint); 2206} 2207void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], 2208 SkScalar constY, const SkPaint& paint) { 2209 this->onDrawPosTextH(text, byteLength, xpos, constY, paint); 2210} 2211void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path, 2212 const SkMatrix* matrix, const SkPaint& paint) { 2213 this->onDrawTextOnPath(text, byteLength, path, matrix, paint); 2214} 2215void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 2216 const SkPaint& paint) { 2217 if (blob) { 2218 this->onDrawTextBlob(blob, x, y, paint); 2219 } 2220} 2221 2222void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 2223 const SkPoint verts[], const SkPoint texs[], 2224 const SkColor colors[], SkXfermode* xmode, 2225 const uint16_t indices[], int indexCount, 2226 const SkPaint& paint) { 2227 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL) 2228 2229 while (iter.next()) { 2230 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 2231 colors, xmode, indices, indexCount, 2232 looper.paint()); 2233 } 2234 2235 LOOPER_END 2236} 2237 2238void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4], 2239 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { 2240 if (NULL == cubics) { 2241 return; 2242 } 2243 2244 // Since a patch is always within the convex hull of the control points, we discard it when its 2245 // bounding rectangle is completely outside the current clip. 2246 SkRect bounds; 2247 bounds.set(cubics, SkPatchUtils::kNumCtrlPts); 2248 if (this->quickReject(bounds)) { 2249 return; 2250 } 2251 2252 this->onDrawPatch(cubics, colors, texCoords, xmode, paint); 2253} 2254 2255void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], 2256 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { 2257 2258 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL) 2259 2260 while (iter.next()) { 2261 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint); 2262 } 2263 2264 LOOPER_END 2265} 2266 2267////////////////////////////////////////////////////////////////////////////// 2268// These methods are NOT virtual, and therefore must call back into virtual 2269// methods, rather than actually drawing themselves. 2270////////////////////////////////////////////////////////////////////////////// 2271 2272void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 2273 SkXfermode::Mode mode) { 2274 SkPaint paint; 2275 2276 paint.setARGB(a, r, g, b); 2277 if (SkXfermode::kSrcOver_Mode != mode) { 2278 paint.setXfermodeMode(mode); 2279 } 2280 this->drawPaint(paint); 2281} 2282 2283void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 2284 SkPaint paint; 2285 2286 paint.setColor(c); 2287 if (SkXfermode::kSrcOver_Mode != mode) { 2288 paint.setXfermodeMode(mode); 2289 } 2290 this->drawPaint(paint); 2291} 2292 2293void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 2294 SkPoint pt; 2295 2296 pt.set(x, y); 2297 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2298} 2299 2300void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 2301 SkPoint pt; 2302 SkPaint paint; 2303 2304 pt.set(x, y); 2305 paint.setColor(color); 2306 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2307} 2308 2309void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 2310 const SkPaint& paint) { 2311 SkPoint pts[2]; 2312 2313 pts[0].set(x0, y0); 2314 pts[1].set(x1, y1); 2315 this->drawPoints(kLines_PointMode, 2, pts, paint); 2316} 2317 2318void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 2319 SkScalar right, SkScalar bottom, 2320 const SkPaint& paint) { 2321 SkRect r; 2322 2323 r.set(left, top, right, bottom); 2324 this->drawRect(r, paint); 2325} 2326 2327void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 2328 const SkPaint& paint) { 2329 if (radius < 0) { 2330 radius = 0; 2331 } 2332 2333 SkRect r; 2334 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 2335 this->drawOval(r, paint); 2336} 2337 2338void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 2339 const SkPaint& paint) { 2340 if (rx > 0 && ry > 0) { 2341 if (paint.canComputeFastBounds()) { 2342 SkRect storage; 2343 if (this->quickReject(paint.computeFastBounds(r, &storage))) { 2344 return; 2345 } 2346 } 2347 SkRRect rrect; 2348 rrect.setRectXY(r, rx, ry); 2349 this->drawRRect(rrect, paint); 2350 } else { 2351 this->drawRect(r, paint); 2352 } 2353} 2354 2355void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 2356 SkScalar sweepAngle, bool useCenter, 2357 const SkPaint& paint) { 2358 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 2359 this->drawOval(oval, paint); 2360 } else { 2361 SkPath path; 2362 if (useCenter) { 2363 path.moveTo(oval.centerX(), oval.centerY()); 2364 } 2365 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 2366 if (useCenter) { 2367 path.close(); 2368 } 2369 this->drawPath(path, paint); 2370 } 2371} 2372 2373void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 2374 const SkPath& path, SkScalar hOffset, 2375 SkScalar vOffset, const SkPaint& paint) { 2376 SkMatrix matrix; 2377 2378 matrix.setTranslate(hOffset, vOffset); 2379 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 2380} 2381 2382/////////////////////////////////////////////////////////////////////////////// 2383void SkCanvas::EXPERIMENTAL_optimize(const SkPicture* picture) { 2384 SkBaseDevice* device = this->getDevice(); 2385 if (device) { 2386 device->EXPERIMENTAL_optimize(picture); 2387 } 2388} 2389 2390void SkCanvas::drawPicture(const SkPicture* picture) { 2391 if (picture) { 2392 this->onDrawPicture(picture, NULL, NULL); 2393 } 2394} 2395 2396void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) { 2397 if (picture) { 2398 if (matrix && matrix->isIdentity()) { 2399 matrix = NULL; 2400 } 2401 this->onDrawPicture(picture, matrix, paint); 2402 } 2403} 2404 2405void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, 2406 const SkPaint* paint) { 2407 SkBaseDevice* device = this->getTopDevice(); 2408 if (device) { 2409 // Canvas has to first give the device the opportunity to render 2410 // the picture itself. 2411 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) { 2412 return; // the device has rendered the entire picture 2413 } 2414 } 2415 2416 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); 2417 2418 picture->playback(this); 2419} 2420 2421/////////////////////////////////////////////////////////////////////////////// 2422/////////////////////////////////////////////////////////////////////////////// 2423 2424SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 2425 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); 2426 2427 SkASSERT(canvas); 2428 2429 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 2430 fDone = !fImpl->next(); 2431} 2432 2433SkCanvas::LayerIter::~LayerIter() { 2434 fImpl->~SkDrawIter(); 2435} 2436 2437void SkCanvas::LayerIter::next() { 2438 fDone = !fImpl->next(); 2439} 2440 2441SkBaseDevice* SkCanvas::LayerIter::device() const { 2442 return fImpl->getDevice(); 2443} 2444 2445const SkMatrix& SkCanvas::LayerIter::matrix() const { 2446 return fImpl->getMatrix(); 2447} 2448 2449const SkPaint& SkCanvas::LayerIter::paint() const { 2450 const SkPaint* paint = fImpl->getPaint(); 2451 if (NULL == paint) { 2452 paint = &fDefaultPaint; 2453 } 2454 return *paint; 2455} 2456 2457const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 2458int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 2459int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 2460 2461/////////////////////////////////////////////////////////////////////////////// 2462 2463SkCanvasClipVisitor::~SkCanvasClipVisitor() { } 2464 2465/////////////////////////////////////////////////////////////////////////////// 2466 2467static bool supported_for_raster_canvas(const SkImageInfo& info) { 2468 switch (info.alphaType()) { 2469 case kPremul_SkAlphaType: 2470 case kOpaque_SkAlphaType: 2471 break; 2472 default: 2473 return false; 2474 } 2475 2476 switch (info.colorType()) { 2477 case kAlpha_8_SkColorType: 2478 case kRGB_565_SkColorType: 2479 case kN32_SkColorType: 2480 break; 2481 default: 2482 return false; 2483 } 2484 2485 return true; 2486} 2487 2488SkCanvas* SkCanvas::NewRaster(const SkImageInfo& info) { 2489 if (!supported_for_raster_canvas(info)) { 2490 return NULL; 2491 } 2492 2493 SkBitmap bitmap; 2494 if (!bitmap.tryAllocPixels(info)) { 2495 return NULL; 2496 } 2497 2498 // should this functionality be moved into allocPixels()? 2499 if (!bitmap.info().isOpaque()) { 2500 bitmap.eraseColor(0); 2501 } 2502 return SkNEW_ARGS(SkCanvas, (bitmap)); 2503} 2504 2505SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) { 2506 if (!supported_for_raster_canvas(info)) { 2507 return NULL; 2508 } 2509 2510 SkBitmap bitmap; 2511 if (!bitmap.installPixels(info, pixels, rowBytes)) { 2512 return NULL; 2513 } 2514 return SkNEW_ARGS(SkCanvas, (bitmap)); 2515} 2516 2517/////////////////////////////////////////////////////////////////////////////// 2518 2519SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix, 2520 const SkPaint* paint, const SkRect& bounds) 2521 : fCanvas(canvas) 2522 , fSaveCount(canvas->getSaveCount()) 2523{ 2524 if (paint) { 2525 SkRect newBounds = bounds; 2526 if (matrix) { 2527 matrix->mapRect(&newBounds); 2528 } 2529 canvas->saveLayer(&newBounds, paint); 2530 } else if (matrix) { 2531 canvas->save(); 2532 } 2533 2534 if (matrix) { 2535 canvas->concat(*matrix); 2536 } 2537} 2538 2539SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() { 2540 fCanvas->restoreToCount(fSaveCount); 2541} 2542