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