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