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