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