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