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