2 * Copyright 2008 The Android Open Source Project
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
10 #include "SkBitmapDevice.h"
11 #include "SkDeviceImageFilterProxy.h"
13 #include "SkDrawFilter.h"
14 #include "SkDrawLooper.h"
15 #include "SkMetaData.h"
16 #include "SkPathOps.h"
17 #include "SkPicture.h"
18 #include "SkRasterClip.h"
20 #include "SkSmallAllocator.h"
21 #include "SkSurface_Base.h"
22 #include "SkTemplates.h"
23 #include "SkTextFormatParams.h"
28 #include "GrRenderTarget.h"
31 // experimental for faster tiled drawing...
32 //#define SK_ENABLE_CLIP_QUICKREJECT
34 //#define SK_TRACE_SAVERESTORE
36 #ifdef SK_TRACE_SAVERESTORE
37 static int gLayerCounter;
38 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
39 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
41 static int gRecCounter;
42 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
43 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
45 static int gCanvasCounter;
46 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
47 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
58 #include "SkPixelRef.h"
61 * Some pixelref subclasses can support being "locked" from another thread
62 * during the lock-scope of skia calling them. In these instances, this balance
63 * check will fail, but may not be indicative of a problem, so we allow a build
64 * flag to disable this check.
66 * Potentially another fix would be to have a (debug-only) virtual or flag on
67 * pixelref, which could tell us at runtime if this check is valid. That would
68 * eliminate the need for this heavy-handed build check.
70 #ifdef SK_DISABLE_PIXELREF_LOCKCOUNT_BALANCE_CHECK
71 class AutoCheckLockCountBalance {
73 AutoCheckLockCountBalance(const SkBitmap&) { /* do nothing */ }
76 class AutoCheckLockCountBalance {
78 AutoCheckLockCountBalance(const SkBitmap& bm) : fPixelRef(bm.pixelRef()) {
79 fLockCount = fPixelRef ? fPixelRef->getLockCount() : 0;
81 ~AutoCheckLockCountBalance() {
82 const int count = fPixelRef ? fPixelRef->getLockCount() : 0;
83 SkASSERT(count == fLockCount);
87 const SkPixelRef* fPixelRef;
92 #define CHECK_LOCKCOUNT_BALANCE(bitmap) AutoCheckLockCountBalance clcb(bitmap)
95 #define CHECK_LOCKCOUNT_BALANCE(bitmap)
98 typedef SkTLazy<SkPaint> SkLazyPaint;
100 void SkCanvas::predrawNotify() {
102 fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode);
106 ///////////////////////////////////////////////////////////////////////////////
108 /* This is the record we keep for each SkBaseDevice that the user installs.
109 The clip/matrix/proc are fields that reflect the top of the save/restore
110 stack. Whenever the canvas changes, it marks a dirty flag, and then before
111 these are used (assuming we're not on a layer) we rebuild these cache
112 values: they reflect the top of the save stack, but translated and clipped
113 by the device's XY offset and bitmap-bounds.
117 SkBaseDevice* fDevice;
119 const SkMatrix* fMatrix;
120 SkPaint* fPaint; // may be null (in the future)
122 DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas)
124 if (NULL != device) {
126 device->onAttachToCanvas(canvas);
129 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
133 if (NULL != fDevice) {
134 fDevice->onDetachFromCanvas();
140 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
141 const SkClipStack& clipStack, SkRasterClip* updateClip) {
142 int x = fDevice->getOrigin().x();
143 int y = fDevice->getOrigin().y();
144 int width = fDevice->width();
145 int height = fDevice->height();
148 fMatrix = &totalMatrix;
151 fMatrixStorage = totalMatrix;
152 fMatrixStorage.postTranslate(SkIntToScalar(-x),
154 fMatrix = &fMatrixStorage;
156 totalClip.translate(-x, -y, &fClip);
159 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
161 // intersect clip, but don't translate it (yet)
164 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
165 SkRegion::kDifference_Op);
168 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
171 if (!fClip.isEmpty()) {
173 deviceR.set(0, 0, width, height);
174 SkASSERT(deviceR.contains(fClip.getBounds()));
180 SkMatrix fMatrixStorage;
183 /* This is the record we keep for each save/restore level in the stack.
184 Since a level optionally copies the matrix and/or stack, we have pointers
185 for these fields. If the value is copied for this level, the copy is
186 stored in the ...Storage field, and the pointer points to that. If the
187 value is not copied for this level, we ignore ...Storage, and just point
188 at the corresponding value in the previous level in the stack.
190 class SkCanvas::MCRec {
193 SkMatrix* fMatrix; // points to either fMatrixStorage or prev MCRec
194 SkRasterClip* fRasterClip; // points to either fRegionStorage or prev MCRec
195 SkDrawFilter* fFilter; // the current filter (or null)
198 /* If there are any layers in the stack, this points to the top-most
199 one that is at or below this level in the stack (so we know what
200 bitmap/device to draw into from this level. This value is NOT
201 reference counted, since the real owner is either our fLayer field,
202 or a previous one in a lower level.)
206 MCRec(const MCRec* prev, int flags) : fFlags(flags) {
208 if (flags & SkCanvas::kMatrix_SaveFlag) {
209 fMatrixStorage = *prev->fMatrix;
210 fMatrix = &fMatrixStorage;
212 fMatrix = prev->fMatrix;
215 if (flags & SkCanvas::kClip_SaveFlag) {
216 fRasterClipStorage = *prev->fRasterClip;
217 fRasterClip = &fRasterClipStorage;
219 fRasterClip = prev->fRasterClip;
222 fFilter = prev->fFilter;
225 fTopLayer = prev->fTopLayer;
227 fMatrixStorage.reset();
229 fMatrix = &fMatrixStorage;
230 fRasterClip = &fRasterClipStorage;
236 // don't bother initializing fNext
240 SkSafeUnref(fFilter);
246 SkMatrix fMatrixStorage;
247 SkRasterClip fRasterClipStorage;
250 class SkDrawIter : public SkDraw {
252 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
253 canvas = canvas->canvasForDrawIter();
255 canvas->updateDeviceCMCache();
257 fClipStack = &canvas->fClipStack;
258 fCurrLayer = canvas->fMCRec->fTopLayer;
259 fSkipEmptyClips = skipEmptyClips;
263 // skip over recs with empty clips
264 if (fSkipEmptyClips) {
265 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
266 fCurrLayer = fCurrLayer->fNext;
270 const DeviceCM* rec = fCurrLayer;
271 if (rec && rec->fDevice) {
273 fMatrix = rec->fMatrix;
274 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
276 fDevice = rec->fDevice;
277 fBitmap = &fDevice->accessBitmap(true);
278 fPaint = rec->fPaint;
279 SkDEBUGCODE(this->validate();)
281 fCurrLayer = rec->fNext;
282 // fCurrLayer may be NULL now
289 SkBaseDevice* getDevice() const { return fDevice; }
290 int getX() const { return fDevice->getOrigin().x(); }
291 int getY() const { return fDevice->getOrigin().y(); }
292 const SkMatrix& getMatrix() const { return *fMatrix; }
293 const SkRegion& getClip() const { return *fClip; }
294 const SkPaint* getPaint() const { return fPaint; }
298 const DeviceCM* fCurrLayer;
299 const SkPaint* fPaint; // May be null.
300 SkBool8 fSkipEmptyClips;
302 typedef SkDraw INHERITED;
305 /////////////////////////////////////////////////////////////////////////////
307 class AutoDrawLooper {
309 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint,
310 bool skipLayerForImageFilter = false,
311 const SkRect* bounds = NULL) : fOrigPaint(paint) {
313 fFilter = canvas->getDrawFilter();
315 fSaveCount = canvas->getSaveCount();
316 fDoClearImageFilter = false;
319 if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
321 tmp.setImageFilter(fOrigPaint.getImageFilter());
322 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
323 true, SkCanvas::kFullLayer_SaveLayerStrategy);
324 // we'll clear the imageFilter for the actual draws in next(), so
325 // it will only be applied during the restore().
326 fDoClearImageFilter = true;
329 if (SkDrawLooper* looper = paint.getLooper()) {
330 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
331 looper->contextSize());
332 fLooperContext = looper->createContext(canvas, buffer);
335 fLooperContext = NULL;
336 // can we be marked as simple?
337 fIsSimple = !fFilter && !fDoClearImageFilter;
342 if (fDoClearImageFilter) {
343 fCanvas->internalRestore();
345 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
348 const SkPaint& paint() const {
353 bool next(SkDrawFilter::Type drawType) {
356 } else if (fIsSimple) {
358 fPaint = &fOrigPaint;
359 return !fPaint->nothingToDraw();
361 return this->doNext(drawType);
366 SkLazyPaint fLazyPaint;
368 const SkPaint& fOrigPaint;
369 SkDrawFilter* fFilter;
370 const SkPaint* fPaint;
372 bool fDoClearImageFilter;
375 SkDrawLooper::Context* fLooperContext;
376 SkSmallAllocator<1, 32> fLooperContextAllocator;
378 bool doNext(SkDrawFilter::Type drawType);
381 bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
383 SkASSERT(!fIsSimple);
384 SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
386 SkPaint* paint = fLazyPaint.set(fOrigPaint);
388 if (fDoClearImageFilter) {
389 paint->setImageFilter(NULL);
392 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
397 if (!fFilter->filter(paint, drawType)) {
401 if (NULL == fLooperContext) {
402 // no looper means we only draw once
408 // if we only came in here for the imagefilter, mark us as done
409 if (!fLooperContext && !fFilter) {
413 // call this after any possible paint modifiers
414 if (fPaint->nothingToDraw()) {
421 #include "SkColorPriv.h"
423 ////////// macros to place around the internal draw calls //////////////////
425 #define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
426 this->predrawNotify(); \
427 AutoDrawLooper looper(this, paint, true); \
428 while (looper.next(type)) { \
429 SkDrawIter iter(this);
431 #define LOOPER_BEGIN(paint, type, bounds) \
432 this->predrawNotify(); \
433 AutoDrawLooper looper(this, paint, false, bounds); \
434 while (looper.next(type)) { \
435 SkDrawIter iter(this);
439 ////////////////////////////////////////////////////////////////////////////
441 SkBaseDevice* SkCanvas::init(SkBaseDevice* device) {
442 fCachedLocalClipBounds.setEmpty();
443 fCachedLocalClipBoundsDirty = true;
444 fAllowSoftClip = true;
445 fAllowSimplifyClip = false;
446 fDeviceCMDirty = false;
451 fMCRec = (MCRec*)fMCStack.push_back();
452 new (fMCRec) MCRec(NULL, 0);
454 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL));
455 fMCRec->fTopLayer = fMCRec->fLayer;
459 return this->setRootDevice(device);
463 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
470 SkCanvas::SkCanvas(int width, int height)
471 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
476 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
477 this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref();
480 SkCanvas::SkCanvas(SkBaseDevice* device)
481 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
488 SkCanvas::SkCanvas(const SkBitmap& bitmap)
489 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
493 this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref();
496 SkCanvas::~SkCanvas() {
497 // free up the contents of our deque
498 this->restoreToCount(1); // restore everything but the last
499 SkASSERT(0 == fSaveLayerCount);
501 this->internalRestore(); // restore the last, since we're going away
508 SkDrawFilter* SkCanvas::getDrawFilter() const {
509 return fMCRec->fFilter;
512 SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
513 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
517 SkMetaData& SkCanvas::getMetaData() {
518 // metadata users are rare, so we lazily allocate it. If that changes we
519 // can decide to just make it a field in the device (rather than a ptr)
520 if (NULL == fMetaData) {
521 fMetaData = new SkMetaData;
526 ///////////////////////////////////////////////////////////////////////////////
528 void SkCanvas::flush() {
529 SkBaseDevice* device = this->getDevice();
535 SkISize SkCanvas::getTopLayerSize() const {
536 SkBaseDevice* d = this->getTopDevice();
537 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
540 SkIPoint SkCanvas::getTopLayerOrigin() const {
541 SkBaseDevice* d = this->getTopDevice();
542 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
545 SkISize SkCanvas::getBaseLayerSize() const {
546 SkBaseDevice* d = this->getDevice();
547 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
550 SkBaseDevice* SkCanvas::getDevice() const {
551 // return root device
552 MCRec* rec = (MCRec*) fMCStack.front();
553 SkASSERT(rec && rec->fLayer);
554 return rec->fLayer->fDevice;
557 SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
558 if (updateMatrixClip) {
559 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
561 return fMCRec->fTopLayer->fDevice;
564 SkBaseDevice* SkCanvas::setRootDevice(SkBaseDevice* device) {
565 // return root device
566 SkDeque::F2BIter iter(fMCStack);
567 MCRec* rec = (MCRec*)iter.next();
568 SkASSERT(rec && rec->fLayer);
569 SkBaseDevice* rootDevice = rec->fLayer->fDevice;
571 if (rootDevice == device) {
576 device->onAttachToCanvas(this);
579 rootDevice->onDetachFromCanvas();
582 SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
585 fDeviceCMDirty = true;
587 /* Now we update our initial region to have the bounds of the new device,
588 and then intersect all of the clips in our stack with these bounds,
589 to ensure that we can't draw outside of the device's bounds (and trash
592 NOTE: this is only a partial-fix, since if the new device is larger than
593 the previous one, we don't know how to "enlarge" the clips in our stack,
594 so drawing may be artificially restricted. Without keeping a history of
595 all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
596 reconstruct the correct clips, so this approximation will have to do.
597 The caller really needs to restore() back to the base if they want to
598 accurately take advantage of the new device bounds.
603 bounds.set(0, 0, device->width(), device->height());
607 // now jam our 1st clip to be bounds, and intersect the rest with that
608 rec->fRasterClip->setRect(bounds);
609 while ((rec = (MCRec*)iter.next()) != NULL) {
610 (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op);
616 bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
617 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
621 bool weAllocated = false;
622 if (NULL == bitmap->pixelRef()) {
623 if (!bitmap->allocPixels()) {
629 SkBitmap bm(*bitmap);
631 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
636 bitmap->setPixelRef(NULL);
641 bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
643 const SkISize size = this->getBaseLayerSize();
644 if (!r.intersect(0, 0, size.width(), size.height())) {
649 if (!bitmap->allocN32Pixels(r.width(), r.height())) {
650 // bitmap will already be reset.
653 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
660 bool SkCanvas::readPixels(const SkImageInfo& origInfo, void* dstP, size_t rowBytes, int x, int y) {
661 switch (origInfo.colorType()) {
662 case kUnknown_SkColorType:
663 case kIndex_8_SkColorType:
668 if (NULL == dstP || rowBytes < origInfo.minRowBytes()) {
671 if (0 == origInfo.width() || 0 == origInfo.height()) {
675 SkBaseDevice* device = this->getDevice();
680 const SkISize size = this->getBaseLayerSize();
681 SkIRect srcR = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
682 if (!srcR.intersect(0, 0, size.width(), size.height())) {
686 SkImageInfo info = origInfo;
687 // the intersect may have shrunk info's logical size
688 info.fWidth = srcR.width();
689 info.fHeight = srcR.height();
691 // if x or y are negative, then we have to adjust pixels
698 // here x,y are either 0 or negative
699 dstP = ((char*)dstP - y * rowBytes - x * info.bytesPerPixel());
701 // The device can assert that the requested area is always contained in its bounds
702 return device->readPixels(info, dstP, rowBytes, srcR.x(), srcR.y());
705 bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
706 if (bitmap.getTexture()) {
711 if (bm.getPixels()) {
712 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
717 bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
719 switch (origInfo.colorType()) {
720 case kUnknown_SkColorType:
721 case kIndex_8_SkColorType:
726 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
730 const SkISize size = this->getBaseLayerSize();
731 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
732 if (!target.intersect(0, 0, size.width(), size.height())) {
736 SkBaseDevice* device = this->getDevice();
741 SkImageInfo info = origInfo;
742 // the intersect may have shrunk info's logical size
743 info.fWidth = target.width();
744 info.fHeight = target.height();
746 // if x or y are negative, then we have to adjust pixels
753 // here x,y are either 0 or negative
754 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
756 // The device can assert that the requested area is always contained in its bounds
757 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
760 SkCanvas* SkCanvas::canvasForDrawIter() {
764 //////////////////////////////////////////////////////////////////////////////
766 void SkCanvas::updateDeviceCMCache() {
767 if (fDeviceCMDirty) {
768 const SkMatrix& totalMatrix = this->getTotalMatrix();
769 const SkRasterClip& totalClip = *fMCRec->fRasterClip;
770 DeviceCM* layer = fMCRec->fTopLayer;
772 if (NULL == layer->fNext) { // only one layer
773 layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
775 SkRasterClip clip(totalClip);
777 layer->updateMC(totalMatrix, clip, fClipStack, &clip);
778 } while ((layer = layer->fNext) != NULL);
780 fDeviceCMDirty = false;
784 ///////////////////////////////////////////////////////////////////////////////
786 int SkCanvas::internalSave(SaveFlags flags) {
787 int saveCount = this->getSaveCount(); // record this before the actual save
789 MCRec* newTop = (MCRec*)fMCStack.push_back();
790 new (newTop) MCRec(fMCRec, flags); // balanced in restore()
794 if (SkCanvas::kClip_SaveFlag & flags) {
801 int SkCanvas::save() {
802 this->willSave(kMatrixClip_SaveFlag);
803 return this->internalSave(kMatrixClip_SaveFlag);
806 int SkCanvas::save(SaveFlags flags) {
807 this->willSave(flags);
809 return this->internalSave(flags);
812 static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
813 #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
814 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
820 bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
821 SkIRect* intersection, const SkImageFilter* imageFilter) {
823 SkRegion::Op op = SkRegion::kIntersect_Op;
824 if (!this->getClipDeviceBounds(&clipBounds)) {
829 imageFilter->filterBounds(clipBounds, *fMCRec->fMatrix, &clipBounds);
830 // Filters may grow the bounds beyond the device bounds.
831 op = SkRegion::kReplace_Op;
834 if (NULL != bounds) {
837 this->getTotalMatrix().mapRect(&r, *bounds);
839 // early exit if the layer's bounds are clipped out
840 if (!ir.intersect(clipBounds)) {
841 if (bounds_affects_clip(flags)) {
842 fMCRec->fRasterClip->setEmpty();
846 } else { // no user bounds, so just use the clip
850 if (bounds_affects_clip(flags)) {
851 fClipStack.clipDevRect(ir, op);
852 // early exit if the clip is now empty
853 if (!fMCRec->fRasterClip->op(ir, op)) {
864 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
865 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
866 return this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, false, strategy);
869 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
871 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
872 return this->internalSaveLayer(bounds, paint, flags, false, strategy);
875 static SkBaseDevice* create_compatible_device(SkCanvas* canvas,
876 const SkImageInfo& info) {
877 SkBaseDevice* device = canvas->getDevice();
878 return device ? device->createCompatibleDevice(info) : NULL;
881 int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
882 bool justForImageFilter, SaveLayerStrategy strategy) {
883 #ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
884 flags |= kClipToLayer_SaveFlag;
887 // do this before we create the layer. We don't call the public save() since
888 // that would invoke a possibly overridden virtual
889 int count = this->internalSave(flags);
891 fDeviceCMDirty = true;
894 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
898 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
899 // the clipRectBounds() call above?
900 if (kNoLayer_SaveLayerStrategy == strategy) {
904 // Kill the imagefilter if our device doesn't allow it
906 if (paint && paint->getImageFilter()) {
907 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
908 if (justForImageFilter) {
909 // early exit if the layer was just for the imageFilter
912 SkPaint* p = lazyP.set(*paint);
913 p->setImageFilter(NULL);
918 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
919 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
920 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
922 SkBaseDevice* device;
923 if (paint && paint->getImageFilter()) {
924 device = create_compatible_device(this, info);
926 device = this->createLayerDevice(info);
928 if (NULL == device) {
929 SkDebugf("Unable to create device for layer.");
933 device->setOrigin(ir.fLeft, ir.fTop);
934 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint, this));
937 layer->fNext = fMCRec->fTopLayer;
938 fMCRec->fLayer = layer;
939 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
941 fSaveLayerCount += 1;
945 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
946 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
949 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
952 return this->saveLayer(bounds, NULL, flags);
955 tmpPaint.setAlpha(alpha);
956 return this->saveLayer(bounds, &tmpPaint, flags);
960 void SkCanvas::restore() {
961 // check for underflow
962 if (fMCStack.count() > 1) {
964 this->internalRestore();
968 void SkCanvas::internalRestore() {
969 SkASSERT(fMCStack.count() != 0);
971 fDeviceCMDirty = true;
972 fCachedLocalClipBoundsDirty = true;
974 if (SkCanvas::kClip_SaveFlag & fMCRec->fFlags) {
975 fClipStack.restore();
978 // reserve our layer (if any)
979 DeviceCM* layer = fMCRec->fLayer; // may be null
980 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
981 fMCRec->fLayer = NULL;
983 // now do the normal restore()
984 fMCRec->~MCRec(); // balanced in save()
986 fMCRec = (MCRec*)fMCStack.back();
988 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
989 since if we're being recorded, we don't want to record this (the
990 recorder will have already recorded the restore).
994 const SkIPoint& origin = layer->fDevice->getOrigin();
995 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
997 // reset this, since internalDrawDevice will have set it to true
998 fDeviceCMDirty = true;
1000 SkASSERT(fSaveLayerCount > 0);
1001 fSaveLayerCount -= 1;
1007 int SkCanvas::getSaveCount() const {
1008 return fMCStack.count();
1011 void SkCanvas::restoreToCount(int count) {
1017 int n = this->getSaveCount() - count;
1018 for (int i = 0; i < n; ++i) {
1023 bool SkCanvas::isDrawingToLayer() const {
1024 return fSaveLayerCount > 0;
1027 SkSurface* SkCanvas::newSurface(const SkImageInfo& info) {
1028 return this->onNewSurface(info);
1031 SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info) {
1032 SkBaseDevice* dev = this->getDevice();
1033 return dev ? dev->newSurface(info) : NULL;
1036 SkImageInfo SkCanvas::imageInfo() const {
1037 SkBaseDevice* dev = this->getDevice();
1039 return dev->imageInfo();
1041 return SkImageInfo::MakeUnknown(0, 0);
1045 const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1046 return this->onPeekPixels(info, rowBytes);
1049 const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1050 SkBaseDevice* dev = this->getDevice();
1051 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1054 void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1055 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1056 if (pixels && origin) {
1057 *origin = this->getTopDevice(false)->getOrigin();
1062 void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1063 SkBaseDevice* dev = this->getTopDevice();
1064 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1067 SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1068 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1069 if (NULL == fAddr) {
1070 fInfo = canvas->imageInfo();
1071 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.allocPixels(fInfo)) {
1072 return; // failure, fAddr is NULL
1074 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1075 return; // failure, fAddr is NULL
1077 fAddr = fBitmap.getPixels();
1078 fRowBytes = fBitmap.rowBytes();
1080 SkASSERT(fAddr); // success
1083 bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1085 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
1092 void SkCanvas::onPushCull(const SkRect& cullRect) {
1093 // do nothing. Subclasses may do something
1096 void SkCanvas::onPopCull() {
1097 // do nothing. Subclasses may do something
1100 /////////////////////////////////////////////////////////////////////////////
1102 // Ensure that cull rects are monotonically nested in device space.
1103 void SkCanvas::validateCull(const SkIRect& devCull) {
1104 if (fCullStack.isEmpty()
1105 || devCull.isEmpty()
1106 || fCullStack.top().contains(devCull)) {
1110 SkDEBUGF(("Invalid cull: [%d %d %d %d] (previous cull: [%d %d %d %d])\n",
1111 devCull.x(), devCull.y(), devCull.right(), devCull.bottom(),
1112 fCullStack.top().x(), fCullStack.top().y(),
1113 fCullStack.top().right(), fCullStack.top().bottom()));
1115 #ifdef ASSERT_NESTED_CULLING
1116 SkDEBUGFAIL("Invalid cull.");
1121 void SkCanvas::pushCull(const SkRect& cullRect) {
1123 this->onPushCull(cullRect);
1126 // Map the cull rect into device space.
1128 this->getTotalMatrix().mapRect(&mappedCull, cullRect);
1130 // Take clipping into account.
1131 SkIRect devClip, devCull;
1132 mappedCull.roundOut(&devCull);
1133 this->getClipDeviceBounds(&devClip);
1134 if (!devCull.intersect(devClip)) {
1138 this->validateCull(devCull);
1139 fCullStack.push(devCull); // balanced in popCull
1143 void SkCanvas::popCull() {
1144 SkASSERT(fCullStack.count() == fCullCount);
1146 if (fCullCount > 0) {
1150 SkDEBUGCODE(fCullStack.pop());
1154 /////////////////////////////////////////////////////////////////////////////
1156 void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
1157 const SkMatrix& matrix, const SkPaint* paint) {
1158 if (bitmap.drawsNothing()) {
1163 if (NULL == paint) {
1164 paint = lazy.init();
1167 SkDEBUGCODE(bitmap.validate();)
1168 CHECK_LOCKCOUNT_BALANCE(bitmap);
1171 const SkRect* bounds = NULL;
1172 if (paint && paint->canComputeFastBounds()) {
1173 bitmap.getBounds(&storage);
1174 matrix.mapRect(&storage);
1175 bounds = &paint->computeFastBounds(storage, &storage);
1178 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
1180 while (iter.next()) {
1181 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1187 void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
1188 const SkPaint* paint) {
1190 if (NULL == paint) {
1191 tmp.setDither(true);
1195 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
1196 while (iter.next()) {
1197 SkBaseDevice* dstDev = iter.fDevice;
1198 paint = &looper.paint();
1199 SkImageFilter* filter = paint->getImageFilter();
1200 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1201 if (filter && !dstDev->canHandleImageFilter(filter)) {
1202 SkDeviceImageFilterProxy proxy(dstDev);
1204 SkIPoint offset = SkIPoint::Make(0, 0);
1205 const SkBitmap& src = srcDev->accessBitmap(false);
1206 SkMatrix matrix = *iter.fMatrix;
1207 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
1208 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
1209 SkImageFilter::Cache* cache = SkImageFilter::GetExternalCache();
1210 SkAutoUnref aur(NULL);
1212 cache = SkImageFilter::Cache::Create();
1215 SkImageFilter::Context ctx(matrix, clipBounds, cache);
1216 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
1217 SkPaint tmpUnfiltered(*paint);
1218 tmpUnfiltered.setImageFilter(NULL);
1219 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1223 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
1229 void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
1230 const SkPaint* paint) {
1231 if (bitmap.drawsNothing()) {
1234 SkDEBUGCODE(bitmap.validate();)
1235 CHECK_LOCKCOUNT_BALANCE(bitmap);
1238 if (NULL == paint) {
1242 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
1244 while (iter.next()) {
1245 paint = &looper.paint();
1246 SkImageFilter* filter = paint->getImageFilter();
1247 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1248 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
1249 SkDeviceImageFilterProxy proxy(iter.fDevice);
1251 SkIPoint offset = SkIPoint::Make(0, 0);
1252 SkMatrix matrix = *iter.fMatrix;
1253 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
1254 SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1255 SkImageFilter::Cache* cache = SkImageFilter::GetExternalCache();
1256 SkAutoUnref aur(NULL);
1258 cache = SkImageFilter::Cache::Create();
1261 SkImageFilter::Context ctx(matrix, clipBounds, cache);
1262 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
1263 SkPaint tmpUnfiltered(*paint);
1264 tmpUnfiltered.setImageFilter(NULL);
1265 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1269 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1275 /////////////////////////////////////////////////////////////////////////////
1276 void SkCanvas::translate(SkScalar dx, SkScalar dy) {
1278 m.setTranslate(dx, dy);
1282 void SkCanvas::scale(SkScalar sx, SkScalar sy) {
1288 void SkCanvas::rotate(SkScalar degrees) {
1290 m.setRotate(degrees);
1294 void SkCanvas::skew(SkScalar sx, SkScalar sy) {
1300 void SkCanvas::concat(const SkMatrix& matrix) {
1301 if (matrix.isIdentity()) {
1305 fDeviceCMDirty = true;
1306 fCachedLocalClipBoundsDirty = true;
1307 fMCRec->fMatrix->preConcat(matrix);
1309 this->didConcat(matrix);
1312 void SkCanvas::setMatrix(const SkMatrix& matrix) {
1313 fDeviceCMDirty = true;
1314 fCachedLocalClipBoundsDirty = true;
1315 *fMCRec->fMatrix = matrix;
1316 this->didSetMatrix(matrix);
1319 void SkCanvas::resetMatrix() {
1323 this->setMatrix(matrix);
1326 //////////////////////////////////////////////////////////////////////////////
1328 void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
1329 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1330 this->onClipRect(rect, op, edgeStyle);
1333 void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1334 #ifdef SK_ENABLE_CLIP_QUICKREJECT
1335 if (SkRegion::kIntersect_Op == op) {
1336 if (fMCRec->fRasterClip->isEmpty()) {
1340 if (this->quickReject(rect)) {
1341 fDeviceCMDirty = true;
1342 fCachedLocalClipBoundsDirty = true;
1344 fClipStack.clipEmpty();
1345 return fMCRec->fRasterClip->setEmpty();
1350 AutoValidateClip avc(this);
1352 fDeviceCMDirty = true;
1353 fCachedLocalClipBoundsDirty = true;
1354 if (!fAllowSoftClip) {
1355 edgeStyle = kHard_ClipEdgeStyle;
1358 if (fMCRec->fMatrix->rectStaysRect()) {
1359 // for these simpler matrices, we can stay a rect even after applying
1360 // the matrix. This means we don't have to a) make a path, and b) tell
1361 // the region code to scan-convert the path, only to discover that it
1362 // is really just a rect.
1365 fMCRec->fMatrix->mapRect(&r, rect);
1366 fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
1367 fMCRec->fRasterClip->op(r, op, kSoft_ClipEdgeStyle == edgeStyle);
1369 // since we're rotated or some such thing, we convert the rect to a path
1370 // and clip against that, since it can handle any matrix. However, to
1371 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1372 // we explicitly call "our" version of clipPath.
1376 this->SkCanvas::onClipPath(path, op, edgeStyle);
1380 static void clip_path_helper(const SkCanvas* canvas, SkRasterClip* currClip,
1381 const SkPath& devPath, SkRegion::Op op, bool doAA) {
1382 // base is used to limit the size (and therefore memory allocation) of the
1383 // region that results from scan converting devPath.
1386 if (SkRegion::kIntersect_Op == op) {
1387 // since we are intersect, we can do better (tighter) with currRgn's
1388 // bounds, than just using the device. However, if currRgn is complex,
1389 // our region blitter may hork, so we do that case in two steps.
1390 if (currClip->isRect()) {
1391 // FIXME: we should also be able to do this when currClip->isBW(),
1392 // but relaxing the test above triggers GM asserts in
1393 // SkRgnBuilder::blitH(). We need to investigate what's going on.
1394 currClip->setPath(devPath, currClip->bwRgn(), doAA);
1396 base.setRect(currClip->getBounds());
1398 clip.setPath(devPath, base, doAA);
1399 currClip->op(clip, op);
1402 const SkBaseDevice* device = canvas->getDevice();
1404 currClip->setEmpty();
1408 base.setRect(0, 0, device->width(), device->height());
1410 if (SkRegion::kReplace_Op == op) {
1411 currClip->setPath(devPath, base, doAA);
1414 clip.setPath(devPath, base, doAA);
1415 currClip->op(clip, op);
1420 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
1421 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1422 if (rrect.isRect()) {
1423 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1425 this->onClipRRect(rrect, op, edgeStyle);
1429 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1430 SkRRect transformedRRect;
1431 if (rrect.transform(*fMCRec->fMatrix, &transformedRRect)) {
1432 AutoValidateClip avc(this);
1434 fDeviceCMDirty = true;
1435 fCachedLocalClipBoundsDirty = true;
1436 if (!fAllowSoftClip) {
1437 edgeStyle = kHard_ClipEdgeStyle;
1440 fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
1443 devPath.addRRect(transformedRRect);
1445 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
1450 path.addRRect(rrect);
1451 // call the non-virtual version
1452 this->SkCanvas::onClipPath(path, op, edgeStyle);
1455 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
1456 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1458 if (!path.isInverseFillType() && path.isRect(&r)) {
1459 this->onClipRect(r, op, edgeStyle);
1461 this->onClipPath(path, op, edgeStyle);
1465 void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1466 #ifdef SK_ENABLE_CLIP_QUICKREJECT
1467 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
1468 if (fMCRec->fRasterClip->isEmpty()) {
1472 if (this->quickReject(path.getBounds())) {
1473 fDeviceCMDirty = true;
1474 fCachedLocalClipBoundsDirty = true;
1476 fClipStack.clipEmpty();
1477 return fMCRec->fRasterClip->setEmpty();
1482 AutoValidateClip avc(this);
1484 fDeviceCMDirty = true;
1485 fCachedLocalClipBoundsDirty = true;
1486 if (!fAllowSoftClip) {
1487 edgeStyle = kHard_ClipEdgeStyle;
1491 path.transform(*fMCRec->fMatrix, &devPath);
1493 // Check if the transfomation, or the original path itself
1494 // made us empty. Note this can also happen if we contained NaN
1495 // values. computing the bounds detects this, and will set our
1496 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1497 if (devPath.getBounds().isEmpty()) {
1498 // resetting the path will remove any NaN or other wanky values
1499 // that might upset our scan converter.
1503 // if we called path.swap() we could avoid a deep copy of this path
1504 fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
1506 if (fAllowSimplifyClip) {
1508 devPath.setFillType(SkPath::kInverseEvenOdd_FillType);
1509 const SkClipStack* clipStack = getClipStack();
1510 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
1511 const SkClipStack::Element* element;
1512 while ((element = iter.next())) {
1513 SkClipStack::Element::Type type = element->getType();
1515 if (type != SkClipStack::Element::kEmpty_Type) {
1516 element->asPath(&operand);
1518 SkRegion::Op elementOp = element->getOp();
1519 if (elementOp == SkRegion::kReplace_Op) {
1522 Op(devPath, operand, (SkPathOp) elementOp, &devPath);
1524 // if the prev and curr clips disagree about aa -vs- not, favor the aa request.
1525 // perhaps we need an API change to avoid this sort of mixed-signals about
1527 if (element->isAA()) {
1528 edgeStyle = kSoft_ClipEdgeStyle;
1531 op = SkRegion::kReplace_Op;
1534 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, edgeStyle);
1537 void SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op,
1538 bool inverseFilled) {
1539 // This is for updating the clip conservatively using only bounds
1542 // The current clip must contain the true clip. The true
1543 // clip is the clip that would have normally been computed
1544 // by calls to clipPath and clipRRect
1546 // Keep the current clip as small as possible without
1547 // breaking the contract, using only clip bounding rectangles
1548 // (for performance).
1550 // N.B.: This *never* calls back through a virtual on canvas, so subclasses
1551 // don't have to worry about getting caught in a loop. Thus anywhere
1552 // we call a virtual method, we explicitly prefix it with
1553 // SkCanvas:: to be sure to call the base-class.
1555 if (inverseFilled) {
1557 case SkRegion::kIntersect_Op:
1558 case SkRegion::kDifference_Op:
1559 // These ops can only shrink the current clip. So leaving
1560 // the clip unchanged conservatively respects the contract.
1562 case SkRegion::kUnion_Op:
1563 case SkRegion::kReplace_Op:
1564 case SkRegion::kReverseDifference_Op:
1565 case SkRegion::kXOR_Op: {
1566 // These ops can grow the current clip up to the extents of
1567 // the input clip, which is inverse filled, so we just set
1568 // the current clip to the device bounds.
1569 SkRect deviceBounds;
1570 SkIRect deviceIBounds;
1571 this->getDevice()->getGlobalBounds(&deviceIBounds);
1572 deviceBounds = SkRect::Make(deviceIBounds);
1574 // set the clip in device space
1575 SkMatrix savedMatrix = this->getTotalMatrix();
1576 this->SkCanvas::setMatrix(SkMatrix::I());
1577 this->SkCanvas::onClipRect(deviceBounds, SkRegion::kReplace_Op,
1578 kHard_ClipEdgeStyle);
1579 this->setMatrix(savedMatrix);
1583 SkASSERT(0); // unhandled op?
1586 // Not inverse filled
1588 case SkRegion::kIntersect_Op:
1589 case SkRegion::kUnion_Op:
1590 case SkRegion::kReplace_Op:
1591 this->SkCanvas::onClipRect(bounds, op, kHard_ClipEdgeStyle);
1593 case SkRegion::kDifference_Op:
1594 // Difference can only shrink the current clip.
1595 // Leaving clip unchanged conservatively fullfills the contract.
1597 case SkRegion::kReverseDifference_Op:
1598 // To reverse, we swap in the bounds with a replace op.
1599 // As with difference, leave it unchanged.
1600 this->SkCanvas::onClipRect(bounds, SkRegion::kReplace_Op, kHard_ClipEdgeStyle);
1602 case SkRegion::kXOR_Op:
1603 // Be conservative, based on (A XOR B) always included in (A union B),
1604 // which is always included in (bounds(A) union bounds(B))
1605 this->SkCanvas::onClipRect(bounds, SkRegion::kUnion_Op, kHard_ClipEdgeStyle);
1608 SkASSERT(0); // unhandled op?
1613 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
1614 this->onClipRegion(rgn, op);
1617 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
1618 AutoValidateClip avc(this);
1620 fDeviceCMDirty = true;
1621 fCachedLocalClipBoundsDirty = true;
1623 // todo: signal fClipStack that we have a region, and therefore (I guess)
1624 // we have to ignore it, and use the region directly?
1625 fClipStack.clipDevRect(rgn.getBounds(), op);
1627 fMCRec->fRasterClip->op(rgn, op);
1631 void SkCanvas::validateClip() const {
1632 // construct clipRgn from the clipstack
1633 const SkBaseDevice* device = this->getDevice();
1635 SkASSERT(this->isClipEmpty());
1640 ir.set(0, 0, device->width(), device->height());
1641 SkRasterClip tmpClip(ir);
1643 SkClipStack::B2TIter iter(fClipStack);
1644 const SkClipStack::Element* element;
1645 while ((element = iter.next()) != NULL) {
1646 switch (element->getType()) {
1647 case SkClipStack::Element::kRect_Type:
1648 element->getRect().round(&ir);
1649 tmpClip.op(ir, element->getOp());
1651 case SkClipStack::Element::kEmpty_Type:
1656 element->asPath(&path);
1657 clip_path_helper(this, &tmpClip, path, element->getOp(), element->isAA());
1665 void SkCanvas::replayClips(ClipVisitor* visitor) const {
1666 SkClipStack::B2TIter iter(fClipStack);
1667 const SkClipStack::Element* element;
1669 while ((element = iter.next()) != NULL) {
1670 element->replay(visitor);
1674 ///////////////////////////////////////////////////////////////////////////////
1676 bool SkCanvas::isClipEmpty() const {
1677 return fMCRec->fRasterClip->isEmpty();
1680 bool SkCanvas::isClipRect() const {
1681 return fMCRec->fRasterClip->isRect();
1684 bool SkCanvas::quickReject(const SkRect& rect) const {
1686 if (!rect.isFinite())
1689 if (fMCRec->fRasterClip->isEmpty()) {
1693 if (fMCRec->fMatrix->hasPerspective()) {
1695 fMCRec->fMatrix->mapRect(&dst, rect);
1697 dst.roundOut(&idst);
1698 return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds());
1700 const SkRect& clipR = this->getLocalClipBounds();
1702 // for speed, do the most likely reject compares first
1703 // TODO: should we use | instead, or compare all 4 at once?
1704 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
1707 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
1714 bool SkCanvas::quickReject(const SkPath& path) const {
1715 return path.isEmpty() || this->quickReject(path.getBounds());
1718 bool SkCanvas::getClipBounds(SkRect* bounds) const {
1720 if (!this->getClipDeviceBounds(&ibounds)) {
1725 // if we can't invert the CTM, we can't return local clip bounds
1726 if (!fMCRec->fMatrix->invert(&inverse)) {
1733 if (NULL != bounds) {
1735 // adjust it outwards in case we are antialiasing
1736 const int inset = 1;
1738 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1739 ibounds.fRight + inset, ibounds.fBottom + inset);
1740 inverse.mapRect(bounds, r);
1745 bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
1746 const SkRasterClip& clip = *fMCRec->fRasterClip;
1747 if (clip.isEmpty()) {
1754 if (NULL != bounds) {
1755 *bounds = clip.getBounds();
1760 const SkMatrix& SkCanvas::getTotalMatrix() const {
1761 return *fMCRec->fMatrix;
1764 #ifdef SK_SUPPORT_LEGACY_GETCLIPTYPE
1765 SkCanvas::ClipType SkCanvas::getClipType() const {
1766 if (fMCRec->fRasterClip->isEmpty()) {
1767 return kEmpty_ClipType;
1769 if (fMCRec->fRasterClip->isRect()) {
1770 return kRect_ClipType;
1772 return kComplex_ClipType;
1776 #ifdef SK_SUPPORT_LEGACY_GETTOTALCLIP
1777 const SkRegion& SkCanvas::getTotalClip() const {
1778 return fMCRec->fRasterClip->forceGetBW();
1782 const SkRegion& SkCanvas::internal_private_getTotalClip() const {
1783 return fMCRec->fRasterClip->forceGetBW();
1786 void SkCanvas::internal_private_getTotalClipAsPath(SkPath* path) const {
1789 const SkRegion& rgn = fMCRec->fRasterClip->forceGetBW();
1790 if (rgn.isEmpty()) {
1793 (void)rgn.getBoundaryPath(path);
1796 GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1797 SkBaseDevice* dev = this->getTopDevice();
1798 return dev ? dev->accessRenderTarget() : NULL;
1801 SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) {
1802 SkBaseDevice* device = this->getTopDevice();
1803 return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL;
1806 GrContext* SkCanvas::getGrContext() {
1808 SkBaseDevice* device = this->getTopDevice();
1809 if (NULL != device) {
1810 GrRenderTarget* renderTarget = device->accessRenderTarget();
1811 if (NULL != renderTarget) {
1812 return renderTarget->getContext();
1821 void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1822 const SkPaint& paint) {
1823 if (outer.isEmpty()) {
1826 if (inner.isEmpty()) {
1827 this->drawRRect(outer, paint);
1831 // We don't have this method (yet), but technically this is what we should
1832 // be able to assert...
1833 // SkASSERT(outer.contains(inner));
1835 // For now at least check for containment of bounds
1836 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1838 this->onDrawDRRect(outer, inner, paint);
1841 //////////////////////////////////////////////////////////////////////////////
1842 // These are the virtual drawing methods
1843 //////////////////////////////////////////////////////////////////////////////
1845 void SkCanvas::clear(SkColor color) {
1846 SkDrawIter iter(this);
1847 this->predrawNotify();
1848 while (iter.next()) {
1849 iter.fDevice->clear(color);
1853 void SkCanvas::onDiscard() {
1854 if (NULL != fSurfaceBase) {
1855 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1859 void SkCanvas::drawPaint(const SkPaint& paint) {
1860 this->internalDrawPaint(paint);
1863 void SkCanvas::internalDrawPaint(const SkPaint& paint) {
1864 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
1866 while (iter.next()) {
1867 iter.fDevice->drawPaint(iter, looper.paint());
1873 void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
1874 const SkPaint& paint) {
1875 if ((long)count <= 0) {
1880 const SkRect* bounds = NULL;
1881 if (paint.canComputeFastBounds()) {
1882 // special-case 2 points (common for drawing a single line)
1884 r.set(pts[0], pts[1]);
1886 r.set(pts, SkToInt(count));
1888 bounds = &paint.computeFastStrokeBounds(r, &storage);
1889 if (this->quickReject(*bounds)) {
1894 SkASSERT(pts != NULL);
1896 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
1898 while (iter.next()) {
1899 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
1905 void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1907 const SkRect* bounds = NULL;
1908 if (paint.canComputeFastBounds()) {
1909 bounds = &paint.computeFastBounds(r, &storage);
1910 if (this->quickReject(*bounds)) {
1915 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
1917 while (iter.next()) {
1918 iter.fDevice->drawRect(iter, r, looper.paint());
1924 void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
1926 const SkRect* bounds = NULL;
1927 if (paint.canComputeFastBounds()) {
1928 bounds = &paint.computeFastBounds(oval, &storage);
1929 if (this->quickReject(*bounds)) {
1934 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
1936 while (iter.next()) {
1937 iter.fDevice->drawOval(iter, oval, looper.paint());
1943 void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1945 const SkRect* bounds = NULL;
1946 if (paint.canComputeFastBounds()) {
1947 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1948 if (this->quickReject(*bounds)) {
1953 if (rrect.isRect()) {
1954 // call the non-virtual version
1955 this->SkCanvas::drawRect(rrect.getBounds(), paint);
1957 } else if (rrect.isOval()) {
1958 // call the non-virtual version
1959 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1963 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
1965 while (iter.next()) {
1966 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1972 void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1973 const SkPaint& paint) {
1975 const SkRect* bounds = NULL;
1976 if (paint.canComputeFastBounds()) {
1977 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1978 if (this->quickReject(*bounds)) {
1983 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
1985 while (iter.next()) {
1986 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1992 void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1993 if (!path.isFinite()) {
1998 const SkRect* bounds = NULL;
1999 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
2000 const SkRect& pathBounds = path.getBounds();
2001 bounds = &paint.computeFastBounds(pathBounds, &storage);
2002 if (this->quickReject(*bounds)) {
2007 const SkRect& r = path.getBounds();
2008 if (r.width() <= 0 && r.height() <= 0) {
2009 if (path.isInverseFillType()) {
2010 this->internalDrawPaint(paint);
2015 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
2017 while (iter.next()) {
2018 iter.fDevice->drawPath(iter, path, looper.paint());
2024 void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
2025 const SkPaint* paint) {
2026 SkDEBUGCODE(bitmap.validate();)
2028 if (NULL == paint || paint->canComputeFastBounds()) {
2031 x + SkIntToScalar(bitmap.width()),
2032 y + SkIntToScalar(bitmap.height())
2035 (void)paint->computeFastBounds(bounds, &bounds);
2037 if (this->quickReject(bounds)) {
2043 matrix.setTranslate(x, y);
2044 this->internalDrawBitmap(bitmap, matrix, paint);
2047 // this one is non-virtual, so it can be called safely by other canvas apis
2048 void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
2049 const SkRect& dst, const SkPaint* paint,
2050 DrawBitmapRectFlags flags) {
2051 if (bitmap.drawsNothing() || dst.isEmpty()) {
2055 CHECK_LOCKCOUNT_BALANCE(bitmap);
2058 const SkRect* bounds = &dst;
2059 if (NULL == paint || paint->canComputeFastBounds()) {
2061 bounds = &paint->computeFastBounds(dst, &storage);
2063 if (this->quickReject(*bounds)) {
2069 if (NULL == paint) {
2070 paint = lazy.init();
2073 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2075 while (iter.next()) {
2076 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
2082 void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
2083 const SkRect& dst, const SkPaint* paint,
2084 DrawBitmapRectFlags flags) {
2085 SkDEBUGCODE(bitmap.validate();)
2086 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
2089 void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
2090 const SkPaint* paint) {
2091 SkDEBUGCODE(bitmap.validate();)
2092 this->internalDrawBitmap(bitmap, matrix, paint);
2095 void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
2096 const SkIRect& center, const SkRect& dst,
2097 const SkPaint* paint) {
2098 if (bitmap.drawsNothing()) {
2101 if (NULL == paint || paint->canComputeFastBounds()) {
2103 const SkRect* bounds = &dst;
2105 bounds = &paint->computeFastBounds(dst, &storage);
2107 if (this->quickReject(*bounds)) {
2112 const int32_t w = bitmap.width();
2113 const int32_t h = bitmap.height();
2116 // pin center to the bounds of the bitmap
2117 c.fLeft = SkMax32(0, center.fLeft);
2118 c.fTop = SkMax32(0, center.fTop);
2119 c.fRight = SkPin32(center.fRight, c.fLeft, w);
2120 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
2122 const SkScalar srcX[4] = {
2123 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
2125 const SkScalar srcY[4] = {
2126 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
2128 SkScalar dstX[4] = {
2129 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2130 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2132 SkScalar dstY[4] = {
2133 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2134 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2137 if (dstX[1] > dstX[2]) {
2138 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2142 if (dstY[1] > dstY[2]) {
2143 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2147 for (int y = 0; y < 3; y++) {
2151 s.fBottom = srcY[y+1];
2153 d.fBottom = dstY[y+1];
2154 for (int x = 0; x < 3; x++) {
2156 s.fRight = srcX[x+1];
2158 d.fRight = dstX[x+1];
2159 this->internalDrawBitmapRect(bitmap, &s, d, paint,
2160 kNone_DrawBitmapRectFlag);
2165 void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
2166 const SkRect& dst, const SkPaint* paint) {
2167 SkDEBUGCODE(bitmap.validate();)
2169 // Need a device entry-point, so gpu can use a mesh
2170 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2173 class SkDeviceFilteredPaint {
2175 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
2176 SkBaseDevice::TextFlags flags;
2177 if (device->filterTextFlags(paint, &flags)) {
2178 SkPaint* newPaint = fLazy.set(paint);
2179 newPaint->setFlags(flags.fFlags);
2180 newPaint->setHinting(flags.fHinting);
2187 const SkPaint& paint() const { return *fPaint; }
2190 const SkPaint* fPaint;
2194 void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2195 const SkRect& r, SkScalar textSize) {
2196 if (paint.getStyle() == SkPaint::kFill_Style) {
2197 draw.fDevice->drawRect(draw, r, paint);
2200 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
2201 draw.fDevice->drawRect(draw, r, p);
2205 void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2206 const char text[], size_t byteLength,
2207 SkScalar x, SkScalar y) {
2208 SkASSERT(byteLength == 0 || text != NULL);
2211 if (text == NULL || byteLength == 0 ||
2212 draw.fClip->isEmpty() ||
2213 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2220 start.set(0, 0); // to avoid warning
2221 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2222 SkPaint::kStrikeThruText_Flag)) {
2223 width = paint.measureText(text, byteLength);
2225 SkScalar offsetX = 0;
2226 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2227 offsetX = SkScalarHalf(width);
2228 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2231 start.set(x - offsetX, y);
2238 uint32_t flags = paint.getFlags();
2240 if (flags & (SkPaint::kUnderlineText_Flag |
2241 SkPaint::kStrikeThruText_Flag)) {
2242 SkScalar textSize = paint.getTextSize();
2243 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2247 r.fRight = start.fX + width;
2249 if (flags & SkPaint::kUnderlineText_Flag) {
2250 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2253 r.fBottom = offset + height;
2254 DrawRect(draw, paint, r, textSize);
2256 if (flags & SkPaint::kStrikeThruText_Flag) {
2257 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2260 r.fBottom = offset + height;
2261 DrawRect(draw, paint, r, textSize);
2266 void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2267 const SkPaint& paint) {
2268 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2270 while (iter.next()) {
2271 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2272 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
2273 DrawTextDecorations(iter, dfp.paint(),
2274 static_cast<const char*>(text), byteLength, x, y);
2280 void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2281 const SkPaint& paint) {
2282 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2284 while (iter.next()) {
2285 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2286 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
2293 void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2294 SkScalar constY, const SkPaint& paint) {
2295 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2297 while (iter.next()) {
2298 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2299 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
2306 void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2307 const SkMatrix* matrix, const SkPaint& paint) {
2308 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2310 while (iter.next()) {
2311 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
2312 matrix, looper.paint());
2318 // These will become non-virtual, so they always call the (virtual) onDraw... method
2319 void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2320 const SkPaint& paint) {
2321 this->onDrawText(text, byteLength, x, y, paint);
2323 void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2324 const SkPaint& paint) {
2325 this->onDrawPosText(text, byteLength, pos, paint);
2327 void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2328 SkScalar constY, const SkPaint& paint) {
2329 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2331 void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2332 const SkMatrix* matrix, const SkPaint& paint) {
2333 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2336 void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
2337 const SkPoint verts[], const SkPoint texs[],
2338 const SkColor colors[], SkXfermode* xmode,
2339 const uint16_t indices[], int indexCount,
2340 const SkPaint& paint) {
2341 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
2343 while (iter.next()) {
2344 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
2345 colors, xmode, indices, indexCount,
2352 //////////////////////////////////////////////////////////////////////////////
2353 // These methods are NOT virtual, and therefore must call back into virtual
2354 // methods, rather than actually drawing themselves.
2355 //////////////////////////////////////////////////////////////////////////////
2357 void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
2358 SkXfermode::Mode mode) {
2361 paint.setARGB(a, r, g, b);
2362 if (SkXfermode::kSrcOver_Mode != mode) {
2363 paint.setXfermodeMode(mode);
2365 this->drawPaint(paint);
2368 void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
2372 if (SkXfermode::kSrcOver_Mode != mode) {
2373 paint.setXfermodeMode(mode);
2375 this->drawPaint(paint);
2378 void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
2382 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2385 void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
2390 paint.setColor(color);
2391 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2394 void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2395 const SkPaint& paint) {
2400 this->drawPoints(kLines_PointMode, 2, pts, paint);
2403 void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2404 SkScalar right, SkScalar bottom,
2405 const SkPaint& paint) {
2408 r.set(left, top, right, bottom);
2409 this->drawRect(r, paint);
2412 void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2413 const SkPaint& paint) {
2419 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
2420 this->drawOval(r, paint);
2423 void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2424 const SkPaint& paint) {
2425 if (rx > 0 && ry > 0) {
2426 if (paint.canComputeFastBounds()) {
2428 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
2433 rrect.setRectXY(r, rx, ry);
2434 this->drawRRect(rrect, paint);
2436 this->drawRect(r, paint);
2440 void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2441 SkScalar sweepAngle, bool useCenter,
2442 const SkPaint& paint) {
2443 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2444 this->drawOval(oval, paint);
2448 path.moveTo(oval.centerX(), oval.centerY());
2450 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2454 this->drawPath(path, paint);
2458 void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2459 const SkPath& path, SkScalar hOffset,
2460 SkScalar vOffset, const SkPaint& paint) {
2463 matrix.setTranslate(hOffset, vOffset);
2464 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2467 ///////////////////////////////////////////////////////////////////////////////
2468 void SkCanvas::EXPERIMENTAL_optimize(const SkPicture* picture) {
2469 SkBaseDevice* device = this->getDevice();
2470 if (NULL != device) {
2471 device->EXPERIMENTAL_optimize(picture);
2475 void SkCanvas::EXPERIMENTAL_purge(const SkPicture* picture) {
2476 SkBaseDevice* device = this->getTopDevice();
2477 if (NULL != device) {
2478 device->EXPERIMENTAL_purge(picture);
2482 void SkCanvas::drawPicture(const SkPicture* picture) {
2483 if (NULL != picture) {
2484 this->onDrawPicture(picture);
2488 void SkCanvas::onDrawPicture(const SkPicture* picture) {
2489 SkASSERT(NULL != picture);
2491 SkBaseDevice* device = this->getTopDevice();
2492 if (NULL != device) {
2493 // Canvas has to first give the device the opportunity to render
2494 // the picture itself.
2495 if (device->EXPERIMENTAL_drawPicture(this, picture)) {
2496 return; // the device has rendered the entire picture
2500 picture->draw(this);
2503 ///////////////////////////////////////////////////////////////////////////////
2504 ///////////////////////////////////////////////////////////////////////////////
2506 SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
2507 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
2511 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2512 fDone = !fImpl->next();
2515 SkCanvas::LayerIter::~LayerIter() {
2516 fImpl->~SkDrawIter();
2519 void SkCanvas::LayerIter::next() {
2520 fDone = !fImpl->next();
2523 SkBaseDevice* SkCanvas::LayerIter::device() const {
2524 return fImpl->getDevice();
2527 const SkMatrix& SkCanvas::LayerIter::matrix() const {
2528 return fImpl->getMatrix();
2531 const SkPaint& SkCanvas::LayerIter::paint() const {
2532 const SkPaint* paint = fImpl->getPaint();
2533 if (NULL == paint) {
2534 paint = &fDefaultPaint;
2539 const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2540 int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2541 int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
2543 ///////////////////////////////////////////////////////////////////////////////
2545 SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
2547 ///////////////////////////////////////////////////////////////////////////////
2549 static bool supported_for_raster_canvas(const SkImageInfo& info) {
2550 switch (info.alphaType()) {
2551 case kPremul_SkAlphaType:
2552 case kOpaque_SkAlphaType:
2558 switch (info.colorType()) {
2559 case kAlpha_8_SkColorType:
2560 case kRGB_565_SkColorType:
2561 case kN32_SkColorType:
2570 SkCanvas* SkCanvas::NewRaster(const SkImageInfo& info) {
2571 if (!supported_for_raster_canvas(info)) {
2576 if (!bitmap.allocPixels(info)) {
2580 // should this functionality be moved into allocPixels()?
2581 if (!bitmap.info().isOpaque()) {
2582 bitmap.eraseColor(0);
2584 return SkNEW_ARGS(SkCanvas, (bitmap));
2587 SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2588 if (!supported_for_raster_canvas(info)) {
2593 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2596 return SkNEW_ARGS(SkCanvas, (bitmap));