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