SkCanvas.cpp revision ac09554dce518e9d4496771f648f3ae17eca857c
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#include "SkBitmapDevice.h" 9#include "SkCanvas.h" 10#include "SkCanvasPriv.h" 11#include "SkClipStack.h" 12#include "SkColorFilter.h" 13#include "SkDraw.h" 14#include "SkDrawable.h" 15#include "SkDrawFilter.h" 16#include "SkDrawLooper.h" 17#include "SkErrorInternals.h" 18#include "SkImage.h" 19#include "SkImage_Base.h" 20#include "SkImageFilter.h" 21#include "SkImageFilterCache.h" 22#include "SkLatticeIter.h" 23#include "SkMatrixUtils.h" 24#include "SkMetaData.h" 25#include "SkPaintPriv.h" 26#include "SkPatchUtils.h" 27#include "SkPicture.h" 28#include "SkRasterClip.h" 29#include "SkReadPixelsRec.h" 30#include "SkRRect.h" 31#include "SkSmallAllocator.h" 32#include "SkSpecialImage.h" 33#include "SkSurface_Base.h" 34#include "SkTextBlob.h" 35#include "SkTextFormatParams.h" 36#include "SkTLazy.h" 37#include "SkTraceEvent.h" 38 39#include <new> 40 41#if SK_SUPPORT_GPU 42#include "GrContext.h" 43#include "GrRenderTarget.h" 44#include "SkGrPriv.h" 45#endif 46 47#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0) 48 49//#define SK_SUPPORT_PRECHECK_CLIPRECT 50 51/* 52 * Return true if the drawing this rect would hit every pixels in the canvas. 53 * 54 * Returns false if 55 * - rect does not contain the canvas' bounds 56 * - paint is not fill 57 * - paint would blur or otherwise change the coverage of the rect 58 */ 59bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint, 60 ShaderOverrideOpacity overrideOpacity) const { 61 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity == 62 (int)kNone_ShaderOverrideOpacity, 63 "need_matching_enums0"); 64 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity == 65 (int)kOpaque_ShaderOverrideOpacity, 66 "need_matching_enums1"); 67 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity == 68 (int)kNotOpaque_ShaderOverrideOpacity, 69 "need_matching_enums2"); 70 71 const SkISize size = this->getBaseLayerSize(); 72 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height()); 73 if (!this->getClipStack()->quickContains(bounds)) { 74 return false; 75 } 76 77 if (rect) { 78 if (!this->getTotalMatrix().isScaleTranslate()) { 79 return false; // conservative 80 } 81 82 SkRect devRect; 83 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect); 84 if (!devRect.contains(bounds)) { 85 return false; 86 } 87 } 88 89 if (paint) { 90 SkPaint::Style paintStyle = paint->getStyle(); 91 if (!(paintStyle == SkPaint::kFill_Style || 92 paintStyle == SkPaint::kStrokeAndFill_Style)) { 93 return false; 94 } 95 if (paint->getMaskFilter() || paint->getLooper() 96 || paint->getPathEffect() || paint->getImageFilter()) { 97 return false; // conservative 98 } 99 } 100 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity); 101} 102 103/////////////////////////////////////////////////////////////////////////////////////////////////// 104 105static bool gIgnoreSaveLayerBounds; 106void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) { 107 gIgnoreSaveLayerBounds = ignore; 108} 109bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() { 110 return gIgnoreSaveLayerBounds; 111} 112 113static bool gTreatSpriteAsBitmap; 114void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) { 115 gTreatSpriteAsBitmap = spriteAsBitmap; 116} 117bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() { 118 return gTreatSpriteAsBitmap; 119} 120 121// experimental for faster tiled drawing... 122//#define SK_ENABLE_CLIP_QUICKREJECT 123//#define SK_TRACE_SAVERESTORE 124 125#ifdef SK_TRACE_SAVERESTORE 126 static int gLayerCounter; 127 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); } 128 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); } 129 130 static int gRecCounter; 131 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); } 132 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); } 133 134 static int gCanvasCounter; 135 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); } 136 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); } 137#else 138 #define inc_layer() 139 #define dec_layer() 140 #define inc_rec() 141 #define dec_rec() 142 #define inc_canvas() 143 #define dec_canvas() 144#endif 145 146typedef SkTLazy<SkPaint> SkLazyPaint; 147 148void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) { 149 if (fSurfaceBase) { 150 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface 151 ? SkSurface::kDiscard_ContentChangeMode 152 : SkSurface::kRetain_ContentChangeMode); 153 } 154} 155 156void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint, 157 ShaderOverrideOpacity overrideOpacity) { 158 if (fSurfaceBase) { 159 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode; 160 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if 161 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write 162 // and therefore we don't care which mode we're in. 163 // 164 if (fSurfaceBase->outstandingImageSnapshot()) { 165 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) { 166 mode = SkSurface::kDiscard_ContentChangeMode; 167 } 168 } 169 fSurfaceBase->aboutToDraw(mode); 170 } 171} 172 173/////////////////////////////////////////////////////////////////////////////// 174 175static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) { 176 const uint32_t propFlags = props.flags(); 177 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) { 178 flags &= ~SkPaint::kDither_Flag; 179 } 180 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) { 181 flags &= ~SkPaint::kAntiAlias_Flag; 182 } 183 return flags; 184} 185 186/////////////////////////////////////////////////////////////////////////////// 187 188/* This is the record we keep for each SkBaseDevice that the user installs. 189 The clip/matrix/proc are fields that reflect the top of the save/restore 190 stack. Whenever the canvas changes, it marks a dirty flag, and then before 191 these are used (assuming we're not on a layer) we rebuild these cache 192 values: they reflect the top of the save stack, but translated and clipped 193 by the device's XY offset and bitmap-bounds. 194*/ 195struct DeviceCM { 196 DeviceCM* fNext; 197 SkBaseDevice* fDevice; 198 SkRasterClip fClip; 199 SkPaint* fPaint; // may be null (in the future) 200 const SkMatrix* fMatrix; 201 SkMatrix fMatrixStorage; 202 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer 203 204 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas, 205 bool conservativeRasterClip, const SkMatrix& stashed) 206 : fNext(nullptr) 207 , fClip(conservativeRasterClip) 208 , fStashedMatrix(stashed) 209 { 210 SkSafeRef(device); 211 fDevice = device; 212 fPaint = paint ? new SkPaint(*paint) : nullptr; 213 } 214 215 ~DeviceCM() { 216 SkSafeUnref(fDevice); 217 delete fPaint; 218 } 219 220 void reset(const SkIRect& bounds) { 221 SkASSERT(!fPaint); 222 SkASSERT(!fNext); 223 SkASSERT(fDevice); 224 fClip.setRect(bounds); 225 } 226 227 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip, 228 const SkClipStack& clipStack, SkRasterClip* updateClip) { 229 int x = fDevice->getOrigin().x(); 230 int y = fDevice->getOrigin().y(); 231 int width = fDevice->width(); 232 int height = fDevice->height(); 233 234 if ((x | y) == 0) { 235 fMatrix = &totalMatrix; 236 fClip = totalClip; 237 } else { 238 fMatrixStorage = totalMatrix; 239 fMatrixStorage.postTranslate(SkIntToScalar(-x), 240 SkIntToScalar(-y)); 241 fMatrix = &fMatrixStorage; 242 243 totalClip.translate(-x, -y, &fClip); 244 } 245 246 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op); 247 248 // intersect clip, but don't translate it (yet) 249 250 if (updateClip) { 251 updateClip->op(SkIRect::MakeXYWH(x, y, width, height), 252 SkRegion::kDifference_Op); 253 } 254 255 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack); 256 257#ifdef SK_DEBUG 258 if (!fClip.isEmpty()) { 259 SkIRect deviceR; 260 deviceR.set(0, 0, width, height); 261 SkASSERT(deviceR.contains(fClip.getBounds())); 262 } 263#endif 264 } 265}; 266 267/* This is the record we keep for each save/restore level in the stack. 268 Since a level optionally copies the matrix and/or stack, we have pointers 269 for these fields. If the value is copied for this level, the copy is 270 stored in the ...Storage field, and the pointer points to that. If the 271 value is not copied for this level, we ignore ...Storage, and just point 272 at the corresponding value in the previous level in the stack. 273*/ 274class SkCanvas::MCRec { 275public: 276 SkDrawFilter* fFilter; // the current filter (or null) 277 DeviceCM* fLayer; 278 /* If there are any layers in the stack, this points to the top-most 279 one that is at or below this level in the stack (so we know what 280 bitmap/device to draw into from this level. This value is NOT 281 reference counted, since the real owner is either our fLayer field, 282 or a previous one in a lower level.) 283 */ 284 DeviceCM* fTopLayer; 285 SkRasterClip fRasterClip; 286 SkMatrix fMatrix; 287 int fDeferredSaveCount; 288 289 // This is the current cumulative depth (aggregate of all done translateZ calls) 290 SkScalar fCurDrawDepth; 291 292 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) { 293 fFilter = nullptr; 294 fLayer = nullptr; 295 fTopLayer = nullptr; 296 fMatrix.reset(); 297 fDeferredSaveCount = 0; 298 fCurDrawDepth = 0; 299 300 // don't bother initializing fNext 301 inc_rec(); 302 } 303 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix), 304 fCurDrawDepth(prev.fCurDrawDepth) { 305 fFilter = SkSafeRef(prev.fFilter); 306 fLayer = nullptr; 307 fTopLayer = prev.fTopLayer; 308 fDeferredSaveCount = 0; 309 310 // don't bother initializing fNext 311 inc_rec(); 312 } 313 ~MCRec() { 314 SkSafeUnref(fFilter); 315 delete fLayer; 316 dec_rec(); 317 } 318 319 void reset(const SkIRect& bounds) { 320 SkASSERT(fLayer); 321 SkASSERT(fDeferredSaveCount == 0); 322 323 fMatrix.reset(); 324 fRasterClip.setRect(bounds); 325 fLayer->reset(bounds); 326 } 327}; 328 329class SkDrawIter : public SkDraw { 330public: 331 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) { 332 canvas = canvas->canvasForDrawIter(); 333 fCanvas = canvas; 334 canvas->updateDeviceCMCache(); 335 336 fClipStack = canvas->fClipStack; 337 fCurrLayer = canvas->fMCRec->fTopLayer; 338 fSkipEmptyClips = skipEmptyClips; 339 } 340 341 bool next() { 342 // skip over recs with empty clips 343 if (fSkipEmptyClips) { 344 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) { 345 fCurrLayer = fCurrLayer->fNext; 346 } 347 } 348 349 const DeviceCM* rec = fCurrLayer; 350 if (rec && rec->fDevice) { 351 352 fMatrix = rec->fMatrix; 353 fRC = &rec->fClip; 354 fDevice = rec->fDevice; 355 if (!fDevice->accessPixels(&fDst)) { 356 fDst.reset(fDevice->imageInfo(), nullptr, 0); 357 } 358 fPaint = rec->fPaint; 359 SkDEBUGCODE(this->validate();) 360 361 fCurrLayer = rec->fNext; 362 // fCurrLayer may be nullptr now 363 364 return true; 365 } 366 return false; 367 } 368 369 SkBaseDevice* getDevice() const { return fDevice; } 370 const SkRasterClip& getClip() const { return *fRC; } 371 int getX() const { return fDevice->getOrigin().x(); } 372 int getY() const { return fDevice->getOrigin().y(); } 373 const SkMatrix& getMatrix() const { return *fMatrix; } 374 const SkPaint* getPaint() const { return fPaint; } 375 376private: 377 SkCanvas* fCanvas; 378 const DeviceCM* fCurrLayer; 379 const SkPaint* fPaint; // May be null. 380 SkBool8 fSkipEmptyClips; 381 382 typedef SkDraw INHERITED; 383}; 384 385///////////////////////////////////////////////////////////////////////////// 386 387static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) { 388 return lazy->isValid() ? lazy->get() : lazy->set(orig); 389} 390 391/** 392 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that 393 * colorfilter, else return nullptr. 394 */ 395static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) { 396 SkImageFilter* imgf = paint.getImageFilter(); 397 if (!imgf) { 398 return nullptr; 399 } 400 401 SkColorFilter* imgCFPtr; 402 if (!imgf->asAColorFilter(&imgCFPtr)) { 403 return nullptr; 404 } 405 sk_sp<SkColorFilter> imgCF(imgCFPtr); 406 407 SkColorFilter* paintCF = paint.getColorFilter(); 408 if (nullptr == paintCF) { 409 // there is no existing paint colorfilter, so we can just return the imagefilter's 410 return imgCF; 411 } 412 413 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF) 414 // and we need to combine them into a single colorfilter. 415 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF)); 416} 417 418/** 419 * There are many bounds in skia. A circle's bounds is just its center extended by its radius. 420 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw 421 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional 422 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters, 423 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the 424 * conservative "effective" bounds based on the settings in the paint... with one exception. This 425 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is 426 * deliberately ignored. 427 */ 428static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint, 429 const SkRect& rawBounds, 430 SkRect* storage) { 431 SkPaint tmpUnfiltered(paint); 432 tmpUnfiltered.setImageFilter(nullptr); 433 if (tmpUnfiltered.canComputeFastBounds()) { 434 return tmpUnfiltered.computeFastBounds(rawBounds, storage); 435 } else { 436 return rawBounds; 437 } 438} 439 440class AutoDrawLooper { 441public: 442 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the 443 // paint. It's used to determine the size of the offscreen layer for filters. 444 // If null, the clip will be used instead. 445 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint, 446 bool skipLayerForImageFilter = false, 447 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) { 448 fCanvas = canvas; 449#ifdef SK_SUPPORT_LEGACY_DRAWFILTER 450 fFilter = canvas->getDrawFilter(); 451#else 452 fFilter = nullptr; 453#endif 454 fPaint = &fOrigPaint; 455 fSaveCount = canvas->getSaveCount(); 456 fTempLayerForImageFilter = false; 457 fDone = false; 458 459 auto simplifiedCF = image_to_color_filter(fOrigPaint); 460 if (simplifiedCF) { 461 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint); 462 paint->setColorFilter(std::move(simplifiedCF)); 463 paint->setImageFilter(nullptr); 464 fPaint = paint; 465 } 466 467 if (!skipLayerForImageFilter && fPaint->getImageFilter()) { 468 /** 469 * We implement ImageFilters for a given draw by creating a layer, then applying the 470 * imagefilter to the pixels of that layer (its backing surface/image), and then 471 * we call restore() to xfer that layer to the main canvas. 472 * 473 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode) 474 * 2. Generate the src pixels: 475 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper) 476 * return (fPaint). We then draw the primitive (using srcover) into a cleared 477 * buffer/surface. 478 * 3. Restore the layer created in #1 479 * The imagefilter is passed the buffer/surface from the layer (now filled with the 480 * src pixels of the primitive). It returns a new "filtered" buffer, which we 481 * draw onto the previous layer using the xfermode from the original paint. 482 */ 483 SkPaint tmp; 484 tmp.setImageFilter(fPaint->getImageFilter()); 485 tmp.setXfermode(sk_ref_sp(fPaint->getXfermode())); 486 SkRect storage; 487 if (rawBounds) { 488 // Make rawBounds include all paint outsets except for those due to image filters. 489 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage); 490 } 491 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp), 492 SkCanvas::kFullLayer_SaveLayerStrategy); 493 fTempLayerForImageFilter = true; 494 // we remove the imagefilter/xfermode inside doNext() 495 } 496 497 if (SkDrawLooper* looper = paint.getLooper()) { 498 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>( 499 looper->contextSize()); 500 fLooperContext = looper->createContext(canvas, buffer); 501 fIsSimple = false; 502 } else { 503 fLooperContext = nullptr; 504 // can we be marked as simple? 505 fIsSimple = !fFilter && !fTempLayerForImageFilter; 506 } 507 508 uint32_t oldFlags = paint.getFlags(); 509 fNewPaintFlags = filter_paint_flags(props, oldFlags); 510 if (fIsSimple && (fNewPaintFlags != oldFlags)) { 511 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint); 512 paint->setFlags(fNewPaintFlags); 513 fPaint = paint; 514 // if we're not simple, doNext() will take care of calling setFlags() 515 } 516 } 517 518 ~AutoDrawLooper() { 519 if (fTempLayerForImageFilter) { 520 fCanvas->internalRestore(); 521 } 522 SkASSERT(fCanvas->getSaveCount() == fSaveCount); 523 } 524 525 const SkPaint& paint() const { 526 SkASSERT(fPaint); 527 return *fPaint; 528 } 529 530 bool next(SkDrawFilter::Type drawType) { 531 if (fDone) { 532 return false; 533 } else if (fIsSimple) { 534 fDone = true; 535 return !fPaint->nothingToDraw(); 536 } else { 537 return this->doNext(drawType); 538 } 539 } 540 541private: 542 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it 543 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it 544 SkCanvas* fCanvas; 545 const SkPaint& fOrigPaint; 546 SkDrawFilter* fFilter; 547 const SkPaint* fPaint; 548 int fSaveCount; 549 uint32_t fNewPaintFlags; 550 bool fTempLayerForImageFilter; 551 bool fDone; 552 bool fIsSimple; 553 SkDrawLooper::Context* fLooperContext; 554 SkSmallAllocator<1, 32> fLooperContextAllocator; 555 556 bool doNext(SkDrawFilter::Type drawType); 557}; 558 559bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) { 560 fPaint = nullptr; 561 SkASSERT(!fIsSimple); 562 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter); 563 564 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ? 565 *fLazyPaintInit.get() : fOrigPaint); 566 paint->setFlags(fNewPaintFlags); 567 568 if (fTempLayerForImageFilter) { 569 paint->setImageFilter(nullptr); 570 paint->setXfermode(nullptr); 571 } 572 573 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) { 574 fDone = true; 575 return false; 576 } 577 if (fFilter) { 578 if (!fFilter->filter(paint, drawType)) { 579 fDone = true; 580 return false; 581 } 582 if (nullptr == fLooperContext) { 583 // no looper means we only draw once 584 fDone = true; 585 } 586 } 587 fPaint = paint; 588 589 // if we only came in here for the imagefilter, mark us as done 590 if (!fLooperContext && !fFilter) { 591 fDone = true; 592 } 593 594 // call this after any possible paint modifiers 595 if (fPaint->nothingToDraw()) { 596 fPaint = nullptr; 597 return false; 598 } 599 return true; 600} 601 602////////// macros to place around the internal draw calls ////////////////// 603 604#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \ 605 this->predrawNotify(); \ 606 AutoDrawLooper looper(this, fProps, paint, skipLayerForFilter, bounds); \ 607 while (looper.next(SkDrawFilter::kBitmap_Type)) { \ 608 SkDrawIter iter(this); 609 610 611#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \ 612 this->predrawNotify(); \ 613 AutoDrawLooper looper(this, fProps, paint, true); \ 614 while (looper.next(type)) { \ 615 SkDrawIter iter(this); 616 617#define LOOPER_BEGIN(paint, type, bounds) \ 618 this->predrawNotify(); \ 619 AutoDrawLooper looper(this, fProps, paint, false, bounds); \ 620 while (looper.next(type)) { \ 621 SkDrawIter iter(this); 622 623#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \ 624 this->predrawNotify(bounds, &paint, auxOpaque); \ 625 AutoDrawLooper looper(this, fProps, paint, false, bounds); \ 626 while (looper.next(type)) { \ 627 SkDrawIter iter(this); 628 629#define LOOPER_END } 630 631//////////////////////////////////////////////////////////////////////////// 632 633void SkCanvas::resetForNextPicture(const SkIRect& bounds) { 634 this->restoreToCount(1); 635 fCachedLocalClipBounds.setEmpty(); 636 fCachedLocalClipBoundsDirty = true; 637 fClipStack->reset(); 638 fMCRec->reset(bounds); 639 640 // We're peering through a lot of structs here. Only at this scope do we 641 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice). 642 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size()); 643} 644 645SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) { 646 if (device && device->forceConservativeRasterClip()) { 647 flags = InitFlags(flags | kConservativeRasterClip_InitFlag); 648 } 649 // Since init() is only called once by our constructors, it is safe to perform this 650 // const-cast. 651 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag); 652 653 fCachedLocalClipBounds.setEmpty(); 654 fCachedLocalClipBoundsDirty = true; 655 fAllowSoftClip = true; 656 fAllowSimplifyClip = false; 657 fDeviceCMDirty = true; 658 fSaveCount = 1; 659 fMetaData = nullptr; 660#ifdef SK_EXPERIMENTAL_SHADOWING 661 fLights = nullptr; 662#endif 663 664 fClipStack.reset(new SkClipStack); 665 666 fMCRec = (MCRec*)fMCStack.push_back(); 667 new (fMCRec) MCRec(fConservativeRasterClip); 668 669 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage)); 670 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage; 671 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip, 672 fMCRec->fMatrix); 673 674 fMCRec->fTopLayer = fMCRec->fLayer; 675 676 fSurfaceBase = nullptr; 677 678 if (device) { 679 // The root device and the canvas should always have the same pixel geometry 680 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry()); 681 fMCRec->fLayer->fDevice = SkRef(device); 682 fMCRec->fRasterClip.setRect(device->getGlobalBounds()); 683 } 684 return device; 685} 686 687SkCanvas::SkCanvas() 688 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 689 , fProps(SkSurfaceProps::kLegacyFontHost_InitType) 690 , fConservativeRasterClip(false) 691{ 692 inc_canvas(); 693 694 this->init(nullptr, kDefault_InitFlags); 695} 696 697static SkBitmap make_nopixels(int width, int height) { 698 SkBitmap bitmap; 699 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height)); 700 return bitmap; 701} 702 703class SkNoPixelsBitmapDevice : public SkBitmapDevice { 704public: 705 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps) 706 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps) 707 { 708 this->setOrigin(bounds.x(), bounds.y()); 709 } 710 711private: 712 713 typedef SkBitmapDevice INHERITED; 714}; 715 716SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props) 717 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 718 , fProps(SkSurfacePropsCopyOrDefault(props)) 719 , fConservativeRasterClip(false) 720{ 721 inc_canvas(); 722 723 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps), 724 kDefault_InitFlags)->unref(); 725} 726 727SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags) 728 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 729 , fProps(SkSurfaceProps::kLegacyFontHost_InitType) 730 , fConservativeRasterClip(false) 731{ 732 inc_canvas(); 733 734 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref(); 735} 736 737SkCanvas::SkCanvas(SkBaseDevice* device) 738 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 739 , fProps(device->surfaceProps()) 740 , fConservativeRasterClip(false) 741{ 742 inc_canvas(); 743 744 this->init(device, kDefault_InitFlags); 745} 746 747SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags) 748 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 749 , fProps(device->surfaceProps()) 750 , fConservativeRasterClip(false) 751{ 752 inc_canvas(); 753 754 this->init(device, flags); 755} 756 757SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props) 758 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 759 , fProps(props) 760 , fConservativeRasterClip(false) 761{ 762 inc_canvas(); 763 764 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps)); 765 this->init(device, kDefault_InitFlags); 766} 767 768SkCanvas::SkCanvas(const SkBitmap& bitmap) 769 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 770 , fProps(SkSurfaceProps::kLegacyFontHost_InitType) 771 , fConservativeRasterClip(false) 772{ 773 inc_canvas(); 774 775 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps)); 776 this->init(device, kDefault_InitFlags); 777} 778 779SkCanvas::~SkCanvas() { 780 // free up the contents of our deque 781 this->restoreToCount(1); // restore everything but the last 782 783 this->internalRestore(); // restore the last, since we're going away 784 785 delete fMetaData; 786 787 dec_canvas(); 788} 789 790#ifdef SK_SUPPORT_LEGACY_DRAWFILTER 791SkDrawFilter* SkCanvas::getDrawFilter() const { 792 return fMCRec->fFilter; 793} 794 795SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) { 796 this->checkForDeferredSave(); 797 SkRefCnt_SafeAssign(fMCRec->fFilter, filter); 798 return filter; 799} 800#endif 801 802SkMetaData& SkCanvas::getMetaData() { 803 // metadata users are rare, so we lazily allocate it. If that changes we 804 // can decide to just make it a field in the device (rather than a ptr) 805 if (nullptr == fMetaData) { 806 fMetaData = new SkMetaData; 807 } 808 return *fMetaData; 809} 810 811/////////////////////////////////////////////////////////////////////////////// 812 813void SkCanvas::flush() { 814 this->onFlush(); 815} 816 817void SkCanvas::onFlush() { 818 SkBaseDevice* device = this->getDevice(); 819 if (device) { 820 device->flush(); 821 } 822} 823 824SkISize SkCanvas::getBaseLayerSize() const { 825 SkBaseDevice* d = this->getDevice(); 826 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0); 827} 828 829SkIRect SkCanvas::getTopLayerBounds() const { 830 SkBaseDevice* d = this->getTopDevice(); 831 if (!d) { 832 return SkIRect::MakeEmpty(); 833 } 834 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height()); 835} 836 837SkBaseDevice* SkCanvas::getDevice() const { 838 // return root device 839 MCRec* rec = (MCRec*) fMCStack.front(); 840 SkASSERT(rec && rec->fLayer); 841 return rec->fLayer->fDevice; 842} 843 844SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const { 845 if (updateMatrixClip) { 846 const_cast<SkCanvas*>(this)->updateDeviceCMCache(); 847 } 848 return fMCRec->fTopLayer->fDevice; 849} 850 851bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) { 852 if (kUnknown_SkColorType == bitmap->colorType()) { 853 return false; 854 } 855 856 bool weAllocated = false; 857 if (nullptr == bitmap->pixelRef()) { 858 if (!bitmap->tryAllocPixels()) { 859 return false; 860 } 861 weAllocated = true; 862 } 863 864 SkAutoPixmapUnlock unlocker; 865 if (bitmap->requestLock(&unlocker)) { 866 const SkPixmap& pm = unlocker.pixmap(); 867 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) { 868 return true; 869 } 870 } 871 872 if (weAllocated) { 873 bitmap->setPixelRef(nullptr); 874 } 875 return false; 876} 877 878bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) { 879 SkIRect r = srcRect; 880 const SkISize size = this->getBaseLayerSize(); 881 if (!r.intersect(0, 0, size.width(), size.height())) { 882 bitmap->reset(); 883 return false; 884 } 885 886 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) { 887 // bitmap will already be reset. 888 return false; 889 } 890 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) { 891 bitmap->reset(); 892 return false; 893 } 894 return true; 895} 896 897bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) { 898 SkBaseDevice* device = this->getDevice(); 899 if (!device) { 900 return false; 901 } 902 const SkISize size = this->getBaseLayerSize(); 903 904 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y); 905 if (!rec.trim(size.width(), size.height())) { 906 return false; 907 } 908 909 // The device can assert that the requested area is always contained in its bounds 910 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY); 911} 912 913bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) { 914 SkAutoPixmapUnlock unlocker; 915 if (bitmap.requestLock(&unlocker)) { 916 const SkPixmap& pm = unlocker.pixmap(); 917 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y); 918 } 919 return false; 920} 921 922bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes, 923 int x, int y) { 924 switch (origInfo.colorType()) { 925 case kUnknown_SkColorType: 926 case kIndex_8_SkColorType: 927 return false; 928 default: 929 break; 930 } 931 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) { 932 return false; 933 } 934 935 const SkISize size = this->getBaseLayerSize(); 936 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height()); 937 if (!target.intersect(0, 0, size.width(), size.height())) { 938 return false; 939 } 940 941 SkBaseDevice* device = this->getDevice(); 942 if (!device) { 943 return false; 944 } 945 946 // the intersect may have shrunk info's logical size 947 const SkImageInfo info = origInfo.makeWH(target.width(), target.height()); 948 949 // if x or y are negative, then we have to adjust pixels 950 if (x > 0) { 951 x = 0; 952 } 953 if (y > 0) { 954 y = 0; 955 } 956 // here x,y are either 0 or negative 957 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel()); 958 959 // Tell our owning surface to bump its generation ID 960 const bool completeOverwrite = info.dimensions() == size; 961 this->predrawNotify(completeOverwrite); 962 963 // The device can assert that the requested area is always contained in its bounds 964 return device->writePixels(info, pixels, rowBytes, target.x(), target.y()); 965} 966 967SkCanvas* SkCanvas::canvasForDrawIter() { 968 return this; 969} 970 971////////////////////////////////////////////////////////////////////////////// 972 973void SkCanvas::updateDeviceCMCache() { 974 if (fDeviceCMDirty) { 975 const SkMatrix& totalMatrix = this->getTotalMatrix(); 976 const SkRasterClip& totalClip = fMCRec->fRasterClip; 977 DeviceCM* layer = fMCRec->fTopLayer; 978 979 if (nullptr == layer->fNext) { // only one layer 980 layer->updateMC(totalMatrix, totalClip, *fClipStack, nullptr); 981 } else { 982 SkRasterClip clip(totalClip); 983 do { 984 layer->updateMC(totalMatrix, clip, *fClipStack, &clip); 985 } while ((layer = layer->fNext) != nullptr); 986 } 987 fDeviceCMDirty = false; 988 } 989} 990 991/////////////////////////////////////////////////////////////////////////////// 992 993void SkCanvas::checkForDeferredSave() { 994 if (fMCRec->fDeferredSaveCount > 0) { 995 this->doSave(); 996 } 997} 998 999int SkCanvas::getSaveCount() const { 1000#ifdef SK_DEBUG 1001 int count = 0; 1002 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart); 1003 for (;;) { 1004 const MCRec* rec = (const MCRec*)iter.next(); 1005 if (!rec) { 1006 break; 1007 } 1008 count += 1 + rec->fDeferredSaveCount; 1009 } 1010 SkASSERT(count == fSaveCount); 1011#endif 1012 return fSaveCount; 1013} 1014 1015int SkCanvas::save() { 1016 fSaveCount += 1; 1017 fMCRec->fDeferredSaveCount += 1; 1018 return this->getSaveCount() - 1; // return our prev value 1019} 1020 1021void SkCanvas::doSave() { 1022 this->willSave(); 1023 1024 SkASSERT(fMCRec->fDeferredSaveCount > 0); 1025 fMCRec->fDeferredSaveCount -= 1; 1026 this->internalSave(); 1027} 1028 1029void SkCanvas::restore() { 1030 if (fMCRec->fDeferredSaveCount > 0) { 1031 SkASSERT(fSaveCount > 1); 1032 fSaveCount -= 1; 1033 fMCRec->fDeferredSaveCount -= 1; 1034 } else { 1035 // check for underflow 1036 if (fMCStack.count() > 1) { 1037 this->willRestore(); 1038 SkASSERT(fSaveCount > 1); 1039 fSaveCount -= 1; 1040 this->internalRestore(); 1041 this->didRestore(); 1042 } 1043 } 1044} 1045 1046void SkCanvas::restoreToCount(int count) { 1047 // sanity check 1048 if (count < 1) { 1049 count = 1; 1050 } 1051 1052 int n = this->getSaveCount() - count; 1053 for (int i = 0; i < n; ++i) { 1054 this->restore(); 1055 } 1056} 1057 1058void SkCanvas::internalSave() { 1059 MCRec* newTop = (MCRec*)fMCStack.push_back(); 1060 new (newTop) MCRec(*fMCRec); // balanced in restore() 1061 fMCRec = newTop; 1062 1063 fClipStack->save(); 1064} 1065 1066bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) { 1067#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG 1068 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag); 1069#else 1070 return true; 1071#endif 1072} 1073 1074bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags, 1075 SkIRect* intersection, const SkImageFilter* imageFilter) { 1076 SkIRect clipBounds; 1077 if (!this->getClipDeviceBounds(&clipBounds)) { 1078 return false; 1079 } 1080 1081 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix() 1082 1083 if (imageFilter) { 1084 clipBounds = imageFilter->filterBounds(clipBounds, ctm); 1085 if (bounds && !imageFilter->canComputeFastBounds()) { 1086 bounds = nullptr; 1087 } 1088 } 1089 SkIRect ir; 1090 if (bounds) { 1091 SkRect r; 1092 1093 ctm.mapRect(&r, *bounds); 1094 r.roundOut(&ir); 1095 // early exit if the layer's bounds are clipped out 1096 if (!ir.intersect(clipBounds)) { 1097 if (BoundsAffectsClip(saveLayerFlags)) { 1098 fCachedLocalClipBoundsDirty = true; 1099 fMCRec->fRasterClip.setEmpty(); 1100 } 1101 return false; 1102 } 1103 } else { // no user bounds, so just use the clip 1104 ir = clipBounds; 1105 } 1106 SkASSERT(!ir.isEmpty()); 1107 1108 if (BoundsAffectsClip(saveLayerFlags)) { 1109 // Simplify the current clips since they will be applied properly during restore() 1110 fCachedLocalClipBoundsDirty = true; 1111 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op); 1112 fMCRec->fRasterClip.setRect(ir); 1113 } 1114 1115 if (intersection) { 1116 *intersection = ir; 1117 } 1118 return true; 1119} 1120 1121 1122int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) { 1123 return this->saveLayer(SaveLayerRec(bounds, paint, 0)); 1124} 1125 1126int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) { 1127 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag)); 1128} 1129 1130int SkCanvas::saveLayer(const SaveLayerRec& origRec) { 1131 SaveLayerRec rec(origRec); 1132 if (gIgnoreSaveLayerBounds) { 1133 rec.fBounds = nullptr; 1134 } 1135 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec); 1136 fSaveCount += 1; 1137 this->internalSaveLayer(rec, strategy); 1138 return this->getSaveCount() - 1; 1139} 1140 1141void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter, 1142 SkBaseDevice* dst, const SkMatrix& ctm, 1143 const SkClipStack* clipStack) { 1144 SkDraw draw; 1145 SkRasterClip rc; 1146 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height())); 1147 if (!dst->accessPixels(&draw.fDst)) { 1148 draw.fDst.reset(dst->imageInfo(), nullptr, 0); 1149 } 1150 draw.fMatrix = &SkMatrix::I(); 1151 draw.fRC = &rc; 1152 draw.fClipStack = clipStack; 1153 draw.fDevice = dst; 1154 1155 SkPaint p; 1156 p.setImageFilter(filter->makeWithLocalMatrix(ctm)); 1157 1158 int x = src->getOrigin().x() - dst->getOrigin().x(); 1159 int y = src->getOrigin().y() - dst->getOrigin().y(); 1160 auto special = src->snapSpecial(); 1161 if (special) { 1162 dst->drawSpecial(draw, special.get(), x, y, p); 1163 } 1164} 1165 1166static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque, 1167 const SkPaint* paint) { 1168 // need to force L32 for now if we have an image filter. Once filters support other colortypes 1169 // e.g. sRGB or F16, we can remove this check 1170 // SRGBTODO: Can we remove this check now? 1171 const bool hasImageFilter = paint && paint->getImageFilter(); 1172 1173 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType; 1174 if ((prev.bytesPerPixel() < 4) || hasImageFilter) { 1175 // force to L32 1176 return SkImageInfo::MakeN32(w, h, alphaType); 1177 } else { 1178 // keep the same characteristics as the prev 1179 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, sk_ref_sp(prev.colorSpace())); 1180 } 1181} 1182 1183void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) { 1184 const SkRect* bounds = rec.fBounds; 1185 const SkPaint* paint = rec.fPaint; 1186 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags; 1187 1188#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG 1189 saveLayerFlags &= ~kDontClipToLayer_PrivateSaveLayerFlag; 1190#endif 1191 1192 SkLazyPaint lazyP; 1193 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL; 1194 SkMatrix stashedMatrix = fMCRec->fMatrix; 1195 SkMatrix remainder; 1196 SkSize scale; 1197 /* 1198 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc. 1199 * but they do handle scaling. To accommodate this, we do the following: 1200 * 1201 * 1. Stash off the current CTM 1202 * 2. Decompose the CTM into SCALE and REMAINDER 1203 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that 1204 * contains the REMAINDER 1205 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM) 1206 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output 1207 * of the original imagefilter, and draw that (via drawSprite) 1208 * 6. Unwack the CTM to its original state (i.e. stashedMatrix) 1209 * 1210 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer 1211 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter. 1212 */ 1213 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() && 1214 stashedMatrix.decomposeScale(&scale, &remainder)) 1215 { 1216 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix 1217 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height())); 1218 SkPaint* p = lazyP.set(*paint); 1219 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder, 1220 SkFilterQuality::kLow_SkFilterQuality, 1221 sk_ref_sp(imageFilter))); 1222 imageFilter = p->getImageFilter(); 1223 paint = p; 1224 } 1225 1226 // do this before we create the layer. We don't call the public save() since 1227 // that would invoke a possibly overridden virtual 1228 this->internalSave(); 1229 1230 fDeviceCMDirty = true; 1231 1232 SkIRect ir; 1233 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) { 1234 return; 1235 } 1236 1237 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about 1238 // the clipRectBounds() call above? 1239 if (kNoLayer_SaveLayerStrategy == strategy) { 1240 return; 1241 } 1242 1243 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag); 1244 SkPixelGeometry geo = fProps.pixelGeometry(); 1245 if (paint) { 1246 // TODO: perhaps add a query to filters so we might preserve opaqueness... 1247 if (paint->getImageFilter() || paint->getColorFilter()) { 1248 isOpaque = false; 1249 geo = kUnknown_SkPixelGeometry; 1250 } 1251 } 1252 1253 SkBaseDevice* priorDevice = this->getTopDevice(); 1254 if (nullptr == priorDevice) { 1255 SkDebugf("Unable to find device for layer."); 1256 return; 1257 } 1258 1259 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque, 1260 paint); 1261 1262 SkAutoTUnref<SkBaseDevice> newDevice; 1263 { 1264 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() || 1265 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag); 1266 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage; 1267 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo, 1268 preserveLCDText); 1269 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint)); 1270 if (!newDevice) { 1271 SkErrorInternals::SetError(kInternalError_SkError, 1272 "Unable to create device for layer."); 1273 return; 1274 } 1275 } 1276 newDevice->setOrigin(ir.fLeft, ir.fTop); 1277 1278 DeviceCM* layer = new DeviceCM(newDevice, paint, this, fConservativeRasterClip, stashedMatrix); 1279 1280 layer->fNext = fMCRec->fTopLayer; 1281 fMCRec->fLayer = layer; 1282 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer 1283 1284 if (rec.fBackdrop) { 1285 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice, 1286 fMCRec->fMatrix, this->getClipStack()); 1287 } 1288} 1289 1290int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) { 1291 if (0xFF == alpha) { 1292 return this->saveLayer(bounds, nullptr); 1293 } else { 1294 SkPaint tmpPaint; 1295 tmpPaint.setAlpha(alpha); 1296 return this->saveLayer(bounds, &tmpPaint); 1297 } 1298} 1299 1300void SkCanvas::internalRestore() { 1301 SkASSERT(fMCStack.count() != 0); 1302 1303 fDeviceCMDirty = true; 1304 fCachedLocalClipBoundsDirty = true; 1305 1306 fClipStack->restore(); 1307 1308 // reserve our layer (if any) 1309 DeviceCM* layer = fMCRec->fLayer; // may be null 1310 // now detach it from fMCRec so we can pop(). Gets freed after its drawn 1311 fMCRec->fLayer = nullptr; 1312 1313 // now do the normal restore() 1314 fMCRec->~MCRec(); // balanced in save() 1315 fMCStack.pop_back(); 1316 fMCRec = (MCRec*)fMCStack.back(); 1317 1318 /* Time to draw the layer's offscreen. We can't call the public drawSprite, 1319 since if we're being recorded, we don't want to record this (the 1320 recorder will have already recorded the restore). 1321 */ 1322 if (layer) { 1323 if (layer->fNext) { 1324 const SkIPoint& origin = layer->fDevice->getOrigin(); 1325 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint); 1326 // restore what we smashed in internalSaveLayer 1327 fMCRec->fMatrix = layer->fStashedMatrix; 1328 // reset this, since internalDrawDevice will have set it to true 1329 fDeviceCMDirty = true; 1330 delete layer; 1331 } else { 1332 // we're at the root 1333 SkASSERT(layer == (void*)fDeviceCMStorage); 1334 layer->~DeviceCM(); 1335 // no need to update fMCRec, 'cause we're killing the canvas 1336 } 1337 } 1338} 1339 1340sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) { 1341 if (nullptr == props) { 1342 props = &fProps; 1343 } 1344 return this->onNewSurface(info, *props); 1345} 1346 1347sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) { 1348 SkBaseDevice* dev = this->getDevice(); 1349 return dev ? dev->makeSurface(info, props) : nullptr; 1350} 1351 1352SkImageInfo SkCanvas::imageInfo() const { 1353 return this->onImageInfo(); 1354} 1355 1356SkImageInfo SkCanvas::onImageInfo() const { 1357 SkBaseDevice* dev = this->getDevice(); 1358 if (dev) { 1359 return dev->imageInfo(); 1360 } else { 1361 return SkImageInfo::MakeUnknown(0, 0); 1362 } 1363} 1364 1365bool SkCanvas::getProps(SkSurfaceProps* props) const { 1366 return this->onGetProps(props); 1367} 1368 1369bool SkCanvas::onGetProps(SkSurfaceProps* props) const { 1370 SkBaseDevice* dev = this->getDevice(); 1371 if (dev) { 1372 if (props) { 1373 *props = fProps; 1374 } 1375 return true; 1376 } else { 1377 return false; 1378 } 1379} 1380 1381#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS 1382const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) { 1383 SkPixmap pmap; 1384 if (this->peekPixels(&pmap)) { 1385 if (info) { 1386 *info = pmap.info(); 1387 } 1388 if (rowBytes) { 1389 *rowBytes = pmap.rowBytes(); 1390 } 1391 return pmap.addr(); 1392 } 1393 return nullptr; 1394} 1395#endif 1396 1397bool SkCanvas::peekPixels(SkPixmap* pmap) { 1398 return this->onPeekPixels(pmap); 1399} 1400 1401bool SkCanvas::onPeekPixels(SkPixmap* pmap) { 1402 SkBaseDevice* dev = this->getDevice(); 1403 return dev && dev->peekPixels(pmap); 1404} 1405 1406void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) { 1407 SkPixmap pmap; 1408 if (!this->onAccessTopLayerPixels(&pmap)) { 1409 return nullptr; 1410 } 1411 if (info) { 1412 *info = pmap.info(); 1413 } 1414 if (rowBytes) { 1415 *rowBytes = pmap.rowBytes(); 1416 } 1417 if (origin) { 1418 *origin = this->getTopDevice(false)->getOrigin(); 1419 } 1420 return pmap.writable_addr(); 1421} 1422 1423bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) { 1424 SkBaseDevice* dev = this->getTopDevice(); 1425 return dev && dev->accessPixels(pmap); 1426} 1427 1428///////////////////////////////////////////////////////////////////////////// 1429 1430void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) { 1431 SkPaint tmp; 1432 if (nullptr == paint) { 1433 paint = &tmp; 1434 } 1435 1436 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 1437 1438 while (iter.next()) { 1439 SkBaseDevice* dstDev = iter.fDevice; 1440 paint = &looper.paint(); 1441 SkImageFilter* filter = paint->getImageFilter(); 1442 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 1443 if (filter) { 1444 dstDev->drawSpecial(iter, srcDev->snapSpecial().get(), pos.x(), pos.y(), *paint); 1445 } else { 1446 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint); 1447 } 1448 } 1449 1450 LOOPER_END 1451} 1452 1453///////////////////////////////////////////////////////////////////////////// 1454 1455void SkCanvas::translate(SkScalar dx, SkScalar dy) { 1456 SkMatrix m; 1457 m.setTranslate(dx, dy); 1458 this->concat(m); 1459} 1460 1461void SkCanvas::scale(SkScalar sx, SkScalar sy) { 1462 SkMatrix m; 1463 m.setScale(sx, sy); 1464 this->concat(m); 1465} 1466 1467void SkCanvas::rotate(SkScalar degrees) { 1468 SkMatrix m; 1469 m.setRotate(degrees); 1470 this->concat(m); 1471} 1472 1473void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) { 1474 SkMatrix m; 1475 m.setRotate(degrees, px, py); 1476 this->concat(m); 1477} 1478 1479void SkCanvas::skew(SkScalar sx, SkScalar sy) { 1480 SkMatrix m; 1481 m.setSkew(sx, sy); 1482 this->concat(m); 1483} 1484 1485void SkCanvas::concat(const SkMatrix& matrix) { 1486 if (matrix.isIdentity()) { 1487 return; 1488 } 1489 1490 this->checkForDeferredSave(); 1491 fDeviceCMDirty = true; 1492 fCachedLocalClipBoundsDirty = true; 1493 fMCRec->fMatrix.preConcat(matrix); 1494 1495 this->didConcat(matrix); 1496} 1497 1498void SkCanvas::internalSetMatrix(const SkMatrix& matrix) { 1499 fDeviceCMDirty = true; 1500 fCachedLocalClipBoundsDirty = true; 1501 fMCRec->fMatrix = matrix; 1502} 1503 1504void SkCanvas::setMatrix(const SkMatrix& matrix) { 1505 this->checkForDeferredSave(); 1506 this->internalSetMatrix(matrix); 1507 this->didSetMatrix(matrix); 1508} 1509 1510void SkCanvas::resetMatrix() { 1511 this->setMatrix(SkMatrix::I()); 1512} 1513 1514#ifdef SK_EXPERIMENTAL_SHADOWING 1515void SkCanvas::translateZ(SkScalar z) { 1516 this->checkForDeferredSave(); 1517 this->fMCRec->fCurDrawDepth += z; 1518 this->didTranslateZ(z); 1519} 1520 1521SkScalar SkCanvas::getZ() const { 1522 return this->fMCRec->fCurDrawDepth; 1523} 1524 1525void SkCanvas::setLights(sk_sp<SkLights> lights) { 1526 this->fLights = lights; 1527} 1528 1529sk_sp<SkLights> SkCanvas::getLights() const { 1530 return this->fLights; 1531} 1532#endif 1533 1534////////////////////////////////////////////////////////////////////////////// 1535 1536void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 1537 if (!fAllowSoftClip) { 1538 doAA = false; 1539 } 1540 1541#ifdef SK_SUPPORT_PRECHECK_CLIPRECT 1542 // Check if we can quick-accept the clip call (and do nothing) 1543 // 1544 if (SkRegion::kIntersect_Op == op && !doAA && fMCRec->fMatrix.isScaleTranslate()) { 1545 SkRect devR; 1546 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect); 1547 // NOTE: this check is CTM specific, since we might round differently with a different 1548 // CTM. Thus this is only 100% reliable if there is not global CTM scale to be 1549 // applied later (i.e. if this is going into a picture). 1550 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) { 1551#if 0 1552 SkDebugf("ignored clipRect [%g %g %g %g]\n", 1553 rect.left(), rect.top(), rect.right(), rect.bottom()); 1554#endif 1555 return; 1556 } 1557 } 1558#endif 1559 1560 this->checkForDeferredSave(); 1561 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1562 this->onClipRect(rect, op, edgeStyle); 1563} 1564 1565void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1566#ifdef SK_ENABLE_CLIP_QUICKREJECT 1567 if (SkRegion::kIntersect_Op == op) { 1568 if (fMCRec->fRasterClip.isEmpty()) { 1569 return; 1570 } 1571 1572 if (this->quickReject(rect)) { 1573 fDeviceCMDirty = true; 1574 fCachedLocalClipBoundsDirty = true; 1575 1576 fClipStack->clipEmpty(); 1577 (void)fMCRec->fRasterClip.setEmpty(); 1578 return; 1579 } 1580 } 1581#endif 1582 1583 const bool isScaleTrans = fMCRec->fMatrix.isScaleTranslate(); 1584 SkRect devR; 1585 if (isScaleTrans) { 1586 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect); 1587 } 1588 1589#ifndef SK_SUPPORT_PRECHECK_CLIPRECT 1590 if (SkRegion::kIntersect_Op == op && 1591 kHard_ClipEdgeStyle == edgeStyle 1592 && isScaleTrans) 1593 { 1594 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) { 1595#if 0 1596 SkDebugf("------- ignored clipRect [%g %g %g %g]\n", 1597 rect.left(), rect.top(), rect.right(), rect.bottom()); 1598#endif 1599 return; 1600 } 1601 } 1602#endif 1603 1604 AutoValidateClip avc(this); 1605 1606 fDeviceCMDirty = true; 1607 fCachedLocalClipBoundsDirty = true; 1608 1609 if (isScaleTrans) { 1610 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle; 1611 fClipStack->clipDevRect(devR, op, isAA); 1612 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA); 1613 } else { 1614 // since we're rotated or some such thing, we convert the rect to a path 1615 // and clip against that, since it can handle any matrix. However, to 1616 // avoid recursion in the case where we are subclassed (e.g. Pictures) 1617 // we explicitly call "our" version of clipPath. 1618 SkPath path; 1619 1620 path.addRect(rect); 1621 this->SkCanvas::onClipPath(path, op, edgeStyle); 1622 } 1623} 1624 1625void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 1626 this->checkForDeferredSave(); 1627 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1628 if (rrect.isRect()) { 1629 this->onClipRect(rrect.getBounds(), op, edgeStyle); 1630 } else { 1631 this->onClipRRect(rrect, op, edgeStyle); 1632 } 1633} 1634 1635void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1636 SkRRect transformedRRect; 1637 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) { 1638 AutoValidateClip avc(this); 1639 1640 fDeviceCMDirty = true; 1641 fCachedLocalClipBoundsDirty = true; 1642 if (!fAllowSoftClip) { 1643 edgeStyle = kHard_ClipEdgeStyle; 1644 } 1645 1646 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle); 1647 1648 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op, 1649 kSoft_ClipEdgeStyle == edgeStyle); 1650 return; 1651 } 1652 1653 SkPath path; 1654 path.addRRect(rrect); 1655 // call the non-virtual version 1656 this->SkCanvas::onClipPath(path, op, edgeStyle); 1657} 1658 1659void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 1660 this->checkForDeferredSave(); 1661 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1662 1663 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) { 1664 SkRect r; 1665 if (path.isRect(&r)) { 1666 this->onClipRect(r, op, edgeStyle); 1667 return; 1668 } 1669 SkRRect rrect; 1670 if (path.isOval(&r)) { 1671 rrect.setOval(r); 1672 this->onClipRRect(rrect, op, edgeStyle); 1673 return; 1674 } 1675 if (path.isRRect(&rrect)) { 1676 this->onClipRRect(rrect, op, edgeStyle); 1677 return; 1678 } 1679 } 1680 1681 this->onClipPath(path, op, edgeStyle); 1682} 1683 1684void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1685#ifdef SK_ENABLE_CLIP_QUICKREJECT 1686 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { 1687 if (fMCRec->fRasterClip.isEmpty()) { 1688 return; 1689 } 1690 1691 if (this->quickReject(path.getBounds())) { 1692 fDeviceCMDirty = true; 1693 fCachedLocalClipBoundsDirty = true; 1694 1695 fClipStack->clipEmpty(); 1696 (void)fMCRec->fRasterClip.setEmpty(); 1697 return; 1698 } 1699 } 1700#endif 1701 1702 AutoValidateClip avc(this); 1703 1704 fDeviceCMDirty = true; 1705 fCachedLocalClipBoundsDirty = true; 1706 if (!fAllowSoftClip) { 1707 edgeStyle = kHard_ClipEdgeStyle; 1708 } 1709 1710 SkPath devPath; 1711 path.transform(fMCRec->fMatrix, &devPath); 1712 1713 // Check if the transfomation, or the original path itself 1714 // made us empty. Note this can also happen if we contained NaN 1715 // values. computing the bounds detects this, and will set our 1716 // bounds to empty if that is the case. (see SkRect::set(pts, count)) 1717 if (devPath.getBounds().isEmpty()) { 1718 // resetting the path will remove any NaN or other wanky values 1719 // that might upset our scan converter. 1720 devPath.reset(); 1721 } 1722 1723 // if we called path.swap() we could avoid a deep copy of this path 1724 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle); 1725 1726 if (fAllowSimplifyClip) { 1727 bool clipIsAA = getClipStack()->asPath(&devPath); 1728 if (clipIsAA) { 1729 edgeStyle = kSoft_ClipEdgeStyle; 1730 } 1731 1732 op = SkRegion::kReplace_Op; 1733 } 1734 1735 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle); 1736} 1737 1738void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1739 this->checkForDeferredSave(); 1740 this->onClipRegion(rgn, op); 1741} 1742 1743void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { 1744 AutoValidateClip avc(this); 1745 1746 fDeviceCMDirty = true; 1747 fCachedLocalClipBoundsDirty = true; 1748 1749 // todo: signal fClipStack that we have a region, and therefore (I guess) 1750 // we have to ignore it, and use the region directly? 1751 fClipStack->clipDevRect(rgn.getBounds(), op); 1752 1753 fMCRec->fRasterClip.op(rgn, op); 1754} 1755 1756#ifdef SK_DEBUG 1757void SkCanvas::validateClip() const { 1758 // construct clipRgn from the clipstack 1759 const SkBaseDevice* device = this->getDevice(); 1760 if (!device) { 1761 SkASSERT(this->isClipEmpty()); 1762 return; 1763 } 1764 1765 SkIRect ir; 1766 ir.set(0, 0, device->width(), device->height()); 1767 SkRasterClip tmpClip(ir, fConservativeRasterClip); 1768 1769 SkClipStack::B2TIter iter(*fClipStack); 1770 const SkClipStack::Element* element; 1771 while ((element = iter.next()) != nullptr) { 1772 switch (element->getType()) { 1773 case SkClipStack::Element::kRect_Type: 1774 element->getRect().round(&ir); 1775 tmpClip.op(ir, element->getOp()); 1776 break; 1777 case SkClipStack::Element::kEmpty_Type: 1778 tmpClip.setEmpty(); 1779 break; 1780 default: { 1781 SkPath path; 1782 element->asPath(&path); 1783 tmpClip.op(path, this->getTopLayerBounds(), element->getOp(), element->isAA()); 1784 break; 1785 } 1786 } 1787 } 1788} 1789#endif 1790 1791void SkCanvas::replayClips(ClipVisitor* visitor) const { 1792 SkClipStack::B2TIter iter(*fClipStack); 1793 const SkClipStack::Element* element; 1794 1795 while ((element = iter.next()) != nullptr) { 1796 element->replay(visitor); 1797 } 1798} 1799 1800/////////////////////////////////////////////////////////////////////////////// 1801 1802bool SkCanvas::isClipEmpty() const { 1803 return fMCRec->fRasterClip.isEmpty(); 1804} 1805 1806bool SkCanvas::isClipRect() const { 1807 return fMCRec->fRasterClip.isRect(); 1808} 1809 1810bool SkCanvas::quickReject(const SkRect& rect) const { 1811 if (!rect.isFinite()) 1812 return true; 1813 1814 if (fMCRec->fRasterClip.isEmpty()) { 1815 return true; 1816 } 1817 1818 if (fMCRec->fMatrix.hasPerspective()) { 1819 SkRect dst; 1820 fMCRec->fMatrix.mapRect(&dst, rect); 1821 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds()); 1822 } else { 1823 const SkRect& clipR = this->getLocalClipBounds(); 1824 1825 // for speed, do the most likely reject compares first 1826 // TODO: should we use | instead, or compare all 4 at once? 1827 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) { 1828 return true; 1829 } 1830 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) { 1831 return true; 1832 } 1833 return false; 1834 } 1835} 1836 1837bool SkCanvas::quickReject(const SkPath& path) const { 1838 return path.isEmpty() || this->quickReject(path.getBounds()); 1839} 1840 1841bool SkCanvas::getClipBounds(SkRect* bounds) const { 1842 SkIRect ibounds; 1843 if (!this->getClipDeviceBounds(&ibounds)) { 1844 return false; 1845 } 1846 1847 SkMatrix inverse; 1848 // if we can't invert the CTM, we can't return local clip bounds 1849 if (!fMCRec->fMatrix.invert(&inverse)) { 1850 if (bounds) { 1851 bounds->setEmpty(); 1852 } 1853 return false; 1854 } 1855 1856 if (bounds) { 1857 SkRect r; 1858 // adjust it outwards in case we are antialiasing 1859 const int inset = 1; 1860 1861 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset, 1862 ibounds.fRight + inset, ibounds.fBottom + inset); 1863 inverse.mapRect(bounds, r); 1864 } 1865 return true; 1866} 1867 1868bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const { 1869 const SkRasterClip& clip = fMCRec->fRasterClip; 1870 if (clip.isEmpty()) { 1871 if (bounds) { 1872 bounds->setEmpty(); 1873 } 1874 return false; 1875 } 1876 1877 if (bounds) { 1878 *bounds = clip.getBounds(); 1879 } 1880 return true; 1881} 1882 1883const SkMatrix& SkCanvas::getTotalMatrix() const { 1884 return fMCRec->fMatrix; 1885} 1886 1887const SkRegion& SkCanvas::internal_private_getTotalClip() const { 1888 return fMCRec->fRasterClip.forceGetBW(); 1889} 1890 1891GrDrawContext* SkCanvas::internal_private_accessTopLayerDrawContext() { 1892 SkBaseDevice* dev = this->getTopDevice(); 1893 return dev ? dev->accessDrawContext() : nullptr; 1894} 1895 1896GrContext* SkCanvas::getGrContext() { 1897 SkBaseDevice* device = this->getTopDevice(); 1898 return device ? device->context() : nullptr; 1899} 1900 1901void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner, 1902 const SkPaint& paint) { 1903 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()"); 1904 if (outer.isEmpty()) { 1905 return; 1906 } 1907 if (inner.isEmpty()) { 1908 this->drawRRect(outer, paint); 1909 return; 1910 } 1911 1912 // We don't have this method (yet), but technically this is what we should 1913 // be able to assert... 1914 // SkASSERT(outer.contains(inner)); 1915 // 1916 // For now at least check for containment of bounds 1917 SkASSERT(outer.getBounds().contains(inner.getBounds())); 1918 1919 this->onDrawDRRect(outer, inner, paint); 1920} 1921 1922// These need to stop being virtual -- clients need to override the onDraw... versions 1923 1924void SkCanvas::drawPaint(const SkPaint& paint) { 1925 this->onDrawPaint(paint); 1926} 1927 1928void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1929 this->onDrawRect(r, paint); 1930} 1931 1932void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) { 1933 this->onDrawOval(r, paint); 1934} 1935 1936void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 1937 this->onDrawRRect(rrect, paint); 1938} 1939 1940void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { 1941 this->onDrawPoints(mode, count, pts, paint); 1942} 1943 1944void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], 1945 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode, 1946 const uint16_t indices[], int indexCount, const SkPaint& paint) { 1947 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode, 1948 indices, indexCount, paint); 1949} 1950 1951void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 1952 this->onDrawPath(path, paint); 1953} 1954 1955void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) { 1956 RETURN_ON_NULL(image); 1957 this->onDrawImage(image, x, y, paint); 1958} 1959 1960void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst, 1961 const SkPaint* paint, SrcRectConstraint constraint) { 1962 RETURN_ON_NULL(image); 1963 if (dst.isEmpty() || src.isEmpty()) { 1964 return; 1965 } 1966 this->onDrawImageRect(image, &src, dst, paint, constraint); 1967} 1968 1969void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst, 1970 const SkPaint* paint, SrcRectConstraint constraint) { 1971 RETURN_ON_NULL(image); 1972 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint); 1973} 1974 1975void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint, 1976 SrcRectConstraint constraint) { 1977 RETURN_ON_NULL(image); 1978 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint, 1979 constraint); 1980} 1981 1982void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, 1983 const SkPaint* paint) { 1984 RETURN_ON_NULL(image); 1985 if (dst.isEmpty()) { 1986 return; 1987 } 1988 if (SkLatticeIter::Valid(image->width(), image->height(), center)) { 1989 this->onDrawImageNine(image, center, dst, paint); 1990 } else { 1991 this->drawImageRect(image, dst, paint); 1992 } 1993} 1994 1995void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) { 1996 if (bitmap.drawsNothing()) { 1997 return; 1998 } 1999 this->onDrawBitmap(bitmap, dx, dy, paint); 2000} 2001 2002void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst, 2003 const SkPaint* paint, SrcRectConstraint constraint) { 2004 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) { 2005 return; 2006 } 2007 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint); 2008} 2009 2010void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst, 2011 const SkPaint* paint, SrcRectConstraint constraint) { 2012 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint); 2013} 2014 2015void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint, 2016 SrcRectConstraint constraint) { 2017 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint, 2018 constraint); 2019} 2020 2021void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, 2022 const SkPaint* paint) { 2023 if (bitmap.drawsNothing() || dst.isEmpty()) { 2024 return; 2025 } 2026 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) { 2027 this->onDrawBitmapNine(bitmap, center, dst, paint); 2028 } else { 2029 this->drawBitmapRect(bitmap, dst, paint); 2030 } 2031 2032} 2033 2034void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst, 2035 const SkPaint* paint) { 2036 sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap); 2037 this->drawImageLattice(image.get(), lattice, dst, paint); 2038} 2039 2040void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, 2041 const SkPaint* paint) { 2042 RETURN_ON_NULL(image); 2043 if (dst.isEmpty()) { 2044 return; 2045 } 2046 if (SkLatticeIter::Valid(image->width(), image->height(), lattice)) { 2047 this->onDrawImageLattice(image, lattice, dst, paint); 2048 } else { 2049 this->drawImageRect(image, dst, paint); 2050 } 2051} 2052 2053void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], 2054 const SkColor colors[], int count, SkXfermode::Mode mode, 2055 const SkRect* cull, const SkPaint* paint) { 2056 RETURN_ON_NULL(atlas); 2057 if (count <= 0) { 2058 return; 2059 } 2060 SkASSERT(atlas); 2061 SkASSERT(xform); 2062 SkASSERT(tex); 2063 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint); 2064} 2065 2066void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) { 2067 if (key) { 2068 this->onDrawAnnotation(rect, key, value); 2069 } 2070} 2071 2072void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, 2073 const SkPaint* paint, SrcRectConstraint constraint) { 2074 if (src) { 2075 this->drawImageRect(image, *src, dst, paint, constraint); 2076 } else { 2077 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), 2078 dst, paint, constraint); 2079 } 2080} 2081void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, 2082 const SkPaint* paint, SrcRectConstraint constraint) { 2083 if (src) { 2084 this->drawBitmapRect(bitmap, *src, dst, paint, constraint); 2085 } else { 2086 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), 2087 dst, paint, constraint); 2088 } 2089} 2090 2091void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) { 2092 SkIRect layer_bounds = this->getTopLayerBounds(); 2093 if (matrix) { 2094 *matrix = this->getTotalMatrix(); 2095 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top()); 2096 } 2097 if (clip_bounds) { 2098 this->getClipDeviceBounds(clip_bounds); 2099 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top()); 2100 } 2101} 2102 2103////////////////////////////////////////////////////////////////////////////// 2104// These are the virtual drawing methods 2105////////////////////////////////////////////////////////////////////////////// 2106 2107void SkCanvas::onDiscard() { 2108 if (fSurfaceBase) { 2109 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode); 2110 } 2111} 2112 2113void SkCanvas::onDrawPaint(const SkPaint& paint) { 2114 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()"); 2115 this->internalDrawPaint(paint); 2116} 2117 2118void SkCanvas::internalDrawPaint(const SkPaint& paint) { 2119 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false) 2120 2121 while (iter.next()) { 2122 iter.fDevice->drawPaint(iter, looper.paint()); 2123 } 2124 2125 LOOPER_END 2126} 2127 2128void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], 2129 const SkPaint& paint) { 2130 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count)); 2131 if ((long)count <= 0) { 2132 return; 2133 } 2134 2135 SkRect r, storage; 2136 const SkRect* bounds = nullptr; 2137 if (paint.canComputeFastBounds()) { 2138 // special-case 2 points (common for drawing a single line) 2139 if (2 == count) { 2140 r.set(pts[0], pts[1]); 2141 } else { 2142 r.set(pts, SkToInt(count)); 2143 } 2144 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) { 2145 return; 2146 } 2147 bounds = &r; 2148 } 2149 2150 SkASSERT(pts != nullptr); 2151 2152 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds) 2153 2154 while (iter.next()) { 2155 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); 2156 } 2157 2158 LOOPER_END 2159} 2160 2161void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) { 2162 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()"); 2163 SkRect storage; 2164 const SkRect* bounds = nullptr; 2165 if (paint.canComputeFastBounds()) { 2166 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream. 2167 // To prevent accidental rejecting at this stage, we have to sort it before we check. 2168 SkRect tmp(r); 2169 tmp.sort(); 2170 2171 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) { 2172 return; 2173 } 2174 bounds = &r; 2175 } 2176 2177 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false) 2178 2179 while (iter.next()) { 2180 iter.fDevice->drawRect(iter, r, looper.paint()); 2181 } 2182 2183 LOOPER_END 2184} 2185 2186void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) { 2187 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()"); 2188 SkRect storage; 2189 const SkRect* bounds = nullptr; 2190 if (paint.canComputeFastBounds()) { 2191 if (this->quickReject(paint.computeFastBounds(oval, &storage))) { 2192 return; 2193 } 2194 bounds = &oval; 2195 } 2196 2197 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds) 2198 2199 while (iter.next()) { 2200 iter.fDevice->drawOval(iter, oval, looper.paint()); 2201 } 2202 2203 LOOPER_END 2204} 2205 2206void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { 2207 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()"); 2208 SkRect storage; 2209 const SkRect* bounds = nullptr; 2210 if (paint.canComputeFastBounds()) { 2211 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) { 2212 return; 2213 } 2214 bounds = &rrect.getBounds(); 2215 } 2216 2217 if (rrect.isRect()) { 2218 // call the non-virtual version 2219 this->SkCanvas::drawRect(rrect.getBounds(), paint); 2220 return; 2221 } else if (rrect.isOval()) { 2222 // call the non-virtual version 2223 this->SkCanvas::drawOval(rrect.getBounds(), paint); 2224 return; 2225 } 2226 2227 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) 2228 2229 while (iter.next()) { 2230 iter.fDevice->drawRRect(iter, rrect, looper.paint()); 2231 } 2232 2233 LOOPER_END 2234} 2235 2236void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, 2237 const SkPaint& paint) { 2238 SkRect storage; 2239 const SkRect* bounds = nullptr; 2240 if (paint.canComputeFastBounds()) { 2241 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) { 2242 return; 2243 } 2244 bounds = &outer.getBounds(); 2245 } 2246 2247 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) 2248 2249 while (iter.next()) { 2250 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint()); 2251 } 2252 2253 LOOPER_END 2254} 2255 2256void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { 2257 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()"); 2258 if (!path.isFinite()) { 2259 return; 2260 } 2261 2262 SkRect storage; 2263 const SkRect* bounds = nullptr; 2264 if (!path.isInverseFillType() && paint.canComputeFastBounds()) { 2265 const SkRect& pathBounds = path.getBounds(); 2266 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) { 2267 return; 2268 } 2269 bounds = &pathBounds; 2270 } 2271 2272 const SkRect& r = path.getBounds(); 2273 if (r.width() <= 0 && r.height() <= 0) { 2274 if (path.isInverseFillType()) { 2275 this->internalDrawPaint(paint); 2276 return; 2277 } 2278 } 2279 2280 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds) 2281 2282 while (iter.next()) { 2283 iter.fDevice->drawPath(iter, path, looper.paint()); 2284 } 2285 2286 LOOPER_END 2287} 2288 2289bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) { 2290 if (!paint.getImageFilter()) { 2291 return false; 2292 } 2293 2294 const SkMatrix& ctm = this->getTotalMatrix(); 2295 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) { 2296 return false; 2297 } 2298 2299 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds. 2300 // Once we can filter and the filter will return a result larger than itself, we should be 2301 // able to remove this constraint. 2302 // skbug.com/4526 2303 // 2304 SkPoint pt; 2305 ctm.mapXY(x, y, &pt); 2306 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h); 2307 return ir.contains(fMCRec->fRasterClip.getBounds()); 2308} 2309 2310void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) { 2311 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()"); 2312 SkRect bounds = SkRect::MakeXYWH(x, y, 2313 SkIntToScalar(image->width()), SkIntToScalar(image->height())); 2314 if (nullptr == paint || paint->canComputeFastBounds()) { 2315 SkRect tmp = bounds; 2316 if (paint) { 2317 paint->computeFastBounds(tmp, &tmp); 2318 } 2319 if (this->quickReject(tmp)) { 2320 return; 2321 } 2322 } 2323 2324 SkLazyPaint lazy; 2325 if (nullptr == paint) { 2326 paint = lazy.init(); 2327 } 2328 2329 sk_sp<SkSpecialImage> special; 2330 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(), 2331 *paint); 2332 if (drawAsSprite && paint->getImageFilter()) { 2333 special = this->getDevice()->makeSpecial(image); 2334 if (!special) { 2335 drawAsSprite = false; 2336 } 2337 } 2338 2339 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds) 2340 2341 while (iter.next()) { 2342 const SkPaint& pnt = looper.paint(); 2343 if (special) { 2344 SkPoint pt; 2345 iter.fMatrix->mapXY(x, y, &pt); 2346 iter.fDevice->drawSpecial(iter, special.get(), 2347 SkScalarRoundToInt(pt.fX), 2348 SkScalarRoundToInt(pt.fY), pnt); 2349 } else { 2350 iter.fDevice->drawImage(iter, image, x, y, pnt); 2351 } 2352 } 2353 2354 LOOPER_END 2355} 2356 2357void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, 2358 const SkPaint* paint) { 2359 if (nullptr == paint || paint->canComputeFastBounds()) { 2360 SkRect storage; 2361 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) { 2362 return; 2363 } 2364 } 2365 2366 SkLazyPaint lazy; 2367 if (nullptr == paint) { 2368 paint = lazy.init(); 2369 } 2370 2371 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst) 2372 2373 while (iter.next()) { 2374 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint()); 2375 } 2376 2377 LOOPER_END 2378} 2379 2380void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, 2381 const SkPaint* paint, SrcRectConstraint constraint) { 2382 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()"); 2383 if (nullptr == paint || paint->canComputeFastBounds()) { 2384 SkRect storage = dst; 2385 if (paint) { 2386 paint->computeFastBounds(dst, &storage); 2387 } 2388 if (this->quickReject(storage)) { 2389 return; 2390 } 2391 } 2392 SkLazyPaint lazy; 2393 if (nullptr == paint) { 2394 paint = lazy.init(); 2395 } 2396 2397 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst, 2398 image->isOpaque()) 2399 2400 while (iter.next()) { 2401 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint); 2402 } 2403 2404 LOOPER_END 2405} 2406 2407void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) { 2408 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()"); 2409 SkDEBUGCODE(bitmap.validate();) 2410 2411 if (bitmap.drawsNothing()) { 2412 return; 2413 } 2414 2415 SkLazyPaint lazy; 2416 if (nullptr == paint) { 2417 paint = lazy.init(); 2418 } 2419 2420 const SkMatrix matrix = SkMatrix::MakeTrans(x, y); 2421 2422 SkRect storage; 2423 const SkRect* bounds = nullptr; 2424 if (paint->canComputeFastBounds()) { 2425 bitmap.getBounds(&storage); 2426 matrix.mapRect(&storage); 2427 SkRect tmp = storage; 2428 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) { 2429 return; 2430 } 2431 bounds = &storage; 2432 } 2433 2434 sk_sp<SkSpecialImage> special; 2435 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(), 2436 *paint); 2437 if (drawAsSprite && paint->getImageFilter()) { 2438 special = this->getDevice()->makeSpecial(bitmap); 2439 if (!special) { 2440 drawAsSprite = false; 2441 } 2442 } 2443 2444 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds) 2445 2446 while (iter.next()) { 2447 const SkPaint& pnt = looper.paint(); 2448 if (special) { 2449 SkPoint pt; 2450 iter.fMatrix->mapXY(x, y, &pt); 2451 iter.fDevice->drawSpecial(iter, special.get(), 2452 SkScalarRoundToInt(pt.fX), 2453 SkScalarRoundToInt(pt.fY), pnt); 2454 } else { 2455 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint()); 2456 } 2457 } 2458 2459 LOOPER_END 2460} 2461 2462// this one is non-virtual, so it can be called safely by other canvas apis 2463void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, 2464 const SkRect& dst, const SkPaint* paint, 2465 SrcRectConstraint constraint) { 2466 if (bitmap.drawsNothing() || dst.isEmpty()) { 2467 return; 2468 } 2469 2470 if (nullptr == paint || paint->canComputeFastBounds()) { 2471 SkRect storage; 2472 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) { 2473 return; 2474 } 2475 } 2476 2477 SkLazyPaint lazy; 2478 if (nullptr == paint) { 2479 paint = lazy.init(); 2480 } 2481 2482 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst, 2483 bitmap.isOpaque()) 2484 2485 while (iter.next()) { 2486 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint); 2487 } 2488 2489 LOOPER_END 2490} 2491 2492void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, 2493 const SkPaint* paint, SrcRectConstraint constraint) { 2494 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()"); 2495 SkDEBUGCODE(bitmap.validate();) 2496 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint); 2497} 2498 2499void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, 2500 const SkPaint* paint) { 2501 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()"); 2502 2503 if (nullptr == paint || paint->canComputeFastBounds()) { 2504 SkRect storage; 2505 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) { 2506 return; 2507 } 2508 } 2509 2510 SkLazyPaint lazy; 2511 if (nullptr == paint) { 2512 paint = lazy.init(); 2513 } 2514 2515 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst) 2516 2517 while (iter.next()) { 2518 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint()); 2519 } 2520 2521 LOOPER_END 2522} 2523 2524void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, 2525 const SkPaint* paint) { 2526 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()"); 2527 SkDEBUGCODE(bitmap.validate();) 2528 2529 if (nullptr == paint || paint->canComputeFastBounds()) { 2530 SkRect storage; 2531 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) { 2532 return; 2533 } 2534 } 2535 2536 SkLazyPaint lazy; 2537 if (nullptr == paint) { 2538 paint = lazy.init(); 2539 } 2540 2541 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst) 2542 2543 while (iter.next()) { 2544 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint()); 2545 } 2546 2547 LOOPER_END 2548} 2549 2550class SkDeviceFilteredPaint { 2551public: 2552 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) { 2553 uint32_t filteredFlags = device->filterTextFlags(paint); 2554 if (filteredFlags != paint.getFlags()) { 2555 SkPaint* newPaint = fLazy.set(paint); 2556 newPaint->setFlags(filteredFlags); 2557 fPaint = newPaint; 2558 } else { 2559 fPaint = &paint; 2560 } 2561 } 2562 2563 const SkPaint& paint() const { return *fPaint; } 2564 2565private: 2566 const SkPaint* fPaint; 2567 SkLazyPaint fLazy; 2568}; 2569 2570void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, 2571 const SkRect& r, SkScalar textSize) { 2572 if (paint.getStyle() == SkPaint::kFill_Style) { 2573 draw.fDevice->drawRect(draw, r, paint); 2574 } else { 2575 SkPaint p(paint); 2576 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); 2577 draw.fDevice->drawRect(draw, r, p); 2578 } 2579} 2580 2581void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, 2582 const char text[], size_t byteLength, 2583 SkScalar x, SkScalar y) { 2584 SkASSERT(byteLength == 0 || text != nullptr); 2585 2586 // nothing to draw 2587 if (text == nullptr || byteLength == 0 || 2588 draw.fRC->isEmpty() || 2589 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) { 2590 return; 2591 } 2592 2593 SkScalar width = 0; 2594 SkPoint start; 2595 2596 start.set(0, 0); // to avoid warning 2597 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | 2598 SkPaint::kStrikeThruText_Flag)) { 2599 width = paint.measureText(text, byteLength); 2600 2601 SkScalar offsetX = 0; 2602 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 2603 offsetX = SkScalarHalf(width); 2604 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { 2605 offsetX = width; 2606 } 2607 start.set(x - offsetX, y); 2608 } 2609 2610 if (0 == width) { 2611 return; 2612 } 2613 2614 uint32_t flags = paint.getFlags(); 2615 2616 if (flags & (SkPaint::kUnderlineText_Flag | 2617 SkPaint::kStrikeThruText_Flag)) { 2618 SkScalar textSize = paint.getTextSize(); 2619 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 2620 SkRect r; 2621 2622 r.fLeft = start.fX; 2623 r.fRight = start.fX + width; 2624 2625 if (flags & SkPaint::kUnderlineText_Flag) { 2626 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, 2627 start.fY); 2628 r.fTop = offset; 2629 r.fBottom = offset + height; 2630 DrawRect(draw, paint, r, 1); 2631 } 2632 if (flags & SkPaint::kStrikeThruText_Flag) { 2633 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, 2634 start.fY); 2635 r.fTop = offset; 2636 r.fBottom = offset + height; 2637 DrawRect(draw, paint, r, 1); 2638 } 2639 } 2640} 2641 2642void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, 2643 const SkPaint& paint) { 2644 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr) 2645 2646 while (iter.next()) { 2647 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2648 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 2649 DrawTextDecorations(iter, dfp.paint(), 2650 static_cast<const char*>(text), byteLength, x, y); 2651 } 2652 2653 LOOPER_END 2654} 2655 2656void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], 2657 const SkPaint& paint) { 2658 SkPoint textOffset = SkPoint::Make(0, 0); 2659 2660 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr) 2661 2662 while (iter.next()) { 2663 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2664 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset, 2665 dfp.paint()); 2666 } 2667 2668 LOOPER_END 2669} 2670 2671void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], 2672 SkScalar constY, const SkPaint& paint) { 2673 2674 SkPoint textOffset = SkPoint::Make(0, constY); 2675 2676 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr) 2677 2678 while (iter.next()) { 2679 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2680 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset, 2681 dfp.paint()); 2682 } 2683 2684 LOOPER_END 2685} 2686 2687void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, 2688 const SkMatrix* matrix, const SkPaint& paint) { 2689 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr) 2690 2691 while (iter.next()) { 2692 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 2693 matrix, looper.paint()); 2694 } 2695 2696 LOOPER_END 2697} 2698 2699void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], 2700 const SkRect* cullRect, const SkPaint& paint) { 2701 if (cullRect && this->quickReject(*cullRect)) { 2702 return; 2703 } 2704 2705 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr) 2706 2707 while (iter.next()) { 2708 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint()); 2709 } 2710 2711 LOOPER_END 2712} 2713 2714void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 2715 const SkPaint& paint) { 2716 2717 SkRect storage; 2718 const SkRect* bounds = nullptr; 2719 if (paint.canComputeFastBounds()) { 2720 storage = blob->bounds().makeOffset(x, y); 2721 SkRect tmp; 2722 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) { 2723 return; 2724 } 2725 bounds = &storage; 2726 } 2727 2728 // We cannot filter in the looper as we normally do, because the paint is 2729 // incomplete at this point (text-related attributes are embedded within blob run paints). 2730 SkDrawFilter* drawFilter = fMCRec->fFilter; 2731 fMCRec->fFilter = nullptr; 2732 2733 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds) 2734 2735 while (iter.next()) { 2736 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 2737 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter); 2738 } 2739 2740 LOOPER_END 2741 2742 fMCRec->fFilter = drawFilter; 2743} 2744 2745// These will become non-virtual, so they always call the (virtual) onDraw... method 2746void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, 2747 const SkPaint& paint) { 2748 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()"); 2749 if (byteLength) { 2750 this->onDrawText(text, byteLength, x, y, paint); 2751 } 2752} 2753void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[], 2754 const SkPaint& paint) { 2755 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()"); 2756 if (byteLength) { 2757 this->onDrawPosText(text, byteLength, pos, paint); 2758 } 2759} 2760void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], 2761 SkScalar constY, const SkPaint& paint) { 2762 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()"); 2763 if (byteLength) { 2764 this->onDrawPosTextH(text, byteLength, xpos, constY, paint); 2765 } 2766} 2767void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path, 2768 const SkMatrix* matrix, const SkPaint& paint) { 2769 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()"); 2770 if (byteLength) { 2771 this->onDrawTextOnPath(text, byteLength, path, matrix, paint); 2772 } 2773} 2774void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], 2775 const SkRect* cullRect, const SkPaint& paint) { 2776 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()"); 2777 if (byteLength) { 2778 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint); 2779 } 2780} 2781void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 2782 const SkPaint& paint) { 2783 RETURN_ON_NULL(blob); 2784 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()"); 2785 this->onDrawTextBlob(blob, x, y, paint); 2786} 2787 2788void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount, 2789 const SkPoint verts[], const SkPoint texs[], 2790 const SkColor colors[], SkXfermode* xmode, 2791 const uint16_t indices[], int indexCount, 2792 const SkPaint& paint) { 2793 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()"); 2794 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr) 2795 2796 while (iter.next()) { 2797 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 2798 colors, xmode, indices, indexCount, 2799 looper.paint()); 2800 } 2801 2802 LOOPER_END 2803} 2804 2805void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4], 2806 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { 2807 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()"); 2808 if (nullptr == cubics) { 2809 return; 2810 } 2811 2812 // Since a patch is always within the convex hull of the control points, we discard it when its 2813 // bounding rectangle is completely outside the current clip. 2814 SkRect bounds; 2815 bounds.set(cubics, SkPatchUtils::kNumCtrlPts); 2816 if (this->quickReject(bounds)) { 2817 return; 2818 } 2819 2820 this->onDrawPatch(cubics, colors, texCoords, xmode, paint); 2821} 2822 2823void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], 2824 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { 2825 2826 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr) 2827 2828 while (iter.next()) { 2829 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint); 2830 } 2831 2832 LOOPER_END 2833} 2834 2835void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) { 2836 RETURN_ON_NULL(dr); 2837 if (x || y) { 2838 SkMatrix matrix = SkMatrix::MakeTrans(x, y); 2839 this->onDrawDrawable(dr, &matrix); 2840 } else { 2841 this->onDrawDrawable(dr, nullptr); 2842 } 2843} 2844 2845void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) { 2846 RETURN_ON_NULL(dr); 2847 if (matrix && matrix->isIdentity()) { 2848 matrix = nullptr; 2849 } 2850 this->onDrawDrawable(dr, matrix); 2851} 2852 2853void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) { 2854 SkRect bounds = dr->getBounds(); 2855 if (matrix) { 2856 matrix->mapRect(&bounds); 2857 } 2858 if (this->quickReject(bounds)) { 2859 return; 2860 } 2861 dr->draw(this, matrix); 2862} 2863 2864void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], 2865 const SkColor colors[], int count, SkXfermode::Mode mode, 2866 const SkRect* cull, const SkPaint* paint) { 2867 if (cull && this->quickReject(*cull)) { 2868 return; 2869 } 2870 2871 SkPaint pnt; 2872 if (paint) { 2873 pnt = *paint; 2874 } 2875 2876 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr) 2877 while (iter.next()) { 2878 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt); 2879 } 2880 LOOPER_END 2881} 2882 2883void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) { 2884 SkASSERT(key); 2885 2886 SkPaint paint; 2887 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr) 2888 while (iter.next()) { 2889 iter.fDevice->drawAnnotation(iter, rect, key, value); 2890 } 2891 LOOPER_END 2892} 2893 2894////////////////////////////////////////////////////////////////////////////// 2895// These methods are NOT virtual, and therefore must call back into virtual 2896// methods, rather than actually drawing themselves. 2897////////////////////////////////////////////////////////////////////////////// 2898 2899void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 2900 SkXfermode::Mode mode) { 2901 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()"); 2902 SkPaint paint; 2903 2904 paint.setARGB(a, r, g, b); 2905 if (SkXfermode::kSrcOver_Mode != mode) { 2906 paint.setXfermodeMode(mode); 2907 } 2908 this->drawPaint(paint); 2909} 2910 2911void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 2912 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()"); 2913 SkPaint paint; 2914 2915 paint.setColor(c); 2916 if (SkXfermode::kSrcOver_Mode != mode) { 2917 paint.setXfermodeMode(mode); 2918 } 2919 this->drawPaint(paint); 2920} 2921 2922void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 2923 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)"); 2924 SkPoint pt; 2925 2926 pt.set(x, y); 2927 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2928} 2929 2930void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 2931 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)"); 2932 SkPoint pt; 2933 SkPaint paint; 2934 2935 pt.set(x, y); 2936 paint.setColor(color); 2937 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2938} 2939 2940void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 2941 const SkPaint& paint) { 2942 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()"); 2943 SkPoint pts[2]; 2944 2945 pts[0].set(x0, y0); 2946 pts[1].set(x1, y1); 2947 this->drawPoints(kLines_PointMode, 2, pts, paint); 2948} 2949 2950void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 2951 SkScalar right, SkScalar bottom, 2952 const SkPaint& paint) { 2953 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()"); 2954 SkRect r; 2955 2956 r.set(left, top, right, bottom); 2957 this->drawRect(r, paint); 2958} 2959 2960void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 2961 const SkPaint& paint) { 2962 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()"); 2963 if (radius < 0) { 2964 radius = 0; 2965 } 2966 2967 SkRect r; 2968 r.set(cx - radius, cy - radius, cx + radius, cy + radius); 2969 this->drawOval(r, paint); 2970} 2971 2972void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 2973 const SkPaint& paint) { 2974 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()"); 2975 if (rx > 0 && ry > 0) { 2976 SkRRect rrect; 2977 rrect.setRectXY(r, rx, ry); 2978 this->drawRRect(rrect, paint); 2979 } else { 2980 this->drawRect(r, paint); 2981 } 2982} 2983 2984void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 2985 SkScalar sweepAngle, bool useCenter, 2986 const SkPaint& paint) { 2987 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()"); 2988 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 2989 this->drawOval(oval, paint); 2990 } else { 2991 SkPath path; 2992 if (useCenter) { 2993 path.moveTo(oval.centerX(), oval.centerY()); 2994 } 2995 path.arcTo(oval, startAngle, sweepAngle, !useCenter); 2996 if (useCenter) { 2997 path.close(); 2998 } 2999 this->drawPath(path, paint); 3000 } 3001} 3002 3003void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 3004 const SkPath& path, SkScalar hOffset, 3005 SkScalar vOffset, const SkPaint& paint) { 3006 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()"); 3007 SkMatrix matrix; 3008 3009 matrix.setTranslate(hOffset, vOffset); 3010 this->drawTextOnPath(text, byteLength, path, &matrix, paint); 3011} 3012 3013/////////////////////////////////////////////////////////////////////////////// 3014 3015/** 3016 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture, 3017 * against the playback cost of recursing into the subpicture to get at its actual ops. 3018 * 3019 * For now we pick a conservatively small value, though measurement (and other heuristics like 3020 * the type of ops contained) may justify changing this value. 3021 */ 3022#define kMaxPictureOpsToUnrollInsteadOfRef 1 3023 3024void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) { 3025 RETURN_ON_NULL(picture); 3026 3027 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()"); 3028 if (matrix && matrix->isIdentity()) { 3029 matrix = nullptr; 3030 } 3031 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) { 3032 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); 3033 picture->playback(this); 3034 } else { 3035 this->onDrawPicture(picture, matrix, paint); 3036 } 3037} 3038 3039void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, 3040 const SkPaint* paint) { 3041 if (!paint || paint->canComputeFastBounds()) { 3042 SkRect bounds = picture->cullRect(); 3043 if (paint) { 3044 paint->computeFastBounds(bounds, &bounds); 3045 } 3046 if (matrix) { 3047 matrix->mapRect(&bounds); 3048 } 3049 if (this->quickReject(bounds)) { 3050 return; 3051 } 3052 } 3053 3054 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); 3055 picture->playback(this); 3056} 3057 3058#ifdef SK_EXPERIMENTAL_SHADOWING 3059void SkCanvas::drawShadowedPicture(const SkPicture* picture, 3060 const SkMatrix* matrix, 3061 const SkPaint* paint) { 3062 RETURN_ON_NULL(picture); 3063 3064 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()"); 3065 3066 this->onDrawShadowedPicture(picture, matrix, paint); 3067} 3068 3069void SkCanvas::onDrawShadowedPicture(const SkPicture* picture, 3070 const SkMatrix* matrix, 3071 const SkPaint* paint) { 3072 this->onDrawPicture(picture, matrix, paint); 3073} 3074#endif 3075 3076/////////////////////////////////////////////////////////////////////////////// 3077/////////////////////////////////////////////////////////////////////////////// 3078 3079SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 3080 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small"); 3081 3082 SkASSERT(canvas); 3083 3084 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 3085 fDone = !fImpl->next(); 3086} 3087 3088SkCanvas::LayerIter::~LayerIter() { 3089 fImpl->~SkDrawIter(); 3090} 3091 3092void SkCanvas::LayerIter::next() { 3093 fDone = !fImpl->next(); 3094} 3095 3096SkBaseDevice* SkCanvas::LayerIter::device() const { 3097 return fImpl->getDevice(); 3098} 3099 3100const SkMatrix& SkCanvas::LayerIter::matrix() const { 3101 return fImpl->getMatrix(); 3102} 3103 3104const SkPaint& SkCanvas::LayerIter::paint() const { 3105 const SkPaint* paint = fImpl->getPaint(); 3106 if (nullptr == paint) { 3107 paint = &fDefaultPaint; 3108 } 3109 return *paint; 3110} 3111 3112const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 3113int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 3114int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 3115 3116/////////////////////////////////////////////////////////////////////////////// 3117 3118SkCanvasClipVisitor::~SkCanvasClipVisitor() { } 3119 3120/////////////////////////////////////////////////////////////////////////////// 3121 3122static bool supported_for_raster_canvas(const SkImageInfo& info) { 3123 switch (info.alphaType()) { 3124 case kPremul_SkAlphaType: 3125 case kOpaque_SkAlphaType: 3126 break; 3127 default: 3128 return false; 3129 } 3130 3131 switch (info.colorType()) { 3132 case kAlpha_8_SkColorType: 3133 case kRGB_565_SkColorType: 3134 case kN32_SkColorType: 3135 break; 3136 default: 3137 return false; 3138 } 3139 3140 return true; 3141} 3142 3143SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) { 3144 if (!supported_for_raster_canvas(info)) { 3145 return nullptr; 3146 } 3147 3148 SkBitmap bitmap; 3149 if (!bitmap.installPixels(info, pixels, rowBytes)) { 3150 return nullptr; 3151 } 3152 return new SkCanvas(bitmap); 3153} 3154 3155/////////////////////////////////////////////////////////////////////////////// 3156 3157SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix, 3158 const SkPaint* paint, const SkRect& bounds) 3159 : fCanvas(canvas) 3160 , fSaveCount(canvas->getSaveCount()) 3161{ 3162 if (paint) { 3163 SkRect newBounds = bounds; 3164 if (matrix) { 3165 matrix->mapRect(&newBounds); 3166 } 3167 canvas->saveLayer(&newBounds, paint); 3168 } else if (matrix) { 3169 canvas->save(); 3170 } 3171 3172 if (matrix) { 3173 canvas->concat(*matrix); 3174 } 3175} 3176 3177SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() { 3178 fCanvas->restoreToCount(fSaveCount); 3179} 3180 3181#ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API 3182SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) { 3183 return this->makeSurface(info, props).release(); 3184} 3185#endif 3186