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