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