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