3 * Copyright 2008 The Android Open Source Project
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
11 #include "SkBitmapDevice.h"
12 #include "SkBounder.h"
13 #include "SkDeviceImageFilterProxy.h"
15 #include "SkDrawFilter.h"
16 #include "SkDrawLooper.h"
17 #include "SkMetaData.h"
18 #include "SkPathOps.h"
19 #include "SkPicture.h"
20 #include "SkRasterClip.h"
22 #include "SkSmallAllocator.h"
23 #include "SkSurface_Base.h"
24 #include "SkTemplates.h"
25 #include "SkTextFormatParams.h"
30 #include "GrRenderTarget.h"
33 // experimental for faster tiled drawing...
34 //#define SK_ENABLE_CLIP_QUICKREJECT
36 //#define SK_TRACE_SAVERESTORE
38 #ifdef SK_TRACE_SAVERESTORE
39 static int gLayerCounter;
40 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
41 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
43 static int gRecCounter;
44 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
45 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
47 static int gCanvasCounter;
48 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
49 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
60 #include "SkPixelRef.h"
63 * Some pixelref subclasses can support being "locked" from another thread
64 * during the lock-scope of skia calling them. In these instances, this balance
65 * check will fail, but may not be indicative of a problem, so we allow a build
66 * flag to disable this check.
68 * Potentially another fix would be to have a (debug-only) virtual or flag on
69 * pixelref, which could tell us at runtime if this check is valid. That would
70 * eliminate the need for this heavy-handed build check.
72 #ifdef SK_DISABLE_PIXELREF_LOCKCOUNT_BALANCE_CHECK
73 class AutoCheckLockCountBalance {
75 AutoCheckLockCountBalance(const SkBitmap&) { /* do nothing */ }
78 class AutoCheckLockCountBalance {
80 AutoCheckLockCountBalance(const SkBitmap& bm) : fPixelRef(bm.pixelRef()) {
81 fLockCount = fPixelRef ? fPixelRef->getLockCount() : 0;
83 ~AutoCheckLockCountBalance() {
84 const int count = fPixelRef ? fPixelRef->getLockCount() : 0;
85 SkASSERT(count == fLockCount);
89 const SkPixelRef* fPixelRef;
94 #define CHECK_LOCKCOUNT_BALANCE(bitmap) AutoCheckLockCountBalance clcb(bitmap)
97 #define CHECK_LOCKCOUNT_BALANCE(bitmap)
100 typedef SkTLazy<SkPaint> SkLazyPaint;
102 void SkCanvas::predrawNotify() {
104 fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode);
108 ///////////////////////////////////////////////////////////////////////////////
110 /* This is the record we keep for each SkBaseDevice that the user installs.
111 The clip/matrix/proc are fields that reflect the top of the save/restore
112 stack. Whenever the canvas changes, it marks a dirty flag, and then before
113 these are used (assuming we're not on a layer) we rebuild these cache
114 values: they reflect the top of the save stack, but translated and clipped
115 by the device's XY offset and bitmap-bounds.
119 SkBaseDevice* fDevice;
121 const SkMatrix* fMatrix;
122 SkPaint* fPaint; // may be null (in the future)
124 DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas)
126 if (NULL != device) {
128 device->onAttachToCanvas(canvas);
131 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
135 if (NULL != fDevice) {
136 fDevice->onDetachFromCanvas();
142 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
143 const SkClipStack& clipStack, SkRasterClip* updateClip) {
144 int x = fDevice->getOrigin().x();
145 int y = fDevice->getOrigin().y();
146 int width = fDevice->width();
147 int height = fDevice->height();
150 fMatrix = &totalMatrix;
153 fMatrixStorage = totalMatrix;
154 fMatrixStorage.postTranslate(SkIntToScalar(-x),
156 fMatrix = &fMatrixStorage;
158 totalClip.translate(-x, -y, &fClip);
161 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
163 // intersect clip, but don't translate it (yet)
166 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
167 SkRegion::kDifference_Op);
170 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
173 if (!fClip.isEmpty()) {
175 deviceR.set(0, 0, width, height);
176 SkASSERT(deviceR.contains(fClip.getBounds()));
182 SkMatrix fMatrixStorage;
185 /* This is the record we keep for each save/restore level in the stack.
186 Since a level optionally copies the matrix and/or stack, we have pointers
187 for these fields. If the value is copied for this level, the copy is
188 stored in the ...Storage field, and the pointer points to that. If the
189 value is not copied for this level, we ignore ...Storage, and just point
190 at the corresponding value in the previous level in the stack.
192 class SkCanvas::MCRec {
195 SkMatrix* fMatrix; // points to either fMatrixStorage or prev MCRec
196 SkRasterClip* fRasterClip; // points to either fRegionStorage or prev MCRec
197 SkDrawFilter* fFilter; // the current filter (or null)
200 /* If there are any layers in the stack, this points to the top-most
201 one that is at or below this level in the stack (so we know what
202 bitmap/device to draw into from this level. This value is NOT
203 reference counted, since the real owner is either our fLayer field,
204 or a previous one in a lower level.)
208 MCRec(const MCRec* prev, int flags) : fFlags(flags) {
210 if (flags & SkCanvas::kMatrix_SaveFlag) {
211 fMatrixStorage = *prev->fMatrix;
212 fMatrix = &fMatrixStorage;
214 fMatrix = prev->fMatrix;
217 if (flags & SkCanvas::kClip_SaveFlag) {
218 fRasterClipStorage = *prev->fRasterClip;
219 fRasterClip = &fRasterClipStorage;
221 fRasterClip = prev->fRasterClip;
224 fFilter = prev->fFilter;
227 fTopLayer = prev->fTopLayer;
229 fMatrixStorage.reset();
231 fMatrix = &fMatrixStorage;
232 fRasterClip = &fRasterClipStorage;
238 // don't bother initializing fNext
242 SkSafeUnref(fFilter);
248 SkMatrix fMatrixStorage;
249 SkRasterClip fRasterClipStorage;
252 class SkDrawIter : public SkDraw {
254 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
255 canvas = canvas->canvasForDrawIter();
257 canvas->updateDeviceCMCache();
259 fClipStack = &canvas->fClipStack;
260 fBounder = canvas->getBounder();
261 fCurrLayer = canvas->fMCRec->fTopLayer;
262 fSkipEmptyClips = skipEmptyClips;
266 // skip over recs with empty clips
267 if (fSkipEmptyClips) {
268 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
269 fCurrLayer = fCurrLayer->fNext;
273 const DeviceCM* rec = fCurrLayer;
274 if (rec && rec->fDevice) {
276 fMatrix = rec->fMatrix;
277 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
279 fDevice = rec->fDevice;
280 fBitmap = &fDevice->accessBitmap(true);
281 fPaint = rec->fPaint;
282 SkDEBUGCODE(this->validate();)
284 fCurrLayer = rec->fNext;
286 fBounder->setClip(fClip);
288 // fCurrLayer may be NULL now
295 SkBaseDevice* getDevice() const { return fDevice; }
296 int getX() const { return fDevice->getOrigin().x(); }
297 int getY() const { return fDevice->getOrigin().y(); }
298 const SkMatrix& getMatrix() const { return *fMatrix; }
299 const SkRegion& getClip() const { return *fClip; }
300 const SkPaint* getPaint() const { return fPaint; }
304 const DeviceCM* fCurrLayer;
305 const SkPaint* fPaint; // May be null.
306 SkBool8 fSkipEmptyClips;
308 typedef SkDraw INHERITED;
311 /////////////////////////////////////////////////////////////////////////////
313 class AutoDrawLooper {
315 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint,
316 bool skipLayerForImageFilter = false,
317 const SkRect* bounds = NULL) : fOrigPaint(paint) {
319 fFilter = canvas->getDrawFilter();
321 fSaveCount = canvas->getSaveCount();
322 fDoClearImageFilter = false;
325 if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
327 tmp.setImageFilter(fOrigPaint.getImageFilter());
328 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
329 true, SkCanvas::kFullLayer_SaveLayerStrategy);
330 // we'll clear the imageFilter for the actual draws in next(), so
331 // it will only be applied during the restore().
332 fDoClearImageFilter = true;
335 if (SkDrawLooper* looper = paint.getLooper()) {
336 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
337 looper->contextSize());
338 fLooperContext = looper->createContext(canvas, buffer);
341 fLooperContext = NULL;
342 // can we be marked as simple?
343 fIsSimple = !fFilter && !fDoClearImageFilter;
348 if (fDoClearImageFilter) {
349 fCanvas->internalRestore();
351 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
354 const SkPaint& paint() const {
359 bool next(SkDrawFilter::Type drawType) {
362 } else if (fIsSimple) {
364 fPaint = &fOrigPaint;
365 return !fPaint->nothingToDraw();
367 return this->doNext(drawType);
372 SkLazyPaint fLazyPaint;
374 const SkPaint& fOrigPaint;
375 SkDrawFilter* fFilter;
376 const SkPaint* fPaint;
378 bool fDoClearImageFilter;
381 SkDrawLooper::Context* fLooperContext;
382 SkSmallAllocator<1, 32> fLooperContextAllocator;
384 bool doNext(SkDrawFilter::Type drawType);
387 bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
389 SkASSERT(!fIsSimple);
390 SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
392 SkPaint* paint = fLazyPaint.set(fOrigPaint);
394 if (fDoClearImageFilter) {
395 paint->setImageFilter(NULL);
398 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
403 if (!fFilter->filter(paint, drawType)) {
407 if (NULL == fLooperContext) {
408 // no looper means we only draw once
414 // if we only came in here for the imagefilter, mark us as done
415 if (!fLooperContext && !fFilter) {
419 // call this after any possible paint modifiers
420 if (fPaint->nothingToDraw()) {
427 /* Stack helper for managing a SkBounder. In the destructor, if we were
428 given a bounder, we call its commit() method, signifying that we are
429 done accumulating bounds for that draw.
431 class SkAutoBounderCommit {
433 SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {}
434 ~SkAutoBounderCommit() {
435 if (NULL != fBounder) {
442 #define SkAutoBounderCommit(...) SK_REQUIRE_LOCAL_VAR(SkAutoBounderCommit)
444 #include "SkColorPriv.h"
446 ////////// macros to place around the internal draw calls //////////////////
448 #define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
449 this->predrawNotify(); \
450 AutoDrawLooper looper(this, paint, true); \
451 while (looper.next(type)) { \
452 SkAutoBounderCommit ac(fBounder); \
453 SkDrawIter iter(this);
455 #define LOOPER_BEGIN(paint, type, bounds) \
456 this->predrawNotify(); \
457 AutoDrawLooper looper(this, paint, false, bounds); \
458 while (looper.next(type)) { \
459 SkAutoBounderCommit ac(fBounder); \
460 SkDrawIter iter(this);
464 ////////////////////////////////////////////////////////////////////////////
466 SkBaseDevice* SkCanvas::init(SkBaseDevice* device) {
468 fCachedLocalClipBounds.setEmpty();
469 fCachedLocalClipBoundsDirty = true;
470 fAllowSoftClip = true;
471 fAllowSimplifyClip = false;
472 fDeviceCMDirty = false;
477 fMCRec = (MCRec*)fMCStack.push_back();
478 new (fMCRec) MCRec(NULL, 0);
480 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL));
481 fMCRec->fTopLayer = fMCRec->fLayer;
485 return this->setRootDevice(device);
489 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
496 SkCanvas::SkCanvas(int width, int height)
497 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
502 bitmap.setConfig(SkImageInfo::MakeUnknown(width, height));
503 this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref();
506 SkCanvas::SkCanvas(SkBaseDevice* device)
507 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
514 SkCanvas::SkCanvas(const SkBitmap& bitmap)
515 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
519 this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref();
522 SkCanvas::~SkCanvas() {
523 // free up the contents of our deque
524 this->restoreToCount(1); // restore everything but the last
525 SkASSERT(0 == fSaveLayerCount);
527 this->internalRestore(); // restore the last, since we're going away
529 SkSafeUnref(fBounder);
535 SkBounder* SkCanvas::setBounder(SkBounder* bounder) {
536 SkRefCnt_SafeAssign(fBounder, bounder);
540 SkDrawFilter* SkCanvas::getDrawFilter() const {
541 return fMCRec->fFilter;
544 SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
545 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
549 SkMetaData& SkCanvas::getMetaData() {
550 // metadata users are rare, so we lazily allocate it. If that changes we
551 // can decide to just make it a field in the device (rather than a ptr)
552 if (NULL == fMetaData) {
553 fMetaData = new SkMetaData;
558 ///////////////////////////////////////////////////////////////////////////////
560 void SkCanvas::flush() {
561 SkBaseDevice* device = this->getDevice();
567 SkISize SkCanvas::getTopLayerSize() const {
568 SkBaseDevice* d = this->getTopDevice();
569 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
572 SkIPoint SkCanvas::getTopLayerOrigin() const {
573 SkBaseDevice* d = this->getTopDevice();
574 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
577 SkISize SkCanvas::getBaseLayerSize() const {
578 SkBaseDevice* d = this->getDevice();
579 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
582 SkBaseDevice* SkCanvas::getDevice() const {
583 // return root device
584 MCRec* rec = (MCRec*) fMCStack.front();
585 SkASSERT(rec && rec->fLayer);
586 return rec->fLayer->fDevice;
589 SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
590 if (updateMatrixClip) {
591 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
593 return fMCRec->fTopLayer->fDevice;
596 SkBaseDevice* SkCanvas::setRootDevice(SkBaseDevice* device) {
597 // return root device
598 SkDeque::F2BIter iter(fMCStack);
599 MCRec* rec = (MCRec*)iter.next();
600 SkASSERT(rec && rec->fLayer);
601 SkBaseDevice* rootDevice = rec->fLayer->fDevice;
603 if (rootDevice == device) {
608 device->onAttachToCanvas(this);
611 rootDevice->onDetachFromCanvas();
614 SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
617 fDeviceCMDirty = true;
619 /* Now we update our initial region to have the bounds of the new device,
620 and then intersect all of the clips in our stack with these bounds,
621 to ensure that we can't draw outside of the device's bounds (and trash
624 NOTE: this is only a partial-fix, since if the new device is larger than
625 the previous one, we don't know how to "enlarge" the clips in our stack,
626 so drawing may be artificially restricted. Without keeping a history of
627 all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
628 reconstruct the correct clips, so this approximation will have to do.
629 The caller really needs to restore() back to the base if they want to
630 accurately take advantage of the new device bounds.
635 bounds.set(0, 0, device->width(), device->height());
639 // now jam our 1st clip to be bounds, and intersect the rest with that
640 rec->fRasterClip->setRect(bounds);
641 while ((rec = (MCRec*)iter.next()) != NULL) {
642 (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op);
648 bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
649 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
653 bool weAllocated = false;
654 if (NULL == bitmap->pixelRef()) {
655 if (!bitmap->allocPixels()) {
661 SkBitmap bm(*bitmap);
663 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
668 bitmap->setPixelRef(NULL);
673 bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
675 const SkISize size = this->getBaseLayerSize();
676 if (!r.intersect(0, 0, size.width(), size.height())) {
681 if (!bitmap->allocN32Pixels(r.width(), r.height())) {
682 // bitmap will already be reset.
685 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
692 bool SkCanvas::readPixels(const SkImageInfo& origInfo, void* dstP, size_t rowBytes, int x, int y) {
693 switch (origInfo.colorType()) {
694 case kUnknown_SkColorType:
695 case kIndex_8_SkColorType:
700 if (NULL == dstP || rowBytes < origInfo.minRowBytes()) {
703 if (0 == origInfo.width() || 0 == origInfo.height()) {
707 SkBaseDevice* device = this->getDevice();
712 const SkISize size = this->getBaseLayerSize();
713 SkIRect srcR = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
714 if (!srcR.intersect(0, 0, size.width(), size.height())) {
718 SkImageInfo info = origInfo;
719 // the intersect may have shrunk info's logical size
720 info.fWidth = srcR.width();
721 info.fHeight = srcR.height();
723 // if x or y are negative, then we have to adjust pixels
730 // here x,y are either 0 or negative
731 dstP = ((char*)dstP - y * rowBytes - x * info.bytesPerPixel());
733 // The device can assert that the requested area is always contained in its bounds
734 return device->readPixels(info, dstP, rowBytes, srcR.x(), srcR.y());
737 bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
738 if (bitmap.getTexture()) {
743 if (bm.getPixels()) {
744 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
749 bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
751 switch (origInfo.colorType()) {
752 case kUnknown_SkColorType:
753 case kIndex_8_SkColorType:
758 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
762 const SkISize size = this->getBaseLayerSize();
763 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
764 if (!target.intersect(0, 0, size.width(), size.height())) {
768 SkBaseDevice* device = this->getDevice();
773 SkImageInfo info = origInfo;
774 // the intersect may have shrunk info's logical size
775 info.fWidth = target.width();
776 info.fHeight = target.height();
778 // if x or y are negative, then we have to adjust pixels
785 // here x,y are either 0 or negative
786 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
788 // The device can assert that the requested area is always contained in its bounds
789 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
792 SkCanvas* SkCanvas::canvasForDrawIter() {
796 //////////////////////////////////////////////////////////////////////////////
798 void SkCanvas::updateDeviceCMCache() {
799 if (fDeviceCMDirty) {
800 const SkMatrix& totalMatrix = this->getTotalMatrix();
801 const SkRasterClip& totalClip = *fMCRec->fRasterClip;
802 DeviceCM* layer = fMCRec->fTopLayer;
804 if (NULL == layer->fNext) { // only one layer
805 layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
807 SkRasterClip clip(totalClip);
809 layer->updateMC(totalMatrix, clip, fClipStack, &clip);
810 } while ((layer = layer->fNext) != NULL);
812 fDeviceCMDirty = false;
816 ///////////////////////////////////////////////////////////////////////////////
818 int SkCanvas::internalSave(SaveFlags flags) {
819 int saveCount = this->getSaveCount(); // record this before the actual save
821 MCRec* newTop = (MCRec*)fMCStack.push_back();
822 new (newTop) MCRec(fMCRec, flags); // balanced in restore()
826 if (SkCanvas::kClip_SaveFlag & flags) {
833 void SkCanvas::willSave(SaveFlags) {
834 // Do nothing. Subclasses may do something.
837 int SkCanvas::save() {
838 this->willSave(kMatrixClip_SaveFlag);
839 return this->internalSave(kMatrixClip_SaveFlag);
842 int SkCanvas::save(SaveFlags flags) {
843 this->willSave(flags);
845 return this->internalSave(flags);
848 static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
849 #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
850 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
856 bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
857 SkIRect* intersection, const SkImageFilter* imageFilter) {
859 SkRegion::Op op = SkRegion::kIntersect_Op;
860 if (!this->getClipDeviceBounds(&clipBounds)) {
865 imageFilter->filterBounds(clipBounds, *fMCRec->fMatrix, &clipBounds);
866 // Filters may grow the bounds beyond the device bounds.
867 op = SkRegion::kReplace_Op;
870 if (NULL != bounds) {
873 this->getTotalMatrix().mapRect(&r, *bounds);
875 // early exit if the layer's bounds are clipped out
876 if (!ir.intersect(clipBounds)) {
877 if (bounds_affects_clip(flags)) {
878 fMCRec->fRasterClip->setEmpty();
882 } else { // no user bounds, so just use the clip
886 if (bounds_affects_clip(flags)) {
887 fClipStack.clipDevRect(ir, op);
888 // early exit if the clip is now empty
889 if (!fMCRec->fRasterClip->op(ir, op)) {
900 SkCanvas::SaveLayerStrategy SkCanvas::willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) {
902 // Do nothing. Subclasses may do something.
903 return kFullLayer_SaveLayerStrategy;
906 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
907 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
908 return this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, false, strategy);
911 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
913 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
914 return this->internalSaveLayer(bounds, paint, flags, false, strategy);
917 static SkBaseDevice* create_compatible_device(SkCanvas* canvas,
918 const SkImageInfo& info) {
919 SkBaseDevice* device = canvas->getDevice();
920 return device ? device->createCompatibleDevice(info) : NULL;
923 int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
924 bool justForImageFilter, SaveLayerStrategy strategy) {
925 #ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
926 flags = (SaveFlags)(flags | kClipToLayer_SaveFlag);
929 // do this before we create the layer. We don't call the public save() since
930 // that would invoke a possibly overridden virtual
931 int count = this->internalSave(flags);
933 fDeviceCMDirty = true;
936 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
940 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
941 // the clipRectBounds() call above?
942 if (kNoLayer_SaveLayerStrategy == strategy) {
946 // Kill the imagefilter if our device doesn't allow it
948 if (paint && paint->getImageFilter()) {
949 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
950 if (justForImageFilter) {
951 // early exit if the layer was just for the imageFilter
954 SkPaint* p = lazyP.set(*paint);
955 p->setImageFilter(NULL);
960 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
961 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
962 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
964 SkBaseDevice* device;
965 if (paint && paint->getImageFilter()) {
966 device = create_compatible_device(this, info);
968 device = this->createLayerDevice(info);
970 if (NULL == device) {
971 SkDebugf("Unable to create device for layer.");
975 device->setOrigin(ir.fLeft, ir.fTop);
976 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint, this));
979 layer->fNext = fMCRec->fTopLayer;
980 fMCRec->fLayer = layer;
981 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
983 fSaveLayerCount += 1;
987 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
988 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
991 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
994 return this->saveLayer(bounds, NULL, flags);
997 tmpPaint.setAlpha(alpha);
998 return this->saveLayer(bounds, &tmpPaint, flags);
1002 void SkCanvas::willRestore() {
1003 // Do nothing. Subclasses may do something.
1006 void SkCanvas::restore() {
1007 // check for underflow
1008 if (fMCStack.count() > 1) {
1009 this->willRestore();
1010 this->internalRestore();
1014 void SkCanvas::internalRestore() {
1015 SkASSERT(fMCStack.count() != 0);
1017 fDeviceCMDirty = true;
1018 fCachedLocalClipBoundsDirty = true;
1020 if (SkCanvas::kClip_SaveFlag & fMCRec->fFlags) {
1021 fClipStack.restore();
1024 // reserve our layer (if any)
1025 DeviceCM* layer = fMCRec->fLayer; // may be null
1026 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1027 fMCRec->fLayer = NULL;
1029 // now do the normal restore()
1030 fMCRec->~MCRec(); // balanced in save()
1031 fMCStack.pop_back();
1032 fMCRec = (MCRec*)fMCStack.back();
1034 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1035 since if we're being recorded, we don't want to record this (the
1036 recorder will have already recorded the restore).
1038 if (NULL != layer) {
1040 const SkIPoint& origin = layer->fDevice->getOrigin();
1041 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
1043 // reset this, since internalDrawDevice will have set it to true
1044 fDeviceCMDirty = true;
1046 SkASSERT(fSaveLayerCount > 0);
1047 fSaveLayerCount -= 1;
1053 int SkCanvas::getSaveCount() const {
1054 return fMCStack.count();
1057 void SkCanvas::restoreToCount(int count) {
1063 int n = this->getSaveCount() - count;
1064 for (int i = 0; i < n; ++i) {
1069 bool SkCanvas::isDrawingToLayer() const {
1070 return fSaveLayerCount > 0;
1073 SkSurface* SkCanvas::newSurface(const SkImageInfo& info) {
1074 return this->onNewSurface(info);
1077 SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info) {
1078 SkBaseDevice* dev = this->getDevice();
1079 return dev ? dev->newSurface(info) : NULL;
1082 SkImageInfo SkCanvas::imageInfo() const {
1083 SkBaseDevice* dev = this->getDevice();
1085 return dev->imageInfo();
1087 return SkImageInfo::MakeUnknown(0, 0);
1091 const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1092 return this->onPeekPixels(info, rowBytes);
1095 const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1096 SkBaseDevice* dev = this->getDevice();
1097 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1100 void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1101 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1102 if (pixels && origin) {
1103 *origin = this->getTopDevice(false)->getOrigin();
1108 void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1109 SkBaseDevice* dev = this->getTopDevice();
1110 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1113 SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1114 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1115 if (NULL == fAddr) {
1116 fInfo = canvas->imageInfo();
1117 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.allocPixels(fInfo)) {
1118 return; // failure, fAddr is NULL
1120 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1121 return; // failure, fAddr is NULL
1123 fAddr = fBitmap.getPixels();
1124 fRowBytes = fBitmap.rowBytes();
1126 SkASSERT(fAddr); // success
1129 bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1131 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes,
1139 void SkCanvas::onPushCull(const SkRect& cullRect) {
1140 // do nothing. Subclasses may do something
1143 void SkCanvas::onPopCull() {
1144 // do nothing. Subclasses may do something
1147 /////////////////////////////////////////////////////////////////////////////
1149 // Ensure that cull rects are monotonically nested in device space.
1150 void SkCanvas::validateCull(const SkIRect& devCull) {
1151 if (fCullStack.isEmpty()
1152 || devCull.isEmpty()
1153 || fCullStack.top().contains(devCull)) {
1157 SkDEBUGF(("Invalid cull: [%d %d %d %d] (previous cull: [%d %d %d %d])\n",
1158 devCull.x(), devCull.y(), devCull.right(), devCull.bottom(),
1159 fCullStack.top().x(), fCullStack.top().y(),
1160 fCullStack.top().right(), fCullStack.top().bottom()));
1162 #ifdef ASSERT_NESTED_CULLING
1163 SkDEBUGFAIL("Invalid cull.");
1168 void SkCanvas::pushCull(const SkRect& cullRect) {
1170 this->onPushCull(cullRect);
1173 // Map the cull rect into device space.
1175 this->getTotalMatrix().mapRect(&mappedCull, cullRect);
1177 // Take clipping into account.
1178 SkIRect devClip, devCull;
1179 mappedCull.roundOut(&devCull);
1180 this->getClipDeviceBounds(&devClip);
1181 if (!devCull.intersect(devClip)) {
1185 this->validateCull(devCull);
1186 fCullStack.push(devCull); // balanced in popCull
1190 void SkCanvas::popCull() {
1191 SkASSERT(fCullStack.count() == fCullCount);
1193 if (fCullCount > 0) {
1197 SkDEBUGCODE(fCullStack.pop());
1201 /////////////////////////////////////////////////////////////////////////////
1203 void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
1204 const SkMatrix& matrix, const SkPaint* paint) {
1205 if (bitmap.drawsNothing()) {
1210 if (NULL == paint) {
1211 paint = lazy.init();
1214 SkDEBUGCODE(bitmap.validate();)
1215 CHECK_LOCKCOUNT_BALANCE(bitmap);
1218 const SkRect* bounds = NULL;
1219 if (paint && paint->canComputeFastBounds()) {
1220 bitmap.getBounds(&storage);
1221 matrix.mapRect(&storage);
1222 bounds = &paint->computeFastBounds(storage, &storage);
1225 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
1227 while (iter.next()) {
1228 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1234 void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
1235 const SkPaint* paint) {
1237 if (NULL == paint) {
1238 tmp.setDither(true);
1242 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
1243 while (iter.next()) {
1244 SkBaseDevice* dstDev = iter.fDevice;
1245 paint = &looper.paint();
1246 SkImageFilter* filter = paint->getImageFilter();
1247 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1248 if (filter && !dstDev->canHandleImageFilter(filter)) {
1249 SkDeviceImageFilterProxy proxy(dstDev);
1251 SkIPoint offset = SkIPoint::Make(0, 0);
1252 const SkBitmap& src = srcDev->accessBitmap(false);
1253 SkMatrix matrix = *iter.fMatrix;
1254 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
1255 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
1256 SkImageFilter::Cache* cache = SkImageFilter::GetExternalCache();
1257 SkAutoUnref aur(NULL);
1259 cache = SkImageFilter::Cache::Create();
1262 SkImageFilter::Context ctx(matrix, clipBounds, cache);
1263 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
1264 SkPaint tmpUnfiltered(*paint);
1265 tmpUnfiltered.setImageFilter(NULL);
1266 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1270 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
1276 void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
1277 const SkPaint* paint) {
1278 if (bitmap.drawsNothing()) {
1281 SkDEBUGCODE(bitmap.validate();)
1282 CHECK_LOCKCOUNT_BALANCE(bitmap);
1285 if (NULL == paint) {
1289 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
1291 while (iter.next()) {
1292 paint = &looper.paint();
1293 SkImageFilter* filter = paint->getImageFilter();
1294 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1295 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
1296 SkDeviceImageFilterProxy proxy(iter.fDevice);
1298 SkIPoint offset = SkIPoint::Make(0, 0);
1299 SkMatrix matrix = *iter.fMatrix;
1300 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
1301 SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1302 SkImageFilter::Cache* cache = SkImageFilter::GetExternalCache();
1303 SkAutoUnref aur(NULL);
1305 cache = SkImageFilter::Cache::Create();
1308 SkImageFilter::Context ctx(matrix, clipBounds, cache);
1309 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
1310 SkPaint tmpUnfiltered(*paint);
1311 tmpUnfiltered.setImageFilter(NULL);
1312 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1316 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1322 /////////////////////////////////////////////////////////////////////////////
1323 void SkCanvas::translate(SkScalar dx, SkScalar dy) {
1325 m.setTranslate(dx, dy);
1329 void SkCanvas::scale(SkScalar sx, SkScalar sy) {
1335 void SkCanvas::rotate(SkScalar degrees) {
1337 m.setRotate(degrees);
1341 void SkCanvas::skew(SkScalar sx, SkScalar sy) {
1347 void SkCanvas::didConcat(const SkMatrix&) {
1348 // Do nothing. Subclasses may do something.
1351 void SkCanvas::concat(const SkMatrix& matrix) {
1352 if (matrix.isIdentity()) {
1356 fDeviceCMDirty = true;
1357 fCachedLocalClipBoundsDirty = true;
1358 fMCRec->fMatrix->preConcat(matrix);
1360 this->didConcat(matrix);
1363 void SkCanvas::didSetMatrix(const SkMatrix&) {
1364 // Do nothing. Subclasses may do something.
1367 void SkCanvas::setMatrix(const SkMatrix& matrix) {
1368 fDeviceCMDirty = true;
1369 fCachedLocalClipBoundsDirty = true;
1370 *fMCRec->fMatrix = matrix;
1371 this->didSetMatrix(matrix);
1374 void SkCanvas::resetMatrix() {
1378 this->setMatrix(matrix);
1381 //////////////////////////////////////////////////////////////////////////////
1383 void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
1384 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1385 this->onClipRect(rect, op, edgeStyle);
1388 void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1389 #ifdef SK_ENABLE_CLIP_QUICKREJECT
1390 if (SkRegion::kIntersect_Op == op) {
1391 if (fMCRec->fRasterClip->isEmpty()) {
1395 if (this->quickReject(rect)) {
1396 fDeviceCMDirty = true;
1397 fCachedLocalClipBoundsDirty = true;
1399 fClipStack.clipEmpty();
1400 return fMCRec->fRasterClip->setEmpty();
1405 AutoValidateClip avc(this);
1407 fDeviceCMDirty = true;
1408 fCachedLocalClipBoundsDirty = true;
1409 if (!fAllowSoftClip) {
1410 edgeStyle = kHard_ClipEdgeStyle;
1413 if (fMCRec->fMatrix->rectStaysRect()) {
1414 // for these simpler matrices, we can stay a rect even after applying
1415 // the matrix. This means we don't have to a) make a path, and b) tell
1416 // the region code to scan-convert the path, only to discover that it
1417 // is really just a rect.
1420 fMCRec->fMatrix->mapRect(&r, rect);
1421 fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
1422 fMCRec->fRasterClip->op(r, op, kSoft_ClipEdgeStyle == edgeStyle);
1424 // since we're rotated or some such thing, we convert the rect to a path
1425 // and clip against that, since it can handle any matrix. However, to
1426 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1427 // we explicitly call "our" version of clipPath.
1431 this->SkCanvas::onClipPath(path, op, edgeStyle);
1435 static void clip_path_helper(const SkCanvas* canvas, SkRasterClip* currClip,
1436 const SkPath& devPath, SkRegion::Op op, bool doAA) {
1437 // base is used to limit the size (and therefore memory allocation) of the
1438 // region that results from scan converting devPath.
1441 if (SkRegion::kIntersect_Op == op) {
1442 // since we are intersect, we can do better (tighter) with currRgn's
1443 // bounds, than just using the device. However, if currRgn is complex,
1444 // our region blitter may hork, so we do that case in two steps.
1445 if (currClip->isRect()) {
1446 // FIXME: we should also be able to do this when currClip->isBW(),
1447 // but relaxing the test above triggers GM asserts in
1448 // SkRgnBuilder::blitH(). We need to investigate what's going on.
1449 currClip->setPath(devPath, currClip->bwRgn(), doAA);
1451 base.setRect(currClip->getBounds());
1453 clip.setPath(devPath, base, doAA);
1454 currClip->op(clip, op);
1457 const SkBaseDevice* device = canvas->getDevice();
1459 currClip->setEmpty();
1463 base.setRect(0, 0, device->width(), device->height());
1465 if (SkRegion::kReplace_Op == op) {
1466 currClip->setPath(devPath, base, doAA);
1469 clip.setPath(devPath, base, doAA);
1470 currClip->op(clip, op);
1475 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
1476 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1477 if (rrect.isRect()) {
1478 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1480 this->onClipRRect(rrect, op, edgeStyle);
1484 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1485 SkRRect transformedRRect;
1486 if (rrect.transform(*fMCRec->fMatrix, &transformedRRect)) {
1487 AutoValidateClip avc(this);
1489 fDeviceCMDirty = true;
1490 fCachedLocalClipBoundsDirty = true;
1491 if (!fAllowSoftClip) {
1492 edgeStyle = kHard_ClipEdgeStyle;
1495 fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
1498 devPath.addRRect(transformedRRect);
1500 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
1505 path.addRRect(rrect);
1506 // call the non-virtual version
1507 this->SkCanvas::onClipPath(path, op, edgeStyle);
1510 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
1511 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1513 if (!path.isInverseFillType() && path.isRect(&r)) {
1514 this->onClipRect(r, op, edgeStyle);
1516 this->onClipPath(path, op, edgeStyle);
1520 void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1521 #ifdef SK_ENABLE_CLIP_QUICKREJECT
1522 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
1523 if (fMCRec->fRasterClip->isEmpty()) {
1527 if (this->quickReject(path.getBounds())) {
1528 fDeviceCMDirty = true;
1529 fCachedLocalClipBoundsDirty = true;
1531 fClipStack.clipEmpty();
1532 return fMCRec->fRasterClip->setEmpty();
1537 AutoValidateClip avc(this);
1539 fDeviceCMDirty = true;
1540 fCachedLocalClipBoundsDirty = true;
1541 if (!fAllowSoftClip) {
1542 edgeStyle = kHard_ClipEdgeStyle;
1546 path.transform(*fMCRec->fMatrix, &devPath);
1548 // Check if the transfomation, or the original path itself
1549 // made us empty. Note this can also happen if we contained NaN
1550 // values. computing the bounds detects this, and will set our
1551 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1552 if (devPath.getBounds().isEmpty()) {
1553 // resetting the path will remove any NaN or other wanky values
1554 // that might upset our scan converter.
1558 // if we called path.swap() we could avoid a deep copy of this path
1559 fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
1561 if (fAllowSimplifyClip) {
1563 devPath.setFillType(SkPath::kInverseEvenOdd_FillType);
1564 const SkClipStack* clipStack = getClipStack();
1565 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
1566 const SkClipStack::Element* element;
1567 while ((element = iter.next())) {
1568 SkClipStack::Element::Type type = element->getType();
1569 if (type == SkClipStack::Element::kEmpty_Type) {
1573 element->asPath(&operand);
1574 SkRegion::Op elementOp = element->getOp();
1575 if (elementOp == SkRegion::kReplace_Op) {
1578 Op(devPath, operand, (SkPathOp) elementOp, &devPath);
1580 // if the prev and curr clips disagree about aa -vs- not, favor the aa request.
1581 // perhaps we need an API change to avoid this sort of mixed-signals about
1583 if (element->isAA()) {
1584 edgeStyle = kSoft_ClipEdgeStyle;
1587 op = SkRegion::kReplace_Op;
1590 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, edgeStyle);
1593 void SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op,
1594 bool inverseFilled) {
1595 // This is for updating the clip conservatively using only bounds
1598 // The current clip must contain the true clip. The true
1599 // clip is the clip that would have normally been computed
1600 // by calls to clipPath and clipRRect
1602 // Keep the current clip as small as possible without
1603 // breaking the contract, using only clip bounding rectangles
1604 // (for performance).
1606 // N.B.: This *never* calls back through a virtual on canvas, so subclasses
1607 // don't have to worry about getting caught in a loop. Thus anywhere
1608 // we call a virtual method, we explicitly prefix it with
1609 // SkCanvas:: to be sure to call the base-class.
1611 if (inverseFilled) {
1613 case SkRegion::kIntersect_Op:
1614 case SkRegion::kDifference_Op:
1615 // These ops can only shrink the current clip. So leaving
1616 // the clip unchanged conservatively respects the contract.
1618 case SkRegion::kUnion_Op:
1619 case SkRegion::kReplace_Op:
1620 case SkRegion::kReverseDifference_Op:
1621 case SkRegion::kXOR_Op: {
1622 // These ops can grow the current clip up to the extents of
1623 // the input clip, which is inverse filled, so we just set
1624 // the current clip to the device bounds.
1625 SkRect deviceBounds;
1626 SkIRect deviceIBounds;
1627 this->getDevice()->getGlobalBounds(&deviceIBounds);
1628 deviceBounds = SkRect::Make(deviceIBounds);
1630 // set the clip in device space
1631 SkMatrix savedMatrix = this->getTotalMatrix();
1632 this->SkCanvas::setMatrix(SkMatrix::I());
1633 this->SkCanvas::onClipRect(deviceBounds, SkRegion::kReplace_Op,
1634 kHard_ClipEdgeStyle);
1635 this->setMatrix(savedMatrix);
1639 SkASSERT(0); // unhandled op?
1642 // Not inverse filled
1644 case SkRegion::kIntersect_Op:
1645 case SkRegion::kUnion_Op:
1646 case SkRegion::kReplace_Op:
1647 this->SkCanvas::onClipRect(bounds, op, kHard_ClipEdgeStyle);
1649 case SkRegion::kDifference_Op:
1650 // Difference can only shrink the current clip.
1651 // Leaving clip unchanged conservatively fullfills the contract.
1653 case SkRegion::kReverseDifference_Op:
1654 // To reverse, we swap in the bounds with a replace op.
1655 // As with difference, leave it unchanged.
1656 this->SkCanvas::onClipRect(bounds, SkRegion::kReplace_Op, kHard_ClipEdgeStyle);
1658 case SkRegion::kXOR_Op:
1659 // Be conservative, based on (A XOR B) always included in (A union B),
1660 // which is always included in (bounds(A) union bounds(B))
1661 this->SkCanvas::onClipRect(bounds, SkRegion::kUnion_Op, kHard_ClipEdgeStyle);
1664 SkASSERT(0); // unhandled op?
1669 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
1670 this->onClipRegion(rgn, op);
1673 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
1674 AutoValidateClip avc(this);
1676 fDeviceCMDirty = true;
1677 fCachedLocalClipBoundsDirty = true;
1679 // todo: signal fClipStack that we have a region, and therefore (I guess)
1680 // we have to ignore it, and use the region directly?
1681 fClipStack.clipDevRect(rgn.getBounds(), op);
1683 fMCRec->fRasterClip->op(rgn, op);
1687 void SkCanvas::validateClip() const {
1688 // construct clipRgn from the clipstack
1689 const SkBaseDevice* device = this->getDevice();
1691 SkASSERT(this->isClipEmpty());
1696 ir.set(0, 0, device->width(), device->height());
1697 SkRasterClip tmpClip(ir);
1699 SkClipStack::B2TIter iter(fClipStack);
1700 const SkClipStack::Element* element;
1701 while ((element = iter.next()) != NULL) {
1702 switch (element->getType()) {
1703 case SkClipStack::Element::kRect_Type:
1704 element->getRect().round(&ir);
1705 tmpClip.op(ir, element->getOp());
1707 case SkClipStack::Element::kEmpty_Type:
1712 element->asPath(&path);
1713 clip_path_helper(this, &tmpClip, path, element->getOp(), element->isAA());
1721 void SkCanvas::replayClips(ClipVisitor* visitor) const {
1722 SkClipStack::B2TIter iter(fClipStack);
1723 const SkClipStack::Element* element;
1725 static const SkRect kEmpty = { 0, 0, 0, 0 };
1726 while ((element = iter.next()) != NULL) {
1727 switch (element->getType()) {
1728 case SkClipStack::Element::kPath_Type:
1729 visitor->clipPath(element->getPath(), element->getOp(), element->isAA());
1731 case SkClipStack::Element::kRRect_Type:
1732 visitor->clipRRect(element->getRRect(), element->getOp(), element->isAA());
1734 case SkClipStack::Element::kRect_Type:
1735 visitor->clipRect(element->getRect(), element->getOp(), element->isAA());
1737 case SkClipStack::Element::kEmpty_Type:
1738 visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false);
1744 ///////////////////////////////////////////////////////////////////////////////
1746 bool SkCanvas::isClipEmpty() const {
1747 return fMCRec->fRasterClip->isEmpty();
1750 bool SkCanvas::isClipRect() const {
1751 return fMCRec->fRasterClip->isRect();
1754 bool SkCanvas::quickReject(const SkRect& rect) const {
1756 if (!rect.isFinite())
1759 if (fMCRec->fRasterClip->isEmpty()) {
1763 if (fMCRec->fMatrix->hasPerspective()) {
1765 fMCRec->fMatrix->mapRect(&dst, rect);
1767 dst.roundOut(&idst);
1768 return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds());
1770 const SkRect& clipR = this->getLocalClipBounds();
1772 // for speed, do the most likely reject compares first
1773 // TODO: should we use | instead, or compare all 4 at once?
1774 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
1777 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
1784 bool SkCanvas::quickReject(const SkPath& path) const {
1785 return path.isEmpty() || this->quickReject(path.getBounds());
1788 bool SkCanvas::getClipBounds(SkRect* bounds) const {
1790 if (!this->getClipDeviceBounds(&ibounds)) {
1795 // if we can't invert the CTM, we can't return local clip bounds
1796 if (!fMCRec->fMatrix->invert(&inverse)) {
1803 if (NULL != bounds) {
1805 // adjust it outwards in case we are antialiasing
1806 const int inset = 1;
1808 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1809 ibounds.fRight + inset, ibounds.fBottom + inset);
1810 inverse.mapRect(bounds, r);
1815 bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
1816 const SkRasterClip& clip = *fMCRec->fRasterClip;
1817 if (clip.isEmpty()) {
1824 if (NULL != bounds) {
1825 *bounds = clip.getBounds();
1830 const SkMatrix& SkCanvas::getTotalMatrix() const {
1831 return *fMCRec->fMatrix;
1834 #ifdef SK_SUPPORT_LEGACY_GETCLIPTYPE
1835 SkCanvas::ClipType SkCanvas::getClipType() const {
1836 if (fMCRec->fRasterClip->isEmpty()) {
1837 return kEmpty_ClipType;
1839 if (fMCRec->fRasterClip->isRect()) {
1840 return kRect_ClipType;
1842 return kComplex_ClipType;
1846 #ifdef SK_SUPPORT_LEGACY_GETTOTALCLIP
1847 const SkRegion& SkCanvas::getTotalClip() const {
1848 return fMCRec->fRasterClip->forceGetBW();
1852 const SkRegion& SkCanvas::internal_private_getTotalClip() const {
1853 return fMCRec->fRasterClip->forceGetBW();
1856 void SkCanvas::internal_private_getTotalClipAsPath(SkPath* path) const {
1859 const SkRegion& rgn = fMCRec->fRasterClip->forceGetBW();
1860 if (rgn.isEmpty()) {
1863 (void)rgn.getBoundaryPath(path);
1866 GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1867 SkBaseDevice* dev = this->getTopDevice();
1868 return dev ? dev->accessRenderTarget() : NULL;
1871 SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) {
1872 SkBaseDevice* device = this->getTopDevice();
1873 return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL;
1876 GrContext* SkCanvas::getGrContext() {
1878 SkBaseDevice* device = this->getTopDevice();
1879 if (NULL != device) {
1880 GrRenderTarget* renderTarget = device->accessRenderTarget();
1881 if (NULL != renderTarget) {
1882 return renderTarget->getContext();
1891 void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1892 const SkPaint& paint) {
1893 if (outer.isEmpty()) {
1896 if (inner.isEmpty()) {
1897 this->drawRRect(outer, paint);
1901 // We don't have this method (yet), but technically this is what we should
1902 // be able to assert...
1903 // SkASSERT(outer.contains(inner));
1905 // For now at least check for containment of bounds
1906 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1908 this->onDrawDRRect(outer, inner, paint);
1911 //////////////////////////////////////////////////////////////////////////////
1912 // These are the virtual drawing methods
1913 //////////////////////////////////////////////////////////////////////////////
1915 void SkCanvas::clear(SkColor color) {
1916 SkDrawIter iter(this);
1917 this->predrawNotify();
1918 while (iter.next()) {
1919 iter.fDevice->clear(color);
1923 void SkCanvas::onDiscard() {
1924 if (NULL != fSurfaceBase) {
1925 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1929 void SkCanvas::drawPaint(const SkPaint& paint) {
1930 this->internalDrawPaint(paint);
1933 void SkCanvas::internalDrawPaint(const SkPaint& paint) {
1934 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
1936 while (iter.next()) {
1937 iter.fDevice->drawPaint(iter, looper.paint());
1943 void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
1944 const SkPaint& paint) {
1945 if ((long)count <= 0) {
1950 const SkRect* bounds = NULL;
1951 if (paint.canComputeFastBounds()) {
1952 // special-case 2 points (common for drawing a single line)
1954 r.set(pts[0], pts[1]);
1956 r.set(pts, SkToInt(count));
1958 bounds = &paint.computeFastStrokeBounds(r, &storage);
1959 if (this->quickReject(*bounds)) {
1964 SkASSERT(pts != NULL);
1966 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
1968 while (iter.next()) {
1969 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
1975 void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1977 const SkRect* bounds = NULL;
1978 if (paint.canComputeFastBounds()) {
1979 bounds = &paint.computeFastBounds(r, &storage);
1980 if (this->quickReject(*bounds)) {
1985 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
1987 while (iter.next()) {
1988 iter.fDevice->drawRect(iter, r, looper.paint());
1994 void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
1996 const SkRect* bounds = NULL;
1997 if (paint.canComputeFastBounds()) {
1998 bounds = &paint.computeFastBounds(oval, &storage);
1999 if (this->quickReject(*bounds)) {
2004 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2006 while (iter.next()) {
2007 iter.fDevice->drawOval(iter, oval, looper.paint());
2013 void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
2015 const SkRect* bounds = NULL;
2016 if (paint.canComputeFastBounds()) {
2017 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
2018 if (this->quickReject(*bounds)) {
2023 if (rrect.isRect()) {
2024 // call the non-virtual version
2025 this->SkCanvas::drawRect(rrect.getBounds(), paint);
2027 } else if (rrect.isOval()) {
2028 // call the non-virtual version
2029 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2033 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
2035 while (iter.next()) {
2036 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2042 void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2043 const SkPaint& paint) {
2045 const SkRect* bounds = NULL;
2046 if (paint.canComputeFastBounds()) {
2047 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
2048 if (this->quickReject(*bounds)) {
2053 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
2055 while (iter.next()) {
2056 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2062 void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
2063 if (!path.isFinite()) {
2068 const SkRect* bounds = NULL;
2069 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
2070 const SkRect& pathBounds = path.getBounds();
2071 bounds = &paint.computeFastBounds(pathBounds, &storage);
2072 if (this->quickReject(*bounds)) {
2077 const SkRect& r = path.getBounds();
2078 if (r.width() <= 0 && r.height() <= 0) {
2079 if (path.isInverseFillType()) {
2080 this->internalDrawPaint(paint);
2085 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
2087 while (iter.next()) {
2088 iter.fDevice->drawPath(iter, path, looper.paint());
2094 void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
2095 const SkPaint* paint) {
2096 SkDEBUGCODE(bitmap.validate();)
2098 if (NULL == paint || paint->canComputeFastBounds()) {
2101 x + SkIntToScalar(bitmap.width()),
2102 y + SkIntToScalar(bitmap.height())
2105 (void)paint->computeFastBounds(bounds, &bounds);
2107 if (this->quickReject(bounds)) {
2113 matrix.setTranslate(x, y);
2114 this->internalDrawBitmap(bitmap, matrix, paint);
2117 // this one is non-virtual, so it can be called safely by other canvas apis
2118 void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
2119 const SkRect& dst, const SkPaint* paint,
2120 DrawBitmapRectFlags flags) {
2121 if (bitmap.drawsNothing() || dst.isEmpty()) {
2125 CHECK_LOCKCOUNT_BALANCE(bitmap);
2128 const SkRect* bounds = &dst;
2129 if (NULL == paint || paint->canComputeFastBounds()) {
2131 bounds = &paint->computeFastBounds(dst, &storage);
2133 if (this->quickReject(*bounds)) {
2139 if (NULL == paint) {
2140 paint = lazy.init();
2143 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2145 while (iter.next()) {
2146 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
2152 void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
2153 const SkRect& dst, const SkPaint* paint,
2154 DrawBitmapRectFlags flags) {
2155 SkDEBUGCODE(bitmap.validate();)
2156 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
2159 void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
2160 const SkPaint* paint) {
2161 SkDEBUGCODE(bitmap.validate();)
2162 this->internalDrawBitmap(bitmap, matrix, paint);
2165 void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
2166 const SkIRect& center, const SkRect& dst,
2167 const SkPaint* paint) {
2168 if (bitmap.drawsNothing()) {
2171 if (NULL == paint || paint->canComputeFastBounds()) {
2173 const SkRect* bounds = &dst;
2175 bounds = &paint->computeFastBounds(dst, &storage);
2177 if (this->quickReject(*bounds)) {
2182 const int32_t w = bitmap.width();
2183 const int32_t h = bitmap.height();
2186 // pin center to the bounds of the bitmap
2187 c.fLeft = SkMax32(0, center.fLeft);
2188 c.fTop = SkMax32(0, center.fTop);
2189 c.fRight = SkPin32(center.fRight, c.fLeft, w);
2190 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
2192 const SkScalar srcX[4] = {
2193 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
2195 const SkScalar srcY[4] = {
2196 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
2198 SkScalar dstX[4] = {
2199 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2200 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2202 SkScalar dstY[4] = {
2203 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2204 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2207 if (dstX[1] > dstX[2]) {
2208 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2212 if (dstY[1] > dstY[2]) {
2213 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2217 for (int y = 0; y < 3; y++) {
2221 s.fBottom = srcY[y+1];
2223 d.fBottom = dstY[y+1];
2224 for (int x = 0; x < 3; x++) {
2226 s.fRight = srcX[x+1];
2228 d.fRight = dstX[x+1];
2229 this->internalDrawBitmapRect(bitmap, &s, d, paint,
2230 kNone_DrawBitmapRectFlag);
2235 void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
2236 const SkRect& dst, const SkPaint* paint) {
2237 SkDEBUGCODE(bitmap.validate();)
2239 // Need a device entry-point, so gpu can use a mesh
2240 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2243 class SkDeviceFilteredPaint {
2245 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
2246 SkBaseDevice::TextFlags flags;
2247 if (device->filterTextFlags(paint, &flags)) {
2248 SkPaint* newPaint = fLazy.set(paint);
2249 newPaint->setFlags(flags.fFlags);
2250 newPaint->setHinting(flags.fHinting);
2257 const SkPaint& paint() const { return *fPaint; }
2260 const SkPaint* fPaint;
2264 void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2265 const SkRect& r, SkScalar textSize) {
2266 if (paint.getStyle() == SkPaint::kFill_Style) {
2267 draw.fDevice->drawRect(draw, r, paint);
2270 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
2271 draw.fDevice->drawRect(draw, r, p);
2275 void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2276 const char text[], size_t byteLength,
2277 SkScalar x, SkScalar y) {
2278 SkASSERT(byteLength == 0 || text != NULL);
2281 if (text == NULL || byteLength == 0 ||
2282 draw.fClip->isEmpty() ||
2283 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2290 start.set(0, 0); // to avoid warning
2291 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2292 SkPaint::kStrikeThruText_Flag)) {
2293 width = paint.measureText(text, byteLength);
2295 SkScalar offsetX = 0;
2296 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2297 offsetX = SkScalarHalf(width);
2298 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2301 start.set(x - offsetX, y);
2308 uint32_t flags = paint.getFlags();
2310 if (flags & (SkPaint::kUnderlineText_Flag |
2311 SkPaint::kStrikeThruText_Flag)) {
2312 SkScalar textSize = paint.getTextSize();
2313 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2317 r.fRight = start.fX + width;
2319 if (flags & SkPaint::kUnderlineText_Flag) {
2320 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2323 r.fBottom = offset + height;
2324 DrawRect(draw, paint, r, textSize);
2326 if (flags & SkPaint::kStrikeThruText_Flag) {
2327 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2330 r.fBottom = offset + height;
2331 DrawRect(draw, paint, r, textSize);
2336 void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2337 const SkPaint& paint) {
2338 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2340 while (iter.next()) {
2341 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2342 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
2343 DrawTextDecorations(iter, dfp.paint(),
2344 static_cast<const char*>(text), byteLength, x, y);
2350 void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2351 const SkPaint& paint) {
2352 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2354 while (iter.next()) {
2355 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2356 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
2363 void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2364 SkScalar constY, const SkPaint& paint) {
2365 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2367 while (iter.next()) {
2368 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2369 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
2376 void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2377 const SkMatrix* matrix, const SkPaint& paint) {
2378 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2380 while (iter.next()) {
2381 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
2382 matrix, looper.paint());
2388 // These will become non-virtual, so they always call the (virtual) onDraw... method
2389 void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2390 const SkPaint& paint) {
2391 this->onDrawText(text, byteLength, x, y, paint);
2393 void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2394 const SkPaint& paint) {
2395 this->onDrawPosText(text, byteLength, pos, paint);
2397 void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2398 SkScalar constY, const SkPaint& paint) {
2399 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2401 void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2402 const SkMatrix* matrix, const SkPaint& paint) {
2403 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2406 void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
2407 const SkPoint verts[], const SkPoint texs[],
2408 const SkColor colors[], SkXfermode* xmode,
2409 const uint16_t indices[], int indexCount,
2410 const SkPaint& paint) {
2411 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
2413 while (iter.next()) {
2414 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
2415 colors, xmode, indices, indexCount,
2422 //////////////////////////////////////////////////////////////////////////////
2423 // These methods are NOT virtual, and therefore must call back into virtual
2424 // methods, rather than actually drawing themselves.
2425 //////////////////////////////////////////////////////////////////////////////
2427 void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
2428 SkXfermode::Mode mode) {
2431 paint.setARGB(a, r, g, b);
2432 if (SkXfermode::kSrcOver_Mode != mode) {
2433 paint.setXfermodeMode(mode);
2435 this->drawPaint(paint);
2438 void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
2442 if (SkXfermode::kSrcOver_Mode != mode) {
2443 paint.setXfermodeMode(mode);
2445 this->drawPaint(paint);
2448 void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
2452 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2455 void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
2460 paint.setColor(color);
2461 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2464 void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2465 const SkPaint& paint) {
2470 this->drawPoints(kLines_PointMode, 2, pts, paint);
2473 void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2474 SkScalar right, SkScalar bottom,
2475 const SkPaint& paint) {
2478 r.set(left, top, right, bottom);
2479 this->drawRect(r, paint);
2482 void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2483 const SkPaint& paint) {
2489 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
2490 this->drawOval(r, paint);
2493 void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2494 const SkPaint& paint) {
2495 if (rx > 0 && ry > 0) {
2496 if (paint.canComputeFastBounds()) {
2498 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
2503 rrect.setRectXY(r, rx, ry);
2504 this->drawRRect(rrect, paint);
2506 this->drawRect(r, paint);
2510 void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2511 SkScalar sweepAngle, bool useCenter,
2512 const SkPaint& paint) {
2513 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2514 this->drawOval(oval, paint);
2518 path.moveTo(oval.centerX(), oval.centerY());
2520 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2524 this->drawPath(path, paint);
2528 void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2529 const SkPath& path, SkScalar hOffset,
2530 SkScalar vOffset, const SkPaint& paint) {
2533 matrix.setTranslate(hOffset, vOffset);
2534 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2537 ///////////////////////////////////////////////////////////////////////////////
2538 void SkCanvas::EXPERIMENTAL_optimize(SkPicture* picture) {
2539 SkBaseDevice* device = this->getDevice();
2540 if (NULL != device) {
2541 device->EXPERIMENTAL_optimize(picture);
2545 void SkCanvas::EXPERIMENTAL_purge(SkPicture* picture) {
2546 SkBaseDevice* device = this->getTopDevice();
2547 if (NULL != device) {
2548 device->EXPERIMENTAL_purge(picture);
2552 void SkCanvas::drawPicture(SkPicture& picture) {
2553 SkBaseDevice* device = this->getTopDevice();
2554 if (NULL != device) {
2555 // Canvas has to first give the device the opportunity to render
2556 // the picture itself.
2557 if (device->EXPERIMENTAL_drawPicture(this, &picture)) {
2558 return; // the device has rendered the entire picture
2565 ///////////////////////////////////////////////////////////////////////////////
2566 ///////////////////////////////////////////////////////////////////////////////
2568 SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
2569 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
2573 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2574 fDone = !fImpl->next();
2577 SkCanvas::LayerIter::~LayerIter() {
2578 fImpl->~SkDrawIter();
2581 void SkCanvas::LayerIter::next() {
2582 fDone = !fImpl->next();
2585 SkBaseDevice* SkCanvas::LayerIter::device() const {
2586 return fImpl->getDevice();
2589 const SkMatrix& SkCanvas::LayerIter::matrix() const {
2590 return fImpl->getMatrix();
2593 const SkPaint& SkCanvas::LayerIter::paint() const {
2594 const SkPaint* paint = fImpl->getPaint();
2595 if (NULL == paint) {
2596 paint = &fDefaultPaint;
2601 const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2602 int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2603 int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
2605 ///////////////////////////////////////////////////////////////////////////////
2607 SkCanvas::ClipVisitor::~ClipVisitor() { }
2609 ///////////////////////////////////////////////////////////////////////////////
2611 static bool supported_for_raster_canvas(const SkImageInfo& info) {
2612 switch (info.alphaType()) {
2613 case kPremul_SkAlphaType:
2614 case kOpaque_SkAlphaType:
2620 switch (info.colorType()) {
2621 case kAlpha_8_SkColorType:
2622 case kRGB_565_SkColorType:
2623 case kN32_SkColorType:
2632 SkCanvas* SkCanvas::NewRaster(const SkImageInfo& info) {
2633 if (!supported_for_raster_canvas(info)) {
2638 if (!bitmap.allocPixels(info)) {
2642 // should this functionality be moved into allocPixels()?
2643 if (!bitmap.info().isOpaque()) {
2644 bitmap.eraseColor(0);
2646 return SkNEW_ARGS(SkCanvas, (bitmap));
2649 SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2650 if (!supported_for_raster_canvas(info)) {
2655 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2658 return SkNEW_ARGS(SkCanvas, (bitmap));