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/private/SkNx.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/SkMakeUnique.h"
35 #include "src/core/SkMatrixUtils.h"
36 #include "src/core/SkPaintPriv.h"
37 #include "src/core/SkRasterClip.h"
38 #include "src/core/SkSpecialImage.h"
39 #include "src/core/SkStrikeCache.h"
40 #include "src/core/SkTLazy.h"
41 #include "src/core/SkTextFormatParams.h"
42 #include "src/core/SkTraceEvent.h"
43 #include "src/image/SkImage_Base.h"
44 #include "src/image/SkSurface_Base.h"
45 #include "src/utils/SkPatchUtils.h"
46 
47 #include <new>
48 
49 #if SK_SUPPORT_GPU
50 #include "include/gpu/GrContext.h"
51 #include "src/gpu/SkGr.h"
52 #endif
53 
54 #define RETURN_ON_NULL(ptr)     do { if (nullptr == (ptr)) return; } while (0)
55 #define RETURN_ON_FALSE(pred)   do { if (!(pred)) return; } while (0)
56 
57 ///////////////////////////////////////////////////////////////////////////////////////////////////
58 
59 /*
60  *  Return true if the drawing this rect would hit every pixels in the canvas.
61  *
62  *  Returns false if
63  *  - rect does not contain the canvas' bounds
64  *  - paint is not fill
65  *  - paint would blur or otherwise change the coverage of the rect
66  */
wouldOverwriteEntireSurface(const SkRect * rect,const SkPaint * paint,ShaderOverrideOpacity overrideOpacity) const67 bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
68                                            ShaderOverrideOpacity overrideOpacity) const {
69     static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
70                   (int)kNone_ShaderOverrideOpacity,
71                   "need_matching_enums0");
72     static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
73                   (int)kOpaque_ShaderOverrideOpacity,
74                   "need_matching_enums1");
75     static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
76                   (int)kNotOpaque_ShaderOverrideOpacity,
77                   "need_matching_enums2");
78 
79     const SkISize size = this->getBaseLayerSize();
80     const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
81 
82     // if we're clipped at all, we can't overwrite the entire surface
83     {
84         SkBaseDevice* base = this->getDevice();
85         SkBaseDevice* top = this->getTopDevice();
86         if (base != top) {
87             return false;   // we're in a saveLayer, so conservatively don't assume we'll overwrite
88         }
89         if (!base->clipIsWideOpen()) {
90             return false;
91         }
92     }
93 
94     if (rect) {
95         if (!this->getTotalMatrix().isScaleTranslate()) {
96             return false; // conservative
97         }
98 
99         SkRect devRect;
100         this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
101         if (!devRect.contains(bounds)) {
102             return false;
103         }
104     }
105 
106     if (paint) {
107         SkPaint::Style paintStyle = paint->getStyle();
108         if (!(paintStyle == SkPaint::kFill_Style ||
109               paintStyle == SkPaint::kStrokeAndFill_Style)) {
110             return false;
111         }
112         if (paint->getMaskFilter() || paint->getPathEffect() || paint->getImageFilter()) {
113             return false; // conservative
114         }
115     }
116     return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
117 }
118 
119 ///////////////////////////////////////////////////////////////////////////////////////////////////
120 
121 // experimental for faster tiled drawing...
122 //#define SK_TRACE_SAVERESTORE
123 
124 #ifdef SK_TRACE_SAVERESTORE
125     static int gLayerCounter;
inc_layer()126     static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
dec_layer()127     static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
128 
129     static int gRecCounter;
inc_rec()130     static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
dec_rec()131     static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
132 
133     static int gCanvasCounter;
inc_canvas()134     static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
dec_canvas()135     static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
136 #else
137     #define inc_layer()
138     #define dec_layer()
139     #define inc_rec()
140     #define dec_rec()
141     #define inc_canvas()
142     #define dec_canvas()
143 #endif
144 
145 typedef SkTLazy<SkPaint> SkLazyPaint;
146 
predrawNotify(bool willOverwritesEntireSurface)147 void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
148     if (fSurfaceBase) {
149         fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
150                                   ? SkSurface::kDiscard_ContentChangeMode
151                                   : SkSurface::kRetain_ContentChangeMode);
152     }
153 }
154 
predrawNotify(const SkRect * rect,const SkPaint * paint,ShaderOverrideOpacity overrideOpacity)155 void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
156                              ShaderOverrideOpacity overrideOpacity) {
157     if (fSurfaceBase) {
158         SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
159         // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
160         // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
161         // and therefore we don't care which mode we're in.
162         //
163         if (fSurfaceBase->outstandingImageSnapshot()) {
164             if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
165                 mode = SkSurface::kDiscard_ContentChangeMode;
166             }
167         }
168         fSurfaceBase->aboutToDraw(mode);
169     }
170 }
171 
172 ///////////////////////////////////////////////////////////////////////////////
173 
174 /*  This is the record we keep for each SkBaseDevice that the user installs.
175     The clip/matrix/proc are fields that reflect the top of the save/restore
176     stack. Whenever the canvas changes, it marks a dirty flag, and then before
177     these are used (assuming we're not on a layer) we rebuild these cache
178     values: they reflect the top of the save stack, but translated and clipped
179     by the device's XY offset and bitmap-bounds.
180 */
181 struct DeviceCM {
182     DeviceCM*                      fNext;
183     sk_sp<SkBaseDevice>            fDevice;
184     SkRasterClip                   fClip;
185     std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
186     SkMatrix                       fStashedMatrix; // original CTM; used by imagefilter in saveLayer
187     sk_sp<SkImage>                 fClipImage;
188     SkMatrix                       fClipMatrix;
189 
DeviceCMDeviceCM190     DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
191              const SkImage* clipImage, const SkMatrix* clipMatrix)
192         : fNext(nullptr)
193         , fDevice(std::move(device))
194         , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
195         , fStashedMatrix(stashed)
196         , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
197         , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
198     {}
199 
resetDeviceCM200     void reset(const SkIRect& bounds) {
201         SkASSERT(!fPaint);
202         SkASSERT(!fNext);
203         SkASSERT(fDevice);
204         fClip.setRect(bounds);
205     }
206 };
207 
208 namespace {
209 // Encapsulate state needed to restore from saveBehind()
210 struct BackImage {
211     sk_sp<SkSpecialImage> fImage;
212     SkIPoint              fLoc;
213 };
214 }
215 
216 /*  This is the record we keep for each save/restore level in the stack.
217     Since a level optionally copies the matrix and/or stack, we have pointers
218     for these fields. If the value is copied for this level, the copy is
219     stored in the ...Storage field, and the pointer points to that. If the
220     value is not copied for this level, we ignore ...Storage, and just point
221     at the corresponding value in the previous level in the stack.
222 */
223 class SkCanvas::MCRec {
224 public:
225     DeviceCM* fLayer;
226     /*  If there are any layers in the stack, this points to the top-most
227         one that is at or below this level in the stack (so we know what
228         bitmap/device to draw into from this level. This value is NOT
229         reference counted, since the real owner is either our fLayer field,
230         or a previous one in a lower level.)
231     */
232     DeviceCM* fTopLayer;
233     std::unique_ptr<BackImage> fBackImage;
234     SkConservativeClip fRasterClip;
235     SkMatrix fMatrix;
236     int fDeferredSaveCount;
237 
MCRec()238     MCRec() {
239         fLayer      = nullptr;
240         fTopLayer   = nullptr;
241         fMatrix.reset();
242         fDeferredSaveCount = 0;
243 
244         // don't bother initializing fNext
245         inc_rec();
246     }
MCRec(const MCRec & prev)247     MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
248         fLayer = nullptr;
249         fTopLayer = prev.fTopLayer;
250         fDeferredSaveCount = 0;
251 
252         // don't bother initializing fNext
253         inc_rec();
254     }
~MCRec()255     ~MCRec() {
256         delete fLayer;
257         dec_rec();
258     }
259 
reset(const SkIRect & bounds)260     void reset(const SkIRect& bounds) {
261         SkASSERT(fLayer);
262         SkASSERT(fDeferredSaveCount == 0);
263 
264         fMatrix.reset();
265         fRasterClip.setRect(bounds);
266         fLayer->reset(bounds);
267     }
268 };
269 
270 class SkDrawIter {
271 public:
SkDrawIter(SkCanvas * canvas)272     SkDrawIter(SkCanvas* canvas)
273         : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
274     {}
275 
next()276     bool next() {
277         const DeviceCM* rec = fCurrLayer;
278         if (rec && rec->fDevice) {
279             fDevice = rec->fDevice.get();
280             fPaint  = rec->fPaint.get();
281             fCurrLayer = rec->fNext;
282             // fCurrLayer may be nullptr now
283             return true;
284         }
285         return false;
286     }
287 
getX() const288     int getX() const { return fDevice->getOrigin().x(); }
getY() const289     int getY() const { return fDevice->getOrigin().y(); }
getPaint() const290     const SkPaint* getPaint() const { return fPaint; }
291 
292     SkBaseDevice*   fDevice;
293 
294 private:
295     const DeviceCM* fCurrLayer;
296     const SkPaint*  fPaint;     // May be null.
297 };
298 
299 #define FOR_EACH_TOP_DEVICE( code )                       \
300     do {                                                  \
301         DeviceCM* layer = fMCRec->fTopLayer;              \
302         while (layer) {                                   \
303             SkBaseDevice* device = layer->fDevice.get();  \
304             if (device) {                                 \
305                 code;                                     \
306             }                                             \
307             layer = layer->fNext;                         \
308         }                                                 \
309     } while (0)
310 
311 /////////////////////////////////////////////////////////////////////////////
312 
313 /**
314  *  If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
315  *  colorfilter, else return nullptr.
316  */
image_to_color_filter(const SkPaint & paint)317 static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
318     SkImageFilter* imgf = paint.getImageFilter();
319     if (!imgf) {
320         return nullptr;
321     }
322 
323     SkColorFilter* imgCFPtr;
324     if (!imgf->asAColorFilter(&imgCFPtr)) {
325         return nullptr;
326     }
327     sk_sp<SkColorFilter> imgCF(imgCFPtr);
328 
329     SkColorFilter* paintCF = paint.getColorFilter();
330     if (nullptr == paintCF) {
331         // there is no existing paint colorfilter, so we can just return the imagefilter's
332         return imgCF;
333     }
334 
335     // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
336     // and we need to combine them into a single colorfilter.
337     return imgCF->makeComposed(sk_ref_sp(paintCF));
338 }
339 
340 /**
341  * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
342  * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
343  * outside of its raw-bounds by 1/2 the stroke width.  SkPaint has lots of optional
344  * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
345  * patheffects, stroking, etc.  This function takes a raw bounds and a paint, and returns the
346  * conservative "effective" bounds based on the settings in the paint... with one exception. This
347  * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
348  * deliberately ignored.
349  */
apply_paint_to_bounds_sans_imagefilter(const SkPaint & paint,const SkRect & rawBounds,SkRect * storage)350 static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
351                                                             const SkRect& rawBounds,
352                                                             SkRect* storage) {
353     SkPaint tmpUnfiltered(paint);
354     tmpUnfiltered.setImageFilter(nullptr);
355     if (tmpUnfiltered.canComputeFastBounds()) {
356         return tmpUnfiltered.computeFastBounds(rawBounds, storage);
357     } else {
358         return rawBounds;
359     }
360 }
361 
362 class AutoLayerForImageFilter {
363 public:
364     // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
365     // paint. It's used to determine the size of the offscreen layer for filters.
366     // If null, the clip will be used instead.
AutoLayerForImageFilter(SkCanvas * canvas,const SkPaint & origPaint,bool skipLayerForImageFilter=false,const SkRect * rawBounds=nullptr)367     AutoLayerForImageFilter(SkCanvas* canvas, const SkPaint& origPaint,
368                             bool skipLayerForImageFilter = false,
369                             const SkRect* rawBounds = nullptr) {
370         fCanvas = canvas;
371         fPaint = &origPaint;
372         fSaveCount = canvas->getSaveCount();
373         fTempLayerForImageFilter = false;
374 
375         if (auto simplifiedCF = image_to_color_filter(origPaint)) {
376             SkASSERT(!fLazyPaint.isValid());
377             SkPaint* paint = fLazyPaint.set(origPaint);
378             paint->setColorFilter(std::move(simplifiedCF));
379             paint->setImageFilter(nullptr);
380             fPaint = paint;
381         }
382 
383         if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
384             /**
385              *  We implement ImageFilters for a given draw by creating a layer, then applying the
386              *  imagefilter to the pixels of that layer (its backing surface/image), and then
387              *  we call restore() to xfer that layer to the main canvas.
388              *
389              *  1. SaveLayer (with a paint containing the current imagefilter and xfermode)
390              *  2. Generate the src pixels:
391              *      Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
392              *      return (fPaint). We then draw the primitive (using srcover) into a cleared
393              *      buffer/surface.
394              *  3. Restore the layer created in #1
395              *      The imagefilter is passed the buffer/surface from the layer (now filled with the
396              *      src pixels of the primitive). It returns a new "filtered" buffer, which we
397              *      draw onto the previous layer using the xfermode from the original paint.
398              */
399 
400             SkPaint restorePaint;
401             restorePaint.setImageFilter(fPaint->refImageFilter());
402             restorePaint.setBlendMode(fPaint->getBlendMode());
403 
404             SkRect storage;
405             if (rawBounds) {
406                 // Make rawBounds include all paint outsets except for those due to image filters.
407                 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
408             }
409             (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &restorePaint),
410                                             SkCanvas::kFullLayer_SaveLayerStrategy);
411             fTempLayerForImageFilter = true;
412 
413             // Remove the restorePaint fields from our "working" paint
414             SkASSERT(!fLazyPaint.isValid());
415             SkPaint* paint = fLazyPaint.set(origPaint);
416             paint->setImageFilter(nullptr);
417             paint->setBlendMode(SkBlendMode::kSrcOver);
418             fPaint = paint;
419         }
420     }
421 
~AutoLayerForImageFilter()422     ~AutoLayerForImageFilter() {
423         if (fTempLayerForImageFilter) {
424             fCanvas->internalRestore();
425         }
426         SkASSERT(fCanvas->getSaveCount() == fSaveCount);
427     }
428 
paint() const429     const SkPaint& paint() const {
430         SkASSERT(fPaint);
431         return *fPaint;
432     }
433 
434 private:
435     SkLazyPaint     fLazyPaint; // base paint storage in case we need to modify it
436     SkCanvas*       fCanvas;
437     const SkPaint*  fPaint;     // points to either the original paint, or lazy (if we needed it)
438     int             fSaveCount;
439     bool            fTempLayerForImageFilter;
440 };
441 
442 ////////// macros to place around the internal draw calls //////////////////
443 
444 #define DRAW_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds)    \
445     this->predrawNotify();                                          \
446     AutoLayerForImageFilter draw(this, paint, skipLayerForFilter, bounds); \
447     {   SkDrawIter iter(this);
448 
449 
450 #define DRAW_BEGIN_DRAWDEVICE(paint)                                \
451     this->predrawNotify();                                          \
452     AutoLayerForImageFilter draw(this, paint, true);                \
453     {   SkDrawIter iter(this);
454 
455 #define DRAW_BEGIN(paint, bounds)                                   \
456     this->predrawNotify();                                          \
457     AutoLayerForImageFilter draw(this, paint, false, bounds);       \
458     {   SkDrawIter iter(this);
459 
460 #define DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque)  \
461     this->predrawNotify(bounds, &paint, auxOpaque);                 \
462     AutoLayerForImageFilter draw(this, paint, false, bounds);       \
463     {   SkDrawIter iter(this);
464 
465 #define DRAW_END    }
466 
467 ////////////////////////////////////////////////////////////////////////////
468 
qr_clip_bounds(const SkIRect & bounds)469 static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
470     if (bounds.isEmpty()) {
471         return SkRect::MakeEmpty();
472     }
473 
474     // Expand bounds out by 1 in case we are anti-aliasing.  We store the
475     // bounds as floats to enable a faster quick reject implementation.
476     SkRect dst;
477     SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
478     return dst;
479 }
480 
resetForNextPicture(const SkIRect & bounds)481 void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
482     this->restoreToCount(1);
483     fMCRec->reset(bounds);
484 
485     // We're peering through a lot of structs here.  Only at this scope do we
486     // know that the device is a SkNoPixelsDevice.
487     static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
488     fDeviceClipBounds = qr_clip_bounds(bounds);
489     fIsScaleTranslate = true;
490 }
491 
init(sk_sp<SkBaseDevice> device)492 void SkCanvas::init(sk_sp<SkBaseDevice> device) {
493     fAllowSimplifyClip = false;
494     fSaveCount = 1;
495 
496     fMCRec = (MCRec*)fMCStack.push_back();
497     new (fMCRec) MCRec;
498     fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
499     fIsScaleTranslate = true;
500 
501     SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
502     fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
503     new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
504 
505     fMCRec->fTopLayer = fMCRec->fLayer;
506 
507     fSurfaceBase = nullptr;
508 
509     if (device) {
510         // The root device and the canvas should always have the same pixel geometry
511         SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
512         fMCRec->fRasterClip.setRect(device->getGlobalBounds());
513         fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
514 
515         device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
516     }
517 
518     fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
519 }
520 
SkCanvas()521 SkCanvas::SkCanvas()
522     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
523     , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
524 {
525     inc_canvas();
526 
527     this->init(nullptr);
528 }
529 
SkCanvas(int width,int height,const SkSurfaceProps * props)530 SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
531     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
532     , fProps(SkSurfacePropsCopyOrDefault(props))
533 {
534     inc_canvas();
535     this->init(sk_make_sp<SkNoPixelsDevice>(
536             SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps));
537 }
538 
SkCanvas(const SkIRect & bounds)539 SkCanvas::SkCanvas(const SkIRect& bounds)
540     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
541     , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
542 {
543     inc_canvas();
544 
545     SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
546     this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
547 }
548 
SkCanvas(sk_sp<SkBaseDevice> device)549 SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
550     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
551     , fProps(device->surfaceProps())
552 {
553     inc_canvas();
554 
555     this->init(device);
556 }
557 
SkCanvas(const SkBitmap & bitmap,const SkSurfaceProps & props)558 SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
559     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
560     , fProps(props)
561 {
562     inc_canvas();
563 
564     sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
565     this->init(device);
566 }
567 
SkCanvas(const SkBitmap & bitmap,std::unique_ptr<SkRasterHandleAllocator> alloc,SkRasterHandleAllocator::Handle hndl)568 SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
569                    SkRasterHandleAllocator::Handle hndl)
570     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
571     , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
572     , fAllocator(std::move(alloc))
573 {
574     inc_canvas();
575 
576     sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
577     this->init(device);
578 }
579 
SkCanvas(const SkBitmap & bitmap)580 SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
581 
582 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
SkCanvas(const SkBitmap & bitmap,ColorBehavior)583 SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
584     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
585     , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
586     , fAllocator(nullptr)
587 {
588     inc_canvas();
589 
590     SkBitmap tmp(bitmap);
591     *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
592     sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
593     this->init(device);
594 }
595 #endif
596 
~SkCanvas()597 SkCanvas::~SkCanvas() {
598     // free up the contents of our deque
599     this->restoreToCount(1);    // restore everything but the last
600 
601     this->internalRestore();    // restore the last, since we're going away
602 
603     dec_canvas();
604 }
605 
606 ///////////////////////////////////////////////////////////////////////////////
607 
flush()608 void SkCanvas::flush() {
609     this->onFlush();
610 }
611 
onFlush()612 void SkCanvas::onFlush() {
613     SkBaseDevice* device = this->getDevice();
614     if (device) {
615         device->flush();
616     }
617 }
618 
getBaseLayerSize() const619 SkISize SkCanvas::getBaseLayerSize() const {
620     SkBaseDevice* d = this->getDevice();
621     return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
622 }
623 
getTopLayerBounds() const624 SkIRect SkCanvas::getTopLayerBounds() const {
625     SkBaseDevice* d = this->getTopDevice();
626     if (!d) {
627         return SkIRect::MakeEmpty();
628     }
629     return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
630 }
631 
getDevice() const632 SkBaseDevice* SkCanvas::getDevice() const {
633     // return root device
634     MCRec* rec = (MCRec*) fMCStack.front();
635     SkASSERT(rec && rec->fLayer);
636     return rec->fLayer->fDevice.get();
637 }
638 
getTopDevice() const639 SkBaseDevice* SkCanvas::getTopDevice() const {
640     return fMCRec->fTopLayer->fDevice.get();
641 }
642 
readPixels(const SkPixmap & pm,int x,int y)643 bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
644     SkBaseDevice* device = this->getDevice();
645     return device && pm.addr() && device->readPixels(pm, x, y);
646 }
647 
readPixels(const SkImageInfo & dstInfo,void * dstP,size_t rowBytes,int x,int y)648 bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
649     return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
650 }
651 
readPixels(const SkBitmap & bm,int x,int y)652 bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
653     SkPixmap pm;
654     return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
655 }
656 
writePixels(const SkBitmap & bitmap,int x,int y)657 bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
658     SkPixmap pm;
659     if (bitmap.peekPixels(&pm)) {
660         return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
661     }
662     return false;
663 }
664 
writePixels(const SkImageInfo & srcInfo,const void * pixels,size_t rowBytes,int x,int y)665 bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
666                            int x, int y) {
667     SkBaseDevice* device = this->getDevice();
668     if (!device) {
669         return false;
670     }
671 
672     // This check gives us an early out and prevents generation ID churn on the surface.
673     // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
674     SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
675     if (!srcRect.intersect({0, 0, device->width(), device->height()})) {
676         return false;
677     }
678 
679     // Tell our owning surface to bump its generation ID.
680     const bool completeOverwrite =
681             srcRect.size() == SkISize::Make(device->width(), device->height());
682     this->predrawNotify(completeOverwrite);
683 
684     // This can still fail, most notably in the case of a invalid color type or alpha type
685     // conversion.  We could pull those checks into this function and avoid the unnecessary
686     // generation ID bump.  But then we would be performing those checks twice, since they
687     // are also necessary at the bitmap/pixmap entry points.
688     return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
689 }
690 
691 //////////////////////////////////////////////////////////////////////////////
692 
checkForDeferredSave()693 void SkCanvas::checkForDeferredSave() {
694     if (fMCRec->fDeferredSaveCount > 0) {
695         this->doSave();
696     }
697 }
698 
getSaveCount() const699 int SkCanvas::getSaveCount() const {
700 #ifdef SK_DEBUG
701     int count = 0;
702     SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
703     for (;;) {
704         const MCRec* rec = (const MCRec*)iter.next();
705         if (!rec) {
706             break;
707         }
708         count += 1 + rec->fDeferredSaveCount;
709     }
710     SkASSERT(count == fSaveCount);
711 #endif
712     return fSaveCount;
713 }
714 
save()715 int SkCanvas::save() {
716     fSaveCount += 1;
717     fMCRec->fDeferredSaveCount += 1;
718     return this->getSaveCount() - 1;  // return our prev value
719 }
720 
doSave()721 void SkCanvas::doSave() {
722     this->willSave();
723 
724     SkASSERT(fMCRec->fDeferredSaveCount > 0);
725     fMCRec->fDeferredSaveCount -= 1;
726     this->internalSave();
727 }
728 
restore()729 void SkCanvas::restore() {
730     if (fMCRec->fDeferredSaveCount > 0) {
731         SkASSERT(fSaveCount > 1);
732         fSaveCount -= 1;
733         fMCRec->fDeferredSaveCount -= 1;
734     } else {
735         // check for underflow
736         if (fMCStack.count() > 1) {
737             this->willRestore();
738             SkASSERT(fSaveCount > 1);
739             fSaveCount -= 1;
740             this->internalRestore();
741             this->didRestore();
742         }
743     }
744 }
745 
restoreToCount(int count)746 void SkCanvas::restoreToCount(int count) {
747     // sanity check
748     if (count < 1) {
749         count = 1;
750     }
751 
752     int n = this->getSaveCount() - count;
753     for (int i = 0; i < n; ++i) {
754         this->restore();
755     }
756 }
757 
internalSave()758 void SkCanvas::internalSave() {
759     MCRec* newTop = (MCRec*)fMCStack.push_back();
760     new (newTop) MCRec(*fMCRec);    // balanced in restore()
761     fMCRec = newTop;
762 
763     FOR_EACH_TOP_DEVICE(device->save());
764 }
765 
BoundsAffectsClip(SaveLayerFlags saveLayerFlags)766 bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
767     return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
768 }
769 
clipRectBounds(const SkRect * bounds,SaveLayerFlags saveLayerFlags,SkIRect * intersection,const SkImageFilter * imageFilter)770 bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
771                               SkIRect* intersection, const SkImageFilter* imageFilter) {
772     // clipRectBounds() is called to determine the input layer size needed for a given image filter.
773     // The coordinate space of the rectangle passed to filterBounds(kReverse) is meant to be in the
774     // filtering layer space. Here, 'clipBounds' is always in the true device space. When an image
775     // filter does not require a decomposed CTM matrix, the filter space and device space are the
776     // same. When it has been decomposed, we want the original image filter node to process the
777     // bounds in the layer space represented by the decomposed scale matrix. 'imageFilter' is no
778     // longer the original filter, but has the remainder matrix baked into it, and passing in the
779     // the true device clip bounds ensures that the matrix image filter provides a layer clip bounds
780     // to the original filter node (barring inflation from consecutive calls to mapRect). While
781     // initially counter-intuitive given the apparent inconsistency of coordinate spaces, always
782     // passing getDeviceClipBounds() to 'imageFilter' is correct.
783     // FIXME (michaelludwig) - When the remainder matrix is instead applied as a final draw, it will
784     // be important to more accurately calculate the clip bounds in the layer space for the original
785     // image filter (similar to how matrix image filter does it, but ideally without the inflation).
786     SkIRect clipBounds = this->getDeviceClipBounds();
787     if (clipBounds.isEmpty()) {
788         return false;
789     }
790 
791     const SkMatrix& ctm = fMCRec->fMatrix;  // this->getTotalMatrix()
792 
793     if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
794         // If the image filter DAG affects transparent black then we will need to render
795         // out to the clip bounds
796         bounds = nullptr;
797     }
798 
799     SkIRect inputSaveLayerBounds;
800     if (bounds) {
801         SkRect r;
802         ctm.mapRect(&r, *bounds);
803         r.roundOut(&inputSaveLayerBounds);
804     } else {    // no user bounds, so just use the clip
805         inputSaveLayerBounds = clipBounds;
806     }
807 
808     if (imageFilter) {
809         // expand the clip bounds by the image filter DAG to include extra content that might
810         // be required by the image filters.
811         clipBounds = imageFilter->filterBounds(clipBounds, ctm,
812                                                SkImageFilter::kReverse_MapDirection,
813                                                &inputSaveLayerBounds);
814     }
815 
816     SkIRect clippedSaveLayerBounds;
817     if (bounds) {
818         // For better or for worse, user bounds currently act as a hard clip on the layer's
819         // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
820         clippedSaveLayerBounds = inputSaveLayerBounds;
821     } else {
822         // If there are no user bounds, we don't want to artificially restrict the resulting
823         // layer bounds, so allow the expanded clip bounds free reign.
824         clippedSaveLayerBounds = clipBounds;
825     }
826 
827     // early exit if the layer's bounds are clipped out
828     if (!clippedSaveLayerBounds.intersect(clipBounds)) {
829         if (BoundsAffectsClip(saveLayerFlags)) {
830             fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
831             fMCRec->fRasterClip.setEmpty();
832             fDeviceClipBounds.setEmpty();
833         }
834         return false;
835     }
836     SkASSERT(!clippedSaveLayerBounds.isEmpty());
837 
838     if (BoundsAffectsClip(saveLayerFlags)) {
839         // Simplify the current clips since they will be applied properly during restore()
840         fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
841         fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
842     }
843 
844     if (intersection) {
845         *intersection = clippedSaveLayerBounds;
846     }
847 
848     return true;
849 }
850 
saveLayer(const SkRect * bounds,const SkPaint * paint)851 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
852     return this->saveLayer(SaveLayerRec(bounds, paint, 0));
853 }
854 
saveLayer(const SaveLayerRec & rec)855 int SkCanvas::saveLayer(const SaveLayerRec& rec) {
856     TRACE_EVENT0("skia", TRACE_FUNC);
857     if (rec.fPaint && rec.fPaint->nothingToDraw()) {
858         // no need for the layer (or any of the draws until the matching restore()
859         this->save();
860         this->clipRect({0,0,0,0});
861     } else {
862         SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
863         fSaveCount += 1;
864         this->internalSaveLayer(rec, strategy);
865     }
866     return this->getSaveCount() - 1;
867 }
868 
only_axis_aligned_saveBehind(const SkRect * bounds)869 int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
870     if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
871         // Assuming clips never expand, if the request bounds is outside of the current clip
872         // there is no need to copy/restore the area, so just devolve back to a regular save.
873         this->save();
874     } else {
875         bool doTheWork = this->onDoSaveBehind(bounds);
876         fSaveCount += 1;
877         this->internalSave();
878         if (doTheWork) {
879             this->internalSaveBehind(bounds);
880         }
881     }
882     return this->getSaveCount() - 1;
883 }
884 
DrawDeviceWithFilter(SkBaseDevice * src,const SkImageFilter * filter,SkBaseDevice * dst,const SkIPoint & dstOrigin,const SkMatrix & ctm)885 void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
886                                     SkBaseDevice* dst, const SkIPoint& dstOrigin,
887                                     const SkMatrix& ctm) {
888     // The local bounds of the src device; all the bounds passed to snapSpecial must be intersected
889     // with this rect.
890     const SkIRect srcDevRect = SkIRect::MakeWH(src->width(), src->height());
891 
892     if (!filter) {
893         // All non-filtered devices are currently axis aligned, so they only differ by their origin.
894         // This means that we only have to copy a dst-sized block of pixels out of src and translate
895         // it to the matching position relative to dst's origin.
896         SkIRect snapBounds = SkIRect::MakeXYWH(dstOrigin.x() - src->getOrigin().x(),
897                                                dstOrigin.y() - src->getOrigin().y(),
898                                                dst->width(), dst->height());
899         if (!snapBounds.intersect(srcDevRect)) {
900             return;
901         }
902 
903         auto special = src->snapSpecial(snapBounds);
904         if (special) {
905             // The image is drawn at 1-1 scale with integer translation, so no filtering is needed.
906             SkPaint p;
907             dst->drawSpecial(special.get(), 0, 0, p, nullptr, SkMatrix::I());
908         }
909         return;
910     }
911 
912     // First decompose the ctm into a post-filter transform and a filter matrix that is supported
913     // by the backdrop filter.
914     SkMatrix toRoot, layerMatrix;
915     SkSize scale;
916     if (ctm.isScaleTranslate() || as_IFB(filter)->canHandleComplexCTM()) {
917         toRoot = SkMatrix::I();
918         layerMatrix = ctm;
919     } else if (ctm.decomposeScale(&scale, &toRoot)) {
920         layerMatrix = SkMatrix::MakeScale(scale.fWidth, scale.fHeight);
921     } else {
922         // Perspective, for now, do no scaling of the layer itself.
923         // TODO (michaelludwig) - perhaps it'd be better to explore a heuristic scale pulled from
924         // the matrix, e.g. based on the midpoint of the near/far planes?
925         toRoot = ctm;
926         layerMatrix = SkMatrix::I();
927     }
928 
929     // We have to map the dst bounds from the root space into the layer space where filtering will
930     // occur. If we knew the input bounds of the content that defined the original dst bounds, we
931     // could map that forward by layerMatrix and have tighter bounds, but toRoot^-1 * dst bounds
932     // is a safe, conservative estimate.
933     SkMatrix fromRoot;
934     if (!toRoot.invert(&fromRoot)) {
935         return;
936     }
937 
938     // This represents what the backdrop filter needs to produce in the layer space, and is sized
939     // such that drawing it into dst with the toRoot transform will cover the actual dst device.
940     SkIRect layerTargetBounds = fromRoot.mapRect(
941             SkRect::MakeXYWH(dstOrigin.x(), dstOrigin.y(), dst->width(), dst->height())).roundOut();
942     // While layerTargetBounds is what needs to be output by the filter, the filtering process may
943     // require some extra input pixels.
944     SkIRect layerInputBounds = filter->filterBounds(
945             layerTargetBounds, layerMatrix, SkImageFilter::kReverse_MapDirection,
946             &layerTargetBounds);
947 
948     // Map the required input into the root space, then make relative to the src device. This will
949     // be the conservative contents required to fill a layerInputBounds-sized surface with the
950     // backdrop content (transformed back into the layer space using fromRoot).
951     SkIRect backdropBounds = toRoot.mapRect(SkRect::Make(layerInputBounds)).roundOut();
952     backdropBounds.offset(-src->getOrigin().x(), -src->getOrigin().y());
953     if (!backdropBounds.intersect(srcDevRect)) {
954         return;
955     }
956 
957     auto special = src->snapSpecial(backdropBounds);
958     if (!special) {
959         return;
960     }
961 
962     SkColorType colorType = src->imageInfo().colorType();
963     if (colorType == kUnknown_SkColorType) {
964         colorType = kRGBA_8888_SkColorType;
965     }
966     SkColorSpace* colorSpace = src->imageInfo().colorSpace();
967 
968     SkPaint p;
969     if (!toRoot.isIdentity()) {
970         // Drawing the temporary and final filtered image requires a higher filter quality if the
971         // 'toRoot' transformation is not identity, in order to minimize the impact on already
972         // rendered edges/content.
973         // TODO (michaelludwig) - Explore reducing this quality, identify visual tradeoffs
974         p.setFilterQuality(kHigh_SkFilterQuality);
975 
976         // The snapped backdrop content needs to be transformed by fromRoot into the layer space,
977         // and stored in a temporary surface, which is then used as the input to the actual filter.
978         auto tmpSurface = special->makeSurface(colorType, colorSpace, layerInputBounds.size());
979         if (!tmpSurface) {
980             return;
981         }
982 
983         auto tmpCanvas = tmpSurface->getCanvas();
984         tmpCanvas->clear(SK_ColorTRANSPARENT);
985         // Reading in reverse, this takes the backdrop bounds from src device space into the root
986         // space, then maps from root space into the layer space, then maps it so the input layer's
987         // top left corner is (0, 0). This transformation automatically accounts for any cropping
988         // performed on backdropBounds.
989         tmpCanvas->translate(-layerInputBounds.fLeft, -layerInputBounds.fTop);
990         tmpCanvas->concat(fromRoot);
991         tmpCanvas->translate(src->getOrigin().x(), src->getOrigin().y());
992 
993         tmpCanvas->drawImageRect(special->asImage(), special->subset(),
994                                  SkRect::Make(backdropBounds), &p, kStrict_SrcRectConstraint);
995         special = tmpSurface->makeImageSnapshot();
996     } else {
997         // Since there is no extra transform that was done, update the input bounds to reflect
998         // cropping of the snapped backdrop image. In this case toRoot = I, so layerInputBounds
999         // was equal to backdropBounds before it was made relative to the src device and cropped.
1000         // When we use the original snapped image directly, just map the update backdrop bounds
1001         // back into the shared layer space
1002         layerInputBounds = backdropBounds;
1003         layerInputBounds.offset(src->getOrigin().x(), src->getOrigin().y());
1004 
1005         // Similar to the unfiltered case above, when toRoot is the identity, then the final
1006         // draw will be 1-1 so there is no need to increase filter quality.
1007         p.setFilterQuality(kNone_SkFilterQuality);
1008     }
1009 
1010     // Now evaluate the filter on 'special', which contains the backdrop content mapped back into
1011     // layer space. This has to further offset everything so that filter evaluation thinks the
1012     // source image's top left corner is (0, 0).
1013     // TODO (michaelludwig) - Once image filters are robust to non-(0,0) image origins for inputs,
1014     // this can be simplified.
1015     layerTargetBounds.offset(-layerInputBounds.fLeft, -layerInputBounds.fTop);
1016     SkMatrix filterCTM = layerMatrix;
1017     filterCTM.postTranslate(-layerInputBounds.fLeft, -layerInputBounds.fTop);
1018     skif::Context ctx(filterCTM, layerTargetBounds, nullptr, colorType, colorSpace, special.get());
1019 
1020     SkIPoint offset;
1021     special = as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset);
1022     if (special) {
1023         // Draw the filtered backdrop content into the dst device. We add layerInputBounds origin
1024         // to offset because the original value in 'offset' was relative to 'filterCTM'. 'filterCTM'
1025         // had subtracted the layerInputBounds origin, so adding that back makes 'offset' relative
1026         // to 'layerMatrix' (what we need it to be when drawing the image by 'toRoot').
1027         offset += layerInputBounds.topLeft();
1028 
1029         // Manually setting the device's CTM requires accounting for the device's origin.
1030         // TODO (michaelludwig) - This could be simpler if the dst device had its origin configured
1031         // before filtering the backdrop device, and if SkAutoDeviceCTMRestore had a way to accept
1032         // a global CTM instead of a device CTM.
1033         SkMatrix dstCTM = toRoot;
1034         dstCTM.postTranslate(-dstOrigin.x(), -dstOrigin.y());
1035         SkAutoDeviceCTMRestore acr(dst, dstCTM);
1036 
1037         // And because devices don't have a special-image draw function that supports arbitrary
1038         // matrices, we are abusing the asImage() functionality here...
1039         SkRect specialSrc = SkRect::Make(special->subset());
1040         auto looseImage = special->asImage();
1041         dst->drawImageRect(
1042                 looseImage.get(), &specialSrc,
1043                 SkRect::MakeXYWH(offset.x(), offset.y(), special->width(), special->height()),
1044                 p, kStrict_SrcRectConstraint);
1045     }
1046 }
1047 
make_layer_info(const SkImageInfo & prev,int w,int h,const SkPaint * paint)1048 static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
1049     SkColorType ct = prev.colorType();
1050     if (prev.bytesPerPixel() <= 4 &&
1051         prev.colorType() != kRGBA_8888_SkColorType &&
1052         prev.colorType() != kBGRA_8888_SkColorType) {
1053         // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
1054         // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
1055         ct = kN32_SkColorType;
1056     }
1057     return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
1058 }
1059 
internalSaveLayer(const SaveLayerRec & rec,SaveLayerStrategy strategy)1060 void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1061     TRACE_EVENT0("skia", TRACE_FUNC);
1062     const SkRect* bounds = rec.fBounds;
1063     const SkPaint* paint = rec.fPaint;
1064     SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1065 
1066     // If we have a backdrop filter, then we must apply it to the entire layer (clip-bounds)
1067     // regardless of any hint-rect from the caller. skbug.com/8783
1068     if (rec.fBackdrop) {
1069         bounds = nullptr;
1070     }
1071 
1072     SkLazyPaint lazyP;
1073     SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
1074     SkMatrix stashedMatrix = fMCRec->fMatrix;
1075     MCRec* modifiedRec = nullptr;
1076 
1077     /*
1078      *  Many ImageFilters (so far) do not (on their own) correctly handle matrices (CTM) that
1079      *  contain rotation/skew/etc. We rely on applyCTM to create a new image filter DAG as needed to
1080      *  accommodate this, but it requires update the CTM we use when drawing into the layer.
1081      *
1082      *  1. Stash off the current CTM
1083      *  2. Apply the CTM to imagefilter, which decomposes it into simple and complex transforms
1084      *     if necessary.
1085      *  3. Wack the CTM to be the remaining scale matrix and use the modified imagefilter, which
1086      *     is a MatrixImageFilter that contains the complex matrix.
1087      *  4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1088      *  5. During restore, the MatrixImageFilter automatically applies complex stage to the output
1089      *     of the original imagefilter, and draw that (via drawSprite)
1090      *  6. Unwack the CTM to its original state (i.e. stashedMatrix)
1091      *
1092      *  Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1093      *  a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1094      */
1095     if (imageFilter) {
1096         SkMatrix modifiedCTM;
1097         sk_sp<SkImageFilter> modifiedFilter = as_IFB(imageFilter)->applyCTM(stashedMatrix,
1098                                                                             &modifiedCTM);
1099         if (as_IFB(modifiedFilter)->uniqueID() != as_IFB(imageFilter)->uniqueID()) {
1100             // The original filter couldn't support the CTM entirely
1101             SkASSERT(modifiedCTM.isScaleTranslate() || as_IFB(imageFilter)->canHandleComplexCTM());
1102             modifiedRec = fMCRec;
1103             this->internalSetMatrix(modifiedCTM);
1104             SkPaint* p = lazyP.set(*paint);
1105             p->setImageFilter(std::move(modifiedFilter));
1106             imageFilter = p->getImageFilter();
1107             paint = p;
1108         }
1109         // Else the filter didn't change, so modifiedCTM == stashedMatrix and there's nothing
1110         // left to do since the stack already has that as the CTM.
1111     }
1112 
1113     // do this before we create the layer. We don't call the public save() since
1114     // that would invoke a possibly overridden virtual
1115     this->internalSave();
1116 
1117     SkIRect ir;
1118     if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
1119         if (modifiedRec) {
1120             // In this case there will be no layer in which to stash the matrix so we need to
1121             // revert the prior MCRec to its earlier state.
1122             modifiedRec->fMatrix = stashedMatrix;
1123         }
1124         return;
1125     }
1126 
1127     // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1128     // the clipRectBounds() call above?
1129     if (kNoLayer_SaveLayerStrategy == strategy) {
1130         return;
1131     }
1132 
1133     SkPixelGeometry geo = fProps.pixelGeometry();
1134     if (paint) {
1135         // TODO: perhaps add a query to filters so we might preserve opaqueness...
1136         if (paint->getImageFilter() || paint->getColorFilter()) {
1137             geo = kUnknown_SkPixelGeometry;
1138         }
1139     }
1140 
1141     SkBaseDevice* priorDevice = this->getTopDevice();
1142     if (nullptr == priorDevice) {   // Do we still need this check???
1143         SkDebugf("Unable to find device for layer.");
1144         return;
1145     }
1146 
1147     SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
1148     if (rec.fSaveLayerFlags & kF16ColorType) {
1149         info = info.makeColorType(kRGBA_F16_SkColorType);
1150     }
1151 
1152     sk_sp<SkBaseDevice> newDevice;
1153     {
1154         const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
1155                                      (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
1156         const SkBaseDevice::TileUsage usage =
1157             preserveLCDText ? SkBaseDevice::kPossible_TileUsage : SkBaseDevice::kNever_TileUsage;
1158         const bool trackCoverage =
1159                 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
1160         const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
1161                                                                              trackCoverage,
1162                                                                              fAllocator.get());
1163         newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1164         if (!newDevice) {
1165             return;
1166         }
1167     }
1168     DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
1169 
1170     // only have a "next" if this new layer doesn't affect the clip (rare)
1171     layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
1172     fMCRec->fLayer = layer;
1173     fMCRec->fTopLayer = layer;    // this field is NOT an owner of layer
1174 
1175     if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
1176         DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
1177                              fMCRec->fMatrix);
1178     }
1179 
1180     newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1181 
1182     newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1183     if (layer->fNext) {
1184         // need to punch a hole in the previous device, so we don't draw there, given that
1185         // the new top-layer will allow drawing to happen "below" it.
1186         SkRegion hole(ir);
1187         do {
1188             layer = layer->fNext;
1189             layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1190         } while (layer->fNext);
1191     }
1192 }
1193 
saveLayerAlpha(const SkRect * bounds,U8CPU alpha)1194 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1195     if (0xFF == alpha) {
1196         return this->saveLayer(bounds, nullptr);
1197     } else {
1198         SkPaint tmpPaint;
1199         tmpPaint.setAlpha(alpha);
1200         return this->saveLayer(bounds, &tmpPaint);
1201     }
1202 }
1203 
internalSaveBehind(const SkRect * localBounds)1204 void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1205     SkIRect devBounds;
1206     if (localBounds) {
1207         SkRect tmp;
1208         fMCRec->fMatrix.mapRect(&tmp, *localBounds);
1209         if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
1210             devBounds.setEmpty();
1211         }
1212     } else {
1213         devBounds = this->getDeviceClipBounds();
1214     }
1215     if (devBounds.isEmpty()) {
1216         return;
1217     }
1218 
1219     SkBaseDevice* device = this->getTopDevice();
1220     if (nullptr == device) {   // Do we still need this check???
1221         return;
1222     }
1223 
1224     // need the bounds relative to the device itself
1225     devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
1226 
1227     // This is getting the special image from the current device, which is then drawn into (both by
1228     // a client, and the drawClippedToSaveBehind below). Since this is not saving a layer, with its
1229     // own device, we need to explicitly copy the back image contents so that its original content
1230     // is available when we splat it back later during restore.
1231     auto backImage = device->snapSpecial(devBounds, /* copy */ true);
1232     if (!backImage) {
1233         return;
1234     }
1235 
1236     // we really need the save, so we can wack the fMCRec
1237     this->checkForDeferredSave();
1238 
1239     fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1240 
1241     SkPaint paint;
1242     paint.setBlendMode(SkBlendMode::kClear);
1243     this->drawClippedToSaveBehind(paint);
1244 }
1245 
internalRestore()1246 void SkCanvas::internalRestore() {
1247     SkASSERT(fMCStack.count() != 0);
1248 
1249     // reserve our layer (if any)
1250     DeviceCM* layer = fMCRec->fLayer;   // may be null
1251     // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1252     fMCRec->fLayer = nullptr;
1253 
1254     // move this out before we do the actual restore
1255     auto backImage = std::move(fMCRec->fBackImage);
1256 
1257     // now do the normal restore()
1258     fMCRec->~MCRec();       // balanced in save()
1259     fMCStack.pop_back();
1260     fMCRec = (MCRec*)fMCStack.back();
1261 
1262     if (fMCRec) {
1263         FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1264     }
1265 
1266     if (backImage) {
1267         SkPaint paint;
1268         paint.setBlendMode(SkBlendMode::kDstOver);
1269         const int x = backImage->fLoc.x();
1270         const int y = backImage->fLoc.y();
1271         this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1272                                           nullptr, SkMatrix::I());
1273     }
1274 
1275     /*  Time to draw the layer's offscreen. We can't call the public drawSprite,
1276         since if we're being recorded, we don't want to record this (the
1277         recorder will have already recorded the restore).
1278     */
1279     if (layer) {
1280         if (fMCRec) {
1281             const SkIPoint& origin = layer->fDevice->getOrigin();
1282             layer->fDevice->setImmutable();
1283             this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
1284                                      layer->fPaint.get(),
1285                                      layer->fClipImage.get(), layer->fClipMatrix);
1286             // restore what we smashed in internalSaveLayer
1287             this->internalSetMatrix(layer->fStashedMatrix);
1288             // reset this, since internalDrawDevice will have set it to true
1289             delete layer;
1290         } else {
1291             // we're at the root
1292             SkASSERT(layer == (void*)fDeviceCMStorage);
1293             layer->~DeviceCM();
1294             // no need to update fMCRec, 'cause we're killing the canvas
1295         }
1296     }
1297 
1298     if (fMCRec) {
1299         fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
1300         fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1301     }
1302 }
1303 
makeSurface(const SkImageInfo & info,const SkSurfaceProps * props)1304 sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1305     if (nullptr == props) {
1306         props = &fProps;
1307     }
1308     return this->onNewSurface(info, *props);
1309 }
1310 
onNewSurface(const SkImageInfo & info,const SkSurfaceProps & props)1311 sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1312     SkBaseDevice* dev = this->getDevice();
1313     return dev ? dev->makeSurface(info, props) : nullptr;
1314 }
1315 
imageInfo() const1316 SkImageInfo SkCanvas::imageInfo() const {
1317     return this->onImageInfo();
1318 }
1319 
onImageInfo() const1320 SkImageInfo SkCanvas::onImageInfo() const {
1321     SkBaseDevice* dev = this->getDevice();
1322     if (dev) {
1323         return dev->imageInfo();
1324     } else {
1325         return SkImageInfo::MakeUnknown(0, 0);
1326     }
1327 }
1328 
getProps(SkSurfaceProps * props) const1329 bool SkCanvas::getProps(SkSurfaceProps* props) const {
1330     return this->onGetProps(props);
1331 }
1332 
onGetProps(SkSurfaceProps * props) const1333 bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
1334     SkBaseDevice* dev = this->getDevice();
1335     if (dev) {
1336         if (props) {
1337             *props = fProps;
1338         }
1339         return true;
1340     } else {
1341         return false;
1342     }
1343 }
1344 
peekPixels(SkPixmap * pmap)1345 bool SkCanvas::peekPixels(SkPixmap* pmap) {
1346     return this->onPeekPixels(pmap);
1347 }
1348 
onPeekPixels(SkPixmap * pmap)1349 bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
1350     SkBaseDevice* dev = this->getDevice();
1351     return dev && dev->peekPixels(pmap);
1352 }
1353 
accessTopLayerPixels(SkImageInfo * info,size_t * rowBytes,SkIPoint * origin)1354 void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1355     SkPixmap pmap;
1356     if (!this->onAccessTopLayerPixels(&pmap)) {
1357         return nullptr;
1358     }
1359     if (info) {
1360         *info = pmap.info();
1361     }
1362     if (rowBytes) {
1363         *rowBytes = pmap.rowBytes();
1364     }
1365     if (origin) {
1366         *origin = this->getTopDevice()->getOrigin();
1367     }
1368     return pmap.writable_addr();
1369 }
1370 
onAccessTopLayerPixels(SkPixmap * pmap)1371 bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
1372     SkBaseDevice* dev = this->getTopDevice();
1373     return dev && dev->accessPixels(pmap);
1374 }
1375 
1376 /////////////////////////////////////////////////////////////////////////////
1377 
1378 // In our current design/features, we should never have a layer (src) in a different colorspace
1379 // than its parent (dst), so we assert that here. This is called out from other asserts, in case
1380 // we add some feature in the future to allow a given layer/imagefilter to operate in a specific
1381 // colorspace.
check_drawdevice_colorspaces(SkColorSpace * src,SkColorSpace * dst)1382 static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
1383     SkASSERT(src == dst);
1384 }
1385 
internalDrawDevice(SkBaseDevice * srcDev,int x,int y,const SkPaint * paint,SkImage * clipImage,const SkMatrix & clipMatrix)1386 void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1387                                   SkImage* clipImage, const SkMatrix& clipMatrix) {
1388     SkPaint tmp;
1389     if (nullptr == paint) {
1390         paint = &tmp;
1391     }
1392 
1393     DRAW_BEGIN_DRAWDEVICE(*paint)
1394 
1395     while (iter.next()) {
1396         SkBaseDevice* dstDev = iter.fDevice;
1397         check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1398                                      srcDev->imageInfo().colorSpace());
1399         paint = &draw.paint();
1400         SkImageFilter* filter = paint->getImageFilter();
1401         SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1402         if (filter || clipImage) {
1403             sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1404             if (specialImage) {
1405                 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1406                                              specialImage->getColorSpace());
1407                 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1408                                     clipImage, clipMatrix);
1409             }
1410         } else {
1411             dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
1412         }
1413     }
1414 
1415     DRAW_END
1416 }
1417 
1418 /////////////////////////////////////////////////////////////////////////////
1419 
translate(SkScalar dx,SkScalar dy)1420 void SkCanvas::translate(SkScalar dx, SkScalar dy) {
1421     if (dx || dy) {
1422         this->checkForDeferredSave();
1423         fMCRec->fMatrix.preTranslate(dx,dy);
1424 
1425         // Translate shouldn't affect the is-scale-translateness of the matrix.
1426         SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
1427 
1428         FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1429 
1430         this->didTranslate(dx,dy);
1431     }
1432 }
1433 
scale(SkScalar sx,SkScalar sy)1434 void SkCanvas::scale(SkScalar sx, SkScalar sy) {
1435     SkMatrix m;
1436     m.setScale(sx, sy);
1437     this->concat(m);
1438 }
1439 
rotate(SkScalar degrees)1440 void SkCanvas::rotate(SkScalar degrees) {
1441     SkMatrix m;
1442     m.setRotate(degrees);
1443     this->concat(m);
1444 }
1445 
rotate(SkScalar degrees,SkScalar px,SkScalar py)1446 void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1447     SkMatrix m;
1448     m.setRotate(degrees, px, py);
1449     this->concat(m);
1450 }
1451 
skew(SkScalar sx,SkScalar sy)1452 void SkCanvas::skew(SkScalar sx, SkScalar sy) {
1453     SkMatrix m;
1454     m.setSkew(sx, sy);
1455     this->concat(m);
1456 }
1457 
concat(const SkMatrix & matrix)1458 void SkCanvas::concat(const SkMatrix& matrix) {
1459     if (matrix.isIdentity()) {
1460         return;
1461     }
1462 
1463     this->checkForDeferredSave();
1464     fMCRec->fMatrix.preConcat(matrix);
1465     fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
1466 
1467     FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1468 
1469     this->didConcat(matrix);
1470 }
1471 
internalSetMatrix(const SkMatrix & matrix)1472 void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
1473     fMCRec->fMatrix = matrix;
1474     fIsScaleTranslate = matrix.isScaleTranslate();
1475 
1476     FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1477 }
1478 
setMatrix(const SkMatrix & matrix)1479 void SkCanvas::setMatrix(const SkMatrix& matrix) {
1480     this->checkForDeferredSave();
1481     this->internalSetMatrix(matrix);
1482     this->didSetMatrix(matrix);
1483 }
1484 
resetMatrix()1485 void SkCanvas::resetMatrix() {
1486     this->setMatrix(SkMatrix::I());
1487 }
1488 
1489 //////////////////////////////////////////////////////////////////////////////
1490 
clipRect(const SkRect & rect,SkClipOp op,bool doAA)1491 void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
1492     if (!rect.isFinite()) {
1493         return;
1494     }
1495     this->checkForDeferredSave();
1496     ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1497     this->onClipRect(rect, op, edgeStyle);
1498 }
1499 
onClipRect(const SkRect & rect,SkClipOp op,ClipEdgeStyle edgeStyle)1500 void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1501     const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1502 
1503     FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
1504 
1505     AutoValidateClip avc(this);
1506     fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1507                                isAA);
1508     fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1509 }
1510 
androidFramework_setDeviceClipRestriction(const SkIRect & rect)1511 void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1512     fClipRestrictionRect = rect;
1513     if (fClipRestrictionRect.isEmpty()) {
1514         // we notify the device, but we *dont* resolve deferred saves (since we're just
1515         // removing the restriction if the rect is empty. how I hate this api.
1516         FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
1517     } else {
1518         this->checkForDeferredSave();
1519         FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
1520         AutoValidateClip avc(this);
1521         fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
1522         fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1523     }
1524 }
1525 
clipRRect(const SkRRect & rrect,SkClipOp op,bool doAA)1526 void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
1527     this->checkForDeferredSave();
1528     ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1529     if (rrect.isRect()) {
1530         this->onClipRect(rrect.getBounds(), op, edgeStyle);
1531     } else {
1532         this->onClipRRect(rrect, op, edgeStyle);
1533     }
1534 }
1535 
onClipRRect(const SkRRect & rrect,SkClipOp op,ClipEdgeStyle edgeStyle)1536 void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1537     AutoValidateClip avc(this);
1538 
1539     bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1540 
1541     FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
1542 
1543     fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1544                                 isAA);
1545     fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1546 }
1547 
clipPath(const SkPath & path,SkClipOp op,bool doAA)1548 void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
1549     this->checkForDeferredSave();
1550     ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1551 
1552     if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1553         SkRect r;
1554         if (path.isRect(&r)) {
1555             this->onClipRect(r, op, edgeStyle);
1556             return;
1557         }
1558         SkRRect rrect;
1559         if (path.isOval(&r)) {
1560             rrect.setOval(r);
1561             this->onClipRRect(rrect, op, edgeStyle);
1562             return;
1563         }
1564         if (path.isRRect(&rrect)) {
1565             this->onClipRRect(rrect, op, edgeStyle);
1566             return;
1567         }
1568     }
1569 
1570     this->onClipPath(path, op, edgeStyle);
1571 }
1572 
onClipPath(const SkPath & path,SkClipOp op,ClipEdgeStyle edgeStyle)1573 void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
1574     AutoValidateClip avc(this);
1575 
1576     bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1577 
1578     FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
1579 
1580     const SkPath* rasterClipPath = &path;
1581     const SkMatrix* matrix = &fMCRec->fMatrix;
1582     fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1583                                (SkRegion::Op)op, isAA);
1584     fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1585 }
1586 
clipRegion(const SkRegion & rgn,SkClipOp op)1587 void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
1588     this->checkForDeferredSave();
1589     this->onClipRegion(rgn, op);
1590 }
1591 
onClipRegion(const SkRegion & rgn,SkClipOp op)1592 void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
1593     FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
1594 
1595     AutoValidateClip avc(this);
1596 
1597     fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
1598     fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1599 }
1600 
1601 #ifdef SK_DEBUG
validateClip() const1602 void SkCanvas::validateClip() const {
1603 #ifndef SK_DISABLE_SLOW_DEBUG_VALIDATION
1604     // construct clipRgn from the clipstack
1605     const SkBaseDevice* device = this->getDevice();
1606     if (!device) {
1607         SkASSERT(this->isClipEmpty());
1608         return;
1609     }
1610 #endif
1611 }
1612 #endif
1613 
androidFramework_isClipAA() const1614 bool SkCanvas::androidFramework_isClipAA() const {
1615     bool containsAA = false;
1616 
1617     FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1618 
1619     return containsAA;
1620 }
1621 
1622 class RgnAccumulator {
1623     SkRegion* fRgn;
1624 public:
RgnAccumulator(SkRegion * total)1625     RgnAccumulator(SkRegion* total) : fRgn(total) {}
accumulate(SkBaseDevice * device,SkRegion * rgn)1626     void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1627         SkIPoint origin = device->getOrigin();
1628         if (origin.x() | origin.y()) {
1629             rgn->translate(origin.x(), origin.y());
1630         }
1631         fRgn->op(*rgn, SkRegion::kUnion_Op);
1632     }
1633 };
1634 
temporary_internal_getRgnClip(SkRegion * rgn)1635 void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1636     RgnAccumulator accum(rgn);
1637     SkRegion tmp;
1638 
1639     rgn->setEmpty();
1640     FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
1641 }
1642 
1643 ///////////////////////////////////////////////////////////////////////////////
1644 
isClipEmpty() const1645 bool SkCanvas::isClipEmpty() const {
1646     return fMCRec->fRasterClip.isEmpty();
1647 
1648     // TODO: should we only use the conservative answer in a recording canvas?
1649 #if 0
1650     SkBaseDevice* dev = this->getTopDevice();
1651     // if no device we return true
1652     return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
1653 #endif
1654 }
1655 
isClipRect() const1656 bool SkCanvas::isClipRect() const {
1657     SkBaseDevice* dev = this->getTopDevice();
1658     // if no device we return false
1659     return dev && dev->onGetClipType() == SkBaseDevice::ClipType::kRect;
1660 }
1661 
is_nan_or_clipped(const Sk4f & devRect,const Sk4f & devClip)1662 static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1663 #if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1664     __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1665     __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1666     __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1667     return 0xF != _mm_movemask_ps(mask);
1668 #elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1669     float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1670     float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1671     uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1672     return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1673 #else
1674     SkRect devRectAsRect;
1675     SkRect devClipAsRect;
1676     devRect.store(&devRectAsRect.fLeft);
1677     devClip.store(&devClipAsRect.fLeft);
1678     return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1679 #endif
1680 }
1681 
1682 // It's important for this function to not be inlined.  Otherwise the compiler will share code
1683 // between the fast path and the slow path, resulting in two slow paths.
quick_reject_slow_path(const SkRect & src,const SkRect & deviceClip,const SkMatrix & matrix)1684 static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1685                                                    const SkMatrix& matrix) {
1686     SkRect deviceRect;
1687     matrix.mapRect(&deviceRect, src);
1688     return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1689 }
1690 
quickReject(const SkRect & src) const1691 bool SkCanvas::quickReject(const SkRect& src) const {
1692 #ifdef SK_DEBUG
1693     // Verify that fDeviceClipBounds are set properly.
1694     SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1695     if (fMCRec->fRasterClip.isEmpty()) {
1696         SkASSERT(fDeviceClipBounds.isEmpty());
1697     } else {
1698         SkASSERT(tmp == fDeviceClipBounds);
1699     }
1700 
1701     // Verify that fIsScaleTranslate is set properly.
1702     SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
1703 #endif
1704 
1705     if (!fIsScaleTranslate) {
1706         return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1707     }
1708 
1709     // We inline the implementation of mapScaleTranslate() for the fast path.
1710     float sx = fMCRec->fMatrix.getScaleX();
1711     float sy = fMCRec->fMatrix.getScaleY();
1712     float tx = fMCRec->fMatrix.getTranslateX();
1713     float ty = fMCRec->fMatrix.getTranslateY();
1714     Sk4f scale(sx, sy, sx, sy);
1715     Sk4f trans(tx, ty, tx, ty);
1716 
1717     // Apply matrix.
1718     Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1719 
1720     // Make sure left < right, top < bottom.
1721     Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1722     Sk4f min = Sk4f::Min(ltrb, rblt);
1723     Sk4f max = Sk4f::Max(ltrb, rblt);
1724     // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1725     // ARM this sequence generates the fastest (a single instruction).
1726     Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1727 
1728     // Check if the device rect is NaN or outside the clip.
1729     return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
1730 }
1731 
quickReject(const SkPath & path) const1732 bool SkCanvas::quickReject(const SkPath& path) const {
1733     return path.isEmpty() || this->quickReject(path.getBounds());
1734 }
1735 
getLocalClipBounds() const1736 SkRect SkCanvas::getLocalClipBounds() const {
1737     SkIRect ibounds = this->getDeviceClipBounds();
1738     if (ibounds.isEmpty()) {
1739         return SkRect::MakeEmpty();
1740     }
1741 
1742     SkMatrix inverse;
1743     // if we can't invert the CTM, we can't return local clip bounds
1744     if (!fMCRec->fMatrix.invert(&inverse)) {
1745         return SkRect::MakeEmpty();
1746     }
1747 
1748     SkRect bounds;
1749     // adjust it outwards in case we are antialiasing
1750     const int margin = 1;
1751 
1752     SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
1753     inverse.mapRect(&bounds, r);
1754     return bounds;
1755 }
1756 
getDeviceClipBounds() const1757 SkIRect SkCanvas::getDeviceClipBounds() const {
1758     return fMCRec->fRasterClip.getBounds();
1759 }
1760 
getTotalMatrix() const1761 const SkMatrix& SkCanvas::getTotalMatrix() const {
1762     return fMCRec->fMatrix;
1763 }
1764 
internal_private_accessTopLayerRenderTargetContext()1765 GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
1766     SkBaseDevice* dev = this->getTopDevice();
1767     return dev ? dev->accessRenderTargetContext() : nullptr;
1768 }
1769 
getGrContext()1770 GrContext* SkCanvas::getGrContext() {
1771     SkBaseDevice* device = this->getTopDevice();
1772     return device ? device->context() : nullptr;
1773 }
1774 
drawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)1775 void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1776                           const SkPaint& paint) {
1777     TRACE_EVENT0("skia", TRACE_FUNC);
1778     if (outer.isEmpty()) {
1779         return;
1780     }
1781     if (inner.isEmpty()) {
1782         this->drawRRect(outer, paint);
1783         return;
1784     }
1785 
1786     // We don't have this method (yet), but technically this is what we should
1787     // be able to return ...
1788     // if (!outer.contains(inner))) {
1789     //
1790     // For now at least check for containment of bounds
1791     if (!outer.getBounds().contains(inner.getBounds())) {
1792         return;
1793     }
1794 
1795     this->onDrawDRRect(outer, inner, paint);
1796 }
1797 
drawPaint(const SkPaint & paint)1798 void SkCanvas::drawPaint(const SkPaint& paint) {
1799     TRACE_EVENT0("skia", TRACE_FUNC);
1800     this->onDrawPaint(paint);
1801 }
1802 
drawRect(const SkRect & r,const SkPaint & paint)1803 void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1804     TRACE_EVENT0("skia", TRACE_FUNC);
1805     // To avoid redundant logic in our culling code and various backends, we always sort rects
1806     // before passing them along.
1807     this->onDrawRect(r.makeSorted(), paint);
1808 }
1809 
drawClippedToSaveBehind(const SkPaint & paint)1810 void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1811     TRACE_EVENT0("skia", TRACE_FUNC);
1812     this->onDrawBehind(paint);
1813 }
1814 
drawRegion(const SkRegion & region,const SkPaint & paint)1815 void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1816     TRACE_EVENT0("skia", TRACE_FUNC);
1817     if (region.isEmpty()) {
1818         return;
1819     }
1820 
1821     if (region.isRect()) {
1822         return this->drawIRect(region.getBounds(), paint);
1823     }
1824 
1825     this->onDrawRegion(region, paint);
1826 }
1827 
drawOval(const SkRect & r,const SkPaint & paint)1828 void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1829     TRACE_EVENT0("skia", TRACE_FUNC);
1830     // To avoid redundant logic in our culling code and various backends, we always sort rects
1831     // before passing them along.
1832     this->onDrawOval(r.makeSorted(), paint);
1833 }
1834 
drawRRect(const SkRRect & rrect,const SkPaint & paint)1835 void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1836     TRACE_EVENT0("skia", TRACE_FUNC);
1837     this->onDrawRRect(rrect, paint);
1838 }
1839 
drawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)1840 void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1841     TRACE_EVENT0("skia", TRACE_FUNC);
1842     this->onDrawPoints(mode, count, pts, paint);
1843 }
1844 
drawVertices(const sk_sp<SkVertices> & vertices,SkBlendMode mode,const SkPaint & paint)1845 void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1846                             const SkPaint& paint) {
1847     TRACE_EVENT0("skia", TRACE_FUNC);
1848     RETURN_ON_NULL(vertices);
1849     // We expect fans to be converted to triangles when building or deserializing SkVertices.
1850     SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
1851     this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
1852 }
1853 
drawVertices(const SkVertices * vertices,SkBlendMode mode,const SkPaint & paint)1854 void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1855     TRACE_EVENT0("skia", TRACE_FUNC);
1856     RETURN_ON_NULL(vertices);
1857     this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1858 }
1859 
drawVertices(const sk_sp<SkVertices> & vertices,const SkVertices::Bone bones[],int boneCount,SkBlendMode mode,const SkPaint & paint)1860 void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1861                             int boneCount, SkBlendMode mode, const SkPaint& paint) {
1862     TRACE_EVENT0("skia", TRACE_FUNC);
1863     RETURN_ON_NULL(vertices);
1864     SkASSERT(boneCount <= 80);
1865     this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1866 }
1867 
drawVertices(const SkVertices * vertices,const SkVertices::Bone bones[],int boneCount,SkBlendMode mode,const SkPaint & paint)1868 void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1869                             int boneCount, SkBlendMode mode, const SkPaint& paint) {
1870     TRACE_EVENT0("skia", TRACE_FUNC);
1871     RETURN_ON_NULL(vertices);
1872     SkASSERT(boneCount <= 80);
1873     this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
1874 }
1875 
drawPath(const SkPath & path,const SkPaint & paint)1876 void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1877     TRACE_EVENT0("skia", TRACE_FUNC);
1878     this->onDrawPath(path, paint);
1879 }
1880 
drawImage(const SkImage * image,SkScalar x,SkScalar y,const SkPaint * paint)1881 void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1882     TRACE_EVENT0("skia", TRACE_FUNC);
1883     RETURN_ON_NULL(image);
1884     this->onDrawImage(image, x, y, paint);
1885 }
1886 
1887 // Returns true if the rect can be "filled" : non-empty and finite
fillable(const SkRect & r)1888 static bool fillable(const SkRect& r) {
1889     SkScalar w = r.width();
1890     SkScalar h = r.height();
1891     return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1892 }
1893 
drawImageRect(const SkImage * image,const SkRect & src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1894 void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1895                              const SkPaint* paint, SrcRectConstraint constraint) {
1896     TRACE_EVENT0("skia", TRACE_FUNC);
1897     RETURN_ON_NULL(image);
1898     if (!fillable(dst) || !fillable(src)) {
1899         return;
1900     }
1901     this->onDrawImageRect(image, &src, dst, paint, constraint);
1902 }
1903 
drawImageRect(const SkImage * image,const SkIRect & isrc,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1904 void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1905                              const SkPaint* paint, SrcRectConstraint constraint) {
1906     RETURN_ON_NULL(image);
1907     this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
1908 }
1909 
drawImageRect(const SkImage * image,const SkRect & dst,const SkPaint * paint)1910 void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
1911     RETURN_ON_NULL(image);
1912     this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1913                         kFast_SrcRectConstraint);
1914 }
1915 
1916 namespace {
1917 class LatticePaint : SkNoncopyable {
1918 public:
LatticePaint(const SkPaint * origPaint)1919     LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1920         if (!origPaint) {
1921             return;
1922         }
1923         if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1924             fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1925         }
1926         if (origPaint->getMaskFilter()) {
1927             fPaint.writable()->setMaskFilter(nullptr);
1928         }
1929         if (origPaint->isAntiAlias()) {
1930             fPaint.writable()->setAntiAlias(false);
1931         }
1932     }
1933 
get() const1934     const SkPaint* get() const {
1935         return fPaint;
1936     }
1937 
1938 private:
1939     SkTCopyOnFirstWrite<SkPaint> fPaint;
1940 };
1941 } // namespace
1942 
drawImageNine(const SkImage * image,const SkIRect & center,const SkRect & dst,const SkPaint * paint)1943 void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1944                              const SkPaint* paint) {
1945     TRACE_EVENT0("skia", TRACE_FUNC);
1946     RETURN_ON_NULL(image);
1947     if (dst.isEmpty()) {
1948         return;
1949     }
1950     if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1951         LatticePaint latticePaint(paint);
1952         this->onDrawImageNine(image, center, dst, latticePaint.get());
1953     } else {
1954         this->drawImageRect(image, dst, paint);
1955     }
1956 }
1957 
drawImageLattice(const SkImage * image,const Lattice & lattice,const SkRect & dst,const SkPaint * paint)1958 void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1959                                 const SkPaint* paint) {
1960     TRACE_EVENT0("skia", TRACE_FUNC);
1961     RETURN_ON_NULL(image);
1962     if (dst.isEmpty()) {
1963         return;
1964     }
1965 
1966     SkIRect bounds;
1967     Lattice latticePlusBounds = lattice;
1968     if (!latticePlusBounds.fBounds) {
1969         bounds = SkIRect::MakeWH(image->width(), image->height());
1970         latticePlusBounds.fBounds = &bounds;
1971     }
1972 
1973     if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1974         LatticePaint latticePaint(paint);
1975         this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
1976     } else {
1977         this->drawImageRect(image, dst, paint);
1978     }
1979 }
1980 
drawBitmap(const SkBitmap & bitmap,SkScalar dx,SkScalar dy,const SkPaint * paint)1981 void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1982     TRACE_EVENT0("skia", TRACE_FUNC);
1983     if (bitmap.drawsNothing()) {
1984         return;
1985     }
1986     this->onDrawBitmap(bitmap, dx, dy, paint);
1987 }
1988 
drawBitmapRect(const SkBitmap & bitmap,const SkRect & src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1989 void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
1990                               const SkPaint* paint, SrcRectConstraint constraint) {
1991     TRACE_EVENT0("skia", TRACE_FUNC);
1992     if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
1993         return;
1994     }
1995     this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
1996 }
1997 
drawBitmapRect(const SkBitmap & bitmap,const SkIRect & isrc,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1998 void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1999                               const SkPaint* paint, SrcRectConstraint constraint) {
2000     this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
2001 }
2002 
drawBitmapRect(const SkBitmap & bitmap,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)2003 void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2004                               SrcRectConstraint constraint) {
2005     this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2006                          constraint);
2007 }
2008 
drawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint * paint)2009 void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2010                               const SkPaint* paint) {
2011     TRACE_EVENT0("skia", TRACE_FUNC);
2012     if (bitmap.drawsNothing() || dst.isEmpty()) {
2013         return;
2014     }
2015     if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2016         LatticePaint latticePaint(paint);
2017         this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
2018     } else {
2019         this->drawBitmapRect(bitmap, dst, paint);
2020     }
2021 }
2022 
drawBitmapLattice(const SkBitmap & bitmap,const Lattice & lattice,const SkRect & dst,const SkPaint * paint)2023 void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2024                                  const SkPaint* paint) {
2025     TRACE_EVENT0("skia", TRACE_FUNC);
2026     if (bitmap.drawsNothing() || dst.isEmpty()) {
2027         return;
2028     }
2029 
2030     SkIRect bounds;
2031     Lattice latticePlusBounds = lattice;
2032     if (!latticePlusBounds.fBounds) {
2033         bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2034         latticePlusBounds.fBounds = &bounds;
2035     }
2036 
2037     if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2038         LatticePaint latticePaint(paint);
2039         this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
2040     } else {
2041         this->drawBitmapRect(bitmap, dst, paint);
2042     }
2043 }
2044 
drawAtlas(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkBlendMode mode,const SkRect * cull,const SkPaint * paint)2045 void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2046                          const SkColor colors[], int count, SkBlendMode mode,
2047                          const SkRect* cull, const SkPaint* paint) {
2048     TRACE_EVENT0("skia", TRACE_FUNC);
2049     RETURN_ON_NULL(atlas);
2050     if (count <= 0) {
2051         return;
2052     }
2053     SkASSERT(atlas);
2054     SkASSERT(tex);
2055     this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2056 }
2057 
drawAnnotation(const SkRect & rect,const char key[],SkData * value)2058 void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2059     TRACE_EVENT0("skia", TRACE_FUNC);
2060     if (key) {
2061         this->onDrawAnnotation(rect, key, value);
2062     }
2063 }
2064 
legacy_drawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)2065 void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2066                                     const SkPaint* paint, SrcRectConstraint constraint) {
2067     if (src) {
2068         this->drawImageRect(image, *src, dst, paint, constraint);
2069     } else {
2070         this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2071                             dst, paint, constraint);
2072     }
2073 }
legacy_drawBitmapRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)2074 void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2075                                      const SkPaint* paint, SrcRectConstraint constraint) {
2076     if (src) {
2077         this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2078     } else {
2079         this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2080                              dst, paint, constraint);
2081     }
2082 }
2083 
private_draw_shadow_rec(const SkPath & path,const SkDrawShadowRec & rec)2084 void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
2085     TRACE_EVENT0("skia", TRACE_FUNC);
2086     this->onDrawShadowRec(path, rec);
2087 }
2088 
onDrawShadowRec(const SkPath & path,const SkDrawShadowRec & rec)2089 void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
2090     SkPaint paint;
2091     const SkRect& pathBounds = path.getBounds();
2092 
2093     DRAW_BEGIN(paint, &pathBounds)
2094     while (iter.next()) {
2095         iter.fDevice->drawShadow(path, rec);
2096     }
2097     DRAW_END
2098 }
2099 
experimental_DrawEdgeAAQuad(const SkRect & rect,const SkPoint clip[4],QuadAAFlags aaFlags,const SkColor4f & color,SkBlendMode mode)2100 void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
2101                                            QuadAAFlags aaFlags, const SkColor4f& color,
2102                                            SkBlendMode mode) {
2103     TRACE_EVENT0("skia", TRACE_FUNC);
2104     // Make sure the rect is sorted before passing it along
2105     this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
2106 }
2107 
experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[],int cnt,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkPaint * paint,SrcRectConstraint constraint)2108 void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
2109                                                const SkPoint dstClips[],
2110                                                const SkMatrix preViewMatrices[],
2111                                                const SkPaint* paint,
2112                                                SrcRectConstraint constraint) {
2113     TRACE_EVENT0("skia", TRACE_FUNC);
2114     this->onDrawEdgeAAImageSet(imageSet, cnt, dstClips, preViewMatrices, paint, constraint);
2115 }
2116 
2117 //////////////////////////////////////////////////////////////////////////////
2118 //  These are the virtual drawing methods
2119 //////////////////////////////////////////////////////////////////////////////
2120 
onDiscard()2121 void SkCanvas::onDiscard() {
2122     if (fSurfaceBase) {
2123         fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2124     }
2125 }
2126 
onDrawPaint(const SkPaint & paint)2127 void SkCanvas::onDrawPaint(const SkPaint& paint) {
2128     this->internalDrawPaint(paint);
2129 }
2130 
internalDrawPaint(const SkPaint & paint)2131 void SkCanvas::internalDrawPaint(const SkPaint& paint) {
2132     DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
2133 
2134     while (iter.next()) {
2135         iter.fDevice->drawPaint(draw.paint());
2136     }
2137 
2138     DRAW_END
2139 }
2140 
onDrawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)2141 void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2142                             const SkPaint& paint) {
2143     if ((long)count <= 0) {
2144         return;
2145     }
2146 
2147     SkRect r;
2148     const SkRect* bounds = nullptr;
2149     if (paint.canComputeFastBounds()) {
2150         // special-case 2 points (common for drawing a single line)
2151         if (2 == count) {
2152             r.set(pts[0], pts[1]);
2153         } else {
2154             r.setBounds(pts, SkToInt(count));
2155         }
2156         if (!r.isFinite()) {
2157             return;
2158         }
2159         SkRect storage;
2160         if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2161             return;
2162         }
2163         bounds = &r;
2164     }
2165 
2166     SkASSERT(pts != nullptr);
2167 
2168     DRAW_BEGIN(paint, bounds)
2169 
2170     while (iter.next()) {
2171         iter.fDevice->drawPoints(mode, count, pts, draw.paint());
2172     }
2173 
2174     DRAW_END
2175 }
2176 
needs_autodrawlooper(SkCanvas * canvas,const SkPaint & paint)2177 static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2178     return paint.getImageFilter() != nullptr;
2179 }
2180 
onDrawRect(const SkRect & r,const SkPaint & paint)2181 void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
2182     SkASSERT(r.isSorted());
2183     if (paint.canComputeFastBounds()) {
2184         SkRect storage;
2185         if (this->quickReject(paint.computeFastBounds(r, &storage))) {
2186             return;
2187         }
2188     }
2189 
2190     if (needs_autodrawlooper(this, paint)) {
2191         DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
2192 
2193         while (iter.next()) {
2194             iter.fDevice->drawRect(r, draw.paint());
2195         }
2196 
2197         DRAW_END
2198     } else if (!paint.nothingToDraw()) {
2199         this->predrawNotify(&r, &paint, false);
2200         SkDrawIter iter(this);
2201         while (iter.next()) {
2202             iter.fDevice->drawRect(r, paint);
2203         }
2204     }
2205 }
2206 
onDrawRegion(const SkRegion & region,const SkPaint & paint)2207 void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2208     SkRect regionRect = SkRect::Make(region.getBounds());
2209     if (paint.canComputeFastBounds()) {
2210         SkRect storage;
2211         if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2212             return;
2213         }
2214     }
2215 
2216     DRAW_BEGIN(paint, &regionRect)
2217 
2218     while (iter.next()) {
2219         iter.fDevice->drawRegion(region, draw.paint());
2220     }
2221 
2222     DRAW_END
2223 }
2224 
onDrawBehind(const SkPaint & paint)2225 void SkCanvas::onDrawBehind(const SkPaint& paint) {
2226     SkIRect bounds;
2227     SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
2228     for (;;) {
2229         const MCRec* rec = (const MCRec*)iter.prev();
2230         if (!rec) {
2231             return; // no backimages, so nothing to draw
2232         }
2233         if (rec->fBackImage) {
2234             bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2235                                        rec->fBackImage->fImage->width(),
2236                                        rec->fBackImage->fImage->height());
2237             break;
2238         }
2239     }
2240 
2241     DRAW_BEGIN(paint, nullptr)
2242 
2243     while (iter.next()) {
2244         SkBaseDevice* dev = iter.fDevice;
2245 
2246         dev->save();
2247         // We use clipRegion because it is already defined to operate in dev-space
2248         // (i.e. ignores the ctm). However, it is going to first translate by -origin,
2249         // but we don't want that, so we undo that before calling in.
2250         SkRegion rgn(bounds.makeOffset(dev->fOrigin));
2251         dev->clipRegion(rgn, SkClipOp::kIntersect);
2252         dev->drawPaint(draw.paint());
2253         dev->restore(fMCRec->fMatrix);
2254     }
2255 
2256     DRAW_END
2257 }
2258 
onDrawOval(const SkRect & oval,const SkPaint & paint)2259 void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
2260     SkASSERT(oval.isSorted());
2261     if (paint.canComputeFastBounds()) {
2262         SkRect storage;
2263         if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2264             return;
2265         }
2266     }
2267 
2268     DRAW_BEGIN(paint, &oval)
2269 
2270     while (iter.next()) {
2271         iter.fDevice->drawOval(oval, draw.paint());
2272     }
2273 
2274     DRAW_END
2275 }
2276 
onDrawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)2277 void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2278                          SkScalar sweepAngle, bool useCenter,
2279                          const SkPaint& paint) {
2280     SkASSERT(oval.isSorted());
2281     if (paint.canComputeFastBounds()) {
2282         SkRect storage;
2283         // Note we're using the entire oval as the bounds.
2284         if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2285             return;
2286         }
2287     }
2288 
2289     DRAW_BEGIN(paint, &oval)
2290 
2291     while (iter.next()) {
2292         iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, draw.paint());
2293     }
2294 
2295     DRAW_END
2296 }
2297 
onDrawRRect(const SkRRect & rrect,const SkPaint & paint)2298 void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
2299     if (paint.canComputeFastBounds()) {
2300         SkRect storage;
2301         if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2302             return;
2303         }
2304     }
2305 
2306     if (rrect.isRect()) {
2307         // call the non-virtual version
2308         this->SkCanvas::drawRect(rrect.getBounds(), paint);
2309         return;
2310     } else if (rrect.isOval()) {
2311         // call the non-virtual version
2312         this->SkCanvas::drawOval(rrect.getBounds(), paint);
2313         return;
2314     }
2315 
2316     DRAW_BEGIN(paint, &rrect.getBounds())
2317 
2318     while (iter.next()) {
2319         iter.fDevice->drawRRect(rrect, draw.paint());
2320     }
2321 
2322     DRAW_END
2323 }
2324 
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)2325 void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
2326     if (paint.canComputeFastBounds()) {
2327         SkRect storage;
2328         if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2329             return;
2330         }
2331     }
2332 
2333     DRAW_BEGIN(paint, &outer.getBounds())
2334 
2335     while (iter.next()) {
2336         iter.fDevice->drawDRRect(outer, inner, draw.paint());
2337     }
2338 
2339     DRAW_END
2340 }
2341 
onDrawPath(const SkPath & path,const SkPaint & paint)2342 void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
2343     if (!path.isFinite()) {
2344         return;
2345     }
2346 
2347     const SkRect& pathBounds = path.getBounds();
2348     if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
2349         SkRect storage;
2350         if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2351             return;
2352         }
2353     }
2354 
2355     if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
2356         if (path.isInverseFillType()) {
2357             this->internalDrawPaint(paint);
2358             return;
2359         }
2360     }
2361 
2362     DRAW_BEGIN(paint, &pathBounds)
2363 
2364     while (iter.next()) {
2365         iter.fDevice->drawPath(path, draw.paint());
2366     }
2367 
2368     DRAW_END
2369 }
2370 
canDrawBitmapAsSprite(SkScalar x,SkScalar y,int w,int h,const SkPaint & paint)2371 bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
2372     if (!paint.getImageFilter()) {
2373         return false;
2374     }
2375 
2376     const SkMatrix& ctm = this->getTotalMatrix();
2377     if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
2378         return false;
2379     }
2380 
2381     // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2382     // Once we can filter and the filter will return a result larger than itself, we should be
2383     // able to remove this constraint.
2384     // skbug.com/4526
2385     //
2386     SkPoint pt;
2387     ctm.mapXY(x, y, &pt);
2388     SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2389     return ir.contains(fMCRec->fRasterClip.getBounds());
2390 }
2391 
2392 // Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2393 // given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2394 // null.
init_image_paint(SkPaint * real,const SkPaint * paintParam)2395 static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2396     if (paintParam) {
2397         *real = *paintParam;
2398         real->setStyle(SkPaint::kFill_Style);
2399         real->setPathEffect(nullptr);
2400         paintParam = real;
2401     }
2402     return paintParam;
2403 }
2404 
onDrawImage(const SkImage * image,SkScalar x,SkScalar y,const SkPaint * paint)2405 void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
2406     SkPaint realPaint;
2407     paint = init_image_paint(&realPaint, paint);
2408 
2409     SkRect bounds = SkRect::MakeXYWH(x, y,
2410                                      SkIntToScalar(image->width()), SkIntToScalar(image->height()));
2411     if (nullptr == paint || paint->canComputeFastBounds()) {
2412         SkRect tmp = bounds;
2413         if (paint) {
2414             paint->computeFastBounds(tmp, &tmp);
2415         }
2416         if (this->quickReject(tmp)) {
2417             return;
2418         }
2419     }
2420     // At this point we need a real paint object. If the caller passed null, then we should
2421     // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2422     // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2423     paint = &realPaint;
2424 
2425     sk_sp<SkSpecialImage> special;
2426     bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2427                                                     *paint);
2428     if (drawAsSprite && paint->getImageFilter()) {
2429         special = this->getDevice()->makeSpecial(image);
2430         if (!special) {
2431             drawAsSprite = false;
2432         }
2433     }
2434 
2435     DRAW_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2436 
2437     while (iter.next()) {
2438         const SkPaint& pnt = draw.paint();
2439         if (special) {
2440             SkPoint pt;
2441             iter.fDevice->ctm().mapXY(x, y, &pt);
2442             iter.fDevice->drawSpecial(special.get(),
2443                                       SkScalarRoundToInt(pt.fX),
2444                                       SkScalarRoundToInt(pt.fY), pnt,
2445                                       nullptr, SkMatrix::I());
2446         } else {
2447             iter.fDevice->drawImageRect(
2448                     image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt,
2449                     kStrict_SrcRectConstraint);
2450         }
2451     }
2452 
2453     DRAW_END
2454 }
2455 
onDrawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)2456 void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2457                                const SkPaint* paint, SrcRectConstraint constraint) {
2458     SkPaint realPaint;
2459     paint = init_image_paint(&realPaint, paint);
2460 
2461     if (nullptr == paint || paint->canComputeFastBounds()) {
2462         SkRect storage = dst;
2463         if (paint) {
2464             paint->computeFastBounds(dst, &storage);
2465         }
2466         if (this->quickReject(storage)) {
2467             return;
2468         }
2469     }
2470     paint = &realPaint;
2471 
2472     DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
2473 
2474     while (iter.next()) {
2475         iter.fDevice->drawImageRect(image, src, dst, draw.paint(), constraint);
2476     }
2477 
2478     DRAW_END
2479 }
2480 
onDrawBitmap(const SkBitmap & bitmap,SkScalar x,SkScalar y,const SkPaint * paint)2481 void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
2482     SkDEBUGCODE(bitmap.validate();)
2483 
2484     if (bitmap.drawsNothing()) {
2485         return;
2486     }
2487 
2488     SkPaint realPaint;
2489     init_image_paint(&realPaint, paint);
2490     paint = &realPaint;
2491 
2492     SkRect bounds;
2493     bitmap.getBounds(&bounds);
2494     bounds.offset(x, y);
2495     bool canFastBounds = paint->canComputeFastBounds();
2496     if (canFastBounds) {
2497         SkRect storage;
2498         if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
2499             return;
2500         }
2501     }
2502 
2503     sk_sp<SkSpecialImage> special;
2504     bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2505                                                                      bitmap.height(), *paint);
2506     if (drawAsSprite && paint->getImageFilter()) {
2507         special = this->getDevice()->makeSpecial(bitmap);
2508         if (!special) {
2509             drawAsSprite = false;
2510         }
2511     }
2512 
2513     DRAW_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2514 
2515     while (iter.next()) {
2516         const SkPaint& pnt = draw.paint();
2517         if (special) {
2518             SkPoint pt;
2519             iter.fDevice->ctm().mapXY(x, y, &pt);
2520             iter.fDevice->drawSpecial(special.get(),
2521                                       SkScalarRoundToInt(pt.fX),
2522                                       SkScalarRoundToInt(pt.fY), pnt,
2523                                       nullptr, SkMatrix::I());
2524         } else {
2525             SkRect fullImage = SkRect::MakeWH(bitmap.width(), bitmap.height());
2526             iter.fDevice->drawBitmapRect(bitmap, &fullImage, fullImage.makeOffset(x, y), pnt,
2527                                          kStrict_SrcRectConstraint);
2528         }
2529     }
2530 
2531     DRAW_END
2532 }
2533 
2534 // this one is non-virtual, so it can be called safely by other canvas apis
internalDrawBitmapRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)2535 void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
2536                                       const SkRect& dst, const SkPaint* paint,
2537                                       SrcRectConstraint constraint) {
2538     if (bitmap.drawsNothing() || dst.isEmpty()) {
2539         return;
2540     }
2541 
2542     if (nullptr == paint || paint->canComputeFastBounds()) {
2543         SkRect storage;
2544         if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2545             return;
2546         }
2547     }
2548 
2549     SkLazyPaint lazy;
2550     if (nullptr == paint) {
2551         paint = lazy.init();
2552     }
2553 
2554     DRAW_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
2555 
2556     while (iter.next()) {
2557         iter.fDevice->drawBitmapRect(bitmap, src, dst, draw.paint(), constraint);
2558     }
2559 
2560     DRAW_END
2561 }
2562 
onDrawBitmapRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)2563 void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2564                                 const SkPaint* paint, SrcRectConstraint constraint) {
2565     SkDEBUGCODE(bitmap.validate();)
2566     this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
2567 }
2568 
onDrawImageNine(const SkImage * image,const SkIRect & center,const SkRect & dst,const SkPaint * paint)2569 void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2570                                const SkPaint* paint) {
2571     SkPaint realPaint;
2572     paint = init_image_paint(&realPaint, paint);
2573 
2574     if (nullptr == paint || paint->canComputeFastBounds()) {
2575         SkRect storage;
2576         if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2577             return;
2578         }
2579     }
2580     paint = &realPaint;
2581 
2582     DRAW_BEGIN(*paint, &dst)
2583 
2584     while (iter.next()) {
2585         iter.fDevice->drawImageNine(image, center, dst, draw.paint());
2586     }
2587 
2588     DRAW_END
2589 }
2590 
onDrawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint * paint)2591 void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2592                                 const SkPaint* paint) {
2593     SkDEBUGCODE(bitmap.validate();)
2594     SkPaint realPaint;
2595     paint = init_image_paint(&realPaint, paint);
2596 
2597     if (nullptr == paint || paint->canComputeFastBounds()) {
2598         SkRect storage;
2599         if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2600             return;
2601         }
2602     }
2603     paint = &realPaint;
2604 
2605     DRAW_BEGIN(*paint, &dst)
2606 
2607     while (iter.next()) {
2608         iter.fDevice->drawBitmapNine(bitmap, center, dst, draw.paint());
2609     }
2610 
2611     DRAW_END
2612 }
2613 
onDrawImageLattice(const SkImage * image,const Lattice & lattice,const SkRect & dst,const SkPaint * paint)2614 void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2615                                   const SkPaint* paint) {
2616     SkPaint realPaint;
2617     paint = init_image_paint(&realPaint, paint);
2618 
2619     if (nullptr == paint || paint->canComputeFastBounds()) {
2620         SkRect storage;
2621         if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2622             return;
2623         }
2624     }
2625     paint = &realPaint;
2626 
2627     DRAW_BEGIN(*paint, &dst)
2628 
2629     while (iter.next()) {
2630         iter.fDevice->drawImageLattice(image, lattice, dst, draw.paint());
2631     }
2632 
2633     DRAW_END
2634 }
2635 
onDrawBitmapLattice(const SkBitmap & bitmap,const Lattice & lattice,const SkRect & dst,const SkPaint * paint)2636 void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2637                                    const SkRect& dst, const SkPaint* paint) {
2638     SkPaint realPaint;
2639     paint = init_image_paint(&realPaint, paint);
2640 
2641     if (nullptr == paint || paint->canComputeFastBounds()) {
2642         SkRect storage;
2643         if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2644             return;
2645         }
2646     }
2647     paint = &realPaint;
2648 
2649     DRAW_BEGIN(*paint, &dst)
2650 
2651     while (iter.next()) {
2652         iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, draw.paint());
2653     }
2654 
2655     DRAW_END
2656 }
2657 
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)2658 void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2659                               const SkPaint& paint) {
2660     SkRect storage;
2661     const SkRect* bounds = nullptr;
2662     if (paint.canComputeFastBounds()) {
2663         storage = blob->bounds().makeOffset(x, y);
2664         SkRect tmp;
2665         if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2666             return;
2667         }
2668         bounds = &storage;
2669     }
2670 
2671     // We cannot filter in the looper as we normally do, because the paint is
2672     // incomplete at this point (text-related attributes are embedded within blob run paints).
2673     DRAW_BEGIN(paint, bounds)
2674 
2675     while (iter.next()) {
2676         fScratchGlyphRunBuilder->drawTextBlob(draw.paint(), *blob, {x, y}, iter.fDevice);
2677     }
2678 
2679     DRAW_END
2680 }
2681 
2682 // 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)2683 void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
2684                               SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2685     TRACE_EVENT0("skia", TRACE_FUNC);
2686     if (byteLength) {
2687         sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
2688         this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
2689     }
2690 }
2691 
drawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)2692 void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2693                             const SkPaint& paint) {
2694     TRACE_EVENT0("skia", TRACE_FUNC);
2695     RETURN_ON_NULL(blob);
2696     RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
2697     this->onDrawTextBlob(blob, x, y, paint);
2698 }
2699 
onDrawVerticesObject(const SkVertices * vertices,const SkVertices::Bone bones[],int boneCount,SkBlendMode bmode,const SkPaint & paint)2700 void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
2701                                     int boneCount, SkBlendMode bmode, const SkPaint& paint) {
2702     DRAW_BEGIN(paint, nullptr)
2703 
2704     while (iter.next()) {
2705         // In the common case of one iteration we could std::move vertices here.
2706         iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, draw.paint());
2707     }
2708 
2709     DRAW_END
2710 }
2711 
drawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode bmode,const SkPaint & paint)2712 void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2713                          const SkPoint texCoords[4], SkBlendMode bmode,
2714                          const SkPaint& paint) {
2715     TRACE_EVENT0("skia", TRACE_FUNC);
2716     if (nullptr == cubics) {
2717         return;
2718     }
2719 
2720     this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
2721 }
2722 
onDrawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode bmode,const SkPaint & paint)2723 void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2724                            const SkPoint texCoords[4], SkBlendMode bmode,
2725                            const SkPaint& paint) {
2726     // Since a patch is always within the convex hull of the control points, we discard it when its
2727     // bounding rectangle is completely outside the current clip.
2728     SkRect bounds;
2729     bounds.setBounds(cubics, SkPatchUtils::kNumCtrlPts);
2730     if (this->quickReject(bounds)) {
2731         return;
2732     }
2733 
2734     DRAW_BEGIN(paint, nullptr)
2735 
2736     while (iter.next()) {
2737         iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
2738     }
2739 
2740     DRAW_END
2741 }
2742 
drawDrawable(SkDrawable * dr,SkScalar x,SkScalar y)2743 void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2744 #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2745     TRACE_EVENT0("skia", TRACE_FUNC);
2746 #endif
2747     RETURN_ON_NULL(dr);
2748     if (x || y) {
2749         SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2750         this->onDrawDrawable(dr, &matrix);
2751     } else {
2752         this->onDrawDrawable(dr, nullptr);
2753     }
2754 }
2755 
drawDrawable(SkDrawable * dr,const SkMatrix * matrix)2756 void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2757 #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2758     TRACE_EVENT0("skia", TRACE_FUNC);
2759 #endif
2760     RETURN_ON_NULL(dr);
2761     if (matrix && matrix->isIdentity()) {
2762         matrix = nullptr;
2763     }
2764     this->onDrawDrawable(dr, matrix);
2765 }
2766 
onDrawDrawable(SkDrawable * dr,const SkMatrix * matrix)2767 void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2768     // drawable bounds are no longer reliable (e.g. android displaylist)
2769     // so don't use them for quick-reject
2770     this->getDevice()->drawDrawable(dr, matrix, this);
2771 }
2772 
onDrawAtlas(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkBlendMode bmode,const SkRect * cull,const SkPaint * paint)2773 void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2774                            const SkColor colors[], int count, SkBlendMode bmode,
2775                            const SkRect* cull, const SkPaint* paint) {
2776     if (cull && this->quickReject(*cull)) {
2777         return;
2778     }
2779 
2780     SkPaint pnt;
2781     if (paint) {
2782         pnt = *paint;
2783     }
2784 
2785     DRAW_BEGIN(pnt, nullptr)
2786     while (iter.next()) {
2787         iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
2788     }
2789     DRAW_END
2790 }
2791 
onDrawAnnotation(const SkRect & rect,const char key[],SkData * value)2792 void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2793     SkASSERT(key);
2794 
2795     SkPaint paint;
2796     DRAW_BEGIN(paint, nullptr)
2797     while (iter.next()) {
2798         iter.fDevice->drawAnnotation(rect, key, value);
2799     }
2800     DRAW_END
2801 }
2802 
onDrawEdgeAAQuad(const SkRect & r,const SkPoint clip[4],QuadAAFlags edgeAA,const SkColor4f & color,SkBlendMode mode)2803 void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2804                                 const SkColor4f& color, SkBlendMode mode) {
2805     SkASSERT(r.isSorted());
2806 
2807     // If this used a paint, it would be a filled color with blend mode, which does not
2808     // need to use an autodraw loop, so use SkDrawIter directly.
2809     if (this->quickReject(r)) {
2810         return;
2811     }
2812 
2813     this->predrawNotify(&r, nullptr, false);
2814     SkDrawIter iter(this);
2815     while(iter.next()) {
2816         iter.fDevice->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2817     }
2818 }
2819 
onDrawEdgeAAImageSet(const ImageSetEntry imageSet[],int count,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkPaint * paint,SrcRectConstraint constraint)2820 void SkCanvas::onDrawEdgeAAImageSet(const ImageSetEntry imageSet[], int count,
2821                                     const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2822                                     const SkPaint* paint, SrcRectConstraint constraint) {
2823     if (count <= 0) {
2824         // Nothing to draw
2825         return;
2826     }
2827 
2828     SkPaint realPaint;
2829     init_image_paint(&realPaint, paint);
2830 
2831     // We could calculate the set's dstRect union to always check quickReject(), but we can't reject
2832     // individual entries and Chromium's occlusion culling already makes it likely that at least one
2833     // entry will be visible. So, we only calculate the draw bounds when it's trivial (count == 1),
2834     // or we need it for the autolooper (since it greatly improves image filter perf).
2835     bool needsAutoLooper = needs_autodrawlooper(this, realPaint);
2836     bool setBoundsValid = count == 1 || needsAutoLooper;
2837     SkRect setBounds = imageSet[0].fDstRect;
2838     if (imageSet[0].fMatrixIndex >= 0) {
2839         // Account for the per-entry transform that is applied prior to the CTM when drawing
2840         preViewMatrices[imageSet[0].fMatrixIndex].mapRect(&setBounds);
2841     }
2842     if (needsAutoLooper) {
2843         for (int i = 1; i < count; ++i) {
2844             SkRect entryBounds = imageSet[i].fDstRect;
2845             if (imageSet[i].fMatrixIndex >= 0) {
2846                 preViewMatrices[imageSet[i].fMatrixIndex].mapRect(&entryBounds);
2847             }
2848             setBounds.joinPossiblyEmptyRect(entryBounds);
2849         }
2850     }
2851 
2852     // If we happen to have the draw bounds, though, might as well check quickReject().
2853     if (setBoundsValid && realPaint.canComputeFastBounds()) {
2854         SkRect tmp;
2855         if (this->quickReject(realPaint.computeFastBounds(setBounds, &tmp))) {
2856             return;
2857         }
2858     }
2859 
2860     if (needsAutoLooper) {
2861         SkASSERT(setBoundsValid);
2862         DRAW_BEGIN(realPaint, &setBounds)
2863         while (iter.next()) {
2864             iter.fDevice->drawEdgeAAImageSet(
2865                 imageSet, count, dstClips, preViewMatrices, draw.paint(), constraint);
2866         }
2867         DRAW_END
2868     } else {
2869         this->predrawNotify();
2870         SkDrawIter iter(this);
2871         while(iter.next()) {
2872             iter.fDevice->drawEdgeAAImageSet(
2873                 imageSet, count, dstClips, preViewMatrices, realPaint, constraint);
2874         }
2875     }
2876 }
2877 
2878 //////////////////////////////////////////////////////////////////////////////
2879 // These methods are NOT virtual, and therefore must call back into virtual
2880 // methods, rather than actually drawing themselves.
2881 //////////////////////////////////////////////////////////////////////////////
2882 
drawColor(SkColor c,SkBlendMode mode)2883 void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
2884     SkPaint paint;
2885     paint.setColor(c);
2886     paint.setBlendMode(mode);
2887     this->drawPaint(paint);
2888 }
2889 
drawPoint(SkScalar x,SkScalar y,const SkPaint & paint)2890 void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
2891     const SkPoint pt = { x, y };
2892     this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2893 }
2894 
drawLine(SkScalar x0,SkScalar y0,SkScalar x1,SkScalar y1,const SkPaint & paint)2895 void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
2896     SkPoint pts[2];
2897     pts[0].set(x0, y0);
2898     pts[1].set(x1, y1);
2899     this->drawPoints(kLines_PointMode, 2, pts, paint);
2900 }
2901 
drawCircle(SkScalar cx,SkScalar cy,SkScalar radius,const SkPaint & paint)2902 void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
2903     if (radius < 0) {
2904         radius = 0;
2905     }
2906 
2907     SkRect  r;
2908     r.setLTRB(cx - radius, cy - radius, cx + radius, cy + radius);
2909     this->drawOval(r, paint);
2910 }
2911 
drawRoundRect(const SkRect & r,SkScalar rx,SkScalar ry,const SkPaint & paint)2912 void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2913                              const SkPaint& paint) {
2914     if (rx > 0 && ry > 0) {
2915         SkRRect rrect;
2916         rrect.setRectXY(r, rx, ry);
2917         this->drawRRect(rrect, paint);
2918     } else {
2919         this->drawRect(r, paint);
2920     }
2921 }
2922 
drawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)2923 void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2924                        SkScalar sweepAngle, bool useCenter,
2925                        const SkPaint& paint) {
2926     TRACE_EVENT0("skia", TRACE_FUNC);
2927     if (oval.isEmpty() || !sweepAngle) {
2928         return;
2929     }
2930     this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
2931 }
2932 
2933 ///////////////////////////////////////////////////////////////////////////////
2934 #ifdef SK_DISABLE_SKPICTURE
drawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2935 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
2936 
2937 
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2938 void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2939                              const SkPaint* paint) {}
2940 #else
2941 /**
2942  *  This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2943  *  against the playback cost of recursing into the subpicture to get at its actual ops.
2944  *
2945  *  For now we pick a conservatively small value, though measurement (and other heuristics like
2946  *  the type of ops contained) may justify changing this value.
2947  */
2948 #define kMaxPictureOpsToUnrollInsteadOfRef  1
2949 
drawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2950 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
2951     TRACE_EVENT0("skia", TRACE_FUNC);
2952     RETURN_ON_NULL(picture);
2953 
2954     if (matrix && matrix->isIdentity()) {
2955         matrix = nullptr;
2956     }
2957     if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2958         SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2959         picture->playback(this);
2960     } else {
2961         this->onDrawPicture(picture, matrix, paint);
2962     }
2963 }
2964 
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2965 void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2966                              const SkPaint* paint) {
2967     if (!paint || paint->canComputeFastBounds()) {
2968         SkRect bounds = picture->cullRect();
2969         if (paint) {
2970             paint->computeFastBounds(bounds, &bounds);
2971         }
2972         if (matrix) {
2973             matrix->mapRect(&bounds);
2974         }
2975         if (this->quickReject(bounds)) {
2976             return;
2977         }
2978     }
2979 
2980     SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2981     picture->playback(this);
2982 }
2983 #endif
2984 
2985 ///////////////////////////////////////////////////////////////////////////////
2986 ///////////////////////////////////////////////////////////////////////////////
2987 
LayerIter(SkCanvas * canvas)2988 SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
2989     static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
2990 
2991     SkASSERT(canvas);
2992 
2993     fImpl = new (fStorage) SkDrawIter(canvas);
2994     fDone = !fImpl->next();
2995 }
2996 
~LayerIter()2997 SkCanvas::LayerIter::~LayerIter() {
2998     fImpl->~SkDrawIter();
2999 }
3000 
next()3001 void SkCanvas::LayerIter::next() {
3002     fDone = !fImpl->next();
3003 }
3004 
device() const3005 SkBaseDevice* SkCanvas::LayerIter::device() const {
3006     return fImpl->fDevice;
3007 }
3008 
matrix() const3009 const SkMatrix& SkCanvas::LayerIter::matrix() const {
3010     return fImpl->fDevice->ctm();
3011 }
3012 
paint() const3013 const SkPaint& SkCanvas::LayerIter::paint() const {
3014     const SkPaint* paint = fImpl->getPaint();
3015     if (nullptr == paint) {
3016         paint = &fDefaultPaint;
3017     }
3018     return *paint;
3019 }
3020 
clipBounds() const3021 SkIRect SkCanvas::LayerIter::clipBounds() const {
3022     return fImpl->fDevice->getGlobalBounds();
3023 }
3024 
x() const3025 int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
y() const3026 int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
3027 
3028 ///////////////////////////////////////////////////////////////////////////////
3029 
3030 SkCanvas::ImageSetEntry::ImageSetEntry() = default;
3031 SkCanvas::ImageSetEntry::~ImageSetEntry() = default;
3032 SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
3033 SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
3034 
ImageSetEntry(sk_sp<const SkImage> image,const SkRect & srcRect,const SkRect & dstRect,int matrixIndex,float alpha,unsigned aaFlags,bool hasClip)3035 SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
3036                                        const SkRect& dstRect, int matrixIndex, float alpha,
3037                                        unsigned aaFlags, bool hasClip)
3038                 : fImage(std::move(image))
3039                 , fSrcRect(srcRect)
3040                 , fDstRect(dstRect)
3041                 , fMatrixIndex(matrixIndex)
3042                 , fAlpha(alpha)
3043                 , fAAFlags(aaFlags)
3044                 , fHasClip(hasClip) {}
3045 
ImageSetEntry(sk_sp<const SkImage> image,const SkRect & srcRect,const SkRect & dstRect,float alpha,unsigned aaFlags)3046 SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
3047                                        const SkRect& dstRect, float alpha, unsigned aaFlags)
3048                 : fImage(std::move(image))
3049                 , fSrcRect(srcRect)
3050                 , fDstRect(dstRect)
3051                 , fAlpha(alpha)
3052                 , fAAFlags(aaFlags) {}
3053 
3054 ///////////////////////////////////////////////////////////////////////////////
3055 
MakeRasterDirect(const SkImageInfo & info,void * pixels,size_t rowBytes,const SkSurfaceProps * props)3056 std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3057                                                      size_t rowBytes, const SkSurfaceProps* props) {
3058     if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
3059         return nullptr;
3060     }
3061 
3062     SkBitmap bitmap;
3063     if (!bitmap.installPixels(info, pixels, rowBytes)) {
3064         return nullptr;
3065     }
3066 
3067     return props ?
3068         skstd::make_unique<SkCanvas>(bitmap, *props) :
3069         skstd::make_unique<SkCanvas>(bitmap);
3070 }
3071 
3072 ///////////////////////////////////////////////////////////////////////////////
3073 
SkNoDrawCanvas(int width,int height)3074 SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3075     : INHERITED(SkIRect::MakeWH(width, height)) {}
3076 
SkNoDrawCanvas(const SkIRect & bounds)3077 SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3078     : INHERITED(bounds) {}
3079 
SkNoDrawCanvas(sk_sp<SkBaseDevice> device)3080 SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
3081     : INHERITED(device) {}
3082 
getSaveLayerStrategy(const SaveLayerRec & rec)3083 SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3084     (void)this->INHERITED::getSaveLayerStrategy(rec);
3085     return kNoLayer_SaveLayerStrategy;
3086 }
3087 
onDoSaveBehind(const SkRect *)3088 bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
3089     return false;
3090 }
3091 
3092 ///////////////////////////////////////////////////////////////////////////////
3093 
3094 static_assert((int)SkRegion::kDifference_Op         == (int)kDifference_SkClipOp, "");
3095 static_assert((int)SkRegion::kIntersect_Op          == (int)kIntersect_SkClipOp, "");
3096 static_assert((int)SkRegion::kUnion_Op              == (int)kUnion_SkClipOp, "");
3097 static_assert((int)SkRegion::kXOR_Op                == (int)kXOR_SkClipOp, "");
3098 static_assert((int)SkRegion::kReverseDifference_Op  == (int)kReverseDifference_SkClipOp, "");
3099 static_assert((int)SkRegion::kReplace_Op            == (int)kReplace_SkClipOp, "");
3100 
3101 ///////////////////////////////////////////////////////////////////////////////////////////////////
3102 
accessTopRasterHandle() const3103 SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3104     if (fAllocator && fMCRec->fTopLayer->fDevice) {
3105         const auto& dev = fMCRec->fTopLayer->fDevice;
3106         SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3107         SkIPoint origin = dev->getOrigin();
3108         SkMatrix ctm = this->getTotalMatrix();
3109         ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3110 
3111         SkIRect clip = fMCRec->fRasterClip.getBounds();
3112         clip.offset(-origin.x(), -origin.y());
3113         if (!clip.intersect({0, 0, dev->width(), dev->height()})) {
3114             clip.setEmpty();
3115         }
3116 
3117         fAllocator->updateHandle(handle, ctm, clip);
3118         return handle;
3119     }
3120     return nullptr;
3121 }
3122 
install(SkBitmap * bm,const SkImageInfo & info,const SkRasterHandleAllocator::Rec & rec)3123 static bool install(SkBitmap* bm, const SkImageInfo& info,
3124                     const SkRasterHandleAllocator::Rec& rec) {
3125     return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
3126 }
3127 
allocBitmap(const SkImageInfo & info,SkBitmap * bm)3128 SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3129                                                                      SkBitmap* bm) {
3130     SkRasterHandleAllocator::Rec rec;
3131     if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3132         return nullptr;
3133     }
3134     return rec.fHandle;
3135 }
3136 
3137 std::unique_ptr<SkCanvas>
MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,const SkImageInfo & info,const Rec * rec)3138 SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3139                                     const SkImageInfo& info, const Rec* rec) {
3140     if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
3141         return nullptr;
3142     }
3143 
3144     SkBitmap bm;
3145     Handle hndl;
3146 
3147     if (rec) {
3148         hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3149     } else {
3150         hndl = alloc->allocBitmap(info, &bm);
3151     }
3152     return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3153 }
3154 
3155 ///////////////////////////////////////////////////////////////////////////////////////////////////
3156