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