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