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