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