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