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