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::drawPosTextOnPath(const void* text, size_t byteLength,
1242                                 const SkPoint pos[], const SkPaint& paint,
1243                                 const SkPath& path, const SkMatrix* matrix) {
1244
1245    ITER_BEGIN(paint, SkDrawFilter::kText_Type)
1246
1247    while (iter.next()) {
1248        iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos,
1249                                        paint, path, matrix);
1250    }
1251
1252    ITER_END
1253}
1254
1255void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
1256                            const SkPoint verts[], const SkPoint texs[],
1257                            const SkColor colors[], SkXfermode* xmode,
1258                            const uint16_t indices[], int indexCount,
1259                            const SkPaint& paint) {
1260    ITER_BEGIN(paint, SkDrawFilter::kPath_Type)
1261
1262    while (iter.next()) {
1263        iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
1264                                   colors, xmode, indices, indexCount, paint);
1265    }
1266
1267    ITER_END
1268}
1269
1270void SkCanvas::drawData(const void* data, size_t length) {
1271    // do nothing. Subclasses may do something with the data
1272}
1273
1274//////////////////////////////////////////////////////////////////////////////
1275// These methods are NOT virtual, and therefore must call back into virtual
1276// methods, rather than actually drawing themselves.
1277//////////////////////////////////////////////////////////////////////////////
1278
1279void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
1280                        SkXfermode::Mode mode) {
1281    SkPaint paint;
1282
1283    paint.setARGB(a, r, g, b);
1284    if (SkXfermode::kSrcOver_Mode != mode) {
1285        paint.setXfermodeMode(mode);
1286    }
1287    this->drawPaint(paint);
1288}
1289
1290void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
1291    SkPaint paint;
1292
1293    paint.setColor(c);
1294    if (SkXfermode::kSrcOver_Mode != mode) {
1295        paint.setXfermodeMode(mode);
1296    }
1297    this->drawPaint(paint);
1298}
1299
1300void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
1301    SkPoint pt;
1302
1303    pt.set(x, y);
1304    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1305}
1306
1307void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
1308    SkPoint pt;
1309    SkPaint paint;
1310
1311    pt.set(x, y);
1312    paint.setColor(color);
1313    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1314}
1315
1316void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
1317                        const SkPaint& paint) {
1318    SkPoint pts[2];
1319
1320    pts[0].set(x0, y0);
1321    pts[1].set(x1, y1);
1322    this->drawPoints(kLines_PointMode, 2, pts, paint);
1323}
1324
1325void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
1326                              SkScalar right, SkScalar bottom,
1327                              const SkPaint& paint) {
1328    SkRect  r;
1329
1330    r.set(left, top, right, bottom);
1331    this->drawRect(r, paint);
1332}
1333
1334void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
1335                          const SkPaint& paint) {
1336    if (radius < 0) {
1337        radius = 0;
1338    }
1339
1340    SkRect  r;
1341    r.set(cx - radius, cy - radius, cx + radius, cy + radius);
1342
1343    if (paint.canComputeFastBounds()) {
1344        SkRect storage;
1345        if (this->quickReject(paint.computeFastBounds(r, &storage),
1346                              paint2EdgeType(&paint))) {
1347            return;
1348        }
1349    }
1350
1351    SkPath  path;
1352    path.addOval(r);
1353    this->drawPath(path, paint);
1354}
1355
1356void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
1357                             const SkPaint& paint) {
1358    if (rx > 0 && ry > 0) {
1359        if (paint.canComputeFastBounds()) {
1360            SkRect storage;
1361            if (this->quickReject(paint.computeFastBounds(r, &storage),
1362                                  paint2EdgeType(&paint))) {
1363                return;
1364            }
1365        }
1366
1367        SkPath  path;
1368        path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
1369        this->drawPath(path, paint);
1370    } else {
1371        this->drawRect(r, paint);
1372    }
1373}
1374
1375void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
1376    if (paint.canComputeFastBounds()) {
1377        SkRect storage;
1378        if (this->quickReject(paint.computeFastBounds(oval, &storage),
1379                              paint2EdgeType(&paint))) {
1380            return;
1381        }
1382    }
1383
1384    SkPath  path;
1385    path.addOval(oval);
1386    this->drawPath(path, paint);
1387}
1388
1389void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
1390                       SkScalar sweepAngle, bool useCenter,
1391                       const SkPaint& paint) {
1392    if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
1393        this->drawOval(oval, paint);
1394    } else {
1395        SkPath  path;
1396        if (useCenter) {
1397            path.moveTo(oval.centerX(), oval.centerY());
1398        }
1399        path.arcTo(oval, startAngle, sweepAngle, !useCenter);
1400        if (useCenter) {
1401            path.close();
1402        }
1403        this->drawPath(path, paint);
1404    }
1405}
1406
1407void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
1408                                const SkPath& path, SkScalar hOffset,
1409                                SkScalar vOffset, const SkPaint& paint) {
1410    SkMatrix    matrix;
1411
1412    matrix.setTranslate(hOffset, vOffset);
1413    this->drawTextOnPath(text, byteLength, path, &matrix, paint);
1414}
1415
1416///////////////////////////////////////////////////////////////////////////////
1417
1418void SkCanvas::drawPicture(SkPicture& picture) {
1419    int saveCount = save();
1420    picture.draw(this);
1421    restoreToCount(saveCount);
1422}
1423
1424void SkCanvas::drawShape(SkShape* shape) {
1425    // shape baseclass takes care of save/restore
1426    shape->draw(this);
1427}
1428
1429///////////////////////////////////////////////////////////////////////////////
1430///////////////////////////////////////////////////////////////////////////////
1431
1432SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
1433    // need COMPILE_TIME_ASSERT
1434    SkASSERT(sizeof(fStorage) >= sizeof(SkDrawIter));
1435
1436    SkASSERT(canvas);
1437
1438    fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
1439    fDone = !fImpl->next();
1440}
1441
1442SkCanvas::LayerIter::~LayerIter() {
1443    fImpl->~SkDrawIter();
1444}
1445
1446void SkCanvas::LayerIter::next() {
1447    fDone = !fImpl->next();
1448}
1449
1450SkDevice* SkCanvas::LayerIter::device() const {
1451    return fImpl->getDevice();
1452}
1453
1454const SkMatrix& SkCanvas::LayerIter::matrix() const {
1455    return fImpl->getMatrix();
1456}
1457
1458const SkPaint& SkCanvas::LayerIter::paint() const {
1459    const SkPaint* paint = fImpl->getPaint();
1460    if (NULL == paint) {
1461        paint = &fDefaultPaint;
1462    }
1463    return *paint;
1464}
1465
1466const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
1467int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
1468int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
1469
1470