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