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