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