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