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