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