SkCanvas.cpp revision 8d84fac294682647694b0d2d8a87ac2bd19b6aab
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();)
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    SkSafeRef(factory);
413    if (!factory)
414        fDeviceFactory = SkNEW(SkRasterDeviceFactory);
415
416    this->init(NULL);
417}
418
419SkCanvas::SkCanvas(SkDevice* device)
420        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)),
421          fDeviceFactory(device->getDeviceFactory()) {
422    inc_canvas();
423
424    this->init(device);
425}
426
427SkCanvas::SkCanvas(const SkBitmap& bitmap)
428        : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
429    inc_canvas();
430
431    SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
432    fDeviceFactory = device->getDeviceFactory();
433    this->init(device)->unref();
434}
435
436SkCanvas::~SkCanvas() {
437    // free up the contents of our deque
438    this->restoreToCount(1);    // restore everything but the last
439    this->internalRestore();    // restore the last, since we're going away
440
441    SkSafeUnref(fBounder);
442    SkSafeUnref(fDeviceFactory);
443
444    dec_canvas();
445}
446
447SkBounder* SkCanvas::setBounder(SkBounder* bounder) {
448    SkRefCnt_SafeAssign(fBounder, bounder);
449    return bounder;
450}
451
452SkDrawFilter* SkCanvas::getDrawFilter() const {
453    return fMCRec->fFilter;
454}
455
456SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
457    SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
458    return filter;
459}
460
461///////////////////////////////////////////////////////////////////////////////
462
463SkDevice* SkCanvas::getDevice() const {
464    // return root device
465    SkDeque::Iter   iter(fMCStack);
466    MCRec*          rec = (MCRec*)iter.next();
467    SkASSERT(rec && rec->fLayer);
468    return rec->fLayer->fDevice;
469}
470
471SkDevice* SkCanvas::setDevice(SkDevice* device) {
472    // return root device
473    SkDeque::Iter   iter(fMCStack);
474    MCRec*          rec = (MCRec*)iter.next();
475    SkASSERT(rec && rec->fLayer);
476    SkDevice*       rootDevice = rec->fLayer->fDevice;
477
478    if (rootDevice == device) {
479        return device;
480    }
481
482    /* Notify the devices that they are going in/out of scope, so they can do
483       things like lock/unlock their pixels, etc.
484    */
485    if (device) {
486        device->lockPixels();
487    }
488    if (rootDevice) {
489        rootDevice->unlockPixels();
490    }
491
492    SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
493    rootDevice = device;
494
495    fDeviceCMDirty = true;
496
497    /*  Now we update our initial region to have the bounds of the new device,
498        and then intersect all of the clips in our stack with these bounds,
499        to ensure that we can't draw outside of the device's bounds (and trash
500                                                                     memory).
501
502    NOTE: this is only a partial-fix, since if the new device is larger than
503        the previous one, we don't know how to "enlarge" the clips in our stack,
504        so drawing may be artificially restricted. Without keeping a history of
505        all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
506        reconstruct the correct clips, so this approximation will have to do.
507        The caller really needs to restore() back to the base if they want to
508        accurately take advantage of the new device bounds.
509    */
510
511    if (NULL == device) {
512        rec->fRegion->setEmpty();
513        while ((rec = (MCRec*)iter.next()) != NULL) {
514            (void)rec->fRegion->setEmpty();
515        }
516    } else {
517        // compute our total bounds for all devices
518        SkIRect bounds;
519
520        bounds.set(0, 0, device->width(), device->height());
521
522        // now jam our 1st clip to be bounds, and intersect the rest with that
523        rec->fRegion->setRect(bounds);
524        while ((rec = (MCRec*)iter.next()) != NULL) {
525            (void)rec->fRegion->op(bounds, SkRegion::kIntersect_Op);
526        }
527    }
528    return device;
529}
530
531SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) {
532    SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap)));
533    device->unref();
534    return device;
535}
536
537//////////////////////////////////////////////////////////////////////////////
538
539bool SkCanvas::getViewport(SkIPoint* size) const {
540    if ((fDeviceFactory->getDeviceCapabilities()
541            & SkDeviceFactory::kGL_Capability) == 0)
542        return false;
543    if (size)
544        size->set(getDevice()->width(), getDevice()->height());
545    return true;
546}
547
548bool SkCanvas::setViewport(int width, int height) {
549    if ((fDeviceFactory->getDeviceCapabilities()
550            & SkDeviceFactory::kGL_Capability) == 0)
551        return false;
552    this->setDevice(createDevice(SkBitmap::kARGB_8888_Config, width, height,
553                                 false, false))->unref();
554    return true;
555}
556
557void SkCanvas::updateDeviceCMCache() {
558    if (fDeviceCMDirty) {
559        const SkMatrix& totalMatrix = this->getTotalMatrix();
560        const SkRegion& totalClip = this->getTotalClip();
561        DeviceCM*       layer = fMCRec->fTopLayer;
562
563        if (NULL == layer->fNext) {   // only one layer
564            layer->updateMC(totalMatrix, totalClip, NULL);
565        } else {
566            SkRegion clip;
567            clip = totalClip;  // make a copy
568            do {
569                layer->updateMC(totalMatrix, clip, &clip);
570            } while ((layer = layer->fNext) != NULL);
571        }
572        fDeviceCMDirty = false;
573    }
574}
575
576void SkCanvas::prepareForDeviceDraw(SkDevice* device) {
577    SkASSERT(device);
578    if (fLastDeviceToGainFocus != device) {
579        device->gainFocus(this);
580        fLastDeviceToGainFocus = device;
581    }
582}
583
584///////////////////////////////////////////////////////////////////////////////
585
586int SkCanvas::internalSave(SaveFlags flags) {
587    int saveCount = this->getSaveCount(); // record this before the actual save
588
589    MCRec* newTop = (MCRec*)fMCStack.push_back();
590    new (newTop) MCRec(fMCRec, flags);    // balanced in restore()
591
592    newTop->fNext = fMCRec;
593    fMCRec = newTop;
594
595    return saveCount;
596}
597
598int SkCanvas::save(SaveFlags flags) {
599    // call shared impl
600    return this->internalSave(flags);
601}
602
603#define C32MASK (1 << SkBitmap::kARGB_8888_Config)
604#define C16MASK (1 << SkBitmap::kRGB_565_Config)
605#define C8MASK  (1 << SkBitmap::kA8_Config)
606
607static SkBitmap::Config resolve_config(SkCanvas* canvas,
608                                       const SkIRect& bounds,
609                                       SkCanvas::SaveFlags flags,
610                                       bool* isOpaque) {
611    *isOpaque = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) == 0;
612
613#if 0
614    // loop through and union all the configs we may draw into
615    uint32_t configMask = 0;
616    for (int i = canvas->countLayerDevices() - 1; i >= 0; --i)
617    {
618        SkDevice* device = canvas->getLayerDevice(i);
619        if (device->intersects(bounds))
620            configMask |= 1 << device->config();
621    }
622
623    // if the caller wants alpha or fullcolor, we can't return 565
624    if (flags & (SkCanvas::kFullColorLayer_SaveFlag |
625                 SkCanvas::kHasAlphaLayer_SaveFlag))
626        configMask &= ~C16MASK;
627
628    switch (configMask) {
629    case C8MASK:    // if we only have A8, return that
630        return SkBitmap::kA8_Config;
631
632    case C16MASK:   // if we only have 565, return that
633        return SkBitmap::kRGB_565_Config;
634
635    default:
636        return SkBitmap::kARGB_8888_Config; // default answer
637    }
638#else
639    return SkBitmap::kARGB_8888_Config; // default answer
640#endif
641}
642
643static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
644    return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
645}
646
647int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
648                        SaveFlags flags) {
649    // do this before we create the layer. We don't call the public save() since
650    // that would invoke a possibly overridden virtual
651    int count = this->internalSave(flags);
652
653    fDeviceCMDirty = true;
654
655    SkIRect         ir;
656    const SkIRect&  clipBounds = this->getTotalClip().getBounds();
657
658    if (NULL != bounds) {
659        SkRect r;
660
661        this->getTotalMatrix().mapRect(&r, *bounds);
662        r.roundOut(&ir);
663        // early exit if the layer's bounds are clipped out
664        if (!ir.intersect(clipBounds)) {
665            if (bounds_affects_clip(flags))
666                fMCRec->fRegion->setEmpty();
667            return count;
668        }
669    } else {    // no user bounds, so just use the clip
670        ir = clipBounds;
671    }
672
673    // early exit if the clip is now empty
674    if (bounds_affects_clip(flags) &&
675        !fMCRec->fRegion->op(ir, SkRegion::kIntersect_Op)) {
676        return count;
677    }
678
679    bool isOpaque;
680    SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque);
681
682    SkDevice* device = this->createDevice(config, ir.width(), ir.height(),
683                                          isOpaque, true);
684    DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint));
685    device->unref();
686
687    layer->fNext = fMCRec->fTopLayer;
688    fMCRec->fLayer = layer;
689    fMCRec->fTopLayer = layer;    // this field is NOT an owner of layer
690
691    return count;
692}
693
694int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
695                             SaveFlags flags) {
696    if (0xFF == alpha) {
697        return this->saveLayer(bounds, NULL, flags);
698    } else {
699        SkPaint tmpPaint;
700        tmpPaint.setAlpha(alpha);
701        return this->saveLayer(bounds, &tmpPaint, flags);
702    }
703}
704
705void SkCanvas::restore() {
706    // check for underflow
707    if (fMCStack.count() > 1) {
708        this->internalRestore();
709    }
710}
711
712void SkCanvas::internalRestore() {
713    SkASSERT(fMCStack.count() != 0);
714
715    fDeviceCMDirty = true;
716    fLocalBoundsCompareTypeDirty = true;
717    fLocalBoundsCompareTypeDirtyBW = true;
718
719	// reserve our layer (if any)
720    DeviceCM* layer = fMCRec->fLayer;   // may be null
721    // now detach it from fMCRec so we can pop(). Gets freed after its drawn
722    fMCRec->fLayer = NULL;
723
724    // now do the normal restore()
725    fMCRec->~MCRec();       // balanced in save()
726    fMCStack.pop_back();
727    fMCRec = (MCRec*)fMCStack.back();
728
729    /*  Time to draw the layer's offscreen. We can't call the public drawSprite,
730        since if we're being recorded, we don't want to record this (the
731        recorder will have already recorded the restore).
732    */
733    if (NULL != layer) {
734        if (layer->fNext) {
735            this->drawDevice(layer->fDevice, layer->fX, layer->fY,
736                             layer->fPaint);
737            // reset this, since drawDevice will have set it to true
738            fDeviceCMDirty = true;
739        }
740        SkDELETE(layer);
741	}
742}
743
744int SkCanvas::getSaveCount() const {
745    return fMCStack.count();
746}
747
748void SkCanvas::restoreToCount(int count) {
749    // sanity check
750    if (count < 1) {
751        count = 1;
752    }
753    while (fMCStack.count() > count) {
754        this->restore();
755    }
756}
757
758/////////////////////////////////////////////////////////////////////////////
759
760// can't draw it if its empty, or its too big for a fixed-point width or height
761static bool reject_bitmap(const SkBitmap& bitmap) {
762    return  bitmap.width() <= 0 || bitmap.height() <= 0 ||
763            bitmap.width() > 32767 || bitmap.height() > 32767;
764}
765
766void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
767                                const SkMatrix& matrix, const SkPaint* paint) {
768    if (reject_bitmap(bitmap)) {
769        return;
770    }
771
772    if (NULL == paint) {
773        SkPaint tmpPaint;
774        this->commonDrawBitmap(bitmap, matrix, tmpPaint);
775    } else {
776        this->commonDrawBitmap(bitmap, matrix, *paint);
777    }
778}
779
780void SkCanvas::drawDevice(SkDevice* device, int x, int y,
781                          const SkPaint* paint) {
782    SkPaint tmp;
783    if (NULL == paint) {
784        tmp.setDither(true);
785        paint = &tmp;
786    }
787
788    ITER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
789    while (iter.next()) {
790        iter.fDevice->drawDevice(iter, device, x - iter.getX(), y - iter.getY(),
791                                 *paint);
792    }
793    ITER_END
794}
795
796/////////////////////////////////////////////////////////////////////////////
797
798bool SkCanvas::translate(SkScalar dx, SkScalar dy) {
799    fDeviceCMDirty = true;
800    fLocalBoundsCompareTypeDirty = true;
801    fLocalBoundsCompareTypeDirtyBW = true;
802    return fMCRec->fMatrix->preTranslate(dx, dy);
803}
804
805bool SkCanvas::scale(SkScalar sx, SkScalar sy) {
806    fDeviceCMDirty = true;
807    fLocalBoundsCompareTypeDirty = true;
808    fLocalBoundsCompareTypeDirtyBW = true;
809    return fMCRec->fMatrix->preScale(sx, sy);
810}
811
812bool SkCanvas::rotate(SkScalar degrees) {
813    fDeviceCMDirty = true;
814    fLocalBoundsCompareTypeDirty = true;
815    fLocalBoundsCompareTypeDirtyBW = true;
816    return fMCRec->fMatrix->preRotate(degrees);
817}
818
819bool SkCanvas::skew(SkScalar sx, SkScalar sy) {
820    fDeviceCMDirty = true;
821    fLocalBoundsCompareTypeDirty = true;
822    fLocalBoundsCompareTypeDirtyBW = true;
823    return fMCRec->fMatrix->preSkew(sx, sy);
824}
825
826bool SkCanvas::concat(const SkMatrix& matrix) {
827    fDeviceCMDirty = true;
828    fLocalBoundsCompareTypeDirty = true;
829    fLocalBoundsCompareTypeDirtyBW = true;
830    return fMCRec->fMatrix->preConcat(matrix);
831}
832
833void SkCanvas::setMatrix(const SkMatrix& matrix) {
834    fDeviceCMDirty = true;
835    fLocalBoundsCompareTypeDirty = true;
836    fLocalBoundsCompareTypeDirtyBW = true;
837    *fMCRec->fMatrix = matrix;
838}
839
840// this is not virtual, so it must call a virtual method so that subclasses
841// will see its action
842void SkCanvas::resetMatrix() {
843    SkMatrix matrix;
844
845    matrix.reset();
846    this->setMatrix(matrix);
847}
848
849//////////////////////////////////////////////////////////////////////////////
850
851bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
852    fDeviceCMDirty = true;
853    fLocalBoundsCompareTypeDirty = true;
854    fLocalBoundsCompareTypeDirtyBW = true;
855
856    if (fMCRec->fMatrix->rectStaysRect()) {
857        // for these simpler matrices, we can stay a rect ever after applying
858        // the matrix. This means we don't have to a) make a path, and b) tell
859        // the region code to scan-convert the path, only to discover that it
860        // is really just a rect.
861        SkRect      r;
862        SkIRect     ir;
863
864        fMCRec->fMatrix->mapRect(&r, rect);
865        r.round(&ir);
866        return fMCRec->fRegion->op(ir, op);
867    } else {
868        // since we're rotate or some such thing, we convert the rect to a path
869        // and clip against that, since it can handle any matrix. However, to
870        // avoid recursion in the case where we are subclassed (e.g. Pictures)
871        // we explicitly call "our" version of clipPath.
872        SkPath  path;
873
874        path.addRect(rect);
875        return this->SkCanvas::clipPath(path, op);
876    }
877}
878
879bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op) {
880    fDeviceCMDirty = true;
881    fLocalBoundsCompareTypeDirty = true;
882    fLocalBoundsCompareTypeDirtyBW = true;
883
884    SkPath devPath;
885    path.transform(*fMCRec->fMatrix, &devPath);
886
887    if (SkRegion::kIntersect_Op == op) {
888        return fMCRec->fRegion->setPath(devPath, *fMCRec->fRegion);
889    } else {
890        SkRegion base;
891        const SkBitmap& bm = this->getDevice()->accessBitmap(false);
892        base.setRect(0, 0, bm.width(), bm.height());
893
894        if (SkRegion::kReplace_Op == op) {
895            return fMCRec->fRegion->setPath(devPath, base);
896        } else {
897            SkRegion rgn;
898            rgn.setPath(devPath, base);
899            return fMCRec->fRegion->op(rgn, op);
900        }
901    }
902}
903
904bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
905    fDeviceCMDirty = true;
906    fLocalBoundsCompareTypeDirty = true;
907    fLocalBoundsCompareTypeDirtyBW = true;
908
909    return fMCRec->fRegion->op(rgn, op);
910}
911
912void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const {
913    SkRect r;
914    SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType :
915            fLocalBoundsCompareTypeBW;
916
917    if (!this->getClipBounds(&r, et)) {
918        rCompare.setEmpty();
919    } else {
920        rCompare.set(SkScalarToCompareType(r.fLeft),
921                     SkScalarToCompareType(r.fTop),
922                     SkScalarToCompareType(r.fRight),
923                     SkScalarToCompareType(r.fBottom));
924    }
925}
926
927/*  current impl ignores edgetype, and relies on
928    getLocalClipBoundsCompareType(), which always returns a value assuming
929    antialiasing (worst case)
930 */
931bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const {
932    if (fMCRec->fRegion->isEmpty()) {
933        return true;
934    }
935
936    if (fMCRec->fMatrix->getType() & SkMatrix::kPerspective_Mask) {
937        SkRect dst;
938        fMCRec->fMatrix->mapRect(&dst, rect);
939        SkIRect idst;
940        dst.roundOut(&idst);
941        return !SkIRect::Intersects(idst, fMCRec->fRegion->getBounds());
942    } else {
943        const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et);
944
945        // for speed, do the most likely reject compares first
946        SkScalarCompareType userT = SkScalarToCompareType(rect.fTop);
947        SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom);
948        if (userT >= clipR.fBottom || userB <= clipR.fTop) {
949            return true;
950        }
951        SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft);
952        SkScalarCompareType userR = SkScalarToCompareType(rect.fRight);
953        if (userL >= clipR.fRight || userR <= clipR.fLeft) {
954            return true;
955        }
956        return false;
957    }
958}
959
960bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const {
961    return path.isEmpty() || this->quickReject(path.getBounds(), et);
962}
963
964bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const {
965    /*  current impl ignores edgetype, and relies on
966        getLocalClipBoundsCompareType(), which always returns a value assuming
967        antialiasing (worst case)
968     */
969
970    if (fMCRec->fRegion->isEmpty()) {
971        return true;
972    }
973
974    SkScalarCompareType userT = SkScalarToCompareType(top);
975    SkScalarCompareType userB = SkScalarToCompareType(bottom);
976
977    // check for invalid user Y coordinates (i.e. empty)
978    // reed: why do we need to do this check, since it slows us down?
979    if (userT >= userB) {
980        return true;
981    }
982
983    // check if we are above or below the local clip bounds
984    const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType();
985    return userT >= clipR.fBottom || userB <= clipR.fTop;
986}
987
988bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const {
989    const SkRegion& clip = *fMCRec->fRegion;
990    if (clip.isEmpty()) {
991        if (bounds) {
992            bounds->setEmpty();
993        }
994        return false;
995    }
996
997    SkMatrix inverse;
998    // if we can't invert the CTM, we can't return local clip bounds
999    if (!fMCRec->fMatrix->invert(&inverse)) {
1000        if (bounds) {
1001            bounds->setEmpty();
1002        }
1003        return false;
1004    }
1005
1006    if (NULL != bounds) {
1007        SkRect   r;
1008        // get the clip's bounds
1009        const SkIRect& ibounds = clip.getBounds();
1010        // adjust it outwards if we are antialiasing
1011        int inset = (kAA_EdgeType == et);
1012        r.iset(ibounds.fLeft - inset,  ibounds.fTop - inset,
1013               ibounds.fRight + inset, ibounds.fBottom + inset);
1014
1015        // invert into local coordinates
1016        inverse.mapRect(bounds, r);
1017    }
1018    return true;
1019}
1020
1021const SkMatrix& SkCanvas::getTotalMatrix() const {
1022    return *fMCRec->fMatrix;
1023}
1024
1025const SkRegion& SkCanvas::getTotalClip() const {
1026    return *fMCRec->fRegion;
1027}
1028
1029///////////////////////////////////////////////////////////////////////////////
1030
1031SkDevice* SkCanvas::createDevice(SkBitmap::Config config, int width,
1032                                 int height, bool isOpaque, bool isForLayer) {
1033
1034    return fDeviceFactory->newDevice(config, width, height, isOpaque,
1035                                     isForLayer);
1036}
1037
1038//////////////////////////////////////////////////////////////////////////////
1039//  These are the virtual drawing methods
1040//////////////////////////////////////////////////////////////////////////////
1041
1042void SkCanvas::drawPaint(const SkPaint& paint) {
1043    ITER_BEGIN(paint, SkDrawFilter::kPaint_Type)
1044
1045    while (iter.next()) {
1046        iter.fDevice->drawPaint(iter, paint);
1047    }
1048
1049    ITER_END
1050}
1051
1052void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
1053                          const SkPaint& paint) {
1054    if ((long)count <= 0) {
1055        return;
1056    }
1057
1058    SkASSERT(pts != NULL);
1059
1060    ITER_BEGIN(paint, SkDrawFilter::kPoint_Type)
1061
1062    while (iter.next()) {
1063        iter.fDevice->drawPoints(iter, mode, count, pts, paint);
1064    }
1065
1066    ITER_END
1067}
1068
1069void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1070    if (paint.canComputeFastBounds()) {
1071        SkRect storage;
1072        if (this->quickReject(paint.computeFastBounds(r, &storage),
1073                              paint2EdgeType(&paint))) {
1074            return;
1075        }
1076    }
1077
1078    ITER_BEGIN(paint, SkDrawFilter::kRect_Type)
1079
1080    while (iter.next()) {
1081        iter.fDevice->drawRect(iter, r, paint);
1082    }
1083
1084    ITER_END
1085}
1086
1087void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1088    if (paint.canComputeFastBounds()) {
1089        SkRect storage;
1090        const SkRect& bounds = path.getBounds();
1091        if (this->quickReject(paint.computeFastBounds(bounds, &storage),
1092                              paint2EdgeType(&paint))) {
1093            return;
1094        }
1095    }
1096
1097    ITER_BEGIN(paint, SkDrawFilter::kPath_Type)
1098
1099    while (iter.next()) {
1100        iter.fDevice->drawPath(iter, path, paint);
1101    }
1102
1103    ITER_END
1104}
1105
1106void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
1107                          const SkPaint* paint) {
1108    SkDEBUGCODE(bitmap.validate();)
1109
1110    if (NULL == paint || (paint->getMaskFilter() == NULL)) {
1111        SkRect fastBounds;
1112        fastBounds.set(x, y,
1113                       x + SkIntToScalar(bitmap.width()),
1114                       y + SkIntToScalar(bitmap.height()));
1115        if (this->quickReject(fastBounds, paint2EdgeType(paint))) {
1116            return;
1117        }
1118    }
1119
1120    SkMatrix matrix;
1121    matrix.setTranslate(x, y);
1122    this->internalDrawBitmap(bitmap, matrix, paint);
1123}
1124
1125void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
1126                              const SkRect& dst, const SkPaint* paint) {
1127    if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) {
1128        return;
1129    }
1130
1131    // do this now, to avoid the cost of calling extract for RLE bitmaps
1132    if (this->quickReject(dst, paint2EdgeType(paint))) {
1133        return;
1134    }
1135
1136    SkBitmap        tmp;    // storage if we need a subset of bitmap
1137    const SkBitmap* bitmapPtr = &bitmap;
1138
1139    if (NULL != src) {
1140        if (!bitmap.extractSubset(&tmp, *src)) {
1141            return;     // extraction failed
1142        }
1143        bitmapPtr = &tmp;
1144    }
1145
1146    SkMatrix matrix;
1147    SkRect tmpSrc;
1148    if (src) {
1149        tmpSrc.set(*src);
1150        // if the extract process clipped off the top or left of the
1151        // original, we adjust for that here to get the position right.
1152        if (tmpSrc.fLeft > 0) {
1153            tmpSrc.fRight -= tmpSrc.fLeft;
1154            tmpSrc.fLeft = 0;
1155        }
1156        if (tmpSrc.fTop > 0) {
1157            tmpSrc.fBottom -= tmpSrc.fTop;
1158            tmpSrc.fTop = 0;
1159        }
1160    } else {
1161        tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()),
1162                   SkIntToScalar(bitmap.height()));
1163    }
1164    matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
1165    this->internalDrawBitmap(*bitmapPtr, matrix, paint);
1166}
1167
1168void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
1169                                const SkPaint* paint) {
1170    SkDEBUGCODE(bitmap.validate();)
1171    this->internalDrawBitmap(bitmap, matrix, paint);
1172}
1173
1174void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
1175                                const SkPaint& paint) {
1176    SkDEBUGCODE(bitmap.validate();)
1177
1178    ITER_BEGIN(paint, SkDrawFilter::kBitmap_Type)
1179
1180    while (iter.next()) {
1181        iter.fDevice->drawBitmap(iter, bitmap, matrix, paint);
1182    }
1183
1184    ITER_END
1185}
1186
1187void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
1188                          const SkPaint* paint) {
1189    SkDEBUGCODE(bitmap.validate();)
1190
1191    if (reject_bitmap(bitmap)) {
1192        return;
1193    }
1194
1195    SkPaint tmp;
1196    if (NULL == paint) {
1197        paint = &tmp;
1198    }
1199
1200    ITER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
1201
1202    while (iter.next()) {
1203        iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(),
1204                                 *paint);
1205    }
1206    ITER_END
1207}
1208
1209void SkCanvas::drawText(const void* text, size_t byteLength,
1210                        SkScalar x, SkScalar y, const SkPaint& paint) {
1211    ITER_BEGIN(paint, SkDrawFilter::kText_Type)
1212
1213    while (iter.next()) {
1214        iter.fDevice->drawText(iter, text, byteLength, x, y, paint);
1215    }
1216
1217    ITER_END
1218}
1219
1220void SkCanvas::drawPosText(const void* text, size_t byteLength,
1221                           const SkPoint pos[], const SkPaint& paint) {
1222    ITER_BEGIN(paint, SkDrawFilter::kText_Type)
1223
1224    while (iter.next()) {
1225        iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
1226                                  paint);
1227    }
1228
1229    ITER_END
1230}
1231
1232void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
1233                            const SkScalar xpos[], SkScalar constY,
1234                            const SkPaint& paint) {
1235    ITER_BEGIN(paint, SkDrawFilter::kText_Type)
1236
1237    while (iter.next()) {
1238        iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
1239                                  paint);
1240    }
1241
1242    ITER_END
1243}
1244
1245void SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
1246                              const SkPath& path, const SkMatrix* matrix,
1247                              const SkPaint& paint) {
1248    ITER_BEGIN(paint, SkDrawFilter::kText_Type)
1249
1250    while (iter.next()) {
1251        iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
1252                                     matrix, paint);
1253    }
1254
1255    ITER_END
1256}
1257
1258void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
1259                            const SkPoint verts[], const SkPoint texs[],
1260                            const SkColor colors[], SkXfermode* xmode,
1261                            const uint16_t indices[], int indexCount,
1262                            const SkPaint& paint) {
1263    ITER_BEGIN(paint, SkDrawFilter::kPath_Type)
1264
1265    while (iter.next()) {
1266        iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
1267                                   colors, xmode, indices, indexCount, paint);
1268    }
1269
1270    ITER_END
1271}
1272
1273void SkCanvas::drawData(const void* data, size_t length) {
1274    // do nothing. Subclasses may do something with the data
1275}
1276
1277//////////////////////////////////////////////////////////////////////////////
1278// These methods are NOT virtual, and therefore must call back into virtual
1279// methods, rather than actually drawing themselves.
1280//////////////////////////////////////////////////////////////////////////////
1281
1282void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
1283                        SkXfermode::Mode mode) {
1284    SkPaint paint;
1285
1286    paint.setARGB(a, r, g, b);
1287    if (SkXfermode::kSrcOver_Mode != mode) {
1288        paint.setXfermodeMode(mode);
1289    }
1290    this->drawPaint(paint);
1291}
1292
1293void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
1294    SkPaint paint;
1295
1296    paint.setColor(c);
1297    if (SkXfermode::kSrcOver_Mode != mode) {
1298        paint.setXfermodeMode(mode);
1299    }
1300    this->drawPaint(paint);
1301}
1302
1303void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
1304    SkPoint pt;
1305
1306    pt.set(x, y);
1307    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1308}
1309
1310void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
1311    SkPoint pt;
1312    SkPaint paint;
1313
1314    pt.set(x, y);
1315    paint.setColor(color);
1316    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1317}
1318
1319void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
1320                        const SkPaint& paint) {
1321    SkPoint pts[2];
1322
1323    pts[0].set(x0, y0);
1324    pts[1].set(x1, y1);
1325    this->drawPoints(kLines_PointMode, 2, pts, paint);
1326}
1327
1328void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
1329                              SkScalar right, SkScalar bottom,
1330                              const SkPaint& paint) {
1331    SkRect  r;
1332
1333    r.set(left, top, right, bottom);
1334    this->drawRect(r, paint);
1335}
1336
1337void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
1338                          const SkPaint& paint) {
1339    if (radius < 0) {
1340        radius = 0;
1341    }
1342
1343    SkRect  r;
1344    r.set(cx - radius, cy - radius, cx + radius, cy + radius);
1345
1346    if (paint.canComputeFastBounds()) {
1347        SkRect storage;
1348        if (this->quickReject(paint.computeFastBounds(r, &storage),
1349                              paint2EdgeType(&paint))) {
1350            return;
1351        }
1352    }
1353
1354    SkPath  path;
1355    path.addOval(r);
1356    this->drawPath(path, paint);
1357}
1358
1359void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
1360                             const SkPaint& paint) {
1361    if (rx > 0 && ry > 0) {
1362        if (paint.canComputeFastBounds()) {
1363            SkRect storage;
1364            if (this->quickReject(paint.computeFastBounds(r, &storage),
1365                                  paint2EdgeType(&paint))) {
1366                return;
1367            }
1368        }
1369
1370        SkPath  path;
1371        path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
1372        this->drawPath(path, paint);
1373    } else {
1374        this->drawRect(r, paint);
1375    }
1376}
1377
1378void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
1379    if (paint.canComputeFastBounds()) {
1380        SkRect storage;
1381        if (this->quickReject(paint.computeFastBounds(oval, &storage),
1382                              paint2EdgeType(&paint))) {
1383            return;
1384        }
1385    }
1386
1387    SkPath  path;
1388    path.addOval(oval);
1389    this->drawPath(path, paint);
1390}
1391
1392void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
1393                       SkScalar sweepAngle, bool useCenter,
1394                       const SkPaint& paint) {
1395    if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
1396        this->drawOval(oval, paint);
1397    } else {
1398        SkPath  path;
1399        if (useCenter) {
1400            path.moveTo(oval.centerX(), oval.centerY());
1401        }
1402        path.arcTo(oval, startAngle, sweepAngle, !useCenter);
1403        if (useCenter) {
1404            path.close();
1405        }
1406        this->drawPath(path, paint);
1407    }
1408}
1409
1410void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
1411                                const SkPath& path, SkScalar hOffset,
1412                                SkScalar vOffset, const SkPaint& paint) {
1413    SkMatrix    matrix;
1414
1415    matrix.setTranslate(hOffset, vOffset);
1416    this->drawTextOnPath(text, byteLength, path, &matrix, paint);
1417}
1418
1419///////////////////////////////////////////////////////////////////////////////
1420
1421void SkCanvas::drawPicture(SkPicture& picture) {
1422    int saveCount = save();
1423    picture.draw(this);
1424    restoreToCount(saveCount);
1425}
1426
1427void SkCanvas::drawShape(SkShape* shape) {
1428    // shape baseclass takes care of save/restore
1429    shape->draw(this);
1430}
1431
1432///////////////////////////////////////////////////////////////////////////////
1433///////////////////////////////////////////////////////////////////////////////
1434
1435SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
1436    // need COMPILE_TIME_ASSERT
1437    SkASSERT(sizeof(fStorage) >= sizeof(SkDrawIter));
1438
1439    SkASSERT(canvas);
1440
1441    fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
1442    fDone = !fImpl->next();
1443}
1444
1445SkCanvas::LayerIter::~LayerIter() {
1446    fImpl->~SkDrawIter();
1447}
1448
1449void SkCanvas::LayerIter::next() {
1450    fDone = !fImpl->next();
1451}
1452
1453SkDevice* SkCanvas::LayerIter::device() const {
1454    return fImpl->getDevice();
1455}
1456
1457const SkMatrix& SkCanvas::LayerIter::matrix() const {
1458    return fImpl->getMatrix();
1459}
1460
1461const SkPaint& SkCanvas::LayerIter::paint() const {
1462    const SkPaint* paint = fImpl->getPaint();
1463    if (NULL == paint) {
1464        paint = &fDefaultPaint;
1465    }
1466    return *paint;
1467}
1468
1469const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
1470int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
1471int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
1472
1473