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