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