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