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