blob: 72988643c8abaa5085f2beae8c19cacbe36d1102 [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
reed@android.comd9c0f0b2009-02-06 22:39:37 +0000960 SkMatrix inverse;
961 // if we can't invert the CTM, we can't return local clip bounds
962 if (!fMCRec->fMatrix->invert(&inverse)) {
963 return false;
964 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965
reed@android.comd9c0f0b2009-02-06 22:39:37 +0000966 if (NULL != bounds) {
967 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968 // get the clip's bounds
969 const SkIRect& ibounds = clip.getBounds();
970 // adjust it outwards if we are antialiasing
971 int inset = (kAA_EdgeType == et);
972 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
973 ibounds.fRight + inset, ibounds.fBottom + inset);
974
975 // invert into local coordinates
976 inverse.mapRect(bounds, r);
977 }
978 return true;
979}
980
981const SkMatrix& SkCanvas::getTotalMatrix() const {
982 return *fMCRec->fMatrix;
983}
984
985const SkRegion& SkCanvas::getTotalClip() const {
986 return *fMCRec->fRegion;
987}
988
989///////////////////////////////////////////////////////////////////////////////
990
991SkDevice* SkCanvas::createDevice(SkBitmap::Config config, int width,
992 int height, bool isOpaque, bool isForLayer) {
993 SkBitmap bitmap;
994
995 bitmap.setConfig(config, width, height);
996 bitmap.setIsOpaque(isOpaque);
997
998 // should this happen in the device subclass?
999 bitmap.allocPixels();
1000 if (!bitmap.isOpaque()) {
1001 bitmap.eraseARGB(0, 0, 0, 0);
1002 }
1003
1004 return SkNEW_ARGS(SkDevice, (bitmap));
1005}
1006
1007//////////////////////////////////////////////////////////////////////////////
1008// These are the virtual drawing methods
1009//////////////////////////////////////////////////////////////////////////////
1010
1011void SkCanvas::drawPaint(const SkPaint& paint) {
1012 ITER_BEGIN(paint, SkDrawFilter::kPaint_Type)
1013
1014 while (iter.next()) {
1015 iter.fDevice->drawPaint(iter, paint);
1016 }
1017
1018 ITER_END
1019}
1020
1021void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
1022 const SkPaint& paint) {
1023 if ((long)count <= 0) {
1024 return;
1025 }
1026
1027 SkASSERT(pts != NULL);
1028
1029 ITER_BEGIN(paint, SkDrawFilter::kPoint_Type)
1030
1031 while (iter.next()) {
1032 iter.fDevice->drawPoints(iter, mode, count, pts, paint);
1033 }
1034
1035 ITER_END
1036}
1037
1038void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1039 if (paint.canComputeFastBounds()) {
1040 SkRect storage;
1041 if (this->quickReject(paint.computeFastBounds(r, &storage),
1042 paint2EdgeType(&paint))) {
1043 return;
1044 }
1045 }
1046
1047 ITER_BEGIN(paint, SkDrawFilter::kRect_Type)
1048
1049 while (iter.next()) {
1050 iter.fDevice->drawRect(iter, r, paint);
1051 }
1052
1053 ITER_END
1054}
1055
1056void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1057 if (paint.canComputeFastBounds()) {
1058 SkRect r;
1059 path.computeBounds(&r, SkPath::kFast_BoundsType);
1060 if (this->quickReject(paint.computeFastBounds(r, &r),
1061 paint2EdgeType(&paint))) {
1062 return;
1063 }
1064 }
1065
1066 ITER_BEGIN(paint, SkDrawFilter::kPath_Type)
1067
1068 while (iter.next()) {
1069 iter.fDevice->drawPath(iter, path, paint);
1070 }
1071
1072 ITER_END
1073}
1074
1075void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
1076 const SkPaint* paint) {
1077 SkDEBUGCODE(bitmap.validate();)
1078
1079 if (NULL == paint || (paint->getMaskFilter() == NULL)) {
1080 SkRect fastBounds;
1081 fastBounds.set(x, y,
1082 x + SkIntToScalar(bitmap.width()),
1083 y + SkIntToScalar(bitmap.height()));
1084 if (this->quickReject(fastBounds, paint2EdgeType(paint))) {
1085 return;
1086 }
1087 }
1088
1089 SkMatrix matrix;
1090 matrix.setTranslate(x, y);
1091 this->internalDrawBitmap(bitmap, matrix, paint);
1092}
1093
1094void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
1095 const SkRect& dst, const SkPaint* paint) {
1096 if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) {
1097 return;
1098 }
1099
1100 // do this now, to avoid the cost of calling extract for RLE bitmaps
1101 if (this->quickReject(dst, paint2EdgeType(paint))) {
1102 return;
1103 }
1104
1105 SkBitmap tmp; // storage if we need a subset of bitmap
1106 const SkBitmap* bitmapPtr = &bitmap;
1107
1108 if (NULL != src) {
1109 if (!bitmap.extractSubset(&tmp, *src)) {
1110 return; // extraction failed
1111 }
1112 bitmapPtr = &tmp;
1113 }
1114
1115 SkScalar width = SkIntToScalar(bitmapPtr->width());
1116 SkScalar height = SkIntToScalar(bitmapPtr->height());
1117 SkMatrix matrix;
1118
1119 if (dst.width() == width && dst.height() == height) {
1120 matrix.setTranslate(dst.fLeft, dst.fTop);
1121 } else {
1122 SkRect tmpSrc;
1123 tmpSrc.set(0, 0, width, height);
1124 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
1125 }
1126 this->internalDrawBitmap(*bitmapPtr, matrix, paint);
1127}
1128
1129void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
1130 const SkPaint* paint) {
1131 SkDEBUGCODE(bitmap.validate();)
1132 this->internalDrawBitmap(bitmap, matrix, paint);
1133}
1134
1135void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
1136 const SkPaint& paint) {
1137 SkDEBUGCODE(bitmap.validate();)
1138
1139 ITER_BEGIN(paint, SkDrawFilter::kBitmap_Type)
1140
1141 while (iter.next()) {
1142 iter.fDevice->drawBitmap(iter, bitmap, matrix, paint);
1143 }
1144
1145 ITER_END
1146}
1147
1148void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
1149 const SkPaint* paint) {
1150 SkDEBUGCODE(bitmap.validate();)
1151
1152 if (reject_bitmap(bitmap)) {
1153 return;
1154 }
1155
1156 SkPaint tmp;
1157 if (NULL == paint) {
1158 paint = &tmp;
1159 }
1160
1161 ITER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
1162
1163 while (iter.next()) {
1164 iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(),
1165 *paint);
1166 }
1167 ITER_END
1168}
1169
1170void SkCanvas::drawText(const void* text, size_t byteLength,
1171 SkScalar x, SkScalar y, const SkPaint& paint) {
1172 ITER_BEGIN(paint, SkDrawFilter::kText_Type)
1173
1174 while (iter.next()) {
1175 iter.fDevice->drawText(iter, text, byteLength, x, y, paint);
1176 }
1177
1178 ITER_END
1179}
1180
1181void SkCanvas::drawPosText(const void* text, size_t byteLength,
1182 const SkPoint pos[], const SkPaint& paint) {
1183 ITER_BEGIN(paint, SkDrawFilter::kText_Type)
1184
1185 while (iter.next()) {
1186 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
1187 paint);
1188 }
1189
1190 ITER_END
1191}
1192
1193void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
1194 const SkScalar xpos[], SkScalar constY,
1195 const SkPaint& paint) {
1196 ITER_BEGIN(paint, SkDrawFilter::kText_Type)
1197
1198 while (iter.next()) {
1199 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
1200 paint);
1201 }
1202
1203 ITER_END
1204}
1205
1206void SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
1207 const SkPath& path, const SkMatrix* matrix,
1208 const SkPaint& paint) {
1209 ITER_BEGIN(paint, SkDrawFilter::kText_Type)
1210
1211 while (iter.next()) {
1212 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
1213 matrix, paint);
1214 }
1215
1216 ITER_END
1217}
1218
1219void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
1220 const SkPoint verts[], const SkPoint texs[],
1221 const SkColor colors[], SkXfermode* xmode,
1222 const uint16_t indices[], int indexCount,
1223 const SkPaint& paint) {
1224 ITER_BEGIN(paint, SkDrawFilter::kPath_Type)
1225
1226 while (iter.next()) {
1227 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
1228 colors, xmode, indices, indexCount, paint);
1229 }
1230
1231 ITER_END
1232}
1233
1234//////////////////////////////////////////////////////////////////////////////
1235// These methods are NOT virtual, and therefore must call back into virtual
1236// methods, rather than actually drawing themselves.
1237//////////////////////////////////////////////////////////////////////////////
1238
1239void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
1240 SkPorterDuff::Mode mode) {
1241 SkPaint paint;
1242
1243 paint.setARGB(a, r, g, b);
1244 if (SkPorterDuff::kSrcOver_Mode != mode) {
1245 paint.setPorterDuffXfermode(mode);
1246 }
1247 this->drawPaint(paint);
1248}
1249
1250void SkCanvas::drawColor(SkColor c, SkPorterDuff::Mode mode) {
1251 SkPaint paint;
1252
1253 paint.setColor(c);
1254 if (SkPorterDuff::kSrcOver_Mode != mode) {
1255 paint.setPorterDuffXfermode(mode);
1256 }
1257 this->drawPaint(paint);
1258}
1259
1260void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
1261 SkPoint pt;
1262
1263 pt.set(x, y);
1264 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1265}
1266
1267void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
1268 SkPoint pt;
1269 SkPaint paint;
1270
1271 pt.set(x, y);
1272 paint.setColor(color);
1273 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1274}
1275
1276void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
1277 const SkPaint& paint) {
1278 SkPoint pts[2];
1279
1280 pts[0].set(x0, y0);
1281 pts[1].set(x1, y1);
1282 this->drawPoints(kLines_PointMode, 2, pts, paint);
1283}
1284
1285void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
1286 SkScalar right, SkScalar bottom,
1287 const SkPaint& paint) {
1288 SkRect r;
1289
1290 r.set(left, top, right, bottom);
1291 this->drawRect(r, paint);
1292}
1293
1294void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
1295 const SkPaint& paint) {
1296 if (radius < 0) {
1297 radius = 0;
1298 }
1299
1300 SkRect r;
1301 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
1302
1303 if (paint.canComputeFastBounds()) {
1304 SkRect storage;
1305 if (this->quickReject(paint.computeFastBounds(r, &storage),
1306 paint2EdgeType(&paint))) {
1307 return;
1308 }
1309 }
1310
1311 SkPath path;
1312 path.addOval(r);
1313 this->drawPath(path, paint);
1314}
1315
1316void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
1317 const SkPaint& paint) {
1318 if (rx > 0 && ry > 0) {
1319 if (paint.canComputeFastBounds()) {
1320 SkRect storage;
1321 if (this->quickReject(paint.computeFastBounds(r, &storage),
1322 paint2EdgeType(&paint))) {
1323 return;
1324 }
1325 }
1326
1327 SkPath path;
1328 path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
1329 this->drawPath(path, paint);
1330 } else {
1331 this->drawRect(r, paint);
1332 }
1333}
1334
1335void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
1336 if (paint.canComputeFastBounds()) {
1337 SkRect storage;
1338 if (this->quickReject(paint.computeFastBounds(oval, &storage),
1339 paint2EdgeType(&paint))) {
1340 return;
1341 }
1342 }
1343
1344 SkPath path;
1345 path.addOval(oval);
1346 this->drawPath(path, paint);
1347}
1348
1349void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
1350 SkScalar sweepAngle, bool useCenter,
1351 const SkPaint& paint) {
1352 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
1353 this->drawOval(oval, paint);
1354 } else {
1355 SkPath path;
1356 if (useCenter) {
1357 path.moveTo(oval.centerX(), oval.centerY());
1358 }
1359 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
1360 if (useCenter) {
1361 path.close();
1362 }
1363 this->drawPath(path, paint);
1364 }
1365}
1366
1367void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
1368 const SkPath& path, SkScalar hOffset,
1369 SkScalar vOffset, const SkPaint& paint) {
1370 SkMatrix matrix;
1371
1372 matrix.setTranslate(hOffset, vOffset);
1373 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
1374}
1375
1376void SkCanvas::drawPicture(SkPicture& picture) {
1377 int saveCount = save();
1378 picture.draw(this);
1379 restoreToCount(saveCount);
1380}
1381
1382///////////////////////////////////////////////////////////////////////////////
1383///////////////////////////////////////////////////////////////////////////////
1384
1385SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
1386 // need COMPILE_TIME_ASSERT
1387 SkASSERT(sizeof(fStorage) >= sizeof(SkDrawIter));
1388
1389 SkASSERT(canvas);
1390
1391 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
1392 fDone = !fImpl->next();
1393}
1394
1395SkCanvas::LayerIter::~LayerIter() {
1396 fImpl->~SkDrawIter();
1397}
1398
1399void SkCanvas::LayerIter::next() {
1400 fDone = !fImpl->next();
1401}
1402
1403SkDevice* SkCanvas::LayerIter::device() const {
1404 return fImpl->getDevice();
1405}
1406
1407const SkMatrix& SkCanvas::LayerIter::matrix() const {
1408 return fImpl->getMatrix();
1409}
1410
1411const SkPaint& SkCanvas::LayerIter::paint() const {
1412 const SkPaint* paint = fImpl->getPaint();
1413 if (NULL == paint) {
1414 paint = &fDefaultPaint;
1415 }
1416 return *paint;
1417}
1418
1419const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
1420int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
1421int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
1422