SkCanvas.cpp revision a27096b4740775ae141fd0abaf456d706065c5ee
1
2/*
3 * Copyright 2008 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkCanvas.h"
11#include "SkBounder.h"
12#include "SkDevice.h"
13#include "SkDraw.h"
14#include "SkDrawFilter.h"
15#include "SkDrawLooper.h"
16#include "SkPicture.h"
17#include "SkRasterClip.h"
18#include "SkScalarCompare.h"
19#include "SkSurface_Base.h"
20#include "SkTemplates.h"
21#include "SkTextFormatParams.h"
22#include "SkTLazy.h"
23#include "SkUtils.h"
24
25SK_DEFINE_INST_COUNT(SkBounder)
26SK_DEFINE_INST_COUNT(SkCanvas)
27SK_DEFINE_INST_COUNT(SkDrawFilter)
28
29// experimental for faster tiled drawing...
30//#define SK_ENABLE_CLIP_QUICKREJECT
31
32//#define SK_TRACE_SAVERESTORE
33
34#ifdef SK_TRACE_SAVERESTORE
35    static int gLayerCounter;
36    static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
37    static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
38
39    static int gRecCounter;
40    static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
41    static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
42
43    static int gCanvasCounter;
44    static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
45    static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
46#else
47    #define inc_layer()
48    #define dec_layer()
49    #define inc_rec()
50    #define dec_rec()
51    #define inc_canvas()
52    #define dec_canvas()
53#endif
54
55typedef SkTLazy<SkPaint> SkLazyPaint;
56
57void SkCanvas::predrawNotify() {
58    if (fSurfaceBase) {
59        fSurfaceBase->aboutToDraw(this);
60    }
61}
62
63///////////////////////////////////////////////////////////////////////////////
64
65/*  This is the record we keep for each SkDevice that the user installs.
66    The clip/matrix/proc are fields that reflect the top of the save/restore
67    stack. Whenever the canvas changes, it marks a dirty flag, and then before
68    these are used (assuming we're not on a layer) we rebuild these cache
69    values: they reflect the top of the save stack, but translated and clipped
70    by the device's XY offset and bitmap-bounds.
71*/
72struct DeviceCM {
73    DeviceCM*           fNext;
74    SkDevice*           fDevice;
75    SkRasterClip        fClip;
76    const SkMatrix*     fMatrix;
77    SkPaint*            fPaint; // may be null (in the future)
78    // optional, related to canvas' external matrix
79    const SkMatrix*     fMVMatrix;
80    const SkMatrix*     fExtMatrix;
81
82    DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas)
83            : fNext(NULL) {
84        if (NULL != device) {
85            device->ref();
86            device->onAttachToCanvas(canvas);
87        }
88        fDevice = device;
89        fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
90    }
91
92    ~DeviceCM() {
93        if (NULL != fDevice) {
94            fDevice->onDetachFromCanvas();
95            fDevice->unref();
96        }
97        SkDELETE(fPaint);
98    }
99
100    void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
101                  const SkClipStack& clipStack, SkRasterClip* updateClip) {
102        int x = fDevice->getOrigin().x();
103        int y = fDevice->getOrigin().y();
104        int width = fDevice->width();
105        int height = fDevice->height();
106
107        if ((x | y) == 0) {
108            fMatrix = &totalMatrix;
109            fClip = totalClip;
110        } else {
111            fMatrixStorage = totalMatrix;
112            fMatrixStorage.postTranslate(SkIntToScalar(-x),
113                                         SkIntToScalar(-y));
114            fMatrix = &fMatrixStorage;
115
116            totalClip.translate(-x, -y, &fClip);
117        }
118
119        fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
120
121        // intersect clip, but don't translate it (yet)
122
123        if (updateClip) {
124            updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
125                           SkRegion::kDifference_Op);
126        }
127
128        fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
129
130#ifdef SK_DEBUG
131        if (!fClip.isEmpty()) {
132            SkIRect deviceR;
133            deviceR.set(0, 0, width, height);
134            SkASSERT(deviceR.contains(fClip.getBounds()));
135        }
136#endif
137        // default is to assume no external matrix
138        fMVMatrix = NULL;
139        fExtMatrix = NULL;
140    }
141
142    // can only be called after calling updateMC()
143    void updateExternalMatrix(const SkMatrix& extM, const SkMatrix& extI) {
144        fMVMatrixStorage.setConcat(extI, *fMatrix);
145        fMVMatrix = &fMVMatrixStorage;
146        fExtMatrix = &extM; // assumes extM has long life-time (owned by canvas)
147    }
148
149private:
150    SkMatrix    fMatrixStorage, fMVMatrixStorage;
151};
152
153/*  This is the record we keep for each save/restore level in the stack.
154    Since a level optionally copies the matrix and/or stack, we have pointers
155    for these fields. If the value is copied for this level, the copy is
156    stored in the ...Storage field, and the pointer points to that. If the
157    value is not copied for this level, we ignore ...Storage, and just point
158    at the corresponding value in the previous level in the stack.
159*/
160class SkCanvas::MCRec {
161public:
162    MCRec*          fNext;
163    SkMatrix*       fMatrix;        // points to either fMatrixStorage or prev MCRec
164    SkRasterClip*   fRasterClip;    // points to either fRegionStorage or prev MCRec
165    SkDrawFilter*   fFilter;        // the current filter (or null)
166
167    DeviceCM*   fLayer;
168    /*  If there are any layers in the stack, this points to the top-most
169        one that is at or below this level in the stack (so we know what
170        bitmap/device to draw into from this level. This value is NOT
171        reference counted, since the real owner is either our fLayer field,
172        or a previous one in a lower level.)
173    */
174    DeviceCM*   fTopLayer;
175
176    MCRec(const MCRec* prev, int flags) {
177        if (NULL != prev) {
178            if (flags & SkCanvas::kMatrix_SaveFlag) {
179                fMatrixStorage = *prev->fMatrix;
180                fMatrix = &fMatrixStorage;
181            } else {
182                fMatrix = prev->fMatrix;
183            }
184
185            if (flags & SkCanvas::kClip_SaveFlag) {
186                fRasterClipStorage = *prev->fRasterClip;
187                fRasterClip = &fRasterClipStorage;
188            } else {
189                fRasterClip = prev->fRasterClip;
190            }
191
192            fFilter = prev->fFilter;
193            SkSafeRef(fFilter);
194
195            fTopLayer = prev->fTopLayer;
196        } else {   // no prev
197            fMatrixStorage.reset();
198
199            fMatrix     = &fMatrixStorage;
200            fRasterClip = &fRasterClipStorage;
201            fFilter     = NULL;
202            fTopLayer   = NULL;
203        }
204        fLayer = NULL;
205
206        // don't bother initializing fNext
207        inc_rec();
208    }
209    ~MCRec() {
210        SkSafeUnref(fFilter);
211        SkDELETE(fLayer);
212        dec_rec();
213    }
214
215private:
216    SkMatrix        fMatrixStorage;
217    SkRasterClip    fRasterClipStorage;
218};
219
220class SkDrawIter : public SkDraw {
221public:
222    SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
223        canvas = canvas->canvasForDrawIter();
224        fCanvas = canvas;
225        canvas->updateDeviceCMCache();
226
227        fClipStack = &canvas->fClipStack;
228        fBounder = canvas->getBounder();
229        fCurrLayer = canvas->fMCRec->fTopLayer;
230        fSkipEmptyClips = skipEmptyClips;
231    }
232
233    bool next() {
234        // skip over recs with empty clips
235        if (fSkipEmptyClips) {
236            while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
237                fCurrLayer = fCurrLayer->fNext;
238            }
239        }
240
241        const DeviceCM* rec = fCurrLayer;
242        if (rec && rec->fDevice) {
243
244            fMatrix = rec->fMatrix;
245            fClip   = &((SkRasterClip*)&rec->fClip)->forceGetBW();
246            fRC     = &rec->fClip;
247            fDevice = rec->fDevice;
248            fBitmap = &fDevice->accessBitmap(true);
249            fPaint  = rec->fPaint;
250            fMVMatrix = rec->fMVMatrix;
251            fExtMatrix = rec->fExtMatrix;
252            SkDEBUGCODE(this->validate();)
253
254            fCurrLayer = rec->fNext;
255            if (fBounder) {
256                fBounder->setClip(fClip);
257            }
258            // fCurrLayer may be NULL now
259
260            fCanvas->prepareForDeviceDraw(fDevice, *fMatrix, *fClip);
261            return true;
262        }
263        return false;
264    }
265
266    SkDevice* getDevice() const { return fDevice; }
267    int getX() const { return fDevice->getOrigin().x(); }
268    int getY() const { return fDevice->getOrigin().y(); }
269    const SkMatrix& getMatrix() const { return *fMatrix; }
270    const SkRegion& getClip() const { return *fClip; }
271    const SkPaint* getPaint() const { return fPaint; }
272
273private:
274    SkCanvas*       fCanvas;
275    const DeviceCM* fCurrLayer;
276    const SkPaint*  fPaint;     // May be null.
277    SkBool8         fSkipEmptyClips;
278
279    typedef SkDraw INHERITED;
280};
281
282/////////////////////////////////////////////////////////////////////////////
283
284class AutoDrawLooper {
285public:
286    AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint,
287                   bool skipLayerForImageFilter = false) : fOrigPaint(paint) {
288        fCanvas = canvas;
289        fLooper = paint.getLooper();
290        fFilter = canvas->getDrawFilter();
291        fPaint = NULL;
292        fSaveCount = canvas->getSaveCount();
293        fDoClearImageFilter = false;
294        fDone = false;
295
296        if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
297            SkPaint tmp;
298            tmp.setImageFilter(fOrigPaint.getImageFilter());
299            // it would be nice if we had a guess at the bounds, instead of null
300            (void)canvas->internalSaveLayer(NULL, &tmp,
301                                    SkCanvas::kARGB_ClipLayer_SaveFlag, true);
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 (fLooper) {
308            fLooper->init(canvas);
309            fIsSimple = false;
310        } else {
311            // can we be marked as simple?
312            fIsSimple = !fFilter && !fDoClearImageFilter;
313        }
314    }
315
316    ~AutoDrawLooper() {
317        if (fDoClearImageFilter) {
318            fCanvas->internalRestore();
319        }
320        SkASSERT(fCanvas->getSaveCount() == fSaveCount);
321    }
322
323    const SkPaint& paint() const {
324        SkASSERT(fPaint);
325        return *fPaint;
326    }
327
328    bool next(SkDrawFilter::Type drawType) {
329        if (fDone) {
330            return false;
331        } else if (fIsSimple) {
332            fDone = true;
333            fPaint = &fOrigPaint;
334            return !fPaint->nothingToDraw();
335        } else {
336            return this->doNext(drawType);
337        }
338    }
339
340private:
341    SkLazyPaint     fLazyPaint;
342    SkCanvas*       fCanvas;
343    const SkPaint&  fOrigPaint;
344    SkDrawLooper*   fLooper;
345    SkDrawFilter*   fFilter;
346    const SkPaint*  fPaint;
347    int             fSaveCount;
348    bool            fDoClearImageFilter;
349    bool            fDone;
350    bool            fIsSimple;
351
352    bool doNext(SkDrawFilter::Type drawType);
353};
354
355bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
356    fPaint = NULL;
357    SkASSERT(!fIsSimple);
358    SkASSERT(fLooper || fFilter || fDoClearImageFilter);
359
360    SkPaint* paint = fLazyPaint.set(fOrigPaint);
361
362    if (fDoClearImageFilter) {
363        paint->setImageFilter(NULL);
364    }
365
366    if (fLooper && !fLooper->next(fCanvas, paint)) {
367        fDone = true;
368        return false;
369    }
370    if (fFilter) {
371        fFilter->filter(paint, drawType);
372        if (NULL == fLooper) {
373            // no looper means we only draw once
374            fDone = true;
375        }
376    }
377    fPaint = paint;
378
379    // if we only came in here for the imagefilter, mark us as done
380    if (!fLooper && !fFilter) {
381        fDone = true;
382    }
383
384    // call this after any possible paint modifiers
385    if (fPaint->nothingToDraw()) {
386        fPaint = NULL;
387        return false;
388    }
389    return true;
390}
391
392/*  Stack helper for managing a SkBounder. In the destructor, if we were
393    given a bounder, we call its commit() method, signifying that we are
394    done accumulating bounds for that draw.
395*/
396class SkAutoBounderCommit {
397public:
398    SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {}
399    ~SkAutoBounderCommit() {
400        if (NULL != fBounder) {
401            fBounder->commit();
402        }
403    }
404private:
405    SkBounder*  fBounder;
406};
407
408#include "SkColorPriv.h"
409
410class AutoValidator {
411public:
412    AutoValidator(SkDevice* device) : fDevice(device) {}
413    ~AutoValidator() {
414#ifdef SK_DEBUG
415        const SkBitmap& bm = fDevice->accessBitmap(false);
416        if (bm.config() == SkBitmap::kARGB_4444_Config) {
417            for (int y = 0; y < bm.height(); y++) {
418                const SkPMColor16* p = bm.getAddr16(0, y);
419                for (int x = 0; x < bm.width(); x++) {
420                    SkPMColor16 c = p[x];
421                    SkPMColor16Assert(c);
422                }
423            }
424        }
425#endif
426    }
427private:
428    SkDevice* fDevice;
429};
430
431////////// macros to place around the internal draw calls //////////////////
432
433#define LOOPER_BEGIN_DRAWDEVICE(paint, type)                        \
434/*    AutoValidator   validator(fMCRec->fTopLayer->fDevice); */     \
435    this->predrawNotify();                                          \
436    AutoDrawLooper  looper(this, paint, true);                      \
437    while (looper.next(type)) {                                     \
438        SkAutoBounderCommit ac(fBounder);                           \
439        SkDrawIter          iter(this);
440
441#define LOOPER_BEGIN(paint, type)                                   \
442/*    AutoValidator   validator(fMCRec->fTopLayer->fDevice); */     \
443    this->predrawNotify();                                          \
444    AutoDrawLooper  looper(this, paint);                            \
445    while (looper.next(type)) {                                     \
446        SkAutoBounderCommit ac(fBounder);                           \
447        SkDrawIter          iter(this);
448
449#define LOOPER_END    }
450
451////////////////////////////////////////////////////////////////////////////
452
453SkDevice* SkCanvas::init(SkDevice* device) {
454    fBounder = NULL;
455    fLocalBoundsCompareType.setEmpty();
456    fLocalBoundsCompareTypeDirty = true;
457    fLastDeviceToGainFocus = NULL;
458    fDeviceCMDirty = false;
459    fSaveLayerCount = 0;
460
461    fMCRec = (MCRec*)fMCStack.push_back();
462    new (fMCRec) MCRec(NULL, 0);
463
464    fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL));
465    fMCRec->fTopLayer = fMCRec->fLayer;
466    fMCRec->fNext = NULL;
467
468    fExternalMatrix.reset();
469    fExternalInverse.reset();
470    fUseExternalMatrix = false;
471
472    fSurfaceBase = NULL;
473
474    return this->setDevice(device);
475}
476
477SkCanvas::SkCanvas()
478: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
479    inc_canvas();
480
481    this->init(NULL);
482}
483
484SkCanvas::SkCanvas(SkDevice* device)
485        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
486    inc_canvas();
487
488    this->init(device);
489}
490
491SkCanvas::SkCanvas(const SkBitmap& bitmap)
492        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
493    inc_canvas();
494
495    this->init(SkNEW_ARGS(SkDevice, (bitmap)))->unref();
496}
497
498SkCanvas::~SkCanvas() {
499    // free up the contents of our deque
500    this->restoreToCount(1);    // restore everything but the last
501    SkASSERT(0 == fSaveLayerCount);
502
503    this->internalRestore();    // restore the last, since we're going away
504
505    SkSafeUnref(fBounder);
506
507    dec_canvas();
508}
509
510SkBounder* SkCanvas::setBounder(SkBounder* bounder) {
511    SkRefCnt_SafeAssign(fBounder, bounder);
512    return bounder;
513}
514
515SkDrawFilter* SkCanvas::getDrawFilter() const {
516    return fMCRec->fFilter;
517}
518
519SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
520    SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
521    return filter;
522}
523
524///////////////////////////////////////////////////////////////////////////////
525
526void SkCanvas::flush() {
527    SkDevice* device = this->getDevice();
528    if (device) {
529        device->flush();
530    }
531}
532
533SkISize SkCanvas::getDeviceSize() const {
534    SkDevice* d = this->getDevice();
535    return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
536}
537
538SkDevice* SkCanvas::getDevice() const {
539    // return root device
540    MCRec* rec = (MCRec*) fMCStack.front();
541    SkASSERT(rec && rec->fLayer);
542    return rec->fLayer->fDevice;
543}
544
545SkDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
546    if (updateMatrixClip) {
547        const_cast<SkCanvas*>(this)->updateDeviceCMCache();
548    }
549    return fMCRec->fTopLayer->fDevice;
550}
551
552SkDevice* SkCanvas::setDevice(SkDevice* device) {
553    // return root device
554    SkDeque::F2BIter iter(fMCStack);
555    MCRec*           rec = (MCRec*)iter.next();
556    SkASSERT(rec && rec->fLayer);
557    SkDevice*       rootDevice = rec->fLayer->fDevice;
558
559    if (rootDevice == device) {
560        return device;
561    }
562
563    if (device) {
564        device->onAttachToCanvas(this);
565    }
566    if (rootDevice) {
567        rootDevice->onDetachFromCanvas();
568    }
569
570    SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
571    rootDevice = device;
572
573    fDeviceCMDirty = true;
574
575    /*  Now we update our initial region to have the bounds of the new device,
576        and then intersect all of the clips in our stack with these bounds,
577        to ensure that we can't draw outside of the device's bounds (and trash
578                                                                     memory).
579
580    NOTE: this is only a partial-fix, since if the new device is larger than
581        the previous one, we don't know how to "enlarge" the clips in our stack,
582        so drawing may be artificially restricted. Without keeping a history of
583        all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
584        reconstruct the correct clips, so this approximation will have to do.
585        The caller really needs to restore() back to the base if they want to
586        accurately take advantage of the new device bounds.
587    */
588
589    SkIRect bounds;
590    if (device) {
591        bounds.set(0, 0, device->width(), device->height());
592    } else {
593        bounds.setEmpty();
594    }
595    // now jam our 1st clip to be bounds, and intersect the rest with that
596    rec->fRasterClip->setRect(bounds);
597    while ((rec = (MCRec*)iter.next()) != NULL) {
598        (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op);
599    }
600
601    return device;
602}
603
604SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) {
605    SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap)));
606    device->unref();
607    return device;
608}
609
610bool SkCanvas::readPixels(SkBitmap* bitmap,
611                          int x, int y,
612                          Config8888 config8888) {
613    SkDevice* device = this->getDevice();
614    if (!device) {
615        return false;
616    }
617    return device->readPixels(bitmap, x, y, config8888);
618}
619
620bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
621    SkDevice* device = this->getDevice();
622    if (!device) {
623        return false;
624    }
625
626    SkIRect bounds;
627    bounds.set(0, 0, device->width(), device->height());
628    if (!bounds.intersect(srcRect)) {
629        return false;
630    }
631
632    SkBitmap tmp;
633    tmp.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(),
634                                               bounds.height());
635    if (this->readPixels(&tmp, bounds.fLeft, bounds.fTop)) {
636        bitmap->swap(tmp);
637        return true;
638    } else {
639        return false;
640    }
641}
642
643void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y,
644                           Config8888 config8888) {
645    SkDevice* device = this->getDevice();
646    if (device) {
647        if (SkIRect::Intersects(SkIRect::MakeSize(this->getDeviceSize()),
648                                SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()))) {
649            device->accessBitmap(true);
650            device->writePixels(bitmap, x, y, config8888);
651        }
652    }
653}
654
655SkCanvas* SkCanvas::canvasForDrawIter() {
656    return this;
657}
658
659//////////////////////////////////////////////////////////////////////////////
660
661void SkCanvas::updateDeviceCMCache() {
662    if (fDeviceCMDirty) {
663        const SkMatrix& totalMatrix = this->getTotalMatrix();
664        const SkRasterClip& totalClip = *fMCRec->fRasterClip;
665        DeviceCM*       layer = fMCRec->fTopLayer;
666
667        if (NULL == layer->fNext) {   // only one layer
668            layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
669            if (fUseExternalMatrix) {
670                layer->updateExternalMatrix(fExternalMatrix,
671                                            fExternalInverse);
672            }
673        } else {
674            SkRasterClip clip(totalClip);
675            do {
676                layer->updateMC(totalMatrix, clip, fClipStack, &clip);
677                if (fUseExternalMatrix) {
678                    layer->updateExternalMatrix(fExternalMatrix,
679                                                fExternalInverse);
680                }
681            } while ((layer = layer->fNext) != NULL);
682        }
683        fDeviceCMDirty = false;
684    }
685}
686
687void SkCanvas::prepareForDeviceDraw(SkDevice* device, const SkMatrix& matrix,
688                                    const SkRegion& clip) {
689    SkASSERT(device);
690    if (fLastDeviceToGainFocus != device) {
691        device->gainFocus(matrix, clip);
692        fLastDeviceToGainFocus = device;
693    }
694}
695
696///////////////////////////////////////////////////////////////////////////////
697
698int SkCanvas::internalSave(SaveFlags flags) {
699    int saveCount = this->getSaveCount(); // record this before the actual save
700
701    MCRec* newTop = (MCRec*)fMCStack.push_back();
702    new (newTop) MCRec(fMCRec, flags);    // balanced in restore()
703
704    newTop->fNext = fMCRec;
705    fMCRec = newTop;
706
707    fClipStack.save();
708    SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
709
710    return saveCount;
711}
712
713int SkCanvas::save(SaveFlags flags) {
714    // call shared impl
715    return this->internalSave(flags);
716}
717
718#define C32MASK (1 << SkBitmap::kARGB_8888_Config)
719#define C16MASK (1 << SkBitmap::kRGB_565_Config)
720#define C8MASK  (1 << SkBitmap::kA8_Config)
721
722static SkBitmap::Config resolve_config(SkCanvas* canvas,
723                                       const SkIRect& bounds,
724                                       SkCanvas::SaveFlags flags,
725                                       bool* isOpaque) {
726    *isOpaque = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) == 0;
727
728#if 0
729    // loop through and union all the configs we may draw into
730    uint32_t configMask = 0;
731    for (int i = canvas->countLayerDevices() - 1; i >= 0; --i)
732    {
733        SkDevice* device = canvas->getLayerDevice(i);
734        if (device->intersects(bounds))
735            configMask |= 1 << device->config();
736    }
737
738    // if the caller wants alpha or fullcolor, we can't return 565
739    if (flags & (SkCanvas::kFullColorLayer_SaveFlag |
740                 SkCanvas::kHasAlphaLayer_SaveFlag))
741        configMask &= ~C16MASK;
742
743    switch (configMask) {
744    case C8MASK:    // if we only have A8, return that
745        return SkBitmap::kA8_Config;
746
747    case C16MASK:   // if we only have 565, return that
748        return SkBitmap::kRGB_565_Config;
749
750    default:
751        return SkBitmap::kARGB_8888_Config; // default answer
752    }
753#else
754    return SkBitmap::kARGB_8888_Config; // default answer
755#endif
756}
757
758static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
759    return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
760}
761
762bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
763                               SkIRect* intersection) {
764    SkIRect clipBounds;
765    if (!this->getClipDeviceBounds(&clipBounds)) {
766        return false;
767    }
768    SkIRect ir;
769    if (NULL != bounds) {
770        SkRect r;
771
772        this->getTotalMatrix().mapRect(&r, *bounds);
773        r.roundOut(&ir);
774        // early exit if the layer's bounds are clipped out
775        if (!ir.intersect(clipBounds)) {
776            if (bounds_affects_clip(flags)) {
777                fMCRec->fRasterClip->setEmpty();
778            }
779            return false;
780        }
781    } else {    // no user bounds, so just use the clip
782        ir = clipBounds;
783    }
784
785    fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op);
786
787    // early exit if the clip is now empty
788    if (bounds_affects_clip(flags) &&
789        !fMCRec->fRasterClip->op(ir, SkRegion::kIntersect_Op)) {
790        return false;
791    }
792
793    if (intersection) {
794        *intersection = ir;
795    }
796    return true;
797}
798
799int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
800                        SaveFlags flags) {
801    return this->internalSaveLayer(bounds, paint, flags, false);
802}
803
804int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint,
805                                SaveFlags flags, bool justForImageFilter) {
806    // do this before we create the layer. We don't call the public save() since
807    // that would invoke a possibly overridden virtual
808    int count = this->internalSave(flags);
809
810    fDeviceCMDirty = true;
811
812    SkIRect ir;
813    if (!this->clipRectBounds(bounds, flags, &ir)) {
814        return count;
815    }
816
817    // Kill the imagefilter if our device doesn't allow it
818    SkLazyPaint lazyP;
819    if (paint && paint->getImageFilter()) {
820        if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
821            if (justForImageFilter) {
822                // early exit if the layer was just for the imageFilter
823                return count;
824            }
825            SkPaint* p = lazyP.set(*paint);
826            p->setImageFilter(NULL);
827            paint = p;
828        }
829    }
830
831    bool isOpaque;
832    SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque);
833
834    SkDevice* device;
835    if (paint && paint->getImageFilter()) {
836        device = this->createCompatibleDevice(config, ir.width(), ir.height(),
837                                              isOpaque);
838    } else {
839        device = this->createLayerDevice(config, ir.width(), ir.height(),
840                                         isOpaque);
841    }
842    if (NULL == device) {
843        SkDebugf("Unable to create device for layer.");
844        return count;
845    }
846
847    device->setOrigin(ir.fLeft, ir.fTop);
848    DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint, this));
849    device->unref();
850
851    layer->fNext = fMCRec->fTopLayer;
852    fMCRec->fLayer = layer;
853    fMCRec->fTopLayer = layer;    // this field is NOT an owner of layer
854
855    fSaveLayerCount += 1;
856    return count;
857}
858
859int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
860                             SaveFlags flags) {
861    if (0xFF == alpha) {
862        return this->saveLayer(bounds, NULL, flags);
863    } else {
864        SkPaint tmpPaint;
865        tmpPaint.setAlpha(alpha);
866        return this->saveLayer(bounds, &tmpPaint, flags);
867    }
868}
869
870void SkCanvas::restore() {
871    // check for underflow
872    if (fMCStack.count() > 1) {
873        this->internalRestore();
874    }
875}
876
877void SkCanvas::internalRestore() {
878    SkASSERT(fMCStack.count() != 0);
879
880    fDeviceCMDirty = true;
881    fLocalBoundsCompareTypeDirty = true;
882    // Dirty this pointer to handle the case of a new device created at the same address as the
883    // device we are restoring from. E.g.:
884    // saveLayer (creates a device)
885    // drawSomething
886    // restore (deletes the device)
887    // saveLayer (oops new device at the same address)
888    fLastDeviceToGainFocus = NULL;
889
890    fClipStack.restore();
891    // reserve our layer (if any)
892    DeviceCM* layer = fMCRec->fLayer;   // may be null
893    // now detach it from fMCRec so we can pop(). Gets freed after its drawn
894    fMCRec->fLayer = NULL;
895
896    // now do the normal restore()
897    fMCRec->~MCRec();       // balanced in save()
898    fMCStack.pop_back();
899    fMCRec = (MCRec*)fMCStack.back();
900
901    /*  Time to draw the layer's offscreen. We can't call the public drawSprite,
902        since if we're being recorded, we don't want to record this (the
903        recorder will have already recorded the restore).
904    */
905    if (NULL != layer) {
906        if (layer->fNext) {
907            const SkIPoint& origin = layer->fDevice->getOrigin();
908            this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
909                                     layer->fPaint);
910            // reset this, since internalDrawDevice will have set it to true
911            fDeviceCMDirty = true;
912
913            SkASSERT(fSaveLayerCount > 0);
914            fSaveLayerCount -= 1;
915        }
916        SkDELETE(layer);
917    }
918
919    SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
920}
921
922int SkCanvas::getSaveCount() const {
923    return fMCStack.count();
924}
925
926void SkCanvas::restoreToCount(int count) {
927    // sanity check
928    if (count < 1) {
929        count = 1;
930    }
931
932    int n = this->getSaveCount() - count;
933    for (int i = 0; i < n; ++i) {
934        this->restore();
935    }
936}
937
938bool SkCanvas::isDrawingToLayer() const {
939    return fSaveLayerCount > 0;
940}
941
942/////////////////////////////////////////////////////////////////////////////
943
944// can't draw it if its empty, or its too big for a fixed-point width or height
945static bool reject_bitmap(const SkBitmap& bitmap) {
946    return  bitmap.width() <= 0 || bitmap.height() <= 0
947#ifndef SK_ALLOW_OVER_32K_BITMAPS
948            || bitmap.width() > 32767 || bitmap.height() > 32767
949#endif
950            ;
951}
952
953void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
954                                const SkMatrix& matrix, const SkPaint* paint) {
955    if (reject_bitmap(bitmap)) {
956        return;
957    }
958
959    SkLazyPaint lazy;
960    if (NULL == paint) {
961        paint = lazy.init();
962    }
963    this->commonDrawBitmap(bitmap, srcRect, matrix, *paint);
964}
965
966#include "SkImageFilter.h"
967
968class DeviceImageFilterProxy : public SkImageFilter::Proxy {
969public:
970    DeviceImageFilterProxy(SkDevice* device) : fDevice(device) {}
971
972    virtual SkDevice* createDevice(int w, int h) SK_OVERRIDE {
973        return fDevice->createCompatibleDevice(SkBitmap::kARGB_8888_Config,
974                                               w, h, false);
975    }
976    virtual bool canHandleImageFilter(SkImageFilter* filter) SK_OVERRIDE {
977        return fDevice->canHandleImageFilter(filter);
978    }
979    virtual bool filterImage(SkImageFilter* filter, const SkBitmap& src,
980                             const SkMatrix& ctm,
981                             SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
982        return fDevice->filterImage(filter, src, ctm, result, offset);
983    }
984
985private:
986    SkDevice* fDevice;
987};
988
989void SkCanvas::internalDrawDevice(SkDevice* srcDev, int x, int y,
990                                  const SkPaint* paint) {
991    SkPaint tmp;
992    if (NULL == paint) {
993        tmp.setDither(true);
994        paint = &tmp;
995    }
996
997    LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
998    while (iter.next()) {
999        SkDevice* dstDev = iter.fDevice;
1000        paint = &looper.paint();
1001        SkImageFilter* filter = paint->getImageFilter();
1002        SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1003        if (filter && !dstDev->canHandleImageFilter(filter)) {
1004            DeviceImageFilterProxy proxy(dstDev);
1005            SkBitmap dst;
1006            const SkBitmap& src = srcDev->accessBitmap(false);
1007            if (filter->filterImage(&proxy, src, *iter.fMatrix, &dst, &pos)) {
1008                SkPaint tmpUnfiltered(*paint);
1009                tmpUnfiltered.setImageFilter(NULL);
1010                dstDev->drawSprite(iter, dst, pos.x(), pos.y(), tmpUnfiltered);
1011            }
1012        } else {
1013            dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
1014        }
1015    }
1016    LOOPER_END
1017}
1018
1019void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
1020                          const SkPaint* paint) {
1021    SkDEBUGCODE(bitmap.validate();)
1022
1023    if (reject_bitmap(bitmap)) {
1024        return;
1025    }
1026
1027    SkPaint tmp;
1028    if (NULL == paint) {
1029        paint = &tmp;
1030    }
1031
1032    LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
1033
1034    while (iter.next()) {
1035        paint = &looper.paint();
1036        SkImageFilter* filter = paint->getImageFilter();
1037        SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1038        if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
1039            DeviceImageFilterProxy proxy(iter.fDevice);
1040            SkBitmap dst;
1041            if (filter->filterImage(&proxy, bitmap, *iter.fMatrix,
1042                                    &dst, &pos)) {
1043                SkPaint tmpUnfiltered(*paint);
1044                tmpUnfiltered.setImageFilter(NULL);
1045                iter.fDevice->drawSprite(iter, dst, pos.x(), pos.y(),
1046                                         tmpUnfiltered);
1047            }
1048        } else {
1049            iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1050        }
1051    }
1052    LOOPER_END
1053}
1054
1055/////////////////////////////////////////////////////////////////////////////
1056
1057bool SkCanvas::translate(SkScalar dx, SkScalar dy) {
1058    fDeviceCMDirty = true;
1059    fLocalBoundsCompareTypeDirty = true;
1060    return fMCRec->fMatrix->preTranslate(dx, dy);
1061}
1062
1063bool SkCanvas::scale(SkScalar sx, SkScalar sy) {
1064    fDeviceCMDirty = true;
1065    fLocalBoundsCompareTypeDirty = true;
1066    return fMCRec->fMatrix->preScale(sx, sy);
1067}
1068
1069bool SkCanvas::rotate(SkScalar degrees) {
1070    fDeviceCMDirty = true;
1071    fLocalBoundsCompareTypeDirty = true;
1072    return fMCRec->fMatrix->preRotate(degrees);
1073}
1074
1075bool SkCanvas::skew(SkScalar sx, SkScalar sy) {
1076    fDeviceCMDirty = true;
1077    fLocalBoundsCompareTypeDirty = true;
1078    return fMCRec->fMatrix->preSkew(sx, sy);
1079}
1080
1081bool SkCanvas::concat(const SkMatrix& matrix) {
1082    fDeviceCMDirty = true;
1083    fLocalBoundsCompareTypeDirty = true;
1084    return fMCRec->fMatrix->preConcat(matrix);
1085}
1086
1087void SkCanvas::setMatrix(const SkMatrix& matrix) {
1088    fDeviceCMDirty = true;
1089    fLocalBoundsCompareTypeDirty = true;
1090    *fMCRec->fMatrix = matrix;
1091}
1092
1093// this is not virtual, so it must call a virtual method so that subclasses
1094// will see its action
1095void SkCanvas::resetMatrix() {
1096    SkMatrix matrix;
1097
1098    matrix.reset();
1099    this->setMatrix(matrix);
1100}
1101
1102//////////////////////////////////////////////////////////////////////////////
1103
1104bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
1105#ifdef SK_ENABLE_CLIP_QUICKREJECT
1106    if (SkRegion::kIntersect_Op == op) {
1107        if (fMCRec->fRasterClip->isEmpty()) {
1108            return false;
1109        }
1110
1111        if (this->quickReject(rect)) {
1112            fDeviceCMDirty = true;
1113            fLocalBoundsCompareTypeDirty = true;
1114
1115            fClipStack.clipEmpty();
1116            return fMCRec->fRasterClip->setEmpty();
1117        }
1118    }
1119#endif
1120
1121    AutoValidateClip avc(this);
1122
1123    fDeviceCMDirty = true;
1124    fLocalBoundsCompareTypeDirty = true;
1125
1126    if (fMCRec->fMatrix->rectStaysRect()) {
1127        // for these simpler matrices, we can stay a rect ever after applying
1128        // the matrix. This means we don't have to a) make a path, and b) tell
1129        // the region code to scan-convert the path, only to discover that it
1130        // is really just a rect.
1131        SkRect      r;
1132
1133        fMCRec->fMatrix->mapRect(&r, rect);
1134        fClipStack.clipDevRect(r, op, doAA);
1135        return fMCRec->fRasterClip->op(r, op, doAA);
1136    } else {
1137        // since we're rotate or some such thing, we convert the rect to a path
1138        // and clip against that, since it can handle any matrix. However, to
1139        // avoid recursion in the case where we are subclassed (e.g. Pictures)
1140        // we explicitly call "our" version of clipPath.
1141        SkPath  path;
1142
1143        path.addRect(rect);
1144        return this->SkCanvas::clipPath(path, op, doAA);
1145    }
1146}
1147
1148static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip,
1149                           const SkPath& devPath, SkRegion::Op op, bool doAA) {
1150    // base is used to limit the size (and therefore memory allocation) of the
1151    // region that results from scan converting devPath.
1152    SkRegion base;
1153
1154    if (SkRegion::kIntersect_Op == op) {
1155        // since we are intersect, we can do better (tighter) with currRgn's
1156        // bounds, than just using the device. However, if currRgn is complex,
1157        // our region blitter may hork, so we do that case in two steps.
1158        if (currClip->isRect()) {
1159            return currClip->setPath(devPath, *currClip, doAA);
1160        } else {
1161            base.setRect(currClip->getBounds());
1162            SkRasterClip clip;
1163            clip.setPath(devPath, base, doAA);
1164            return currClip->op(clip, op);
1165        }
1166    } else {
1167        const SkDevice* device = canvas->getDevice();
1168        if (!device) {
1169            return currClip->setEmpty();
1170        }
1171
1172        base.setRect(0, 0, device->width(), device->height());
1173
1174        if (SkRegion::kReplace_Op == op) {
1175            return currClip->setPath(devPath, base, doAA);
1176        } else {
1177            SkRasterClip clip;
1178            clip.setPath(devPath, base, doAA);
1179            return currClip->op(clip, op);
1180        }
1181    }
1182}
1183
1184bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
1185#ifdef SK_ENABLE_CLIP_QUICKREJECT
1186    if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
1187        if (fMCRec->fRasterClip->isEmpty()) {
1188            return false;
1189        }
1190
1191        if (this->quickReject(path.getBounds())) {
1192            fDeviceCMDirty = true;
1193            fLocalBoundsCompareTypeDirty = true;
1194
1195            fClipStack.clipEmpty();
1196            return fMCRec->fRasterClip->setEmpty();
1197        }
1198    }
1199#endif
1200
1201    AutoValidateClip avc(this);
1202
1203    fDeviceCMDirty = true;
1204    fLocalBoundsCompareTypeDirty = true;
1205
1206    SkPath devPath;
1207    path.transform(*fMCRec->fMatrix, &devPath);
1208
1209    // Check if the transfomation, or the original path itself
1210    // made us empty. Note this can also happen if we contained NaN
1211    // values. computing the bounds detects this, and will set our
1212    // bounds to empty if that is the case. (see SkRect::set(pts, count))
1213    if (devPath.getBounds().isEmpty()) {
1214        // resetting the path will remove any NaN or other wanky values
1215        // that might upset our scan converter.
1216        devPath.reset();
1217    }
1218
1219    // if we called path.swap() we could avoid a deep copy of this path
1220    fClipStack.clipDevPath(devPath, op, doAA);
1221
1222    return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA);
1223}
1224
1225bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
1226    AutoValidateClip avc(this);
1227
1228    fDeviceCMDirty = true;
1229    fLocalBoundsCompareTypeDirty = true;
1230
1231    // todo: signal fClipStack that we have a region, and therefore (I guess)
1232    // we have to ignore it, and use the region directly?
1233    fClipStack.clipDevRect(rgn.getBounds(), op);
1234
1235    return fMCRec->fRasterClip->op(rgn, op);
1236}
1237
1238#ifdef SK_DEBUG
1239void SkCanvas::validateClip() const {
1240    // construct clipRgn from the clipstack
1241    const SkDevice* device = this->getDevice();
1242    if (!device) {
1243        SkASSERT(this->getTotalClip().isEmpty());
1244        return;
1245    }
1246
1247    SkIRect ir;
1248    ir.set(0, 0, device->width(), device->height());
1249    SkRasterClip tmpClip(ir);
1250
1251    SkClipStack::B2TIter                iter(fClipStack);
1252    const SkClipStack::B2TIter::Clip*   clip;
1253    while ((clip = iter.next()) != NULL) {
1254        if (clip->fPath) {
1255            clipPathHelper(this, &tmpClip, *clip->fPath, clip->fOp, clip->fDoAA);
1256        } else if (clip->fRect) {
1257            clip->fRect->round(&ir);
1258            tmpClip.op(ir, clip->fOp);
1259        } else {
1260            tmpClip.setEmpty();
1261        }
1262    }
1263
1264#if 0   // enable this locally for testing
1265    // now compare against the current rgn
1266    const SkRegion& rgn = this->getTotalClip();
1267    SkASSERT(rgn == tmpClip);
1268#endif
1269}
1270#endif
1271
1272void SkCanvas::replayClips(ClipVisitor* visitor) const {
1273    SkClipStack::B2TIter                iter(fClipStack);
1274    const SkClipStack::B2TIter::Clip*   clip;
1275
1276    SkRect empty = { 0, 0, 0, 0 };
1277    while ((clip = iter.next()) != NULL) {
1278        if (clip->fPath) {
1279            visitor->clipPath(*clip->fPath, clip->fOp, clip->fDoAA);
1280        } else if (clip->fRect) {
1281            visitor->clipRect(*clip->fRect, clip->fOp, clip->fDoAA);
1282        } else {
1283            visitor->clipRect(empty, SkRegion::kIntersect_Op, false);
1284        }
1285    }
1286}
1287
1288///////////////////////////////////////////////////////////////////////////////
1289
1290void SkCanvas::computeLocalClipBoundsCompareType() const {
1291    SkRect r;
1292
1293    if (!this->getClipBounds(&r)) {
1294        fLocalBoundsCompareType.setEmpty();
1295    } else {
1296        fLocalBoundsCompareType.set(SkScalarToCompareType(r.fLeft),
1297                                    SkScalarToCompareType(r.fTop),
1298                                    SkScalarToCompareType(r.fRight),
1299                                    SkScalarToCompareType(r.fBottom));
1300    }
1301}
1302
1303bool SkCanvas::quickReject(const SkRect& rect) const {
1304
1305    if (!rect.isFinite())
1306        return true;
1307
1308    if (fMCRec->fRasterClip->isEmpty()) {
1309        return true;
1310    }
1311
1312    if (fMCRec->fMatrix->hasPerspective()) {
1313        SkRect dst;
1314        fMCRec->fMatrix->mapRect(&dst, rect);
1315        SkIRect idst;
1316        dst.roundOut(&idst);
1317        return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds());
1318    } else {
1319        const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType();
1320
1321        // for speed, do the most likely reject compares first
1322        SkScalarCompareType userT = SkScalarToCompareType(rect.fTop);
1323        SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom);
1324        if (userT >= clipR.fBottom || userB <= clipR.fTop) {
1325            return true;
1326        }
1327        SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft);
1328        SkScalarCompareType userR = SkScalarToCompareType(rect.fRight);
1329        if (userL >= clipR.fRight || userR <= clipR.fLeft) {
1330            return true;
1331        }
1332        return false;
1333    }
1334}
1335
1336bool SkCanvas::quickReject(const SkPath& path) const {
1337    return path.isEmpty() || this->quickReject(path.getBounds());
1338}
1339
1340static inline int pinIntForScalar(int x) {
1341#ifdef SK_SCALAR_IS_FIXED
1342    if (x < SK_MinS16) {
1343        x = SK_MinS16;
1344    } else if (x > SK_MaxS16) {
1345        x = SK_MaxS16;
1346    }
1347#endif
1348    return x;
1349}
1350
1351bool SkCanvas::getClipBounds(SkRect* bounds) const {
1352    SkIRect ibounds;
1353    if (!getClipDeviceBounds(&ibounds)) {
1354        return false;
1355    }
1356
1357    SkMatrix inverse;
1358    // if we can't invert the CTM, we can't return local clip bounds
1359    if (!fMCRec->fMatrix->invert(&inverse)) {
1360        if (bounds) {
1361            bounds->setEmpty();
1362        }
1363        return false;
1364    }
1365
1366    if (NULL != bounds) {
1367        SkRect r;
1368        // adjust it outwards in case we are antialiasing
1369        const int inset = 1;
1370
1371        // SkRect::iset() will correctly assert if we pass a value out of range
1372        // (when SkScalar==fixed), so we pin to legal values. This does not
1373        // really returnt the correct answer, but its the best we can do given
1374        // that we've promised to return SkRect (even though we support devices
1375        // that can be larger than 32K in width or height).
1376        r.iset(pinIntForScalar(ibounds.fLeft - inset),
1377               pinIntForScalar(ibounds.fTop - inset),
1378               pinIntForScalar(ibounds.fRight + inset),
1379               pinIntForScalar(ibounds.fBottom + inset));
1380        inverse.mapRect(bounds, r);
1381    }
1382    return true;
1383}
1384
1385bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
1386    const SkRasterClip& clip = *fMCRec->fRasterClip;
1387    if (clip.isEmpty()) {
1388        if (bounds) {
1389            bounds->setEmpty();
1390        }
1391        return false;
1392    }
1393
1394    if (NULL != bounds) {
1395        *bounds = clip.getBounds();
1396    }
1397    return true;
1398}
1399
1400const SkMatrix& SkCanvas::getTotalMatrix() const {
1401    return *fMCRec->fMatrix;
1402}
1403
1404SkCanvas::ClipType SkCanvas::getClipType() const {
1405    if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType;
1406    if (fMCRec->fRasterClip->isRect()) return kRect_ClipType;
1407    return kComplex_ClipType;
1408}
1409
1410const SkRegion& SkCanvas::getTotalClip() const {
1411    return fMCRec->fRasterClip->forceGetBW();
1412}
1413
1414void SkCanvas::setExternalMatrix(const SkMatrix* matrix) {
1415    if (NULL == matrix || matrix->isIdentity()) {
1416        if (fUseExternalMatrix) {
1417            fDeviceCMDirty = true;
1418        }
1419        fUseExternalMatrix = false;
1420    } else {
1421        if (matrix->invert(&fExternalInverse)) {
1422            fExternalMatrix = *matrix;
1423            fUseExternalMatrix = true;
1424            fDeviceCMDirty = true;  // |= (fExternalMatrix != *matrix)
1425        }
1426    }
1427}
1428
1429SkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config,
1430                                      int width, int height,
1431                                      bool isOpaque) {
1432    SkDevice* device = this->getTopDevice();
1433    if (device) {
1434        return device->createCompatibleDeviceForSaveLayer(config, width, height,
1435                                                          isOpaque);
1436    } else {
1437        return NULL;
1438    }
1439}
1440
1441SkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config,
1442                                           int width, int height,
1443                                           bool isOpaque) {
1444    SkDevice* device = this->getDevice();
1445    if (device) {
1446        return device->createCompatibleDevice(config, width, height, isOpaque);
1447    } else {
1448        return NULL;
1449    }
1450}
1451
1452
1453//////////////////////////////////////////////////////////////////////////////
1454//  These are the virtual drawing methods
1455//////////////////////////////////////////////////////////////////////////////
1456
1457void SkCanvas::clear(SkColor color) {
1458    SkDrawIter  iter(this);
1459
1460    while (iter.next()) {
1461        iter.fDevice->clear(color);
1462    }
1463}
1464
1465void SkCanvas::drawPaint(const SkPaint& paint) {
1466    this->internalDrawPaint(paint);
1467}
1468
1469void SkCanvas::internalDrawPaint(const SkPaint& paint) {
1470    LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type)
1471
1472    while (iter.next()) {
1473        iter.fDevice->drawPaint(iter, looper.paint());
1474    }
1475
1476    LOOPER_END
1477}
1478
1479void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
1480                          const SkPaint& paint) {
1481    if ((long)count <= 0) {
1482        return;
1483    }
1484
1485    if (paint.canComputeFastBounds()) {
1486        SkRect r;
1487        // special-case 2 points (common for drawing a single line)
1488        if (2 == count) {
1489            r.set(pts[0], pts[1]);
1490        } else {
1491            r.set(pts, count);
1492        }
1493        SkRect storage;
1494        if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1495            return;
1496        }
1497    }
1498
1499    SkASSERT(pts != NULL);
1500
1501    LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type)
1502
1503    while (iter.next()) {
1504        iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
1505    }
1506
1507    LOOPER_END
1508}
1509
1510void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1511    if (paint.canComputeFastBounds()) {
1512        SkRect storage;
1513        if (this->quickReject(paint.computeFastBounds(r, &storage))) {
1514            return;
1515        }
1516    }
1517
1518    LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type)
1519
1520    while (iter.next()) {
1521        iter.fDevice->drawRect(iter, r, looper.paint());
1522    }
1523
1524    LOOPER_END
1525}
1526
1527void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1528    if (!path.isFinite()) {
1529        return;
1530    }
1531
1532    if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
1533        SkRect storage;
1534        const SkRect& bounds = path.getBounds();
1535        if (this->quickReject(paint.computeFastBounds(bounds, &storage))) {
1536            return;
1537        }
1538    }
1539    if (path.isEmpty()) {
1540        if (path.isInverseFillType()) {
1541            this->internalDrawPaint(paint);
1542        }
1543        return;
1544    }
1545
1546    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
1547
1548    while (iter.next()) {
1549        iter.fDevice->drawPath(iter, path, looper.paint());
1550    }
1551
1552    LOOPER_END
1553}
1554
1555void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
1556                          const SkPaint* paint) {
1557    SkDEBUGCODE(bitmap.validate();)
1558
1559    if (NULL == paint || paint->canComputeFastBounds()) {
1560        SkRect bounds = {
1561            x, y,
1562            x + SkIntToScalar(bitmap.width()),
1563            y + SkIntToScalar(bitmap.height())
1564        };
1565        if (paint) {
1566            (void)paint->computeFastBounds(bounds, &bounds);
1567        }
1568        if (this->quickReject(bounds)) {
1569            return;
1570        }
1571    }
1572
1573    SkMatrix matrix;
1574    matrix.setTranslate(x, y);
1575    this->internalDrawBitmap(bitmap, NULL, matrix, paint);
1576}
1577
1578// this one is non-virtual, so it can be called safely by other canvas apis
1579void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
1580                                      const SkRect& dst, const SkPaint* paint) {
1581    if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) {
1582        return;
1583    }
1584
1585    // do this now, to avoid the cost of calling extract for RLE bitmaps
1586    if (NULL == paint || paint->canComputeFastBounds()) {
1587        SkRect storage;
1588        const SkRect* bounds = &dst;
1589        if (paint) {
1590            bounds = &paint->computeFastBounds(dst, &storage);
1591        }
1592        if (this->quickReject(*bounds)) {
1593            return;
1594        }
1595    }
1596
1597    const SkBitmap* bitmapPtr = &bitmap;
1598
1599    SkMatrix matrix;
1600    SkRect tmpSrc;
1601    if (src) {
1602        tmpSrc.set(*src);
1603        // if the extract process clipped off the top or left of the
1604        // original, we adjust for that here to get the position right.
1605        if (tmpSrc.fLeft > 0) {
1606            tmpSrc.fRight -= tmpSrc.fLeft;
1607            tmpSrc.fLeft = 0;
1608        }
1609        if (tmpSrc.fTop > 0) {
1610            tmpSrc.fBottom -= tmpSrc.fTop;
1611            tmpSrc.fTop = 0;
1612        }
1613    } else {
1614        tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()),
1615                   SkIntToScalar(bitmap.height()));
1616    }
1617    matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
1618
1619    // ensure that src is "valid" before we pass it to our internal routines
1620    // and to SkDevice. i.e. sure it is contained inside the original bitmap.
1621    SkIRect tmpISrc;
1622    if (src) {
1623        tmpISrc.set(0, 0, bitmap.width(), bitmap.height());
1624        if (!tmpISrc.intersect(*src)) {
1625            return;
1626        }
1627        src = &tmpISrc;
1628    }
1629    this->internalDrawBitmap(*bitmapPtr, src, matrix, paint);
1630}
1631
1632void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
1633                              const SkRect& dst, const SkPaint* paint) {
1634    SkDEBUGCODE(bitmap.validate();)
1635    this->internalDrawBitmapRect(bitmap, src, dst, paint);
1636}
1637
1638void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
1639                                const SkPaint* paint) {
1640    SkDEBUGCODE(bitmap.validate();)
1641    this->internalDrawBitmap(bitmap, NULL, matrix, paint);
1642}
1643
1644void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
1645                                const SkMatrix& matrix, const SkPaint& paint) {
1646    SkDEBUGCODE(bitmap.validate();)
1647
1648    LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type)
1649
1650    while (iter.next()) {
1651        iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint());
1652    }
1653
1654    LOOPER_END
1655}
1656
1657void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1658                                      const SkIRect& center, const SkRect& dst,
1659                                      const SkPaint* paint) {
1660    if (NULL == paint || paint->canComputeFastBounds()) {
1661        SkRect storage;
1662        const SkRect* bounds = &dst;
1663        if (paint) {
1664            bounds = &paint->computeFastBounds(dst, &storage);
1665        }
1666        if (this->quickReject(*bounds)) {
1667            return;
1668        }
1669    }
1670
1671    const int32_t w = bitmap.width();
1672    const int32_t h = bitmap.height();
1673
1674    SkIRect c = center;
1675    // pin center to the bounds of the bitmap
1676    c.fLeft = SkMax32(0, center.fLeft);
1677    c.fTop = SkMax32(0, center.fTop);
1678    c.fRight = SkPin32(center.fRight, c.fLeft, w);
1679    c.fBottom = SkPin32(center.fBottom, c.fTop, h);
1680
1681    const int32_t srcX[4] = { 0, c.fLeft, c.fRight, w };
1682    const int32_t srcY[4] = { 0, c.fTop, c.fBottom, h };
1683    SkScalar dstX[4] = {
1684        dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
1685        dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
1686    };
1687    SkScalar dstY[4] = {
1688        dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
1689        dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
1690    };
1691
1692    if (dstX[1] > dstX[2]) {
1693        dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
1694        dstX[2] = dstX[1];
1695    }
1696
1697    if (dstY[1] > dstY[2]) {
1698        dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
1699        dstY[2] = dstY[1];
1700    }
1701
1702    SkIRect s;
1703    SkRect  d;
1704    for (int y = 0; y < 3; y++) {
1705        s.fTop = srcY[y];
1706        s.fBottom = srcY[y+1];
1707        d.fTop = dstY[y];
1708        d.fBottom = dstY[y+1];
1709        for (int x = 0; x < 3; x++) {
1710            s.fLeft = srcX[x];
1711            s.fRight = srcX[x+1];
1712            d.fLeft = dstX[x];
1713            d.fRight = dstX[x+1];
1714            this->internalDrawBitmapRect(bitmap, &s, d, paint);
1715        }
1716    }
1717}
1718
1719void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1720                              const SkRect& dst, const SkPaint* paint) {
1721    SkDEBUGCODE(bitmap.validate();)
1722
1723    // Need a device entry-point, so gpu can use a mesh
1724    this->internalDrawBitmapNine(bitmap, center, dst, paint);
1725}
1726
1727class SkDeviceFilteredPaint {
1728public:
1729    SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) {
1730        SkDevice::TextFlags flags;
1731        if (device->filterTextFlags(paint, &flags)) {
1732            SkPaint* newPaint = fLazy.set(paint);
1733            newPaint->setFlags(flags.fFlags);
1734            newPaint->setHinting(flags.fHinting);
1735            fPaint = newPaint;
1736        } else {
1737            fPaint = &paint;
1738        }
1739    }
1740
1741    const SkPaint& paint() const { return *fPaint; }
1742
1743private:
1744    const SkPaint*  fPaint;
1745    SkLazyPaint     fLazy;
1746};
1747
1748void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
1749                        const SkRect& r, SkScalar textSize) {
1750    if (paint.getStyle() == SkPaint::kFill_Style) {
1751        draw.fDevice->drawRect(draw, r, paint);
1752    } else {
1753        SkPaint p(paint);
1754        p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
1755        draw.fDevice->drawRect(draw, r, p);
1756    }
1757}
1758
1759void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
1760                                   const char text[], size_t byteLength,
1761                                   SkScalar x, SkScalar y) {
1762    SkASSERT(byteLength == 0 || text != NULL);
1763
1764    // nothing to draw
1765    if (text == NULL || byteLength == 0 ||
1766        draw.fClip->isEmpty() ||
1767        (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
1768        return;
1769    }
1770
1771    SkScalar    width = 0;
1772    SkPoint     start;
1773
1774    start.set(0, 0);    // to avoid warning
1775    if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
1776                            SkPaint::kStrikeThruText_Flag)) {
1777        width = paint.measureText(text, byteLength);
1778
1779        SkScalar offsetX = 0;
1780        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
1781            offsetX = SkScalarHalf(width);
1782        } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
1783            offsetX = width;
1784        }
1785        start.set(x - offsetX, y);
1786    }
1787
1788    if (0 == width) {
1789        return;
1790    }
1791
1792    uint32_t flags = paint.getFlags();
1793
1794    if (flags & (SkPaint::kUnderlineText_Flag |
1795                 SkPaint::kStrikeThruText_Flag)) {
1796        SkScalar textSize = paint.getTextSize();
1797        SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
1798        SkRect   r;
1799
1800        r.fLeft = start.fX;
1801        r.fRight = start.fX + width;
1802
1803        if (flags & SkPaint::kUnderlineText_Flag) {
1804            SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
1805                                             start.fY);
1806            r.fTop = offset;
1807            r.fBottom = offset + height;
1808            DrawRect(draw, paint, r, textSize);
1809        }
1810        if (flags & SkPaint::kStrikeThruText_Flag) {
1811            SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
1812                                             start.fY);
1813            r.fTop = offset;
1814            r.fBottom = offset + height;
1815            DrawRect(draw, paint, r, textSize);
1816        }
1817    }
1818}
1819
1820void SkCanvas::drawText(const void* text, size_t byteLength,
1821                        SkScalar x, SkScalar y, const SkPaint& paint) {
1822    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1823
1824    while (iter.next()) {
1825        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1826        iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
1827        DrawTextDecorations(iter, dfp.paint(),
1828                            static_cast<const char*>(text), byteLength, x, y);
1829    }
1830
1831    LOOPER_END
1832}
1833
1834void SkCanvas::drawPosText(const void* text, size_t byteLength,
1835                           const SkPoint pos[], const SkPaint& paint) {
1836    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1837
1838    while (iter.next()) {
1839        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1840        iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
1841                                  dfp.paint());
1842    }
1843
1844    LOOPER_END
1845}
1846
1847void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
1848                            const SkScalar xpos[], SkScalar constY,
1849                            const SkPaint& paint) {
1850    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1851
1852    while (iter.next()) {
1853        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1854        iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
1855                                  dfp.paint());
1856    }
1857
1858    LOOPER_END
1859}
1860
1861void SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
1862                              const SkPath& path, const SkMatrix* matrix,
1863                              const SkPaint& paint) {
1864    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1865
1866    while (iter.next()) {
1867        iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
1868                                     matrix, looper.paint());
1869    }
1870
1871    LOOPER_END
1872}
1873
1874#ifdef SK_BUILD_FOR_ANDROID
1875void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength,
1876                                 const SkPoint pos[], const SkPaint& paint,
1877                                 const SkPath& path, const SkMatrix* matrix) {
1878    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1879
1880    while (iter.next()) {
1881        iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos,
1882                                        looper.paint(), path, matrix);
1883    }
1884
1885    LOOPER_END
1886}
1887#endif
1888
1889void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
1890                            const SkPoint verts[], const SkPoint texs[],
1891                            const SkColor colors[], SkXfermode* xmode,
1892                            const uint16_t indices[], int indexCount,
1893                            const SkPaint& paint) {
1894    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
1895
1896    while (iter.next()) {
1897        iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
1898                                   colors, xmode, indices, indexCount,
1899                                   looper.paint());
1900    }
1901
1902    LOOPER_END
1903}
1904
1905void SkCanvas::drawData(const void* data, size_t length) {
1906    // do nothing. Subclasses may do something with the data
1907}
1908
1909//////////////////////////////////////////////////////////////////////////////
1910// These methods are NOT virtual, and therefore must call back into virtual
1911// methods, rather than actually drawing themselves.
1912//////////////////////////////////////////////////////////////////////////////
1913
1914void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
1915                        SkXfermode::Mode mode) {
1916    SkPaint paint;
1917
1918    paint.setARGB(a, r, g, b);
1919    if (SkXfermode::kSrcOver_Mode != mode) {
1920        paint.setXfermodeMode(mode);
1921    }
1922    this->drawPaint(paint);
1923}
1924
1925void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
1926    SkPaint paint;
1927
1928    paint.setColor(c);
1929    if (SkXfermode::kSrcOver_Mode != mode) {
1930        paint.setXfermodeMode(mode);
1931    }
1932    this->drawPaint(paint);
1933}
1934
1935void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
1936    SkPoint pt;
1937
1938    pt.set(x, y);
1939    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1940}
1941
1942void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
1943    SkPoint pt;
1944    SkPaint paint;
1945
1946    pt.set(x, y);
1947    paint.setColor(color);
1948    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1949}
1950
1951void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
1952                        const SkPaint& paint) {
1953    SkPoint pts[2];
1954
1955    pts[0].set(x0, y0);
1956    pts[1].set(x1, y1);
1957    this->drawPoints(kLines_PointMode, 2, pts, paint);
1958}
1959
1960void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
1961                              SkScalar right, SkScalar bottom,
1962                              const SkPaint& paint) {
1963    SkRect  r;
1964
1965    r.set(left, top, right, bottom);
1966    this->drawRect(r, paint);
1967}
1968
1969void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
1970                          const SkPaint& paint) {
1971    if (radius < 0) {
1972        radius = 0;
1973    }
1974
1975    SkRect  r;
1976    r.set(cx - radius, cy - radius, cx + radius, cy + radius);
1977
1978    if (paint.canComputeFastBounds()) {
1979        SkRect storage;
1980        if (this->quickReject(paint.computeFastBounds(r, &storage))) {
1981            return;
1982        }
1983    }
1984
1985    SkPath  path;
1986    path.addOval(r);
1987    this->drawPath(path, paint);
1988}
1989
1990void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
1991                             const SkPaint& paint) {
1992    if (rx > 0 && ry > 0) {
1993        if (paint.canComputeFastBounds()) {
1994            SkRect storage;
1995            if (this->quickReject(paint.computeFastBounds(r, &storage))) {
1996                return;
1997            }
1998        }
1999
2000        SkPath  path;
2001        path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
2002        this->drawPath(path, paint);
2003    } else {
2004        this->drawRect(r, paint);
2005    }
2006}
2007
2008void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
2009    if (paint.canComputeFastBounds()) {
2010        SkRect storage;
2011        if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2012            return;
2013        }
2014    }
2015
2016    SkPath  path;
2017    path.addOval(oval);
2018    this->drawPath(path, paint);
2019}
2020
2021void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2022                       SkScalar sweepAngle, bool useCenter,
2023                       const SkPaint& paint) {
2024    if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2025        this->drawOval(oval, paint);
2026    } else {
2027        SkPath  path;
2028        if (useCenter) {
2029            path.moveTo(oval.centerX(), oval.centerY());
2030        }
2031        path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2032        if (useCenter) {
2033            path.close();
2034        }
2035        this->drawPath(path, paint);
2036    }
2037}
2038
2039void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2040                                const SkPath& path, SkScalar hOffset,
2041                                SkScalar vOffset, const SkPaint& paint) {
2042    SkMatrix    matrix;
2043
2044    matrix.setTranslate(hOffset, vOffset);
2045    this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2046}
2047
2048///////////////////////////////////////////////////////////////////////////////
2049
2050void SkCanvas::drawPicture(SkPicture& picture) {
2051    picture.draw(this);
2052}
2053
2054///////////////////////////////////////////////////////////////////////////////
2055///////////////////////////////////////////////////////////////////////////////
2056
2057SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
2058    SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
2059
2060    SkASSERT(canvas);
2061
2062    fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2063    fDone = !fImpl->next();
2064}
2065
2066SkCanvas::LayerIter::~LayerIter() {
2067    fImpl->~SkDrawIter();
2068}
2069
2070void SkCanvas::LayerIter::next() {
2071    fDone = !fImpl->next();
2072}
2073
2074SkDevice* SkCanvas::LayerIter::device() const {
2075    return fImpl->getDevice();
2076}
2077
2078const SkMatrix& SkCanvas::LayerIter::matrix() const {
2079    return fImpl->getMatrix();
2080}
2081
2082const SkPaint& SkCanvas::LayerIter::paint() const {
2083    const SkPaint* paint = fImpl->getPaint();
2084    if (NULL == paint) {
2085        paint = &fDefaultPaint;
2086    }
2087    return *paint;
2088}
2089
2090const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2091int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2092int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
2093
2094///////////////////////////////////////////////////////////////////////////////
2095
2096SkCanvas::ClipVisitor::~ClipVisitor() { }
2097
2098
2099