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