SkCanvas.cpp revision c0784dbd408596aff13a5d97448f7a9e5d3cf7d9
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 "SkBitmapDevice.h"
12#include "SkBounder.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 "SkSurface_Base.h"
23#include "SkTemplates.h"
24#include "SkTextFormatParams.h"
25#include "SkTLazy.h"
26#include "SkUtils.h"
27
28#if SK_SUPPORT_GPU
29#include "GrRenderTarget.h"
30#endif
31
32// experimental for faster tiled drawing...
33//#define SK_ENABLE_CLIP_QUICKREJECT
34
35//#define SK_TRACE_SAVERESTORE
36
37#ifdef SK_TRACE_SAVERESTORE
38    static int gLayerCounter;
39    static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
40    static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
41
42    static int gRecCounter;
43    static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
44    static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
45
46    static int gCanvasCounter;
47    static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
48    static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
49#else
50    #define inc_layer()
51    #define dec_layer()
52    #define inc_rec()
53    #define dec_rec()
54    #define inc_canvas()
55    #define dec_canvas()
56#endif
57
58#ifdef SK_DEBUG
59#include "SkPixelRef.h"
60
61/*
62 *  Some pixelref subclasses can support being "locked" from another thread
63 *  during the lock-scope of skia calling them. In these instances, this balance
64 *  check will fail, but may not be indicative of a problem, so we allow a build
65 *  flag to disable this check.
66 *
67 *  Potentially another fix would be to have a (debug-only) virtual or flag on
68 *  pixelref, which could tell us at runtime if this check is valid. That would
69 *  eliminate the need for this heavy-handed build check.
70 */
71#ifdef SK_DISABLE_PIXELREF_LOCKCOUNT_BALANCE_CHECK
72class AutoCheckLockCountBalance {
73public:
74    AutoCheckLockCountBalance(const SkBitmap&) { /* do nothing */ }
75};
76#else
77class AutoCheckLockCountBalance {
78public:
79    AutoCheckLockCountBalance(const SkBitmap& bm) : fPixelRef(bm.pixelRef()) {
80        fLockCount = fPixelRef ? fPixelRef->getLockCount() : 0;
81    }
82    ~AutoCheckLockCountBalance() {
83        const int count = fPixelRef ? fPixelRef->getLockCount() : 0;
84        SkASSERT(count == fLockCount);
85    }
86
87private:
88    const SkPixelRef* fPixelRef;
89    int               fLockCount;
90};
91#endif
92
93class AutoCheckNoSetContext {
94public:
95    AutoCheckNoSetContext(const SkPaint& paint) : fPaint(paint) {
96        this->assertNoSetContext(fPaint);
97    }
98    ~AutoCheckNoSetContext() {
99        this->assertNoSetContext(fPaint);
100    }
101
102private:
103    const SkPaint& fPaint;
104
105    void assertNoSetContext(const SkPaint& paint) {
106        SkShader* s = paint.getShader();
107        if (s) {
108            SkASSERT(!s->setContextHasBeenCalled());
109        }
110    }
111};
112
113#define CHECK_LOCKCOUNT_BALANCE(bitmap)  AutoCheckLockCountBalance clcb(bitmap)
114#define CHECK_SHADER_NOSETCONTEXT(paint) AutoCheckNoSetContext     cshsc(paint)
115
116#else
117    #define CHECK_LOCKCOUNT_BALANCE(bitmap)
118    #define CHECK_SHADER_NOSETCONTEXT(paint)
119#endif
120
121typedef SkTLazy<SkPaint> SkLazyPaint;
122
123void SkCanvas::predrawNotify() {
124    if (fSurfaceBase) {
125        fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode);
126    }
127}
128
129///////////////////////////////////////////////////////////////////////////////
130
131/*  This is the record we keep for each SkBaseDevice that the user installs.
132    The clip/matrix/proc are fields that reflect the top of the save/restore
133    stack. Whenever the canvas changes, it marks a dirty flag, and then before
134    these are used (assuming we're not on a layer) we rebuild these cache
135    values: they reflect the top of the save stack, but translated and clipped
136    by the device's XY offset and bitmap-bounds.
137*/
138struct DeviceCM {
139    DeviceCM*           fNext;
140    SkBaseDevice*       fDevice;
141    SkRasterClip        fClip;
142    const SkMatrix*     fMatrix;
143    SkPaint*            fPaint; // may be null (in the future)
144
145    DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas)
146            : fNext(NULL) {
147        if (NULL != device) {
148            device->ref();
149            device->onAttachToCanvas(canvas);
150        }
151        fDevice = device;
152        fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
153    }
154
155    ~DeviceCM() {
156        if (NULL != fDevice) {
157            fDevice->onDetachFromCanvas();
158            fDevice->unref();
159        }
160        SkDELETE(fPaint);
161    }
162
163    void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
164                  const SkClipStack& clipStack, SkRasterClip* updateClip) {
165        int x = fDevice->getOrigin().x();
166        int y = fDevice->getOrigin().y();
167        int width = fDevice->width();
168        int height = fDevice->height();
169
170        if ((x | y) == 0) {
171            fMatrix = &totalMatrix;
172            fClip = totalClip;
173        } else {
174            fMatrixStorage = totalMatrix;
175            fMatrixStorage.postTranslate(SkIntToScalar(-x),
176                                         SkIntToScalar(-y));
177            fMatrix = &fMatrixStorage;
178
179            totalClip.translate(-x, -y, &fClip);
180        }
181
182        fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
183
184        // intersect clip, but don't translate it (yet)
185
186        if (updateClip) {
187            updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
188                           SkRegion::kDifference_Op);
189        }
190
191        fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
192
193#ifdef SK_DEBUG
194        if (!fClip.isEmpty()) {
195            SkIRect deviceR;
196            deviceR.set(0, 0, width, height);
197            SkASSERT(deviceR.contains(fClip.getBounds()));
198        }
199#endif
200    }
201
202private:
203    SkMatrix    fMatrixStorage;
204};
205
206/*  This is the record we keep for each save/restore level in the stack.
207    Since a level optionally copies the matrix and/or stack, we have pointers
208    for these fields. If the value is copied for this level, the copy is
209    stored in the ...Storage field, and the pointer points to that. If the
210    value is not copied for this level, we ignore ...Storage, and just point
211    at the corresponding value in the previous level in the stack.
212*/
213class SkCanvas::MCRec {
214public:
215    MCRec*          fNext;
216    int             fFlags;
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) : fFlags(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    SkBaseDevice* 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#define SkAutoBounderCommit(...) SK_REQUIRE_LOCAL_VAR(SkAutoBounderCommit)
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
485SkBaseDevice* SkCanvas::init(SkBaseDevice* device) {
486    fBounder = NULL;
487    fCachedLocalClipBounds.setEmpty();
488    fCachedLocalClipBoundsDirty = 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(SkBaseDevice* 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(SkBitmapDevice, (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    SkBaseDevice* device = this->getDevice();
568    if (device) {
569        device->flush();
570    }
571}
572
573SkISize SkCanvas::getDeviceSize() const {
574    SkBaseDevice* d = this->getDevice();
575    return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
576}
577
578SkBaseDevice* 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
585SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
586    if (updateMatrixClip) {
587        const_cast<SkCanvas*>(this)->updateDeviceCMCache();
588    }
589    return fMCRec->fTopLayer->fDevice;
590}
591
592SkBaseDevice* SkCanvas::setDevice(SkBaseDevice* device) {
593    // return root device
594    SkDeque::F2BIter iter(fMCStack);
595    MCRec*           rec = (MCRec*)iter.next();
596    SkASSERT(rec && rec->fLayer);
597    SkBaseDevice*    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    SkBaseDevice* 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    SkBaseDevice* 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    SkBaseDevice* 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        SkBaseDevice* 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    SkBaseDevice* 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    fCachedLocalClipBoundsDirty = 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
934int SkCanvas::getSaveCount() const {
935    return fMCStack.count();
936}
937
938void SkCanvas::restoreToCount(int count) {
939    // sanity check
940    if (count < 1) {
941        count = 1;
942    }
943
944    int n = this->getSaveCount() - count;
945    for (int i = 0; i < n; ++i) {
946        this->restore();
947    }
948}
949
950bool SkCanvas::isDrawingToLayer() const {
951    return fSaveLayerCount > 0;
952}
953
954/////////////////////////////////////////////////////////////////////////////
955
956// can't draw it if its empty, or its too big for a fixed-point width or height
957static bool reject_bitmap(const SkBitmap& bitmap) {
958    return  bitmap.width() <= 0 || bitmap.height() <= 0;
959}
960
961void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
962                                const SkMatrix& matrix, const SkPaint* paint) {
963    if (reject_bitmap(bitmap)) {
964        return;
965    }
966
967    SkLazyPaint lazy;
968    if (NULL == paint) {
969        paint = lazy.init();
970    }
971
972    SkDEBUGCODE(bitmap.validate();)
973    CHECK_LOCKCOUNT_BALANCE(bitmap);
974
975    LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
976
977    while (iter.next()) {
978        iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
979    }
980
981    LOOPER_END
982}
983
984void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
985                                  const SkPaint* paint) {
986    SkPaint tmp;
987    if (NULL == paint) {
988        tmp.setDither(true);
989        paint = &tmp;
990    }
991
992    LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
993    while (iter.next()) {
994        SkBaseDevice* dstDev = iter.fDevice;
995        paint = &looper.paint();
996        SkImageFilter* filter = paint->getImageFilter();
997        SkIPoint pos = { x - iter.getX(), y - iter.getY() };
998        if (filter && !dstDev->canHandleImageFilter(filter)) {
999            SkDeviceImageFilterProxy proxy(dstDev);
1000            SkBitmap dst;
1001            const SkBitmap& src = srcDev->accessBitmap(false);
1002            SkMatrix matrix = *iter.fMatrix;
1003            matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
1004            if (filter->filterImage(&proxy, src, matrix, &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            SkMatrix matrix = *iter.fMatrix;
1040            matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
1041            if (filter->filterImage(&proxy, bitmap, matrix, &dst, &pos)) {
1042                SkPaint tmpUnfiltered(*paint);
1043                tmpUnfiltered.setImageFilter(NULL);
1044                iter.fDevice->drawSprite(iter, dst, pos.x(), pos.y(),
1045                                         tmpUnfiltered);
1046            }
1047        } else {
1048            iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1049        }
1050    }
1051    LOOPER_END
1052}
1053
1054/////////////////////////////////////////////////////////////////////////////
1055
1056bool SkCanvas::translate(SkScalar dx, SkScalar dy) {
1057    fDeviceCMDirty = true;
1058    fCachedLocalClipBoundsDirty = true;
1059    return fMCRec->fMatrix->preTranslate(dx, dy);
1060}
1061
1062bool SkCanvas::scale(SkScalar sx, SkScalar sy) {
1063    fDeviceCMDirty = true;
1064    fCachedLocalClipBoundsDirty = true;
1065    return fMCRec->fMatrix->preScale(sx, sy);
1066}
1067
1068bool SkCanvas::rotate(SkScalar degrees) {
1069    fDeviceCMDirty = true;
1070    fCachedLocalClipBoundsDirty = true;
1071    return fMCRec->fMatrix->preRotate(degrees);
1072}
1073
1074bool SkCanvas::skew(SkScalar sx, SkScalar sy) {
1075    fDeviceCMDirty = true;
1076    fCachedLocalClipBoundsDirty = true;
1077    return fMCRec->fMatrix->preSkew(sx, sy);
1078}
1079
1080bool SkCanvas::concat(const SkMatrix& matrix) {
1081    fDeviceCMDirty = true;
1082    fCachedLocalClipBoundsDirty = true;
1083    return fMCRec->fMatrix->preConcat(matrix);
1084}
1085
1086void SkCanvas::setMatrix(const SkMatrix& matrix) {
1087    fDeviceCMDirty = true;
1088    fCachedLocalClipBoundsDirty = true;
1089    *fMCRec->fMatrix = matrix;
1090}
1091
1092// this is not virtual, so it must call a virtual method so that subclasses
1093// will see its action
1094void SkCanvas::resetMatrix() {
1095    SkMatrix matrix;
1096
1097    matrix.reset();
1098    this->setMatrix(matrix);
1099}
1100
1101//////////////////////////////////////////////////////////////////////////////
1102
1103bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
1104#ifdef SK_ENABLE_CLIP_QUICKREJECT
1105    if (SkRegion::kIntersect_Op == op) {
1106        if (fMCRec->fRasterClip->isEmpty()) {
1107            return false;
1108        }
1109
1110        if (this->quickReject(rect)) {
1111            fDeviceCMDirty = true;
1112            fCachedLocalClipBoundsDirty = true;
1113
1114            fClipStack.clipEmpty();
1115            return fMCRec->fRasterClip->setEmpty();
1116        }
1117    }
1118#endif
1119
1120    AutoValidateClip avc(this);
1121
1122    fDeviceCMDirty = true;
1123    fCachedLocalClipBoundsDirty = true;
1124    doAA &= fAllowSoftClip;
1125
1126    if (fMCRec->fMatrix->rectStaysRect()) {
1127        // for these simpler matrices, we can stay a rect even after applying
1128        // the matrix. This means we don't have to a) make a path, and b) tell
1129        // the region code to scan-convert the path, only to discover that it
1130        // is really just a rect.
1131        SkRect      r;
1132
1133        fMCRec->fMatrix->mapRect(&r, rect);
1134        fClipStack.clipDevRect(r, op, doAA);
1135        return fMCRec->fRasterClip->op(r, op, doAA);
1136    } else {
1137        // since we're rotated or some such thing, we convert the rect to a path
1138        // and clip against that, since it can handle any matrix. However, to
1139        // avoid recursion in the case where we are subclassed (e.g. Pictures)
1140        // we explicitly call "our" version of clipPath.
1141        SkPath  path;
1142
1143        path.addRect(rect);
1144        return this->SkCanvas::clipPath(path, op, doAA);
1145    }
1146}
1147
1148static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip,
1149                           const SkPath& devPath, SkRegion::Op op, bool doAA) {
1150    // base is used to limit the size (and therefore memory allocation) of the
1151    // region that results from scan converting devPath.
1152    SkRegion base;
1153
1154    if (SkRegion::kIntersect_Op == op) {
1155        // since we are intersect, we can do better (tighter) with currRgn's
1156        // bounds, than just using the device. However, if currRgn is complex,
1157        // our region blitter may hork, so we do that case in two steps.
1158        if (currClip->isRect()) {
1159            // FIXME: we should also be able to do this when currClip->isBW(),
1160            // but relaxing the test above triggers GM asserts in
1161            // SkRgnBuilder::blitH(). We need to investigate what's going on.
1162            return currClip->setPath(devPath, currClip->bwRgn(), doAA);
1163        } else {
1164            base.setRect(currClip->getBounds());
1165            SkRasterClip clip;
1166            clip.setPath(devPath, base, doAA);
1167            return currClip->op(clip, op);
1168        }
1169    } else {
1170        const SkBaseDevice* device = canvas->getDevice();
1171        if (!device) {
1172            return currClip->setEmpty();
1173        }
1174
1175        base.setRect(0, 0, device->width(), device->height());
1176
1177        if (SkRegion::kReplace_Op == op) {
1178            return currClip->setPath(devPath, base, doAA);
1179        } else {
1180            SkRasterClip clip;
1181            clip.setPath(devPath, base, doAA);
1182            return currClip->op(clip, op);
1183        }
1184    }
1185}
1186
1187bool SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
1188    if (rrect.isRect()) {
1189        // call the non-virtual version
1190        return this->SkCanvas::clipRect(rrect.getBounds(), op, doAA);
1191    } else {
1192        SkPath path;
1193        path.addRRect(rrect);
1194        // call the non-virtual version
1195        return this->SkCanvas::clipPath(path, op, doAA);
1196    }
1197}
1198
1199bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
1200#ifdef SK_ENABLE_CLIP_QUICKREJECT
1201    if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
1202        if (fMCRec->fRasterClip->isEmpty()) {
1203            return false;
1204        }
1205
1206        if (this->quickReject(path.getBounds())) {
1207            fDeviceCMDirty = true;
1208            fCachedLocalClipBoundsDirty = true;
1209
1210            fClipStack.clipEmpty();
1211            return fMCRec->fRasterClip->setEmpty();
1212        }
1213    }
1214#endif
1215
1216    AutoValidateClip avc(this);
1217
1218    fDeviceCMDirty = true;
1219    fCachedLocalClipBoundsDirty = true;
1220    doAA &= fAllowSoftClip;
1221
1222    SkPath devPath;
1223    path.transform(*fMCRec->fMatrix, &devPath);
1224
1225    // Check if the transfomation, or the original path itself
1226    // made us empty. Note this can also happen if we contained NaN
1227    // values. computing the bounds detects this, and will set our
1228    // bounds to empty if that is the case. (see SkRect::set(pts, count))
1229    if (devPath.getBounds().isEmpty()) {
1230        // resetting the path will remove any NaN or other wanky values
1231        // that might upset our scan converter.
1232        devPath.reset();
1233    }
1234
1235    // if we called path.swap() we could avoid a deep copy of this path
1236    fClipStack.clipDevPath(devPath, op, doAA);
1237
1238    if (fAllowSimplifyClip) {
1239        devPath.reset();
1240        devPath.setFillType(SkPath::kInverseEvenOdd_FillType);
1241        const SkClipStack* clipStack = getClipStack();
1242        SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
1243        const SkClipStack::Element* element;
1244        while ((element = iter.next())) {
1245            SkClipStack::Element::Type type = element->getType();
1246            if (type == SkClipStack::Element::kEmpty_Type) {
1247                continue;
1248            }
1249            SkPath operand;
1250            if (type == SkClipStack::Element::kRect_Type) {
1251                operand.addRect(element->getRect());
1252            } else if (type == SkClipStack::Element::kPath_Type) {
1253                operand = element->getPath();
1254            } else {
1255                SkDEBUGFAIL("Unexpected type.");
1256            }
1257            SkRegion::Op elementOp = element->getOp();
1258            if (elementOp == SkRegion::kReplace_Op) {
1259                devPath = operand;
1260            } else {
1261                Op(devPath, operand, (SkPathOp) elementOp, &devPath);
1262            }
1263            // if the prev and curr clips disagree about aa -vs- not, favor the aa request.
1264            // perhaps we need an API change to avoid this sort of mixed-signals about
1265            // clipping.
1266            doAA |= element->isAA();
1267        }
1268        op = SkRegion::kReplace_Op;
1269    }
1270
1271    return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA);
1272}
1273
1274bool SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op,
1275                                                   bool inverseFilled) {
1276    // This is for updating the clip conservatively using only bounds
1277    // information.
1278    // Contract:
1279    //    The current clip must contain the true clip. The true
1280    //    clip is the clip that would have normally been computed
1281    //    by calls to clipPath and clipRRect
1282    // Objective:
1283    //    Keep the current clip as small as possible without
1284    //    breaking the contract, using only clip bounding rectangles
1285    //    (for performance).
1286
1287    // N.B.: This *never* calls back through a virtual on canvas, so subclasses
1288    // don't have to worry about getting caught in a loop. Thus anywhere
1289    // we call a virtual method, we explicitly prefix it with
1290    // SkCanvas:: to be sure to call the base-class.
1291
1292    if (inverseFilled) {
1293        switch (op) {
1294            case SkRegion::kIntersect_Op:
1295            case SkRegion::kDifference_Op:
1296                // These ops can only shrink the current clip. So leaving
1297                // the clip unchanges conservatively respects the contract.
1298                return this->getClipDeviceBounds(NULL);
1299            case SkRegion::kUnion_Op:
1300            case SkRegion::kReplace_Op:
1301            case SkRegion::kReverseDifference_Op:
1302            case SkRegion::kXOR_Op:
1303                {
1304                    // These ops can grow the current clip up to the extents of
1305                    // the input clip, which is inverse filled, so we just set
1306                    // the current clip to the device bounds.
1307                    SkRect deviceBounds;
1308                    SkIRect deviceIBounds;
1309                    this->getDevice()->getGlobalBounds(&deviceIBounds);
1310                    deviceBounds = SkRect::Make(deviceIBounds);
1311                    this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag);
1312                    // set the clip in device space
1313                    this->SkCanvas::setMatrix(SkMatrix::I());
1314                    bool result = this->SkCanvas::clipRect(deviceBounds,
1315                        SkRegion::kReplace_Op, false);
1316                    this->SkCanvas::restore(); //pop the matrix, but keep the clip
1317                    return result;
1318                }
1319            default:
1320                SkASSERT(0); // unhandled op?
1321        }
1322    } else {
1323        // Not inverse filled
1324        switch (op) {
1325            case SkRegion::kIntersect_Op:
1326            case SkRegion::kUnion_Op:
1327            case SkRegion::kReplace_Op:
1328                return this->SkCanvas::clipRect(bounds, op, false);
1329            case SkRegion::kDifference_Op:
1330                // Difference can only shrink the current clip.
1331                // Leaving clip unchanged conservatively fullfills the contract.
1332                return this->getClipDeviceBounds(NULL);
1333            case SkRegion::kReverseDifference_Op:
1334                // To reverse, we swap in the bounds with a replace op.
1335                // As with difference, leave it unchanged.
1336                return this->SkCanvas::clipRect(bounds, SkRegion::kReplace_Op, false);
1337            case SkRegion::kXOR_Op:
1338                // Be conservative, based on (A XOR B) always included in (A union B),
1339                // which is always included in (bounds(A) union bounds(B))
1340                return this->SkCanvas::clipRect(bounds, SkRegion::kUnion_Op, false);
1341            default:
1342                SkASSERT(0); // unhandled op?
1343        }
1344    }
1345    return true;
1346}
1347
1348bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
1349    AutoValidateClip avc(this);
1350
1351    fDeviceCMDirty = true;
1352    fCachedLocalClipBoundsDirty = true;
1353
1354    // todo: signal fClipStack that we have a region, and therefore (I guess)
1355    // we have to ignore it, and use the region directly?
1356    fClipStack.clipDevRect(rgn.getBounds(), op);
1357
1358    return fMCRec->fRasterClip->op(rgn, op);
1359}
1360
1361#ifdef SK_DEBUG
1362void SkCanvas::validateClip() const {
1363    // construct clipRgn from the clipstack
1364    const SkBaseDevice* device = this->getDevice();
1365    if (!device) {
1366        SkASSERT(this->getTotalClip().isEmpty());
1367        return;
1368    }
1369
1370    SkIRect ir;
1371    ir.set(0, 0, device->width(), device->height());
1372    SkRasterClip tmpClip(ir);
1373
1374    SkClipStack::B2TIter                iter(fClipStack);
1375    const SkClipStack::Element* element;
1376    while ((element = iter.next()) != NULL) {
1377        switch (element->getType()) {
1378            case SkClipStack::Element::kPath_Type:
1379                clipPathHelper(this,
1380                               &tmpClip,
1381                               element->getPath(),
1382                               element->getOp(),
1383                               element->isAA());
1384                break;
1385            case SkClipStack::Element::kRect_Type:
1386                element->getRect().round(&ir);
1387                tmpClip.op(ir, element->getOp());
1388                break;
1389            case SkClipStack::Element::kEmpty_Type:
1390                tmpClip.setEmpty();
1391                break;
1392        }
1393    }
1394
1395#if 0   // enable this locally for testing
1396    // now compare against the current rgn
1397    const SkRegion& rgn = this->getTotalClip();
1398    SkASSERT(rgn == tmpClip);
1399#endif
1400}
1401#endif
1402
1403void SkCanvas::replayClips(ClipVisitor* visitor) const {
1404    SkClipStack::B2TIter                iter(fClipStack);
1405    const SkClipStack::Element*         element;
1406
1407    static const SkRect kEmpty = { 0, 0, 0, 0 };
1408    while ((element = iter.next()) != NULL) {
1409        switch (element->getType()) {
1410            case SkClipStack::Element::kPath_Type:
1411                visitor->clipPath(element->getPath(), element->getOp(), element->isAA());
1412                break;
1413            case SkClipStack::Element::kRect_Type:
1414                visitor->clipRect(element->getRect(), element->getOp(), element->isAA());
1415                break;
1416            case SkClipStack::Element::kEmpty_Type:
1417                visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false);
1418                break;
1419        }
1420    }
1421}
1422
1423///////////////////////////////////////////////////////////////////////////////
1424
1425bool SkCanvas::quickReject(const SkRect& rect) const {
1426
1427    if (!rect.isFinite())
1428        return true;
1429
1430    if (fMCRec->fRasterClip->isEmpty()) {
1431        return true;
1432    }
1433
1434    if (fMCRec->fMatrix->hasPerspective()) {
1435        SkRect dst;
1436        fMCRec->fMatrix->mapRect(&dst, rect);
1437        SkIRect idst;
1438        dst.roundOut(&idst);
1439        return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds());
1440    } else {
1441        const SkRect& clipR = this->getLocalClipBounds();
1442
1443        // for speed, do the most likely reject compares first
1444        // TODO: should we use | instead, or compare all 4 at once?
1445        if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
1446            return true;
1447        }
1448        if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
1449            return true;
1450        }
1451        return false;
1452    }
1453}
1454
1455bool SkCanvas::quickReject(const SkPath& path) const {
1456    return path.isEmpty() || this->quickReject(path.getBounds());
1457}
1458
1459static inline int pinIntForScalar(int x) {
1460#ifdef SK_SCALAR_IS_FIXED
1461    if (x < SK_MinS16) {
1462        x = SK_MinS16;
1463    } else if (x > SK_MaxS16) {
1464        x = SK_MaxS16;
1465    }
1466#endif
1467    return x;
1468}
1469
1470bool SkCanvas::getClipBounds(SkRect* bounds) const {
1471    SkIRect ibounds;
1472    if (!getClipDeviceBounds(&ibounds)) {
1473        return false;
1474    }
1475
1476    SkMatrix inverse;
1477    // if we can't invert the CTM, we can't return local clip bounds
1478    if (!fMCRec->fMatrix->invert(&inverse)) {
1479        if (bounds) {
1480            bounds->setEmpty();
1481        }
1482        return false;
1483    }
1484
1485    if (NULL != bounds) {
1486        SkRect r;
1487        // adjust it outwards in case we are antialiasing
1488        const int inset = 1;
1489
1490        // SkRect::iset() will correctly assert if we pass a value out of range
1491        // (when SkScalar==fixed), so we pin to legal values. This does not
1492        // really returnt the correct answer, but its the best we can do given
1493        // that we've promised to return SkRect (even though we support devices
1494        // that can be larger than 32K in width or height).
1495        r.iset(pinIntForScalar(ibounds.fLeft - inset),
1496               pinIntForScalar(ibounds.fTop - inset),
1497               pinIntForScalar(ibounds.fRight + inset),
1498               pinIntForScalar(ibounds.fBottom + inset));
1499        inverse.mapRect(bounds, r);
1500    }
1501    return true;
1502}
1503
1504bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
1505    const SkRasterClip& clip = *fMCRec->fRasterClip;
1506    if (clip.isEmpty()) {
1507        if (bounds) {
1508            bounds->setEmpty();
1509        }
1510        return false;
1511    }
1512
1513    if (NULL != bounds) {
1514        *bounds = clip.getBounds();
1515    }
1516    return true;
1517}
1518
1519const SkMatrix& SkCanvas::getTotalMatrix() const {
1520    return *fMCRec->fMatrix;
1521}
1522
1523SkCanvas::ClipType SkCanvas::getClipType() const {
1524    if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType;
1525    if (fMCRec->fRasterClip->isRect()) return kRect_ClipType;
1526    return kComplex_ClipType;
1527}
1528
1529const SkRegion& SkCanvas::getTotalClip() const {
1530    return fMCRec->fRasterClip->forceGetBW();
1531}
1532
1533SkBaseDevice* SkCanvas::createLayerDevice(SkBitmap::Config config,
1534                                      int width, int height,
1535                                      bool isOpaque) {
1536    SkBaseDevice* device = this->getTopDevice();
1537    if (device) {
1538        return device->createCompatibleDeviceForSaveLayer(config, width, height,
1539                                                          isOpaque);
1540    } else {
1541        return NULL;
1542    }
1543}
1544
1545SkBaseDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config,
1546                                           int width, int height,
1547                                           bool isOpaque) {
1548    SkBaseDevice* device = this->getDevice();
1549    if (device) {
1550        return device->createCompatibleDevice(config, width, height, isOpaque);
1551    } else {
1552        return NULL;
1553    }
1554}
1555
1556GrContext* SkCanvas::getGrContext() {
1557#if SK_SUPPORT_GPU
1558    SkBaseDevice* device = this->getTopDevice();
1559    if (NULL != device) {
1560        GrRenderTarget* renderTarget = device->accessRenderTarget();
1561        if (NULL != renderTarget) {
1562            return renderTarget->getContext();
1563        }
1564    }
1565#endif
1566
1567    return NULL;
1568
1569}
1570
1571//////////////////////////////////////////////////////////////////////////////
1572//  These are the virtual drawing methods
1573//////////////////////////////////////////////////////////////////////////////
1574
1575void SkCanvas::clear(SkColor color) {
1576    SkDrawIter  iter(this);
1577    this->predrawNotify();
1578    while (iter.next()) {
1579        iter.fDevice->clear(color);
1580    }
1581}
1582
1583void SkCanvas::drawPaint(const SkPaint& paint) {
1584    this->internalDrawPaint(paint);
1585}
1586
1587void SkCanvas::internalDrawPaint(const SkPaint& paint) {
1588    CHECK_SHADER_NOSETCONTEXT(paint);
1589
1590    LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type)
1591
1592    while (iter.next()) {
1593        iter.fDevice->drawPaint(iter, looper.paint());
1594    }
1595
1596    LOOPER_END
1597}
1598
1599void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
1600                          const SkPaint& paint) {
1601    if ((long)count <= 0) {
1602        return;
1603    }
1604
1605    CHECK_SHADER_NOSETCONTEXT(paint);
1606
1607    if (paint.canComputeFastBounds()) {
1608        SkRect r;
1609        // special-case 2 points (common for drawing a single line)
1610        if (2 == count) {
1611            r.set(pts[0], pts[1]);
1612        } else {
1613            r.set(pts, count);
1614        }
1615        SkRect storage;
1616        if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1617            return;
1618        }
1619    }
1620
1621    SkASSERT(pts != NULL);
1622
1623    LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type)
1624
1625    while (iter.next()) {
1626        iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
1627    }
1628
1629    LOOPER_END
1630}
1631
1632void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1633    CHECK_SHADER_NOSETCONTEXT(paint);
1634
1635    if (paint.canComputeFastBounds()) {
1636        SkRect storage;
1637        if (this->quickReject(paint.computeFastBounds(r, &storage))) {
1638            return;
1639        }
1640    }
1641
1642    LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type)
1643
1644    while (iter.next()) {
1645        iter.fDevice->drawRect(iter, r, looper.paint());
1646    }
1647
1648    LOOPER_END
1649}
1650
1651void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
1652    CHECK_SHADER_NOSETCONTEXT(paint);
1653
1654    if (paint.canComputeFastBounds()) {
1655        SkRect storage;
1656        if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
1657            return;
1658        }
1659    }
1660
1661    LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type)
1662
1663    while (iter.next()) {
1664        iter.fDevice->drawOval(iter, oval, looper.paint());
1665    }
1666
1667    LOOPER_END
1668}
1669
1670void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1671    CHECK_SHADER_NOSETCONTEXT(paint);
1672
1673    if (paint.canComputeFastBounds()) {
1674        SkRect storage;
1675        if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
1676            return;
1677        }
1678    }
1679
1680    if (rrect.isRect()) {
1681        // call the non-virtual version
1682        this->SkCanvas::drawRect(rrect.getBounds(), paint);
1683        return;
1684    } else if (rrect.isOval()) {
1685        // call the non-virtual version
1686        this->SkCanvas::drawOval(rrect.getBounds(), paint);
1687        return;
1688    }
1689
1690    LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type)
1691
1692    while (iter.next()) {
1693        iter.fDevice->drawRRect(iter, rrect, looper.paint());
1694    }
1695
1696    LOOPER_END
1697}
1698
1699
1700void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1701    CHECK_SHADER_NOSETCONTEXT(paint);
1702
1703    if (!path.isFinite()) {
1704        return;
1705    }
1706
1707    if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
1708        SkRect storage;
1709        const SkRect& bounds = path.getBounds();
1710        if (this->quickReject(paint.computeFastBounds(bounds, &storage))) {
1711            return;
1712        }
1713    }
1714    if (path.isEmpty()) {
1715        if (path.isInverseFillType()) {
1716            this->internalDrawPaint(paint);
1717        }
1718        return;
1719    }
1720
1721    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
1722
1723    while (iter.next()) {
1724        iter.fDevice->drawPath(iter, path, looper.paint());
1725    }
1726
1727    LOOPER_END
1728}
1729
1730void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
1731                          const SkPaint* paint) {
1732    SkDEBUGCODE(bitmap.validate();)
1733
1734    if (NULL == paint || paint->canComputeFastBounds()) {
1735        SkRect bounds = {
1736            x, y,
1737            x + SkIntToScalar(bitmap.width()),
1738            y + SkIntToScalar(bitmap.height())
1739        };
1740        if (paint) {
1741            (void)paint->computeFastBounds(bounds, &bounds);
1742        }
1743        if (this->quickReject(bounds)) {
1744            return;
1745        }
1746    }
1747
1748    SkMatrix matrix;
1749    matrix.setTranslate(x, y);
1750    this->internalDrawBitmap(bitmap, matrix, paint);
1751}
1752
1753// this one is non-virtual, so it can be called safely by other canvas apis
1754void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
1755                                      const SkRect& dst, const SkPaint* paint,
1756                                      DrawBitmapRectFlags flags) {
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(), flags);
1783    }
1784
1785    LOOPER_END
1786}
1787
1788void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
1789                                    const SkRect& dst, const SkPaint* paint,
1790                                    DrawBitmapRectFlags flags) {
1791    SkDEBUGCODE(bitmap.validate();)
1792    this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
1793}
1794
1795void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
1796                                const SkPaint* paint) {
1797    SkDEBUGCODE(bitmap.validate();)
1798    this->internalDrawBitmap(bitmap, matrix, paint);
1799}
1800
1801void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1802                                      const SkIRect& center, const SkRect& dst,
1803                                      const SkPaint* paint) {
1804    if (NULL == paint || paint->canComputeFastBounds()) {
1805        SkRect storage;
1806        const SkRect* bounds = &dst;
1807        if (paint) {
1808            bounds = &paint->computeFastBounds(dst, &storage);
1809        }
1810        if (this->quickReject(*bounds)) {
1811            return;
1812        }
1813    }
1814
1815    const int32_t w = bitmap.width();
1816    const int32_t h = bitmap.height();
1817
1818    SkIRect c = center;
1819    // pin center to the bounds of the bitmap
1820    c.fLeft = SkMax32(0, center.fLeft);
1821    c.fTop = SkMax32(0, center.fTop);
1822    c.fRight = SkPin32(center.fRight, c.fLeft, w);
1823    c.fBottom = SkPin32(center.fBottom, c.fTop, h);
1824
1825    const SkScalar srcX[4] = {
1826        0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
1827    };
1828    const SkScalar srcY[4] = {
1829        0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
1830    };
1831    SkScalar dstX[4] = {
1832        dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
1833        dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
1834    };
1835    SkScalar dstY[4] = {
1836        dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
1837        dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
1838    };
1839
1840    if (dstX[1] > dstX[2]) {
1841        dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
1842        dstX[2] = dstX[1];
1843    }
1844
1845    if (dstY[1] > dstY[2]) {
1846        dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
1847        dstY[2] = dstY[1];
1848    }
1849
1850    for (int y = 0; y < 3; y++) {
1851        SkRect s, d;
1852
1853        s.fTop = srcY[y];
1854        s.fBottom = srcY[y+1];
1855        d.fTop = dstY[y];
1856        d.fBottom = dstY[y+1];
1857        for (int x = 0; x < 3; x++) {
1858            s.fLeft = srcX[x];
1859            s.fRight = srcX[x+1];
1860            d.fLeft = dstX[x];
1861            d.fRight = dstX[x+1];
1862            this->internalDrawBitmapRect(bitmap, &s, d, paint,
1863                                         kNone_DrawBitmapRectFlag);
1864        }
1865    }
1866}
1867
1868void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1869                              const SkRect& dst, const SkPaint* paint) {
1870    SkDEBUGCODE(bitmap.validate();)
1871
1872    // Need a device entry-point, so gpu can use a mesh
1873    this->internalDrawBitmapNine(bitmap, center, dst, paint);
1874}
1875
1876class SkDeviceFilteredPaint {
1877public:
1878    SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
1879        SkBaseDevice::TextFlags flags;
1880        if (device->filterTextFlags(paint, &flags)) {
1881            SkPaint* newPaint = fLazy.set(paint);
1882            newPaint->setFlags(flags.fFlags);
1883            newPaint->setHinting(flags.fHinting);
1884            fPaint = newPaint;
1885        } else {
1886            fPaint = &paint;
1887        }
1888    }
1889
1890    const SkPaint& paint() const { return *fPaint; }
1891
1892private:
1893    const SkPaint*  fPaint;
1894    SkLazyPaint     fLazy;
1895};
1896
1897void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
1898                        const SkRect& r, SkScalar textSize) {
1899    if (paint.getStyle() == SkPaint::kFill_Style) {
1900        draw.fDevice->drawRect(draw, r, paint);
1901    } else {
1902        SkPaint p(paint);
1903        p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
1904        draw.fDevice->drawRect(draw, r, p);
1905    }
1906}
1907
1908void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
1909                                   const char text[], size_t byteLength,
1910                                   SkScalar x, SkScalar y) {
1911    SkASSERT(byteLength == 0 || text != NULL);
1912
1913    // nothing to draw
1914    if (text == NULL || byteLength == 0 ||
1915        draw.fClip->isEmpty() ||
1916        (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
1917        return;
1918    }
1919
1920    SkScalar    width = 0;
1921    SkPoint     start;
1922
1923    start.set(0, 0);    // to avoid warning
1924    if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
1925                            SkPaint::kStrikeThruText_Flag)) {
1926        width = paint.measureText(text, byteLength);
1927
1928        SkScalar offsetX = 0;
1929        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
1930            offsetX = SkScalarHalf(width);
1931        } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
1932            offsetX = width;
1933        }
1934        start.set(x - offsetX, y);
1935    }
1936
1937    if (0 == width) {
1938        return;
1939    }
1940
1941    uint32_t flags = paint.getFlags();
1942
1943    if (flags & (SkPaint::kUnderlineText_Flag |
1944                 SkPaint::kStrikeThruText_Flag)) {
1945        SkScalar textSize = paint.getTextSize();
1946        SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
1947        SkRect   r;
1948
1949        r.fLeft = start.fX;
1950        r.fRight = start.fX + width;
1951
1952        if (flags & SkPaint::kUnderlineText_Flag) {
1953            SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
1954                                             start.fY);
1955            r.fTop = offset;
1956            r.fBottom = offset + height;
1957            DrawRect(draw, paint, r, textSize);
1958        }
1959        if (flags & SkPaint::kStrikeThruText_Flag) {
1960            SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
1961                                             start.fY);
1962            r.fTop = offset;
1963            r.fBottom = offset + height;
1964            DrawRect(draw, paint, r, textSize);
1965        }
1966    }
1967}
1968
1969void SkCanvas::drawText(const void* text, size_t byteLength,
1970                        SkScalar x, SkScalar y, const SkPaint& paint) {
1971    CHECK_SHADER_NOSETCONTEXT(paint);
1972
1973    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1974
1975    while (iter.next()) {
1976        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1977        iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
1978        DrawTextDecorations(iter, dfp.paint(),
1979                            static_cast<const char*>(text), byteLength, x, y);
1980    }
1981
1982    LOOPER_END
1983}
1984
1985void SkCanvas::drawPosText(const void* text, size_t byteLength,
1986                           const SkPoint pos[], const SkPaint& paint) {
1987    CHECK_SHADER_NOSETCONTEXT(paint);
1988
1989    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1990
1991    while (iter.next()) {
1992        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1993        iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
1994                                  dfp.paint());
1995    }
1996
1997    LOOPER_END
1998}
1999
2000void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
2001                            const SkScalar xpos[], SkScalar constY,
2002                            const SkPaint& paint) {
2003    CHECK_SHADER_NOSETCONTEXT(paint);
2004
2005    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
2006
2007    while (iter.next()) {
2008        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2009        iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
2010                                  dfp.paint());
2011    }
2012
2013    LOOPER_END
2014}
2015
2016void SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
2017                              const SkPath& path, const SkMatrix* matrix,
2018                              const SkPaint& paint) {
2019    CHECK_SHADER_NOSETCONTEXT(paint);
2020
2021    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
2022
2023    while (iter.next()) {
2024        iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
2025                                     matrix, looper.paint());
2026    }
2027
2028    LOOPER_END
2029}
2030
2031void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
2032                            const SkPoint verts[], const SkPoint texs[],
2033                            const SkColor colors[], SkXfermode* xmode,
2034                            const uint16_t indices[], int indexCount,
2035                            const SkPaint& paint) {
2036    CHECK_SHADER_NOSETCONTEXT(paint);
2037
2038    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
2039
2040    while (iter.next()) {
2041        iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
2042                                   colors, xmode, indices, indexCount,
2043                                   looper.paint());
2044    }
2045
2046    LOOPER_END
2047}
2048
2049//////////////////////////////////////////////////////////////////////////////
2050// These methods are NOT virtual, and therefore must call back into virtual
2051// methods, rather than actually drawing themselves.
2052//////////////////////////////////////////////////////////////////////////////
2053
2054void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
2055                        SkXfermode::Mode mode) {
2056    SkPaint paint;
2057
2058    paint.setARGB(a, r, g, b);
2059    if (SkXfermode::kSrcOver_Mode != mode) {
2060        paint.setXfermodeMode(mode);
2061    }
2062    this->drawPaint(paint);
2063}
2064
2065void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
2066    SkPaint paint;
2067
2068    paint.setColor(c);
2069    if (SkXfermode::kSrcOver_Mode != mode) {
2070        paint.setXfermodeMode(mode);
2071    }
2072    this->drawPaint(paint);
2073}
2074
2075void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
2076    SkPoint pt;
2077
2078    pt.set(x, y);
2079    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2080}
2081
2082void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
2083    SkPoint pt;
2084    SkPaint paint;
2085
2086    pt.set(x, y);
2087    paint.setColor(color);
2088    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2089}
2090
2091void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2092                        const SkPaint& paint) {
2093    SkPoint pts[2];
2094
2095    pts[0].set(x0, y0);
2096    pts[1].set(x1, y1);
2097    this->drawPoints(kLines_PointMode, 2, pts, paint);
2098}
2099
2100void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2101                              SkScalar right, SkScalar bottom,
2102                              const SkPaint& paint) {
2103    SkRect  r;
2104
2105    r.set(left, top, right, bottom);
2106    this->drawRect(r, paint);
2107}
2108
2109void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2110                          const SkPaint& paint) {
2111    if (radius < 0) {
2112        radius = 0;
2113    }
2114
2115    SkRect  r;
2116    r.set(cx - radius, cy - radius, cx + radius, cy + radius);
2117    this->drawOval(r, paint);
2118}
2119
2120void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2121                             const SkPaint& paint) {
2122    if (rx > 0 && ry > 0) {
2123        if (paint.canComputeFastBounds()) {
2124            SkRect storage;
2125            if (this->quickReject(paint.computeFastBounds(r, &storage))) {
2126                return;
2127            }
2128        }
2129        SkRRect rrect;
2130        rrect.setRectXY(r, rx, ry);
2131        this->drawRRect(rrect, paint);
2132    } else {
2133        this->drawRect(r, paint);
2134    }
2135}
2136
2137void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2138                       SkScalar sweepAngle, bool useCenter,
2139                       const SkPaint& paint) {
2140    if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2141        this->drawOval(oval, paint);
2142    } else {
2143        SkPath  path;
2144        if (useCenter) {
2145            path.moveTo(oval.centerX(), oval.centerY());
2146        }
2147        path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2148        if (useCenter) {
2149            path.close();
2150        }
2151        this->drawPath(path, paint);
2152    }
2153}
2154
2155void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2156                                const SkPath& path, SkScalar hOffset,
2157                                SkScalar vOffset, const SkPaint& paint) {
2158    SkMatrix    matrix;
2159
2160    matrix.setTranslate(hOffset, vOffset);
2161    this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2162}
2163
2164///////////////////////////////////////////////////////////////////////////////
2165
2166void SkCanvas::drawPicture(SkPicture& picture) {
2167    picture.draw(this);
2168}
2169
2170///////////////////////////////////////////////////////////////////////////////
2171///////////////////////////////////////////////////////////////////////////////
2172
2173SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
2174    SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
2175
2176    SkASSERT(canvas);
2177
2178    fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2179    fDone = !fImpl->next();
2180}
2181
2182SkCanvas::LayerIter::~LayerIter() {
2183    fImpl->~SkDrawIter();
2184}
2185
2186void SkCanvas::LayerIter::next() {
2187    fDone = !fImpl->next();
2188}
2189
2190SkBaseDevice* SkCanvas::LayerIter::device() const {
2191    return fImpl->getDevice();
2192}
2193
2194const SkMatrix& SkCanvas::LayerIter::matrix() const {
2195    return fImpl->getMatrix();
2196}
2197
2198const SkPaint& SkCanvas::LayerIter::paint() const {
2199    const SkPaint* paint = fImpl->getPaint();
2200    if (NULL == paint) {
2201        paint = &fDefaultPaint;
2202    }
2203    return *paint;
2204}
2205
2206const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2207int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2208int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
2209
2210///////////////////////////////////////////////////////////////////////////////
2211
2212SkCanvas::ClipVisitor::~ClipVisitor() { }
2213