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