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 "include/core/SkCanvas.h" 9 10 #include "include/core/SkBlender.h" 11 #include "include/core/SkColorFilter.h" 12 #include "include/core/SkImage.h" 13 #include "include/core/SkImageFilter.h" 14 #include "include/core/SkPathEffect.h" 15 #include "include/core/SkPicture.h" 16 #include "include/core/SkRRect.h" 17 #include "include/core/SkRasterHandleAllocator.h" 18 #include "include/core/SkString.h" 19 #include "include/core/SkTextBlob.h" 20 #include "include/core/SkVertices.h" 21 #include "include/effects/SkRuntimeEffect.h" 22 #include "include/private/SkTOptional.h" 23 #include "include/private/SkTo.h" 24 #include "include/utils/SkNoDrawCanvas.h" 25 #include "src/core/SkArenaAlloc.h" 26 #include "src/core/SkBitmapDevice.h" 27 #include "src/core/SkCanvasPriv.h" 28 #include "src/core/SkClipStack.h" 29 #include "src/core/SkColorFilterBase.h" 30 #include "src/core/SkDraw.h" 31 #include "src/core/SkGlyphRun.h" 32 #include "src/core/SkImageFilterCache.h" 33 #include "src/core/SkImageFilter_Base.h" 34 #include "src/core/SkLatticeIter.h" 35 #include "src/core/SkMSAN.h" 36 #include "src/core/SkMarkerStack.h" 37 #include "src/core/SkMatrixPriv.h" 38 #include "src/core/SkMatrixUtils.h" 39 #include "src/core/SkPaintPriv.h" 40 #include "src/core/SkRasterClip.h" 41 #include "src/core/SkSpecialImage.h" 42 #include "src/core/SkStrikeCache.h" 43 #include "src/core/SkTLazy.h" 44 #include "src/core/SkTextFormatParams.h" 45 #include "src/core/SkTraceEvent.h" 46 #include "src/core/SkVerticesPriv.h" 47 #include "src/image/SkImage_Base.h" 48 #include "src/image/SkSurface_Base.h" 49 #include "src/utils/SkPatchUtils.h" 50 51 #include <memory> 52 #include <new> 53 54 #if SK_SUPPORT_GPU 55 #include "include/gpu/GrDirectContext.h" 56 #include "src/gpu/BaseDevice.h" 57 #include "src/gpu/SkGr.h" 58 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) 59 # include "src/gpu/GrRenderTarget.h" 60 # include "src/gpu/GrRenderTargetProxy.h" 61 #endif 62 #endif 63 64 #define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0) 65 #define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0) 66 67 // This is a test: static_assert with no message is a c++17 feature, 68 // and std::max() is constexpr only since the c++14 stdlib. 69 static_assert(std::max(3,4) == 4); 70 71 /////////////////////////////////////////////////////////////////////////////////////////////////// 72 73 /* 74 * Return true if the drawing this rect would hit every pixels in the canvas. 75 * 76 * Returns false if 77 * - rect does not contain the canvas' bounds 78 * - paint is not fill 79 * - paint would blur or otherwise change the coverage of the rect 80 */ wouldOverwriteEntireSurface(const SkRect * rect,const SkPaint * paint,ShaderOverrideOpacity overrideOpacity) const81 bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint, 82 ShaderOverrideOpacity overrideOpacity) const { 83 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity == 84 (int)kNone_ShaderOverrideOpacity, 85 "need_matching_enums0"); 86 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity == 87 (int)kOpaque_ShaderOverrideOpacity, 88 "need_matching_enums1"); 89 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity == 90 (int)kNotOpaque_ShaderOverrideOpacity, 91 "need_matching_enums2"); 92 93 const SkISize size = this->getBaseLayerSize(); 94 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height()); 95 96 // if we're clipped at all, we can't overwrite the entire surface 97 { 98 const SkBaseDevice* base = this->baseDevice(); 99 const SkBaseDevice* top = this->topDevice(); 100 if (base != top) { 101 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite 102 } 103 if (!base->clipIsWideOpen()) { 104 return false; 105 } 106 } 107 108 if (rect) { 109 if (!this->getTotalMatrix().isScaleTranslate()) { 110 return false; // conservative 111 } 112 113 SkRect devRect; 114 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect); 115 if (!devRect.contains(bounds)) { 116 return false; 117 } 118 } 119 120 if (paint) { 121 SkPaint::Style paintStyle = paint->getStyle(); 122 if (!(paintStyle == SkPaint::kFill_Style || 123 paintStyle == SkPaint::kStrokeAndFill_Style)) { 124 return false; 125 } 126 if (paint->getMaskFilter() || paint->getPathEffect() || paint->getImageFilter()) { 127 return false; // conservative 128 } 129 } 130 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity); 131 } 132 133 /////////////////////////////////////////////////////////////////////////////////////////////////// 134 135 // experimental for faster tiled drawing... 136 //#define SK_TRACE_SAVERESTORE 137 138 #ifdef SK_TRACE_SAVERESTORE 139 static int gLayerCounter; inc_layer()140 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); } dec_layer()141 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); } 142 143 static int gRecCounter; inc_rec()144 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); } dec_rec()145 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); } 146 147 static int gCanvasCounter; inc_canvas()148 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); } dec_canvas()149 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); } 150 #else 151 #define inc_layer() 152 #define dec_layer() 153 #define inc_rec() 154 #define dec_rec() 155 #define inc_canvas() 156 #define dec_canvas() 157 #endif 158 predrawNotify(bool willOverwritesEntireSurface)159 bool SkCanvas::predrawNotify(bool willOverwritesEntireSurface) { 160 if (fSurfaceBase) { 161 if (!fSurfaceBase->aboutToDraw(willOverwritesEntireSurface 162 ? SkSurface::kDiscard_ContentChangeMode 163 : SkSurface::kRetain_ContentChangeMode)) { 164 return false; 165 } 166 } 167 return true; 168 } 169 predrawNotify(const SkRect * rect,const SkPaint * paint,ShaderOverrideOpacity overrideOpacity)170 bool SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint, 171 ShaderOverrideOpacity overrideOpacity) { 172 if (fSurfaceBase) { 173 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode; 174 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if 175 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write 176 // and therefore we don't care which mode we're in. 177 // 178 if (fSurfaceBase->outstandingImageSnapshot()) { 179 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) { 180 mode = SkSurface::kDiscard_ContentChangeMode; 181 } 182 } 183 if (!fSurfaceBase->aboutToDraw(mode)) { 184 return false; 185 } 186 } 187 return true; 188 } 189 190 /////////////////////////////////////////////////////////////////////////////// 191 Layer(sk_sp<SkBaseDevice> device,sk_sp<SkImageFilter> imageFilter,const SkPaint & paint)192 SkCanvas::Layer::Layer(sk_sp<SkBaseDevice> device, 193 sk_sp<SkImageFilter> imageFilter, 194 const SkPaint& paint) 195 : fDevice(std::move(device)) 196 , fImageFilter(std::move(imageFilter)) 197 , fPaint(paint) 198 , fDiscard(false) { 199 SkASSERT(fDevice); 200 // Any image filter should have been pulled out and stored in 'imageFilter' so that 'paint' 201 // can be used as-is to draw the result of the filter to the dst device. 202 SkASSERT(!fPaint.getImageFilter()); 203 } 204 MCRec(SkBaseDevice * device)205 SkCanvas::MCRec::MCRec(SkBaseDevice* device) : fDevice(device) { 206 SkASSERT(fDevice); 207 inc_rec(); 208 } 209 MCRec(const MCRec * prev)210 SkCanvas::MCRec::MCRec(const MCRec* prev) : fDevice(prev->fDevice), fMatrix(prev->fMatrix) { 211 SkASSERT(fDevice); 212 inc_rec(); 213 } 214 ~MCRec()215 SkCanvas::MCRec::~MCRec() { dec_rec(); } 216 newLayer(sk_sp<SkBaseDevice> layerDevice,sk_sp<SkImageFilter> filter,const SkPaint & restorePaint)217 void SkCanvas::MCRec::newLayer(sk_sp<SkBaseDevice> layerDevice, 218 sk_sp<SkImageFilter> filter, 219 const SkPaint& restorePaint) { 220 SkASSERT(!fBackImage); 221 fLayer = std::make_unique<Layer>(std::move(layerDevice), std::move(filter), restorePaint); 222 fDevice = fLayer->fDevice.get(); 223 } 224 reset(SkBaseDevice * device)225 void SkCanvas::MCRec::reset(SkBaseDevice* device) { 226 SkASSERT(!fLayer); 227 SkASSERT(device); 228 SkASSERT(fDeferredSaveCount == 0); 229 fDevice = device; 230 fMatrix.setIdentity(); 231 } 232 233 class SkCanvas::AutoUpdateQRBounds { 234 public: AutoUpdateQRBounds(SkCanvas * canvas)235 explicit AutoUpdateQRBounds(SkCanvas* canvas) : fCanvas(canvas) { 236 // pre-condition, fQuickRejectBounds and other state should be valid before anything 237 // modifies the device's clip. 238 fCanvas->validateClip(); 239 } ~AutoUpdateQRBounds()240 ~AutoUpdateQRBounds() { 241 fCanvas->fQuickRejectBounds = fCanvas->computeDeviceClipBounds(); 242 // post-condition, we should remain valid after re-computing the bounds 243 fCanvas->validateClip(); 244 } 245 246 private: 247 SkCanvas* fCanvas; 248 249 AutoUpdateQRBounds(AutoUpdateQRBounds&&) = delete; 250 AutoUpdateQRBounds(const AutoUpdateQRBounds&) = delete; 251 AutoUpdateQRBounds& operator=(AutoUpdateQRBounds&&) = delete; 252 AutoUpdateQRBounds& operator=(const AutoUpdateQRBounds&) = delete; 253 }; 254 255 ///////////////////////////////////////////////////////////////////////////// 256 // Attempts to convert an image filter to its equivalent color filter, which if possible, modifies 257 // the paint to compose the image filter's color filter into the paint's color filter slot. 258 // Returns true if the paint has been modified. 259 // Requires the paint to have an image filter and the copy-on-write be initialized. image_to_color_filter(SkPaint * paint)260 static bool image_to_color_filter(SkPaint* paint) { 261 SkASSERT(SkToBool(paint) && paint->getImageFilter()); 262 263 SkColorFilter* imgCFPtr; 264 if (!paint->getImageFilter()->asAColorFilter(&imgCFPtr)) { 265 return false; 266 } 267 sk_sp<SkColorFilter> imgCF(imgCFPtr); 268 269 SkColorFilter* paintCF = paint->getColorFilter(); 270 if (paintCF) { 271 // The paint has both a colorfilter(paintCF) and an imagefilter-that-is-a-colorfilter(imgCF) 272 // and we need to combine them into a single colorfilter. 273 imgCF = imgCF->makeComposed(sk_ref_sp(paintCF)); 274 } 275 276 paint->setColorFilter(std::move(imgCF)); 277 paint->setImageFilter(nullptr); 278 return true; 279 } 280 281 /** 282 * We implement ImageFilters for a given draw by creating a layer, then applying the 283 * imagefilter to the pixels of that layer (its backing surface/image), and then 284 * we call restore() to xfer that layer to the main canvas. 285 * 286 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode) 287 * 2. Generate the src pixels: 288 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper) 289 * return (fPaint). We then draw the primitive (using srcover) into a cleared 290 * buffer/surface. 291 * 3. Restore the layer created in #1 292 * The imagefilter is passed the buffer/surface from the layer (now filled with the 293 * src pixels of the primitive). It returns a new "filtered" buffer, which we 294 * draw onto the previous layer using the xfermode from the original paint. 295 */ 296 class AutoLayerForImageFilter { 297 public: 298 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the 299 // paint. It's used to determine the size of the offscreen layer for filters. 300 // If null, the clip will be used instead. 301 // 302 // Draw functions should use layer->paint() instead of the passed-in paint. AutoLayerForImageFilter(SkCanvas * canvas,const SkPaint & paint,const SkRect * rawBounds=nullptr)303 AutoLayerForImageFilter(SkCanvas* canvas, 304 const SkPaint& paint, 305 const SkRect* rawBounds = nullptr) 306 : fPaint(paint) 307 , fCanvas(canvas) 308 , fTempLayerForImageFilter(false) { 309 SkDEBUGCODE(fSaveCount = canvas->getSaveCount();) 310 311 if (fPaint.getImageFilter() && !image_to_color_filter(&fPaint)) { 312 // The draw paint has an image filter that couldn't be simplified to an equivalent 313 // color filter, so we have to inject an automatic saveLayer(). 314 SkPaint restorePaint; 315 restorePaint.setImageFilter(fPaint.refImageFilter()); 316 restorePaint.setBlender(fPaint.refBlender()); 317 318 // Remove the restorePaint fields from our "working" paint 319 fPaint.setImageFilter(nullptr); 320 fPaint.setBlendMode(SkBlendMode::kSrcOver); 321 322 SkRect storage; 323 if (rawBounds && fPaint.canComputeFastBounds()) { 324 // Make rawBounds include all paint outsets except for those due to image filters. 325 // At this point, fPaint's image filter has been moved to 'restorePaint'. 326 SkASSERT(!fPaint.getImageFilter()); 327 rawBounds = &fPaint.computeFastBounds(*rawBounds, &storage); 328 } 329 330 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &restorePaint), 331 SkCanvas::kFullLayer_SaveLayerStrategy); 332 fTempLayerForImageFilter = true; 333 } 334 } 335 336 AutoLayerForImageFilter(const AutoLayerForImageFilter&) = delete; 337 AutoLayerForImageFilter& operator=(const AutoLayerForImageFilter&) = delete; 338 AutoLayerForImageFilter(AutoLayerForImageFilter&&) = default; 339 AutoLayerForImageFilter& operator=(AutoLayerForImageFilter&&) = default; 340 ~AutoLayerForImageFilter()341 ~AutoLayerForImageFilter() { 342 if (fTempLayerForImageFilter) { 343 fCanvas->internalRestore(); 344 } 345 SkASSERT(fCanvas->getSaveCount() == fSaveCount); 346 } 347 paint() const348 const SkPaint& paint() const { return fPaint; } 349 350 private: 351 SkPaint fPaint; 352 SkCanvas* fCanvas; 353 bool fTempLayerForImageFilter; 354 355 SkDEBUGCODE(int fSaveCount;) 356 }; 357 aboutToDraw(SkCanvas * canvas,const SkPaint & paint,const SkRect * rawBounds,CheckForOverwrite checkOverwrite,ShaderOverrideOpacity overrideOpacity)358 skstd::optional<AutoLayerForImageFilter> SkCanvas::aboutToDraw( 359 SkCanvas* canvas, 360 const SkPaint& paint, 361 const SkRect* rawBounds, 362 CheckForOverwrite checkOverwrite, 363 ShaderOverrideOpacity overrideOpacity) 364 { 365 if (checkOverwrite == CheckForOverwrite::kYes) { 366 if (!this->predrawNotify(rawBounds, &paint, overrideOpacity)) { 367 return skstd::nullopt; 368 } 369 } else { 370 if (!this->predrawNotify()) { 371 return skstd::nullopt; 372 } 373 } 374 return skstd::optional<AutoLayerForImageFilter>(canvas, paint, rawBounds); 375 } 376 377 //////////////////////////////////////////////////////////////////////////// 378 resetForNextPicture(const SkIRect & bounds)379 void SkCanvas::resetForNextPicture(const SkIRect& bounds) { 380 this->restoreToCount(1); 381 382 // We're peering through a lot of structs here. Only at this scope do we 383 // know that the device is a SkNoPixelsDevice. 384 SkASSERT(fBaseDevice->isNoPixelsDevice()); 385 static_cast<SkNoPixelsDevice*>(fBaseDevice.get())->resetForNextPicture(bounds); 386 fMCRec->reset(fBaseDevice.get()); 387 fQuickRejectBounds = this->computeDeviceClipBounds(); 388 } 389 init(sk_sp<SkBaseDevice> device)390 void SkCanvas::init(sk_sp<SkBaseDevice> device) { 391 // SkCanvas.h declares internal storage for the hidden struct MCRec, and this 392 // assert ensure it's sufficient. <= is used because the struct has pointer fields, so the 393 // declared size is an upper bound across architectures. When the size is smaller, more stack 394 static_assert(sizeof(MCRec) <= kMCRecSize); 395 396 if (!device) { 397 device = sk_make_sp<SkNoPixelsDevice>(SkIRect::MakeEmpty(), fProps); 398 } 399 400 // From this point on, SkCanvas will always have a device 401 SkASSERT(device); 402 403 fSaveCount = 1; 404 fMCRec = new (fMCStack.push_back()) MCRec(device.get()); 405 fMarkerStack = sk_make_sp<SkMarkerStack>(); 406 407 // The root device and the canvas should always have the same pixel geometry 408 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry()); 409 device->setMarkerStack(fMarkerStack.get()); 410 411 fSurfaceBase = nullptr; 412 fBaseDevice = std::move(device); 413 fScratchGlyphRunBuilder = std::make_unique<SkGlyphRunBuilder>(); 414 fQuickRejectBounds = this->computeDeviceClipBounds(); 415 } 416 SkCanvas()417 SkCanvas::SkCanvas() : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 418 inc_canvas(); 419 this->init(nullptr); 420 } 421 SkCanvas(int width,int height,const SkSurfaceProps * props)422 SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props) 423 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 424 , fProps(SkSurfacePropsCopyOrDefault(props)) { 425 inc_canvas(); 426 this->init(sk_make_sp<SkNoPixelsDevice>( 427 SkIRect::MakeWH(std::max(width, 0), std::max(height, 0)), fProps)); 428 } 429 SkCanvas(const SkIRect & bounds)430 SkCanvas::SkCanvas(const SkIRect& bounds) 431 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 432 inc_canvas(); 433 434 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds; 435 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps)); 436 } 437 SkCanvas(sk_sp<SkBaseDevice> device)438 SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device) 439 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 440 , fProps(device->surfaceProps()) { 441 inc_canvas(); 442 443 this->init(device); 444 } 445 SkCanvas(const SkBitmap & bitmap,const SkSurfaceProps & props)446 SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props) 447 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), fProps(props) { 448 inc_canvas(); 449 450 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr)); 451 this->init(device); 452 } 453 SkCanvas(const SkBitmap & bitmap,std::unique_ptr<SkRasterHandleAllocator> alloc,SkRasterHandleAllocator::Handle hndl)454 SkCanvas::SkCanvas(const SkBitmap& bitmap, 455 std::unique_ptr<SkRasterHandleAllocator> alloc, 456 SkRasterHandleAllocator::Handle hndl) 457 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 458 , fAllocator(std::move(alloc)) { 459 inc_canvas(); 460 461 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr)); 462 this->init(device); 463 } 464 SkCanvas(const SkBitmap & bitmap)465 SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {} 466 467 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK SkCanvas(const SkBitmap & bitmap,ColorBehavior)468 SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior) 469 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { 470 inc_canvas(); 471 472 SkBitmap tmp(bitmap); 473 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr); 474 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr)); 475 this->init(device); 476 } 477 #endif 478 ~SkCanvas()479 SkCanvas::~SkCanvas() { 480 // Mark all pending layers to be discarded during restore (rather than drawn) 481 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart); 482 for (;;) { 483 MCRec* rec = (MCRec*)iter.next(); 484 if (!rec) { 485 break; 486 } 487 if (rec->fLayer) { 488 rec->fLayer->fDiscard = true; 489 } 490 } 491 492 // free up the contents of our deque 493 this->restoreToCount(1); // restore everything but the last 494 this->internalRestore(); // restore the last, since we're going away 495 496 dec_canvas(); 497 } 498 499 /////////////////////////////////////////////////////////////////////////////// 500 flush()501 void SkCanvas::flush() { 502 this->onFlush(); 503 } 504 onFlush()505 void SkCanvas::onFlush() { 506 #if SK_SUPPORT_GPU 507 auto dContext = GrAsDirectContext(this->recordingContext()); 508 509 if (dContext) { 510 dContext->flushAndSubmit(); 511 } 512 #endif 513 } 514 getSurface() const515 SkSurface* SkCanvas::getSurface() const { 516 return fSurfaceBase; 517 } 518 getBaseLayerSize() const519 SkISize SkCanvas::getBaseLayerSize() const { 520 return this->baseDevice()->imageInfo().dimensions(); 521 } 522 topDevice() const523 SkBaseDevice* SkCanvas::topDevice() const { 524 SkASSERT(fMCRec->fDevice); 525 return fMCRec->fDevice; 526 } 527 readPixels(const SkPixmap & pm,int x,int y)528 bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) { 529 return pm.addr() && this->baseDevice()->readPixels(pm, x, y); 530 } 531 readPixels(const SkImageInfo & dstInfo,void * dstP,size_t rowBytes,int x,int y)532 bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) { 533 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y); 534 } 535 readPixels(const SkBitmap & bm,int x,int y)536 bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) { 537 SkPixmap pm; 538 return bm.peekPixels(&pm) && this->readPixels(pm, x, y); 539 } 540 writePixels(const SkBitmap & bitmap,int x,int y)541 bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) { 542 SkPixmap pm; 543 if (bitmap.peekPixels(&pm)) { 544 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y); 545 } 546 return false; 547 } 548 writePixels(const SkImageInfo & srcInfo,const void * pixels,size_t rowBytes,int x,int y)549 bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes, 550 int x, int y) { 551 SkBaseDevice* device = this->baseDevice(); 552 553 // This check gives us an early out and prevents generation ID churn on the surface. 554 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec. 555 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height()); 556 if (!srcRect.intersect({0, 0, device->width(), device->height()})) { 557 return false; 558 } 559 560 // Tell our owning surface to bump its generation ID. 561 const bool completeOverwrite = srcRect.size() == device->imageInfo().dimensions(); 562 if (!this->predrawNotify(completeOverwrite)) { 563 return false; 564 } 565 566 // This can still fail, most notably in the case of a invalid color type or alpha type 567 // conversion. We could pull those checks into this function and avoid the unnecessary 568 // generation ID bump. But then we would be performing those checks twice, since they 569 // are also necessary at the bitmap/pixmap entry points. 570 return device->writePixels({srcInfo, pixels, rowBytes}, x, y); 571 } 572 573 ////////////////////////////////////////////////////////////////////////////// 574 checkForDeferredSave()575 void SkCanvas::checkForDeferredSave() { 576 if (fMCRec->fDeferredSaveCount > 0) { 577 this->doSave(); 578 } 579 } 580 getSaveCount() const581 int SkCanvas::getSaveCount() const { 582 #ifdef SK_DEBUG 583 int count = 0; 584 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart); 585 for (;;) { 586 const MCRec* rec = (const MCRec*)iter.next(); 587 if (!rec) { 588 break; 589 } 590 count += 1 + rec->fDeferredSaveCount; 591 } 592 SkASSERT(count == fSaveCount); 593 #endif 594 return fSaveCount; 595 } 596 save()597 int SkCanvas::save() { 598 fSaveCount += 1; 599 fMCRec->fDeferredSaveCount += 1; 600 return this->getSaveCount() - 1; // return our prev value 601 } 602 doSave()603 void SkCanvas::doSave() { 604 this->willSave(); 605 606 SkASSERT(fMCRec->fDeferredSaveCount > 0); 607 fMCRec->fDeferredSaveCount -= 1; 608 this->internalSave(); 609 } 610 restore()611 void SkCanvas::restore() { 612 if (fMCRec->fDeferredSaveCount > 0) { 613 SkASSERT(fSaveCount > 1); 614 fSaveCount -= 1; 615 fMCRec->fDeferredSaveCount -= 1; 616 } else { 617 // check for underflow 618 if (fMCStack.count() > 1) { 619 this->willRestore(); 620 SkASSERT(fSaveCount > 1); 621 fSaveCount -= 1; 622 this->internalRestore(); 623 this->didRestore(); 624 } 625 } 626 } 627 restoreToCount(int count)628 void SkCanvas::restoreToCount(int count) { 629 // safety check 630 if (count < 1) { 631 count = 1; 632 } 633 634 int n = this->getSaveCount() - count; 635 for (int i = 0; i < n; ++i) { 636 this->restore(); 637 } 638 } 639 internalSave()640 void SkCanvas::internalSave() { 641 fMCRec = new (fMCStack.push_back()) MCRec(fMCRec); 642 643 this->topDevice()->save(); 644 } 645 saveLayer(const SkRect * bounds,const SkPaint * paint)646 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) { 647 return this->saveLayer(SaveLayerRec(bounds, paint, 0)); 648 } 649 saveLayer(const SaveLayerRec & rec)650 int SkCanvas::saveLayer(const SaveLayerRec& rec) { 651 TRACE_EVENT0("skia", TRACE_FUNC); 652 if (rec.fPaint && rec.fPaint->nothingToDraw()) { 653 // no need for the layer (or any of the draws until the matching restore() 654 this->save(); 655 this->clipRect({0,0,0,0}); 656 } else { 657 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec); 658 fSaveCount += 1; 659 this->internalSaveLayer(rec, strategy); 660 } 661 return this->getSaveCount() - 1; 662 } 663 only_axis_aligned_saveBehind(const SkRect * bounds)664 int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) { 665 if (bounds && !this->getLocalClipBounds().intersects(*bounds)) { 666 // Assuming clips never expand, if the request bounds is outside of the current clip 667 // there is no need to copy/restore the area, so just devolve back to a regular save. 668 this->save(); 669 } else { 670 bool doTheWork = this->onDoSaveBehind(bounds); 671 fSaveCount += 1; 672 this->internalSave(); 673 if (doTheWork) { 674 this->internalSaveBehind(bounds); 675 } 676 } 677 return this->getSaveCount() - 1; 678 } 679 680 // In our current design/features, we should never have a layer (src) in a different colorspace 681 // than its parent (dst), so we assert that here. This is called out from other asserts, in case 682 // we add some feature in the future to allow a given layer/imagefilter to operate in a specific 683 // colorspace. check_drawdevice_colorspaces(SkColorSpace * src,SkColorSpace * dst)684 static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) { 685 SkASSERT(src == dst); 686 } 687 688 // Helper function to compute the center reference point used for scale decomposition under 689 // non-linear transformations. compute_decomposition_center(const SkMatrix & dstToLocal,const skif::ParameterSpace<SkRect> * contentBounds,const skif::DeviceSpace<SkIRect> & targetOutput)690 static skif::ParameterSpace<SkPoint> compute_decomposition_center( 691 const SkMatrix& dstToLocal, 692 const skif::ParameterSpace<SkRect>* contentBounds, 693 const skif::DeviceSpace<SkIRect>& targetOutput) { 694 // Will use the inverse and center of the device bounds if the content bounds aren't provided. 695 SkRect rect = contentBounds ? SkRect(*contentBounds) : SkRect::Make(SkIRect(targetOutput)); 696 SkPoint center = {rect.centerX(), rect.centerY()}; 697 if (!contentBounds) { 698 // Theoretically, the inverse transform could put center's homogeneous coord behind W = 0, 699 // but that case is handled automatically in Mapping::decomposeCTM later. 700 dstToLocal.mapPoints(¢er, 1); 701 } 702 703 return skif::ParameterSpace<SkPoint>(center); 704 } 705 706 // Compute suitable transformations and layer bounds for a new layer that will be used as the source 707 // input into 'filter' before being drawn into 'dst' via the returned skif::Mapping. 708 // Null filters are permitted and act as the identity. The returned mapping will be compatible with 709 // the image filter. 710 // 711 // Returns an empty rect if the layer wouldn't draw anything after filtering. get_layer_mapping_and_bounds(const SkImageFilter * filter,const SkMatrix & localToDst,const skif::DeviceSpace<SkIRect> & targetOutput,const skif::ParameterSpace<SkRect> * contentBounds=nullptr,bool mustCoverDst=true,SkScalar scaleFactor=1.0f)712 static std::pair<skif::Mapping, skif::LayerSpace<SkIRect>> get_layer_mapping_and_bounds( 713 const SkImageFilter* filter, 714 const SkMatrix& localToDst, 715 const skif::DeviceSpace<SkIRect>& targetOutput, 716 const skif::ParameterSpace<SkRect>* contentBounds = nullptr, 717 bool mustCoverDst = true, 718 SkScalar scaleFactor = 1.0f) { 719 auto failedMapping = []() { 720 return std::make_pair<skif::Mapping, skif::LayerSpace<SkIRect>>( 721 {}, skif::LayerSpace<SkIRect>::Empty()); 722 }; 723 724 SkMatrix dstToLocal; 725 if (!localToDst.isFinite() || 726 !localToDst.invert(&dstToLocal)) { 727 return failedMapping(); 728 } 729 730 skif::ParameterSpace<SkPoint> center = 731 compute_decomposition_center(dstToLocal, contentBounds, targetOutput); 732 // *after* possibly getting a representative point from the provided content bounds, it might 733 // be necessary to discard the bounds for subsequent layer calculations. 734 if (mustCoverDst) { 735 contentBounds = nullptr; 736 } 737 738 // Determine initial mapping and a reasonable maximum dimension to prevent layer-to-device 739 // transforms with perspective and skew from triggering excessive buffer allocations. 740 skif::Mapping mapping; 741 if (!mapping.decomposeCTM(localToDst, filter, center)) { 742 return failedMapping(); 743 } 744 // Push scale factor into layer matrix and device matrix (net no change, but the layer will have 745 // its resolution adjusted in comparison to the final device). 746 if (scaleFactor != 1.0f && 747 !mapping.adjustLayerSpace(SkMatrix::Scale(scaleFactor, scaleFactor))) { 748 return failedMapping(); 749 } 750 751 // Perspective and skew could exceed this since mapping.deviceToLayer(targetOutput) is 752 // theoretically unbounded under those conditions. Under a 45 degree rotation, a layer needs to 753 // be 2X larger per side of the prior device in order to fully cover it. We use the max of that 754 // and 2048 for a reasonable upper limit (this allows small layers under extreme transforms to 755 // use more relative resolution than a larger layer). 756 static const int kMinDimThreshold = 2048; 757 int maxLayerDim = std::max(Sk64_pin_to_s32(2 * std::max(SkIRect(targetOutput).width64(), 758 SkIRect(targetOutput).height64())), 759 kMinDimThreshold); 760 761 skif::LayerSpace<SkIRect> layerBounds; 762 if (filter) { 763 layerBounds = as_IFB(filter)->getInputBounds(mapping, targetOutput, contentBounds); 764 // When a filter is involved, the layer size may be larger than the default maxLayerDim due 765 // to required inputs for filters (e.g. a displacement map with a large radius). 766 if (layerBounds.width() > maxLayerDim || layerBounds.height() > maxLayerDim) { 767 skif::Mapping idealMapping(SkMatrix::I(), mapping.layerMatrix()); 768 auto idealLayerBounds = as_IFB(filter)->getInputBounds(idealMapping, targetOutput, 769 contentBounds); 770 maxLayerDim = std::max(std::max(idealLayerBounds.width(), idealLayerBounds.height()), 771 maxLayerDim); 772 } 773 } else { 774 layerBounds = mapping.deviceToLayer(targetOutput); 775 if (contentBounds) { 776 // For better or for worse, user bounds currently act as a hard clip on the layer's 777 // extent (i.e., they implement the CSS filter-effects 'filter region' feature). 778 skif::LayerSpace<SkIRect> knownBounds = mapping.paramToLayer(*contentBounds).roundOut(); 779 if (!layerBounds.intersect(knownBounds)) { 780 return failedMapping(); 781 } 782 } 783 } 784 785 if (layerBounds.width() > maxLayerDim || layerBounds.height() > maxLayerDim) { 786 skif::LayerSpace<SkIRect> newLayerBounds( 787 SkIRect::MakeWH(std::min(layerBounds.width(), maxLayerDim), 788 std::min(layerBounds.height(), maxLayerDim))); 789 SkMatrix adjust = SkMatrix::MakeRectToRect(SkRect::Make(SkIRect(layerBounds)), 790 SkRect::Make(SkIRect(newLayerBounds)), 791 SkMatrix::kFill_ScaleToFit); 792 if (!mapping.adjustLayerSpace(adjust)) { 793 return failedMapping(); 794 } else { 795 layerBounds = newLayerBounds; 796 } 797 } 798 799 return {mapping, layerBounds}; 800 } 801 make_layer_info(const SkImageInfo & prev,int w,int h,bool f16)802 static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool f16) { 803 SkColorType ct = f16 ? SkColorType::kRGBA_F16_SkColorType : prev.colorType(); 804 if (!f16 && 805 prev.bytesPerPixel() <= 4 && 806 prev.colorType() != kRGBA_8888_SkColorType && 807 prev.colorType() != kBGRA_8888_SkColorType) { 808 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888, 809 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return. 810 ct = kN32_SkColorType; 811 } 812 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace()); 813 } 814 draw_layer_as_sprite(const SkMatrix & matrix,const SkISize & size)815 static bool draw_layer_as_sprite(const SkMatrix& matrix, const SkISize& size) { 816 // Assume anti-aliasing and highest valid filter mode (linear) for drawing layers and image 817 // filters. If the layer can be drawn as a sprite, these can be downgraded. 818 SkPaint paint; 819 paint.setAntiAlias(true); 820 SkSamplingOptions sampling{SkFilterMode::kLinear}; 821 return SkTreatAsSprite(matrix, size, sampling, paint); 822 } 823 internalDrawDeviceWithFilter(SkBaseDevice * src,SkBaseDevice * dst,const SkImageFilter * filter,const SkPaint & paint,DeviceCompatibleWithFilter compat,SkScalar scaleFactor)824 void SkCanvas::internalDrawDeviceWithFilter(SkBaseDevice* src, 825 SkBaseDevice* dst, 826 const SkImageFilter* filter, 827 const SkPaint& paint, 828 DeviceCompatibleWithFilter compat, 829 SkScalar scaleFactor) { 830 check_drawdevice_colorspaces(dst->imageInfo().colorSpace(), 831 src->imageInfo().colorSpace()); 832 833 // 'filter' sees the src device's buffer as the implicit input image, and processes the image 834 // in this device space (referred to as the "layer" space). However, the filter 835 // parameters need to respect the current matrix, which is not necessarily the local matrix that 836 // was set on 'src' (e.g. because we've popped src off the stack already). 837 // TODO (michaelludwig): Stay in SkM44 once skif::Mapping supports SkM44 instead of SkMatrix. 838 SkMatrix localToSrc = (src->globalToDevice() * fMCRec->fMatrix).asM33(); 839 SkISize srcDims = src->imageInfo().dimensions(); 840 841 // Whether or not we need to make a transformed tmp image from 'src', and what that transform is 842 bool needsIntermediateImage = false; 843 SkMatrix srcToIntermediate; 844 845 skif::Mapping mapping; 846 skif::LayerSpace<SkIRect> requiredInput; 847 if (compat == DeviceCompatibleWithFilter::kYes) { 848 // Just use the relative transform from src to dst and the src's whole image, since 849 // internalSaveLayer should have already determined what was necessary. 850 SkASSERT(scaleFactor == 1.0f); 851 mapping = skif::Mapping(src->getRelativeTransform(*dst), localToSrc); 852 requiredInput = skif::LayerSpace<SkIRect>(SkIRect::MakeSize(srcDims)); 853 SkASSERT(!requiredInput.isEmpty()); 854 } else { 855 // Compute the image filter mapping by decomposing the local->device matrix of dst and 856 // re-determining the required input. 857 std::tie(mapping, requiredInput) = get_layer_mapping_and_bounds( 858 filter, dst->localToDevice(), skif::DeviceSpace<SkIRect>(dst->devClipBounds()), 859 nullptr, true, SkTPin(scaleFactor, 0.f, 1.f)); 860 if (requiredInput.isEmpty()) { 861 return; 862 } 863 864 // The above mapping transforms from local to dst's device space, where the layer space 865 // represents the intermediate buffer. Now we need to determine the transform from src to 866 // intermediate to prepare the input to the filter. 867 if (!localToSrc.invert(&srcToIntermediate)) { 868 return; 869 } 870 srcToIntermediate.postConcat(mapping.layerMatrix()); 871 if (draw_layer_as_sprite(srcToIntermediate, srcDims)) { 872 // src differs from intermediate by just an integer translation, so it can be applied 873 // automatically when taking a subset of src if we update the mapping. 874 skif::LayerSpace<SkIPoint> srcOrigin({(int) srcToIntermediate.getTranslateX(), 875 (int) srcToIntermediate.getTranslateY()}); 876 mapping.applyOrigin(srcOrigin); 877 requiredInput.offset(-srcOrigin); 878 } else { 879 // The contents of 'src' will be drawn to an intermediate buffer using srcToIntermediate 880 // and that buffer will be the input to the image filter. 881 needsIntermediateImage = true; 882 } 883 } 884 885 sk_sp<SkSpecialImage> filterInput; 886 if (!needsIntermediateImage) { 887 // The src device can be snapped directly 888 skif::LayerSpace<SkIRect> srcSubset(SkIRect::MakeSize(srcDims)); 889 if (srcSubset.intersect(requiredInput)) { 890 filterInput = src->snapSpecial(SkIRect(srcSubset)); 891 892 // TODO: For now image filter input images need to have a (0,0) origin. The required 893 // input's top left has been baked into srcSubset so we use that as the image origin. 894 mapping.applyOrigin(srcSubset.topLeft()); 895 } 896 } else { 897 // We need to produce a temporary image that is equivalent to 'src' but transformed to 898 // a coordinate space compatible with the image filter 899 900 // TODO: If the srcToIntermediate is scale+translate, can we use the framebuffer blit 901 // extensions to handle doing the copy and scale at the same time? 902 903 SkASSERT(compat == DeviceCompatibleWithFilter::kUnknown); 904 SkRect srcRect; 905 if (!SkMatrixPriv::InverseMapRect(srcToIntermediate, &srcRect, 906 SkRect::Make(SkIRect(requiredInput)))) { 907 return; 908 } 909 910 SkIRect srcSubset = srcRect.roundOut(); 911 sk_sp<SkSpecialImage> srcImage; 912 if (srcSubset.intersect(SkIRect::MakeSize(srcDims)) && 913 (srcImage = src->snapSpecial(srcSubset))) { 914 // Make a new surface and draw 'srcImage' into it with the srcToIntermediate transform 915 // to produce the final input image for the filter 916 SkBaseDevice::CreateInfo info(make_layer_info(src->imageInfo(), requiredInput.width(), 917 requiredInput.height(), false), 918 SkPixelGeometry::kUnknown_SkPixelGeometry, 919 SkBaseDevice::TileUsage::kNever_TileUsage, 920 false, fAllocator.get()); 921 sk_sp<SkBaseDevice> intermediateDevice(src->onCreateDevice(info, &paint)); 922 if (!intermediateDevice) { 923 return; 924 } 925 intermediateDevice->setOrigin(SkM44(srcToIntermediate), 926 requiredInput.left(), requiredInput.top()); 927 928 SkMatrix offsetLocalToDevice = intermediateDevice->localToDevice(); 929 offsetLocalToDevice.preTranslate(srcSubset.left(), srcSubset.top()); 930 // We draw with non-AA bilinear since we cover the destination but definitely don't have 931 // a pixel-aligned transform. 932 intermediateDevice->drawSpecial(srcImage.get(), offsetLocalToDevice, 933 SkSamplingOptions{SkFilterMode::kLinear}, {}); 934 filterInput = intermediateDevice->snapSpecial(); 935 936 // TODO: Like the non-intermediate case, we need to apply the image origin. 937 mapping.applyOrigin(requiredInput.topLeft()); 938 } 939 } 940 941 if (filterInput) { 942 const bool use_nn = draw_layer_as_sprite(mapping.deviceMatrix(), 943 filterInput->subset().size()); 944 SkSamplingOptions sampling{use_nn ? SkFilterMode::kNearest : SkFilterMode::kLinear}; 945 if (filter) { 946 dst->drawFilteredImage(mapping, filterInput.get(), filter, sampling, paint); 947 } else { 948 dst->drawSpecial(filterInput.get(), mapping.deviceMatrix(), sampling, paint); 949 } 950 } 951 } 952 953 // This is similar to image_to_color_filter used by AutoLayerForImageFilter, but with key changes: 954 // - image_to_color_filter requires the entire image filter DAG to be represented as a color filter 955 // that does not affect transparent black (SkImageFilter::asAColorFilter) 956 // - when that is met, the image filter's CF is composed around any CF that was on the draw's paint 957 // since for a draw, the color filtering happens before any image filtering 958 // - optimize_layer_filter only applies to the last node and does not care about transparent black 959 // since a layer is being made regardless (SkImageFilter::isColorFilterNode) 960 // - any extracted CF is composed inside the restore paint's CF because image filters are evaluated 961 // before the color filter of a restore paint for layers. 962 // 963 // Assumes that 'filter', and thus its inputs, will remain owned by the caller. Modifies 'paint' 964 // to have the updated color filter and returns the image filter to evaluate on restore. 965 // 966 // FIXME: skbug.com/12083 - we modify 'coversDevice' here because for now, only the color filter 967 // produced from an image filter node is checked for affecting transparent black, even though it's 968 // better in the long run to have any CF that affects transparent black expand to the clip. optimize_layer_filter(const SkImageFilter * filter,SkPaint * paint,bool * coversDevice=nullptr)969 static const SkImageFilter* optimize_layer_filter(const SkImageFilter* filter, SkPaint* paint, 970 bool* coversDevice=nullptr) { 971 SkASSERT(paint); 972 SkColorFilter* cf; 973 if (filter && filter->isColorFilterNode(&cf)) { 974 sk_sp<SkColorFilter> inner(cf); 975 if (paint->getAlphaf() < 1.f) { 976 // The paint's alpha is applied after the image filter but before the paint's color 977 // filter. If there is transparency, we have to apply it between the two filters. 978 // FIXME: The Blend CF should allow composing directly at construction. 979 inner = SkColorFilters::Compose( 980 SkColorFilters::Blend(/* src */ paint->getColor(), SkBlendMode::kDstIn), 981 /* dst */ std::move(inner)); 982 paint->setAlphaf(1.f); 983 } 984 985 // Check if the once-wrapped color filter affects transparent black *before* we combine 986 // it with any original color filter on the paint. 987 if (coversDevice) { 988 *coversDevice = as_CFB(inner)->affectsTransparentBlack(); 989 } 990 991 paint->setColorFilter(SkColorFilters::Compose(paint->refColorFilter(), std::move(inner))); 992 SkASSERT(filter->countInputs() == 1); 993 return filter->getInput(0); 994 } else { 995 if (coversDevice) { 996 *coversDevice = false; 997 } 998 return filter; 999 } 1000 } 1001 1002 // If there is a backdrop filter, or if the restore paint has a color filter that affects 1003 // transparent black, then the new layer must be sized such that it covers the entire device 1004 // clip bounds of the prior device (otherwise edges of the temporary layer would be visible). 1005 // See skbug.com/8783 must_cover_prior_device(const SkImageFilter * backdrop,const SkPaint & restorePaint)1006 static bool must_cover_prior_device(const SkImageFilter* backdrop, 1007 const SkPaint& restorePaint) { 1008 // FIXME(michaelludwig) - see skbug.com/12083, once clients do not depend on user bounds for 1009 // clipping a layer visually, we can respect the fact that the color filter affects transparent 1010 // black and should cover the device. 1011 return SkToBool(backdrop); // || 1012 // (restorePaint.getColorFilter() && 1013 // as_CFB(restorePaint.getColorFilter())->affectsTransparentBlack()); 1014 } 1015 internalSaveLayer(const SaveLayerRec & rec,SaveLayerStrategy strategy)1016 void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) { 1017 TRACE_EVENT0("skia", TRACE_FUNC); 1018 // Do this before we create the layer. We don't call the public save() since that would invoke a 1019 // possibly overridden virtual. 1020 this->internalSave(); 1021 1022 if (this->isClipEmpty()) { 1023 // Early out if the layer wouldn't draw anything 1024 return; 1025 } 1026 1027 // Build up the paint for restoring the layer, taking only the pieces of rec.fPaint that are 1028 // relevant. Filtering is automatically chosen in internalDrawDeviceWithFilter based on the 1029 // device's coordinate space. 1030 SkPaint restorePaint(rec.fPaint ? *rec.fPaint : SkPaint()); 1031 restorePaint.setMaskFilter(nullptr); // mask filters are ignored for saved layers 1032 restorePaint.setImageFilter(nullptr); // the image filter is held separately 1033 // Smooth non-axis-aligned layer edges; this automatically downgrades to non-AA for aligned 1034 // layer restores. This is done to match legacy behavior where the post-applied MatrixTransform 1035 // bilerp also smoothed cropped edges. See skbug.com/11252 1036 restorePaint.setAntiAlias(true); 1037 1038 bool optimizedCFAffectsTransparent; 1039 const SkImageFilter* filter = optimize_layer_filter( 1040 rec.fPaint ? rec.fPaint->getImageFilter() : nullptr, &restorePaint, 1041 &optimizedCFAffectsTransparent); 1042 1043 // Size the new layer relative to the prior device, which may already be aligned for filters. 1044 SkBaseDevice* priorDevice = this->topDevice(); 1045 skif::Mapping newLayerMapping; 1046 skif::LayerSpace<SkIRect> layerBounds; 1047 std::tie(newLayerMapping, layerBounds) = get_layer_mapping_and_bounds( 1048 filter, priorDevice->localToDevice(), 1049 skif::DeviceSpace<SkIRect>(priorDevice->devClipBounds()), 1050 skif::ParameterSpace<SkRect>::Optional(rec.fBounds), 1051 must_cover_prior_device(rec.fBackdrop, restorePaint) || optimizedCFAffectsTransparent); 1052 1053 auto abortLayer = [this]() { 1054 // The filtered content would not draw anything, or the new device space has an invalid 1055 // coordinate system, in which case we mark the current top device as empty so that nothing 1056 // draws until the canvas is restored past this saveLayer. 1057 AutoUpdateQRBounds aqr(this); 1058 this->topDevice()->clipRect(SkRect::MakeEmpty(), SkClipOp::kIntersect, /* aa */ false); 1059 }; 1060 1061 if (layerBounds.isEmpty()) { 1062 abortLayer(); 1063 return; 1064 } 1065 1066 sk_sp<SkBaseDevice> newDevice; 1067 if (strategy == kFullLayer_SaveLayerStrategy) { 1068 SkASSERT(!layerBounds.isEmpty()); 1069 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), 1070 layerBounds.width(), layerBounds.height(), 1071 SkToBool(rec.fSaveLayerFlags & kF16ColorType)); 1072 if (rec.fSaveLayerFlags & kF16ColorType) { 1073 info = info.makeColorType(kRGBA_F16_SkColorType); 1074 } 1075 SkASSERT(info.alphaType() != kOpaque_SkAlphaType); 1076 1077 SkPixelGeometry geo = rec.fSaveLayerFlags & kPreserveLCDText_SaveLayerFlag 1078 ? fProps.pixelGeometry() 1079 : kUnknown_SkPixelGeometry; 1080 const bool trackCoverage = SkToBool( 1081 rec.fSaveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag); 1082 const auto createInfo = SkBaseDevice::CreateInfo(info, geo, SkBaseDevice::kNever_TileUsage, 1083 trackCoverage, fAllocator.get()); 1084 // Use the original paint as a hint so that it includes the image filter 1085 newDevice.reset(priorDevice->onCreateDevice(createInfo, rec.fPaint)); 1086 } 1087 1088 bool initBackdrop = (rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop; 1089 if (!newDevice) { 1090 // Either we weren't meant to allocate a full layer, or the full layer creation failed. 1091 // Using an explicit NoPixelsDevice lets us reflect what the layer state would have been 1092 // on success (or kFull_LayerStrategy) while squashing draw calls that target something that 1093 // doesn't exist. 1094 newDevice = sk_make_sp<SkNoPixelsDevice>(SkIRect::MakeWH(layerBounds.width(), 1095 layerBounds.height()), 1096 fProps, this->imageInfo().refColorSpace()); 1097 initBackdrop = false; 1098 } 1099 1100 // Configure device to match determined mapping for any image filters. 1101 // The setDeviceCoordinateSystem applies the prior device's global transform since 1102 // 'newLayerMapping' only defines the transforms between the two devices and it must be updated 1103 // to the global coordinate system. 1104 newDevice->setMarkerStack(fMarkerStack.get()); 1105 if (!newDevice->setDeviceCoordinateSystem(priorDevice->deviceToGlobal() * 1106 SkM44(newLayerMapping.deviceMatrix()), 1107 SkM44(newLayerMapping.layerMatrix()), 1108 layerBounds.left(), layerBounds.top())) { 1109 // If we made it this far and the coordinate system is invalid, we most likely had a valid 1110 // mapping until being combined with the previous device-to-global matrix, at which point 1111 // it overflowed or floating point rounding caused it to no longer be invertible. There's 1112 // not much we can do but clean up the layer and mark the clip as empty. This tends to come 1113 // up in fuzzer-generated inputs, so this policy is not unreasonable and helps avoids UB. 1114 newDevice = nullptr; 1115 abortLayer(); 1116 return; 1117 } 1118 1119 if (initBackdrop) { 1120 SkPaint backdropPaint; 1121 const SkImageFilter* backdropFilter = optimize_layer_filter(rec.fBackdrop, &backdropPaint); 1122 // The new device was constructed to be compatible with 'filter', not necessarily 1123 // 'rec.fBackdrop', so allow DrawDeviceWithFilter to transform the prior device contents 1124 // if necessary to evaluate the backdrop filter. If no filters are involved, then the 1125 // devices differ by integer translations and are always compatible. 1126 bool scaleBackdrop = rec.fExperimentalBackdropScale != 1.0f; 1127 auto compat = (filter || backdropFilter || scaleBackdrop) 1128 ? DeviceCompatibleWithFilter::kUnknown : DeviceCompatibleWithFilter::kYes; 1129 this->internalDrawDeviceWithFilter(priorDevice, // src 1130 newDevice.get(), // dst 1131 backdropFilter, 1132 backdropPaint, 1133 compat, 1134 rec.fExperimentalBackdropScale); 1135 } 1136 1137 fMCRec->newLayer(std::move(newDevice), sk_ref_sp(filter), restorePaint); 1138 fQuickRejectBounds = this->computeDeviceClipBounds(); 1139 } 1140 saveLayerAlpha(const SkRect * bounds,U8CPU alpha)1141 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) { 1142 if (0xFF == alpha) { 1143 return this->saveLayer(bounds, nullptr); 1144 } else { 1145 SkPaint tmpPaint; 1146 tmpPaint.setAlpha(alpha); 1147 return this->saveLayer(bounds, &tmpPaint); 1148 } 1149 } 1150 internalSaveBehind(const SkRect * localBounds)1151 void SkCanvas::internalSaveBehind(const SkRect* localBounds) { 1152 SkBaseDevice* device = this->topDevice(); 1153 1154 // Map the local bounds into the top device's coordinate space (this is not 1155 // necessarily the full global CTM transform). 1156 SkIRect devBounds; 1157 if (localBounds) { 1158 SkRect tmp; 1159 device->localToDevice().mapRect(&tmp, *localBounds); 1160 if (!devBounds.intersect(tmp.round(), device->devClipBounds())) { 1161 devBounds.setEmpty(); 1162 } 1163 } else { 1164 devBounds = device->devClipBounds(); 1165 } 1166 if (devBounds.isEmpty()) { 1167 return; 1168 } 1169 1170 // This is getting the special image from the current device, which is then drawn into (both by 1171 // a client, and the drawClippedToSaveBehind below). Since this is not saving a layer, with its 1172 // own device, we need to explicitly copy the back image contents so that its original content 1173 // is available when we splat it back later during restore. 1174 auto backImage = device->snapSpecial(devBounds, /* copy */ true); 1175 if (!backImage) { 1176 return; 1177 } 1178 1179 // we really need the save, so we can wack the fMCRec 1180 this->checkForDeferredSave(); 1181 1182 fMCRec->fBackImage = 1183 std::make_unique<BackImage>(BackImage{std::move(backImage), devBounds.topLeft()}); 1184 1185 SkPaint paint; 1186 paint.setBlendMode(SkBlendMode::kClear); 1187 this->drawClippedToSaveBehind(paint); 1188 } 1189 internalRestore()1190 void SkCanvas::internalRestore() { 1191 SkASSERT(!fMCStack.empty()); 1192 1193 // now detach these from fMCRec so we can pop(). Gets freed after its drawn 1194 std::unique_ptr<Layer> layer = std::move(fMCRec->fLayer); 1195 std::unique_ptr<BackImage> backImage = std::move(fMCRec->fBackImage); 1196 1197 fMarkerStack->restore(fMCRec); 1198 1199 // now do the normal restore() 1200 fMCRec->~MCRec(); // balanced in save() 1201 fMCStack.pop_back(); 1202 fMCRec = (MCRec*) fMCStack.back(); 1203 1204 if (!fMCRec) { 1205 // This was the last record, restored during the destruction of the SkCanvas 1206 return; 1207 } 1208 1209 this->topDevice()->restore(fMCRec->fMatrix); 1210 1211 if (backImage) { 1212 SkPaint paint; 1213 paint.setBlendMode(SkBlendMode::kDstOver); 1214 this->topDevice()->drawSpecial(backImage->fImage.get(), 1215 SkMatrix::Translate(backImage->fLoc), 1216 SkSamplingOptions(), 1217 paint); 1218 } 1219 1220 // Draw the layer's device contents into the now-current older device. We can't call public 1221 // draw functions since we don't want to record them. 1222 if (layer && !layer->fDevice->isNoPixelsDevice() && !layer->fDiscard) { 1223 layer->fDevice->setImmutable(); 1224 1225 // Don't go through AutoLayerForImageFilter since device draws are so closely tied to 1226 // internalSaveLayer and internalRestore. 1227 if (this->predrawNotify()) { 1228 SkBaseDevice* dstDev = this->topDevice(); 1229 if (layer->fImageFilter) { 1230 this->internalDrawDeviceWithFilter(layer->fDevice.get(), // src 1231 dstDev, // dst 1232 layer->fImageFilter.get(), 1233 layer->fPaint, 1234 DeviceCompatibleWithFilter::kYes); 1235 } else { 1236 // NOTE: We don't just call internalDrawDeviceWithFilter with a null filter 1237 // because we want to take advantage of overridden drawDevice functions for 1238 // document-based devices. 1239 SkSamplingOptions sampling; 1240 dstDev->drawDevice(layer->fDevice.get(), sampling, layer->fPaint); 1241 } 1242 } 1243 } 1244 1245 // Reset the clip restriction if the restore went past the save point that had added it. 1246 if (this->getSaveCount() < fClipRestrictionSaveCount) { 1247 fClipRestrictionRect.setEmpty(); 1248 fClipRestrictionSaveCount = -1; 1249 } 1250 // Update the quick-reject bounds in case the restore changed the top device or the 1251 // removed save record had included modifications to the clip stack. 1252 fQuickRejectBounds = this->computeDeviceClipBounds(); 1253 this->validateClip(); 1254 } 1255 makeSurface(const SkImageInfo & info,const SkSurfaceProps * props)1256 sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) { 1257 if (nullptr == props) { 1258 props = &fProps; 1259 } 1260 return this->onNewSurface(info, *props); 1261 } 1262 onNewSurface(const SkImageInfo & info,const SkSurfaceProps & props)1263 sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) { 1264 return this->baseDevice()->makeSurface(info, props); 1265 } 1266 imageInfo() const1267 SkImageInfo SkCanvas::imageInfo() const { 1268 return this->onImageInfo(); 1269 } 1270 onImageInfo() const1271 SkImageInfo SkCanvas::onImageInfo() const { 1272 return this->baseDevice()->imageInfo(); 1273 } 1274 getProps(SkSurfaceProps * props) const1275 bool SkCanvas::getProps(SkSurfaceProps* props) const { 1276 return this->onGetProps(props); 1277 } 1278 onGetProps(SkSurfaceProps * props) const1279 bool SkCanvas::onGetProps(SkSurfaceProps* props) const { 1280 if (props) { 1281 *props = fProps; 1282 } 1283 return true; 1284 } 1285 peekPixels(SkPixmap * pmap)1286 bool SkCanvas::peekPixels(SkPixmap* pmap) { 1287 return this->onPeekPixels(pmap); 1288 } 1289 onPeekPixels(SkPixmap * pmap)1290 bool SkCanvas::onPeekPixels(SkPixmap* pmap) { 1291 return this->baseDevice()->peekPixels(pmap); 1292 } 1293 accessTopLayerPixels(SkImageInfo * info,size_t * rowBytes,SkIPoint * origin)1294 void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) { 1295 SkPixmap pmap; 1296 if (!this->onAccessTopLayerPixels(&pmap)) { 1297 return nullptr; 1298 } 1299 if (info) { 1300 *info = pmap.info(); 1301 } 1302 if (rowBytes) { 1303 *rowBytes = pmap.rowBytes(); 1304 } 1305 if (origin) { 1306 // If the caller requested the origin, they presumably are expecting the returned pixels to 1307 // be axis-aligned with the root canvas. If the top level device isn't axis aligned, that's 1308 // not the case. Until we update accessTopLayerPixels() to accept a coord space matrix 1309 // instead of an origin, just don't expose the pixels in that case. Note that this means 1310 // that layers with complex coordinate spaces can still report their pixels if the caller 1311 // does not ask for the origin (e.g. just to dump its output to a file, etc). 1312 if (this->topDevice()->isPixelAlignedToGlobal()) { 1313 *origin = this->topDevice()->getOrigin(); 1314 } else { 1315 return nullptr; 1316 } 1317 } 1318 return pmap.writable_addr(); 1319 } 1320 onAccessTopLayerPixels(SkPixmap * pmap)1321 bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) { 1322 return this->topDevice()->accessPixels(pmap); 1323 } 1324 1325 ///////////////////////////////////////////////////////////////////////////// 1326 translate(SkScalar dx,SkScalar dy)1327 void SkCanvas::translate(SkScalar dx, SkScalar dy) { 1328 if (dx || dy) { 1329 this->checkForDeferredSave(); 1330 fMCRec->fMatrix.preTranslate(dx, dy); 1331 1332 this->topDevice()->setGlobalCTM(fMCRec->fMatrix); 1333 1334 this->didTranslate(dx,dy); 1335 } 1336 } 1337 scale(SkScalar sx,SkScalar sy)1338 void SkCanvas::scale(SkScalar sx, SkScalar sy) { 1339 if (sx != 1 || sy != 1) { 1340 this->checkForDeferredSave(); 1341 fMCRec->fMatrix.preScale(sx, sy); 1342 1343 this->topDevice()->setGlobalCTM(fMCRec->fMatrix); 1344 1345 this->didScale(sx, sy); 1346 } 1347 } 1348 rotate(SkScalar degrees)1349 void SkCanvas::rotate(SkScalar degrees) { 1350 SkMatrix m; 1351 m.setRotate(degrees); 1352 this->concat(m); 1353 } 1354 rotate(SkScalar degrees,SkScalar px,SkScalar py)1355 void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) { 1356 SkMatrix m; 1357 m.setRotate(degrees, px, py); 1358 this->concat(m); 1359 } 1360 skew(SkScalar sx,SkScalar sy)1361 void SkCanvas::skew(SkScalar sx, SkScalar sy) { 1362 SkMatrix m; 1363 m.setSkew(sx, sy); 1364 this->concat(m); 1365 } 1366 concat(const SkMatrix & matrix)1367 void SkCanvas::concat(const SkMatrix& matrix) { 1368 if (matrix.isIdentity()) { 1369 return; 1370 } 1371 this->concat(SkM44(matrix)); 1372 } 1373 internalConcat44(const SkM44 & m)1374 void SkCanvas::internalConcat44(const SkM44& m) { 1375 this->checkForDeferredSave(); 1376 1377 fMCRec->fMatrix.preConcat(m); 1378 1379 this->topDevice()->setGlobalCTM(fMCRec->fMatrix); 1380 } 1381 concat(const SkM44 & m)1382 void SkCanvas::concat(const SkM44& m) { 1383 this->internalConcat44(m); 1384 // notify subclasses 1385 this->didConcat44(m); 1386 } 1387 internalSetMatrix(const SkM44 & m)1388 void SkCanvas::internalSetMatrix(const SkM44& m) { 1389 fMCRec->fMatrix = m; 1390 1391 this->topDevice()->setGlobalCTM(fMCRec->fMatrix); 1392 } 1393 setMatrix(const SkMatrix & matrix)1394 void SkCanvas::setMatrix(const SkMatrix& matrix) { 1395 this->setMatrix(SkM44(matrix)); 1396 } 1397 setMatrix(const SkM44 & m)1398 void SkCanvas::setMatrix(const SkM44& m) { 1399 this->checkForDeferredSave(); 1400 this->internalSetMatrix(m); 1401 this->didSetM44(m); 1402 } 1403 resetMatrix()1404 void SkCanvas::resetMatrix() { 1405 this->setMatrix(SkM44()); 1406 } 1407 markCTM(const char * name)1408 void SkCanvas::markCTM(const char* name) { 1409 if (SkCanvasPriv::ValidateMarker(name)) { 1410 fMarkerStack->setMarker(SkOpts::hash_fn(name, strlen(name), 0), 1411 this->getLocalToDevice(), fMCRec); 1412 this->onMarkCTM(name); 1413 } 1414 } 1415 findMarkedCTM(const char * name,SkM44 * mx) const1416 bool SkCanvas::findMarkedCTM(const char* name, SkM44* mx) const { 1417 return SkCanvasPriv::ValidateMarker(name) && 1418 fMarkerStack->findMarker(SkOpts::hash_fn(name, strlen(name), 0), mx); 1419 } 1420 1421 ////////////////////////////////////////////////////////////////////////////// 1422 clipRect(const SkRect & rect,SkClipOp op,bool doAA)1423 void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) { 1424 if (!rect.isFinite()) { 1425 return; 1426 } 1427 this->checkForDeferredSave(); 1428 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1429 this->onClipRect(rect.makeSorted(), op, edgeStyle); 1430 } 1431 onClipRect(const SkRect & rect,SkClipOp op,ClipEdgeStyle edgeStyle)1432 void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) { 1433 SkASSERT(rect.isSorted()); 1434 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle; 1435 1436 AutoUpdateQRBounds aqr(this); 1437 this->topDevice()->clipRect(rect, op, isAA); 1438 } 1439 androidFramework_setDeviceClipRestriction(const SkIRect & rect)1440 void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) { 1441 // The device clip restriction is a surface-space rectangular intersection that cannot be 1442 // drawn outside of. The rectangle is remembered so that subsequent resetClip calls still 1443 // respect the restriction. Other than clip resetting, all clip operations restrict the set 1444 // of renderable pixels, so once set, the restriction will be respected until the canvas 1445 // save stack is restored past the point this function was invoked. Unfortunately, the current 1446 // implementation relies on the clip stack of the underyling SkDevices, which leads to some 1447 // awkward behavioral interactions (see skbug.com/12252). 1448 // 1449 // Namely, a canvas restore() could undo the clip restriction's rect, and if 1450 // setDeviceClipRestriction were called at a nested save level, there's no way to undo just the 1451 // prior restriction and re-apply the new one. It also only makes sense to apply to the base 1452 // device; any other device for a saved layer will be clipped back to the base device during its 1453 // matched restore. As such, we: 1454 // - Remember the save count that added the clip restriction and reset the rect to empty when 1455 // we've restored past that point to keep our state in sync with the device's clip stack. 1456 // - We assert that we're on the base device when this is invoked. 1457 // - We assert that setDeviceClipRestriction() is only called when there was no prior 1458 // restriction (cannot re-restrict, and prior state must have been reset by restoring the 1459 // canvas state). 1460 // - Historically, the empty rect would reset the clip restriction but it only could do so 1461 // partially since the device's clips wasn't adjusted. Resetting is now handled 1462 // automatically via SkCanvas::restore(), so empty input rects are skipped. 1463 SkASSERT(this->topDevice() == this->baseDevice()); // shouldn't be in a nested layer 1464 // and shouldn't already have a restriction 1465 SkASSERT(fClipRestrictionSaveCount < 0 && fClipRestrictionRect.isEmpty()); 1466 1467 if (fClipRestrictionSaveCount < 0 && !rect.isEmpty()) { 1468 fClipRestrictionRect = rect; 1469 fClipRestrictionSaveCount = this->getSaveCount(); 1470 1471 // A non-empty clip restriction immediately applies an intersection op (ignoring the ctm). 1472 // so we have to resolve the save. 1473 this->checkForDeferredSave(); 1474 AutoUpdateQRBounds aqr(this); 1475 // Use clipRegion() since that operates in canvas-space, whereas clipRect() would apply the 1476 // device's current transform first. 1477 this->topDevice()->clipRegion(SkRegion(rect), SkClipOp::kIntersect); 1478 } 1479 } 1480 internal_private_resetClip()1481 void SkCanvas::internal_private_resetClip() { 1482 this->checkForDeferredSave(); 1483 this->onResetClip(); 1484 } 1485 onResetClip()1486 void SkCanvas::onResetClip() { 1487 SkIRect deviceRestriction = this->topDevice()->imageInfo().bounds(); 1488 if (fClipRestrictionSaveCount >= 0 && this->topDevice() == this->baseDevice()) { 1489 // Respect the device clip restriction when resetting the clip if we're on the base device. 1490 // If we're not on the base device, then the "reset" applies to the top device's clip stack, 1491 // and the clip restriction will be respected automatically during a restore of the layer. 1492 if (!deviceRestriction.intersect(fClipRestrictionRect)) { 1493 deviceRestriction = SkIRect::MakeEmpty(); 1494 } 1495 } 1496 1497 AutoUpdateQRBounds aqr(this); 1498 this->topDevice()->replaceClip(deviceRestriction); 1499 } 1500 clipRRect(const SkRRect & rrect,SkClipOp op,bool doAA)1501 void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) { 1502 this->checkForDeferredSave(); 1503 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1504 if (rrect.isRect()) { 1505 this->onClipRect(rrect.getBounds(), op, edgeStyle); 1506 } else { 1507 this->onClipRRect(rrect, op, edgeStyle); 1508 } 1509 } 1510 onClipRRect(const SkRRect & rrect,SkClipOp op,ClipEdgeStyle edgeStyle)1511 void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) { 1512 bool isAA = kSoft_ClipEdgeStyle == edgeStyle; 1513 1514 AutoUpdateQRBounds aqr(this); 1515 this->topDevice()->clipRRect(rrect, op, isAA); 1516 } 1517 clipPath(const SkPath & path,SkClipOp op,bool doAA)1518 void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) { 1519 this->checkForDeferredSave(); 1520 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1521 1522 if (!path.isInverseFillType() && fMCRec->fMatrix.asM33().rectStaysRect()) { 1523 SkRect r; 1524 if (path.isRect(&r)) { 1525 this->onClipRect(r, op, edgeStyle); 1526 return; 1527 } 1528 SkRRect rrect; 1529 if (path.isOval(&r)) { 1530 rrect.setOval(r); 1531 this->onClipRRect(rrect, op, edgeStyle); 1532 return; 1533 } 1534 if (path.isRRect(&rrect)) { 1535 this->onClipRRect(rrect, op, edgeStyle); 1536 return; 1537 } 1538 } 1539 1540 this->onClipPath(path, op, edgeStyle); 1541 } 1542 onClipPath(const SkPath & path,SkClipOp op,ClipEdgeStyle edgeStyle)1543 void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) { 1544 bool isAA = kSoft_ClipEdgeStyle == edgeStyle; 1545 1546 AutoUpdateQRBounds aqr(this); 1547 this->topDevice()->clipPath(path, op, isAA); 1548 } 1549 clipShader(sk_sp<SkShader> sh,SkClipOp op)1550 void SkCanvas::clipShader(sk_sp<SkShader> sh, SkClipOp op) { 1551 if (sh) { 1552 if (sh->isOpaque()) { 1553 if (op == SkClipOp::kIntersect) { 1554 // we don't occlude anything, so skip this call 1555 } else { 1556 SkASSERT(op == SkClipOp::kDifference); 1557 // we occlude everything, so set the clip to empty 1558 this->clipRect({0,0,0,0}); 1559 } 1560 } else { 1561 this->checkForDeferredSave(); 1562 this->onClipShader(std::move(sh), op); 1563 } 1564 } 1565 } 1566 onClipShader(sk_sp<SkShader> sh,SkClipOp op)1567 void SkCanvas::onClipShader(sk_sp<SkShader> sh, SkClipOp op) { 1568 AutoUpdateQRBounds aqr(this); 1569 this->topDevice()->clipShader(sh, op); 1570 } 1571 clipRegion(const SkRegion & rgn,SkClipOp op)1572 void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) { 1573 this->checkForDeferredSave(); 1574 this->onClipRegion(rgn, op); 1575 } 1576 onClipRegion(const SkRegion & rgn,SkClipOp op)1577 void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) { 1578 AutoUpdateQRBounds aqr(this); 1579 this->topDevice()->clipRegion(rgn, op); 1580 } 1581 validateClip() const1582 void SkCanvas::validateClip() const { 1583 #ifdef SK_DEBUG 1584 SkRect tmp = this->computeDeviceClipBounds(); 1585 if (this->isClipEmpty()) { 1586 SkASSERT(fQuickRejectBounds.isEmpty()); 1587 } else { 1588 SkASSERT(tmp == fQuickRejectBounds); 1589 } 1590 #endif 1591 } 1592 androidFramework_isClipAA() const1593 bool SkCanvas::androidFramework_isClipAA() const { 1594 return this->topDevice()->onClipIsAA(); 1595 } 1596 temporary_internal_getRgnClip(SkRegion * rgn)1597 void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) { 1598 rgn->setEmpty(); 1599 SkBaseDevice* device = this->topDevice(); 1600 if (device && device->isPixelAlignedToGlobal()) { 1601 device->onAsRgnClip(rgn); 1602 SkIPoint origin = device->getOrigin(); 1603 if (origin.x() | origin.y()) { 1604 rgn->translate(origin.x(), origin.y()); 1605 } 1606 } 1607 } 1608 1609 /////////////////////////////////////////////////////////////////////////////// 1610 isClipEmpty() const1611 bool SkCanvas::isClipEmpty() const { 1612 return this->topDevice()->onGetClipType() == SkBaseDevice::ClipType::kEmpty; 1613 } 1614 isClipRect() const1615 bool SkCanvas::isClipRect() const { 1616 return this->topDevice()->onGetClipType() == SkBaseDevice::ClipType::kRect; 1617 } 1618 quickReject(const SkRect & src) const1619 bool SkCanvas::quickReject(const SkRect& src) const { 1620 #ifdef SK_DEBUG 1621 // Verify that fQuickRejectBounds are set properly. 1622 this->validateClip(); 1623 #endif 1624 1625 SkRect devRect = SkMatrixPriv::MapRect(fMCRec->fMatrix, src); 1626 return !devRect.isFinite() || !devRect.intersects(fQuickRejectBounds); 1627 } 1628 quickReject(const SkPath & path) const1629 bool SkCanvas::quickReject(const SkPath& path) const { 1630 return path.isEmpty() || this->quickReject(path.getBounds()); 1631 } 1632 internalQuickReject(const SkRect & bounds,const SkPaint & paint,const SkMatrix * matrix)1633 bool SkCanvas::internalQuickReject(const SkRect& bounds, const SkPaint& paint, 1634 const SkMatrix* matrix) { 1635 if (!bounds.isFinite() || paint.nothingToDraw()) { 1636 return true; 1637 } 1638 1639 if (paint.canComputeFastBounds()) { 1640 SkRect tmp = matrix ? matrix->mapRect(bounds) : bounds; 1641 return this->quickReject(paint.computeFastBounds(tmp, &tmp)); 1642 } 1643 1644 return false; 1645 } 1646 1647 getLocalClipBounds() const1648 SkRect SkCanvas::getLocalClipBounds() const { 1649 SkIRect ibounds = this->getDeviceClipBounds(); 1650 if (ibounds.isEmpty()) { 1651 return SkRect::MakeEmpty(); 1652 } 1653 1654 SkMatrix inverse; 1655 // if we can't invert the CTM, we can't return local clip bounds 1656 if (!fMCRec->fMatrix.asM33().invert(&inverse)) { 1657 return SkRect::MakeEmpty(); 1658 } 1659 1660 SkRect bounds; 1661 // adjust it outwards in case we are antialiasing 1662 const int margin = 1; 1663 1664 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin)); 1665 inverse.mapRect(&bounds, r); 1666 return bounds; 1667 } 1668 getDeviceClipBounds() const1669 SkIRect SkCanvas::getDeviceClipBounds() const { 1670 return this->computeDeviceClipBounds(/*outsetForAA=*/false).roundOut(); 1671 } 1672 computeDeviceClipBounds(bool outsetForAA) const1673 SkRect SkCanvas::computeDeviceClipBounds(bool outsetForAA) const { 1674 const SkBaseDevice* dev = this->topDevice(); 1675 if (dev->onGetClipType() == SkBaseDevice::ClipType::kEmpty) { 1676 return SkRect::MakeEmpty(); 1677 } else { 1678 SkRect devClipBounds = 1679 SkMatrixPriv::MapRect(dev->deviceToGlobal(), SkRect::Make(dev->devClipBounds())); 1680 if (outsetForAA) { 1681 // Expand bounds out by 1 in case we are anti-aliasing. We store the 1682 // bounds as floats to enable a faster quick reject implementation. 1683 devClipBounds.outset(1.f, 1.f); 1684 } 1685 return devClipBounds; 1686 } 1687 } 1688 1689 /////////////////////////////////////////////////////////////////////// 1690 getTotalMatrix() const1691 SkMatrix SkCanvas::getTotalMatrix() const { 1692 return fMCRec->fMatrix.asM33(); 1693 } 1694 getLocalToDevice() const1695 SkM44 SkCanvas::getLocalToDevice() const { 1696 return fMCRec->fMatrix; 1697 } 1698 1699 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && SK_SUPPORT_GPU 1700 topLayerBounds() const1701 SkIRect SkCanvas::topLayerBounds() const { 1702 return this->topDevice()->getGlobalBounds(); 1703 } 1704 topLayerBackendRenderTarget() const1705 GrBackendRenderTarget SkCanvas::topLayerBackendRenderTarget() const { 1706 auto proxy = SkCanvasPriv::TopDeviceTargetProxy(const_cast<SkCanvas*>(this)); 1707 if (!proxy) { 1708 return {}; 1709 } 1710 const GrRenderTarget* renderTarget = proxy->peekRenderTarget(); 1711 return renderTarget ? renderTarget->getBackendRenderTarget() : GrBackendRenderTarget(); 1712 } 1713 #endif 1714 recordingContext()1715 GrRecordingContext* SkCanvas::recordingContext() { 1716 #if SK_SUPPORT_GPU 1717 if (auto gpuDevice = this->topDevice()->asGpuDevice()) { 1718 return gpuDevice->recordingContext(); 1719 } 1720 #endif 1721 1722 return nullptr; 1723 } 1724 drawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)1725 void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner, 1726 const SkPaint& paint) { 1727 TRACE_EVENT0("skia", TRACE_FUNC); 1728 if (outer.isEmpty()) { 1729 return; 1730 } 1731 if (inner.isEmpty()) { 1732 this->drawRRect(outer, paint); 1733 return; 1734 } 1735 1736 // We don't have this method (yet), but technically this is what we should 1737 // be able to return ... 1738 // if (!outer.contains(inner))) { 1739 // 1740 // For now at least check for containment of bounds 1741 if (!outer.getBounds().contains(inner.getBounds())) { 1742 return; 1743 } 1744 1745 this->onDrawDRRect(outer, inner, paint); 1746 } 1747 drawPaint(const SkPaint & paint)1748 void SkCanvas::drawPaint(const SkPaint& paint) { 1749 TRACE_EVENT0("skia", TRACE_FUNC); 1750 this->onDrawPaint(paint); 1751 } 1752 drawRect(const SkRect & r,const SkPaint & paint)1753 void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1754 TRACE_EVENT0("skia", TRACE_FUNC); 1755 // To avoid redundant logic in our culling code and various backends, we always sort rects 1756 // before passing them along. 1757 this->onDrawRect(r.makeSorted(), paint); 1758 } 1759 drawClippedToSaveBehind(const SkPaint & paint)1760 void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) { 1761 TRACE_EVENT0("skia", TRACE_FUNC); 1762 this->onDrawBehind(paint); 1763 } 1764 drawRegion(const SkRegion & region,const SkPaint & paint)1765 void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) { 1766 TRACE_EVENT0("skia", TRACE_FUNC); 1767 if (region.isEmpty()) { 1768 return; 1769 } 1770 1771 if (region.isRect()) { 1772 return this->drawIRect(region.getBounds(), paint); 1773 } 1774 1775 this->onDrawRegion(region, paint); 1776 } 1777 drawOval(const SkRect & r,const SkPaint & paint)1778 void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) { 1779 TRACE_EVENT0("skia", TRACE_FUNC); 1780 // To avoid redundant logic in our culling code and various backends, we always sort rects 1781 // before passing them along. 1782 this->onDrawOval(r.makeSorted(), paint); 1783 } 1784 drawRRect(const SkRRect & rrect,const SkPaint & paint)1785 void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 1786 TRACE_EVENT0("skia", TRACE_FUNC); 1787 this->onDrawRRect(rrect, paint); 1788 } 1789 drawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)1790 void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { 1791 TRACE_EVENT0("skia", TRACE_FUNC); 1792 this->onDrawPoints(mode, count, pts, paint); 1793 } 1794 drawVertices(const sk_sp<SkVertices> & vertices,SkBlendMode mode,const SkPaint & paint)1795 void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode, 1796 const SkPaint& paint) { 1797 this->drawVertices(vertices.get(), mode, paint); 1798 } 1799 drawVertices(const SkVertices * vertices,SkBlendMode mode,const SkPaint & paint)1800 void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) { 1801 TRACE_EVENT0("skia", TRACE_FUNC); 1802 RETURN_ON_NULL(vertices); 1803 1804 // We expect fans to be converted to triangles when building or deserializing SkVertices. 1805 SkASSERT(vertices->priv().mode() != SkVertices::kTriangleFan_VertexMode); 1806 1807 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 1808 // Preserve legacy behavior for Android: ignore the SkShader if there are no texCoords present 1809 if (paint.getShader() && !vertices->priv().hasTexCoords()) { 1810 SkPaint noShaderPaint(paint); 1811 noShaderPaint.setShader(nullptr); 1812 this->onDrawVerticesObject(vertices, mode, noShaderPaint); 1813 return; 1814 } 1815 #endif 1816 1817 this->onDrawVerticesObject(vertices, mode, paint); 1818 } 1819 drawPath(const SkPath & path,const SkPaint & paint)1820 void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 1821 TRACE_EVENT0("skia", TRACE_FUNC); 1822 this->onDrawPath(path, paint); 1823 } 1824 1825 // Returns true if the rect can be "filled" : non-empty and finite fillable(const SkRect & r)1826 static bool fillable(const SkRect& r) { 1827 SkScalar w = r.width(); 1828 SkScalar h = r.height(); 1829 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0; 1830 } 1831 clean_paint_for_lattice(const SkPaint * paint)1832 static SkPaint clean_paint_for_lattice(const SkPaint* paint) { 1833 SkPaint cleaned; 1834 if (paint) { 1835 cleaned = *paint; 1836 cleaned.setMaskFilter(nullptr); 1837 cleaned.setAntiAlias(false); 1838 } 1839 return cleaned; 1840 } 1841 drawImageNine(const SkImage * image,const SkIRect & center,const SkRect & dst,SkFilterMode filter,const SkPaint * paint)1842 void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, 1843 SkFilterMode filter, const SkPaint* paint) { 1844 RETURN_ON_NULL(image); 1845 1846 const int xdivs[] = {center.fLeft, center.fRight}; 1847 const int ydivs[] = {center.fTop, center.fBottom}; 1848 1849 Lattice lat; 1850 lat.fXDivs = xdivs; 1851 lat.fYDivs = ydivs; 1852 lat.fRectTypes = nullptr; 1853 lat.fXCount = lat.fYCount = 2; 1854 lat.fBounds = nullptr; 1855 lat.fColors = nullptr; 1856 this->drawImageLattice(image, lat, dst, filter, paint); 1857 } 1858 drawImageLattice(const SkImage * image,const Lattice & lattice,const SkRect & dst,SkFilterMode filter,const SkPaint * paint)1859 void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, 1860 SkFilterMode filter, const SkPaint* paint) { 1861 TRACE_EVENT0("skia", TRACE_FUNC); 1862 RETURN_ON_NULL(image); 1863 if (dst.isEmpty()) { 1864 return; 1865 } 1866 1867 SkIRect bounds; 1868 Lattice latticePlusBounds = lattice; 1869 if (!latticePlusBounds.fBounds) { 1870 bounds = SkIRect::MakeWH(image->width(), image->height()); 1871 latticePlusBounds.fBounds = &bounds; 1872 } 1873 1874 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) { 1875 SkPaint latticePaint = clean_paint_for_lattice(paint); 1876 this->onDrawImageLattice2(image, latticePlusBounds, dst, filter, &latticePaint); 1877 } else { 1878 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, 1879 SkSamplingOptions(filter), paint, kStrict_SrcRectConstraint); 1880 } 1881 } 1882 drawAtlas(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkBlendMode mode,const SkSamplingOptions & sampling,const SkRect * cull,const SkPaint * paint)1883 void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], 1884 const SkColor colors[], int count, SkBlendMode mode, 1885 const SkSamplingOptions& sampling, const SkRect* cull, 1886 const SkPaint* paint) { 1887 TRACE_EVENT0("skia", TRACE_FUNC); 1888 RETURN_ON_NULL(atlas); 1889 if (count <= 0) { 1890 return; 1891 } 1892 SkASSERT(atlas); 1893 SkASSERT(tex); 1894 this->onDrawAtlas2(atlas, xform, tex, colors, count, mode, sampling, cull, paint); 1895 } 1896 drawAnnotation(const SkRect & rect,const char key[],SkData * value)1897 void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) { 1898 TRACE_EVENT0("skia", TRACE_FUNC); 1899 if (key) { 1900 this->onDrawAnnotation(rect, key, value); 1901 } 1902 } 1903 private_draw_shadow_rec(const SkPath & path,const SkDrawShadowRec & rec)1904 void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) { 1905 TRACE_EVENT0("skia", TRACE_FUNC); 1906 this->onDrawShadowRec(path, rec); 1907 } 1908 onDrawShadowRec(const SkPath & path,const SkDrawShadowRec & rec)1909 void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) { 1910 // We don't test quickReject because the shadow outsets the path's bounds. 1911 // TODO(michaelludwig): Is it worth calling SkDrawShadowMetrics::GetLocalBounds here? 1912 if (!this->predrawNotify()) { 1913 return; 1914 } 1915 this->topDevice()->drawShadow(path, rec); 1916 } 1917 experimental_DrawEdgeAAQuad(const SkRect & rect,const SkPoint clip[4],QuadAAFlags aaFlags,const SkColor4f & color,SkBlendMode mode)1918 void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], 1919 QuadAAFlags aaFlags, const SkColor4f& color, 1920 SkBlendMode mode) { 1921 TRACE_EVENT0("skia", TRACE_FUNC); 1922 // Make sure the rect is sorted before passing it along 1923 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode); 1924 } 1925 experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[],int cnt,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)1926 void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt, 1927 const SkPoint dstClips[], 1928 const SkMatrix preViewMatrices[], 1929 const SkSamplingOptions& sampling, 1930 const SkPaint* paint, 1931 SrcRectConstraint constraint) { 1932 TRACE_EVENT0("skia", TRACE_FUNC); 1933 this->onDrawEdgeAAImageSet2(imageSet, cnt, dstClips, preViewMatrices, sampling, paint, 1934 constraint); 1935 } 1936 1937 ////////////////////////////////////////////////////////////////////////////// 1938 // These are the virtual drawing methods 1939 ////////////////////////////////////////////////////////////////////////////// 1940 onDiscard()1941 void SkCanvas::onDiscard() { 1942 if (fSurfaceBase) { 1943 sk_ignore_unused_variable(fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode)); 1944 } 1945 } 1946 onDrawPaint(const SkPaint & paint)1947 void SkCanvas::onDrawPaint(const SkPaint& paint) { 1948 this->internalDrawPaint(paint); 1949 } 1950 internalDrawPaint(const SkPaint & paint)1951 void SkCanvas::internalDrawPaint(const SkPaint& paint) { 1952 // drawPaint does not call internalQuickReject() because computing its geometry is not free 1953 // (see getLocalClipBounds(), and the two conditions below are sufficient. 1954 if (paint.nothingToDraw() || this->isClipEmpty()) { 1955 return; 1956 } 1957 1958 auto layer = this->aboutToDraw(this, paint, nullptr, CheckForOverwrite::kYes); 1959 if (layer) { 1960 this->topDevice()->drawPaint(layer->paint()); 1961 } 1962 } 1963 onDrawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)1964 void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], 1965 const SkPaint& paint) { 1966 if ((long)count <= 0 || paint.nothingToDraw()) { 1967 return; 1968 } 1969 SkASSERT(pts != nullptr); 1970 1971 SkRect bounds; 1972 // Compute bounds from points (common for drawing a single line) 1973 if (count == 2) { 1974 bounds.set(pts[0], pts[1]); 1975 } else { 1976 bounds.setBounds(pts, SkToInt(count)); 1977 } 1978 1979 // Enforce paint style matches implicit behavior of drawPoints 1980 SkPaint strokePaint = paint; 1981 strokePaint.setStyle(SkPaint::kStroke_Style); 1982 if (this->internalQuickReject(bounds, strokePaint)) { 1983 return; 1984 } 1985 1986 auto layer = this->aboutToDraw(this, strokePaint, &bounds); 1987 if (layer) { 1988 this->topDevice()->drawPoints(mode, count, pts, layer->paint()); 1989 } 1990 } 1991 onDrawRect(const SkRect & r,const SkPaint & paint)1992 void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) { 1993 SkASSERT(r.isSorted()); 1994 if (this->internalQuickReject(r, paint)) { 1995 return; 1996 } 1997 1998 auto layer = this->aboutToDraw(this, paint, &r, CheckForOverwrite::kYes); 1999 if (layer) { 2000 this->topDevice()->drawRect(r, layer->paint()); 2001 } 2002 } 2003 onDrawRegion(const SkRegion & region,const SkPaint & paint)2004 void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) { 2005 const SkRect bounds = SkRect::Make(region.getBounds()); 2006 if (this->internalQuickReject(bounds, paint)) { 2007 return; 2008 } 2009 2010 auto layer = this->aboutToDraw(this, paint, &bounds); 2011 if (layer) { 2012 this->topDevice()->drawRegion(region, layer->paint()); 2013 } 2014 } 2015 onDrawBehind(const SkPaint & paint)2016 void SkCanvas::onDrawBehind(const SkPaint& paint) { 2017 SkBaseDevice* dev = this->topDevice(); 2018 if (!dev) { 2019 return; 2020 } 2021 2022 SkIRect bounds; 2023 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart); 2024 for (;;) { 2025 const MCRec* rec = (const MCRec*)iter.prev(); 2026 if (!rec) { 2027 return; // no backimages, so nothing to draw 2028 } 2029 if (rec->fBackImage) { 2030 // drawBehind should only have been called when the saveBehind record is active; 2031 // if this fails, it means a real saveLayer was made w/o being restored first. 2032 SkASSERT(dev == rec->fDevice); 2033 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY, 2034 rec->fBackImage->fImage->width(), 2035 rec->fBackImage->fImage->height()); 2036 break; 2037 } 2038 } 2039 2040 // The backimage location (and thus bounds) were defined in the device's space, so mark it 2041 // as a clip. We use a clip instead of just drawing a rect in case the paint has an image 2042 // filter on it (which is applied before any auto-layer so the filter is clipped). 2043 dev->save(); 2044 { 2045 // We also have to temporarily whack the device matrix since clipRegion is affected by the 2046 // global-to-device matrix and clipRect is affected by the local-to-device. 2047 SkAutoDeviceTransformRestore adtr(dev, SkMatrix::I()); 2048 dev->clipRect(SkRect::Make(bounds), SkClipOp::kIntersect, /* aa */ false); 2049 // ~adtr will reset the local-to-device matrix so that drawPaint() shades correctly. 2050 } 2051 2052 auto layer = this->aboutToDraw(this, paint); 2053 if (layer) { 2054 this->topDevice()->drawPaint(layer->paint()); 2055 } 2056 2057 dev->restore(fMCRec->fMatrix); 2058 } 2059 onDrawOval(const SkRect & oval,const SkPaint & paint)2060 void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) { 2061 SkASSERT(oval.isSorted()); 2062 if (this->internalQuickReject(oval, paint)) { 2063 return; 2064 } 2065 2066 auto layer = this->aboutToDraw(this, paint, &oval); 2067 if (layer) { 2068 this->topDevice()->drawOval(oval, layer->paint()); 2069 } 2070 } 2071 onDrawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)2072 void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle, 2073 SkScalar sweepAngle, bool useCenter, 2074 const SkPaint& paint) { 2075 SkASSERT(oval.isSorted()); 2076 if (this->internalQuickReject(oval, paint)) { 2077 return; 2078 } 2079 2080 auto layer = this->aboutToDraw(this, paint, &oval); 2081 if (layer) { 2082 this->topDevice()->drawArc(oval, startAngle, sweepAngle, useCenter, layer->paint()); 2083 } 2084 } 2085 onDrawRRect(const SkRRect & rrect,const SkPaint & paint)2086 void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { 2087 const SkRect& bounds = rrect.getBounds(); 2088 2089 // Delegating to simpler draw operations 2090 if (rrect.isRect()) { 2091 // call the non-virtual version 2092 this->SkCanvas::drawRect(bounds, paint); 2093 return; 2094 } else if (rrect.isOval()) { 2095 // call the non-virtual version 2096 this->SkCanvas::drawOval(bounds, paint); 2097 return; 2098 } 2099 2100 if (this->internalQuickReject(bounds, paint)) { 2101 return; 2102 } 2103 2104 auto layer = this->aboutToDraw(this, paint, &bounds); 2105 if (layer) { 2106 this->topDevice()->drawRRect(rrect, layer->paint()); 2107 } 2108 } 2109 onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)2110 void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { 2111 const SkRect& bounds = outer.getBounds(); 2112 if (this->internalQuickReject(bounds, paint)) { 2113 return; 2114 } 2115 2116 auto layer = this->aboutToDraw(this, paint, &bounds); 2117 if (layer) { 2118 this->topDevice()->drawDRRect(outer, inner, layer->paint()); 2119 } 2120 } 2121 onDrawPath(const SkPath & path,const SkPaint & paint)2122 void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { 2123 if (!path.isFinite()) { 2124 return; 2125 } 2126 2127 const SkRect& pathBounds = path.getBounds(); 2128 if (!path.isInverseFillType() && this->internalQuickReject(pathBounds, paint)) { 2129 return; 2130 } 2131 if (path.isInverseFillType() && pathBounds.width() <= 0 && pathBounds.height() <= 0) { 2132 this->internalDrawPaint(paint); 2133 return; 2134 } 2135 2136 auto layer = this->aboutToDraw(this, paint, &pathBounds); 2137 if (layer) { 2138 this->topDevice()->drawPath(path, layer->paint()); 2139 } 2140 } 2141 canDrawBitmapAsSprite(SkScalar x,SkScalar y,int w,int h,const SkSamplingOptions & sampling,const SkPaint & paint)2142 bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, 2143 const SkSamplingOptions& sampling, const SkPaint& paint) { 2144 if (!paint.getImageFilter()) { 2145 return false; 2146 } 2147 2148 const SkMatrix& ctm = this->getTotalMatrix(); 2149 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), sampling, paint)) { 2150 return false; 2151 } 2152 2153 // The other paint effects need to be applied before the image filter, but the sprite draw 2154 // applies the filter explicitly first. 2155 if (paint.getAlphaf() < 1.f || paint.getColorFilter() || paint.getMaskFilter()) { 2156 return false; 2157 } 2158 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds. 2159 // Once we can filter and the filter will return a result larger than itself, we should be 2160 // able to remove this constraint. 2161 // skbug.com/4526 2162 // 2163 SkPoint pt; 2164 ctm.mapXY(x, y, &pt); 2165 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h); 2166 // quick bounds have been outset by 1px compared to overall device bounds, so this makes the 2167 // contains check equivalent to between ir and device bounds 2168 ir.outset(1, 1); 2169 return ir.contains(fQuickRejectBounds); 2170 } 2171 2172 // Clean-up the paint to match the drawing semantics for drawImage et al. (skbug.com/7804). clean_paint_for_drawImage(const SkPaint * paint)2173 static SkPaint clean_paint_for_drawImage(const SkPaint* paint) { 2174 SkPaint cleaned; 2175 if (paint) { 2176 cleaned = *paint; 2177 cleaned.setStyle(SkPaint::kFill_Style); 2178 cleaned.setPathEffect(nullptr); 2179 } 2180 return cleaned; 2181 } 2182 2183 // drawVertices fills triangles and ignores mask filter and path effect, 2184 // so canonicalize the paint before checking quick reject. clean_paint_for_drawVertices(SkPaint paint)2185 static SkPaint clean_paint_for_drawVertices(SkPaint paint) { 2186 paint.setStyle(SkPaint::kFill_Style); 2187 paint.setMaskFilter(nullptr); 2188 paint.setPathEffect(nullptr); 2189 return paint; 2190 } 2191 onDrawImage2(const SkImage * image,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint)2192 void SkCanvas::onDrawImage2(const SkImage* image, SkScalar x, SkScalar y, 2193 const SkSamplingOptions& sampling, const SkPaint* paint) { 2194 SkPaint realPaint = clean_paint_for_drawImage(paint); 2195 2196 SkRect bounds = SkRect::MakeXYWH(x, y, image->width(), image->height()); 2197 if (this->internalQuickReject(bounds, realPaint)) { 2198 return; 2199 } 2200 2201 if (realPaint.getImageFilter() && 2202 this->canDrawBitmapAsSprite(x, y, image->width(), image->height(), sampling, realPaint) && 2203 !image_to_color_filter(&realPaint)) { 2204 // Evaluate the image filter directly on the input image and then draw the result, instead 2205 // of first drawing the image to a temporary layer and filtering. 2206 SkBaseDevice* device = this->topDevice(); 2207 sk_sp<SkSpecialImage> special; 2208 if ((special = device->makeSpecial(image))) { 2209 sk_sp<SkImageFilter> filter = realPaint.refImageFilter(); 2210 realPaint.setImageFilter(nullptr); 2211 2212 // TODO(michaelludwig) - Many filters could probably be evaluated like this even if the 2213 // CTM is not translate-only; the post-transformation of the filtered image by the CTM 2214 // will probably look just as good and not require an extra layer. 2215 // TODO(michaelludwig) - Once image filter implementations can support source images 2216 // with non-(0,0) origins, we can just mark the origin as (x,y) instead of doing a 2217 // pre-concat here. 2218 SkMatrix layerToDevice = device->localToDevice(); 2219 layerToDevice.preTranslate(x, y); 2220 skif::Mapping mapping(layerToDevice, SkMatrix::Translate(-x, -y)); 2221 2222 if (this->predrawNotify()) { 2223 device->drawFilteredImage(mapping, special.get(), filter.get(), sampling,realPaint); 2224 } 2225 return; 2226 } // else fall through to regular drawing path 2227 } 2228 2229 auto layer = this->aboutToDraw(this, realPaint, &bounds); 2230 if (layer) { 2231 this->topDevice()->drawImageRect(image, nullptr, bounds, sampling, 2232 layer->paint(), kStrict_SrcRectConstraint); 2233 } 2234 } 2235 onDrawImageRect2(const SkImage * image,const SkRect & src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)2236 void SkCanvas::onDrawImageRect2(const SkImage* image, const SkRect& src, const SkRect& dst, 2237 const SkSamplingOptions& sampling, const SkPaint* paint, 2238 SrcRectConstraint constraint) { 2239 SkPaint realPaint = clean_paint_for_drawImage(paint); 2240 2241 if (this->internalQuickReject(dst, realPaint)) { 2242 return; 2243 } 2244 2245 auto layer = this->aboutToDraw(this, realPaint, &dst, CheckForOverwrite::kYes, 2246 image->isOpaque() ? kOpaque_ShaderOverrideOpacity 2247 : kNotOpaque_ShaderOverrideOpacity); 2248 if (layer) { 2249 this->topDevice()->drawImageRect(image, &src, dst, sampling, layer->paint(), constraint); 2250 } 2251 } 2252 onDrawImageLattice2(const SkImage * image,const Lattice & lattice,const SkRect & dst,SkFilterMode filter,const SkPaint * paint)2253 void SkCanvas::onDrawImageLattice2(const SkImage* image, const Lattice& lattice, const SkRect& dst, 2254 SkFilterMode filter, const SkPaint* paint) { 2255 SkPaint realPaint = clean_paint_for_drawImage(paint); 2256 2257 if (this->internalQuickReject(dst, realPaint)) { 2258 return; 2259 } 2260 2261 auto layer = this->aboutToDraw(this, realPaint, &dst); 2262 if (layer) { 2263 this->topDevice()->drawImageLattice(image, lattice, dst, filter, layer->paint()); 2264 } 2265 } 2266 drawImage(const SkImage * image,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint)2267 void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, 2268 const SkSamplingOptions& sampling, const SkPaint* paint) { 2269 TRACE_EVENT0("skia", TRACE_FUNC); 2270 RETURN_ON_NULL(image); 2271 this->onDrawImage2(image, x, y, sampling, paint); 2272 } 2273 drawImageRect(const SkImage * image,const SkRect & src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)2274 void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst, 2275 const SkSamplingOptions& sampling, const SkPaint* paint, 2276 SrcRectConstraint constraint) { 2277 RETURN_ON_NULL(image); 2278 if (!fillable(dst) || !fillable(src)) { 2279 return; 2280 } 2281 this->onDrawImageRect2(image, src, dst, sampling, paint, constraint); 2282 } 2283 drawImageRect(const SkImage * image,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint * paint)2284 void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, 2285 const SkSamplingOptions& sampling, const SkPaint* paint) { 2286 RETURN_ON_NULL(image); 2287 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, sampling, 2288 paint, kFast_SrcRectConstraint); 2289 } 2290 onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)2291 void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 2292 const SkPaint& paint) { 2293 auto glyphRunList = fScratchGlyphRunBuilder->blobToGlyphRunList(*blob, {x, y}); 2294 this->onDrawGlyphRunList(glyphRunList, paint); 2295 } 2296 onDrawGlyphRunList(const SkGlyphRunList & glyphRunList,const SkPaint & paint)2297 void SkCanvas::onDrawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint) { 2298 SkRect bounds = glyphRunList.sourceBounds(); 2299 if (this->internalQuickReject(bounds, paint)) { 2300 return; 2301 } 2302 auto layer = this->aboutToDraw(this, paint, &bounds); 2303 if (layer) { 2304 this->topDevice()->drawGlyphRunList(glyphRunList, layer->paint()); 2305 } 2306 } 2307 2308 // These call the (virtual) onDraw... method drawSimpleText(const void * text,size_t byteLength,SkTextEncoding encoding,SkScalar x,SkScalar y,const SkFont & font,const SkPaint & paint)2309 void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding, 2310 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) { 2311 TRACE_EVENT0("skia", TRACE_FUNC); 2312 if (byteLength) { 2313 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength)); 2314 const SkGlyphRunList& glyphRunList = 2315 fScratchGlyphRunBuilder->textToGlyphRunList( 2316 font, paint, text, byteLength, {x, y}, encoding); 2317 if (!glyphRunList.empty()) { 2318 this->onDrawGlyphRunList(glyphRunList, paint); 2319 } 2320 } 2321 } 2322 drawGlyphs(int count,const SkGlyphID * glyphs,const SkPoint * positions,const uint32_t * clusters,int textByteCount,const char * utf8text,SkPoint origin,const SkFont & font,const SkPaint & paint)2323 void SkCanvas::drawGlyphs(int count, const SkGlyphID* glyphs, const SkPoint* positions, 2324 const uint32_t* clusters, int textByteCount, const char* utf8text, 2325 SkPoint origin, const SkFont& font, const SkPaint& paint) { 2326 if (count <= 0) { return; } 2327 2328 SkGlyphRun glyphRun { 2329 font, 2330 SkMakeSpan(positions, count), 2331 SkMakeSpan(glyphs, count), 2332 SkMakeSpan(utf8text, textByteCount), 2333 SkMakeSpan(clusters, count), 2334 SkSpan<SkVector>() 2335 }; 2336 SkGlyphRunList glyphRunList { 2337 glyphRun, 2338 glyphRun.sourceBounds(paint).makeOffset(origin), 2339 origin 2340 }; 2341 this->onDrawGlyphRunList(glyphRunList, paint); 2342 } 2343 drawGlyphs(int count,const SkGlyphID glyphs[],const SkPoint positions[],SkPoint origin,const SkFont & font,const SkPaint & paint)2344 void SkCanvas::drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[], 2345 SkPoint origin, const SkFont& font, const SkPaint& paint) { 2346 if (count <= 0) { return; } 2347 2348 SkGlyphRun glyphRun { 2349 font, 2350 SkMakeSpan(positions, count), 2351 SkMakeSpan(glyphs, count), 2352 SkSpan<const char>(), 2353 SkSpan<const uint32_t>(), 2354 SkSpan<SkVector>() 2355 }; 2356 SkGlyphRunList glyphRunList { 2357 glyphRun, 2358 glyphRun.sourceBounds(paint).makeOffset(origin), 2359 origin 2360 }; 2361 this->onDrawGlyphRunList(glyphRunList, paint); 2362 } 2363 drawGlyphs(int count,const SkGlyphID glyphs[],const SkRSXform xforms[],SkPoint origin,const SkFont & font,const SkPaint & paint)2364 void SkCanvas::drawGlyphs(int count, const SkGlyphID glyphs[], const SkRSXform xforms[], 2365 SkPoint origin, const SkFont& font, const SkPaint& paint) { 2366 if (count <= 0) { return; } 2367 2368 auto [positions, rotateScales] = 2369 fScratchGlyphRunBuilder->convertRSXForm(SkMakeSpan(xforms, count)); 2370 2371 SkGlyphRun glyphRun { 2372 font, 2373 positions, 2374 SkMakeSpan(glyphs, count), 2375 SkSpan<const char>(), 2376 SkSpan<const uint32_t>(), 2377 rotateScales 2378 }; 2379 SkGlyphRunList glyphRunList { 2380 glyphRun, 2381 glyphRun.sourceBounds(paint).makeOffset(origin), 2382 origin 2383 }; 2384 this->onDrawGlyphRunList(glyphRunList, paint); 2385 } 2386 drawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)2387 void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 2388 const SkPaint& paint) { 2389 TRACE_EVENT0("skia", TRACE_FUNC); 2390 RETURN_ON_NULL(blob); 2391 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite()); 2392 2393 // Overflow if more than 2^21 glyphs stopping a buffer overflow latter in the stack. 2394 // See chromium:1080481 2395 // TODO: can consider unrolling a few at a time if this limit becomes a problem. 2396 int totalGlyphCount = 0; 2397 constexpr int kMaxGlyphCount = 1 << 21; 2398 SkTextBlob::Iter i(*blob); 2399 SkTextBlob::Iter::Run r; 2400 while (i.next(&r)) { 2401 int glyphsLeft = kMaxGlyphCount - totalGlyphCount; 2402 RETURN_ON_FALSE(r.fGlyphCount <= glyphsLeft); 2403 totalGlyphCount += r.fGlyphCount; 2404 } 2405 this->onDrawTextBlob(blob, x, y, paint); 2406 } 2407 onDrawVerticesObject(const SkVertices * vertices,SkBlendMode bmode,const SkPaint & paint)2408 void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode, 2409 const SkPaint& paint) { 2410 SkPaint simplePaint = clean_paint_for_drawVertices(paint); 2411 2412 const SkRect& bounds = vertices->bounds(); 2413 if (this->internalQuickReject(bounds, simplePaint)) { 2414 return; 2415 } 2416 2417 auto layer = this->aboutToDraw(this, simplePaint, &bounds); 2418 if (layer) { 2419 this->topDevice()->drawVertices(vertices, bmode, layer->paint()); 2420 } 2421 } 2422 drawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode bmode,const SkPaint & paint)2423 void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4], 2424 const SkPoint texCoords[4], SkBlendMode bmode, 2425 const SkPaint& paint) { 2426 TRACE_EVENT0("skia", TRACE_FUNC); 2427 if (nullptr == cubics) { 2428 return; 2429 } 2430 2431 this->onDrawPatch(cubics, colors, texCoords, bmode, paint); 2432 } 2433 onDrawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode bmode,const SkPaint & paint)2434 void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], 2435 const SkPoint texCoords[4], SkBlendMode bmode, 2436 const SkPaint& paint) { 2437 // drawPatch has the same behavior restrictions as drawVertices 2438 SkPaint simplePaint = clean_paint_for_drawVertices(paint); 2439 2440 // Since a patch is always within the convex hull of the control points, we discard it when its 2441 // bounding rectangle is completely outside the current clip. 2442 SkRect bounds; 2443 bounds.setBounds(cubics, SkPatchUtils::kNumCtrlPts); 2444 if (this->internalQuickReject(bounds, simplePaint)) { 2445 return; 2446 } 2447 2448 auto layer = this->aboutToDraw(this, simplePaint, &bounds); 2449 if (layer) { 2450 this->topDevice()->drawPatch(cubics, colors, texCoords, bmode, layer->paint()); 2451 } 2452 } 2453 drawDrawable(SkDrawable * dr,SkScalar x,SkScalar y)2454 void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) { 2455 #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK 2456 TRACE_EVENT0("skia", TRACE_FUNC); 2457 #endif 2458 RETURN_ON_NULL(dr); 2459 if (x || y) { 2460 SkMatrix matrix = SkMatrix::Translate(x, y); 2461 this->onDrawDrawable(dr, &matrix); 2462 } else { 2463 this->onDrawDrawable(dr, nullptr); 2464 } 2465 } 2466 drawDrawable(SkDrawable * dr,const SkMatrix * matrix)2467 void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) { 2468 #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK 2469 TRACE_EVENT0("skia", TRACE_FUNC); 2470 #endif 2471 RETURN_ON_NULL(dr); 2472 if (matrix && matrix->isIdentity()) { 2473 matrix = nullptr; 2474 } 2475 this->onDrawDrawable(dr, matrix); 2476 } 2477 onDrawDrawable(SkDrawable * dr,const SkMatrix * matrix)2478 void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) { 2479 // drawable bounds are no longer reliable (e.g. android displaylist) 2480 // so don't use them for quick-reject 2481 if (this->predrawNotify()) { 2482 this->topDevice()->drawDrawable(dr, matrix, this); 2483 } 2484 } 2485 onDrawAtlas2(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkBlendMode bmode,const SkSamplingOptions & sampling,const SkRect * cull,const SkPaint * paint)2486 void SkCanvas::onDrawAtlas2(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], 2487 const SkColor colors[], int count, SkBlendMode bmode, 2488 const SkSamplingOptions& sampling, const SkRect* cull, 2489 const SkPaint* paint) { 2490 // drawAtlas is a combination of drawVertices and drawImage... 2491 SkPaint realPaint = clean_paint_for_drawVertices(clean_paint_for_drawImage(paint)); 2492 realPaint.setShader(atlas->makeShader(sampling)); 2493 2494 if (cull && this->internalQuickReject(*cull, realPaint)) { 2495 return; 2496 } 2497 2498 auto layer = this->aboutToDraw(this, realPaint); 2499 if (layer) { 2500 this->topDevice()->drawAtlas(xform, tex, colors, count, bmode, layer->paint()); 2501 } 2502 } 2503 onDrawAnnotation(const SkRect & rect,const char key[],SkData * value)2504 void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) { 2505 SkASSERT(key); 2506 2507 if (this->predrawNotify()) { 2508 this->topDevice()->drawAnnotation(rect, key, value); 2509 } 2510 } 2511 onDrawEdgeAAQuad(const SkRect & r,const SkPoint clip[4],QuadAAFlags edgeAA,const SkColor4f & color,SkBlendMode mode)2512 void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA, 2513 const SkColor4f& color, SkBlendMode mode) { 2514 SkASSERT(r.isSorted()); 2515 2516 SkPaint paint{color}; 2517 paint.setBlendMode(mode); 2518 if (this->internalQuickReject(r, paint)) { 2519 return; 2520 } 2521 2522 if (this->predrawNotify()) { 2523 this->topDevice()->drawEdgeAAQuad(r, clip, edgeAA, color, mode); 2524 } 2525 } 2526 onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[],int count,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)2527 void SkCanvas::onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[], int count, 2528 const SkPoint dstClips[], const SkMatrix preViewMatrices[], 2529 const SkSamplingOptions& sampling, const SkPaint* paint, 2530 SrcRectConstraint constraint) { 2531 if (count <= 0) { 2532 // Nothing to draw 2533 return; 2534 } 2535 2536 SkPaint realPaint = clean_paint_for_drawImage(paint); 2537 2538 // We could calculate the set's dstRect union to always check quickReject(), but we can't reject 2539 // individual entries and Chromium's occlusion culling already makes it likely that at least one 2540 // entry will be visible. So, we only calculate the draw bounds when it's trivial (count == 1), 2541 // or we need it for the autolooper (since it greatly improves image filter perf). 2542 bool needsAutoLayer = SkToBool(realPaint.getImageFilter()); 2543 bool setBoundsValid = count == 1 || needsAutoLayer; 2544 SkRect setBounds = imageSet[0].fDstRect; 2545 if (imageSet[0].fMatrixIndex >= 0) { 2546 // Account for the per-entry transform that is applied prior to the CTM when drawing 2547 preViewMatrices[imageSet[0].fMatrixIndex].mapRect(&setBounds); 2548 } 2549 if (needsAutoLayer) { 2550 for (int i = 1; i < count; ++i) { 2551 SkRect entryBounds = imageSet[i].fDstRect; 2552 if (imageSet[i].fMatrixIndex >= 0) { 2553 preViewMatrices[imageSet[i].fMatrixIndex].mapRect(&entryBounds); 2554 } 2555 setBounds.joinPossiblyEmptyRect(entryBounds); 2556 } 2557 } 2558 2559 // If we happen to have the draw bounds, though, might as well check quickReject(). 2560 if (setBoundsValid && this->internalQuickReject(setBounds, realPaint)) { 2561 return; 2562 } 2563 2564 auto layer = this->aboutToDraw(this, realPaint, setBoundsValid ? &setBounds : nullptr); 2565 if (layer) { 2566 this->topDevice()->drawEdgeAAImageSet(imageSet, count, dstClips, preViewMatrices, sampling, 2567 layer->paint(), constraint); 2568 } 2569 } 2570 2571 ////////////////////////////////////////////////////////////////////////////// 2572 // These methods are NOT virtual, and therefore must call back into virtual 2573 // methods, rather than actually drawing themselves. 2574 ////////////////////////////////////////////////////////////////////////////// 2575 drawColor(const SkColor4f & c,SkBlendMode mode)2576 void SkCanvas::drawColor(const SkColor4f& c, SkBlendMode mode) { 2577 SkPaint paint; 2578 paint.setColor(c); 2579 paint.setBlendMode(mode); 2580 this->drawPaint(paint); 2581 } 2582 drawPoint(SkScalar x,SkScalar y,const SkPaint & paint)2583 void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 2584 const SkPoint pt = { x, y }; 2585 this->drawPoints(kPoints_PointMode, 1, &pt, paint); 2586 } 2587 drawLine(SkScalar x0,SkScalar y0,SkScalar x1,SkScalar y1,const SkPaint & paint)2588 void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) { 2589 SkPoint pts[2]; 2590 pts[0].set(x0, y0); 2591 pts[1].set(x1, y1); 2592 this->drawPoints(kLines_PointMode, 2, pts, paint); 2593 } 2594 drawCircle(SkScalar cx,SkScalar cy,SkScalar radius,const SkPaint & paint)2595 void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) { 2596 if (radius < 0) { 2597 radius = 0; 2598 } 2599 2600 SkRect r; 2601 r.setLTRB(cx - radius, cy - radius, cx + radius, cy + radius); 2602 this->drawOval(r, paint); 2603 } 2604 drawRoundRect(const SkRect & r,SkScalar rx,SkScalar ry,const SkPaint & paint)2605 void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 2606 const SkPaint& paint) { 2607 if (rx > 0 && ry > 0) { 2608 SkRRect rrect; 2609 rrect.setRectXY(r, rx, ry); 2610 this->drawRRect(rrect, paint); 2611 } else { 2612 this->drawRect(r, paint); 2613 } 2614 } 2615 drawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)2616 void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 2617 SkScalar sweepAngle, bool useCenter, 2618 const SkPaint& paint) { 2619 TRACE_EVENT0("skia", TRACE_FUNC); 2620 if (oval.isEmpty() || !sweepAngle) { 2621 return; 2622 } 2623 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint); 2624 } 2625 2626 /////////////////////////////////////////////////////////////////////////////// 2627 #ifdef SK_DISABLE_SKPICTURE drawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2628 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {} 2629 2630 onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2631 void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, 2632 const SkPaint* paint) {} 2633 #else 2634 drawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2635 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) { 2636 TRACE_EVENT0("skia", TRACE_FUNC); 2637 RETURN_ON_NULL(picture); 2638 2639 if (matrix && matrix->isIdentity()) { 2640 matrix = nullptr; 2641 } 2642 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) { 2643 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); 2644 picture->playback(this); 2645 } else { 2646 this->onDrawPicture(picture, matrix, paint); 2647 } 2648 } 2649 onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2650 void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, 2651 const SkPaint* paint) { 2652 if (this->internalQuickReject(picture->cullRect(), paint ? *paint : SkPaint{}, matrix)) { 2653 return; 2654 } 2655 2656 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); 2657 picture->playback(this); 2658 } 2659 #endif 2660 2661 /////////////////////////////////////////////////////////////////////////////// 2662 2663 SkCanvas::ImageSetEntry::ImageSetEntry() = default; 2664 SkCanvas::ImageSetEntry::~ImageSetEntry() = default; 2665 SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default; 2666 SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default; 2667 ImageSetEntry(sk_sp<const SkImage> image,const SkRect & srcRect,const SkRect & dstRect,int matrixIndex,float alpha,unsigned aaFlags,bool hasClip)2668 SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect, 2669 const SkRect& dstRect, int matrixIndex, float alpha, 2670 unsigned aaFlags, bool hasClip) 2671 : fImage(std::move(image)) 2672 , fSrcRect(srcRect) 2673 , fDstRect(dstRect) 2674 , fMatrixIndex(matrixIndex) 2675 , fAlpha(alpha) 2676 , fAAFlags(aaFlags) 2677 , fHasClip(hasClip) {} 2678 ImageSetEntry(sk_sp<const SkImage> image,const SkRect & srcRect,const SkRect & dstRect,float alpha,unsigned aaFlags)2679 SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect, 2680 const SkRect& dstRect, float alpha, unsigned aaFlags) 2681 : fImage(std::move(image)) 2682 , fSrcRect(srcRect) 2683 , fDstRect(dstRect) 2684 , fAlpha(alpha) 2685 , fAAFlags(aaFlags) {} 2686 2687 /////////////////////////////////////////////////////////////////////////////// 2688 MakeRasterDirect(const SkImageInfo & info,void * pixels,size_t rowBytes,const SkSurfaceProps * props)2689 std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels, 2690 size_t rowBytes, const SkSurfaceProps* props) { 2691 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) { 2692 return nullptr; 2693 } 2694 2695 SkBitmap bitmap; 2696 if (!bitmap.installPixels(info, pixels, rowBytes)) { 2697 return nullptr; 2698 } 2699 2700 return props ? 2701 std::make_unique<SkCanvas>(bitmap, *props) : 2702 std::make_unique<SkCanvas>(bitmap); 2703 } 2704 2705 /////////////////////////////////////////////////////////////////////////////// 2706 SkNoDrawCanvas(int width,int height)2707 SkNoDrawCanvas::SkNoDrawCanvas(int width, int height) 2708 : INHERITED(SkIRect::MakeWH(width, height)) {} 2709 SkNoDrawCanvas(const SkIRect & bounds)2710 SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds) 2711 : INHERITED(bounds) {} 2712 SkNoDrawCanvas(sk_sp<SkBaseDevice> device)2713 SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device) 2714 : INHERITED(device) {} 2715 getSaveLayerStrategy(const SaveLayerRec & rec)2716 SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) { 2717 (void)this->INHERITED::getSaveLayerStrategy(rec); 2718 return kNoLayer_SaveLayerStrategy; 2719 } 2720 onDoSaveBehind(const SkRect *)2721 bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) { 2722 return false; 2723 } 2724 2725 /////////////////////////////////////////////////////////////////////////////// 2726 2727 static_assert((int)SkRegion::kDifference_Op == (int)SkClipOp::kDifference, ""); 2728 static_assert((int)SkRegion::kIntersect_Op == (int)SkClipOp::kIntersect, ""); 2729 2730 /////////////////////////////////////////////////////////////////////////////////////////////////// 2731 accessTopRasterHandle() const2732 SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const { 2733 const SkBaseDevice* dev = this->topDevice(); 2734 if (fAllocator) { 2735 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle(); 2736 SkIRect clip = dev->devClipBounds(); 2737 if (!clip.intersect({0, 0, dev->width(), dev->height()})) { 2738 clip.setEmpty(); 2739 } 2740 2741 fAllocator->updateHandle(handle, dev->localToDevice(), clip); 2742 return handle; 2743 } 2744 return nullptr; 2745 } 2746 install(SkBitmap * bm,const SkImageInfo & info,const SkRasterHandleAllocator::Rec & rec)2747 static bool install(SkBitmap* bm, const SkImageInfo& info, 2748 const SkRasterHandleAllocator::Rec& rec) { 2749 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx); 2750 } 2751 allocBitmap(const SkImageInfo & info,SkBitmap * bm)2752 SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info, 2753 SkBitmap* bm) { 2754 SkRasterHandleAllocator::Rec rec; 2755 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) { 2756 return nullptr; 2757 } 2758 return rec.fHandle; 2759 } 2760 2761 std::unique_ptr<SkCanvas> MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,const SkImageInfo & info,const Rec * rec)2762 SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc, 2763 const SkImageInfo& info, const Rec* rec) { 2764 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) { 2765 return nullptr; 2766 } 2767 2768 SkBitmap bm; 2769 Handle hndl; 2770 2771 if (rec) { 2772 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr; 2773 } else { 2774 hndl = alloc->allocBitmap(info, &bm); 2775 } 2776 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr; 2777 } 2778 2779 /////////////////////////////////////////////////////////////////////////////////////////////////// 2780