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