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.
9 #include "SkCanvasPriv.h"
10 #include "SkBitmapDevice.h"
11 #include "SkDeviceImageFilterProxy.h"
13 #include "SkDrawFilter.h"
14 #include "SkDrawLooper.h"
16 #include "SkMetaData.h"
17 #include "SkPathOps.h"
18 #include "SkPatchUtils.h"
19 #include "SkPicture.h"
20 #include "SkRasterClip.h"
22 #include "SkSmallAllocator.h"
23 #include "SkSurface_Base.h"
24 #include "SkTemplates.h"
25 #include "SkTextBlob.h"
26 #include "SkTextFormatParams.h"
31 #include "GrRenderTarget.h"
34 // experimental for faster tiled drawing...
35 //#define SK_ENABLE_CLIP_QUICKREJECT
37 //#define SK_TRACE_SAVERESTORE
39 #ifdef SK_TRACE_SAVERESTORE
40 static int gLayerCounter;
41 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
42 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
44 static int gRecCounter;
45 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
46 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
48 static int gCanvasCounter;
49 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
50 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
60 typedef SkTLazy<SkPaint> SkLazyPaint;
62 void SkCanvas::predrawNotify() {
64 fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode);
68 ///////////////////////////////////////////////////////////////////////////////
70 static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
71 const uint32_t propFlags = props.flags();
72 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
73 flags &= ~SkPaint::kDither_Flag;
75 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
76 flags &= ~SkPaint::kAntiAlias_Flag;
81 ///////////////////////////////////////////////////////////////////////////////
83 /* This is the record we keep for each SkBaseDevice that the user installs.
84 The clip/matrix/proc are fields that reflect the top of the save/restore
85 stack. Whenever the canvas changes, it marks a dirty flag, and then before
86 these are used (assuming we're not on a layer) we rebuild these cache
87 values: they reflect the top of the save stack, but translated and clipped
88 by the device's XY offset and bitmap-bounds.
92 SkBaseDevice* fDevice;
94 const SkMatrix* fMatrix;
95 SkPaint* fPaint; // may be null (in the future)
97 DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas,
98 bool conservativeRasterClip)
100 , fClip(conservativeRasterClip)
102 if (NULL != device) {
104 device->onAttachToCanvas(canvas);
107 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
112 fDevice->onDetachFromCanvas();
118 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
119 const SkClipStack& clipStack, SkRasterClip* updateClip) {
120 int x = fDevice->getOrigin().x();
121 int y = fDevice->getOrigin().y();
122 int width = fDevice->width();
123 int height = fDevice->height();
126 fMatrix = &totalMatrix;
129 fMatrixStorage = totalMatrix;
130 fMatrixStorage.postTranslate(SkIntToScalar(-x),
132 fMatrix = &fMatrixStorage;
134 totalClip.translate(-x, -y, &fClip);
137 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
139 // intersect clip, but don't translate it (yet)
142 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
143 SkRegion::kDifference_Op);
146 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
149 if (!fClip.isEmpty()) {
151 deviceR.set(0, 0, width, height);
152 SkASSERT(deviceR.contains(fClip.getBounds()));
158 SkMatrix fMatrixStorage;
161 /* This is the record we keep for each save/restore level in the stack.
162 Since a level optionally copies the matrix and/or stack, we have pointers
163 for these fields. If the value is copied for this level, the copy is
164 stored in the ...Storage field, and the pointer points to that. If the
165 value is not copied for this level, we ignore ...Storage, and just point
166 at the corresponding value in the previous level in the stack.
168 class SkCanvas::MCRec {
170 SkRasterClip fRasterClip;
172 SkDrawFilter* fFilter; // the current filter (or null)
174 /* If there are any layers in the stack, this points to the top-most
175 one that is at or below this level in the stack (so we know what
176 bitmap/device to draw into from this level. This value is NOT
177 reference counted, since the real owner is either our fLayer field,
178 or a previous one in a lower level.)
182 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
188 // don't bother initializing fNext
191 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip) {
192 fMatrix = prev.fMatrix;
193 fFilter = SkSafeRef(prev.fFilter);
195 fTopLayer = prev.fTopLayer;
197 // don't bother initializing fNext
201 SkSafeUnref(fFilter);
207 class SkDrawIter : public SkDraw {
209 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
210 canvas = canvas->canvasForDrawIter();
212 canvas->updateDeviceCMCache();
214 fClipStack = &canvas->fClipStack;
215 fCurrLayer = canvas->fMCRec->fTopLayer;
216 fSkipEmptyClips = skipEmptyClips;
220 // skip over recs with empty clips
221 if (fSkipEmptyClips) {
222 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
223 fCurrLayer = fCurrLayer->fNext;
227 const DeviceCM* rec = fCurrLayer;
228 if (rec && rec->fDevice) {
230 fMatrix = rec->fMatrix;
231 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
233 fDevice = rec->fDevice;
234 fBitmap = &fDevice->accessBitmap(true);
235 fPaint = rec->fPaint;
236 SkDEBUGCODE(this->validate();)
238 fCurrLayer = rec->fNext;
239 // fCurrLayer may be NULL now
246 SkBaseDevice* getDevice() const { return fDevice; }
247 int getX() const { return fDevice->getOrigin().x(); }
248 int getY() const { return fDevice->getOrigin().y(); }
249 const SkMatrix& getMatrix() const { return *fMatrix; }
250 const SkRegion& getClip() const { return *fClip; }
251 const SkPaint* getPaint() const { return fPaint; }
255 const DeviceCM* fCurrLayer;
256 const SkPaint* fPaint; // May be null.
257 SkBool8 fSkipEmptyClips;
259 typedef SkDraw INHERITED;
262 /////////////////////////////////////////////////////////////////////////////
264 class AutoDrawLooper {
266 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
267 bool skipLayerForImageFilter = false,
268 const SkRect* bounds = NULL) : fOrigPaint(paint) {
270 fFilter = canvas->getDrawFilter();
271 fPaint = &fOrigPaint;
272 fSaveCount = canvas->getSaveCount();
273 fDoClearImageFilter = false;
276 if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
278 tmp.setImageFilter(fOrigPaint.getImageFilter());
279 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
280 true, SkCanvas::kFullLayer_SaveLayerStrategy);
281 // we'll clear the imageFilter for the actual draws in next(), so
282 // it will only be applied during the restore().
283 fDoClearImageFilter = true;
286 if (SkDrawLooper* looper = paint.getLooper()) {
287 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
288 looper->contextSize());
289 fLooperContext = looper->createContext(canvas, buffer);
292 fLooperContext = NULL;
293 // can we be marked as simple?
294 fIsSimple = !fFilter && !fDoClearImageFilter;
297 uint32_t oldFlags = paint.getFlags();
298 fNewPaintFlags = filter_paint_flags(props, oldFlags);
299 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
300 SkPaint* paint = fLazyPaint.set(fOrigPaint);
301 paint->setFlags(fNewPaintFlags);
303 // if we're not simple, doNext() will take care of calling setFlags()
308 if (fDoClearImageFilter) {
309 fCanvas->internalRestore();
311 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
314 const SkPaint& paint() const {
319 bool next(SkDrawFilter::Type drawType) {
322 } else if (fIsSimple) {
324 return !fPaint->nothingToDraw();
326 return this->doNext(drawType);
331 SkLazyPaint fLazyPaint;
333 const SkPaint& fOrigPaint;
334 SkDrawFilter* fFilter;
335 const SkPaint* fPaint;
337 uint32_t fNewPaintFlags;
338 bool fDoClearImageFilter;
341 SkDrawLooper::Context* fLooperContext;
342 SkSmallAllocator<1, 32> fLooperContextAllocator;
344 bool doNext(SkDrawFilter::Type drawType);
347 bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
349 SkASSERT(!fIsSimple);
350 SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
352 SkPaint* paint = fLazyPaint.set(fOrigPaint);
353 paint->setFlags(fNewPaintFlags);
355 if (fDoClearImageFilter) {
356 paint->setImageFilter(NULL);
359 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
364 if (!fFilter->filter(paint, drawType)) {
368 if (NULL == fLooperContext) {
369 // no looper means we only draw once
375 // if we only came in here for the imagefilter, mark us as done
376 if (!fLooperContext && !fFilter) {
380 // call this after any possible paint modifiers
381 if (fPaint->nothingToDraw()) {
388 ////////// macros to place around the internal draw calls //////////////////
390 #define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
391 this->predrawNotify(); \
392 AutoDrawLooper looper(this, fProps, paint, true); \
393 while (looper.next(type)) { \
394 SkDrawIter iter(this);
396 #define LOOPER_BEGIN(paint, type, bounds) \
397 this->predrawNotify(); \
398 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
399 while (looper.next(type)) { \
400 SkDrawIter iter(this);
404 ////////////////////////////////////////////////////////////////////////////
406 void SkCanvas::setupDevice(SkBaseDevice* device) {
407 device->setPixelGeometry(fProps.pixelGeometry());
410 SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
411 fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
412 fCachedLocalClipBounds.setEmpty();
413 fCachedLocalClipBoundsDirty = true;
414 fAllowSoftClip = true;
415 fAllowSimplifyClip = false;
416 fDeviceCMDirty = true;
421 fMCRec = (MCRec*)fMCStack.push_back();
422 new (fMCRec) MCRec(fConservativeRasterClip);
424 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL, fConservativeRasterClip));
425 fMCRec->fTopLayer = fMCRec->fLayer;
430 this->setupDevice(device);
431 if (device->forceConservativeRasterClip()) {
432 fConservativeRasterClip = true;
434 device->onAttachToCanvas(this);
435 fMCRec->fLayer->fDevice = SkRef(device);
436 fMCRec->fRasterClip.setRect(SkIRect::MakeWH(device->width(), device->height()));
442 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
443 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
447 this->init(NULL, kDefault_InitFlags);
450 static SkBitmap make_nopixels(int width, int height) {
452 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
456 class SkNoPixelsBitmapDevice : public SkBitmapDevice {
458 SkNoPixelsBitmapDevice(int width, int height) : INHERITED(make_nopixels(width, height)) {}
462 typedef SkBitmapDevice INHERITED;
465 SkCanvas::SkCanvas(int width, int height)
466 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
467 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
471 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (width, height)), kDefault_InitFlags)->unref();
474 SkCanvas::SkCanvas(int width, int height, InitFlags flags)
475 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
476 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
480 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (width, height)), flags)->unref();
483 SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
484 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
485 , fProps(SkSurfacePropsCopyOrDefault(props))
489 this->init(device, flags);
492 SkCanvas::SkCanvas(SkBaseDevice* device)
493 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
494 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
498 this->init(device, kDefault_InitFlags);
501 SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
502 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
507 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
508 this->init(device, kDefault_InitFlags);
511 SkCanvas::SkCanvas(const SkBitmap& bitmap)
512 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
513 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
517 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
518 this->init(device, kDefault_InitFlags);
521 SkCanvas::~SkCanvas() {
522 // free up the contents of our deque
523 this->restoreToCount(1); // restore everything but the last
524 SkASSERT(0 == fSaveLayerCount);
526 this->internalRestore(); // restore the last, since we're going away
533 SkDrawFilter* SkCanvas::getDrawFilter() const {
534 return fMCRec->fFilter;
537 SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
538 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
542 SkMetaData& SkCanvas::getMetaData() {
543 // metadata users are rare, so we lazily allocate it. If that changes we
544 // can decide to just make it a field in the device (rather than a ptr)
545 if (NULL == fMetaData) {
546 fMetaData = new SkMetaData;
551 ///////////////////////////////////////////////////////////////////////////////
553 void SkCanvas::flush() {
554 SkBaseDevice* device = this->getDevice();
560 SkISize SkCanvas::getTopLayerSize() const {
561 SkBaseDevice* d = this->getTopDevice();
562 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
565 SkIPoint SkCanvas::getTopLayerOrigin() const {
566 SkBaseDevice* d = this->getTopDevice();
567 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
570 SkISize SkCanvas::getBaseLayerSize() const {
571 SkBaseDevice* d = this->getDevice();
572 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
575 SkBaseDevice* SkCanvas::getDevice() const {
576 // return root device
577 MCRec* rec = (MCRec*) fMCStack.front();
578 SkASSERT(rec && rec->fLayer);
579 return rec->fLayer->fDevice;
582 SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
583 if (updateMatrixClip) {
584 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
586 return fMCRec->fTopLayer->fDevice;
589 SkBaseDevice* SkCanvas::setRootDevice(SkBaseDevice* device) {
590 // return root device
591 SkDeque::F2BIter iter(fMCStack);
592 MCRec* rec = (MCRec*)iter.next();
593 SkASSERT(rec && rec->fLayer);
594 SkBaseDevice* rootDevice = rec->fLayer->fDevice;
596 if (rootDevice == device) {
601 device->onAttachToCanvas(this);
604 rootDevice->onDetachFromCanvas();
607 SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
609 this->setupDevice(device);
611 fDeviceCMDirty = true;
613 /* Now we update our initial region to have the bounds of the new device,
614 and then intersect all of the clips in our stack with these bounds,
615 to ensure that we can't draw outside of the device's bounds (and trash
618 NOTE: this is only a partial-fix, since if the new device is larger than
619 the previous one, we don't know how to "enlarge" the clips in our stack,
620 so drawing may be artificially restricted. Without keeping a history of
621 all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
622 reconstruct the correct clips, so this approximation will have to do.
623 The caller really needs to restore() back to the base if they want to
624 accurately take advantage of the new device bounds.
629 bounds.set(0, 0, device->width(), device->height());
633 // now jam our 1st clip to be bounds, and intersect the rest with that
634 rec->fRasterClip.setRect(bounds);
635 while ((rec = (MCRec*)iter.next()) != NULL) {
636 (void)rec->fRasterClip.op(bounds, SkRegion::kIntersect_Op);
642 bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
643 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
647 bool weAllocated = false;
648 if (NULL == bitmap->pixelRef()) {
649 if (!bitmap->tryAllocPixels()) {
655 SkBitmap bm(*bitmap);
657 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
662 bitmap->setPixelRef(NULL);
667 bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
669 const SkISize size = this->getBaseLayerSize();
670 if (!r.intersect(0, 0, size.width(), size.height())) {
675 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
676 // bitmap will already be reset.
679 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
686 bool SkCanvas::readPixels(const SkImageInfo& origInfo, void* dstP, size_t rowBytes, int x, int y) {
687 switch (origInfo.colorType()) {
688 case kUnknown_SkColorType:
689 case kIndex_8_SkColorType:
694 if (NULL == dstP || rowBytes < origInfo.minRowBytes()) {
697 if (0 == origInfo.width() || 0 == origInfo.height()) {
701 SkBaseDevice* device = this->getDevice();
706 const SkISize size = this->getBaseLayerSize();
707 SkIRect srcR = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
708 if (!srcR.intersect(0, 0, size.width(), size.height())) {
712 // the intersect may have shrunk info's logical size
713 const SkImageInfo info = origInfo.makeWH(srcR.width(), srcR.height());
715 // if x or y are negative, then we have to adjust pixels
722 // here x,y are either 0 or negative
723 dstP = ((char*)dstP - y * rowBytes - x * info.bytesPerPixel());
725 // The device can assert that the requested area is always contained in its bounds
726 return device->readPixels(info, dstP, rowBytes, srcR.x(), srcR.y());
729 bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
730 if (bitmap.getTexture()) {
735 if (bm.getPixels()) {
736 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
741 bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
743 switch (origInfo.colorType()) {
744 case kUnknown_SkColorType:
745 case kIndex_8_SkColorType:
750 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
754 const SkISize size = this->getBaseLayerSize();
755 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
756 if (!target.intersect(0, 0, size.width(), size.height())) {
760 SkBaseDevice* device = this->getDevice();
765 // the intersect may have shrunk info's logical size
766 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
768 // if x or y are negative, then we have to adjust pixels
775 // here x,y are either 0 or negative
776 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
778 // Tell our owning surface to bump its generation ID
779 this->predrawNotify();
781 // The device can assert that the requested area is always contained in its bounds
782 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
785 SkCanvas* SkCanvas::canvasForDrawIter() {
789 //////////////////////////////////////////////////////////////////////////////
791 void SkCanvas::updateDeviceCMCache() {
792 if (fDeviceCMDirty) {
793 const SkMatrix& totalMatrix = this->getTotalMatrix();
794 const SkRasterClip& totalClip = fMCRec->fRasterClip;
795 DeviceCM* layer = fMCRec->fTopLayer;
797 if (NULL == layer->fNext) { // only one layer
798 layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
800 SkRasterClip clip(totalClip);
802 layer->updateMC(totalMatrix, clip, fClipStack, &clip);
803 } while ((layer = layer->fNext) != NULL);
805 fDeviceCMDirty = false;
809 ///////////////////////////////////////////////////////////////////////////////
811 int SkCanvas::internalSave() {
812 int saveCount = this->getSaveCount(); // record this before the actual save
814 MCRec* newTop = (MCRec*)fMCStack.push_back();
815 new (newTop) MCRec(*fMCRec); // balanced in restore()
823 int SkCanvas::save() {
825 return this->internalSave();
828 static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
829 #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
830 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
836 bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
837 SkIRect* intersection, const SkImageFilter* imageFilter) {
839 SkRegion::Op op = SkRegion::kIntersect_Op;
840 if (!this->getClipDeviceBounds(&clipBounds)) {
845 imageFilter->filterBounds(clipBounds, fMCRec->fMatrix, &clipBounds);
846 // Filters may grow the bounds beyond the device bounds.
847 op = SkRegion::kReplace_Op;
853 this->getTotalMatrix().mapRect(&r, *bounds);
855 // early exit if the layer's bounds are clipped out
856 if (!ir.intersect(clipBounds)) {
857 if (bounds_affects_clip(flags)) {
858 fMCRec->fRasterClip.setEmpty();
862 } else { // no user bounds, so just use the clip
866 if (bounds_affects_clip(flags)) {
867 fClipStack.clipDevRect(ir, op);
868 // early exit if the clip is now empty
869 if (!fMCRec->fRasterClip.op(ir, op)) {
880 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
881 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
882 return this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, false, strategy);
885 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
887 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
888 return this->internalSaveLayer(bounds, paint, flags, false, strategy);
891 int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
892 bool justForImageFilter, SaveLayerStrategy strategy) {
893 #ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
894 flags |= kClipToLayer_SaveFlag;
897 // do this before we create the layer. We don't call the public save() since
898 // that would invoke a possibly overridden virtual
899 int count = this->internalSave();
901 fDeviceCMDirty = true;
904 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
908 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
909 // the clipRectBounds() call above?
910 if (kNoLayer_SaveLayerStrategy == strategy) {
914 // Kill the imagefilter if our device doesn't allow it
916 if (paint && paint->getImageFilter()) {
917 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
918 if (justForImageFilter) {
919 // early exit if the layer was just for the imageFilter
922 SkPaint* p = lazyP.set(*paint);
923 p->setImageFilter(NULL);
928 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
929 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
930 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
932 SkBaseDevice* device;
933 if (paint && paint->getImageFilter()) {
934 device = this->getDevice();
936 device = device->createCompatibleDevice(info);
939 device = this->createLayerDevice(info);
941 if (NULL == device) {
942 SkDebugf("Unable to create device for layer.");
945 this->setupDevice(device);
947 device->setOrigin(ir.fLeft, ir.fTop);
948 DeviceCM* layer = SkNEW_ARGS(DeviceCM,
949 (device, ir.fLeft, ir.fTop, paint, this, fConservativeRasterClip));
952 layer->fNext = fMCRec->fTopLayer;
953 fMCRec->fLayer = layer;
954 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
956 fSaveLayerCount += 1;
960 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
961 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
964 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
967 return this->saveLayer(bounds, NULL, flags);
970 tmpPaint.setAlpha(alpha);
971 return this->saveLayer(bounds, &tmpPaint, flags);
975 void SkCanvas::restore() {
976 // check for underflow
977 if (fMCStack.count() > 1) {
979 this->internalRestore();
984 void SkCanvas::internalRestore() {
985 SkASSERT(fMCStack.count() != 0);
987 fDeviceCMDirty = true;
988 fCachedLocalClipBoundsDirty = true;
990 fClipStack.restore();
992 // reserve our layer (if any)
993 DeviceCM* layer = fMCRec->fLayer; // may be null
994 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
995 fMCRec->fLayer = NULL;
997 // now do the normal restore()
998 fMCRec->~MCRec(); // balanced in save()
1000 fMCRec = (MCRec*)fMCStack.back();
1002 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1003 since if we're being recorded, we don't want to record this (the
1004 recorder will have already recorded the restore).
1008 const SkIPoint& origin = layer->fDevice->getOrigin();
1009 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
1011 // reset this, since internalDrawDevice will have set it to true
1012 fDeviceCMDirty = true;
1014 SkASSERT(fSaveLayerCount > 0);
1015 fSaveLayerCount -= 1;
1021 int SkCanvas::getSaveCount() const {
1022 return fMCStack.count();
1025 void SkCanvas::restoreToCount(int count) {
1031 int n = this->getSaveCount() - count;
1032 for (int i = 0; i < n; ++i) {
1037 bool SkCanvas::isDrawingToLayer() const {
1038 return fSaveLayerCount > 0;
1041 SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1042 if (NULL == props) {
1045 return this->onNewSurface(info, *props);
1048 SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1049 SkBaseDevice* dev = this->getDevice();
1050 return dev ? dev->newSurface(info, props) : NULL;
1053 SkImageInfo SkCanvas::imageInfo() const {
1054 SkBaseDevice* dev = this->getDevice();
1056 return dev->imageInfo();
1058 return SkImageInfo::MakeUnknown(0, 0);
1062 const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1063 return this->onPeekPixels(info, rowBytes);
1066 const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1067 SkBaseDevice* dev = this->getDevice();
1068 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1071 void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1072 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1073 if (pixels && origin) {
1074 *origin = this->getTopDevice(false)->getOrigin();
1079 void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1080 SkBaseDevice* dev = this->getTopDevice();
1081 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1084 SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1085 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1086 if (NULL == fAddr) {
1087 fInfo = canvas->imageInfo();
1088 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
1089 return; // failure, fAddr is NULL
1091 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1092 return; // failure, fAddr is NULL
1094 fAddr = fBitmap.getPixels();
1095 fRowBytes = fBitmap.rowBytes();
1097 SkASSERT(fAddr); // success
1100 bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1102 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
1109 void SkCanvas::onPushCull(const SkRect& cullRect) {
1110 // do nothing. Subclasses may do something
1113 void SkCanvas::onPopCull() {
1114 // do nothing. Subclasses may do something
1117 /////////////////////////////////////////////////////////////////////////////
1119 // Ensure that cull rects are monotonically nested in device space.
1120 void SkCanvas::validateCull(const SkIRect& devCull) {
1121 if (fCullStack.isEmpty()
1122 || devCull.isEmpty()
1123 || fCullStack.top().contains(devCull)) {
1127 SkDEBUGF(("Invalid cull: [%d %d %d %d] (previous cull: [%d %d %d %d])\n",
1128 devCull.x(), devCull.y(), devCull.right(), devCull.bottom(),
1129 fCullStack.top().x(), fCullStack.top().y(),
1130 fCullStack.top().right(), fCullStack.top().bottom()));
1132 #ifdef ASSERT_NESTED_CULLING
1133 SkDEBUGFAIL("Invalid cull.");
1138 void SkCanvas::pushCull(const SkRect& cullRect) {
1140 this->onPushCull(cullRect);
1143 // Map the cull rect into device space.
1145 this->getTotalMatrix().mapRect(&mappedCull, cullRect);
1147 // Take clipping into account.
1148 SkIRect devClip, devCull;
1149 mappedCull.roundOut(&devCull);
1150 this->getClipDeviceBounds(&devClip);
1151 if (!devCull.intersect(devClip)) {
1155 this->validateCull(devCull);
1156 fCullStack.push(devCull); // balanced in popCull
1160 void SkCanvas::popCull() {
1161 SkASSERT(fCullStack.count() == fCullCount);
1163 if (fCullCount > 0) {
1167 SkDEBUGCODE(fCullStack.pop());
1171 /////////////////////////////////////////////////////////////////////////////
1173 void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
1174 const SkMatrix& matrix, const SkPaint* paint) {
1175 if (bitmap.drawsNothing()) {
1180 if (NULL == paint) {
1181 paint = lazy.init();
1184 SkDEBUGCODE(bitmap.validate();)
1187 const SkRect* bounds = NULL;
1188 if (paint && paint->canComputeFastBounds()) {
1189 bitmap.getBounds(&storage);
1190 matrix.mapRect(&storage);
1191 bounds = &paint->computeFastBounds(storage, &storage);
1194 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
1196 while (iter.next()) {
1197 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1203 void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
1204 const SkPaint* paint) {
1206 if (NULL == paint) {
1207 tmp.setDither(true);
1211 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
1212 while (iter.next()) {
1213 SkBaseDevice* dstDev = iter.fDevice;
1214 paint = &looper.paint();
1215 SkImageFilter* filter = paint->getImageFilter();
1216 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1217 if (filter && !dstDev->canHandleImageFilter(filter)) {
1218 SkDeviceImageFilterProxy proxy(dstDev);
1220 SkIPoint offset = SkIPoint::Make(0, 0);
1221 const SkBitmap& src = srcDev->accessBitmap(false);
1222 SkMatrix matrix = *iter.fMatrix;
1223 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
1224 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
1225 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
1226 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
1227 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
1228 SkPaint tmpUnfiltered(*paint);
1229 tmpUnfiltered.setImageFilter(NULL);
1230 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1234 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
1240 void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
1241 const SkPaint* paint) {
1242 if (bitmap.drawsNothing()) {
1245 SkDEBUGCODE(bitmap.validate();)
1248 if (NULL == paint) {
1252 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
1254 while (iter.next()) {
1255 paint = &looper.paint();
1256 SkImageFilter* filter = paint->getImageFilter();
1257 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1258 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
1259 SkDeviceImageFilterProxy proxy(iter.fDevice);
1261 SkIPoint offset = SkIPoint::Make(0, 0);
1262 SkMatrix matrix = *iter.fMatrix;
1263 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
1264 SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1265 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
1266 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
1267 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
1268 SkPaint tmpUnfiltered(*paint);
1269 tmpUnfiltered.setImageFilter(NULL);
1270 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1274 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1280 /////////////////////////////////////////////////////////////////////////////
1281 void SkCanvas::translate(SkScalar dx, SkScalar dy) {
1283 m.setTranslate(dx, dy);
1287 void SkCanvas::scale(SkScalar sx, SkScalar sy) {
1293 void SkCanvas::rotate(SkScalar degrees) {
1295 m.setRotate(degrees);
1299 void SkCanvas::skew(SkScalar sx, SkScalar sy) {
1305 void SkCanvas::concat(const SkMatrix& matrix) {
1306 if (matrix.isIdentity()) {
1310 fDeviceCMDirty = true;
1311 fCachedLocalClipBoundsDirty = true;
1312 fMCRec->fMatrix.preConcat(matrix);
1314 this->didConcat(matrix);
1317 void SkCanvas::setMatrix(const SkMatrix& matrix) {
1318 fDeviceCMDirty = true;
1319 fCachedLocalClipBoundsDirty = true;
1320 fMCRec->fMatrix = matrix;
1321 this->didSetMatrix(matrix);
1324 void SkCanvas::resetMatrix() {
1328 this->setMatrix(matrix);
1331 //////////////////////////////////////////////////////////////////////////////
1333 void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
1334 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1335 this->onClipRect(rect, op, edgeStyle);
1338 void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1339 #ifdef SK_ENABLE_CLIP_QUICKREJECT
1340 if (SkRegion::kIntersect_Op == op) {
1341 if (fMCRec->fRasterClip.isEmpty()) {
1345 if (this->quickReject(rect)) {
1346 fDeviceCMDirty = true;
1347 fCachedLocalClipBoundsDirty = true;
1349 fClipStack.clipEmpty();
1350 return fMCRec->fRasterClip.setEmpty();
1355 AutoValidateClip avc(this);
1357 fDeviceCMDirty = true;
1358 fCachedLocalClipBoundsDirty = true;
1359 if (!fAllowSoftClip) {
1360 edgeStyle = kHard_ClipEdgeStyle;
1363 if (fMCRec->fMatrix.rectStaysRect()) {
1364 // for these simpler matrices, we can stay a rect even after applying
1365 // the matrix. This means we don't have to a) make a path, and b) tell
1366 // the region code to scan-convert the path, only to discover that it
1367 // is really just a rect.
1370 fMCRec->fMatrix.mapRect(&r, rect);
1371 fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
1372 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
1374 // since we're rotated or some such thing, we convert the rect to a path
1375 // and clip against that, since it can handle any matrix. However, to
1376 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1377 // we explicitly call "our" version of clipPath.
1381 this->SkCanvas::onClipPath(path, op, edgeStyle);
1385 static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1386 SkRegion::Op op, bool doAA) {
1387 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
1390 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
1391 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1392 if (rrect.isRect()) {
1393 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1395 this->onClipRRect(rrect, op, edgeStyle);
1399 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1400 SkRRect transformedRRect;
1401 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
1402 AutoValidateClip avc(this);
1404 fDeviceCMDirty = true;
1405 fCachedLocalClipBoundsDirty = true;
1406 if (!fAllowSoftClip) {
1407 edgeStyle = kHard_ClipEdgeStyle;
1410 fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
1413 devPath.addRRect(transformedRRect);
1415 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
1420 path.addRRect(rrect);
1421 // call the non-virtual version
1422 this->SkCanvas::onClipPath(path, op, edgeStyle);
1425 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
1426 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1428 if (!path.isInverseFillType() && path.isRect(&r)) {
1429 this->onClipRect(r, op, edgeStyle);
1431 this->onClipPath(path, op, edgeStyle);
1435 void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1436 #ifdef SK_ENABLE_CLIP_QUICKREJECT
1437 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
1438 if (fMCRec->fRasterClip.isEmpty()) {
1442 if (this->quickReject(path.getBounds())) {
1443 fDeviceCMDirty = true;
1444 fCachedLocalClipBoundsDirty = true;
1446 fClipStack.clipEmpty();
1447 return fMCRec->fRasterClip.setEmpty();
1452 AutoValidateClip avc(this);
1454 fDeviceCMDirty = true;
1455 fCachedLocalClipBoundsDirty = true;
1456 if (!fAllowSoftClip) {
1457 edgeStyle = kHard_ClipEdgeStyle;
1461 path.transform(fMCRec->fMatrix, &devPath);
1463 // Check if the transfomation, or the original path itself
1464 // made us empty. Note this can also happen if we contained NaN
1465 // values. computing the bounds detects this, and will set our
1466 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1467 if (devPath.getBounds().isEmpty()) {
1468 // resetting the path will remove any NaN or other wanky values
1469 // that might upset our scan converter.
1473 // if we called path.swap() we could avoid a deep copy of this path
1474 fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
1476 if (fAllowSimplifyClip) {
1478 devPath.setFillType(SkPath::kInverseEvenOdd_FillType);
1479 const SkClipStack* clipStack = getClipStack();
1480 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
1481 const SkClipStack::Element* element;
1482 while ((element = iter.next())) {
1483 SkClipStack::Element::Type type = element->getType();
1485 if (type != SkClipStack::Element::kEmpty_Type) {
1486 element->asPath(&operand);
1488 SkRegion::Op elementOp = element->getOp();
1489 if (elementOp == SkRegion::kReplace_Op) {
1492 Op(devPath, operand, (SkPathOp) elementOp, &devPath);
1494 // if the prev and curr clips disagree about aa -vs- not, favor the aa request.
1495 // perhaps we need an API change to avoid this sort of mixed-signals about
1497 if (element->isAA()) {
1498 edgeStyle = kSoft_ClipEdgeStyle;
1501 op = SkRegion::kReplace_Op;
1504 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
1507 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
1508 this->onClipRegion(rgn, op);
1511 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
1512 AutoValidateClip avc(this);
1514 fDeviceCMDirty = true;
1515 fCachedLocalClipBoundsDirty = true;
1517 // todo: signal fClipStack that we have a region, and therefore (I guess)
1518 // we have to ignore it, and use the region directly?
1519 fClipStack.clipDevRect(rgn.getBounds(), op);
1521 fMCRec->fRasterClip.op(rgn, op);
1525 void SkCanvas::validateClip() const {
1526 // construct clipRgn from the clipstack
1527 const SkBaseDevice* device = this->getDevice();
1529 SkASSERT(this->isClipEmpty());
1534 ir.set(0, 0, device->width(), device->height());
1535 SkRasterClip tmpClip(ir, fConservativeRasterClip);
1537 SkClipStack::B2TIter iter(fClipStack);
1538 const SkClipStack::Element* element;
1539 while ((element = iter.next()) != NULL) {
1540 switch (element->getType()) {
1541 case SkClipStack::Element::kRect_Type:
1542 element->getRect().round(&ir);
1543 tmpClip.op(ir, element->getOp());
1545 case SkClipStack::Element::kEmpty_Type:
1550 element->asPath(&path);
1551 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
1559 void SkCanvas::replayClips(ClipVisitor* visitor) const {
1560 SkClipStack::B2TIter iter(fClipStack);
1561 const SkClipStack::Element* element;
1563 while ((element = iter.next()) != NULL) {
1564 element->replay(visitor);
1568 ///////////////////////////////////////////////////////////////////////////////
1570 bool SkCanvas::isClipEmpty() const {
1571 return fMCRec->fRasterClip.isEmpty();
1574 bool SkCanvas::isClipRect() const {
1575 return fMCRec->fRasterClip.isRect();
1578 bool SkCanvas::quickReject(const SkRect& rect) const {
1579 if (!rect.isFinite())
1582 if (fMCRec->fRasterClip.isEmpty()) {
1586 if (fMCRec->fMatrix.hasPerspective()) {
1588 fMCRec->fMatrix.mapRect(&dst, rect);
1590 dst.roundOut(&idst);
1591 return !SkIRect::Intersects(idst, fMCRec->fRasterClip.getBounds());
1593 const SkRect& clipR = this->getLocalClipBounds();
1595 // for speed, do the most likely reject compares first
1596 // TODO: should we use | instead, or compare all 4 at once?
1597 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
1600 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
1607 bool SkCanvas::quickReject(const SkPath& path) const {
1608 return path.isEmpty() || this->quickReject(path.getBounds());
1611 bool SkCanvas::getClipBounds(SkRect* bounds) const {
1613 if (!this->getClipDeviceBounds(&ibounds)) {
1618 // if we can't invert the CTM, we can't return local clip bounds
1619 if (!fMCRec->fMatrix.invert(&inverse)) {
1628 // adjust it outwards in case we are antialiasing
1629 const int inset = 1;
1631 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1632 ibounds.fRight + inset, ibounds.fBottom + inset);
1633 inverse.mapRect(bounds, r);
1638 bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
1639 const SkRasterClip& clip = fMCRec->fRasterClip;
1640 if (clip.isEmpty()) {
1648 *bounds = clip.getBounds();
1653 const SkMatrix& SkCanvas::getTotalMatrix() const {
1654 return fMCRec->fMatrix;
1657 const SkRegion& SkCanvas::internal_private_getTotalClip() const {
1658 return fMCRec->fRasterClip.forceGetBW();
1661 GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1662 SkBaseDevice* dev = this->getTopDevice();
1663 return dev ? dev->accessRenderTarget() : NULL;
1666 SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) {
1667 SkBaseDevice* device = this->getTopDevice();
1668 return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL;
1671 GrContext* SkCanvas::getGrContext() {
1673 SkBaseDevice* device = this->getTopDevice();
1675 GrRenderTarget* renderTarget = device->accessRenderTarget();
1677 return renderTarget->getContext();
1686 void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1687 const SkPaint& paint) {
1688 if (outer.isEmpty()) {
1691 if (inner.isEmpty()) {
1692 this->drawRRect(outer, paint);
1696 // We don't have this method (yet), but technically this is what we should
1697 // be able to assert...
1698 // SkASSERT(outer.contains(inner));
1700 // For now at least check for containment of bounds
1701 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1703 this->onDrawDRRect(outer, inner, paint);
1706 //////////////////////////////////////////////////////////////////////////////
1707 // These are the virtual drawing methods
1708 //////////////////////////////////////////////////////////////////////////////
1710 void SkCanvas::clear(SkColor color) {
1711 SkDrawIter iter(this);
1712 this->predrawNotify();
1713 while (iter.next()) {
1714 iter.fDevice->clear(color);
1718 void SkCanvas::onDiscard() {
1720 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1724 void SkCanvas::drawPaint(const SkPaint& paint) {
1725 this->internalDrawPaint(paint);
1728 void SkCanvas::internalDrawPaint(const SkPaint& paint) {
1729 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
1731 while (iter.next()) {
1732 iter.fDevice->drawPaint(iter, looper.paint());
1738 void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
1739 const SkPaint& paint) {
1740 if ((long)count <= 0) {
1745 const SkRect* bounds = NULL;
1746 if (paint.canComputeFastBounds()) {
1747 // special-case 2 points (common for drawing a single line)
1749 r.set(pts[0], pts[1]);
1751 r.set(pts, SkToInt(count));
1753 bounds = &paint.computeFastStrokeBounds(r, &storage);
1754 if (this->quickReject(*bounds)) {
1759 SkASSERT(pts != NULL);
1761 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
1763 while (iter.next()) {
1764 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
1770 void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1772 const SkRect* bounds = NULL;
1773 if (paint.canComputeFastBounds()) {
1774 bounds = &paint.computeFastBounds(r, &storage);
1775 if (this->quickReject(*bounds)) {
1780 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
1782 while (iter.next()) {
1783 iter.fDevice->drawRect(iter, r, looper.paint());
1789 void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
1791 const SkRect* bounds = NULL;
1792 if (paint.canComputeFastBounds()) {
1793 bounds = &paint.computeFastBounds(oval, &storage);
1794 if (this->quickReject(*bounds)) {
1799 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
1801 while (iter.next()) {
1802 iter.fDevice->drawOval(iter, oval, looper.paint());
1808 void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1810 const SkRect* bounds = NULL;
1811 if (paint.canComputeFastBounds()) {
1812 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1813 if (this->quickReject(*bounds)) {
1818 if (rrect.isRect()) {
1819 // call the non-virtual version
1820 this->SkCanvas::drawRect(rrect.getBounds(), paint);
1822 } else if (rrect.isOval()) {
1823 // call the non-virtual version
1824 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1828 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
1830 while (iter.next()) {
1831 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1837 void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1838 const SkPaint& paint) {
1840 const SkRect* bounds = NULL;
1841 if (paint.canComputeFastBounds()) {
1842 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1843 if (this->quickReject(*bounds)) {
1848 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
1850 while (iter.next()) {
1851 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1857 void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1858 if (!path.isFinite()) {
1863 const SkRect* bounds = NULL;
1864 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
1865 const SkRect& pathBounds = path.getBounds();
1866 bounds = &paint.computeFastBounds(pathBounds, &storage);
1867 if (this->quickReject(*bounds)) {
1872 const SkRect& r = path.getBounds();
1873 if (r.width() <= 0 && r.height() <= 0) {
1874 if (path.isInverseFillType()) {
1875 this->internalDrawPaint(paint);
1880 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
1882 while (iter.next()) {
1883 iter.fDevice->drawPath(iter, path, looper.paint());
1889 void SkCanvas::drawImage(const SkImage* image, SkScalar left, SkScalar top,
1890 const SkPaint* paint) {
1891 image->draw(this, left, top, paint);
1894 void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src,
1896 const SkPaint* paint) {
1897 image->draw(this, src, dst, paint);
1900 void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
1901 const SkPaint* paint) {
1902 SkDEBUGCODE(bitmap.validate();)
1904 if (NULL == paint || paint->canComputeFastBounds()) {
1907 x + SkIntToScalar(bitmap.width()),
1908 y + SkIntToScalar(bitmap.height())
1911 (void)paint->computeFastBounds(bounds, &bounds);
1913 if (this->quickReject(bounds)) {
1919 matrix.setTranslate(x, y);
1920 this->internalDrawBitmap(bitmap, matrix, paint);
1923 // this one is non-virtual, so it can be called safely by other canvas apis
1924 void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
1925 const SkRect& dst, const SkPaint* paint,
1926 DrawBitmapRectFlags flags) {
1927 if (bitmap.drawsNothing() || dst.isEmpty()) {
1932 const SkRect* bounds = &dst;
1933 if (NULL == paint || paint->canComputeFastBounds()) {
1935 bounds = &paint->computeFastBounds(dst, &storage);
1937 if (this->quickReject(*bounds)) {
1943 if (NULL == paint) {
1944 paint = lazy.init();
1947 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
1949 while (iter.next()) {
1950 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
1956 void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
1957 const SkRect& dst, const SkPaint* paint,
1958 DrawBitmapRectFlags flags) {
1959 SkDEBUGCODE(bitmap.validate();)
1960 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
1963 void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
1964 const SkPaint* paint) {
1965 SkDEBUGCODE(bitmap.validate();)
1966 this->internalDrawBitmap(bitmap, matrix, paint);
1969 void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1970 const SkIRect& center, const SkRect& dst,
1971 const SkPaint* paint) {
1972 if (bitmap.drawsNothing()) {
1975 if (NULL == paint || paint->canComputeFastBounds()) {
1977 const SkRect* bounds = &dst;
1979 bounds = &paint->computeFastBounds(dst, &storage);
1981 if (this->quickReject(*bounds)) {
1986 const int32_t w = bitmap.width();
1987 const int32_t h = bitmap.height();
1990 // pin center to the bounds of the bitmap
1991 c.fLeft = SkMax32(0, center.fLeft);
1992 c.fTop = SkMax32(0, center.fTop);
1993 c.fRight = SkPin32(center.fRight, c.fLeft, w);
1994 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
1996 const SkScalar srcX[4] = {
1997 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
1999 const SkScalar srcY[4] = {
2000 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
2002 SkScalar dstX[4] = {
2003 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2004 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2006 SkScalar dstY[4] = {
2007 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2008 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2011 if (dstX[1] > dstX[2]) {
2012 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2016 if (dstY[1] > dstY[2]) {
2017 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2021 for (int y = 0; y < 3; y++) {
2025 s.fBottom = srcY[y+1];
2027 d.fBottom = dstY[y+1];
2028 for (int x = 0; x < 3; x++) {
2030 s.fRight = srcX[x+1];
2032 d.fRight = dstX[x+1];
2033 this->internalDrawBitmapRect(bitmap, &s, d, paint,
2034 kNone_DrawBitmapRectFlag);
2039 void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
2040 const SkRect& dst, const SkPaint* paint) {
2041 SkDEBUGCODE(bitmap.validate();)
2043 // Need a device entry-point, so gpu can use a mesh
2044 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2047 class SkDeviceFilteredPaint {
2049 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
2050 SkBaseDevice::TextFlags flags;
2051 if (device->filterTextFlags(paint, &flags)) {
2052 SkPaint* newPaint = fLazy.set(paint);
2053 newPaint->setFlags(flags.fFlags);
2060 const SkPaint& paint() const { return *fPaint; }
2063 const SkPaint* fPaint;
2067 void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2068 const SkRect& r, SkScalar textSize) {
2069 if (paint.getStyle() == SkPaint::kFill_Style) {
2070 draw.fDevice->drawRect(draw, r, paint);
2073 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
2074 draw.fDevice->drawRect(draw, r, p);
2078 void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2079 const char text[], size_t byteLength,
2080 SkScalar x, SkScalar y) {
2081 SkASSERT(byteLength == 0 || text != NULL);
2084 if (text == NULL || byteLength == 0 ||
2085 draw.fClip->isEmpty() ||
2086 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2093 start.set(0, 0); // to avoid warning
2094 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2095 SkPaint::kStrikeThruText_Flag)) {
2096 width = paint.measureText(text, byteLength);
2098 SkScalar offsetX = 0;
2099 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2100 offsetX = SkScalarHalf(width);
2101 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2104 start.set(x - offsetX, y);
2111 uint32_t flags = paint.getFlags();
2113 if (flags & (SkPaint::kUnderlineText_Flag |
2114 SkPaint::kStrikeThruText_Flag)) {
2115 SkScalar textSize = paint.getTextSize();
2116 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2120 r.fRight = start.fX + width;
2122 if (flags & SkPaint::kUnderlineText_Flag) {
2123 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2126 r.fBottom = offset + height;
2127 DrawRect(draw, paint, r, textSize);
2129 if (flags & SkPaint::kStrikeThruText_Flag) {
2130 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2133 r.fBottom = offset + height;
2134 DrawRect(draw, paint, r, textSize);
2139 void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2140 const SkPaint& paint) {
2141 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2143 while (iter.next()) {
2144 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2145 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
2146 DrawTextDecorations(iter, dfp.paint(),
2147 static_cast<const char*>(text), byteLength, x, y);
2153 void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2154 const SkPaint& paint) {
2155 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2157 while (iter.next()) {
2158 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2159 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
2166 void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2167 SkScalar constY, const SkPaint& paint) {
2168 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2170 while (iter.next()) {
2171 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2172 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
2179 void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2180 const SkMatrix* matrix, const SkPaint& paint) {
2181 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2183 while (iter.next()) {
2184 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
2185 matrix, looper.paint());
2191 void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2192 const SkPaint& paint) {
2194 // FIXME: temporarily disable quickreject for empty bounds,
2195 // pending implicit blob bounds implementation.
2196 if (!blob->bounds().isEmpty() && paint.canComputeFastBounds()) {
2199 if (this->quickReject(paint.computeFastBounds(blob->bounds().makeOffset(x, y), &storage))) {
2204 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2206 while (iter.next()) {
2207 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2208 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint());
2214 // These will become non-virtual, so they always call the (virtual) onDraw... method
2215 void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2216 const SkPaint& paint) {
2217 this->onDrawText(text, byteLength, x, y, paint);
2219 void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2220 const SkPaint& paint) {
2221 this->onDrawPosText(text, byteLength, pos, paint);
2223 void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2224 SkScalar constY, const SkPaint& paint) {
2225 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2227 void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2228 const SkMatrix* matrix, const SkPaint& paint) {
2229 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2231 void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2232 const SkPaint& paint) {
2234 this->onDrawTextBlob(blob, x, y, paint);
2238 void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
2239 const SkPoint verts[], const SkPoint texs[],
2240 const SkColor colors[], SkXfermode* xmode,
2241 const uint16_t indices[], int indexCount,
2242 const SkPaint& paint) {
2243 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
2245 while (iter.next()) {
2246 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
2247 colors, xmode, indices, indexCount,
2254 void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2255 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2256 if (NULL == cubics) {
2260 // Since a patch is always within the convex hull of the control points, we discard it when its
2261 // bounding rectangle is completely outside the current clip.
2263 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
2264 if (this->quickReject(bounds)) {
2268 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2271 void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2272 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2274 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
2276 while (iter.next()) {
2277 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
2283 //////////////////////////////////////////////////////////////////////////////
2284 // These methods are NOT virtual, and therefore must call back into virtual
2285 // methods, rather than actually drawing themselves.
2286 //////////////////////////////////////////////////////////////////////////////
2288 void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
2289 SkXfermode::Mode mode) {
2292 paint.setARGB(a, r, g, b);
2293 if (SkXfermode::kSrcOver_Mode != mode) {
2294 paint.setXfermodeMode(mode);
2296 this->drawPaint(paint);
2299 void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
2303 if (SkXfermode::kSrcOver_Mode != mode) {
2304 paint.setXfermodeMode(mode);
2306 this->drawPaint(paint);
2309 void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
2313 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2316 void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
2321 paint.setColor(color);
2322 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2325 void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2326 const SkPaint& paint) {
2331 this->drawPoints(kLines_PointMode, 2, pts, paint);
2334 void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2335 SkScalar right, SkScalar bottom,
2336 const SkPaint& paint) {
2339 r.set(left, top, right, bottom);
2340 this->drawRect(r, paint);
2343 void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2344 const SkPaint& paint) {
2350 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
2351 this->drawOval(r, paint);
2354 void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2355 const SkPaint& paint) {
2356 if (rx > 0 && ry > 0) {
2357 if (paint.canComputeFastBounds()) {
2359 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
2364 rrect.setRectXY(r, rx, ry);
2365 this->drawRRect(rrect, paint);
2367 this->drawRect(r, paint);
2371 void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2372 SkScalar sweepAngle, bool useCenter,
2373 const SkPaint& paint) {
2374 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2375 this->drawOval(oval, paint);
2379 path.moveTo(oval.centerX(), oval.centerY());
2381 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2385 this->drawPath(path, paint);
2389 void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2390 const SkPath& path, SkScalar hOffset,
2391 SkScalar vOffset, const SkPaint& paint) {
2394 matrix.setTranslate(hOffset, vOffset);
2395 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2398 ///////////////////////////////////////////////////////////////////////////////
2399 void SkCanvas::EXPERIMENTAL_optimize(const SkPicture* picture) {
2400 SkBaseDevice* device = this->getDevice();
2402 device->EXPERIMENTAL_optimize(picture);
2406 void SkCanvas::drawPicture(const SkPicture* picture) {
2408 this->onDrawPicture(picture, NULL, NULL);
2412 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
2414 if (matrix && matrix->isIdentity()) {
2417 this->onDrawPicture(picture, matrix, paint);
2421 void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2422 const SkPaint* paint) {
2423 SkBaseDevice* device = this->getTopDevice();
2425 // Canvas has to first give the device the opportunity to render
2426 // the picture itself.
2427 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
2428 return; // the device has rendered the entire picture
2432 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2434 picture->playback(this);
2437 ///////////////////////////////////////////////////////////////////////////////
2438 ///////////////////////////////////////////////////////////////////////////////
2440 SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
2441 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
2445 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2446 fDone = !fImpl->next();
2449 SkCanvas::LayerIter::~LayerIter() {
2450 fImpl->~SkDrawIter();
2453 void SkCanvas::LayerIter::next() {
2454 fDone = !fImpl->next();
2457 SkBaseDevice* SkCanvas::LayerIter::device() const {
2458 return fImpl->getDevice();
2461 const SkMatrix& SkCanvas::LayerIter::matrix() const {
2462 return fImpl->getMatrix();
2465 const SkPaint& SkCanvas::LayerIter::paint() const {
2466 const SkPaint* paint = fImpl->getPaint();
2467 if (NULL == paint) {
2468 paint = &fDefaultPaint;
2473 const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2474 int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2475 int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
2477 ///////////////////////////////////////////////////////////////////////////////
2479 SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
2481 ///////////////////////////////////////////////////////////////////////////////
2483 static bool supported_for_raster_canvas(const SkImageInfo& info) {
2484 switch (info.alphaType()) {
2485 case kPremul_SkAlphaType:
2486 case kOpaque_SkAlphaType:
2492 switch (info.colorType()) {
2493 case kAlpha_8_SkColorType:
2494 case kRGB_565_SkColorType:
2495 case kN32_SkColorType:
2504 SkCanvas* SkCanvas::NewRaster(const SkImageInfo& info) {
2505 if (!supported_for_raster_canvas(info)) {
2510 if (!bitmap.tryAllocPixels(info)) {
2514 // should this functionality be moved into allocPixels()?
2515 if (!bitmap.info().isOpaque()) {
2516 bitmap.eraseColor(0);
2518 return SkNEW_ARGS(SkCanvas, (bitmap));
2521 SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2522 if (!supported_for_raster_canvas(info)) {
2527 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2530 return SkNEW_ARGS(SkCanvas, (bitmap));
2533 ///////////////////////////////////////////////////////////////////////////////
2535 SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
2536 const SkPaint* paint, const SkRect& bounds)
2538 , fSaveCount(canvas->getSaveCount())
2541 SkRect newBounds = bounds;
2543 matrix->mapRect(&newBounds);
2545 canvas->saveLayer(&newBounds, paint);
2546 } else if (matrix) {
2551 canvas->concat(*matrix);
2555 SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2556 fCanvas->restoreToCount(fSaveCount);