SkCanvas.cpp revision 1a481fe4bf632ed4f76cb337691236fabfd4ab03
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 "SkCanvas.h"
9#include "SkCanvasDrawable.h"
10#include "SkCanvasPriv.h"
11#include "SkBitmapDevice.h"
12#include "SkDeviceImageFilterProxy.h"
13#include "SkDraw.h"
14#include "SkDrawFilter.h"
15#include "SkDrawLooper.h"
16#include "SkImage.h"
17#include "SkMetaData.h"
18#include "SkPathOps.h"
19#include "SkPatchUtils.h"
20#include "SkPicture.h"
21#include "SkRasterClip.h"
22#include "SkReadPixelsRec.h"
23#include "SkRRect.h"
24#include "SkSmallAllocator.h"
25#include "SkSurface_Base.h"
26#include "SkTemplates.h"
27#include "SkTextBlob.h"
28#include "SkTextFormatParams.h"
29#include "SkTLazy.h"
30#include "SkTraceEvent.h"
31#include "SkUtils.h"
32
33#if SK_SUPPORT_GPU
34#include "GrRenderTarget.h"
35#endif
36
37static bool gIgnoreSaveLayerBounds;
38void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
39    gIgnoreSaveLayerBounds = ignore;
40}
41bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
42    return gIgnoreSaveLayerBounds;
43}
44
45static bool gTreatSpriteAsBitmap;
46void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
47    gTreatSpriteAsBitmap = spriteAsBitmap;
48}
49bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
50    return gTreatSpriteAsBitmap;
51}
52
53// experimental for faster tiled drawing...
54//#define SK_ENABLE_CLIP_QUICKREJECT
55
56//#define SK_TRACE_SAVERESTORE
57
58#ifdef SK_TRACE_SAVERESTORE
59    static int gLayerCounter;
60    static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
61    static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
62
63    static int gRecCounter;
64    static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
65    static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
66
67    static int gCanvasCounter;
68    static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
69    static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
70#else
71    #define inc_layer()
72    #define dec_layer()
73    #define inc_rec()
74    #define dec_rec()
75    #define inc_canvas()
76    #define dec_canvas()
77#endif
78
79typedef SkTLazy<SkPaint> SkLazyPaint;
80
81void SkCanvas::predrawNotify() {
82    if (fSurfaceBase) {
83        fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode);
84    }
85}
86
87///////////////////////////////////////////////////////////////////////////////
88
89static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
90    const uint32_t propFlags = props.flags();
91    if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
92        flags &= ~SkPaint::kDither_Flag;
93    }
94    if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
95        flags &= ~SkPaint::kAntiAlias_Flag;
96    }
97    return flags;
98}
99
100///////////////////////////////////////////////////////////////////////////////
101
102/*  This is the record we keep for each SkBaseDevice that the user installs.
103    The clip/matrix/proc are fields that reflect the top of the save/restore
104    stack. Whenever the canvas changes, it marks a dirty flag, and then before
105    these are used (assuming we're not on a layer) we rebuild these cache
106    values: they reflect the top of the save stack, but translated and clipped
107    by the device's XY offset and bitmap-bounds.
108*/
109struct DeviceCM {
110    DeviceCM*           fNext;
111    SkBaseDevice*       fDevice;
112    SkRasterClip        fClip;
113    const SkMatrix*     fMatrix;
114    SkPaint*            fPaint; // may be null (in the future)
115
116    DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas,
117             bool conservativeRasterClip)
118        : fNext(NULL)
119        , fClip(conservativeRasterClip)
120    {
121        if (NULL != device) {
122            device->ref();
123            device->onAttachToCanvas(canvas);
124        }
125        fDevice = device;
126        fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
127    }
128
129    ~DeviceCM() {
130        if (fDevice) {
131            fDevice->onDetachFromCanvas();
132            fDevice->unref();
133        }
134        SkDELETE(fPaint);
135    }
136
137    void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
138                  const SkClipStack& clipStack, SkRasterClip* updateClip) {
139        int x = fDevice->getOrigin().x();
140        int y = fDevice->getOrigin().y();
141        int width = fDevice->width();
142        int height = fDevice->height();
143
144        if ((x | y) == 0) {
145            fMatrix = &totalMatrix;
146            fClip = totalClip;
147        } else {
148            fMatrixStorage = totalMatrix;
149            fMatrixStorage.postTranslate(SkIntToScalar(-x),
150                                         SkIntToScalar(-y));
151            fMatrix = &fMatrixStorage;
152
153            totalClip.translate(-x, -y, &fClip);
154        }
155
156        fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
157
158        // intersect clip, but don't translate it (yet)
159
160        if (updateClip) {
161            updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
162                           SkRegion::kDifference_Op);
163        }
164
165        fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
166
167#ifdef SK_DEBUG
168        if (!fClip.isEmpty()) {
169            SkIRect deviceR;
170            deviceR.set(0, 0, width, height);
171            SkASSERT(deviceR.contains(fClip.getBounds()));
172        }
173#endif
174    }
175
176private:
177    SkMatrix    fMatrixStorage;
178};
179
180/*  This is the record we keep for each save/restore level in the stack.
181    Since a level optionally copies the matrix and/or stack, we have pointers
182    for these fields. If the value is copied for this level, the copy is
183    stored in the ...Storage field, and the pointer points to that. If the
184    value is not copied for this level, we ignore ...Storage, and just point
185    at the corresponding value in the previous level in the stack.
186*/
187class SkCanvas::MCRec {
188public:
189    SkDrawFilter*   fFilter;    // the current filter (or null)
190    DeviceCM*       fLayer;
191    /*  If there are any layers in the stack, this points to the top-most
192        one that is at or below this level in the stack (so we know what
193        bitmap/device to draw into from this level. This value is NOT
194        reference counted, since the real owner is either our fLayer field,
195        or a previous one in a lower level.)
196    */
197    DeviceCM*       fTopLayer;
198    SkRasterClip    fRasterClip;
199    SkMatrix        fMatrix;
200    int             fDeferredSaveCount;
201
202    MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
203        fFilter     = NULL;
204        fLayer      = NULL;
205        fTopLayer   = NULL;
206        fMatrix.reset();
207        fDeferredSaveCount = 0;
208
209        // don't bother initializing fNext
210        inc_rec();
211    }
212    MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
213        fFilter = SkSafeRef(prev.fFilter);
214        fLayer = NULL;
215        fTopLayer = prev.fTopLayer;
216        fDeferredSaveCount = 0;
217
218        // don't bother initializing fNext
219        inc_rec();
220    }
221    ~MCRec() {
222        SkSafeUnref(fFilter);
223        SkDELETE(fLayer);
224        dec_rec();
225    }
226};
227
228class SkDrawIter : public SkDraw {
229public:
230    SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
231        canvas = canvas->canvasForDrawIter();
232        fCanvas = canvas;
233        canvas->updateDeviceCMCache();
234
235        fClipStack = &canvas->fClipStack;
236        fCurrLayer = canvas->fMCRec->fTopLayer;
237        fSkipEmptyClips = skipEmptyClips;
238    }
239
240    bool next() {
241        // skip over recs with empty clips
242        if (fSkipEmptyClips) {
243            while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
244                fCurrLayer = fCurrLayer->fNext;
245            }
246        }
247
248        const DeviceCM* rec = fCurrLayer;
249        if (rec && rec->fDevice) {
250
251            fMatrix = rec->fMatrix;
252            fClip   = &((SkRasterClip*)&rec->fClip)->forceGetBW();
253            fRC     = &rec->fClip;
254            fDevice = rec->fDevice;
255            fBitmap = &fDevice->accessBitmap(true);
256            fPaint  = rec->fPaint;
257            SkDEBUGCODE(this->validate();)
258
259            fCurrLayer = rec->fNext;
260            // fCurrLayer may be NULL now
261
262            return true;
263        }
264        return false;
265    }
266
267    SkBaseDevice* getDevice() const { return fDevice; }
268    int getX() const { return fDevice->getOrigin().x(); }
269    int getY() const { return fDevice->getOrigin().y(); }
270    const SkMatrix& getMatrix() const { return *fMatrix; }
271    const SkRegion& getClip() const { return *fClip; }
272    const SkPaint* getPaint() const { return fPaint; }
273
274private:
275    SkCanvas*       fCanvas;
276    const DeviceCM* fCurrLayer;
277    const SkPaint*  fPaint;     // May be null.
278    SkBool8         fSkipEmptyClips;
279
280    typedef SkDraw INHERITED;
281};
282
283/////////////////////////////////////////////////////////////////////////////
284
285class AutoDrawLooper {
286public:
287    AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
288                   bool skipLayerForImageFilter = false,
289                   const SkRect* bounds = NULL) : fOrigPaint(paint) {
290        fCanvas = canvas;
291        fFilter = canvas->getDrawFilter();
292        fPaint = &fOrigPaint;
293        fSaveCount = canvas->getSaveCount();
294        fDoClearImageFilter = false;
295        fDone = false;
296
297        if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
298            SkPaint tmp;
299            tmp.setImageFilter(fOrigPaint.getImageFilter());
300            (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
301                                            true, SkCanvas::kFullLayer_SaveLayerStrategy);
302            // we'll clear the imageFilter for the actual draws in next(), so
303            // it will only be applied during the restore().
304            fDoClearImageFilter = true;
305        }
306
307        if (SkDrawLooper* looper = paint.getLooper()) {
308            void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
309                    looper->contextSize());
310            fLooperContext = looper->createContext(canvas, buffer);
311            fIsSimple = false;
312        } else {
313            fLooperContext = NULL;
314            // can we be marked as simple?
315            fIsSimple = !fFilter && !fDoClearImageFilter;
316        }
317
318        uint32_t oldFlags = paint.getFlags();
319        fNewPaintFlags = filter_paint_flags(props, oldFlags);
320        if (fIsSimple && (fNewPaintFlags != oldFlags)) {
321            SkPaint* paint = fLazyPaint.set(fOrigPaint);
322            paint->setFlags(fNewPaintFlags);
323            fPaint = paint;
324            // if we're not simple, doNext() will take care of calling setFlags()
325        }
326    }
327
328    ~AutoDrawLooper() {
329        if (fDoClearImageFilter) {
330            fCanvas->internalRestore();
331        }
332        SkASSERT(fCanvas->getSaveCount() == fSaveCount);
333    }
334
335    const SkPaint& paint() const {
336        SkASSERT(fPaint);
337        return *fPaint;
338    }
339
340    bool next(SkDrawFilter::Type drawType) {
341        if (fDone) {
342            return false;
343        } else if (fIsSimple) {
344            fDone = true;
345            return !fPaint->nothingToDraw();
346        } else {
347            return this->doNext(drawType);
348        }
349    }
350
351private:
352    SkLazyPaint     fLazyPaint;
353    SkCanvas*       fCanvas;
354    const SkPaint&  fOrigPaint;
355    SkDrawFilter*   fFilter;
356    const SkPaint*  fPaint;
357    int             fSaveCount;
358    uint32_t        fNewPaintFlags;
359    bool            fDoClearImageFilter;
360    bool            fDone;
361    bool            fIsSimple;
362    SkDrawLooper::Context* fLooperContext;
363    SkSmallAllocator<1, 32> fLooperContextAllocator;
364
365    bool doNext(SkDrawFilter::Type drawType);
366};
367
368bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
369    fPaint = NULL;
370    SkASSERT(!fIsSimple);
371    SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
372
373    SkPaint* paint = fLazyPaint.set(fOrigPaint);
374    paint->setFlags(fNewPaintFlags);
375
376    if (fDoClearImageFilter) {
377        paint->setImageFilter(NULL);
378    }
379
380    if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
381        fDone = true;
382        return false;
383    }
384    if (fFilter) {
385        if (!fFilter->filter(paint, drawType)) {
386            fDone = true;
387            return false;
388        }
389        if (NULL == fLooperContext) {
390            // no looper means we only draw once
391            fDone = true;
392        }
393    }
394    fPaint = paint;
395
396    // if we only came in here for the imagefilter, mark us as done
397    if (!fLooperContext && !fFilter) {
398        fDone = true;
399    }
400
401    // call this after any possible paint modifiers
402    if (fPaint->nothingToDraw()) {
403        fPaint = NULL;
404        return false;
405    }
406    return true;
407}
408
409////////// macros to place around the internal draw calls //////////////////
410
411#define LOOPER_BEGIN_DRAWDEVICE(paint, type)                        \
412    this->predrawNotify();                                          \
413    AutoDrawLooper  looper(this, fProps, paint, true);              \
414    while (looper.next(type)) {                                     \
415        SkDrawIter          iter(this);
416
417#define LOOPER_BEGIN(paint, type, bounds)                           \
418    this->predrawNotify();                                          \
419    AutoDrawLooper  looper(this, fProps, paint, false, bounds);     \
420    while (looper.next(type)) {                                     \
421        SkDrawIter          iter(this);
422
423#define LOOPER_END    }
424
425////////////////////////////////////////////////////////////////////////////
426
427SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
428    fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
429    fCachedLocalClipBounds.setEmpty();
430    fCachedLocalClipBoundsDirty = true;
431    fAllowSoftClip = true;
432    fAllowSimplifyClip = false;
433    fDeviceCMDirty = true;
434    fSaveCount = 1;
435    fMetaData = NULL;
436
437    fMCRec = (MCRec*)fMCStack.push_back();
438    new (fMCRec) MCRec(fConservativeRasterClip);
439
440    fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL, fConservativeRasterClip));
441    fMCRec->fTopLayer = fMCRec->fLayer;
442
443    fSurfaceBase = NULL;
444
445    if (device) {
446        device->initForRootLayer(fProps.pixelGeometry());
447        if (device->forceConservativeRasterClip()) {
448            fConservativeRasterClip = true;
449        }
450        device->onAttachToCanvas(this);
451        fMCRec->fLayer->fDevice = SkRef(device);
452        fMCRec->fRasterClip.setRect(device->getGlobalBounds());
453    }
454    return device;
455}
456
457SkCanvas::SkCanvas()
458    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
459    , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
460{
461    inc_canvas();
462
463    this->init(NULL, kDefault_InitFlags);
464}
465
466static SkBitmap make_nopixels(int width, int height) {
467    SkBitmap bitmap;
468    bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
469    return bitmap;
470}
471
472class SkNoPixelsBitmapDevice : public SkBitmapDevice {
473public:
474    SkNoPixelsBitmapDevice(const SkIRect& bounds)
475        : INHERITED(make_nopixels(bounds.width(), bounds.height()))
476    {
477        this->setOrigin(bounds.x(), bounds.y());
478    }
479
480private:
481
482    typedef SkBitmapDevice INHERITED;
483};
484
485SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
486    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
487    , fProps(SkSurfacePropsCopyOrDefault(props))
488{
489    inc_canvas();
490
491    this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice,
492                          (SkIRect::MakeWH(width, height))), kDefault_InitFlags)->unref();
493}
494
495SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
496    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
497    , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
498{
499    inc_canvas();
500
501    this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (bounds)), flags)->unref();
502}
503
504SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
505    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
506    , fProps(SkSurfacePropsCopyOrDefault(props))
507{
508    inc_canvas();
509
510    this->init(device, flags);
511}
512
513SkCanvas::SkCanvas(SkBaseDevice* device)
514    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
515    , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
516{
517    inc_canvas();
518
519    this->init(device, kDefault_InitFlags);
520}
521
522SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
523    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
524    , fProps(props)
525{
526    inc_canvas();
527
528    SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
529    this->init(device, kDefault_InitFlags);
530}
531
532SkCanvas::SkCanvas(const SkBitmap& bitmap)
533    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
534    , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
535{
536    inc_canvas();
537
538    SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
539    this->init(device, kDefault_InitFlags);
540}
541
542SkCanvas::~SkCanvas() {
543    // free up the contents of our deque
544    this->restoreToCount(1);    // restore everything but the last
545
546    this->internalRestore();    // restore the last, since we're going away
547
548    SkDELETE(fMetaData);
549
550    dec_canvas();
551}
552
553SkDrawFilter* SkCanvas::getDrawFilter() const {
554    return fMCRec->fFilter;
555}
556
557SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
558    SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
559    return filter;
560}
561
562SkMetaData& SkCanvas::getMetaData() {
563    // metadata users are rare, so we lazily allocate it. If that changes we
564    // can decide to just make it a field in the device (rather than a ptr)
565    if (NULL == fMetaData) {
566        fMetaData = new SkMetaData;
567    }
568    return *fMetaData;
569}
570
571///////////////////////////////////////////////////////////////////////////////
572
573void SkCanvas::flush() {
574    SkBaseDevice* device = this->getDevice();
575    if (device) {
576        device->flush();
577    }
578}
579
580SkISize SkCanvas::getTopLayerSize() const {
581    SkBaseDevice* d = this->getTopDevice();
582    return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
583}
584
585SkIPoint SkCanvas::getTopLayerOrigin() const {
586    SkBaseDevice* d = this->getTopDevice();
587    return d ? d->getOrigin() : SkIPoint::Make(0, 0);
588}
589
590SkISize SkCanvas::getBaseLayerSize() const {
591    SkBaseDevice* d = this->getDevice();
592    return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
593}
594
595SkBaseDevice* SkCanvas::getDevice() const {
596    // return root device
597    MCRec* rec = (MCRec*) fMCStack.front();
598    SkASSERT(rec && rec->fLayer);
599    return rec->fLayer->fDevice;
600}
601
602SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
603    if (updateMatrixClip) {
604        const_cast<SkCanvas*>(this)->updateDeviceCMCache();
605    }
606    return fMCRec->fTopLayer->fDevice;
607}
608
609SkBaseDevice* SkCanvas::setRootDevice(SkBaseDevice* device) {
610    // return root device
611    SkDeque::F2BIter iter(fMCStack);
612    MCRec*           rec = (MCRec*)iter.next();
613    SkASSERT(rec && rec->fLayer);
614    SkBaseDevice*    rootDevice = rec->fLayer->fDevice;
615
616    if (rootDevice == device) {
617        return device;
618    }
619
620    if (device) {
621        device->onAttachToCanvas(this);
622        device->initForRootLayer(fProps.pixelGeometry());
623    }
624    if (rootDevice) {
625        rootDevice->onDetachFromCanvas();
626    }
627
628    SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
629    rootDevice = device;
630
631    fDeviceCMDirty = true;
632
633    /*  Now we update our initial region to have the bounds of the new device,
634        and then intersect all of the clips in our stack with these bounds,
635        to ensure that we can't draw outside of the device's bounds (and trash
636                                                                     memory).
637
638    NOTE: this is only a partial-fix, since if the new device is larger than
639        the previous one, we don't know how to "enlarge" the clips in our stack,
640        so drawing may be artificially restricted. Without keeping a history of
641        all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
642        reconstruct the correct clips, so this approximation will have to do.
643        The caller really needs to restore() back to the base if they want to
644        accurately take advantage of the new device bounds.
645    */
646
647    SkIRect bounds;
648    if (device) {
649        bounds.set(0, 0, device->width(), device->height());
650    } else {
651        bounds.setEmpty();
652    }
653    // now jam our 1st clip to be bounds, and intersect the rest with that
654    rec->fRasterClip.setRect(bounds);
655    while ((rec = (MCRec*)iter.next()) != NULL) {
656        (void)rec->fRasterClip.op(bounds, SkRegion::kIntersect_Op);
657    }
658
659    return device;
660}
661
662bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
663    if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
664        return false;
665    }
666
667    bool weAllocated = false;
668    if (NULL == bitmap->pixelRef()) {
669        if (!bitmap->tryAllocPixels()) {
670            return false;
671        }
672        weAllocated = true;
673    }
674
675    SkBitmap bm(*bitmap);
676    bm.lockPixels();
677    if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
678        return true;
679    }
680
681    if (weAllocated) {
682        bitmap->setPixelRef(NULL);
683    }
684    return false;
685}
686
687bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
688    SkIRect r = srcRect;
689    const SkISize size = this->getBaseLayerSize();
690    if (!r.intersect(0, 0, size.width(), size.height())) {
691        bitmap->reset();
692        return false;
693    }
694
695    if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
696        // bitmap will already be reset.
697        return false;
698    }
699    if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
700        bitmap->reset();
701        return false;
702    }
703    return true;
704}
705
706bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
707    SkBaseDevice* device = this->getDevice();
708    if (!device) {
709        return false;
710    }
711    const SkISize size = this->getBaseLayerSize();
712
713    SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
714    if (!rec.trim(size.width(), size.height())) {
715        return false;
716    }
717
718    // The device can assert that the requested area is always contained in its bounds
719    return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
720}
721
722bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
723    if (bitmap.getTexture()) {
724        return false;
725    }
726    SkBitmap bm(bitmap);
727    bm.lockPixels();
728    if (bm.getPixels()) {
729        return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
730    }
731    return false;
732}
733
734bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
735                           int x, int y) {
736    switch (origInfo.colorType()) {
737        case kUnknown_SkColorType:
738        case kIndex_8_SkColorType:
739            return false;
740        default:
741            break;
742    }
743    if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
744        return false;
745    }
746
747    const SkISize size = this->getBaseLayerSize();
748    SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
749    if (!target.intersect(0, 0, size.width(), size.height())) {
750        return false;
751    }
752
753    SkBaseDevice* device = this->getDevice();
754    if (!device) {
755        return false;
756    }
757
758    // the intersect may have shrunk info's logical size
759    const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
760
761    // if x or y are negative, then we have to adjust pixels
762    if (x > 0) {
763        x = 0;
764    }
765    if (y > 0) {
766        y = 0;
767    }
768    // here x,y are either 0 or negative
769    pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
770
771    // Tell our owning surface to bump its generation ID
772    this->predrawNotify();
773
774    // The device can assert that the requested area is always contained in its bounds
775    return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
776}
777
778SkCanvas* SkCanvas::canvasForDrawIter() {
779    return this;
780}
781
782//////////////////////////////////////////////////////////////////////////////
783
784void SkCanvas::updateDeviceCMCache() {
785    if (fDeviceCMDirty) {
786        const SkMatrix& totalMatrix = this->getTotalMatrix();
787        const SkRasterClip& totalClip = fMCRec->fRasterClip;
788        DeviceCM*       layer = fMCRec->fTopLayer;
789
790        if (NULL == layer->fNext) {   // only one layer
791            layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
792        } else {
793            SkRasterClip clip(totalClip);
794            do {
795                layer->updateMC(totalMatrix, clip, fClipStack, &clip);
796            } while ((layer = layer->fNext) != NULL);
797        }
798        fDeviceCMDirty = false;
799    }
800}
801
802///////////////////////////////////////////////////////////////////////////////
803
804void SkCanvas::checkForDeferredSave() {
805    if (fMCRec->fDeferredSaveCount > 0) {
806        fMCRec->fDeferredSaveCount -= 1;
807        this->doSave();
808    }
809}
810
811int SkCanvas::getSaveCount() const {
812#ifdef SK_DEBUG
813    int count = 0;
814    SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
815    for (;;) {
816        const MCRec* rec = (const MCRec*)iter.next();
817        if (!rec) {
818            break;
819        }
820        count += 1 + rec->fDeferredSaveCount;
821    }
822    SkASSERT(count == fSaveCount);
823#endif
824    return fSaveCount;
825}
826
827int SkCanvas::save() {
828    fSaveCount += 1;
829    fMCRec->fDeferredSaveCount += 1;
830    return this->getSaveCount() - 1;  // return our prev value
831}
832
833void SkCanvas::doSave() {
834    this->willSave();
835    this->internalSave();
836}
837
838void SkCanvas::restore() {
839    if (fMCRec->fDeferredSaveCount > 0) {
840        SkASSERT(fSaveCount > 1);
841        fSaveCount -= 1;
842        fMCRec->fDeferredSaveCount -= 1;
843    } else {
844        // check for underflow
845        if (fMCStack.count() > 1) {
846            this->willRestore();
847            SkASSERT(fSaveCount > 1);
848            fSaveCount -= 1;
849            this->internalRestore();
850            this->didRestore();
851        }
852    }
853}
854
855void SkCanvas::restoreToCount(int count) {
856    // sanity check
857    if (count < 1) {
858        count = 1;
859    }
860
861    int n = this->getSaveCount() - count;
862    for (int i = 0; i < n; ++i) {
863        this->restore();
864    }
865}
866
867void SkCanvas::internalSave() {
868    MCRec* newTop = (MCRec*)fMCStack.push_back();
869    new (newTop) MCRec(*fMCRec);    // balanced in restore()
870    fMCRec = newTop;
871
872    fClipStack.save();
873}
874
875static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
876#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
877    return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
878#else
879    return true;
880#endif
881}
882
883bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
884                               SkIRect* intersection, const SkImageFilter* imageFilter) {
885    SkIRect clipBounds;
886    SkRegion::Op op = SkRegion::kIntersect_Op;
887    if (!this->getClipDeviceBounds(&clipBounds)) {
888        return false;
889    }
890
891    if (imageFilter) {
892        imageFilter->filterBounds(clipBounds, fMCRec->fMatrix, &clipBounds);
893        // Filters may grow the bounds beyond the device bounds.
894        op = SkRegion::kReplace_Op;
895    }
896    SkIRect ir;
897    if (bounds) {
898        SkRect r;
899
900        this->getTotalMatrix().mapRect(&r, *bounds);
901        r.roundOut(&ir);
902        // early exit if the layer's bounds are clipped out
903        if (!ir.intersect(clipBounds)) {
904            if (bounds_affects_clip(flags)) {
905                fMCRec->fRasterClip.setEmpty();
906            }
907            return false;
908        }
909    } else {    // no user bounds, so just use the clip
910        ir = clipBounds;
911    }
912
913    if (bounds_affects_clip(flags)) {
914        fClipStack.clipDevRect(ir, op);
915        // early exit if the clip is now empty
916        if (!fMCRec->fRasterClip.op(ir, op)) {
917            return false;
918        }
919    }
920
921    if (intersection) {
922        *intersection = ir;
923    }
924    return true;
925}
926
927int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
928    if (gIgnoreSaveLayerBounds) {
929        bounds = NULL;
930    }
931    SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
932    fSaveCount += 1;
933    this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, false, strategy);
934    return this->getSaveCount() - 1;
935}
936
937int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
938    if (gIgnoreSaveLayerBounds) {
939        bounds = NULL;
940    }
941    SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
942    fSaveCount += 1;
943    this->internalSaveLayer(bounds, paint, flags, false, strategy);
944    return this->getSaveCount() - 1;
945}
946
947void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
948                                bool justForImageFilter, SaveLayerStrategy strategy) {
949#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
950    flags |= kClipToLayer_SaveFlag;
951#endif
952
953    // do this before we create the layer. We don't call the public save() since
954    // that would invoke a possibly overridden virtual
955    this->internalSave();
956
957    fDeviceCMDirty = true;
958
959    SkIRect ir;
960    if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
961        return;
962    }
963
964    // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
965    // the clipRectBounds() call above?
966    if (kNoLayer_SaveLayerStrategy == strategy) {
967        return;
968    }
969
970    // Kill the imagefilter if our device doesn't allow it
971    SkLazyPaint lazyP;
972    if (paint && paint->getImageFilter()) {
973        if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
974            if (justForImageFilter) {
975                // early exit if the layer was just for the imageFilter
976                return;
977            }
978            SkPaint* p = lazyP.set(*paint);
979            p->setImageFilter(NULL);
980            paint = p;
981        }
982    }
983
984    bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
985    SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
986                        isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
987
988    SkBaseDevice* device = this->getTopDevice();
989    if (NULL == device) {
990        SkDebugf("Unable to find device for layer.");
991        return;
992    }
993
994    SkBaseDevice::Usage usage = SkBaseDevice::kSaveLayer_Usage;
995    if (paint && paint->getImageFilter()) {
996        usage = SkBaseDevice::kImageFilter_Usage;
997    }
998    device = device->onCreateCompatibleDevice(SkBaseDevice::CreateInfo(info, usage,
999                                                                       fProps.pixelGeometry()));
1000    if (NULL == device) {
1001        SkDebugf("Unable to create device for layer.");
1002        return;
1003    }
1004
1005    device->setOrigin(ir.fLeft, ir.fTop);
1006    DeviceCM* layer = SkNEW_ARGS(DeviceCM,
1007                                 (device, ir.fLeft, ir.fTop, paint, this, fConservativeRasterClip));
1008    device->unref();
1009
1010    layer->fNext = fMCRec->fTopLayer;
1011    fMCRec->fLayer = layer;
1012    fMCRec->fTopLayer = layer;    // this field is NOT an owner of layer
1013}
1014
1015int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1016    return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1017}
1018
1019int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1020                             SaveFlags flags) {
1021    if (0xFF == alpha) {
1022        return this->saveLayer(bounds, NULL, flags);
1023    } else {
1024        SkPaint tmpPaint;
1025        tmpPaint.setAlpha(alpha);
1026        return this->saveLayer(bounds, &tmpPaint, flags);
1027    }
1028}
1029
1030void SkCanvas::internalRestore() {
1031    SkASSERT(fMCStack.count() != 0);
1032
1033    fDeviceCMDirty = true;
1034    fCachedLocalClipBoundsDirty = true;
1035
1036    fClipStack.restore();
1037
1038    // reserve our layer (if any)
1039    DeviceCM* layer = fMCRec->fLayer;   // may be null
1040    // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1041    fMCRec->fLayer = NULL;
1042
1043    // now do the normal restore()
1044    fMCRec->~MCRec();       // balanced in save()
1045    fMCStack.pop_back();
1046    fMCRec = (MCRec*)fMCStack.back();
1047
1048    /*  Time to draw the layer's offscreen. We can't call the public drawSprite,
1049        since if we're being recorded, we don't want to record this (the
1050        recorder will have already recorded the restore).
1051    */
1052    if (layer) {
1053        if (layer->fNext) {
1054            const SkIPoint& origin = layer->fDevice->getOrigin();
1055            this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
1056                                     layer->fPaint);
1057            // reset this, since internalDrawDevice will have set it to true
1058            fDeviceCMDirty = true;
1059        }
1060        SkDELETE(layer);
1061    }
1062}
1063
1064SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1065    if (NULL == props) {
1066        props = &fProps;
1067    }
1068    return this->onNewSurface(info, *props);
1069}
1070
1071SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1072    SkBaseDevice* dev = this->getDevice();
1073    return dev ? dev->newSurface(info, props) : NULL;
1074}
1075
1076SkImageInfo SkCanvas::imageInfo() const {
1077    SkBaseDevice* dev = this->getDevice();
1078    if (dev) {
1079        return dev->imageInfo();
1080    } else {
1081        return SkImageInfo::MakeUnknown(0, 0);
1082    }
1083}
1084
1085const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1086    return this->onPeekPixels(info, rowBytes);
1087}
1088
1089const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1090    SkBaseDevice* dev = this->getDevice();
1091    return dev ? dev->peekPixels(info, rowBytes) : NULL;
1092}
1093
1094void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1095    void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1096    if (pixels && origin) {
1097        *origin = this->getTopDevice(false)->getOrigin();
1098    }
1099    return pixels;
1100}
1101
1102void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1103    SkBaseDevice* dev = this->getTopDevice();
1104    return dev ? dev->accessPixels(info, rowBytes) : NULL;
1105}
1106
1107SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1108    fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1109    if (NULL == fAddr) {
1110        fInfo = canvas->imageInfo();
1111        if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
1112            return; // failure, fAddr is NULL
1113        }
1114        if (!canvas->readPixels(&fBitmap, 0, 0)) {
1115            return; // failure, fAddr is NULL
1116        }
1117        fAddr = fBitmap.getPixels();
1118        fRowBytes = fBitmap.rowBytes();
1119    }
1120    SkASSERT(fAddr);    // success
1121}
1122
1123bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1124    if (fAddr) {
1125        return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
1126    } else {
1127        bitmap->reset();
1128        return false;
1129    }
1130}
1131
1132/////////////////////////////////////////////////////////////////////////////
1133void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
1134                                const SkMatrix& matrix, const SkPaint* paint) {
1135    if (bitmap.drawsNothing()) {
1136        return;
1137    }
1138
1139    SkLazyPaint lazy;
1140    if (NULL == paint) {
1141        paint = lazy.init();
1142    }
1143
1144    SkDEBUGCODE(bitmap.validate();)
1145
1146    SkRect storage;
1147    const SkRect* bounds = NULL;
1148    if (paint && paint->canComputeFastBounds()) {
1149        bitmap.getBounds(&storage);
1150        matrix.mapRect(&storage);
1151        bounds = &paint->computeFastBounds(storage, &storage);
1152    }
1153
1154    LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
1155
1156    while (iter.next()) {
1157        iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1158    }
1159
1160    LOOPER_END
1161}
1162
1163void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
1164                                  const SkPaint* paint) {
1165    SkPaint tmp;
1166    if (NULL == paint) {
1167        paint = &tmp;
1168    }
1169
1170    LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
1171    while (iter.next()) {
1172        SkBaseDevice* dstDev = iter.fDevice;
1173        paint = &looper.paint();
1174        SkImageFilter* filter = paint->getImageFilter();
1175        SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1176        if (filter && !dstDev->canHandleImageFilter(filter)) {
1177            SkDeviceImageFilterProxy proxy(dstDev, fProps);
1178            SkBitmap dst;
1179            SkIPoint offset = SkIPoint::Make(0, 0);
1180            const SkBitmap& src = srcDev->accessBitmap(false);
1181            SkMatrix matrix = *iter.fMatrix;
1182            matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
1183            SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
1184            SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
1185            SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
1186            if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
1187                SkPaint tmpUnfiltered(*paint);
1188                tmpUnfiltered.setImageFilter(NULL);
1189                dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1190                                   tmpUnfiltered);
1191            }
1192        } else {
1193            dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
1194        }
1195    }
1196    LOOPER_END
1197}
1198
1199void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
1200    if (gTreatSpriteAsBitmap) {
1201        this->save();
1202        this->resetMatrix();
1203        this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1204        this->restore();
1205        return;
1206    }
1207
1208    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
1209    if (bitmap.drawsNothing()) {
1210        return;
1211    }
1212    SkDEBUGCODE(bitmap.validate();)
1213
1214    SkPaint tmp;
1215    if (NULL == paint) {
1216        paint = &tmp;
1217    }
1218
1219    LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
1220
1221    while (iter.next()) {
1222        paint = &looper.paint();
1223        SkImageFilter* filter = paint->getImageFilter();
1224        SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1225        if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
1226            SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
1227            SkBitmap dst;
1228            SkIPoint offset = SkIPoint::Make(0, 0);
1229            SkMatrix matrix = *iter.fMatrix;
1230            matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
1231            const SkIRect clipBounds = bitmap.bounds();
1232            SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
1233            SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
1234            if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
1235                SkPaint tmpUnfiltered(*paint);
1236                tmpUnfiltered.setImageFilter(NULL);
1237                iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1238                                         tmpUnfiltered);
1239            }
1240        } else {
1241            iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1242        }
1243    }
1244    LOOPER_END
1245}
1246
1247/////////////////////////////////////////////////////////////////////////////
1248void SkCanvas::translate(SkScalar dx, SkScalar dy) {
1249    SkMatrix m;
1250    m.setTranslate(dx, dy);
1251    this->concat(m);
1252}
1253
1254void SkCanvas::scale(SkScalar sx, SkScalar sy) {
1255    SkMatrix m;
1256    m.setScale(sx, sy);
1257    this->concat(m);
1258}
1259
1260void SkCanvas::rotate(SkScalar degrees) {
1261    SkMatrix m;
1262    m.setRotate(degrees);
1263    this->concat(m);
1264}
1265
1266void SkCanvas::skew(SkScalar sx, SkScalar sy) {
1267    SkMatrix m;
1268    m.setSkew(sx, sy);
1269    this->concat(m);
1270}
1271
1272void SkCanvas::concat(const SkMatrix& matrix) {
1273    if (matrix.isIdentity()) {
1274        return;
1275    }
1276
1277    this->checkForDeferredSave();
1278    fDeviceCMDirty = true;
1279    fCachedLocalClipBoundsDirty = true;
1280    fMCRec->fMatrix.preConcat(matrix);
1281
1282    this->didConcat(matrix);
1283}
1284
1285void SkCanvas::setMatrix(const SkMatrix& matrix) {
1286    this->checkForDeferredSave();
1287    fDeviceCMDirty = true;
1288    fCachedLocalClipBoundsDirty = true;
1289    fMCRec->fMatrix = matrix;
1290    this->didSetMatrix(matrix);
1291}
1292
1293void SkCanvas::resetMatrix() {
1294    SkMatrix matrix;
1295
1296    matrix.reset();
1297    this->setMatrix(matrix);
1298}
1299
1300//////////////////////////////////////////////////////////////////////////////
1301
1302void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
1303    this->checkForDeferredSave();
1304    ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1305    this->onClipRect(rect, op, edgeStyle);
1306}
1307
1308void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1309#ifdef SK_ENABLE_CLIP_QUICKREJECT
1310    if (SkRegion::kIntersect_Op == op) {
1311        if (fMCRec->fRasterClip.isEmpty()) {
1312            return false;
1313        }
1314
1315        if (this->quickReject(rect)) {
1316            fDeviceCMDirty = true;
1317            fCachedLocalClipBoundsDirty = true;
1318
1319            fClipStack.clipEmpty();
1320            return fMCRec->fRasterClip.setEmpty();
1321        }
1322    }
1323#endif
1324
1325    AutoValidateClip avc(this);
1326
1327    fDeviceCMDirty = true;
1328    fCachedLocalClipBoundsDirty = true;
1329    if (!fAllowSoftClip) {
1330        edgeStyle = kHard_ClipEdgeStyle;
1331    }
1332
1333    if (fMCRec->fMatrix.rectStaysRect()) {
1334        // for these simpler matrices, we can stay a rect even after applying
1335        // the matrix. This means we don't have to a) make a path, and b) tell
1336        // the region code to scan-convert the path, only to discover that it
1337        // is really just a rect.
1338        SkRect      r;
1339
1340        fMCRec->fMatrix.mapRect(&r, rect);
1341        fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
1342        fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
1343    } else {
1344        // since we're rotated or some such thing, we convert the rect to a path
1345        // and clip against that, since it can handle any matrix. However, to
1346        // avoid recursion in the case where we are subclassed (e.g. Pictures)
1347        // we explicitly call "our" version of clipPath.
1348        SkPath  path;
1349
1350        path.addRect(rect);
1351        this->SkCanvas::onClipPath(path, op, edgeStyle);
1352    }
1353}
1354
1355static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1356                            SkRegion::Op op, bool doAA) {
1357    rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
1358}
1359
1360void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
1361    this->checkForDeferredSave();
1362    ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1363    if (rrect.isRect()) {
1364        this->onClipRect(rrect.getBounds(), op, edgeStyle);
1365    } else {
1366        this->onClipRRect(rrect, op, edgeStyle);
1367    }
1368}
1369
1370void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1371    SkRRect transformedRRect;
1372    if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
1373        AutoValidateClip avc(this);
1374
1375        fDeviceCMDirty = true;
1376        fCachedLocalClipBoundsDirty = true;
1377        if (!fAllowSoftClip) {
1378            edgeStyle = kHard_ClipEdgeStyle;
1379        }
1380
1381        fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
1382
1383        SkPath devPath;
1384        devPath.addRRect(transformedRRect);
1385
1386        rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
1387        return;
1388    }
1389
1390    SkPath path;
1391    path.addRRect(rrect);
1392    // call the non-virtual version
1393    this->SkCanvas::onClipPath(path, op, edgeStyle);
1394}
1395
1396void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
1397    this->checkForDeferredSave();
1398    ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1399    SkRect r;
1400    if (!path.isInverseFillType() && path.isRect(&r)) {
1401        this->onClipRect(r, op, edgeStyle);
1402    } else {
1403        this->onClipPath(path, op, edgeStyle);
1404    }
1405}
1406
1407void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1408#ifdef SK_ENABLE_CLIP_QUICKREJECT
1409    if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
1410        if (fMCRec->fRasterClip.isEmpty()) {
1411            return false;
1412        }
1413
1414        if (this->quickReject(path.getBounds())) {
1415            fDeviceCMDirty = true;
1416            fCachedLocalClipBoundsDirty = true;
1417
1418            fClipStack.clipEmpty();
1419            return fMCRec->fRasterClip.setEmpty();
1420        }
1421    }
1422#endif
1423
1424    AutoValidateClip avc(this);
1425
1426    fDeviceCMDirty = true;
1427    fCachedLocalClipBoundsDirty = true;
1428    if (!fAllowSoftClip) {
1429        edgeStyle = kHard_ClipEdgeStyle;
1430    }
1431
1432    SkPath devPath;
1433    path.transform(fMCRec->fMatrix, &devPath);
1434
1435    // Check if the transfomation, or the original path itself
1436    // made us empty. Note this can also happen if we contained NaN
1437    // values. computing the bounds detects this, and will set our
1438    // bounds to empty if that is the case. (see SkRect::set(pts, count))
1439    if (devPath.getBounds().isEmpty()) {
1440        // resetting the path will remove any NaN or other wanky values
1441        // that might upset our scan converter.
1442        devPath.reset();
1443    }
1444
1445    // if we called path.swap() we could avoid a deep copy of this path
1446    fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
1447
1448    if (fAllowSimplifyClip) {
1449        bool clipIsAA = getClipStack()->asPath(&devPath);
1450        if (clipIsAA) {
1451            edgeStyle = kSoft_ClipEdgeStyle;
1452        }
1453
1454        op = SkRegion::kReplace_Op;
1455    }
1456
1457    rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
1458}
1459
1460void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
1461    this->checkForDeferredSave();
1462    this->onClipRegion(rgn, op);
1463}
1464
1465void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
1466    AutoValidateClip avc(this);
1467
1468    fDeviceCMDirty = true;
1469    fCachedLocalClipBoundsDirty = true;
1470
1471    // todo: signal fClipStack that we have a region, and therefore (I guess)
1472    // we have to ignore it, and use the region directly?
1473    fClipStack.clipDevRect(rgn.getBounds(), op);
1474
1475    fMCRec->fRasterClip.op(rgn, op);
1476}
1477
1478#ifdef SK_DEBUG
1479void SkCanvas::validateClip() const {
1480    // construct clipRgn from the clipstack
1481    const SkBaseDevice* device = this->getDevice();
1482    if (!device) {
1483        SkASSERT(this->isClipEmpty());
1484        return;
1485    }
1486
1487    SkIRect ir;
1488    ir.set(0, 0, device->width(), device->height());
1489    SkRasterClip tmpClip(ir, fConservativeRasterClip);
1490
1491    SkClipStack::B2TIter                iter(fClipStack);
1492    const SkClipStack::Element* element;
1493    while ((element = iter.next()) != NULL) {
1494        switch (element->getType()) {
1495            case SkClipStack::Element::kRect_Type:
1496                element->getRect().round(&ir);
1497                tmpClip.op(ir, element->getOp());
1498                break;
1499            case SkClipStack::Element::kEmpty_Type:
1500                tmpClip.setEmpty();
1501                break;
1502            default: {
1503                SkPath path;
1504                element->asPath(&path);
1505                rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
1506                break;
1507            }
1508        }
1509    }
1510}
1511#endif
1512
1513void SkCanvas::replayClips(ClipVisitor* visitor) const {
1514    SkClipStack::B2TIter                iter(fClipStack);
1515    const SkClipStack::Element*         element;
1516
1517    while ((element = iter.next()) != NULL) {
1518        element->replay(visitor);
1519    }
1520}
1521
1522///////////////////////////////////////////////////////////////////////////////
1523
1524bool SkCanvas::isClipEmpty() const {
1525    return fMCRec->fRasterClip.isEmpty();
1526}
1527
1528bool SkCanvas::isClipRect() const {
1529    return fMCRec->fRasterClip.isRect();
1530}
1531
1532bool SkCanvas::quickReject(const SkRect& rect) const {
1533    if (!rect.isFinite())
1534        return true;
1535
1536    if (fMCRec->fRasterClip.isEmpty()) {
1537        return true;
1538    }
1539
1540    if (fMCRec->fMatrix.hasPerspective()) {
1541        SkRect dst;
1542        fMCRec->fMatrix.mapRect(&dst, rect);
1543        return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
1544    } else {
1545        const SkRect& clipR = this->getLocalClipBounds();
1546
1547        // for speed, do the most likely reject compares first
1548        // TODO: should we use | instead, or compare all 4 at once?
1549        if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
1550            return true;
1551        }
1552        if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
1553            return true;
1554        }
1555        return false;
1556    }
1557}
1558
1559bool SkCanvas::quickReject(const SkPath& path) const {
1560    return path.isEmpty() || this->quickReject(path.getBounds());
1561}
1562
1563bool SkCanvas::getClipBounds(SkRect* bounds) const {
1564    SkIRect ibounds;
1565    if (!this->getClipDeviceBounds(&ibounds)) {
1566        return false;
1567    }
1568
1569    SkMatrix inverse;
1570    // if we can't invert the CTM, we can't return local clip bounds
1571    if (!fMCRec->fMatrix.invert(&inverse)) {
1572        if (bounds) {
1573            bounds->setEmpty();
1574        }
1575        return false;
1576    }
1577
1578    if (bounds) {
1579        SkRect r;
1580        // adjust it outwards in case we are antialiasing
1581        const int inset = 1;
1582
1583        r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1584               ibounds.fRight + inset, ibounds.fBottom + inset);
1585        inverse.mapRect(bounds, r);
1586    }
1587    return true;
1588}
1589
1590bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
1591    const SkRasterClip& clip = fMCRec->fRasterClip;
1592    if (clip.isEmpty()) {
1593        if (bounds) {
1594            bounds->setEmpty();
1595        }
1596        return false;
1597    }
1598
1599    if (bounds) {
1600        *bounds = clip.getBounds();
1601    }
1602    return true;
1603}
1604
1605const SkMatrix& SkCanvas::getTotalMatrix() const {
1606    return fMCRec->fMatrix;
1607}
1608
1609const SkRegion& SkCanvas::internal_private_getTotalClip() const {
1610    return fMCRec->fRasterClip.forceGetBW();
1611}
1612
1613GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1614    SkBaseDevice* dev = this->getTopDevice();
1615    return dev ? dev->accessRenderTarget() : NULL;
1616}
1617
1618GrContext* SkCanvas::getGrContext() {
1619#if SK_SUPPORT_GPU
1620    SkBaseDevice* device = this->getTopDevice();
1621    if (device) {
1622        GrRenderTarget* renderTarget = device->accessRenderTarget();
1623        if (renderTarget) {
1624            return renderTarget->getContext();
1625        }
1626    }
1627#endif
1628
1629    return NULL;
1630
1631}
1632
1633void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1634                          const SkPaint& paint) {
1635    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
1636    if (outer.isEmpty()) {
1637        return;
1638    }
1639    if (inner.isEmpty()) {
1640        this->drawRRect(outer, paint);
1641        return;
1642    }
1643
1644    // We don't have this method (yet), but technically this is what we should
1645    // be able to assert...
1646    // SkASSERT(outer.contains(inner));
1647    //
1648    // For now at least check for containment of bounds
1649    SkASSERT(outer.getBounds().contains(inner.getBounds()));
1650
1651    this->onDrawDRRect(outer, inner, paint);
1652}
1653
1654// These need to stop being virtual -- clients need to override the onDraw... versions
1655
1656void SkCanvas::drawPaint(const SkPaint& paint) {
1657    this->onDrawPaint(paint);
1658}
1659
1660void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1661    this->onDrawRect(r, paint);
1662}
1663
1664void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1665    this->onDrawOval(r, paint);
1666}
1667
1668void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1669    this->onDrawRRect(rrect, paint);
1670}
1671
1672void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1673    this->onDrawPoints(mode, count, pts, paint);
1674}
1675
1676void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1677                            const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1678                            const uint16_t indices[], int indexCount, const SkPaint& paint) {
1679    this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1680                         indices, indexCount, paint);
1681}
1682
1683void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1684    this->onDrawPath(path, paint);
1685}
1686
1687void SkCanvas::drawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1688    this->onDrawImage(image, dx, dy, paint);
1689}
1690
1691void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1692                             const SkPaint* paint) {
1693    this->onDrawImageRect(image, src, dst, paint);
1694}
1695
1696void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1697    this->onDrawBitmap(bitmap, dx, dy, paint);
1698}
1699
1700void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1701                                    const SkPaint* paint, DrawBitmapRectFlags flags) {
1702    this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1703}
1704
1705void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1706                              const SkPaint* paint) {
1707    this->onDrawBitmapNine(bitmap, center, dst, paint);
1708}
1709
1710void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
1711    this->onDrawSprite(bitmap, left, top, paint);
1712}
1713
1714//////////////////////////////////////////////////////////////////////////////
1715//  These are the virtual drawing methods
1716//////////////////////////////////////////////////////////////////////////////
1717
1718void SkCanvas::onDiscard() {
1719    if (fSurfaceBase) {
1720        fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1721    }
1722}
1723
1724void SkCanvas::onDrawPaint(const SkPaint& paint) {
1725    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
1726    this->internalDrawPaint(paint);
1727}
1728
1729void SkCanvas::internalDrawPaint(const SkPaint& paint) {
1730    LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
1731
1732    while (iter.next()) {
1733        iter.fDevice->drawPaint(iter, looper.paint());
1734    }
1735
1736    LOOPER_END
1737}
1738
1739void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1740                            const SkPaint& paint) {
1741    TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
1742    if ((long)count <= 0) {
1743        return;
1744    }
1745
1746    SkRect r, storage;
1747    const SkRect* bounds = NULL;
1748    if (paint.canComputeFastBounds()) {
1749        // special-case 2 points (common for drawing a single line)
1750        if (2 == count) {
1751            r.set(pts[0], pts[1]);
1752        } else {
1753            r.set(pts, SkToInt(count));
1754        }
1755        bounds = &paint.computeFastStrokeBounds(r, &storage);
1756        if (this->quickReject(*bounds)) {
1757            return;
1758        }
1759    }
1760
1761    SkASSERT(pts != NULL);
1762
1763    LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
1764
1765    while (iter.next()) {
1766        iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
1767    }
1768
1769    LOOPER_END
1770}
1771
1772void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
1773    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
1774    SkRect storage;
1775    const SkRect* bounds = NULL;
1776    if (paint.canComputeFastBounds()) {
1777        bounds = &paint.computeFastBounds(r, &storage);
1778        if (this->quickReject(*bounds)) {
1779            return;
1780        }
1781    }
1782
1783    LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
1784
1785    while (iter.next()) {
1786        iter.fDevice->drawRect(iter, r, looper.paint());
1787    }
1788
1789    LOOPER_END
1790}
1791
1792void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
1793    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
1794    SkRect storage;
1795    const SkRect* bounds = NULL;
1796    if (paint.canComputeFastBounds()) {
1797        bounds = &paint.computeFastBounds(oval, &storage);
1798        if (this->quickReject(*bounds)) {
1799            return;
1800        }
1801    }
1802
1803    LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
1804
1805    while (iter.next()) {
1806        iter.fDevice->drawOval(iter, oval, looper.paint());
1807    }
1808
1809    LOOPER_END
1810}
1811
1812void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
1813    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
1814    SkRect storage;
1815    const SkRect* bounds = NULL;
1816    if (paint.canComputeFastBounds()) {
1817        bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1818        if (this->quickReject(*bounds)) {
1819            return;
1820        }
1821    }
1822
1823    if (rrect.isRect()) {
1824        // call the non-virtual version
1825        this->SkCanvas::drawRect(rrect.getBounds(), paint);
1826        return;
1827    } else if (rrect.isOval()) {
1828        // call the non-virtual version
1829        this->SkCanvas::drawOval(rrect.getBounds(), paint);
1830        return;
1831    }
1832
1833    LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
1834
1835    while (iter.next()) {
1836        iter.fDevice->drawRRect(iter, rrect, looper.paint());
1837    }
1838
1839    LOOPER_END
1840}
1841
1842void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1843                            const SkPaint& paint) {
1844    SkRect storage;
1845    const SkRect* bounds = NULL;
1846    if (paint.canComputeFastBounds()) {
1847        bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1848        if (this->quickReject(*bounds)) {
1849            return;
1850        }
1851    }
1852
1853    LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
1854
1855    while (iter.next()) {
1856        iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1857    }
1858
1859    LOOPER_END
1860}
1861
1862void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
1863    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
1864    if (!path.isFinite()) {
1865        return;
1866    }
1867
1868    SkRect storage;
1869    const SkRect* bounds = NULL;
1870    if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
1871        const SkRect& pathBounds = path.getBounds();
1872        bounds = &paint.computeFastBounds(pathBounds, &storage);
1873        if (this->quickReject(*bounds)) {
1874            return;
1875        }
1876    }
1877
1878    const SkRect& r = path.getBounds();
1879    if (r.width() <= 0 && r.height() <= 0) {
1880        if (path.isInverseFillType()) {
1881            this->internalDrawPaint(paint);
1882        }
1883        return;
1884    }
1885
1886    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
1887
1888    while (iter.next()) {
1889        iter.fDevice->drawPath(iter, path, looper.paint());
1890    }
1891
1892    LOOPER_END
1893}
1894
1895void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1896    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
1897    image->draw(this, dx, dy, paint);
1898}
1899
1900void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1901                               const SkPaint* paint) {
1902    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
1903    image->drawRect(this, src, dst, paint);
1904}
1905
1906void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
1907    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
1908    SkDEBUGCODE(bitmap.validate();)
1909
1910    if (NULL == paint || paint->canComputeFastBounds()) {
1911        SkRect bounds = {
1912            x, y,
1913            x + SkIntToScalar(bitmap.width()),
1914            y + SkIntToScalar(bitmap.height())
1915        };
1916        if (paint) {
1917            (void)paint->computeFastBounds(bounds, &bounds);
1918        }
1919        if (this->quickReject(bounds)) {
1920            return;
1921        }
1922    }
1923
1924    SkMatrix matrix;
1925    matrix.setTranslate(x, y);
1926    this->internalDrawBitmap(bitmap, matrix, paint);
1927}
1928
1929// this one is non-virtual, so it can be called safely by other canvas apis
1930void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
1931                                      const SkRect& dst, const SkPaint* paint,
1932                                      DrawBitmapRectFlags flags) {
1933    if (bitmap.drawsNothing() || dst.isEmpty()) {
1934        return;
1935    }
1936
1937    SkRect storage;
1938    const SkRect* bounds = &dst;
1939    if (NULL == paint || paint->canComputeFastBounds()) {
1940        if (paint) {
1941            bounds = &paint->computeFastBounds(dst, &storage);
1942        }
1943        if (this->quickReject(*bounds)) {
1944            return;
1945        }
1946    }
1947
1948    SkLazyPaint lazy;
1949    if (NULL == paint) {
1950        paint = lazy.init();
1951    }
1952
1953    LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
1954
1955    while (iter.next()) {
1956        iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
1957    }
1958
1959    LOOPER_END
1960}
1961
1962void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1963                                const SkPaint* paint, DrawBitmapRectFlags flags) {
1964    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
1965    SkDEBUGCODE(bitmap.validate();)
1966    this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
1967}
1968
1969void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1970                                      const SkIRect& center, const SkRect& dst,
1971                                      const SkPaint* paint) {
1972    if (bitmap.drawsNothing()) {
1973        return;
1974    }
1975    if (NULL == paint || paint->canComputeFastBounds()) {
1976        SkRect storage;
1977        const SkRect* bounds = &dst;
1978        if (paint) {
1979            bounds = &paint->computeFastBounds(dst, &storage);
1980        }
1981        if (this->quickReject(*bounds)) {
1982            return;
1983        }
1984    }
1985
1986    const int32_t w = bitmap.width();
1987    const int32_t h = bitmap.height();
1988
1989    SkIRect c = center;
1990    // pin center to the bounds of the bitmap
1991    c.fLeft = SkMax32(0, center.fLeft);
1992    c.fTop = SkMax32(0, center.fTop);
1993    c.fRight = SkPin32(center.fRight, c.fLeft, w);
1994    c.fBottom = SkPin32(center.fBottom, c.fTop, h);
1995
1996    const SkScalar srcX[4] = {
1997        0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
1998    };
1999    const SkScalar srcY[4] = {
2000        0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
2001    };
2002    SkScalar dstX[4] = {
2003        dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2004        dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2005    };
2006    SkScalar dstY[4] = {
2007        dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2008        dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2009    };
2010
2011    if (dstX[1] > dstX[2]) {
2012        dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2013        dstX[2] = dstX[1];
2014    }
2015
2016    if (dstY[1] > dstY[2]) {
2017        dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2018        dstY[2] = dstY[1];
2019    }
2020
2021    for (int y = 0; y < 3; y++) {
2022        SkRect s, d;
2023
2024        s.fTop = srcY[y];
2025        s.fBottom = srcY[y+1];
2026        d.fTop = dstY[y];
2027        d.fBottom = dstY[y+1];
2028        for (int x = 0; x < 3; x++) {
2029            s.fLeft = srcX[x];
2030            s.fRight = srcX[x+1];
2031            d.fLeft = dstX[x];
2032            d.fRight = dstX[x+1];
2033            this->internalDrawBitmapRect(bitmap, &s, d, paint,
2034                                         kNone_DrawBitmapRectFlag);
2035        }
2036    }
2037}
2038
2039void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2040                                const SkPaint* paint) {
2041    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
2042    SkDEBUGCODE(bitmap.validate();)
2043
2044    // Need a device entry-point, so gpu can use a mesh
2045    this->internalDrawBitmapNine(bitmap, center, dst, paint);
2046}
2047
2048class SkDeviceFilteredPaint {
2049public:
2050    SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
2051        uint32_t filteredFlags = device->filterTextFlags(paint);
2052        if (filteredFlags != paint.getFlags()) {
2053            SkPaint* newPaint = fLazy.set(paint);
2054            newPaint->setFlags(filteredFlags);
2055            fPaint = newPaint;
2056        } else {
2057            fPaint = &paint;
2058        }
2059    }
2060
2061    const SkPaint& paint() const { return *fPaint; }
2062
2063private:
2064    const SkPaint*  fPaint;
2065    SkLazyPaint     fLazy;
2066};
2067
2068void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2069                        const SkRect& r, SkScalar textSize) {
2070    if (paint.getStyle() == SkPaint::kFill_Style) {
2071        draw.fDevice->drawRect(draw, r, paint);
2072    } else {
2073        SkPaint p(paint);
2074        p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
2075        draw.fDevice->drawRect(draw, r, p);
2076    }
2077}
2078
2079void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2080                                   const char text[], size_t byteLength,
2081                                   SkScalar x, SkScalar y) {
2082    SkASSERT(byteLength == 0 || text != NULL);
2083
2084    // nothing to draw
2085    if (text == NULL || byteLength == 0 ||
2086        draw.fClip->isEmpty() ||
2087        (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2088        return;
2089    }
2090
2091    SkScalar    width = 0;
2092    SkPoint     start;
2093
2094    start.set(0, 0);    // to avoid warning
2095    if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2096                            SkPaint::kStrikeThruText_Flag)) {
2097        width = paint.measureText(text, byteLength);
2098
2099        SkScalar offsetX = 0;
2100        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2101            offsetX = SkScalarHalf(width);
2102        } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2103            offsetX = width;
2104        }
2105        start.set(x - offsetX, y);
2106    }
2107
2108    if (0 == width) {
2109        return;
2110    }
2111
2112    uint32_t flags = paint.getFlags();
2113
2114    if (flags & (SkPaint::kUnderlineText_Flag |
2115                 SkPaint::kStrikeThruText_Flag)) {
2116        SkScalar textSize = paint.getTextSize();
2117        SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2118        SkRect   r;
2119
2120        r.fLeft = start.fX;
2121        r.fRight = start.fX + width;
2122
2123        if (flags & SkPaint::kUnderlineText_Flag) {
2124            SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2125                                             start.fY);
2126            r.fTop = offset;
2127            r.fBottom = offset + height;
2128            DrawRect(draw, paint, r, textSize);
2129        }
2130        if (flags & SkPaint::kStrikeThruText_Flag) {
2131            SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2132                                             start.fY);
2133            r.fTop = offset;
2134            r.fBottom = offset + height;
2135            DrawRect(draw, paint, r, textSize);
2136        }
2137    }
2138}
2139
2140void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2141                          const SkPaint& paint) {
2142    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2143
2144    while (iter.next()) {
2145        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2146        iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
2147        DrawTextDecorations(iter, dfp.paint(),
2148                            static_cast<const char*>(text), byteLength, x, y);
2149    }
2150
2151    LOOPER_END
2152}
2153
2154void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2155                             const SkPaint& paint) {
2156    SkPoint textOffset = SkPoint::Make(0, 0);
2157
2158    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2159
2160    while (iter.next()) {
2161        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2162        iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
2163                                  dfp.paint());
2164    }
2165
2166    LOOPER_END
2167}
2168
2169void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2170                              SkScalar constY, const SkPaint& paint) {
2171
2172    SkPoint textOffset = SkPoint::Make(0, constY);
2173
2174    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2175
2176    while (iter.next()) {
2177        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2178        iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
2179                                  dfp.paint());
2180    }
2181
2182    LOOPER_END
2183}
2184
2185void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2186                                const SkMatrix* matrix, const SkPaint& paint) {
2187    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2188
2189    while (iter.next()) {
2190        iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
2191                                     matrix, looper.paint());
2192    }
2193
2194    LOOPER_END
2195}
2196
2197void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2198                              const SkPaint& paint) {
2199
2200    if (paint.canComputeFastBounds()) {
2201        SkRect storage;
2202
2203        if (this->quickReject(paint.computeFastBounds(blob->bounds().makeOffset(x, y), &storage))) {
2204            return;
2205        }
2206    }
2207
2208    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2209
2210    while (iter.next()) {
2211        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2212        iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint());
2213    }
2214
2215    LOOPER_END
2216}
2217
2218// These will become non-virtual, so they always call the (virtual) onDraw... method
2219void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2220                        const SkPaint& paint) {
2221    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
2222    this->onDrawText(text, byteLength, x, y, paint);
2223}
2224void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2225                           const SkPaint& paint) {
2226    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
2227    this->onDrawPosText(text, byteLength, pos, paint);
2228}
2229void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2230                            SkScalar constY, const SkPaint& paint) {
2231    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
2232    this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2233}
2234void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2235                              const SkMatrix* matrix, const SkPaint& paint) {
2236    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
2237    this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2238}
2239void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2240                            const SkPaint& paint) {
2241    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
2242    if (blob) {
2243        this->onDrawTextBlob(blob, x, y, paint);
2244    }
2245}
2246
2247void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2248                              const SkPoint verts[], const SkPoint texs[],
2249                              const SkColor colors[], SkXfermode* xmode,
2250                              const uint16_t indices[], int indexCount,
2251                              const SkPaint& paint) {
2252    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2253    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
2254
2255    while (iter.next()) {
2256        iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
2257                                   colors, xmode, indices, indexCount,
2258                                   looper.paint());
2259    }
2260
2261    LOOPER_END
2262}
2263
2264void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2265                         const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2266    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
2267    if (NULL == cubics) {
2268        return;
2269    }
2270
2271    // Since a patch is always within the convex hull of the control points, we discard it when its
2272    // bounding rectangle is completely outside the current clip.
2273    SkRect bounds;
2274    bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
2275    if (this->quickReject(bounds)) {
2276        return;
2277    }
2278
2279    this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2280}
2281
2282void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2283                           const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2284
2285    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
2286
2287    while (iter.next()) {
2288        iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
2289    }
2290
2291    LOOPER_END
2292}
2293
2294void SkCanvas::EXPERIMENTAL_drawDrawable(SkCanvasDrawable* dr) {
2295    if (dr && !this->quickReject(dr->getBounds())) {
2296        this->onDrawDrawable(dr);
2297    }
2298}
2299
2300void SkCanvas::onDrawDrawable(SkCanvasDrawable* dr) {
2301    dr->draw(this);
2302}
2303
2304//////////////////////////////////////////////////////////////////////////////
2305// These methods are NOT virtual, and therefore must call back into virtual
2306// methods, rather than actually drawing themselves.
2307//////////////////////////////////////////////////////////////////////////////
2308
2309void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
2310                        SkXfermode::Mode mode) {
2311    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
2312    SkPaint paint;
2313
2314    paint.setARGB(a, r, g, b);
2315    if (SkXfermode::kSrcOver_Mode != mode) {
2316        paint.setXfermodeMode(mode);
2317    }
2318    this->drawPaint(paint);
2319}
2320
2321void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
2322    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
2323    SkPaint paint;
2324
2325    paint.setColor(c);
2326    if (SkXfermode::kSrcOver_Mode != mode) {
2327        paint.setXfermodeMode(mode);
2328    }
2329    this->drawPaint(paint);
2330}
2331
2332void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
2333    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
2334    SkPoint pt;
2335
2336    pt.set(x, y);
2337    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2338}
2339
2340void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
2341    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
2342    SkPoint pt;
2343    SkPaint paint;
2344
2345    pt.set(x, y);
2346    paint.setColor(color);
2347    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2348}
2349
2350void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2351                        const SkPaint& paint) {
2352    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
2353    SkPoint pts[2];
2354
2355    pts[0].set(x0, y0);
2356    pts[1].set(x1, y1);
2357    this->drawPoints(kLines_PointMode, 2, pts, paint);
2358}
2359
2360void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2361                              SkScalar right, SkScalar bottom,
2362                              const SkPaint& paint) {
2363    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
2364    SkRect  r;
2365
2366    r.set(left, top, right, bottom);
2367    this->drawRect(r, paint);
2368}
2369
2370void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2371                          const SkPaint& paint) {
2372    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
2373    if (radius < 0) {
2374        radius = 0;
2375    }
2376
2377    SkRect  r;
2378    r.set(cx - radius, cy - radius, cx + radius, cy + radius);
2379    this->drawOval(r, paint);
2380}
2381
2382void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2383                             const SkPaint& paint) {
2384    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
2385    if (rx > 0 && ry > 0) {
2386        if (paint.canComputeFastBounds()) {
2387            SkRect storage;
2388            if (this->quickReject(paint.computeFastBounds(r, &storage))) {
2389                return;
2390            }
2391        }
2392        SkRRect rrect;
2393        rrect.setRectXY(r, rx, ry);
2394        this->drawRRect(rrect, paint);
2395    } else {
2396        this->drawRect(r, paint);
2397    }
2398}
2399
2400void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2401                       SkScalar sweepAngle, bool useCenter,
2402                       const SkPaint& paint) {
2403    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2404    if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2405        this->drawOval(oval, paint);
2406    } else {
2407        SkPath  path;
2408        if (useCenter) {
2409            path.moveTo(oval.centerX(), oval.centerY());
2410        }
2411        path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2412        if (useCenter) {
2413            path.close();
2414        }
2415        this->drawPath(path, paint);
2416    }
2417}
2418
2419void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2420                                const SkPath& path, SkScalar hOffset,
2421                                SkScalar vOffset, const SkPaint& paint) {
2422    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
2423    SkMatrix    matrix;
2424
2425    matrix.setTranslate(hOffset, vOffset);
2426    this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2427}
2428
2429///////////////////////////////////////////////////////////////////////////////
2430void SkCanvas::drawPicture(const SkPicture* picture) {
2431    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
2432    if (picture) {
2433        this->onDrawPicture(picture, NULL, NULL);
2434    }
2435}
2436
2437void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
2438    TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)");
2439    if (picture) {
2440        if (matrix && matrix->isIdentity()) {
2441            matrix = NULL;
2442        }
2443        this->onDrawPicture(picture, matrix, paint);
2444    }
2445}
2446
2447void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2448                             const SkPaint* paint) {
2449    SkBaseDevice* device = this->getTopDevice();
2450    if (device) {
2451        // Canvas has to first give the device the opportunity to render
2452        // the picture itself.
2453        if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
2454            return; // the device has rendered the entire picture
2455        }
2456    }
2457
2458    SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2459
2460    picture->playback(this);
2461}
2462
2463///////////////////////////////////////////////////////////////////////////////
2464///////////////////////////////////////////////////////////////////////////////
2465
2466SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
2467    SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
2468
2469    SkASSERT(canvas);
2470
2471    fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2472    fDone = !fImpl->next();
2473}
2474
2475SkCanvas::LayerIter::~LayerIter() {
2476    fImpl->~SkDrawIter();
2477}
2478
2479void SkCanvas::LayerIter::next() {
2480    fDone = !fImpl->next();
2481}
2482
2483SkBaseDevice* SkCanvas::LayerIter::device() const {
2484    return fImpl->getDevice();
2485}
2486
2487const SkMatrix& SkCanvas::LayerIter::matrix() const {
2488    return fImpl->getMatrix();
2489}
2490
2491const SkPaint& SkCanvas::LayerIter::paint() const {
2492    const SkPaint* paint = fImpl->getPaint();
2493    if (NULL == paint) {
2494        paint = &fDefaultPaint;
2495    }
2496    return *paint;
2497}
2498
2499const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2500int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2501int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
2502
2503///////////////////////////////////////////////////////////////////////////////
2504
2505SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
2506
2507///////////////////////////////////////////////////////////////////////////////
2508
2509static bool supported_for_raster_canvas(const SkImageInfo& info) {
2510    switch (info.alphaType()) {
2511        case kPremul_SkAlphaType:
2512        case kOpaque_SkAlphaType:
2513            break;
2514        default:
2515            return false;
2516    }
2517
2518    switch (info.colorType()) {
2519        case kAlpha_8_SkColorType:
2520        case kRGB_565_SkColorType:
2521        case kN32_SkColorType:
2522            break;
2523        default:
2524            return false;
2525    }
2526
2527    return true;
2528}
2529
2530SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2531    if (!supported_for_raster_canvas(info)) {
2532        return NULL;
2533    }
2534
2535    SkBitmap bitmap;
2536    if (!bitmap.installPixels(info, pixels, rowBytes)) {
2537        return NULL;
2538    }
2539    return SkNEW_ARGS(SkCanvas, (bitmap));
2540}
2541
2542///////////////////////////////////////////////////////////////////////////////
2543
2544SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
2545                                                 const SkPaint* paint, const SkRect& bounds)
2546    : fCanvas(canvas)
2547    , fSaveCount(canvas->getSaveCount())
2548{
2549    if (paint) {
2550        SkRect newBounds = bounds;
2551        if (matrix) {
2552            matrix->mapRect(&newBounds);
2553        }
2554        canvas->saveLayer(&newBounds, paint);
2555    } else if (matrix) {
2556        canvas->save();
2557    }
2558
2559    if (matrix) {
2560        canvas->concat(*matrix);
2561    }
2562}
2563
2564SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2565    fCanvas->restoreToCount(fSaveCount);
2566}
2567