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