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