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