SkCanvas.cpp revision b81be7a7809fb0c24ff7d589d537c38b04b772f1
1
2/*
3 * Copyright 2008 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkCanvas.h"
11#include "SkBounder.h"
12#include "SkDevice.h"
13#include "SkDraw.h"
14#include "SkDrawFilter.h"
15#include "SkDrawLooper.h"
16#include "SkPicture.h"
17#include "SkScalarCompare.h"
18#include "SkTemplates.h"
19#include "SkTLazy.h"
20#include "SkUtils.h"
21
22//#define SK_TRACE_SAVERESTORE
23
24#ifdef SK_TRACE_SAVERESTORE
25    static int gLayerCounter;
26    static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
27    static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
28
29    static int gRecCounter;
30    static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
31    static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
32
33    static int gCanvasCounter;
34    static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
35    static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
36#else
37    #define inc_layer()
38    #define dec_layer()
39    #define inc_rec()
40    #define dec_rec()
41    #define inc_canvas()
42    #define dec_canvas()
43#endif
44
45typedef SkTLazy<SkPaint> SkLazyPaint;
46
47///////////////////////////////////////////////////////////////////////////////
48// Helpers for computing fast bounds for quickReject tests
49
50static SkCanvas::EdgeType paint2EdgeType(const SkPaint* paint) {
51    return paint != NULL && paint->isAntiAlias() ?
52            SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType;
53}
54
55///////////////////////////////////////////////////////////////////////////////
56
57/*  This is the record we keep for each SkDevice that the user installs.
58    The clip/matrix/proc are fields that reflect the top of the save/restore
59    stack. Whenever the canvas changes, it marks a dirty flag, and then before
60    these are used (assuming we're not on a layer) we rebuild these cache
61    values: they reflect the top of the save stack, but translated and clipped
62    by the device's XY offset and bitmap-bounds.
63*/
64struct DeviceCM {
65    DeviceCM*           fNext;
66    SkDevice*           fDevice;
67    SkRegion            fClip;
68    const SkMatrix*     fMatrix;
69    SkPaint*            fPaint; // may be null (in the future)
70    // optional, related to canvas' external matrix
71    const SkMatrix*     fMVMatrix;
72    const SkMatrix*     fExtMatrix;
73
74	DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint)
75            : fNext(NULL) {
76        if (NULL != device) {
77            device->ref();
78            device->lockPixels();
79        }
80        fDevice = device;
81        fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
82	}
83
84	~DeviceCM() {
85        if (NULL != fDevice) {
86            fDevice->unlockPixels();
87            fDevice->unref();
88        }
89		SkDELETE(fPaint);
90	}
91
92    void updateMC(const SkMatrix& totalMatrix, const SkRegion& totalClip,
93                  const SkClipStack& clipStack, SkRegion* updateClip) {
94        int x = fDevice->getOrigin().x();
95        int y = fDevice->getOrigin().y();
96        int width = fDevice->width();
97        int height = fDevice->height();
98
99        if ((x | y) == 0) {
100            fMatrix = &totalMatrix;
101            fClip = totalClip;
102        } else {
103            fMatrixStorage = totalMatrix;
104            fMatrixStorage.postTranslate(SkIntToScalar(-x),
105                                         SkIntToScalar(-y));
106            fMatrix = &fMatrixStorage;
107
108            totalClip.translate(-x, -y, &fClip);
109        }
110
111        fClip.op(0, 0, width, height, SkRegion::kIntersect_Op);
112
113        // intersect clip, but don't translate it (yet)
114
115        if (updateClip) {
116            updateClip->op(x, y, x + width, y + height,
117                           SkRegion::kDifference_Op);
118        }
119
120        fDevice->setMatrixClip(*fMatrix, fClip, clipStack);
121
122#ifdef SK_DEBUG
123        if (!fClip.isEmpty()) {
124            SkIRect deviceR;
125            deviceR.set(0, 0, width, height);
126            SkASSERT(deviceR.contains(fClip.getBounds()));
127        }
128#endif
129        // default is to assume no external matrix
130        fMVMatrix = NULL;
131        fExtMatrix = NULL;
132    }
133
134    // can only be called after calling updateMC()
135    void updateExternalMatrix(const SkMatrix& extM, const SkMatrix& extI) {
136        fMVMatrixStorage.setConcat(extI, *fMatrix);
137        fMVMatrix = &fMVMatrixStorage;
138        fExtMatrix = &extM; // assumes extM has long life-time (owned by canvas)
139    }
140
141private:
142    SkMatrix    fMatrixStorage, fMVMatrixStorage;
143};
144
145/*  This is the record we keep for each save/restore level in the stack.
146    Since a level optionally copies the matrix and/or stack, we have pointers
147    for these fields. If the value is copied for this level, the copy is
148    stored in the ...Storage field, and the pointer points to that. If the
149    value is not copied for this level, we ignore ...Storage, and just point
150    at the corresponding value in the previous level in the stack.
151*/
152class SkCanvas::MCRec {
153public:
154    MCRec*          fNext;
155    SkMatrix*       fMatrix;    // points to either fMatrixStorage or prev MCRec
156    SkRegion*       fRegion;    // points to either fRegionStorage or prev MCRec
157    SkDrawFilter*   fFilter;    // the current filter (or null)
158
159    DeviceCM*   fLayer;
160    /*  If there are any layers in the stack, this points to the top-most
161        one that is at or below this level in the stack (so we know what
162        bitmap/device to draw into from this level. This value is NOT
163        reference counted, since the real owner is either our fLayer field,
164        or a previous one in a lower level.)
165    */
166    DeviceCM*	fTopLayer;
167
168    MCRec(const MCRec* prev, int flags) {
169        if (NULL != prev) {
170            if (flags & SkCanvas::kMatrix_SaveFlag) {
171                fMatrixStorage = *prev->fMatrix;
172                fMatrix = &fMatrixStorage;
173            } else {
174                fMatrix = prev->fMatrix;
175            }
176
177            if (flags & SkCanvas::kClip_SaveFlag) {
178                fRegionStorage = *prev->fRegion;
179                fRegion = &fRegionStorage;
180            } else {
181                fRegion = prev->fRegion;
182            }
183
184            fFilter = prev->fFilter;
185            SkSafeRef(fFilter);
186
187            fTopLayer = prev->fTopLayer;
188        } else {   // no prev
189            fMatrixStorage.reset();
190
191            fMatrix     = &fMatrixStorage;
192            fRegion     = &fRegionStorage;
193            fFilter     = NULL;
194            fTopLayer   = NULL;
195        }
196        fLayer = NULL;
197
198        // don't bother initializing fNext
199        inc_rec();
200    }
201    ~MCRec() {
202        SkSafeUnref(fFilter);
203        SkDELETE(fLayer);
204        dec_rec();
205    }
206
207private:
208    SkMatrix    fMatrixStorage;
209    SkRegion    fRegionStorage;
210};
211
212class SkDrawIter : public SkDraw {
213public:
214    SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
215        fCanvas = canvas;
216        canvas->updateDeviceCMCache();
217
218        fClipStack = &canvas->getTotalClipStack();
219        fBounder = canvas->getBounder();
220        fCurrLayer = canvas->fMCRec->fTopLayer;
221        fSkipEmptyClips = skipEmptyClips;
222    }
223
224    bool next() {
225        // skip over recs with empty clips
226        if (fSkipEmptyClips) {
227            while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
228                fCurrLayer = fCurrLayer->fNext;
229            }
230        }
231
232        if (NULL != fCurrLayer) {
233            const DeviceCM* rec = fCurrLayer;
234
235            fMatrix = rec->fMatrix;
236            fClip   = &rec->fClip;
237            fDevice = rec->fDevice;
238            fBitmap = &fDevice->accessBitmap(true);
239            fPaint  = rec->fPaint;
240            fMVMatrix = rec->fMVMatrix;
241            fExtMatrix = rec->fExtMatrix;
242            SkDEBUGCODE(this->validate();)
243
244            fCurrLayer = rec->fNext;
245            if (fBounder) {
246                fBounder->setClip(fClip);
247            }
248            // fCurrLayer may be NULL now
249
250            fCanvas->prepareForDeviceDraw(fDevice, *fMatrix, *fClip, *fClipStack);
251            return true;
252        }
253        return false;
254    }
255
256    SkDevice* getDevice() const { return fDevice; }
257    int getX() const { return fDevice->getOrigin().x(); }
258    int getY() const { return fDevice->getOrigin().y(); }
259    const SkMatrix& getMatrix() const { return *fMatrix; }
260    const SkRegion& getClip() const { return *fClip; }
261    const SkPaint* getPaint() const { return fPaint; }
262
263private:
264    SkCanvas*       fCanvas;
265    const DeviceCM* fCurrLayer;
266    const SkPaint*  fPaint;     // May be null.
267    SkBool8         fSkipEmptyClips;
268
269    typedef SkDraw INHERITED;
270};
271
272/////////////////////////////////////////////////////////////////////////////
273
274class AutoDrawLooper {
275public:
276    AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint) : fOrigPaint(paint) {
277        fCanvas = canvas;
278        fLooper = paint.getLooper();
279        fFilter = canvas->getDrawFilter();
280        fPaint = NULL;
281        fSaveCount = canvas->getSaveCount();
282        fDone = false;
283
284        if (fLooper) {
285            fLooper->init(canvas);
286        }
287    }
288
289    ~AutoDrawLooper() {
290        SkASSERT(fCanvas->getSaveCount() == fSaveCount);
291    }
292
293    const SkPaint& paint() const {
294        SkASSERT(fPaint);
295        return *fPaint;
296    }
297
298    bool next(SkDrawFilter::Type drawType);
299
300private:
301    SkLazyPaint     fLazyPaint;
302    SkCanvas*       fCanvas;
303    const SkPaint&  fOrigPaint;
304    SkDrawLooper*   fLooper;
305    SkDrawFilter*   fFilter;
306    const SkPaint*  fPaint;
307    int             fSaveCount;
308    bool            fDone;
309};
310
311bool AutoDrawLooper::next(SkDrawFilter::Type drawType) {
312    if (fDone) {
313        fPaint = NULL;
314        return false;
315    }
316    if (!fLooper && !fFilter) {
317        fDone = true;
318        fPaint = &fOrigPaint;
319        return true;
320    }
321
322    SkPaint* paint = fLazyPaint.set(fOrigPaint);
323    if (fLooper && !fLooper->next(fCanvas, paint)) {
324        fDone = true;
325        fPaint = NULL;
326        return false;
327    }
328    if (fFilter) {
329        fFilter->filter(paint, drawType);
330        if (NULL == fLooper) {
331            // no looper means we only draw once
332            fDone = true;
333        }
334    }
335    fPaint = paint;
336    return true;
337}
338
339/*  Stack helper for managing a SkBounder. In the destructor, if we were
340    given a bounder, we call its commit() method, signifying that we are
341    done accumulating bounds for that draw.
342*/
343class SkAutoBounderCommit {
344public:
345    SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {}
346    ~SkAutoBounderCommit() {
347        if (NULL != fBounder) {
348            fBounder->commit();
349        }
350    }
351private:
352    SkBounder*  fBounder;
353};
354
355#include "SkColorPriv.h"
356
357class AutoValidator {
358public:
359    AutoValidator(SkDevice* device) : fDevice(device) {}
360    ~AutoValidator() {
361#ifdef SK_DEBUG
362        const SkBitmap& bm = fDevice->accessBitmap(false);
363        if (bm.config() == SkBitmap::kARGB_4444_Config) {
364            for (int y = 0; y < bm.height(); y++) {
365                const SkPMColor16* p = bm.getAddr16(0, y);
366                for (int x = 0; x < bm.width(); x++) {
367                    SkPMColor16 c = p[x];
368                    SkPMColor16Assert(c);
369                }
370            }
371        }
372#endif
373    }
374private:
375    SkDevice* fDevice;
376};
377
378////////// macros to place around the internal draw calls //////////////////
379
380#define LOOPER_BEGIN(paint, type)                                   \
381/*    AutoValidator   validator(fMCRec->fTopLayer->fDevice); */     \
382    AutoDrawLooper  looper(this, paint);                            \
383    while (looper.next(type)) {                                     \
384        SkAutoBounderCommit ac(fBounder);                           \
385        SkDrawIter          iter(this);
386
387#define LOOPER_END    }
388
389////////////////////////////////////////////////////////////////////////////
390
391SkDevice* SkCanvas::init(SkDevice* device) {
392    fBounder = NULL;
393    fLocalBoundsCompareType.setEmpty();
394    fLocalBoundsCompareTypeDirty = true;
395    fLocalBoundsCompareTypeBW.setEmpty();
396    fLocalBoundsCompareTypeDirtyBW = true;
397    fLastDeviceToGainFocus = NULL;
398    fDeviceCMDirty = false;
399
400    fMCRec = (MCRec*)fMCStack.push_back();
401    new (fMCRec) MCRec(NULL, 0);
402
403    fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL));
404    fMCRec->fTopLayer = fMCRec->fLayer;
405    fMCRec->fNext = NULL;
406
407    fExternalMatrix.reset();
408    fExternalInverse.reset();
409    fUseExternalMatrix = false;
410
411    return this->setDevice(device);
412}
413
414SkCanvas::SkCanvas()
415: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
416    inc_canvas();
417
418    this->init(NULL);
419}
420
421SkCanvas::SkCanvas(SkDevice* device)
422        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
423    inc_canvas();
424
425    this->init(device);
426}
427
428SkCanvas::SkCanvas(const SkBitmap& bitmap)
429        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
430    inc_canvas();
431
432    this->init(SkNEW_ARGS(SkDevice, (bitmap)))->unref();
433}
434
435SkCanvas::~SkCanvas() {
436    // free up the contents of our deque
437    this->restoreToCount(1);    // restore everything but the last
438    this->internalRestore();    // restore the last, since we're going away
439
440    SkSafeUnref(fBounder);
441
442    dec_canvas();
443}
444
445SkBounder* SkCanvas::setBounder(SkBounder* bounder) {
446    SkRefCnt_SafeAssign(fBounder, bounder);
447    return bounder;
448}
449
450SkDrawFilter* SkCanvas::getDrawFilter() const {
451    return fMCRec->fFilter;
452}
453
454SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
455    SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
456    return filter;
457}
458
459///////////////////////////////////////////////////////////////////////////////
460
461SkDevice* SkCanvas::getDevice() const {
462    // return root device
463    SkDeque::F2BIter iter(fMCStack);
464    MCRec*           rec = (MCRec*)iter.next();
465    SkASSERT(rec && rec->fLayer);
466    return rec->fLayer->fDevice;
467}
468
469SkDevice* SkCanvas::getTopDevice() const {
470    return fMCRec->fTopLayer->fDevice;
471}
472
473SkDevice* SkCanvas::setDevice(SkDevice* device) {
474    // return root device
475    SkDeque::F2BIter iter(fMCStack);
476    MCRec*           rec = (MCRec*)iter.next();
477    SkASSERT(rec && rec->fLayer);
478    SkDevice*       rootDevice = rec->fLayer->fDevice;
479
480    if (rootDevice == device) {
481        return device;
482    }
483
484    /* Notify the devices that they are going in/out of scope, so they can do
485       things like lock/unlock their pixels, etc.
486    */
487    if (device) {
488        device->lockPixels();
489    }
490    if (rootDevice) {
491        rootDevice->unlockPixels();
492    }
493
494    SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
495    rootDevice = device;
496
497    fDeviceCMDirty = true;
498
499    /*  Now we update our initial region to have the bounds of the new device,
500        and then intersect all of the clips in our stack with these bounds,
501        to ensure that we can't draw outside of the device's bounds (and trash
502                                                                     memory).
503
504    NOTE: this is only a partial-fix, since if the new device is larger than
505        the previous one, we don't know how to "enlarge" the clips in our stack,
506        so drawing may be artificially restricted. Without keeping a history of
507        all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
508        reconstruct the correct clips, so this approximation will have to do.
509        The caller really needs to restore() back to the base if they want to
510        accurately take advantage of the new device bounds.
511    */
512
513    if (NULL == device) {
514        rec->fRegion->setEmpty();
515        while ((rec = (MCRec*)iter.next()) != NULL) {
516            (void)rec->fRegion->setEmpty();
517        }
518        fClipStack.reset();
519    } else {
520        // compute our total bounds for all devices
521        SkIRect bounds;
522
523        bounds.set(0, 0, device->width(), device->height());
524
525        // now jam our 1st clip to be bounds, and intersect the rest with that
526        rec->fRegion->setRect(bounds);
527        while ((rec = (MCRec*)iter.next()) != NULL) {
528            (void)rec->fRegion->op(bounds, SkRegion::kIntersect_Op);
529        }
530        fClipStack.clipDevRect(bounds, SkRegion::kIntersect_Op);
531    }
532    return device;
533}
534
535SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) {
536    SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap)));
537    device->unref();
538    return device;
539}
540
541bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
542    SkDevice* device = this->getDevice();
543    if (!device) {
544        return false;
545    }
546    return device->readPixels(srcRect, bitmap);
547}
548
549//////////////////////////////////////////////////////////////////////////////
550
551bool SkCanvas::readPixels(SkBitmap* bitmap) {
552    SkDevice* device = this->getDevice();
553    if (!device) {
554        return false;
555    }
556    SkIRect bounds;
557    bounds.set(0, 0, device->width(), device->height());
558    return this->readPixels(bounds, bitmap);
559}
560
561void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
562    SkDevice* device = this->getDevice();
563    if (device) {
564        device->writePixels(bitmap, x, y);
565    }
566}
567
568//////////////////////////////////////////////////////////////////////////////
569
570void SkCanvas::updateDeviceCMCache() {
571    if (fDeviceCMDirty) {
572        const SkMatrix& totalMatrix = this->getTotalMatrix();
573        const SkRegion& totalClip = this->getTotalClip();
574        DeviceCM*       layer = fMCRec->fTopLayer;
575
576        if (NULL == layer->fNext) {   // only one layer
577            layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
578            if (fUseExternalMatrix) {
579                layer->updateExternalMatrix(fExternalMatrix,
580                                            fExternalInverse);
581            }
582        } else {
583            SkRegion clip;
584            clip = totalClip;  // make a copy
585            do {
586                layer->updateMC(totalMatrix, clip, fClipStack, &clip);
587                if (fUseExternalMatrix) {
588                    layer->updateExternalMatrix(fExternalMatrix,
589                                                fExternalInverse);
590                }
591            } while ((layer = layer->fNext) != NULL);
592        }
593        fDeviceCMDirty = false;
594    }
595}
596
597void SkCanvas::prepareForDeviceDraw(SkDevice* device, const SkMatrix& matrix,
598                                    const SkRegion& clip,
599                                    const SkClipStack& clipStack) {
600    SkASSERT(device);
601    if (fLastDeviceToGainFocus != device) {
602        device->gainFocus(this, matrix, clip, clipStack);
603        fLastDeviceToGainFocus = device;
604    }
605}
606
607///////////////////////////////////////////////////////////////////////////////
608
609int SkCanvas::internalSave(SaveFlags flags) {
610    int saveCount = this->getSaveCount(); // record this before the actual save
611
612    MCRec* newTop = (MCRec*)fMCStack.push_back();
613    new (newTop) MCRec(fMCRec, flags);    // balanced in restore()
614
615    newTop->fNext = fMCRec;
616    fMCRec = newTop;
617
618    fClipStack.save();
619    SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
620
621    return saveCount;
622}
623
624int SkCanvas::save(SaveFlags flags) {
625    // call shared impl
626    return this->internalSave(flags);
627}
628
629#define C32MASK (1 << SkBitmap::kARGB_8888_Config)
630#define C16MASK (1 << SkBitmap::kRGB_565_Config)
631#define C8MASK  (1 << SkBitmap::kA8_Config)
632
633static SkBitmap::Config resolve_config(SkCanvas* canvas,
634                                       const SkIRect& bounds,
635                                       SkCanvas::SaveFlags flags,
636                                       bool* isOpaque) {
637    *isOpaque = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) == 0;
638
639#if 0
640    // loop through and union all the configs we may draw into
641    uint32_t configMask = 0;
642    for (int i = canvas->countLayerDevices() - 1; i >= 0; --i)
643    {
644        SkDevice* device = canvas->getLayerDevice(i);
645        if (device->intersects(bounds))
646            configMask |= 1 << device->config();
647    }
648
649    // if the caller wants alpha or fullcolor, we can't return 565
650    if (flags & (SkCanvas::kFullColorLayer_SaveFlag |
651                 SkCanvas::kHasAlphaLayer_SaveFlag))
652        configMask &= ~C16MASK;
653
654    switch (configMask) {
655    case C8MASK:    // if we only have A8, return that
656        return SkBitmap::kA8_Config;
657
658    case C16MASK:   // if we only have 565, return that
659        return SkBitmap::kRGB_565_Config;
660
661    default:
662        return SkBitmap::kARGB_8888_Config; // default answer
663    }
664#else
665    return SkBitmap::kARGB_8888_Config; // default answer
666#endif
667}
668
669static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
670    return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
671}
672
673int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
674                        SaveFlags flags) {
675    // do this before we create the layer. We don't call the public save() since
676    // that would invoke a possibly overridden virtual
677    int count = this->internalSave(flags);
678
679    fDeviceCMDirty = true;
680
681    SkIRect         ir;
682    const SkIRect&  clipBounds = this->getTotalClip().getBounds();
683    if (clipBounds.isEmpty()) {
684        return count;
685    }
686
687    if (NULL != bounds) {
688        SkRect r;
689
690        this->getTotalMatrix().mapRect(&r, *bounds);
691        r.roundOut(&ir);
692        // early exit if the layer's bounds are clipped out
693        if (!ir.intersect(clipBounds)) {
694            if (bounds_affects_clip(flags))
695                fMCRec->fRegion->setEmpty();
696            return count;
697        }
698    } else {    // no user bounds, so just use the clip
699        ir = clipBounds;
700    }
701
702    fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op);
703    // early exit if the clip is now empty
704    if (bounds_affects_clip(flags) &&
705        !fMCRec->fRegion->op(ir, SkRegion::kIntersect_Op)) {
706        return count;
707    }
708
709    bool isOpaque;
710    SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque);
711
712    SkDevice* device = this->createLayerDevice(config, ir.width(), ir.height(),
713                                               isOpaque);
714
715    device->setOrigin(ir.fLeft, ir.fTop);
716    DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint));
717    device->unref();
718
719    layer->fNext = fMCRec->fTopLayer;
720    fMCRec->fLayer = layer;
721    fMCRec->fTopLayer = layer;    // this field is NOT an owner of layer
722
723    return count;
724}
725
726int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
727                             SaveFlags flags) {
728    if (0xFF == alpha) {
729        return this->saveLayer(bounds, NULL, flags);
730    } else {
731        SkPaint tmpPaint;
732        tmpPaint.setAlpha(alpha);
733        return this->saveLayer(bounds, &tmpPaint, flags);
734    }
735}
736
737void SkCanvas::restore() {
738    // check for underflow
739    if (fMCStack.count() > 1) {
740        this->internalRestore();
741    }
742}
743
744void SkCanvas::internalRestore() {
745    SkASSERT(fMCStack.count() != 0);
746
747    fDeviceCMDirty = true;
748    fLocalBoundsCompareTypeDirty = true;
749    fLocalBoundsCompareTypeDirtyBW = true;
750
751    fClipStack.restore();
752	// reserve our layer (if any)
753    DeviceCM* layer = fMCRec->fLayer;   // may be null
754    // now detach it from fMCRec so we can pop(). Gets freed after its drawn
755    fMCRec->fLayer = NULL;
756
757    // now do the normal restore()
758    fMCRec->~MCRec();       // balanced in save()
759    fMCStack.pop_back();
760    fMCRec = (MCRec*)fMCStack.back();
761
762    /*  Time to draw the layer's offscreen. We can't call the public drawSprite,
763        since if we're being recorded, we don't want to record this (the
764        recorder will have already recorded the restore).
765    */
766    if (NULL != layer) {
767        if (layer->fNext) {
768            const SkIPoint& origin = layer->fDevice->getOrigin();
769            this->drawDevice(layer->fDevice, origin.x(), origin.y(),
770                             layer->fPaint);
771            // reset this, since drawDevice will have set it to true
772            fDeviceCMDirty = true;
773        }
774        SkDELETE(layer);
775	}
776
777    SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
778}
779
780int SkCanvas::getSaveCount() const {
781    return fMCStack.count();
782}
783
784void SkCanvas::restoreToCount(int count) {
785    // sanity check
786    if (count < 1) {
787        count = 1;
788    }
789    while (fMCStack.count() > count) {
790        this->restore();
791    }
792}
793
794/////////////////////////////////////////////////////////////////////////////
795
796// can't draw it if its empty, or its too big for a fixed-point width or height
797static bool reject_bitmap(const SkBitmap& bitmap) {
798    return  bitmap.width() <= 0 || bitmap.height() <= 0
799#ifndef SK_ALLOW_OVER_32K_BITMAPS
800            || bitmap.width() > 32767 || bitmap.height() > 32767
801#endif
802            ;
803}
804
805void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
806                                const SkMatrix& matrix, const SkPaint* paint) {
807    if (reject_bitmap(bitmap)) {
808        return;
809    }
810
811    SkLazyPaint lazy;
812    if (NULL == paint) {
813        paint = lazy.init();
814    }
815    this->commonDrawBitmap(bitmap, srcRect, matrix, *paint);
816}
817
818void SkCanvas::drawDevice(SkDevice* device, int x, int y,
819                          const SkPaint* paint) {
820    SkPaint tmp;
821    if (NULL == paint) {
822        tmp.setDither(true);
823        paint = &tmp;
824    }
825
826    LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
827    while (iter.next()) {
828        iter.fDevice->drawDevice(iter, device, x - iter.getX(), y - iter.getY(),
829                                 looper.paint());
830    }
831    LOOPER_END
832}
833
834/////////////////////////////////////////////////////////////////////////////
835
836bool SkCanvas::translate(SkScalar dx, SkScalar dy) {
837    fDeviceCMDirty = true;
838    fLocalBoundsCompareTypeDirty = true;
839    fLocalBoundsCompareTypeDirtyBW = true;
840    return fMCRec->fMatrix->preTranslate(dx, dy);
841}
842
843bool SkCanvas::scale(SkScalar sx, SkScalar sy) {
844    fDeviceCMDirty = true;
845    fLocalBoundsCompareTypeDirty = true;
846    fLocalBoundsCompareTypeDirtyBW = true;
847    return fMCRec->fMatrix->preScale(sx, sy);
848}
849
850bool SkCanvas::rotate(SkScalar degrees) {
851    fDeviceCMDirty = true;
852    fLocalBoundsCompareTypeDirty = true;
853    fLocalBoundsCompareTypeDirtyBW = true;
854    return fMCRec->fMatrix->preRotate(degrees);
855}
856
857bool SkCanvas::skew(SkScalar sx, SkScalar sy) {
858    fDeviceCMDirty = true;
859    fLocalBoundsCompareTypeDirty = true;
860    fLocalBoundsCompareTypeDirtyBW = true;
861    return fMCRec->fMatrix->preSkew(sx, sy);
862}
863
864bool SkCanvas::concat(const SkMatrix& matrix) {
865    fDeviceCMDirty = true;
866    fLocalBoundsCompareTypeDirty = true;
867    fLocalBoundsCompareTypeDirtyBW = true;
868    return fMCRec->fMatrix->preConcat(matrix);
869}
870
871void SkCanvas::setMatrix(const SkMatrix& matrix) {
872    fDeviceCMDirty = true;
873    fLocalBoundsCompareTypeDirty = true;
874    fLocalBoundsCompareTypeDirtyBW = true;
875    *fMCRec->fMatrix = matrix;
876}
877
878// this is not virtual, so it must call a virtual method so that subclasses
879// will see its action
880void SkCanvas::resetMatrix() {
881    SkMatrix matrix;
882
883    matrix.reset();
884    this->setMatrix(matrix);
885}
886
887//////////////////////////////////////////////////////////////////////////////
888
889bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
890    AutoValidateClip avc(this);
891
892    fDeviceCMDirty = true;
893    fLocalBoundsCompareTypeDirty = true;
894    fLocalBoundsCompareTypeDirtyBW = true;
895
896    if (fMCRec->fMatrix->rectStaysRect()) {
897        // for these simpler matrices, we can stay a rect ever after applying
898        // the matrix. This means we don't have to a) make a path, and b) tell
899        // the region code to scan-convert the path, only to discover that it
900        // is really just a rect.
901        SkRect      r;
902        SkIRect     ir;
903
904        fMCRec->fMatrix->mapRect(&r, rect);
905        fClipStack.clipDevRect(r, op);
906        r.round(&ir);
907        return fMCRec->fRegion->op(ir, op);
908    } else {
909        // since we're rotate or some such thing, we convert the rect to a path
910        // and clip against that, since it can handle any matrix. However, to
911        // avoid recursion in the case where we are subclassed (e.g. Pictures)
912        // we explicitly call "our" version of clipPath.
913        SkPath  path;
914
915        path.addRect(rect);
916        return this->SkCanvas::clipPath(path, op);
917    }
918}
919
920static bool clipPathHelper(const SkCanvas* canvas, SkRegion* currRgn,
921                           const SkPath& devPath, SkRegion::Op op) {
922    // base is used to limit the size (and therefore memory allocation) of the
923    // region that results from scan converting devPath.
924    SkRegion base;
925
926    if (SkRegion::kIntersect_Op == op) {
927        // since we are intersect, we can do better (tighter) with currRgn's
928        // bounds, than just using the device. However, if currRgn is complex,
929        // our region blitter may hork, so we do that case in two steps.
930        if (currRgn->isRect()) {
931            return currRgn->setPath(devPath, *currRgn);
932        } else {
933            base.setRect(currRgn->getBounds());
934            SkRegion rgn;
935            rgn.setPath(devPath, base);
936            return currRgn->op(rgn, op);
937        }
938    } else {
939        const SkBitmap& bm = canvas->getDevice()->accessBitmap(false);
940        base.setRect(0, 0, bm.width(), bm.height());
941
942        if (SkRegion::kReplace_Op == op) {
943            return currRgn->setPath(devPath, base);
944        } else {
945            SkRegion rgn;
946            rgn.setPath(devPath, base);
947            return currRgn->op(rgn, op);
948        }
949    }
950}
951
952bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op) {
953    AutoValidateClip avc(this);
954
955    fDeviceCMDirty = true;
956    fLocalBoundsCompareTypeDirty = true;
957    fLocalBoundsCompareTypeDirtyBW = true;
958
959    SkPath devPath;
960    path.transform(*fMCRec->fMatrix, &devPath);
961
962    // if we called path.swap() we could avoid a deep copy of this path
963    fClipStack.clipDevPath(devPath, op);
964
965    return clipPathHelper(this, fMCRec->fRegion, devPath, op);
966}
967
968bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
969    AutoValidateClip avc(this);
970
971    fDeviceCMDirty = true;
972    fLocalBoundsCompareTypeDirty = true;
973    fLocalBoundsCompareTypeDirtyBW = true;
974
975    // todo: signal fClipStack that we have a region, and therefore (I guess)
976    // we have to ignore it, and use the region directly?
977    fClipStack.clipDevRect(rgn.getBounds());
978
979    return fMCRec->fRegion->op(rgn, op);
980}
981
982#ifdef SK_DEBUG
983void SkCanvas::validateClip() const {
984    // construct clipRgn from the clipstack
985    const SkDevice* device = this->getDevice();
986    SkIRect ir;
987    ir.set(0, 0, device->width(), device->height());
988    SkRegion clipRgn(ir);
989
990    SkClipStack::B2FIter                iter(fClipStack);
991    const SkClipStack::B2FIter::Clip*   clip;
992    while ((clip = iter.next()) != NULL) {
993        if (clip->fPath) {
994            clipPathHelper(this, &clipRgn, *clip->fPath, clip->fOp);
995        } else if (clip->fRect) {
996            clip->fRect->round(&ir);
997            clipRgn.op(ir, clip->fOp);
998        } else {
999            clipRgn.setEmpty();
1000        }
1001    }
1002
1003#if 0   // enable this locally for testing
1004    // now compare against the current rgn
1005    const SkRegion& rgn = this->getTotalClip();
1006    SkASSERT(rgn == clipRgn);
1007#endif
1008}
1009#endif
1010
1011///////////////////////////////////////////////////////////////////////////////
1012
1013void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const {
1014    SkRect r;
1015    SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType :
1016            fLocalBoundsCompareTypeBW;
1017
1018    if (!this->getClipBounds(&r, et)) {
1019        rCompare.setEmpty();
1020    } else {
1021        rCompare.set(SkScalarToCompareType(r.fLeft),
1022                     SkScalarToCompareType(r.fTop),
1023                     SkScalarToCompareType(r.fRight),
1024                     SkScalarToCompareType(r.fBottom));
1025    }
1026}
1027
1028/*  current impl ignores edgetype, and relies on
1029    getLocalClipBoundsCompareType(), which always returns a value assuming
1030    antialiasing (worst case)
1031 */
1032bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const {
1033
1034    if (!rect.hasValidCoordinates())
1035        return true;
1036
1037    if (fMCRec->fRegion->isEmpty()) {
1038        return true;
1039    }
1040
1041    if (fMCRec->fMatrix->hasPerspective()) {
1042        SkRect dst;
1043        fMCRec->fMatrix->mapRect(&dst, rect);
1044        SkIRect idst;
1045        dst.roundOut(&idst);
1046        return !SkIRect::Intersects(idst, fMCRec->fRegion->getBounds());
1047    } else {
1048        const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et);
1049
1050        // for speed, do the most likely reject compares first
1051        SkScalarCompareType userT = SkScalarToCompareType(rect.fTop);
1052        SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom);
1053        if (userT >= clipR.fBottom || userB <= clipR.fTop) {
1054            return true;
1055        }
1056        SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft);
1057        SkScalarCompareType userR = SkScalarToCompareType(rect.fRight);
1058        if (userL >= clipR.fRight || userR <= clipR.fLeft) {
1059            return true;
1060        }
1061        return false;
1062    }
1063}
1064
1065bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const {
1066    return path.isEmpty() || this->quickReject(path.getBounds(), et);
1067}
1068
1069bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const {
1070    /*  current impl ignores edgetype, and relies on
1071        getLocalClipBoundsCompareType(), which always returns a value assuming
1072        antialiasing (worst case)
1073     */
1074
1075    if (fMCRec->fRegion->isEmpty()) {
1076        return true;
1077    }
1078
1079    SkScalarCompareType userT = SkScalarToCompareType(top);
1080    SkScalarCompareType userB = SkScalarToCompareType(bottom);
1081
1082    // check for invalid user Y coordinates (i.e. empty)
1083    // reed: why do we need to do this check, since it slows us down?
1084    if (userT >= userB) {
1085        return true;
1086    }
1087
1088    // check if we are above or below the local clip bounds
1089    const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType();
1090    return userT >= clipR.fBottom || userB <= clipR.fTop;
1091}
1092
1093bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const {
1094    const SkRegion& clip = *fMCRec->fRegion;
1095    if (clip.isEmpty()) {
1096        if (bounds) {
1097            bounds->setEmpty();
1098        }
1099        return false;
1100    }
1101
1102    SkMatrix inverse;
1103    // if we can't invert the CTM, we can't return local clip bounds
1104    if (!fMCRec->fMatrix->invert(&inverse)) {
1105        if (bounds) {
1106            bounds->setEmpty();
1107        }
1108        return false;
1109    }
1110
1111    if (NULL != bounds) {
1112        SkRect   r;
1113        // get the clip's bounds
1114        const SkIRect& ibounds = clip.getBounds();
1115        // adjust it outwards if we are antialiasing
1116        int inset = (kAA_EdgeType == et);
1117        r.iset(ibounds.fLeft - inset,  ibounds.fTop - inset,
1118               ibounds.fRight + inset, ibounds.fBottom + inset);
1119
1120        // invert into local coordinates
1121        inverse.mapRect(bounds, r);
1122    }
1123    return true;
1124}
1125
1126const SkMatrix& SkCanvas::getTotalMatrix() const {
1127    return *fMCRec->fMatrix;
1128}
1129
1130const SkRegion& SkCanvas::getTotalClip() const {
1131    return *fMCRec->fRegion;
1132}
1133
1134const SkClipStack& SkCanvas::getTotalClipStack() const {
1135    return fClipStack;
1136}
1137
1138void SkCanvas::setExternalMatrix(const SkMatrix* matrix) {
1139    if (NULL == matrix || matrix->isIdentity()) {
1140        if (fUseExternalMatrix) {
1141            fDeviceCMDirty = true;
1142        }
1143        fUseExternalMatrix = false;
1144    } else {
1145        fUseExternalMatrix = true;
1146        fDeviceCMDirty = true;  // |= (fExternalMatrix != *matrix)
1147
1148        fExternalMatrix = *matrix;
1149        matrix->invert(&fExternalInverse);
1150    }
1151}
1152
1153SkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config,
1154                                      int width, int height,
1155                                      bool isOpaque) {
1156    SkDevice* device = this->getDevice();
1157    if (device) {
1158        return device->createCompatibleDeviceForSaveLayer(config, width, height,
1159                                                          isOpaque);
1160    } else {
1161        return NULL;
1162    }
1163}
1164
1165SkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config,
1166                                           int width, int height,
1167                                           bool isOpaque) {
1168    SkDevice* device = this->getDevice();
1169    if (device) {
1170        return device->createCompatibleDevice(config, width, height, isOpaque);
1171    } else {
1172        return NULL;
1173    }
1174}
1175
1176
1177//////////////////////////////////////////////////////////////////////////////
1178//  These are the virtual drawing methods
1179//////////////////////////////////////////////////////////////////////////////
1180
1181void SkCanvas::clear(SkColor color) {
1182    SkDrawIter  iter(this);
1183
1184    while (iter.next()) {
1185        iter.fDevice->clear(color);
1186    }
1187}
1188
1189void SkCanvas::drawPaint(const SkPaint& paint) {
1190    LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type)
1191
1192    while (iter.next()) {
1193        iter.fDevice->drawPaint(iter, looper.paint());
1194    }
1195
1196    LOOPER_END
1197}
1198
1199void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
1200                          const SkPaint& paint) {
1201    if ((long)count <= 0) {
1202        return;
1203    }
1204
1205    SkASSERT(pts != NULL);
1206
1207    LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type)
1208
1209    while (iter.next()) {
1210        iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
1211    }
1212
1213    LOOPER_END
1214}
1215
1216void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1217    if (paint.canComputeFastBounds()) {
1218        SkRect storage;
1219        if (this->quickReject(paint.computeFastBounds(r, &storage),
1220                              paint2EdgeType(&paint))) {
1221            return;
1222        }
1223    }
1224
1225    LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type)
1226
1227    while (iter.next()) {
1228        iter.fDevice->drawRect(iter, r, looper.paint());
1229    }
1230
1231    LOOPER_END
1232}
1233
1234void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1235    if (paint.canComputeFastBounds()) {
1236        SkRect storage;
1237        const SkRect& bounds = path.getBounds();
1238        if (this->quickReject(paint.computeFastBounds(bounds, &storage),
1239                              paint2EdgeType(&paint))) {
1240            return;
1241        }
1242    }
1243
1244    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
1245
1246    while (iter.next()) {
1247        iter.fDevice->drawPath(iter, path, looper.paint());
1248    }
1249
1250    LOOPER_END
1251}
1252
1253void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
1254                          const SkPaint* paint) {
1255    SkDEBUGCODE(bitmap.validate();)
1256
1257    if (NULL == paint || (paint->getMaskFilter() == NULL)) {
1258        SkRect fastBounds;
1259        fastBounds.set(x, y,
1260                       x + SkIntToScalar(bitmap.width()),
1261                       y + SkIntToScalar(bitmap.height()));
1262        if (this->quickReject(fastBounds, paint2EdgeType(paint))) {
1263            return;
1264        }
1265    }
1266
1267    SkMatrix matrix;
1268    matrix.setTranslate(x, y);
1269    this->internalDrawBitmap(bitmap, NULL, matrix, paint);
1270}
1271
1272void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
1273                              const SkRect& dst, const SkPaint* paint) {
1274    if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) {
1275        return;
1276    }
1277
1278    // do this now, to avoid the cost of calling extract for RLE bitmaps
1279    if (this->quickReject(dst, paint2EdgeType(paint))) {
1280        return;
1281    }
1282
1283    const SkBitmap* bitmapPtr = &bitmap;
1284
1285    SkMatrix matrix;
1286    SkRect tmpSrc;
1287    if (src) {
1288        tmpSrc.set(*src);
1289        // if the extract process clipped off the top or left of the
1290        // original, we adjust for that here to get the position right.
1291        if (tmpSrc.fLeft > 0) {
1292            tmpSrc.fRight -= tmpSrc.fLeft;
1293            tmpSrc.fLeft = 0;
1294        }
1295        if (tmpSrc.fTop > 0) {
1296            tmpSrc.fBottom -= tmpSrc.fTop;
1297            tmpSrc.fTop = 0;
1298        }
1299    } else {
1300        tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()),
1301                   SkIntToScalar(bitmap.height()));
1302    }
1303    matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
1304
1305    // ensure that src is "valid" before we pass it to our internal routines
1306    // and to SkDevice. i.e. sure it is contained inside the original bitmap.
1307    SkIRect tmpISrc;
1308    if (src) {
1309        tmpISrc.set(0, 0, bitmap.width(), bitmap.height());
1310        if (!tmpISrc.intersect(*src)) {
1311            return;
1312        }
1313        src = &tmpISrc;
1314    }
1315    this->internalDrawBitmap(*bitmapPtr, src, matrix, paint);
1316}
1317
1318void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
1319                                const SkPaint* paint) {
1320    SkDEBUGCODE(bitmap.validate();)
1321    this->internalDrawBitmap(bitmap, NULL, matrix, paint);
1322}
1323
1324void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
1325                                const SkMatrix& matrix, const SkPaint& paint) {
1326    SkDEBUGCODE(bitmap.validate();)
1327
1328    LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type)
1329
1330    while (iter.next()) {
1331        iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint());
1332    }
1333
1334    LOOPER_END
1335}
1336
1337void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
1338                          const SkPaint* paint) {
1339    SkDEBUGCODE(bitmap.validate();)
1340
1341    if (reject_bitmap(bitmap)) {
1342        return;
1343    }
1344
1345    SkPaint tmp;
1346    if (NULL == paint) {
1347        paint = &tmp;
1348    }
1349
1350    LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
1351
1352    while (iter.next()) {
1353        iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(),
1354                                 looper.paint());
1355    }
1356    LOOPER_END
1357}
1358
1359class SkDeviceFilteredPaint {
1360public:
1361    SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) {
1362        SkDevice::TextFlags flags;
1363        if (device->filterTextFlags(paint, &flags)) {
1364            SkPaint* newPaint = fLazy.set(paint);
1365            newPaint->setFlags(flags.fFlags);
1366            newPaint->setHinting(flags.fHinting);
1367            fPaint = newPaint;
1368        } else {
1369            fPaint = &paint;
1370        }
1371    }
1372
1373    const SkPaint& paint() const { return *fPaint; }
1374
1375private:
1376    const SkPaint*  fPaint;
1377    SkLazyPaint     fLazy;
1378};
1379
1380void SkCanvas::drawText(const void* text, size_t byteLength,
1381                        SkScalar x, SkScalar y, const SkPaint& paint) {
1382    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1383
1384    while (iter.next()) {
1385        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1386        iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
1387    }
1388
1389    LOOPER_END
1390}
1391
1392void SkCanvas::drawPosText(const void* text, size_t byteLength,
1393                           const SkPoint pos[], const SkPaint& paint) {
1394    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1395
1396    while (iter.next()) {
1397        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1398        iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
1399                                  dfp.paint());
1400    }
1401
1402    LOOPER_END
1403}
1404
1405void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
1406                            const SkScalar xpos[], SkScalar constY,
1407                            const SkPaint& paint) {
1408    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1409
1410    while (iter.next()) {
1411        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1412        iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
1413                                  dfp.paint());
1414    }
1415
1416    LOOPER_END
1417}
1418
1419void SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
1420                              const SkPath& path, const SkMatrix* matrix,
1421                              const SkPaint& paint) {
1422    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1423
1424    while (iter.next()) {
1425        iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
1426                                     matrix, looper.paint());
1427    }
1428
1429    LOOPER_END
1430}
1431
1432#ifdef ANDROID
1433void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength,
1434                                 const SkPoint pos[], const SkPaint& paint,
1435                                 const SkPath& path, const SkMatrix* matrix) {
1436
1437    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1438
1439    while (iter.next()) {
1440        iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos,
1441                                        looper.paint(), path, matrix);
1442    }
1443
1444    LOOPER_END
1445}
1446#endif
1447
1448void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
1449                            const SkPoint verts[], const SkPoint texs[],
1450                            const SkColor colors[], SkXfermode* xmode,
1451                            const uint16_t indices[], int indexCount,
1452                            const SkPaint& paint) {
1453    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
1454
1455    while (iter.next()) {
1456        iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
1457                                   colors, xmode, indices, indexCount,
1458                                   looper.paint());
1459    }
1460
1461    LOOPER_END
1462}
1463
1464void SkCanvas::drawData(const void* data, size_t length) {
1465    // do nothing. Subclasses may do something with the data
1466}
1467
1468//////////////////////////////////////////////////////////////////////////////
1469// These methods are NOT virtual, and therefore must call back into virtual
1470// methods, rather than actually drawing themselves.
1471//////////////////////////////////////////////////////////////////////////////
1472
1473void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
1474                        SkXfermode::Mode mode) {
1475    SkPaint paint;
1476
1477    paint.setARGB(a, r, g, b);
1478    if (SkXfermode::kSrcOver_Mode != mode) {
1479        paint.setXfermodeMode(mode);
1480    }
1481    this->drawPaint(paint);
1482}
1483
1484void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
1485    SkPaint paint;
1486
1487    paint.setColor(c);
1488    if (SkXfermode::kSrcOver_Mode != mode) {
1489        paint.setXfermodeMode(mode);
1490    }
1491    this->drawPaint(paint);
1492}
1493
1494void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
1495    SkPoint pt;
1496
1497    pt.set(x, y);
1498    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1499}
1500
1501void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
1502    SkPoint pt;
1503    SkPaint paint;
1504
1505    pt.set(x, y);
1506    paint.setColor(color);
1507    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1508}
1509
1510void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
1511                        const SkPaint& paint) {
1512    SkPoint pts[2];
1513
1514    pts[0].set(x0, y0);
1515    pts[1].set(x1, y1);
1516    this->drawPoints(kLines_PointMode, 2, pts, paint);
1517}
1518
1519void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
1520                              SkScalar right, SkScalar bottom,
1521                              const SkPaint& paint) {
1522    SkRect  r;
1523
1524    r.set(left, top, right, bottom);
1525    this->drawRect(r, paint);
1526}
1527
1528void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
1529                          const SkPaint& paint) {
1530    if (radius < 0) {
1531        radius = 0;
1532    }
1533
1534    SkRect  r;
1535    r.set(cx - radius, cy - radius, cx + radius, cy + radius);
1536
1537    if (paint.canComputeFastBounds()) {
1538        SkRect storage;
1539        if (this->quickReject(paint.computeFastBounds(r, &storage),
1540                              paint2EdgeType(&paint))) {
1541            return;
1542        }
1543    }
1544
1545    SkPath  path;
1546    path.addOval(r);
1547    this->drawPath(path, paint);
1548}
1549
1550void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
1551                             const SkPaint& paint) {
1552    if (rx > 0 && ry > 0) {
1553        if (paint.canComputeFastBounds()) {
1554            SkRect storage;
1555            if (this->quickReject(paint.computeFastBounds(r, &storage),
1556                                  paint2EdgeType(&paint))) {
1557                return;
1558            }
1559        }
1560
1561        SkPath  path;
1562        path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
1563        this->drawPath(path, paint);
1564    } else {
1565        this->drawRect(r, paint);
1566    }
1567}
1568
1569void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
1570    if (paint.canComputeFastBounds()) {
1571        SkRect storage;
1572        if (this->quickReject(paint.computeFastBounds(oval, &storage),
1573                              paint2EdgeType(&paint))) {
1574            return;
1575        }
1576    }
1577
1578    SkPath  path;
1579    path.addOval(oval);
1580    this->drawPath(path, paint);
1581}
1582
1583void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
1584                       SkScalar sweepAngle, bool useCenter,
1585                       const SkPaint& paint) {
1586    if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
1587        this->drawOval(oval, paint);
1588    } else {
1589        SkPath  path;
1590        if (useCenter) {
1591            path.moveTo(oval.centerX(), oval.centerY());
1592        }
1593        path.arcTo(oval, startAngle, sweepAngle, !useCenter);
1594        if (useCenter) {
1595            path.close();
1596        }
1597        this->drawPath(path, paint);
1598    }
1599}
1600
1601void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
1602                                const SkPath& path, SkScalar hOffset,
1603                                SkScalar vOffset, const SkPaint& paint) {
1604    SkMatrix    matrix;
1605
1606    matrix.setTranslate(hOffset, vOffset);
1607    this->drawTextOnPath(text, byteLength, path, &matrix, paint);
1608}
1609
1610///////////////////////////////////////////////////////////////////////////////
1611
1612void SkCanvas::drawPicture(SkPicture& picture) {
1613    int saveCount = save();
1614    picture.draw(this);
1615    restoreToCount(saveCount);
1616}
1617
1618///////////////////////////////////////////////////////////////////////////////
1619///////////////////////////////////////////////////////////////////////////////
1620
1621SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
1622    SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
1623
1624    SkASSERT(canvas);
1625
1626    fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
1627    fDone = !fImpl->next();
1628}
1629
1630SkCanvas::LayerIter::~LayerIter() {
1631    fImpl->~SkDrawIter();
1632}
1633
1634void SkCanvas::LayerIter::next() {
1635    fDone = !fImpl->next();
1636}
1637
1638SkDevice* SkCanvas::LayerIter::device() const {
1639    return fImpl->getDevice();
1640}
1641
1642const SkMatrix& SkCanvas::LayerIter::matrix() const {
1643    return fImpl->getMatrix();
1644}
1645
1646const SkPaint& SkCanvas::LayerIter::paint() const {
1647    const SkPaint* paint = fImpl->getPaint();
1648    if (NULL == paint) {
1649        paint = &fDefaultPaint;
1650    }
1651    return *paint;
1652}
1653
1654const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
1655int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
1656int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
1657