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