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