• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006-2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "SkCanvas.h"
18 #include "SkBounder.h"
19 #include "SkDevice.h"
20 #include "SkDraw.h"
21 #include "SkDrawFilter.h"
22 #include "SkDrawLooper.h"
23 #include "SkPicture.h"
24 #include "SkScalarCompare.h"
25 #include "SkShape.h"
26 #include "SkTemplates.h"
27 #include "SkUtils.h"
28 #include <new>
29 
30 //#define SK_TRACE_SAVERESTORE
31 
32 #ifdef SK_TRACE_SAVERESTORE
33     static int gLayerCounter;
inc_layer()34     static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
dec_layer()35     static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
36 
37     static int gRecCounter;
inc_rec()38     static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
dec_rec()39     static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
40 
41     static int gCanvasCounter;
inc_canvas()42     static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
dec_canvas()43     static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
44 #else
45     #define inc_layer()
46     #define dec_layer()
47     #define inc_rec()
48     #define dec_rec()
49     #define inc_canvas()
50     #define dec_canvas()
51 #endif
52 
53 ///////////////////////////////////////////////////////////////////////////////
54 // Helpers for computing fast bounds for quickReject tests
55 
paint2EdgeType(const SkPaint * paint)56 static SkCanvas::EdgeType paint2EdgeType(const SkPaint* paint) {
57     return paint != NULL && paint->isAntiAlias() ?
58             SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType;
59 }
60 
61 ///////////////////////////////////////////////////////////////////////////////
62 
63 /*  This is the record we keep for each SkDevice that the user installs.
64     The clip/matrix/proc are fields that reflect the top of the save/restore
65     stack. Whenever the canvas changes, it marks a dirty flag, and then before
66     these are used (assuming we're not on a layer) we rebuild these cache
67     values: they reflect the top of the save stack, but translated and clipped
68     by the device's XY offset and bitmap-bounds.
69 */
70 struct DeviceCM {
71     DeviceCM*           fNext;
72     SkDevice*           fDevice;
73     SkRegion            fClip;
74     const SkMatrix*     fMatrix;
75 	SkPaint*			fPaint;	// may be null (in the future)
76     int16_t             fX, fY; // relative to base matrix/clip
77 
DeviceCMDeviceCM78 	DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint)
79             : fNext(NULL) {
80         if (NULL != device) {
81             device->ref();
82             device->lockPixels();
83         }
84         fDevice = device;
85         fX = SkToS16(x);
86         fY = SkToS16(y);
87         fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
88 	}
89 
~DeviceCMDeviceCM90 	~DeviceCM() {
91         if (NULL != fDevice) {
92             fDevice->unlockPixels();
93             fDevice->unref();
94         }
95 		SkDELETE(fPaint);
96 	}
97 
updateMCDeviceCM98     void updateMC(const SkMatrix& totalMatrix, const SkRegion& totalClip,
99                   SkRegion* updateClip) {
100         int x = fX;
101         int y = fY;
102         int width = fDevice->width();
103         int height = fDevice->height();
104 
105         if ((x | y) == 0) {
106             fMatrix = &totalMatrix;
107             fClip = totalClip;
108         } else {
109             fMatrixStorage = totalMatrix;
110             fMatrixStorage.postTranslate(SkIntToScalar(-x),
111                                          SkIntToScalar(-y));
112             fMatrix = &fMatrixStorage;
113 
114             totalClip.translate(-x, -y, &fClip);
115         }
116 
117         fClip.op(0, 0, width, height, SkRegion::kIntersect_Op);
118 
119         // intersect clip, but don't translate it (yet)
120 
121         if (updateClip) {
122             updateClip->op(x, y, x + width, y + height,
123                            SkRegion::kDifference_Op);
124         }
125 
126         fDevice->setMatrixClip(*fMatrix, fClip);
127 
128 #ifdef SK_DEBUG
129         if (!fClip.isEmpty()) {
130             SkIRect deviceR;
131             deviceR.set(0, 0, width, height);
132             SkASSERT(deviceR.contains(fClip.getBounds()));
133         }
134 #endif
135     }
136 
translateClipDeviceCM137     void translateClip() {
138         if (fX | fY) {
139             fClip.translate(fX, fY);
140         }
141     }
142 
143 private:
144     SkMatrix    fMatrixStorage;
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 */
154 class SkCanvas::MCRec {
155 public:
156     MCRec*          fNext;
157     SkMatrix*       fMatrix;    // points to either fMatrixStorage or prev MCRec
158     SkRegion*       fRegion;    // 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 
MCRec(const MCRec * prev,int flags)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                 fRegionStorage = *prev->fRegion;
181                 fRegion = &fRegionStorage;
182             } else {
183                 fRegion = prev->fRegion;
184             }
185 
186             fFilter = prev->fFilter;
187             fFilter->safeRef();
188 
189             fTopLayer = prev->fTopLayer;
190         } else {   // no prev
191             fMatrixStorage.reset();
192 
193             fMatrix     = &fMatrixStorage;
194             fRegion     = &fRegionStorage;
195             fFilter     = NULL;
196             fTopLayer   = NULL;
197         }
198         fLayer = NULL;
199 
200         // don't bother initializing fNext
201         inc_rec();
202     }
~MCRec()203     ~MCRec() {
204         fFilter->safeUnref();
205         SkDELETE(fLayer);
206         dec_rec();
207     }
208 
209 private:
210     SkMatrix    fMatrixStorage;
211     SkRegion    fRegionStorage;
212 };
213 
214 class SkDrawIter : public SkDraw {
215 public:
SkDrawIter(SkCanvas * canvas,bool skipEmptyClips=true)216     SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
217         fCanvas = canvas;
218         canvas->updateDeviceCMCache();
219 
220         fBounder = canvas->getBounder();
221         fCurrLayer = canvas->fMCRec->fTopLayer;
222         fSkipEmptyClips = skipEmptyClips;
223     }
224 
next()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             fLayerX = rec->fX;
241             fLayerY = rec->fY;
242             fPaint  = rec->fPaint;
243             SkDEBUGCODE(this->validate();)
244 
245             fCurrLayer = rec->fNext;
246             if (fBounder) {
247                 fBounder->setClip(fClip);
248             }
249 
250             // fCurrLayer may be NULL now
251 
252             fCanvas->prepareForDeviceDraw(fDevice);
253             return true;
254         }
255         return false;
256     }
257 
getX() const258     int getX() const { return fLayerX; }
getY() const259     int getY() const { return fLayerY; }
getDevice() const260     SkDevice* getDevice() const { return fDevice; }
getMatrix() const261     const SkMatrix& getMatrix() const { return *fMatrix; }
getClip() const262     const SkRegion& getClip() const { return *fClip; }
getPaint() const263     const SkPaint* getPaint() const { return fPaint; }
264 private:
265     SkCanvas*       fCanvas;
266     const DeviceCM* fCurrLayer;
267     const SkPaint*  fPaint;     // May be null.
268     int             fLayerX;
269     int             fLayerY;
270     SkBool8         fSkipEmptyClips;
271 
272     typedef SkDraw INHERITED;
273 };
274 
275 /////////////////////////////////////////////////////////////////////////////
276 
277 class AutoDrawLooper {
278 public:
AutoDrawLooper(SkCanvas * canvas,const SkPaint & paint,SkDrawFilter::Type t)279     AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, SkDrawFilter::Type t)
280             : fCanvas(canvas), fPaint((SkPaint*)&paint), fType(t) {
281         if ((fLooper = paint.getLooper()) != NULL) {
282             fLooper->init(canvas, (SkPaint*)&paint);
283         } else {
284             fOnce = true;
285         }
286         fFilter = canvas->getDrawFilter();
287         fNeedFilterRestore = false;
288     }
289 
~AutoDrawLooper()290     ~AutoDrawLooper() {
291         if (fNeedFilterRestore) {
292             SkASSERT(fFilter);
293             fFilter->restore(fCanvas, fPaint, fType);
294         }
295         if (NULL != fLooper) {
296             fLooper->restore();
297         }
298     }
299 
next()300     bool next() {
301         SkDrawFilter* filter = fFilter;
302 
303         // if we drew earlier with a filter, then we need to restore first
304         if (fNeedFilterRestore) {
305             SkASSERT(filter);
306             filter->restore(fCanvas, fPaint, fType);
307             fNeedFilterRestore = false;
308         }
309 
310         bool result;
311 
312         if (NULL != fLooper) {
313             result = fLooper->next();
314         } else {
315             result = fOnce;
316             fOnce = false;
317         }
318 
319         // if we're gonna draw, give the filter a chance to do its work
320         if (result && NULL != filter) {
321             fNeedFilterRestore = result = filter->filter(fCanvas, fPaint,
322                                                          fType);
323         }
324         return result;
325     }
326 
327 private:
328     SkDrawLooper*   fLooper;
329     SkDrawFilter*   fFilter;
330     SkCanvas*       fCanvas;
331     SkPaint*        fPaint;
332     SkDrawFilter::Type  fType;
333     bool            fOnce;
334     bool            fNeedFilterRestore;
335 
336 };
337 
338 /*  Stack helper for managing a SkBounder. In the destructor, if we were
339     given a bounder, we call its commit() method, signifying that we are
340     done accumulating bounds for that draw.
341 */
342 class SkAutoBounderCommit {
343 public:
SkAutoBounderCommit(SkBounder * bounder)344     SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {}
~SkAutoBounderCommit()345     ~SkAutoBounderCommit() {
346         if (NULL != fBounder) {
347             fBounder->commit();
348         }
349     }
350 private:
351     SkBounder*  fBounder;
352 };
353 
354 #include "SkColorPriv.h"
355 
356 class AutoValidator {
357 public:
AutoValidator(SkDevice * device)358     AutoValidator(SkDevice* device) : fDevice(device) {}
~AutoValidator()359     ~AutoValidator() {
360 #ifdef SK_DEBUG
361         const SkBitmap& bm = fDevice->accessBitmap(false);
362         if (bm.config() == SkBitmap::kARGB_4444_Config) {
363             for (int y = 0; y < bm.height(); y++) {
364                 const SkPMColor16* p = bm.getAddr16(0, y);
365                 for (int x = 0; x < bm.width(); x++) {
366                     SkPMColor16 c = p[x];
367                     SkPMColor16Assert(c);
368                 }
369             }
370         }
371 #endif
372     }
373 private:
374     SkDevice* fDevice;
375 };
376 
377 ////////// macros to place around the internal draw calls //////////////////
378 
379 #define ITER_BEGIN(paint, type)                                     \
380 /*    AutoValidator   validator(fMCRec->fTopLayer->fDevice); */     \
381     AutoDrawLooper  looper(this, paint, type);                      \
382     while (looper.next()) {                                         \
383         SkAutoBounderCommit ac(fBounder);                           \
384         SkDrawIter          iter(this);
385 
386 #define ITER_END    }
387 
388 ////////////////////////////////////////////////////////////////////////////
389 
init(SkDevice * device)390 SkDevice* SkCanvas::init(SkDevice* device) {
391     fBounder = NULL;
392     fLocalBoundsCompareTypeDirty = true;
393     fLastDeviceToGainFocus = NULL;
394 
395     fMCRec = (MCRec*)fMCStack.push_back();
396     new (fMCRec) MCRec(NULL, 0);
397 
398     fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL));
399     fMCRec->fTopLayer = fMCRec->fLayer;
400     fMCRec->fNext = NULL;
401 
402     return this->setDevice(device);
403 }
404 
SkCanvas(SkDevice * device)405 SkCanvas::SkCanvas(SkDevice* device)
406         : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
407     inc_canvas();
408 
409     this->init(device);
410 }
411 
SkCanvas(const SkBitmap & bitmap)412 SkCanvas::SkCanvas(const SkBitmap& bitmap)
413         : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
414     inc_canvas();
415 
416     this->init(SkNEW_ARGS(SkDevice, (bitmap)))->unref();
417 }
418 
~SkCanvas()419 SkCanvas::~SkCanvas() {
420     // free up the contents of our deque
421     this->restoreToCount(1);    // restore everything but the last
422     this->internalRestore();    // restore the last, since we're going away
423 
424     fBounder->safeUnref();
425 
426     dec_canvas();
427 }
428 
setBounder(SkBounder * bounder)429 SkBounder* SkCanvas::setBounder(SkBounder* bounder) {
430     SkRefCnt_SafeAssign(fBounder, bounder);
431     return bounder;
432 }
433 
getDrawFilter() const434 SkDrawFilter* SkCanvas::getDrawFilter() const {
435     return fMCRec->fFilter;
436 }
437 
setDrawFilter(SkDrawFilter * filter)438 SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
439     SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
440     return filter;
441 }
442 
443 ///////////////////////////////////////////////////////////////////////////////
444 
getDevice() const445 SkDevice* SkCanvas::getDevice() const {
446     // return root device
447     SkDeque::Iter   iter(fMCStack);
448     MCRec*          rec = (MCRec*)iter.next();
449     SkASSERT(rec && rec->fLayer);
450     return rec->fLayer->fDevice;
451 }
452 
setDevice(SkDevice * device)453 SkDevice* SkCanvas::setDevice(SkDevice* device) {
454     // return root device
455     SkDeque::Iter   iter(fMCStack);
456     MCRec*          rec = (MCRec*)iter.next();
457     SkASSERT(rec && rec->fLayer);
458     SkDevice*       rootDevice = rec->fLayer->fDevice;
459 
460     if (rootDevice == device) {
461         return device;
462     }
463 
464     /* Notify the devices that they are going in/out of scope, so they can do
465        things like lock/unlock their pixels, etc.
466     */
467     if (device) {
468         device->lockPixels();
469     }
470     if (rootDevice) {
471         rootDevice->unlockPixels();
472     }
473 
474     SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
475     rootDevice = device;
476 
477     fDeviceCMDirty = true;
478 
479     /*  Now we update our initial region to have the bounds of the new device,
480         and then intersect all of the clips in our stack with these bounds,
481         to ensure that we can't draw outside of the device's bounds (and trash
482                                                                      memory).
483 
484     NOTE: this is only a partial-fix, since if the new device is larger than
485         the previous one, we don't know how to "enlarge" the clips in our stack,
486         so drawing may be artificially restricted. Without keeping a history of
487         all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
488         reconstruct the correct clips, so this approximation will have to do.
489         The caller really needs to restore() back to the base if they want to
490         accurately take advantage of the new device bounds.
491     */
492 
493     if (NULL == device) {
494         rec->fRegion->setEmpty();
495         while ((rec = (MCRec*)iter.next()) != NULL) {
496             (void)rec->fRegion->setEmpty();
497         }
498     } else {
499         // compute our total bounds for all devices
500         SkIRect bounds;
501 
502         bounds.set(0, 0, device->width(), device->height());
503 
504         // now jam our 1st clip to be bounds, and intersect the rest with that
505         rec->fRegion->setRect(bounds);
506         while ((rec = (MCRec*)iter.next()) != NULL) {
507             (void)rec->fRegion->op(bounds, SkRegion::kIntersect_Op);
508         }
509     }
510     return device;
511 }
512 
setBitmapDevice(const SkBitmap & bitmap)513 SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) {
514     SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap)));
515     device->unref();
516     return device;
517 }
518 
519 //////////////////////////////////////////////////////////////////////////////
520 
getViewport(SkIPoint * size) const521 bool SkCanvas::getViewport(SkIPoint* size) const {
522     return false;
523 }
524 
setViewport(int width,int height)525 bool SkCanvas::setViewport(int width, int height) {
526     return false;
527 }
528 
updateDeviceCMCache()529 void SkCanvas::updateDeviceCMCache() {
530     if (fDeviceCMDirty) {
531         const SkMatrix& totalMatrix = this->getTotalMatrix();
532         const SkRegion& totalClip = this->getTotalClip();
533         DeviceCM*       layer = fMCRec->fTopLayer;
534 
535         if (NULL == layer->fNext) {   // only one layer
536             layer->updateMC(totalMatrix, totalClip, NULL);
537         } else {
538             SkRegion clip;
539             clip = totalClip;  // make a copy
540             do {
541                 layer->updateMC(totalMatrix, clip, &clip);
542             } while ((layer = layer->fNext) != NULL);
543         }
544         fDeviceCMDirty = false;
545     }
546 }
547 
prepareForDeviceDraw(SkDevice * device)548 void SkCanvas::prepareForDeviceDraw(SkDevice* device) {
549     SkASSERT(device);
550     if (fLastDeviceToGainFocus != device) {
551         device->gainFocus(this);
552         fLastDeviceToGainFocus = device;
553     }
554 }
555 
556 ///////////////////////////////////////////////////////////////////////////////
557 
internalSave(SaveFlags flags)558 int SkCanvas::internalSave(SaveFlags flags) {
559     int saveCount = this->getSaveCount(); // record this before the actual save
560 
561     MCRec* newTop = (MCRec*)fMCStack.push_back();
562     new (newTop) MCRec(fMCRec, flags);    // balanced in restore()
563 
564     newTop->fNext = fMCRec;
565     fMCRec = newTop;
566 
567     return saveCount;
568 }
569 
save(SaveFlags flags)570 int SkCanvas::save(SaveFlags flags) {
571     // call shared impl
572     return this->internalSave(flags);
573 }
574 
575 #define C32MASK (1 << SkBitmap::kARGB_8888_Config)
576 #define C16MASK (1 << SkBitmap::kRGB_565_Config)
577 #define C8MASK  (1 << SkBitmap::kA8_Config)
578 
resolve_config(SkCanvas * canvas,const SkIRect & bounds,SkCanvas::SaveFlags flags,bool * isOpaque)579 static SkBitmap::Config resolve_config(SkCanvas* canvas,
580                                        const SkIRect& bounds,
581                                        SkCanvas::SaveFlags flags,
582                                        bool* isOpaque) {
583     *isOpaque = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) == 0;
584 
585 #if 0
586     // loop through and union all the configs we may draw into
587     uint32_t configMask = 0;
588     for (int i = canvas->countLayerDevices() - 1; i >= 0; --i)
589     {
590         SkDevice* device = canvas->getLayerDevice(i);
591         if (device->intersects(bounds))
592             configMask |= 1 << device->config();
593     }
594 
595     // if the caller wants alpha or fullcolor, we can't return 565
596     if (flags & (SkCanvas::kFullColorLayer_SaveFlag |
597                  SkCanvas::kHasAlphaLayer_SaveFlag))
598         configMask &= ~C16MASK;
599 
600     switch (configMask) {
601     case C8MASK:    // if we only have A8, return that
602         return SkBitmap::kA8_Config;
603 
604     case C16MASK:   // if we only have 565, return that
605         return SkBitmap::kRGB_565_Config;
606 
607     default:
608         return SkBitmap::kARGB_8888_Config; // default answer
609     }
610 #else
611     return SkBitmap::kARGB_8888_Config; // default answer
612 #endif
613 }
614 
bounds_affects_clip(SkCanvas::SaveFlags flags)615 static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
616     return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
617 }
618 
saveLayer(const SkRect * bounds,const SkPaint * paint,SaveFlags flags)619 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
620                         SaveFlags flags) {
621     // do this before we create the layer. We don't call the public save() since
622     // that would invoke a possibly overridden virtual
623     int count = this->internalSave(flags);
624 
625     fDeviceCMDirty = true;
626 
627     SkIRect         ir;
628     const SkIRect&  clipBounds = this->getTotalClip().getBounds();
629 
630     if (NULL != bounds) {
631         SkRect r;
632 
633         this->getTotalMatrix().mapRect(&r, *bounds);
634         r.roundOut(&ir);
635         // early exit if the layer's bounds are clipped out
636         if (!ir.intersect(clipBounds)) {
637             if (bounds_affects_clip(flags))
638                 fMCRec->fRegion->setEmpty();
639             return count;
640         }
641     } else {    // no user bounds, so just use the clip
642         ir = clipBounds;
643     }
644 
645     // early exit if the clip is now empty
646     if (bounds_affects_clip(flags) &&
647         !fMCRec->fRegion->op(ir, SkRegion::kIntersect_Op)) {
648         return count;
649     }
650 
651     bool isOpaque;
652     SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque);
653 
654     SkDevice* device = this->createDevice(config, ir.width(), ir.height(),
655                                           isOpaque, true);
656     DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint));
657     device->unref();
658 
659     layer->fNext = fMCRec->fTopLayer;
660     fMCRec->fLayer = layer;
661     fMCRec->fTopLayer = layer;    // this field is NOT an owner of layer
662 
663     return count;
664 }
665 
saveLayerAlpha(const SkRect * bounds,U8CPU alpha,SaveFlags flags)666 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
667                              SaveFlags flags) {
668     if (0xFF == alpha) {
669         return this->saveLayer(bounds, NULL, flags);
670     } else {
671         SkPaint tmpPaint;
672         tmpPaint.setAlpha(alpha);
673         return this->saveLayer(bounds, &tmpPaint, flags);
674     }
675 }
676 
restore()677 void SkCanvas::restore() {
678     // check for underflow
679     if (fMCStack.count() > 1) {
680         this->internalRestore();
681     }
682 }
683 
internalRestore()684 void SkCanvas::internalRestore() {
685     SkASSERT(fMCStack.count() != 0);
686 
687     fDeviceCMDirty = true;
688     fLocalBoundsCompareTypeDirty = true;
689 
690 	// reserve our layer (if any)
691     DeviceCM* layer = fMCRec->fLayer;   // may be null
692     // now detach it from fMCRec so we can pop(). Gets freed after its drawn
693     fMCRec->fLayer = NULL;
694 
695     // now do the normal restore()
696     fMCRec->~MCRec();       // balanced in save()
697     fMCStack.pop_back();
698     fMCRec = (MCRec*)fMCStack.back();
699 
700     /*  Time to draw the layer's offscreen. We can't call the public drawSprite,
701         since if we're being recorded, we don't want to record this (the
702         recorder will have already recorded the restore).
703     */
704     if (NULL != layer) {
705         if (layer->fNext) {
706             this->drawDevice(layer->fDevice, layer->fX, layer->fY,
707                              layer->fPaint);
708             // reset this, since drawDevice will have set it to true
709             fDeviceCMDirty = true;
710         }
711         SkDELETE(layer);
712 	}
713 }
714 
getSaveCount() const715 int SkCanvas::getSaveCount() const {
716     return fMCStack.count();
717 }
718 
restoreToCount(int count)719 void SkCanvas::restoreToCount(int count) {
720     // sanity check
721     if (count < 1) {
722         count = 1;
723     }
724     while (fMCStack.count() > count) {
725         this->restore();
726     }
727 }
728 
729 /////////////////////////////////////////////////////////////////////////////
730 
731 // can't draw it if its empty, or its too big for a fixed-point width or height
reject_bitmap(const SkBitmap & bitmap)732 static bool reject_bitmap(const SkBitmap& bitmap) {
733     return  bitmap.width() <= 0 || bitmap.height() <= 0 ||
734             bitmap.width() > 32767 || bitmap.height() > 32767;
735 }
736 
internalDrawBitmap(const SkBitmap & bitmap,const SkMatrix & matrix,const SkPaint * paint)737 void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
738                                 const SkMatrix& matrix, const SkPaint* paint) {
739     if (reject_bitmap(bitmap)) {
740         return;
741     }
742 
743     if (NULL == paint) {
744         SkPaint tmpPaint;
745         this->commonDrawBitmap(bitmap, matrix, tmpPaint);
746     } else {
747         this->commonDrawBitmap(bitmap, matrix, *paint);
748     }
749 }
750 
drawDevice(SkDevice * device,int x,int y,const SkPaint * paint)751 void SkCanvas::drawDevice(SkDevice* device, int x, int y,
752                           const SkPaint* paint) {
753     SkPaint tmp;
754     if (NULL == paint) {
755         tmp.setDither(true);
756         paint = &tmp;
757     }
758 
759     ITER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
760     while (iter.next()) {
761         iter.fDevice->drawDevice(iter, device, x - iter.getX(), y - iter.getY(),
762                                  *paint);
763     }
764     ITER_END
765 }
766 
767 /////////////////////////////////////////////////////////////////////////////
768 
translate(SkScalar dx,SkScalar dy)769 bool SkCanvas::translate(SkScalar dx, SkScalar dy) {
770     fDeviceCMDirty = true;
771     fLocalBoundsCompareTypeDirty = true;
772     return fMCRec->fMatrix->preTranslate(dx, dy);
773 }
774 
scale(SkScalar sx,SkScalar sy)775 bool SkCanvas::scale(SkScalar sx, SkScalar sy) {
776     fDeviceCMDirty = true;
777     fLocalBoundsCompareTypeDirty = true;
778     return fMCRec->fMatrix->preScale(sx, sy);
779 }
780 
rotate(SkScalar degrees)781 bool SkCanvas::rotate(SkScalar degrees) {
782     fDeviceCMDirty = true;
783     fLocalBoundsCompareTypeDirty = true;
784     return fMCRec->fMatrix->preRotate(degrees);
785 }
786 
skew(SkScalar sx,SkScalar sy)787 bool SkCanvas::skew(SkScalar sx, SkScalar sy) {
788     fDeviceCMDirty = true;
789     fLocalBoundsCompareTypeDirty = true;
790     return fMCRec->fMatrix->preSkew(sx, sy);
791 }
792 
concat(const SkMatrix & matrix)793 bool SkCanvas::concat(const SkMatrix& matrix) {
794     fDeviceCMDirty = true;
795     fLocalBoundsCompareTypeDirty = true;
796     return fMCRec->fMatrix->preConcat(matrix);
797 }
798 
setMatrix(const SkMatrix & matrix)799 void SkCanvas::setMatrix(const SkMatrix& matrix) {
800     fDeviceCMDirty = true;
801     fLocalBoundsCompareTypeDirty = true;
802     *fMCRec->fMatrix = matrix;
803 }
804 
805 // this is not virtual, so it must call a virtual method so that subclasses
806 // will see its action
resetMatrix()807 void SkCanvas::resetMatrix() {
808     SkMatrix matrix;
809 
810     matrix.reset();
811     this->setMatrix(matrix);
812 }
813 
814 //////////////////////////////////////////////////////////////////////////////
815 
clipRect(const SkRect & rect,SkRegion::Op op)816 bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
817     fDeviceCMDirty = true;
818     fLocalBoundsCompareTypeDirty = true;
819 
820     if (fMCRec->fMatrix->rectStaysRect()) {
821         // for these simpler matrices, we can stay a rect ever after applying
822         // the matrix. This means we don't have to a) make a path, and b) tell
823         // the region code to scan-convert the path, only to discover that it
824         // is really just a rect.
825         SkRect      r;
826         SkIRect     ir;
827 
828         fMCRec->fMatrix->mapRect(&r, rect);
829         r.round(&ir);
830         return fMCRec->fRegion->op(ir, op);
831     } else {
832         // since we're rotate or some such thing, we convert the rect to a path
833         // and clip against that, since it can handle any matrix. However, to
834         // avoid recursion in the case where we are subclassed (e.g. Pictures)
835         // we explicitly call "our" version of clipPath.
836         SkPath  path;
837 
838         path.addRect(rect);
839         return this->SkCanvas::clipPath(path, op);
840     }
841 }
842 
clipPath(const SkPath & path,SkRegion::Op op)843 bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op) {
844     fDeviceCMDirty = true;
845     fLocalBoundsCompareTypeDirty = true;
846 
847     SkPath devPath;
848     path.transform(*fMCRec->fMatrix, &devPath);
849 
850     if (SkRegion::kIntersect_Op == op) {
851         return fMCRec->fRegion->setPath(devPath, *fMCRec->fRegion);
852     } else {
853         SkRegion base;
854         const SkBitmap& bm = this->getDevice()->accessBitmap(false);
855         base.setRect(0, 0, bm.width(), bm.height());
856 
857         if (SkRegion::kReplace_Op == op) {
858             return fMCRec->fRegion->setPath(devPath, base);
859         } else {
860             SkRegion rgn;
861             rgn.setPath(devPath, base);
862             return fMCRec->fRegion->op(rgn, op);
863         }
864     }
865 }
866 
clipRegion(const SkRegion & rgn,SkRegion::Op op)867 bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
868     fDeviceCMDirty = true;
869     fLocalBoundsCompareTypeDirty = true;
870 
871     return fMCRec->fRegion->op(rgn, op);
872 }
873 
computeLocalClipBoundsCompareType() const874 void SkCanvas::computeLocalClipBoundsCompareType() const {
875     SkRect r;
876 
877     if (!this->getClipBounds(&r, kAA_EdgeType)) {
878         fLocalBoundsCompareType.setEmpty();
879     } else {
880         fLocalBoundsCompareType.set(SkScalarToCompareType(r.fLeft),
881                                     SkScalarToCompareType(r.fTop),
882                                     SkScalarToCompareType(r.fRight),
883                                     SkScalarToCompareType(r.fBottom));
884     }
885 }
886 
887 /*  current impl ignores edgetype, and relies on
888     getLocalClipBoundsCompareType(), which always returns a value assuming
889     antialiasing (worst case)
890  */
quickReject(const SkRect & rect,EdgeType) const891 bool SkCanvas::quickReject(const SkRect& rect, EdgeType) const {
892     if (fMCRec->fRegion->isEmpty()) {
893         return true;
894     }
895 
896     if (fMCRec->fMatrix->getType() & SkMatrix::kPerspective_Mask) {
897         SkRect dst;
898         fMCRec->fMatrix->mapRect(&dst, rect);
899         SkIRect idst;
900         dst.roundOut(&idst);
901         return !SkIRect::Intersects(idst, fMCRec->fRegion->getBounds());
902     } else {
903         const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType();
904 
905         // for speed, do the most likely reject compares first
906         SkScalarCompareType userT = SkScalarToCompareType(rect.fTop);
907         SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom);
908         if (userT >= clipR.fBottom || userB <= clipR.fTop) {
909             return true;
910         }
911         SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft);
912         SkScalarCompareType userR = SkScalarToCompareType(rect.fRight);
913         if (userL >= clipR.fRight || userR <= clipR.fLeft) {
914             return true;
915         }
916         return false;
917     }
918 }
919 
quickReject(const SkPath & path,EdgeType et) const920 bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const {
921     return path.isEmpty() || this->quickReject(path.getBounds(), et);
922 }
923 
quickRejectY(SkScalar top,SkScalar bottom,EdgeType et) const924 bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const {
925     /*  current impl ignores edgetype, and relies on
926         getLocalClipBoundsCompareType(), which always returns a value assuming
927         antialiasing (worst case)
928      */
929 
930     if (fMCRec->fRegion->isEmpty()) {
931         return true;
932     }
933 
934     SkScalarCompareType userT = SkScalarToCompareType(top);
935     SkScalarCompareType userB = SkScalarToCompareType(bottom);
936 
937     // check for invalid user Y coordinates (i.e. empty)
938     // reed: why do we need to do this check, since it slows us down?
939     if (userT >= userB) {
940         return true;
941     }
942 
943     // check if we are above or below the local clip bounds
944     const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType();
945     return userT >= clipR.fBottom || userB <= clipR.fTop;
946 }
947 
getClipBounds(SkRect * bounds,EdgeType et) const948 bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const {
949     const SkRegion& clip = *fMCRec->fRegion;
950     if (clip.isEmpty()) {
951         if (bounds) {
952             bounds->setEmpty();
953         }
954         return false;
955     }
956 
957     SkMatrix inverse;
958     // if we can't invert the CTM, we can't return local clip bounds
959     if (!fMCRec->fMatrix->invert(&inverse)) {
960         if (bounds) {
961             bounds->setEmpty();
962         }
963         return false;
964     }
965 
966     if (NULL != bounds) {
967         SkRect   r;
968         // get the clip's bounds
969         const SkIRect& ibounds = clip.getBounds();
970         // adjust it outwards if we are antialiasing
971         int inset = (kAA_EdgeType == et);
972         r.iset(ibounds.fLeft - inset,  ibounds.fTop - inset,
973                ibounds.fRight + inset, ibounds.fBottom + inset);
974 
975         // invert into local coordinates
976         inverse.mapRect(bounds, r);
977     }
978     return true;
979 }
980 
getTotalMatrix() const981 const SkMatrix& SkCanvas::getTotalMatrix() const {
982     return *fMCRec->fMatrix;
983 }
984 
getTotalClip() const985 const SkRegion& SkCanvas::getTotalClip() const {
986     return *fMCRec->fRegion;
987 }
988 
989 ///////////////////////////////////////////////////////////////////////////////
990 
createDevice(SkBitmap::Config config,int width,int height,bool isOpaque,bool isForLayer)991 SkDevice* SkCanvas::createDevice(SkBitmap::Config config, int width,
992                                  int height, bool isOpaque, bool isForLayer) {
993     SkBitmap bitmap;
994 
995     bitmap.setConfig(config, width, height);
996     bitmap.setIsOpaque(isOpaque);
997 
998     // should this happen in the device subclass?
999     bitmap.allocPixels();
1000     if (!bitmap.isOpaque()) {
1001         bitmap.eraseARGB(0, 0, 0, 0);
1002     }
1003 
1004     return SkNEW_ARGS(SkDevice, (bitmap));
1005 }
1006 
1007 //////////////////////////////////////////////////////////////////////////////
1008 //  These are the virtual drawing methods
1009 //////////////////////////////////////////////////////////////////////////////
1010 
drawPaint(const SkPaint & paint)1011 void SkCanvas::drawPaint(const SkPaint& paint) {
1012     ITER_BEGIN(paint, SkDrawFilter::kPaint_Type)
1013 
1014     while (iter.next()) {
1015         iter.fDevice->drawPaint(iter, paint);
1016     }
1017 
1018     ITER_END
1019 }
1020 
drawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)1021 void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
1022                           const SkPaint& paint) {
1023     if ((long)count <= 0) {
1024         return;
1025     }
1026 
1027     SkASSERT(pts != NULL);
1028 
1029     ITER_BEGIN(paint, SkDrawFilter::kPoint_Type)
1030 
1031     while (iter.next()) {
1032         iter.fDevice->drawPoints(iter, mode, count, pts, paint);
1033     }
1034 
1035     ITER_END
1036 }
1037 
drawRect(const SkRect & r,const SkPaint & paint)1038 void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1039     if (paint.canComputeFastBounds()) {
1040         SkRect storage;
1041         if (this->quickReject(paint.computeFastBounds(r, &storage),
1042                               paint2EdgeType(&paint))) {
1043             return;
1044         }
1045     }
1046 
1047     ITER_BEGIN(paint, SkDrawFilter::kRect_Type)
1048 
1049     while (iter.next()) {
1050         iter.fDevice->drawRect(iter, r, paint);
1051     }
1052 
1053     ITER_END
1054 }
1055 
drawPath(const SkPath & path,const SkPaint & paint)1056 void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1057     if (paint.canComputeFastBounds()) {
1058         SkRect storage;
1059         const SkRect& bounds = path.getBounds();
1060         if (this->quickReject(paint.computeFastBounds(bounds, &storage),
1061                               paint2EdgeType(&paint))) {
1062             return;
1063         }
1064     }
1065 
1066     ITER_BEGIN(paint, SkDrawFilter::kPath_Type)
1067 
1068     while (iter.next()) {
1069         iter.fDevice->drawPath(iter, path, paint);
1070     }
1071 
1072     ITER_END
1073 }
1074 
drawBitmap(const SkBitmap & bitmap,SkScalar x,SkScalar y,const SkPaint * paint)1075 void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
1076                           const SkPaint* paint) {
1077     SkDEBUGCODE(bitmap.validate();)
1078 
1079     if (NULL == paint || (paint->getMaskFilter() == NULL)) {
1080         SkRect fastBounds;
1081         fastBounds.set(x, y,
1082                        x + SkIntToScalar(bitmap.width()),
1083                        y + SkIntToScalar(bitmap.height()));
1084         if (this->quickReject(fastBounds, paint2EdgeType(paint))) {
1085             return;
1086         }
1087     }
1088 
1089     SkMatrix matrix;
1090     matrix.setTranslate(x, y);
1091     this->internalDrawBitmap(bitmap, matrix, paint);
1092 }
1093 
drawBitmapRect(const SkBitmap & bitmap,const SkIRect * src,const SkRect & dst,const SkPaint * paint)1094 void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
1095                               const SkRect& dst, const SkPaint* paint) {
1096     if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) {
1097         return;
1098     }
1099 
1100     // do this now, to avoid the cost of calling extract for RLE bitmaps
1101     if (this->quickReject(dst, paint2EdgeType(paint))) {
1102         return;
1103     }
1104 
1105     SkBitmap        tmp;    // storage if we need a subset of bitmap
1106     const SkBitmap* bitmapPtr = &bitmap;
1107 
1108     if (NULL != src) {
1109         if (!bitmap.extractSubset(&tmp, *src)) {
1110             return;     // extraction failed
1111         }
1112         bitmapPtr = &tmp;
1113     }
1114 
1115     SkScalar width = SkIntToScalar(bitmapPtr->width());
1116     SkScalar height = SkIntToScalar(bitmapPtr->height());
1117     SkMatrix matrix;
1118 
1119     if (dst.width() == width && dst.height() == height) {
1120         matrix.setTranslate(dst.fLeft, dst.fTop);
1121     } else {
1122         SkRect tmpSrc;
1123         tmpSrc.set(0, 0, width, height);
1124         matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
1125     }
1126     this->internalDrawBitmap(*bitmapPtr, matrix, paint);
1127 }
1128 
drawBitmapMatrix(const SkBitmap & bitmap,const SkMatrix & matrix,const SkPaint * paint)1129 void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
1130                                 const SkPaint* paint) {
1131     SkDEBUGCODE(bitmap.validate();)
1132     this->internalDrawBitmap(bitmap, matrix, paint);
1133 }
1134 
commonDrawBitmap(const SkBitmap & bitmap,const SkMatrix & matrix,const SkPaint & paint)1135 void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
1136                                 const SkPaint& paint) {
1137     SkDEBUGCODE(bitmap.validate();)
1138 
1139     ITER_BEGIN(paint, SkDrawFilter::kBitmap_Type)
1140 
1141     while (iter.next()) {
1142         iter.fDevice->drawBitmap(iter, bitmap, matrix, paint);
1143     }
1144 
1145     ITER_END
1146 }
1147 
drawSprite(const SkBitmap & bitmap,int x,int y,const SkPaint * paint)1148 void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
1149                           const SkPaint* paint) {
1150     SkDEBUGCODE(bitmap.validate();)
1151 
1152     if (reject_bitmap(bitmap)) {
1153         return;
1154     }
1155 
1156     SkPaint tmp;
1157     if (NULL == paint) {
1158         paint = &tmp;
1159     }
1160 
1161     ITER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
1162 
1163     while (iter.next()) {
1164         iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(),
1165                                  *paint);
1166     }
1167     ITER_END
1168 }
1169 
drawText(const void * text,size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint)1170 void SkCanvas::drawText(const void* text, size_t byteLength,
1171                         SkScalar x, SkScalar y, const SkPaint& paint) {
1172     ITER_BEGIN(paint, SkDrawFilter::kText_Type)
1173 
1174     while (iter.next()) {
1175         iter.fDevice->drawText(iter, text, byteLength, x, y, paint);
1176     }
1177 
1178     ITER_END
1179 }
1180 
drawPosText(const void * text,size_t byteLength,const SkPoint pos[],const SkPaint & paint)1181 void SkCanvas::drawPosText(const void* text, size_t byteLength,
1182                            const SkPoint pos[], const SkPaint& paint) {
1183     ITER_BEGIN(paint, SkDrawFilter::kText_Type)
1184 
1185     while (iter.next()) {
1186         iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
1187                                   paint);
1188     }
1189 
1190     ITER_END
1191 }
1192 
drawPosTextH(const void * text,size_t byteLength,const SkScalar xpos[],SkScalar constY,const SkPaint & paint)1193 void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
1194                             const SkScalar xpos[], SkScalar constY,
1195                             const SkPaint& paint) {
1196     ITER_BEGIN(paint, SkDrawFilter::kText_Type)
1197 
1198     while (iter.next()) {
1199         iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
1200                                   paint);
1201     }
1202 
1203     ITER_END
1204 }
1205 
drawTextOnPath(const void * text,size_t byteLength,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)1206 void SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
1207                               const SkPath& path, const SkMatrix* matrix,
1208                               const SkPaint& paint) {
1209     ITER_BEGIN(paint, SkDrawFilter::kText_Type)
1210 
1211     while (iter.next()) {
1212         iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
1213                                      matrix, paint);
1214     }
1215 
1216     ITER_END
1217 }
1218 
drawVertices(VertexMode vmode,int vertexCount,const SkPoint verts[],const SkPoint texs[],const SkColor colors[],SkXfermode * xmode,const uint16_t indices[],int indexCount,const SkPaint & paint)1219 void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
1220                             const SkPoint verts[], const SkPoint texs[],
1221                             const SkColor colors[], SkXfermode* xmode,
1222                             const uint16_t indices[], int indexCount,
1223                             const SkPaint& paint) {
1224     ITER_BEGIN(paint, SkDrawFilter::kPath_Type)
1225 
1226     while (iter.next()) {
1227         iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
1228                                    colors, xmode, indices, indexCount, paint);
1229     }
1230 
1231     ITER_END
1232 }
1233 
1234 //////////////////////////////////////////////////////////////////////////////
1235 // These methods are NOT virtual, and therefore must call back into virtual
1236 // methods, rather than actually drawing themselves.
1237 //////////////////////////////////////////////////////////////////////////////
1238 
drawARGB(U8CPU a,U8CPU r,U8CPU g,U8CPU b,SkXfermode::Mode mode)1239 void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
1240                         SkXfermode::Mode mode) {
1241     SkPaint paint;
1242 
1243     paint.setARGB(a, r, g, b);
1244     if (SkXfermode::kSrcOver_Mode != mode) {
1245         paint.setXfermodeMode(mode);
1246     }
1247     this->drawPaint(paint);
1248 }
1249 
drawColor(SkColor c,SkXfermode::Mode mode)1250 void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
1251     SkPaint paint;
1252 
1253     paint.setColor(c);
1254     if (SkXfermode::kSrcOver_Mode != mode) {
1255         paint.setXfermodeMode(mode);
1256     }
1257     this->drawPaint(paint);
1258 }
1259 
drawPoint(SkScalar x,SkScalar y,const SkPaint & paint)1260 void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
1261     SkPoint pt;
1262 
1263     pt.set(x, y);
1264     this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1265 }
1266 
drawPoint(SkScalar x,SkScalar y,SkColor color)1267 void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
1268     SkPoint pt;
1269     SkPaint paint;
1270 
1271     pt.set(x, y);
1272     paint.setColor(color);
1273     this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1274 }
1275 
drawLine(SkScalar x0,SkScalar y0,SkScalar x1,SkScalar y1,const SkPaint & paint)1276 void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
1277                         const SkPaint& paint) {
1278     SkPoint pts[2];
1279 
1280     pts[0].set(x0, y0);
1281     pts[1].set(x1, y1);
1282     this->drawPoints(kLines_PointMode, 2, pts, paint);
1283 }
1284 
drawRectCoords(SkScalar left,SkScalar top,SkScalar right,SkScalar bottom,const SkPaint & paint)1285 void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
1286                               SkScalar right, SkScalar bottom,
1287                               const SkPaint& paint) {
1288     SkRect  r;
1289 
1290     r.set(left, top, right, bottom);
1291     this->drawRect(r, paint);
1292 }
1293 
drawCircle(SkScalar cx,SkScalar cy,SkScalar radius,const SkPaint & paint)1294 void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
1295                           const SkPaint& paint) {
1296     if (radius < 0) {
1297         radius = 0;
1298     }
1299 
1300     SkRect  r;
1301     r.set(cx - radius, cy - radius, cx + radius, cy + radius);
1302 
1303     if (paint.canComputeFastBounds()) {
1304         SkRect storage;
1305         if (this->quickReject(paint.computeFastBounds(r, &storage),
1306                               paint2EdgeType(&paint))) {
1307             return;
1308         }
1309     }
1310 
1311     SkPath  path;
1312     path.addOval(r);
1313     this->drawPath(path, paint);
1314 }
1315 
drawRoundRect(const SkRect & r,SkScalar rx,SkScalar ry,const SkPaint & paint)1316 void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
1317                              const SkPaint& paint) {
1318     if (rx > 0 && ry > 0) {
1319         if (paint.canComputeFastBounds()) {
1320             SkRect storage;
1321             if (this->quickReject(paint.computeFastBounds(r, &storage),
1322                                   paint2EdgeType(&paint))) {
1323                 return;
1324             }
1325         }
1326 
1327         SkPath  path;
1328         path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
1329         this->drawPath(path, paint);
1330     } else {
1331         this->drawRect(r, paint);
1332     }
1333 }
1334 
drawOval(const SkRect & oval,const SkPaint & paint)1335 void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
1336     if (paint.canComputeFastBounds()) {
1337         SkRect storage;
1338         if (this->quickReject(paint.computeFastBounds(oval, &storage),
1339                               paint2EdgeType(&paint))) {
1340             return;
1341         }
1342     }
1343 
1344     SkPath  path;
1345     path.addOval(oval);
1346     this->drawPath(path, paint);
1347 }
1348 
drawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)1349 void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
1350                        SkScalar sweepAngle, bool useCenter,
1351                        const SkPaint& paint) {
1352     if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
1353         this->drawOval(oval, paint);
1354     } else {
1355         SkPath  path;
1356         if (useCenter) {
1357             path.moveTo(oval.centerX(), oval.centerY());
1358         }
1359         path.arcTo(oval, startAngle, sweepAngle, !useCenter);
1360         if (useCenter) {
1361             path.close();
1362         }
1363         this->drawPath(path, paint);
1364     }
1365 }
1366 
drawTextOnPathHV(const void * text,size_t byteLength,const SkPath & path,SkScalar hOffset,SkScalar vOffset,const SkPaint & paint)1367 void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
1368                                 const SkPath& path, SkScalar hOffset,
1369                                 SkScalar vOffset, const SkPaint& paint) {
1370     SkMatrix    matrix;
1371 
1372     matrix.setTranslate(hOffset, vOffset);
1373     this->drawTextOnPath(text, byteLength, path, &matrix, paint);
1374 }
1375 
1376 ///////////////////////////////////////////////////////////////////////////////
1377 
drawPicture(SkPicture & picture)1378 void SkCanvas::drawPicture(SkPicture& picture) {
1379     int saveCount = save();
1380     picture.draw(this);
1381     restoreToCount(saveCount);
1382 }
1383 
drawShape(SkShape * shape)1384 void SkCanvas::drawShape(SkShape* shape) {
1385     // shape baseclass takes care of save/restore
1386     shape->draw(this);
1387 }
1388 
1389 ///////////////////////////////////////////////////////////////////////////////
1390 ///////////////////////////////////////////////////////////////////////////////
1391 
LayerIter(SkCanvas * canvas,bool skipEmptyClips)1392 SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
1393     // need COMPILE_TIME_ASSERT
1394     SkASSERT(sizeof(fStorage) >= sizeof(SkDrawIter));
1395 
1396     SkASSERT(canvas);
1397 
1398     fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
1399     fDone = !fImpl->next();
1400 }
1401 
~LayerIter()1402 SkCanvas::LayerIter::~LayerIter() {
1403     fImpl->~SkDrawIter();
1404 }
1405 
next()1406 void SkCanvas::LayerIter::next() {
1407     fDone = !fImpl->next();
1408 }
1409 
device() const1410 SkDevice* SkCanvas::LayerIter::device() const {
1411     return fImpl->getDevice();
1412 }
1413 
matrix() const1414 const SkMatrix& SkCanvas::LayerIter::matrix() const {
1415     return fImpl->getMatrix();
1416 }
1417 
paint() const1418 const SkPaint& SkCanvas::LayerIter::paint() const {
1419     const SkPaint* paint = fImpl->getPaint();
1420     if (NULL == paint) {
1421         paint = &fDefaultPaint;
1422     }
1423     return *paint;
1424 }
1425 
clip() const1426 const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
x() const1427 int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
y() const1428 int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
1429 
1430