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