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