SkCanvas.cpp revision 17b78946096265d80215a6c946286ecaa35ea7ed
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 "SkTextFormatParams.h"
20#include "SkTLazy.h"
21#include "SkUtils.h"
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    }
532    return device;
533}
534
535SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) {
536    SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap)));
537    device->unref();
538    return device;
539}
540
541bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
542    SkDevice* device = this->getDevice();
543    if (!device) {
544        return false;
545    }
546    return device->readPixels(srcRect, bitmap);
547}
548
549//////////////////////////////////////////////////////////////////////////////
550
551bool SkCanvas::readPixels(SkBitmap* bitmap) {
552    SkDevice* device = this->getDevice();
553    if (!device) {
554        return false;
555    }
556    SkIRect bounds;
557    bounds.set(0, 0, device->width(), device->height());
558    return this->readPixels(bounds, bitmap);
559}
560
561void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
562    SkDevice* device = this->getDevice();
563    if (device) {
564        device->writePixels(bitmap, x, y);
565    }
566}
567
568//////////////////////////////////////////////////////////////////////////////
569
570void SkCanvas::updateDeviceCMCache() {
571    if (fDeviceCMDirty) {
572        const SkMatrix& totalMatrix = this->getTotalMatrix();
573        const SkRegion& totalClip = this->getTotalClip();
574        DeviceCM*       layer = fMCRec->fTopLayer;
575
576        if (NULL == layer->fNext) {   // only one layer
577            layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
578            if (fUseExternalMatrix) {
579                layer->updateExternalMatrix(fExternalMatrix,
580                                            fExternalInverse);
581            }
582        } else {
583            SkRegion clip;
584            clip = totalClip;  // make a copy
585            do {
586                layer->updateMC(totalMatrix, clip, fClipStack, &clip);
587                if (fUseExternalMatrix) {
588                    layer->updateExternalMatrix(fExternalMatrix,
589                                                fExternalInverse);
590                }
591            } while ((layer = layer->fNext) != NULL);
592        }
593        fDeviceCMDirty = false;
594    }
595}
596
597void SkCanvas::prepareForDeviceDraw(SkDevice* device, const SkMatrix& matrix,
598                                    const SkRegion& clip,
599                                    const SkClipStack& clipStack) {
600    SkASSERT(device);
601    if (fLastDeviceToGainFocus != device) {
602        device->gainFocus(this, matrix, clip, clipStack);
603        fLastDeviceToGainFocus = device;
604    }
605}
606
607///////////////////////////////////////////////////////////////////////////////
608
609int SkCanvas::internalSave(SaveFlags flags) {
610    int saveCount = this->getSaveCount(); // record this before the actual save
611
612    MCRec* newTop = (MCRec*)fMCStack.push_back();
613    new (newTop) MCRec(fMCRec, flags);    // balanced in restore()
614
615    newTop->fNext = fMCRec;
616    fMCRec = newTop;
617
618    fClipStack.save();
619    SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
620
621    return saveCount;
622}
623
624int SkCanvas::save(SaveFlags flags) {
625    // call shared impl
626    return this->internalSave(flags);
627}
628
629#define C32MASK (1 << SkBitmap::kARGB_8888_Config)
630#define C16MASK (1 << SkBitmap::kRGB_565_Config)
631#define C8MASK  (1 << SkBitmap::kA8_Config)
632
633static SkBitmap::Config resolve_config(SkCanvas* canvas,
634                                       const SkIRect& bounds,
635                                       SkCanvas::SaveFlags flags,
636                                       bool* isOpaque) {
637    *isOpaque = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) == 0;
638
639#if 0
640    // loop through and union all the configs we may draw into
641    uint32_t configMask = 0;
642    for (int i = canvas->countLayerDevices() - 1; i >= 0; --i)
643    {
644        SkDevice* device = canvas->getLayerDevice(i);
645        if (device->intersects(bounds))
646            configMask |= 1 << device->config();
647    }
648
649    // if the caller wants alpha or fullcolor, we can't return 565
650    if (flags & (SkCanvas::kFullColorLayer_SaveFlag |
651                 SkCanvas::kHasAlphaLayer_SaveFlag))
652        configMask &= ~C16MASK;
653
654    switch (configMask) {
655    case C8MASK:    // if we only have A8, return that
656        return SkBitmap::kA8_Config;
657
658    case C16MASK:   // if we only have 565, return that
659        return SkBitmap::kRGB_565_Config;
660
661    default:
662        return SkBitmap::kARGB_8888_Config; // default answer
663    }
664#else
665    return SkBitmap::kARGB_8888_Config; // default answer
666#endif
667}
668
669static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
670    return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
671}
672
673int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
674                        SaveFlags flags) {
675    // do this before we create the layer. We don't call the public save() since
676    // that would invoke a possibly overridden virtual
677    int count = this->internalSave(flags);
678
679    fDeviceCMDirty = true;
680
681    SkIRect         ir;
682    const SkIRect&  clipBounds = this->getTotalClip().getBounds();
683    if (clipBounds.isEmpty()) {
684        return count;
685    }
686
687    if (NULL != bounds) {
688        SkRect r;
689
690        this->getTotalMatrix().mapRect(&r, *bounds);
691        r.roundOut(&ir);
692        // early exit if the layer's bounds are clipped out
693        if (!ir.intersect(clipBounds)) {
694            if (bounds_affects_clip(flags))
695                fMCRec->fRegion->setEmpty();
696            return count;
697        }
698    } else {    // no user bounds, so just use the clip
699        ir = clipBounds;
700    }
701
702    fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op);
703    // early exit if the clip is now empty
704    if (bounds_affects_clip(flags) &&
705        !fMCRec->fRegion->op(ir, SkRegion::kIntersect_Op)) {
706        return count;
707    }
708
709    bool isOpaque;
710    SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque);
711
712    SkDevice* device = this->createLayerDevice(config, ir.width(), ir.height(),
713                                               isOpaque);
714    if (NULL == device) {
715        SkDebugf("Unable to create device for layer.");
716        return count;
717    }
718
719    device->setOrigin(ir.fLeft, ir.fTop);
720    DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint));
721    device->unref();
722
723    layer->fNext = fMCRec->fTopLayer;
724    fMCRec->fLayer = layer;
725    fMCRec->fTopLayer = layer;    // this field is NOT an owner of layer
726
727    return count;
728}
729
730int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
731                             SaveFlags flags) {
732    if (0xFF == alpha) {
733        return this->saveLayer(bounds, NULL, flags);
734    } else {
735        SkPaint tmpPaint;
736        tmpPaint.setAlpha(alpha);
737        return this->saveLayer(bounds, &tmpPaint, flags);
738    }
739}
740
741void SkCanvas::restore() {
742    // check for underflow
743    if (fMCStack.count() > 1) {
744        this->internalRestore();
745    }
746}
747
748void SkCanvas::internalRestore() {
749    SkASSERT(fMCStack.count() != 0);
750
751    fDeviceCMDirty = true;
752    fLocalBoundsCompareTypeDirty = true;
753    fLocalBoundsCompareTypeDirtyBW = true;
754
755    fClipStack.restore();
756    // reserve our layer (if any)
757    DeviceCM* layer = fMCRec->fLayer;   // may be null
758    // now detach it from fMCRec so we can pop(). Gets freed after its drawn
759    fMCRec->fLayer = NULL;
760
761    // now do the normal restore()
762    fMCRec->~MCRec();       // balanced in save()
763    fMCStack.pop_back();
764    fMCRec = (MCRec*)fMCStack.back();
765
766    /*  Time to draw the layer's offscreen. We can't call the public drawSprite,
767        since if we're being recorded, we don't want to record this (the
768        recorder will have already recorded the restore).
769    */
770    if (NULL != layer) {
771        if (layer->fNext) {
772            const SkIPoint& origin = layer->fDevice->getOrigin();
773            this->drawDevice(layer->fDevice, origin.x(), origin.y(),
774                             layer->fPaint);
775            // reset this, since drawDevice will have set it to true
776            fDeviceCMDirty = true;
777        }
778        SkDELETE(layer);
779    }
780
781    SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
782}
783
784int SkCanvas::getSaveCount() const {
785    return fMCStack.count();
786}
787
788void SkCanvas::restoreToCount(int count) {
789    // sanity check
790    if (count < 1) {
791        count = 1;
792    }
793    while (fMCStack.count() > count) {
794        this->restore();
795    }
796}
797
798/////////////////////////////////////////////////////////////////////////////
799
800// can't draw it if its empty, or its too big for a fixed-point width or height
801static bool reject_bitmap(const SkBitmap& bitmap) {
802    return  bitmap.width() <= 0 || bitmap.height() <= 0
803#ifndef SK_ALLOW_OVER_32K_BITMAPS
804            || bitmap.width() > 32767 || bitmap.height() > 32767
805#endif
806            ;
807}
808
809void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
810                                const SkMatrix& matrix, const SkPaint* paint) {
811    if (reject_bitmap(bitmap)) {
812        return;
813    }
814
815    SkLazyPaint lazy;
816    if (NULL == paint) {
817        paint = lazy.init();
818    }
819    this->commonDrawBitmap(bitmap, srcRect, matrix, *paint);
820}
821
822void SkCanvas::drawDevice(SkDevice* device, int x, int y,
823                          const SkPaint* paint) {
824    SkPaint tmp;
825    if (NULL == paint) {
826        tmp.setDither(true);
827        paint = &tmp;
828    }
829
830    LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
831    while (iter.next()) {
832        iter.fDevice->drawDevice(iter, device, x - iter.getX(), y - iter.getY(),
833                                 looper.paint());
834    }
835    LOOPER_END
836}
837
838/////////////////////////////////////////////////////////////////////////////
839
840bool SkCanvas::translate(SkScalar dx, SkScalar dy) {
841    fDeviceCMDirty = true;
842    fLocalBoundsCompareTypeDirty = true;
843    fLocalBoundsCompareTypeDirtyBW = true;
844    return fMCRec->fMatrix->preTranslate(dx, dy);
845}
846
847bool SkCanvas::scale(SkScalar sx, SkScalar sy) {
848    fDeviceCMDirty = true;
849    fLocalBoundsCompareTypeDirty = true;
850    fLocalBoundsCompareTypeDirtyBW = true;
851    return fMCRec->fMatrix->preScale(sx, sy);
852}
853
854bool SkCanvas::rotate(SkScalar degrees) {
855    fDeviceCMDirty = true;
856    fLocalBoundsCompareTypeDirty = true;
857    fLocalBoundsCompareTypeDirtyBW = true;
858    return fMCRec->fMatrix->preRotate(degrees);
859}
860
861bool SkCanvas::skew(SkScalar sx, SkScalar sy) {
862    fDeviceCMDirty = true;
863    fLocalBoundsCompareTypeDirty = true;
864    fLocalBoundsCompareTypeDirtyBW = true;
865    return fMCRec->fMatrix->preSkew(sx, sy);
866}
867
868bool SkCanvas::concat(const SkMatrix& matrix) {
869    fDeviceCMDirty = true;
870    fLocalBoundsCompareTypeDirty = true;
871    fLocalBoundsCompareTypeDirtyBW = true;
872    return fMCRec->fMatrix->preConcat(matrix);
873}
874
875void SkCanvas::setMatrix(const SkMatrix& matrix) {
876    fDeviceCMDirty = true;
877    fLocalBoundsCompareTypeDirty = true;
878    fLocalBoundsCompareTypeDirtyBW = true;
879    *fMCRec->fMatrix = matrix;
880}
881
882// this is not virtual, so it must call a virtual method so that subclasses
883// will see its action
884void SkCanvas::resetMatrix() {
885    SkMatrix matrix;
886
887    matrix.reset();
888    this->setMatrix(matrix);
889}
890
891//////////////////////////////////////////////////////////////////////////////
892
893bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
894    AutoValidateClip avc(this);
895
896    fDeviceCMDirty = true;
897    fLocalBoundsCompareTypeDirty = true;
898    fLocalBoundsCompareTypeDirtyBW = true;
899
900    if (fMCRec->fMatrix->rectStaysRect()) {
901        // for these simpler matrices, we can stay a rect ever after applying
902        // the matrix. This means we don't have to a) make a path, and b) tell
903        // the region code to scan-convert the path, only to discover that it
904        // is really just a rect.
905        SkRect      r;
906        SkIRect     ir;
907
908        fMCRec->fMatrix->mapRect(&r, rect);
909        fClipStack.clipDevRect(r, op);
910        r.round(&ir);
911        return fMCRec->fRegion->op(ir, op);
912    } else {
913        // since we're rotate or some such thing, we convert the rect to a path
914        // and clip against that, since it can handle any matrix. However, to
915        // avoid recursion in the case where we are subclassed (e.g. Pictures)
916        // we explicitly call "our" version of clipPath.
917        SkPath  path;
918
919        path.addRect(rect);
920        return this->SkCanvas::clipPath(path, op);
921    }
922}
923
924static bool clipPathHelper(const SkCanvas* canvas, SkRegion* currRgn,
925                           const SkPath& devPath, SkRegion::Op op) {
926    // base is used to limit the size (and therefore memory allocation) of the
927    // region that results from scan converting devPath.
928    SkRegion base;
929
930    if (SkRegion::kIntersect_Op == op) {
931        // since we are intersect, we can do better (tighter) with currRgn's
932        // bounds, than just using the device. However, if currRgn is complex,
933        // our region blitter may hork, so we do that case in two steps.
934        if (currRgn->isRect()) {
935            return currRgn->setPath(devPath, *currRgn);
936        } else {
937            base.setRect(currRgn->getBounds());
938            SkRegion rgn;
939            rgn.setPath(devPath, base);
940            return currRgn->op(rgn, op);
941        }
942    } else {
943        const SkBitmap& bm = canvas->getDevice()->accessBitmap(false);
944        base.setRect(0, 0, bm.width(), bm.height());
945
946        if (SkRegion::kReplace_Op == op) {
947            return currRgn->setPath(devPath, base);
948        } else {
949            SkRegion rgn;
950            rgn.setPath(devPath, base);
951            return currRgn->op(rgn, op);
952        }
953    }
954}
955
956bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op) {
957    AutoValidateClip avc(this);
958
959    fDeviceCMDirty = true;
960    fLocalBoundsCompareTypeDirty = true;
961    fLocalBoundsCompareTypeDirtyBW = true;
962
963    SkPath devPath;
964    path.transform(*fMCRec->fMatrix, &devPath);
965
966    // if we called path.swap() we could avoid a deep copy of this path
967    fClipStack.clipDevPath(devPath, op);
968
969    return clipPathHelper(this, fMCRec->fRegion, devPath, op);
970}
971
972bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
973    AutoValidateClip avc(this);
974
975    fDeviceCMDirty = true;
976    fLocalBoundsCompareTypeDirty = true;
977    fLocalBoundsCompareTypeDirtyBW = true;
978
979    // todo: signal fClipStack that we have a region, and therefore (I guess)
980    // we have to ignore it, and use the region directly?
981    fClipStack.clipDevRect(rgn.getBounds());
982
983    return fMCRec->fRegion->op(rgn, op);
984}
985
986#ifdef SK_DEBUG
987void SkCanvas::validateClip() const {
988    // construct clipRgn from the clipstack
989    const SkDevice* device = this->getDevice();
990    SkIRect ir;
991    ir.set(0, 0, device->width(), device->height());
992    SkRegion clipRgn(ir);
993
994    SkClipStack::B2FIter                iter(fClipStack);
995    const SkClipStack::B2FIter::Clip*   clip;
996    while ((clip = iter.next()) != NULL) {
997        if (clip->fPath) {
998            clipPathHelper(this, &clipRgn, *clip->fPath, clip->fOp);
999        } else if (clip->fRect) {
1000            clip->fRect->round(&ir);
1001            clipRgn.op(ir, clip->fOp);
1002        } else {
1003            clipRgn.setEmpty();
1004        }
1005    }
1006
1007#if 0   // enable this locally for testing
1008    // now compare against the current rgn
1009    const SkRegion& rgn = this->getTotalClip();
1010    SkASSERT(rgn == clipRgn);
1011#endif
1012}
1013#endif
1014
1015///////////////////////////////////////////////////////////////////////////////
1016
1017void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const {
1018    SkRect r;
1019    SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType :
1020            fLocalBoundsCompareTypeBW;
1021
1022    if (!this->getClipBounds(&r, et)) {
1023        rCompare.setEmpty();
1024    } else {
1025        rCompare.set(SkScalarToCompareType(r.fLeft),
1026                     SkScalarToCompareType(r.fTop),
1027                     SkScalarToCompareType(r.fRight),
1028                     SkScalarToCompareType(r.fBottom));
1029    }
1030}
1031
1032/*  current impl ignores edgetype, and relies on
1033    getLocalClipBoundsCompareType(), which always returns a value assuming
1034    antialiasing (worst case)
1035 */
1036bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const {
1037
1038    if (!rect.hasValidCoordinates())
1039        return true;
1040
1041    if (fMCRec->fRegion->isEmpty()) {
1042        return true;
1043    }
1044
1045    if (fMCRec->fMatrix->hasPerspective()) {
1046        SkRect dst;
1047        fMCRec->fMatrix->mapRect(&dst, rect);
1048        SkIRect idst;
1049        dst.roundOut(&idst);
1050        return !SkIRect::Intersects(idst, fMCRec->fRegion->getBounds());
1051    } else {
1052        const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et);
1053
1054        // for speed, do the most likely reject compares first
1055        SkScalarCompareType userT = SkScalarToCompareType(rect.fTop);
1056        SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom);
1057        if (userT >= clipR.fBottom || userB <= clipR.fTop) {
1058            return true;
1059        }
1060        SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft);
1061        SkScalarCompareType userR = SkScalarToCompareType(rect.fRight);
1062        if (userL >= clipR.fRight || userR <= clipR.fLeft) {
1063            return true;
1064        }
1065        return false;
1066    }
1067}
1068
1069bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const {
1070    return path.isEmpty() || this->quickReject(path.getBounds(), et);
1071}
1072
1073bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const {
1074    /*  current impl ignores edgetype, and relies on
1075        getLocalClipBoundsCompareType(), which always returns a value assuming
1076        antialiasing (worst case)
1077     */
1078
1079    if (fMCRec->fRegion->isEmpty()) {
1080        return true;
1081    }
1082
1083    SkScalarCompareType userT = SkScalarToCompareType(top);
1084    SkScalarCompareType userB = SkScalarToCompareType(bottom);
1085
1086    // check for invalid user Y coordinates (i.e. empty)
1087    // reed: why do we need to do this check, since it slows us down?
1088    if (userT >= userB) {
1089        return true;
1090    }
1091
1092    // check if we are above or below the local clip bounds
1093    const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType();
1094    return userT >= clipR.fBottom || userB <= clipR.fTop;
1095}
1096
1097bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const {
1098    const SkRegion& clip = *fMCRec->fRegion;
1099    if (clip.isEmpty()) {
1100        if (bounds) {
1101            bounds->setEmpty();
1102        }
1103        return false;
1104    }
1105
1106    SkMatrix inverse;
1107    // if we can't invert the CTM, we can't return local clip bounds
1108    if (!fMCRec->fMatrix->invert(&inverse)) {
1109        if (bounds) {
1110            bounds->setEmpty();
1111        }
1112        return false;
1113    }
1114
1115    if (NULL != bounds) {
1116        SkRect   r;
1117        // get the clip's bounds
1118        const SkIRect& ibounds = clip.getBounds();
1119        // adjust it outwards if we are antialiasing
1120        int inset = (kAA_EdgeType == et);
1121        r.iset(ibounds.fLeft - inset,  ibounds.fTop - inset,
1122               ibounds.fRight + inset, ibounds.fBottom + inset);
1123
1124        // invert into local coordinates
1125        inverse.mapRect(bounds, r);
1126    }
1127    return true;
1128}
1129
1130const SkMatrix& SkCanvas::getTotalMatrix() const {
1131    return *fMCRec->fMatrix;
1132}
1133
1134const SkRegion& SkCanvas::getTotalClip() const {
1135    return *fMCRec->fRegion;
1136}
1137
1138const SkClipStack& SkCanvas::getTotalClipStack() const {
1139    return fClipStack;
1140}
1141
1142void SkCanvas::setExternalMatrix(const SkMatrix* matrix) {
1143    if (NULL == matrix || matrix->isIdentity()) {
1144        if (fUseExternalMatrix) {
1145            fDeviceCMDirty = true;
1146        }
1147        fUseExternalMatrix = false;
1148    } else {
1149        fUseExternalMatrix = true;
1150        fDeviceCMDirty = true;  // |= (fExternalMatrix != *matrix)
1151
1152        fExternalMatrix = *matrix;
1153        matrix->invert(&fExternalInverse);
1154    }
1155}
1156
1157SkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config,
1158                                      int width, int height,
1159                                      bool isOpaque) {
1160    SkDevice* device = this->getTopDevice();
1161    if (device) {
1162        return device->createCompatibleDeviceForSaveLayer(config, width, height,
1163                                                          isOpaque);
1164    } else {
1165        return NULL;
1166    }
1167}
1168
1169SkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config,
1170                                           int width, int height,
1171                                           bool isOpaque) {
1172    SkDevice* device = this->getDevice();
1173    if (device) {
1174        return device->createCompatibleDevice(config, width, height, isOpaque);
1175    } else {
1176        return NULL;
1177    }
1178}
1179
1180
1181//////////////////////////////////////////////////////////////////////////////
1182//  These are the virtual drawing methods
1183//////////////////////////////////////////////////////////////////////////////
1184
1185void SkCanvas::clear(SkColor color) {
1186    SkDrawIter  iter(this);
1187
1188    while (iter.next()) {
1189        iter.fDevice->clear(color);
1190    }
1191}
1192
1193void SkCanvas::drawPaint(const SkPaint& paint) {
1194    LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type)
1195
1196    while (iter.next()) {
1197        iter.fDevice->drawPaint(iter, looper.paint());
1198    }
1199
1200    LOOPER_END
1201}
1202
1203void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
1204                          const SkPaint& paint) {
1205    if ((long)count <= 0) {
1206        return;
1207    }
1208
1209    SkASSERT(pts != NULL);
1210
1211    LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type)
1212
1213    while (iter.next()) {
1214        iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
1215    }
1216
1217    LOOPER_END
1218}
1219
1220void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1221    if (paint.canComputeFastBounds()) {
1222        SkRect storage;
1223        if (this->quickReject(paint.computeFastBounds(r, &storage),
1224                              paint2EdgeType(&paint))) {
1225            return;
1226        }
1227    }
1228
1229    LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type)
1230
1231    while (iter.next()) {
1232        iter.fDevice->drawRect(iter, r, looper.paint());
1233    }
1234
1235    LOOPER_END
1236}
1237
1238void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1239    if (paint.canComputeFastBounds()) {
1240        SkRect storage;
1241        const SkRect& bounds = path.getBounds();
1242        if (this->quickReject(paint.computeFastBounds(bounds, &storage),
1243                              paint2EdgeType(&paint))) {
1244            return;
1245        }
1246    }
1247
1248    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
1249
1250    while (iter.next()) {
1251        iter.fDevice->drawPath(iter, path, looper.paint());
1252    }
1253
1254    LOOPER_END
1255}
1256
1257void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
1258                          const SkPaint* paint) {
1259    SkDEBUGCODE(bitmap.validate();)
1260
1261    if (NULL == paint || (paint->getMaskFilter() == NULL)) {
1262        SkRect fastBounds;
1263        fastBounds.set(x, y,
1264                       x + SkIntToScalar(bitmap.width()),
1265                       y + SkIntToScalar(bitmap.height()));
1266        if (this->quickReject(fastBounds, paint2EdgeType(paint))) {
1267            return;
1268        }
1269    }
1270
1271    SkMatrix matrix;
1272    matrix.setTranslate(x, y);
1273    this->internalDrawBitmap(bitmap, NULL, matrix, paint);
1274}
1275
1276void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
1277                              const SkRect& dst, const SkPaint* paint) {
1278    if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) {
1279        return;
1280    }
1281
1282    // do this now, to avoid the cost of calling extract for RLE bitmaps
1283    if (this->quickReject(dst, paint2EdgeType(paint))) {
1284        return;
1285    }
1286
1287    const SkBitmap* bitmapPtr = &bitmap;
1288
1289    SkMatrix matrix;
1290    SkRect tmpSrc;
1291    if (src) {
1292        tmpSrc.set(*src);
1293        // if the extract process clipped off the top or left of the
1294        // original, we adjust for that here to get the position right.
1295        if (tmpSrc.fLeft > 0) {
1296            tmpSrc.fRight -= tmpSrc.fLeft;
1297            tmpSrc.fLeft = 0;
1298        }
1299        if (tmpSrc.fTop > 0) {
1300            tmpSrc.fBottom -= tmpSrc.fTop;
1301            tmpSrc.fTop = 0;
1302        }
1303    } else {
1304        tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()),
1305                   SkIntToScalar(bitmap.height()));
1306    }
1307    matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
1308
1309    // ensure that src is "valid" before we pass it to our internal routines
1310    // and to SkDevice. i.e. sure it is contained inside the original bitmap.
1311    SkIRect tmpISrc;
1312    if (src) {
1313        tmpISrc.set(0, 0, bitmap.width(), bitmap.height());
1314        if (!tmpISrc.intersect(*src)) {
1315            return;
1316        }
1317        src = &tmpISrc;
1318    }
1319    this->internalDrawBitmap(*bitmapPtr, src, matrix, paint);
1320}
1321
1322void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
1323                                const SkPaint* paint) {
1324    SkDEBUGCODE(bitmap.validate();)
1325    this->internalDrawBitmap(bitmap, NULL, matrix, paint);
1326}
1327
1328void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
1329                                const SkMatrix& matrix, const SkPaint& paint) {
1330    SkDEBUGCODE(bitmap.validate();)
1331
1332    LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type)
1333
1334    while (iter.next()) {
1335        iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint());
1336    }
1337
1338    LOOPER_END
1339}
1340
1341void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
1342                          const SkPaint* paint) {
1343    SkDEBUGCODE(bitmap.validate();)
1344
1345    if (reject_bitmap(bitmap)) {
1346        return;
1347    }
1348
1349    SkPaint tmp;
1350    if (NULL == paint) {
1351        paint = &tmp;
1352    }
1353
1354    LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
1355
1356    while (iter.next()) {
1357        iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(),
1358                                 looper.paint());
1359    }
1360    LOOPER_END
1361}
1362
1363class SkDeviceFilteredPaint {
1364public:
1365    SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) {
1366        SkDevice::TextFlags flags;
1367        if (device->filterTextFlags(paint, &flags)) {
1368            SkPaint* newPaint = fLazy.set(paint);
1369            newPaint->setFlags(flags.fFlags);
1370            newPaint->setHinting(flags.fHinting);
1371            fPaint = newPaint;
1372        } else {
1373            fPaint = &paint;
1374        }
1375    }
1376
1377    const SkPaint& paint() const { return *fPaint; }
1378
1379private:
1380    const SkPaint*  fPaint;
1381    SkLazyPaint     fLazy;
1382};
1383
1384void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
1385                        const SkRect& r, SkScalar textSize) {
1386    if (paint.getStyle() == SkPaint::kFill_Style) {
1387        draw.fDevice->drawRect(draw, r, paint);
1388    } else {
1389        SkPaint p(paint);
1390        p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
1391        draw.fDevice->drawRect(draw, r, p);
1392    }
1393}
1394
1395void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
1396                                   const char text[], size_t byteLength,
1397                                   SkScalar x, SkScalar y) {
1398    SkASSERT(byteLength == 0 || text != NULL);
1399
1400    // nothing to draw
1401    if (text == NULL || byteLength == 0 ||
1402        draw.fClip->isEmpty() ||
1403        (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
1404        return;
1405    }
1406
1407    SkScalar    width = 0;
1408    SkPoint     start;
1409
1410    start.set(0, 0);    // to avoid warning
1411    if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
1412                            SkPaint::kStrikeThruText_Flag)) {
1413        width = paint.measureText(text, byteLength);
1414
1415        SkScalar offsetX = 0;
1416        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
1417            offsetX = SkScalarHalf(width);
1418        } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
1419            offsetX = width;
1420        }
1421        start.set(x - offsetX, y);
1422    }
1423
1424    if (0 == width) {
1425        return;
1426    }
1427
1428    uint32_t flags = paint.getFlags();
1429
1430    if (flags & (SkPaint::kUnderlineText_Flag |
1431                 SkPaint::kStrikeThruText_Flag)) {
1432        SkScalar textSize = paint.getTextSize();
1433        SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
1434        SkRect   r;
1435
1436        r.fLeft = start.fX;
1437        r.fRight = start.fX + width;
1438
1439        if (flags & SkPaint::kUnderlineText_Flag) {
1440            SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
1441                                             start.fY);
1442            r.fTop = offset;
1443            r.fBottom = offset + height;
1444            DrawRect(draw, paint, r, textSize);
1445        }
1446        if (flags & SkPaint::kStrikeThruText_Flag) {
1447            SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
1448                                             start.fY);
1449            r.fTop = offset;
1450            r.fBottom = offset + height;
1451            DrawRect(draw, paint, r, textSize);
1452        }
1453    }
1454}
1455
1456void SkCanvas::drawText(const void* text, size_t byteLength,
1457                        SkScalar x, SkScalar y, const SkPaint& paint) {
1458    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1459
1460    while (iter.next()) {
1461        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1462        iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
1463        DrawTextDecorations(iter, dfp.paint(),
1464                            static_cast<const char*>(text), byteLength, x, y);
1465    }
1466
1467    LOOPER_END
1468}
1469
1470void SkCanvas::drawPosText(const void* text, size_t byteLength,
1471                           const SkPoint pos[], const SkPaint& paint) {
1472    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1473
1474    while (iter.next()) {
1475        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1476        iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
1477                                  dfp.paint());
1478    }
1479
1480    LOOPER_END
1481}
1482
1483void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
1484                            const SkScalar xpos[], SkScalar constY,
1485                            const SkPaint& paint) {
1486    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1487
1488    while (iter.next()) {
1489        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1490        iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
1491                                  dfp.paint());
1492    }
1493
1494    LOOPER_END
1495}
1496
1497void SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
1498                              const SkPath& path, const SkMatrix* matrix,
1499                              const SkPaint& paint) {
1500    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1501
1502    while (iter.next()) {
1503        iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
1504                                     matrix, looper.paint());
1505    }
1506
1507    LOOPER_END
1508}
1509
1510#ifdef ANDROID
1511void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength,
1512                                 const SkPoint pos[], const SkPaint& paint,
1513                                 const SkPath& path, const SkMatrix* matrix) {
1514
1515    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1516
1517    while (iter.next()) {
1518        iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos,
1519                                        looper.paint(), path, matrix);
1520    }
1521
1522    LOOPER_END
1523}
1524#endif
1525
1526void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
1527                            const SkPoint verts[], const SkPoint texs[],
1528                            const SkColor colors[], SkXfermode* xmode,
1529                            const uint16_t indices[], int indexCount,
1530                            const SkPaint& paint) {
1531    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
1532
1533    while (iter.next()) {
1534        iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
1535                                   colors, xmode, indices, indexCount,
1536                                   looper.paint());
1537    }
1538
1539    LOOPER_END
1540}
1541
1542void SkCanvas::drawData(const void* data, size_t length) {
1543    // do nothing. Subclasses may do something with the data
1544}
1545
1546//////////////////////////////////////////////////////////////////////////////
1547// These methods are NOT virtual, and therefore must call back into virtual
1548// methods, rather than actually drawing themselves.
1549//////////////////////////////////////////////////////////////////////////////
1550
1551void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
1552                        SkXfermode::Mode mode) {
1553    SkPaint paint;
1554
1555    paint.setARGB(a, r, g, b);
1556    if (SkXfermode::kSrcOver_Mode != mode) {
1557        paint.setXfermodeMode(mode);
1558    }
1559    this->drawPaint(paint);
1560}
1561
1562void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
1563    SkPaint paint;
1564
1565    paint.setColor(c);
1566    if (SkXfermode::kSrcOver_Mode != mode) {
1567        paint.setXfermodeMode(mode);
1568    }
1569    this->drawPaint(paint);
1570}
1571
1572void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
1573    SkPoint pt;
1574
1575    pt.set(x, y);
1576    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1577}
1578
1579void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
1580    SkPoint pt;
1581    SkPaint paint;
1582
1583    pt.set(x, y);
1584    paint.setColor(color);
1585    this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1586}
1587
1588void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
1589                        const SkPaint& paint) {
1590    SkPoint pts[2];
1591
1592    pts[0].set(x0, y0);
1593    pts[1].set(x1, y1);
1594    this->drawPoints(kLines_PointMode, 2, pts, paint);
1595}
1596
1597void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
1598                              SkScalar right, SkScalar bottom,
1599                              const SkPaint& paint) {
1600    SkRect  r;
1601
1602    r.set(left, top, right, bottom);
1603    this->drawRect(r, paint);
1604}
1605
1606void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
1607                          const SkPaint& paint) {
1608    if (radius < 0) {
1609        radius = 0;
1610    }
1611
1612    SkRect  r;
1613    r.set(cx - radius, cy - radius, cx + radius, cy + radius);
1614
1615    if (paint.canComputeFastBounds()) {
1616        SkRect storage;
1617        if (this->quickReject(paint.computeFastBounds(r, &storage),
1618                              paint2EdgeType(&paint))) {
1619            return;
1620        }
1621    }
1622
1623    SkPath  path;
1624    path.addOval(r);
1625    this->drawPath(path, paint);
1626}
1627
1628void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
1629                             const SkPaint& paint) {
1630    if (rx > 0 && ry > 0) {
1631        if (paint.canComputeFastBounds()) {
1632            SkRect storage;
1633            if (this->quickReject(paint.computeFastBounds(r, &storage),
1634                                  paint2EdgeType(&paint))) {
1635                return;
1636            }
1637        }
1638
1639        SkPath  path;
1640        path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
1641        this->drawPath(path, paint);
1642    } else {
1643        this->drawRect(r, paint);
1644    }
1645}
1646
1647void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
1648    if (paint.canComputeFastBounds()) {
1649        SkRect storage;
1650        if (this->quickReject(paint.computeFastBounds(oval, &storage),
1651                              paint2EdgeType(&paint))) {
1652            return;
1653        }
1654    }
1655
1656    SkPath  path;
1657    path.addOval(oval);
1658    this->drawPath(path, paint);
1659}
1660
1661void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
1662                       SkScalar sweepAngle, bool useCenter,
1663                       const SkPaint& paint) {
1664    if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
1665        this->drawOval(oval, paint);
1666    } else {
1667        SkPath  path;
1668        if (useCenter) {
1669            path.moveTo(oval.centerX(), oval.centerY());
1670        }
1671        path.arcTo(oval, startAngle, sweepAngle, !useCenter);
1672        if (useCenter) {
1673            path.close();
1674        }
1675        this->drawPath(path, paint);
1676    }
1677}
1678
1679void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
1680                                const SkPath& path, SkScalar hOffset,
1681                                SkScalar vOffset, const SkPaint& paint) {
1682    SkMatrix    matrix;
1683
1684    matrix.setTranslate(hOffset, vOffset);
1685    this->drawTextOnPath(text, byteLength, path, &matrix, paint);
1686}
1687
1688///////////////////////////////////////////////////////////////////////////////
1689
1690void SkCanvas::drawPicture(SkPicture& picture) {
1691    int saveCount = save();
1692    picture.draw(this);
1693    restoreToCount(saveCount);
1694}
1695
1696///////////////////////////////////////////////////////////////////////////////
1697///////////////////////////////////////////////////////////////////////////////
1698
1699SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
1700    SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
1701
1702    SkASSERT(canvas);
1703
1704    fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
1705    fDone = !fImpl->next();
1706}
1707
1708SkCanvas::LayerIter::~LayerIter() {
1709    fImpl->~SkDrawIter();
1710}
1711
1712void SkCanvas::LayerIter::next() {
1713    fDone = !fImpl->next();
1714}
1715
1716SkDevice* SkCanvas::LayerIter::device() const {
1717    return fImpl->getDevice();
1718}
1719
1720const SkMatrix& SkCanvas::LayerIter::matrix() const {
1721    return fImpl->getMatrix();
1722}
1723
1724const SkPaint& SkCanvas::LayerIter::paint() const {
1725    const SkPaint* paint = fImpl->getPaint();
1726    if (NULL == paint) {
1727        paint = &fDefaultPaint;
1728    }
1729    return *paint;
1730}
1731
1732const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
1733int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
1734int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
1735