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 "SkCanvasPriv.h"
11 #include "SkBitmapDevice.h"
12 #include "SkDeviceImageFilterProxy.h"
14 #include "SkDrawFilter.h"
15 #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 "SkTextFormatParams.h"
30 #include "GrRenderTarget.h"
33 // experimental for faster tiled drawing...
34 //#define SK_ENABLE_CLIP_QUICKREJECT
36 //#define SK_TRACE_SAVERESTORE
38 #ifdef SK_TRACE_SAVERESTORE
39 static int gLayerCounter;
40 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
41 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
43 static int gRecCounter;
44 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
45 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
47 static int gCanvasCounter;
48 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
49 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
59 typedef SkTLazy<SkPaint> SkLazyPaint;
61 void SkCanvas::predrawNotify() {
63 fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode);
67 ///////////////////////////////////////////////////////////////////////////////
69 /* This is the record we keep for each SkBaseDevice that the user installs.
70 The clip/matrix/proc are fields that reflect the top of the save/restore
71 stack. Whenever the canvas changes, it marks a dirty flag, and then before
72 these are used (assuming we're not on a layer) we rebuild these cache
73 values: they reflect the top of the save stack, but translated and clipped
74 by the device's XY offset and bitmap-bounds.
78 SkBaseDevice* fDevice;
80 const SkMatrix* fMatrix;
81 SkPaint* fPaint; // may be null (in the future)
83 DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas)
87 device->onAttachToCanvas(canvas);
90 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
94 if (NULL != fDevice) {
95 fDevice->onDetachFromCanvas();
101 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
102 const SkClipStack& clipStack, SkRasterClip* updateClip) {
103 int x = fDevice->getOrigin().x();
104 int y = fDevice->getOrigin().y();
105 int width = fDevice->width();
106 int height = fDevice->height();
109 fMatrix = &totalMatrix;
112 fMatrixStorage = totalMatrix;
113 fMatrixStorage.postTranslate(SkIntToScalar(-x),
115 fMatrix = &fMatrixStorage;
117 totalClip.translate(-x, -y, &fClip);
120 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
122 // intersect clip, but don't translate it (yet)
125 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
126 SkRegion::kDifference_Op);
129 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
132 if (!fClip.isEmpty()) {
134 deviceR.set(0, 0, width, height);
135 SkASSERT(deviceR.contains(fClip.getBounds()));
141 SkMatrix fMatrixStorage;
144 /* This is the record we keep for each save/restore level in the stack.
145 Since a level optionally copies the matrix and/or stack, we have pointers
146 for these fields. If the value is copied for this level, the copy is
147 stored in the ...Storage field, and the pointer points to that. If the
148 value is not copied for this level, we ignore ...Storage, and just point
149 at the corresponding value in the previous level in the stack.
151 class SkCanvas::MCRec {
154 SkRasterClip fRasterClip;
155 SkDrawFilter* fFilter; // the current filter (or null)
158 /* If there are any layers in the stack, this points to the top-most
159 one that is at or below this level in the stack (so we know what
160 bitmap/device to draw into from this level. This value is NOT
161 reference counted, since the real owner is either our fLayer field,
162 or a previous one in a lower level.)
166 MCRec(const MCRec* prev) {
168 fMatrix = prev->fMatrix;
169 fRasterClip = prev->fRasterClip;
171 fFilter = prev->fFilter;
174 fTopLayer = prev->fTopLayer;
182 // don't bother initializing fNext
186 SkSafeUnref(fFilter);
192 class SkDrawIter : public SkDraw {
194 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
195 canvas = canvas->canvasForDrawIter();
197 canvas->updateDeviceCMCache();
199 fClipStack = &canvas->fClipStack;
200 fCurrLayer = canvas->fMCRec->fTopLayer;
201 fSkipEmptyClips = skipEmptyClips;
205 // skip over recs with empty clips
206 if (fSkipEmptyClips) {
207 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
208 fCurrLayer = fCurrLayer->fNext;
212 const DeviceCM* rec = fCurrLayer;
213 if (rec && rec->fDevice) {
215 fMatrix = rec->fMatrix;
216 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
218 fDevice = rec->fDevice;
219 fBitmap = &fDevice->accessBitmap(true);
220 fPaint = rec->fPaint;
221 SkDEBUGCODE(this->validate();)
223 fCurrLayer = rec->fNext;
224 // fCurrLayer may be NULL now
231 SkBaseDevice* getDevice() const { return fDevice; }
232 int getX() const { return fDevice->getOrigin().x(); }
233 int getY() const { return fDevice->getOrigin().y(); }
234 const SkMatrix& getMatrix() const { return *fMatrix; }
235 const SkRegion& getClip() const { return *fClip; }
236 const SkPaint* getPaint() const { return fPaint; }
240 const DeviceCM* fCurrLayer;
241 const SkPaint* fPaint; // May be null.
242 SkBool8 fSkipEmptyClips;
244 typedef SkDraw INHERITED;
247 /////////////////////////////////////////////////////////////////////////////
249 class AutoDrawLooper {
251 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint,
252 bool skipLayerForImageFilter = false,
253 const SkRect* bounds = NULL) : fOrigPaint(paint) {
255 fFilter = canvas->getDrawFilter();
257 fSaveCount = canvas->getSaveCount();
258 fDoClearImageFilter = false;
261 if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
263 tmp.setImageFilter(fOrigPaint.getImageFilter());
264 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
265 true, SkCanvas::kFullLayer_SaveLayerStrategy);
266 // we'll clear the imageFilter for the actual draws in next(), so
267 // it will only be applied during the restore().
268 fDoClearImageFilter = true;
271 if (SkDrawLooper* looper = paint.getLooper()) {
272 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
273 looper->contextSize());
274 fLooperContext = looper->createContext(canvas, buffer);
277 fLooperContext = NULL;
278 // can we be marked as simple?
279 fIsSimple = !fFilter && !fDoClearImageFilter;
284 if (fDoClearImageFilter) {
285 fCanvas->internalRestore();
287 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
290 const SkPaint& paint() const {
295 bool next(SkDrawFilter::Type drawType) {
298 } else if (fIsSimple) {
300 fPaint = &fOrigPaint;
301 return !fPaint->nothingToDraw();
303 return this->doNext(drawType);
308 SkLazyPaint fLazyPaint;
310 const SkPaint& fOrigPaint;
311 SkDrawFilter* fFilter;
312 const SkPaint* fPaint;
314 bool fDoClearImageFilter;
317 SkDrawLooper::Context* fLooperContext;
318 SkSmallAllocator<1, 32> fLooperContextAllocator;
320 bool doNext(SkDrawFilter::Type drawType);
323 bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
325 SkASSERT(!fIsSimple);
326 SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
328 SkPaint* paint = fLazyPaint.set(fOrigPaint);
330 if (fDoClearImageFilter) {
331 paint->setImageFilter(NULL);
334 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
339 if (!fFilter->filter(paint, drawType)) {
343 if (NULL == fLooperContext) {
344 // no looper means we only draw once
350 // if we only came in here for the imagefilter, mark us as done
351 if (!fLooperContext && !fFilter) {
355 // call this after any possible paint modifiers
356 if (fPaint->nothingToDraw()) {
363 #include "SkColorPriv.h"
365 ////////// macros to place around the internal draw calls //////////////////
367 #define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
368 this->predrawNotify(); \
369 AutoDrawLooper looper(this, paint, true); \
370 while (looper.next(type)) { \
371 SkDrawIter iter(this);
373 #define LOOPER_BEGIN(paint, type, bounds) \
374 this->predrawNotify(); \
375 AutoDrawLooper looper(this, paint, false, bounds); \
376 while (looper.next(type)) { \
377 SkDrawIter iter(this);
381 ////////////////////////////////////////////////////////////////////////////
383 SkBaseDevice* SkCanvas::init(SkBaseDevice* device) {
384 fCachedLocalClipBounds.setEmpty();
385 fCachedLocalClipBoundsDirty = true;
386 fAllowSoftClip = true;
387 fAllowSimplifyClip = false;
388 fDeviceCMDirty = false;
393 fMCRec = (MCRec*)fMCStack.push_back();
394 new (fMCRec) MCRec(NULL);
396 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL));
397 fMCRec->fTopLayer = fMCRec->fLayer;
401 return this->setRootDevice(device);
405 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
412 SkCanvas::SkCanvas(int width, int height)
413 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
418 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
419 this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref();
422 SkCanvas::SkCanvas(SkBaseDevice* device)
423 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
430 SkCanvas::SkCanvas(const SkBitmap& bitmap)
431 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
435 this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref();
438 SkCanvas::~SkCanvas() {
439 // free up the contents of our deque
440 this->restoreToCount(1); // restore everything but the last
441 SkASSERT(0 == fSaveLayerCount);
443 this->internalRestore(); // restore the last, since we're going away
450 SkDrawFilter* SkCanvas::getDrawFilter() const {
451 return fMCRec->fFilter;
454 SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
455 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
459 SkMetaData& SkCanvas::getMetaData() {
460 // metadata users are rare, so we lazily allocate it. If that changes we
461 // can decide to just make it a field in the device (rather than a ptr)
462 if (NULL == fMetaData) {
463 fMetaData = new SkMetaData;
468 ///////////////////////////////////////////////////////////////////////////////
470 void SkCanvas::flush() {
471 SkBaseDevice* device = this->getDevice();
477 SkISize SkCanvas::getTopLayerSize() const {
478 SkBaseDevice* d = this->getTopDevice();
479 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
482 SkIPoint SkCanvas::getTopLayerOrigin() const {
483 SkBaseDevice* d = this->getTopDevice();
484 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
487 SkISize SkCanvas::getBaseLayerSize() const {
488 SkBaseDevice* d = this->getDevice();
489 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
492 SkBaseDevice* SkCanvas::getDevice() const {
493 // return root device
494 MCRec* rec = (MCRec*) fMCStack.front();
495 SkASSERT(rec && rec->fLayer);
496 return rec->fLayer->fDevice;
499 SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
500 if (updateMatrixClip) {
501 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
503 return fMCRec->fTopLayer->fDevice;
506 SkBaseDevice* SkCanvas::setRootDevice(SkBaseDevice* device) {
507 // return root device
508 SkDeque::F2BIter iter(fMCStack);
509 MCRec* rec = (MCRec*)iter.next();
510 SkASSERT(rec && rec->fLayer);
511 SkBaseDevice* rootDevice = rec->fLayer->fDevice;
513 if (rootDevice == device) {
518 device->onAttachToCanvas(this);
521 rootDevice->onDetachFromCanvas();
524 SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
527 fDeviceCMDirty = true;
529 /* Now we update our initial region to have the bounds of the new device,
530 and then intersect all of the clips in our stack with these bounds,
531 to ensure that we can't draw outside of the device's bounds (and trash
534 NOTE: this is only a partial-fix, since if the new device is larger than
535 the previous one, we don't know how to "enlarge" the clips in our stack,
536 so drawing may be artificially restricted. Without keeping a history of
537 all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
538 reconstruct the correct clips, so this approximation will have to do.
539 The caller really needs to restore() back to the base if they want to
540 accurately take advantage of the new device bounds.
545 bounds.set(0, 0, device->width(), device->height());
549 // now jam our 1st clip to be bounds, and intersect the rest with that
550 rec->fRasterClip.setRect(bounds);
551 while ((rec = (MCRec*)iter.next()) != NULL) {
552 (void)rec->fRasterClip.op(bounds, SkRegion::kIntersect_Op);
558 bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
559 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
563 bool weAllocated = false;
564 if (NULL == bitmap->pixelRef()) {
565 if (!bitmap->allocPixels()) {
571 SkBitmap bm(*bitmap);
573 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
578 bitmap->setPixelRef(NULL);
583 bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
585 const SkISize size = this->getBaseLayerSize();
586 if (!r.intersect(0, 0, size.width(), size.height())) {
591 if (!bitmap->allocN32Pixels(r.width(), r.height())) {
592 // bitmap will already be reset.
595 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
602 bool SkCanvas::readPixels(const SkImageInfo& origInfo, void* dstP, size_t rowBytes, int x, int y) {
603 switch (origInfo.colorType()) {
604 case kUnknown_SkColorType:
605 case kIndex_8_SkColorType:
610 if (NULL == dstP || rowBytes < origInfo.minRowBytes()) {
613 if (0 == origInfo.width() || 0 == origInfo.height()) {
617 SkBaseDevice* device = this->getDevice();
622 const SkISize size = this->getBaseLayerSize();
623 SkIRect srcR = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
624 if (!srcR.intersect(0, 0, size.width(), size.height())) {
628 SkImageInfo info = origInfo;
629 // the intersect may have shrunk info's logical size
630 info.fWidth = srcR.width();
631 info.fHeight = srcR.height();
633 // if x or y are negative, then we have to adjust pixels
640 // here x,y are either 0 or negative
641 dstP = ((char*)dstP - y * rowBytes - x * info.bytesPerPixel());
643 // The device can assert that the requested area is always contained in its bounds
644 return device->readPixels(info, dstP, rowBytes, srcR.x(), srcR.y());
647 bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
648 if (bitmap.getTexture()) {
653 if (bm.getPixels()) {
654 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
659 bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
661 switch (origInfo.colorType()) {
662 case kUnknown_SkColorType:
663 case kIndex_8_SkColorType:
668 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
672 const SkISize size = this->getBaseLayerSize();
673 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
674 if (!target.intersect(0, 0, size.width(), size.height())) {
678 SkBaseDevice* device = this->getDevice();
683 SkImageInfo info = origInfo;
684 // the intersect may have shrunk info's logical size
685 info.fWidth = target.width();
686 info.fHeight = target.height();
688 // if x or y are negative, then we have to adjust pixels
695 // here x,y are either 0 or negative
696 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
698 // Tell our owning surface to bump its generation ID
699 this->predrawNotify();
701 // The device can assert that the requested area is always contained in its bounds
702 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
705 SkCanvas* SkCanvas::canvasForDrawIter() {
709 //////////////////////////////////////////////////////////////////////////////
711 void SkCanvas::updateDeviceCMCache() {
712 if (fDeviceCMDirty) {
713 const SkMatrix& totalMatrix = this->getTotalMatrix();
714 const SkRasterClip& totalClip = fMCRec->fRasterClip;
715 DeviceCM* layer = fMCRec->fTopLayer;
717 if (NULL == layer->fNext) { // only one layer
718 layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
720 SkRasterClip clip(totalClip);
722 layer->updateMC(totalMatrix, clip, fClipStack, &clip);
723 } while ((layer = layer->fNext) != NULL);
725 fDeviceCMDirty = false;
729 ///////////////////////////////////////////////////////////////////////////////
731 int SkCanvas::internalSave() {
732 int saveCount = this->getSaveCount(); // record this before the actual save
734 MCRec* newTop = (MCRec*)fMCStack.push_back();
735 new (newTop) MCRec(fMCRec); // balanced in restore()
743 int SkCanvas::save() {
745 return this->internalSave();
748 static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
749 #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
750 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
756 bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
757 SkIRect* intersection, const SkImageFilter* imageFilter) {
759 SkRegion::Op op = SkRegion::kIntersect_Op;
760 if (!this->getClipDeviceBounds(&clipBounds)) {
765 imageFilter->filterBounds(clipBounds, fMCRec->fMatrix, &clipBounds);
766 // Filters may grow the bounds beyond the device bounds.
767 op = SkRegion::kReplace_Op;
770 if (NULL != bounds) {
773 this->getTotalMatrix().mapRect(&r, *bounds);
775 // early exit if the layer's bounds are clipped out
776 if (!ir.intersect(clipBounds)) {
777 if (bounds_affects_clip(flags)) {
778 fMCRec->fRasterClip.setEmpty();
782 } else { // no user bounds, so just use the clip
786 if (bounds_affects_clip(flags)) {
787 fClipStack.clipDevRect(ir, op);
788 // early exit if the clip is now empty
789 if (!fMCRec->fRasterClip.op(ir, op)) {
800 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
801 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
802 return this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, false, strategy);
805 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
807 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
808 return this->internalSaveLayer(bounds, paint, flags, false, strategy);
811 int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
812 bool justForImageFilter, SaveLayerStrategy strategy) {
813 #ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
814 flags |= kClipToLayer_SaveFlag;
817 // do this before we create the layer. We don't call the public save() since
818 // that would invoke a possibly overridden virtual
819 int count = this->internalSave();
821 fDeviceCMDirty = true;
824 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
828 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
829 // the clipRectBounds() call above?
830 if (kNoLayer_SaveLayerStrategy == strategy) {
834 // Kill the imagefilter if our device doesn't allow it
836 if (paint && paint->getImageFilter()) {
837 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
838 if (justForImageFilter) {
839 // early exit if the layer was just for the imageFilter
842 SkPaint* p = lazyP.set(*paint);
843 p->setImageFilter(NULL);
848 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
849 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
850 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
852 SkBaseDevice* device;
853 if (paint && paint->getImageFilter()) {
854 device = this->getDevice();
856 device = device->createCompatibleDevice(info);
859 device = this->createLayerDevice(info);
861 if (NULL == device) {
862 SkDebugf("Unable to create device for layer.");
866 device->setOrigin(ir.fLeft, ir.fTop);
867 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint, this));
870 layer->fNext = fMCRec->fTopLayer;
871 fMCRec->fLayer = layer;
872 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
874 fSaveLayerCount += 1;
878 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
879 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
882 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
885 return this->saveLayer(bounds, NULL, flags);
888 tmpPaint.setAlpha(alpha);
889 return this->saveLayer(bounds, &tmpPaint, flags);
893 void SkCanvas::restore() {
894 // check for underflow
895 if (fMCStack.count() > 1) {
897 this->internalRestore();
902 void SkCanvas::internalRestore() {
903 SkASSERT(fMCStack.count() != 0);
905 fDeviceCMDirty = true;
906 fCachedLocalClipBoundsDirty = true;
908 fClipStack.restore();
910 // reserve our layer (if any)
911 DeviceCM* layer = fMCRec->fLayer; // may be null
912 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
913 fMCRec->fLayer = NULL;
915 // now do the normal restore()
916 fMCRec->~MCRec(); // balanced in save()
918 fMCRec = (MCRec*)fMCStack.back();
920 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
921 since if we're being recorded, we don't want to record this (the
922 recorder will have already recorded the restore).
926 const SkIPoint& origin = layer->fDevice->getOrigin();
927 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
929 // reset this, since internalDrawDevice will have set it to true
930 fDeviceCMDirty = true;
932 SkASSERT(fSaveLayerCount > 0);
933 fSaveLayerCount -= 1;
939 int SkCanvas::getSaveCount() const {
940 return fMCStack.count();
943 void SkCanvas::restoreToCount(int count) {
949 int n = this->getSaveCount() - count;
950 for (int i = 0; i < n; ++i) {
955 bool SkCanvas::isDrawingToLayer() const {
956 return fSaveLayerCount > 0;
959 SkSurface* SkCanvas::newSurface(const SkImageInfo& info) {
960 return this->onNewSurface(info);
963 SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info) {
964 SkBaseDevice* dev = this->getDevice();
965 return dev ? dev->newSurface(info) : NULL;
968 SkImageInfo SkCanvas::imageInfo() const {
969 SkBaseDevice* dev = this->getDevice();
971 return dev->imageInfo();
973 return SkImageInfo::MakeUnknown(0, 0);
977 const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
978 return this->onPeekPixels(info, rowBytes);
981 const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
982 SkBaseDevice* dev = this->getDevice();
983 return dev ? dev->peekPixels(info, rowBytes) : NULL;
986 void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
987 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
988 if (pixels && origin) {
989 *origin = this->getTopDevice(false)->getOrigin();
994 void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
995 SkBaseDevice* dev = this->getTopDevice();
996 return dev ? dev->accessPixels(info, rowBytes) : NULL;
999 SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1000 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1001 if (NULL == fAddr) {
1002 fInfo = canvas->imageInfo();
1003 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.allocPixels(fInfo)) {
1004 return; // failure, fAddr is NULL
1006 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1007 return; // failure, fAddr is NULL
1009 fAddr = fBitmap.getPixels();
1010 fRowBytes = fBitmap.rowBytes();
1012 SkASSERT(fAddr); // success
1015 bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1017 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
1024 void SkCanvas::onPushCull(const SkRect& cullRect) {
1025 // do nothing. Subclasses may do something
1028 void SkCanvas::onPopCull() {
1029 // do nothing. Subclasses may do something
1032 /////////////////////////////////////////////////////////////////////////////
1034 // Ensure that cull rects are monotonically nested in device space.
1035 void SkCanvas::validateCull(const SkIRect& devCull) {
1036 if (fCullStack.isEmpty()
1037 || devCull.isEmpty()
1038 || fCullStack.top().contains(devCull)) {
1042 SkDEBUGF(("Invalid cull: [%d %d %d %d] (previous cull: [%d %d %d %d])\n",
1043 devCull.x(), devCull.y(), devCull.right(), devCull.bottom(),
1044 fCullStack.top().x(), fCullStack.top().y(),
1045 fCullStack.top().right(), fCullStack.top().bottom()));
1047 #ifdef ASSERT_NESTED_CULLING
1048 SkDEBUGFAIL("Invalid cull.");
1053 void SkCanvas::pushCull(const SkRect& cullRect) {
1055 this->onPushCull(cullRect);
1058 // Map the cull rect into device space.
1060 this->getTotalMatrix().mapRect(&mappedCull, cullRect);
1062 // Take clipping into account.
1063 SkIRect devClip, devCull;
1064 mappedCull.roundOut(&devCull);
1065 this->getClipDeviceBounds(&devClip);
1066 if (!devCull.intersect(devClip)) {
1070 this->validateCull(devCull);
1071 fCullStack.push(devCull); // balanced in popCull
1075 void SkCanvas::popCull() {
1076 SkASSERT(fCullStack.count() == fCullCount);
1078 if (fCullCount > 0) {
1082 SkDEBUGCODE(fCullStack.pop());
1086 /////////////////////////////////////////////////////////////////////////////
1088 void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
1089 const SkMatrix& matrix, const SkPaint* paint) {
1090 if (bitmap.drawsNothing()) {
1095 if (NULL == paint) {
1096 paint = lazy.init();
1099 SkDEBUGCODE(bitmap.validate();)
1102 const SkRect* bounds = NULL;
1103 if (paint && paint->canComputeFastBounds()) {
1104 bitmap.getBounds(&storage);
1105 matrix.mapRect(&storage);
1106 bounds = &paint->computeFastBounds(storage, &storage);
1109 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
1111 while (iter.next()) {
1112 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1118 void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
1119 const SkPaint* paint) {
1121 if (NULL == paint) {
1122 tmp.setDither(true);
1126 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
1127 while (iter.next()) {
1128 SkBaseDevice* dstDev = iter.fDevice;
1129 paint = &looper.paint();
1130 SkImageFilter* filter = paint->getImageFilter();
1131 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1132 if (filter && !dstDev->canHandleImageFilter(filter)) {
1133 SkDeviceImageFilterProxy proxy(dstDev);
1135 SkIPoint offset = SkIPoint::Make(0, 0);
1136 const SkBitmap& src = srcDev->accessBitmap(false);
1137 SkMatrix matrix = *iter.fMatrix;
1138 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
1139 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
1140 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
1141 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
1142 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
1143 SkPaint tmpUnfiltered(*paint);
1144 tmpUnfiltered.setImageFilter(NULL);
1145 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1149 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
1155 void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
1156 const SkPaint* paint) {
1157 if (bitmap.drawsNothing()) {
1160 SkDEBUGCODE(bitmap.validate();)
1163 if (NULL == paint) {
1167 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
1169 while (iter.next()) {
1170 paint = &looper.paint();
1171 SkImageFilter* filter = paint->getImageFilter();
1172 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1173 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
1174 SkDeviceImageFilterProxy proxy(iter.fDevice);
1176 SkIPoint offset = SkIPoint::Make(0, 0);
1177 SkMatrix matrix = *iter.fMatrix;
1178 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
1179 SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1180 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
1181 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
1182 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
1183 SkPaint tmpUnfiltered(*paint);
1184 tmpUnfiltered.setImageFilter(NULL);
1185 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1189 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1195 /////////////////////////////////////////////////////////////////////////////
1196 void SkCanvas::translate(SkScalar dx, SkScalar dy) {
1198 m.setTranslate(dx, dy);
1202 void SkCanvas::scale(SkScalar sx, SkScalar sy) {
1208 void SkCanvas::rotate(SkScalar degrees) {
1210 m.setRotate(degrees);
1214 void SkCanvas::skew(SkScalar sx, SkScalar sy) {
1220 void SkCanvas::concat(const SkMatrix& matrix) {
1221 if (matrix.isIdentity()) {
1225 fDeviceCMDirty = true;
1226 fCachedLocalClipBoundsDirty = true;
1227 fMCRec->fMatrix.preConcat(matrix);
1229 this->didConcat(matrix);
1232 void SkCanvas::setMatrix(const SkMatrix& matrix) {
1233 fDeviceCMDirty = true;
1234 fCachedLocalClipBoundsDirty = true;
1235 fMCRec->fMatrix = matrix;
1236 this->didSetMatrix(matrix);
1239 void SkCanvas::resetMatrix() {
1243 this->setMatrix(matrix);
1246 //////////////////////////////////////////////////////////////////////////////
1248 void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
1249 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1250 this->onClipRect(rect, op, edgeStyle);
1253 void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1254 #ifdef SK_ENABLE_CLIP_QUICKREJECT
1255 if (SkRegion::kIntersect_Op == op) {
1256 if (fMCRec->fRasterClip.isEmpty()) {
1260 if (this->quickReject(rect)) {
1261 fDeviceCMDirty = true;
1262 fCachedLocalClipBoundsDirty = true;
1264 fClipStack.clipEmpty();
1265 return fMCRec->fRasterClip.setEmpty();
1270 AutoValidateClip avc(this);
1272 fDeviceCMDirty = true;
1273 fCachedLocalClipBoundsDirty = true;
1274 if (!fAllowSoftClip) {
1275 edgeStyle = kHard_ClipEdgeStyle;
1278 if (fMCRec->fMatrix.rectStaysRect()) {
1279 // for these simpler matrices, we can stay a rect even after applying
1280 // the matrix. This means we don't have to a) make a path, and b) tell
1281 // the region code to scan-convert the path, only to discover that it
1282 // is really just a rect.
1285 fMCRec->fMatrix.mapRect(&r, rect);
1286 fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
1287 fMCRec->fRasterClip.op(r, op, kSoft_ClipEdgeStyle == edgeStyle);
1289 // since we're rotated or some such thing, we convert the rect to a path
1290 // and clip against that, since it can handle any matrix. However, to
1291 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1292 // we explicitly call "our" version of clipPath.
1296 this->SkCanvas::onClipPath(path, op, edgeStyle);
1300 static void clip_path_helper(const SkCanvas* canvas, SkRasterClip* currClip,
1301 const SkPath& devPath, SkRegion::Op op, bool doAA) {
1302 // base is used to limit the size (and therefore memory allocation) of the
1303 // region that results from scan converting devPath.
1306 if (SkRegion::kIntersect_Op == op) {
1307 // since we are intersect, we can do better (tighter) with currRgn's
1308 // bounds, than just using the device. However, if currRgn is complex,
1309 // our region blitter may hork, so we do that case in two steps.
1310 if (currClip->isRect()) {
1311 // FIXME: we should also be able to do this when currClip->isBW(),
1312 // but relaxing the test above triggers GM asserts in
1313 // SkRgnBuilder::blitH(). We need to investigate what's going on.
1314 currClip->setPath(devPath, currClip->bwRgn(), doAA);
1316 base.setRect(currClip->getBounds());
1318 clip.setPath(devPath, base, doAA);
1319 currClip->op(clip, op);
1322 const SkISize size = canvas->getBaseLayerSize();
1323 base.setRect(0, 0, size.width(), size.height());
1325 if (SkRegion::kReplace_Op == op) {
1326 currClip->setPath(devPath, base, doAA);
1329 clip.setPath(devPath, base, doAA);
1330 currClip->op(clip, op);
1335 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
1336 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1337 if (rrect.isRect()) {
1338 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1340 this->onClipRRect(rrect, op, edgeStyle);
1344 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1345 SkRRect transformedRRect;
1346 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
1347 AutoValidateClip avc(this);
1349 fDeviceCMDirty = true;
1350 fCachedLocalClipBoundsDirty = true;
1351 if (!fAllowSoftClip) {
1352 edgeStyle = kHard_ClipEdgeStyle;
1355 fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
1358 devPath.addRRect(transformedRRect);
1360 clip_path_helper(this, &fMCRec->fRasterClip, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
1365 path.addRRect(rrect);
1366 // call the non-virtual version
1367 this->SkCanvas::onClipPath(path, op, edgeStyle);
1370 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
1371 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1373 if (!path.isInverseFillType() && path.isRect(&r)) {
1374 this->onClipRect(r, op, edgeStyle);
1376 this->onClipPath(path, op, edgeStyle);
1380 void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1381 #ifdef SK_ENABLE_CLIP_QUICKREJECT
1382 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
1383 if (fMCRec->fRasterClip.isEmpty()) {
1387 if (this->quickReject(path.getBounds())) {
1388 fDeviceCMDirty = true;
1389 fCachedLocalClipBoundsDirty = true;
1391 fClipStack.clipEmpty();
1392 return fMCRec->fRasterClip.setEmpty();
1397 AutoValidateClip avc(this);
1399 fDeviceCMDirty = true;
1400 fCachedLocalClipBoundsDirty = true;
1401 if (!fAllowSoftClip) {
1402 edgeStyle = kHard_ClipEdgeStyle;
1406 path.transform(fMCRec->fMatrix, &devPath);
1408 // Check if the transfomation, or the original path itself
1409 // made us empty. Note this can also happen if we contained NaN
1410 // values. computing the bounds detects this, and will set our
1411 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1412 if (devPath.getBounds().isEmpty()) {
1413 // resetting the path will remove any NaN or other wanky values
1414 // that might upset our scan converter.
1418 // if we called path.swap() we could avoid a deep copy of this path
1419 fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
1421 if (fAllowSimplifyClip) {
1423 devPath.setFillType(SkPath::kInverseEvenOdd_FillType);
1424 const SkClipStack* clipStack = getClipStack();
1425 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
1426 const SkClipStack::Element* element;
1427 while ((element = iter.next())) {
1428 SkClipStack::Element::Type type = element->getType();
1430 if (type != SkClipStack::Element::kEmpty_Type) {
1431 element->asPath(&operand);
1433 SkRegion::Op elementOp = element->getOp();
1434 if (elementOp == SkRegion::kReplace_Op) {
1437 Op(devPath, operand, (SkPathOp) elementOp, &devPath);
1439 // if the prev and curr clips disagree about aa -vs- not, favor the aa request.
1440 // perhaps we need an API change to avoid this sort of mixed-signals about
1442 if (element->isAA()) {
1443 edgeStyle = kSoft_ClipEdgeStyle;
1446 op = SkRegion::kReplace_Op;
1449 clip_path_helper(this, &fMCRec->fRasterClip, devPath, op, edgeStyle);
1452 void SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op,
1453 bool inverseFilled) {
1454 // This is for updating the clip conservatively using only bounds
1457 // The current clip must contain the true clip. The true
1458 // clip is the clip that would have normally been computed
1459 // by calls to clipPath and clipRRect
1461 // Keep the current clip as small as possible without
1462 // breaking the contract, using only clip bounding rectangles
1463 // (for performance).
1465 // N.B.: This *never* calls back through a virtual on canvas, so subclasses
1466 // don't have to worry about getting caught in a loop. Thus anywhere
1467 // we call a virtual method, we explicitly prefix it with
1468 // SkCanvas:: to be sure to call the base-class.
1470 if (inverseFilled) {
1472 case SkRegion::kIntersect_Op:
1473 case SkRegion::kDifference_Op:
1474 // These ops can only shrink the current clip. So leaving
1475 // the clip unchanged conservatively respects the contract.
1477 case SkRegion::kUnion_Op:
1478 case SkRegion::kReplace_Op:
1479 case SkRegion::kReverseDifference_Op:
1480 case SkRegion::kXOR_Op: {
1481 // These ops can grow the current clip up to the extents of
1482 // the input clip, which is inverse filled, so we just set
1483 // the current clip to the device bounds.
1484 SkRect deviceBounds;
1485 SkIRect deviceIBounds;
1486 this->getDevice()->getGlobalBounds(&deviceIBounds);
1487 deviceBounds = SkRect::Make(deviceIBounds);
1489 // set the clip in device space
1490 SkMatrix savedMatrix = this->getTotalMatrix();
1491 this->SkCanvas::setMatrix(SkMatrix::I());
1492 this->SkCanvas::onClipRect(deviceBounds, SkRegion::kReplace_Op,
1493 kHard_ClipEdgeStyle);
1494 this->setMatrix(savedMatrix);
1498 SkASSERT(0); // unhandled op?
1501 // Not inverse filled
1503 case SkRegion::kIntersect_Op:
1504 case SkRegion::kUnion_Op:
1505 case SkRegion::kReplace_Op:
1506 this->SkCanvas::onClipRect(bounds, op, kHard_ClipEdgeStyle);
1508 case SkRegion::kDifference_Op:
1509 // Difference can only shrink the current clip.
1510 // Leaving clip unchanged conservatively fullfills the contract.
1512 case SkRegion::kReverseDifference_Op:
1513 // To reverse, we swap in the bounds with a replace op.
1514 // As with difference, leave it unchanged.
1515 this->SkCanvas::onClipRect(bounds, SkRegion::kReplace_Op, kHard_ClipEdgeStyle);
1517 case SkRegion::kXOR_Op:
1518 // Be conservative, based on (A XOR B) always included in (A union B),
1519 // which is always included in (bounds(A) union bounds(B))
1520 this->SkCanvas::onClipRect(bounds, SkRegion::kUnion_Op, kHard_ClipEdgeStyle);
1523 SkASSERT(0); // unhandled op?
1528 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
1529 this->onClipRegion(rgn, op);
1532 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
1533 AutoValidateClip avc(this);
1535 fDeviceCMDirty = true;
1536 fCachedLocalClipBoundsDirty = true;
1538 // todo: signal fClipStack that we have a region, and therefore (I guess)
1539 // we have to ignore it, and use the region directly?
1540 fClipStack.clipDevRect(rgn.getBounds(), op);
1542 fMCRec->fRasterClip.op(rgn, op);
1546 void SkCanvas::validateClip() const {
1547 // construct clipRgn from the clipstack
1548 const SkBaseDevice* device = this->getDevice();
1550 SkASSERT(this->isClipEmpty());
1555 ir.set(0, 0, device->width(), device->height());
1556 SkRasterClip tmpClip(ir);
1558 SkClipStack::B2TIter iter(fClipStack);
1559 const SkClipStack::Element* element;
1560 while ((element = iter.next()) != NULL) {
1561 switch (element->getType()) {
1562 case SkClipStack::Element::kRect_Type:
1563 element->getRect().round(&ir);
1564 tmpClip.op(ir, element->getOp());
1566 case SkClipStack::Element::kEmpty_Type:
1571 element->asPath(&path);
1572 clip_path_helper(this, &tmpClip, path, element->getOp(), element->isAA());
1580 void SkCanvas::replayClips(ClipVisitor* visitor) const {
1581 SkClipStack::B2TIter iter(fClipStack);
1582 const SkClipStack::Element* element;
1584 while ((element = iter.next()) != NULL) {
1585 element->replay(visitor);
1589 ///////////////////////////////////////////////////////////////////////////////
1591 bool SkCanvas::isClipEmpty() const {
1592 return fMCRec->fRasterClip.isEmpty();
1595 bool SkCanvas::isClipRect() const {
1596 return fMCRec->fRasterClip.isRect();
1599 bool SkCanvas::quickReject(const SkRect& rect) const {
1601 if (!rect.isFinite())
1604 if (fMCRec->fRasterClip.isEmpty()) {
1608 if (fMCRec->fMatrix.hasPerspective()) {
1610 fMCRec->fMatrix.mapRect(&dst, rect);
1612 dst.roundOut(&idst);
1613 return !SkIRect::Intersects(idst, fMCRec->fRasterClip.getBounds());
1615 const SkRect& clipR = this->getLocalClipBounds();
1617 // for speed, do the most likely reject compares first
1618 // TODO: should we use | instead, or compare all 4 at once?
1619 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
1622 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
1629 bool SkCanvas::quickReject(const SkPath& path) const {
1630 return path.isEmpty() || this->quickReject(path.getBounds());
1633 bool SkCanvas::getClipBounds(SkRect* bounds) const {
1635 if (!this->getClipDeviceBounds(&ibounds)) {
1640 // if we can't invert the CTM, we can't return local clip bounds
1641 if (!fMCRec->fMatrix.invert(&inverse)) {
1648 if (NULL != bounds) {
1650 // adjust it outwards in case we are antialiasing
1651 const int inset = 1;
1653 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1654 ibounds.fRight + inset, ibounds.fBottom + inset);
1655 inverse.mapRect(bounds, r);
1660 bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
1661 const SkRasterClip& clip = fMCRec->fRasterClip;
1662 if (clip.isEmpty()) {
1669 if (NULL != bounds) {
1670 *bounds = clip.getBounds();
1675 const SkMatrix& SkCanvas::getTotalMatrix() const {
1676 return fMCRec->fMatrix;
1679 #ifdef SK_SUPPORT_LEGACY_GETCLIPTYPE
1680 SkCanvas::ClipType SkCanvas::getClipType() const {
1681 if (fMCRec->fRasterClip.isEmpty()) {
1682 return kEmpty_ClipType;
1684 if (fMCRec->fRasterClip.isRect()) {
1685 return kRect_ClipType;
1687 return kComplex_ClipType;
1691 const SkRegion& SkCanvas::internal_private_getTotalClip() const {
1692 return fMCRec->fRasterClip.forceGetBW();
1695 void SkCanvas::internal_private_getTotalClipAsPath(SkPath* path) const {
1698 const SkRegion& rgn = fMCRec->fRasterClip.forceGetBW();
1699 if (rgn.isEmpty()) {
1702 (void)rgn.getBoundaryPath(path);
1705 GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1706 SkBaseDevice* dev = this->getTopDevice();
1707 return dev ? dev->accessRenderTarget() : NULL;
1710 SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) {
1711 SkBaseDevice* device = this->getTopDevice();
1712 return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL;
1715 GrContext* SkCanvas::getGrContext() {
1717 SkBaseDevice* device = this->getTopDevice();
1718 if (NULL != device) {
1719 GrRenderTarget* renderTarget = device->accessRenderTarget();
1720 if (NULL != renderTarget) {
1721 return renderTarget->getContext();
1730 void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1731 const SkPaint& paint) {
1732 if (outer.isEmpty()) {
1735 if (inner.isEmpty()) {
1736 this->drawRRect(outer, paint);
1740 // We don't have this method (yet), but technically this is what we should
1741 // be able to assert...
1742 // SkASSERT(outer.contains(inner));
1744 // For now at least check for containment of bounds
1745 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1747 this->onDrawDRRect(outer, inner, paint);
1750 //////////////////////////////////////////////////////////////////////////////
1751 // These are the virtual drawing methods
1752 //////////////////////////////////////////////////////////////////////////////
1754 void SkCanvas::clear(SkColor color) {
1755 SkDrawIter iter(this);
1756 this->predrawNotify();
1757 while (iter.next()) {
1758 iter.fDevice->clear(color);
1762 void SkCanvas::onDiscard() {
1763 if (NULL != fSurfaceBase) {
1764 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1768 void SkCanvas::drawPaint(const SkPaint& paint) {
1769 this->internalDrawPaint(paint);
1772 void SkCanvas::internalDrawPaint(const SkPaint& paint) {
1773 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
1775 while (iter.next()) {
1776 iter.fDevice->drawPaint(iter, looper.paint());
1782 void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
1783 const SkPaint& paint) {
1784 if ((long)count <= 0) {
1789 const SkRect* bounds = NULL;
1790 if (paint.canComputeFastBounds()) {
1791 // special-case 2 points (common for drawing a single line)
1793 r.set(pts[0], pts[1]);
1795 r.set(pts, SkToInt(count));
1797 bounds = &paint.computeFastStrokeBounds(r, &storage);
1798 if (this->quickReject(*bounds)) {
1803 SkASSERT(pts != NULL);
1805 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
1807 while (iter.next()) {
1808 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
1814 void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1816 const SkRect* bounds = NULL;
1817 if (paint.canComputeFastBounds()) {
1818 bounds = &paint.computeFastBounds(r, &storage);
1819 if (this->quickReject(*bounds)) {
1824 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
1826 while (iter.next()) {
1827 iter.fDevice->drawRect(iter, r, looper.paint());
1833 void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
1835 const SkRect* bounds = NULL;
1836 if (paint.canComputeFastBounds()) {
1837 bounds = &paint.computeFastBounds(oval, &storage);
1838 if (this->quickReject(*bounds)) {
1843 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
1845 while (iter.next()) {
1846 iter.fDevice->drawOval(iter, oval, looper.paint());
1852 void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1854 const SkRect* bounds = NULL;
1855 if (paint.canComputeFastBounds()) {
1856 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1857 if (this->quickReject(*bounds)) {
1862 if (rrect.isRect()) {
1863 // call the non-virtual version
1864 this->SkCanvas::drawRect(rrect.getBounds(), paint);
1866 } else if (rrect.isOval()) {
1867 // call the non-virtual version
1868 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1872 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
1874 while (iter.next()) {
1875 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1881 void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1882 const SkPaint& paint) {
1884 const SkRect* bounds = NULL;
1885 if (paint.canComputeFastBounds()) {
1886 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1887 if (this->quickReject(*bounds)) {
1892 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
1894 while (iter.next()) {
1895 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1901 void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1902 if (!path.isFinite()) {
1907 const SkRect* bounds = NULL;
1908 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
1909 const SkRect& pathBounds = path.getBounds();
1910 bounds = &paint.computeFastBounds(pathBounds, &storage);
1911 if (this->quickReject(*bounds)) {
1916 const SkRect& r = path.getBounds();
1917 if (r.width() <= 0 && r.height() <= 0) {
1918 if (path.isInverseFillType()) {
1919 this->internalDrawPaint(paint);
1924 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
1926 while (iter.next()) {
1927 iter.fDevice->drawPath(iter, path, looper.paint());
1933 void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
1934 const SkPaint* paint) {
1935 SkDEBUGCODE(bitmap.validate();)
1937 if (NULL == paint || paint->canComputeFastBounds()) {
1940 x + SkIntToScalar(bitmap.width()),
1941 y + SkIntToScalar(bitmap.height())
1944 (void)paint->computeFastBounds(bounds, &bounds);
1946 if (this->quickReject(bounds)) {
1952 matrix.setTranslate(x, y);
1953 this->internalDrawBitmap(bitmap, matrix, paint);
1956 // this one is non-virtual, so it can be called safely by other canvas apis
1957 void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
1958 const SkRect& dst, const SkPaint* paint,
1959 DrawBitmapRectFlags flags) {
1960 if (bitmap.drawsNothing() || dst.isEmpty()) {
1965 const SkRect* bounds = &dst;
1966 if (NULL == paint || paint->canComputeFastBounds()) {
1968 bounds = &paint->computeFastBounds(dst, &storage);
1970 if (this->quickReject(*bounds)) {
1976 if (NULL == paint) {
1977 paint = lazy.init();
1980 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
1982 while (iter.next()) {
1983 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
1989 void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
1990 const SkRect& dst, const SkPaint* paint,
1991 DrawBitmapRectFlags flags) {
1992 SkDEBUGCODE(bitmap.validate();)
1993 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
1996 void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
1997 const SkPaint* paint) {
1998 SkDEBUGCODE(bitmap.validate();)
1999 this->internalDrawBitmap(bitmap, matrix, paint);
2002 void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
2003 const SkIRect& center, const SkRect& dst,
2004 const SkPaint* paint) {
2005 if (bitmap.drawsNothing()) {
2008 if (NULL == paint || paint->canComputeFastBounds()) {
2010 const SkRect* bounds = &dst;
2012 bounds = &paint->computeFastBounds(dst, &storage);
2014 if (this->quickReject(*bounds)) {
2019 const int32_t w = bitmap.width();
2020 const int32_t h = bitmap.height();
2023 // pin center to the bounds of the bitmap
2024 c.fLeft = SkMax32(0, center.fLeft);
2025 c.fTop = SkMax32(0, center.fTop);
2026 c.fRight = SkPin32(center.fRight, c.fLeft, w);
2027 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
2029 const SkScalar srcX[4] = {
2030 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
2032 const SkScalar srcY[4] = {
2033 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
2035 SkScalar dstX[4] = {
2036 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2037 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2039 SkScalar dstY[4] = {
2040 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2041 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2044 if (dstX[1] > dstX[2]) {
2045 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2049 if (dstY[1] > dstY[2]) {
2050 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2054 for (int y = 0; y < 3; y++) {
2058 s.fBottom = srcY[y+1];
2060 d.fBottom = dstY[y+1];
2061 for (int x = 0; x < 3; x++) {
2063 s.fRight = srcX[x+1];
2065 d.fRight = dstX[x+1];
2066 this->internalDrawBitmapRect(bitmap, &s, d, paint,
2067 kNone_DrawBitmapRectFlag);
2072 void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
2073 const SkRect& dst, const SkPaint* paint) {
2074 SkDEBUGCODE(bitmap.validate();)
2076 // Need a device entry-point, so gpu can use a mesh
2077 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2080 class SkDeviceFilteredPaint {
2082 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
2083 SkBaseDevice::TextFlags flags;
2084 if (device->filterTextFlags(paint, &flags)) {
2085 SkPaint* newPaint = fLazy.set(paint);
2086 newPaint->setFlags(flags.fFlags);
2087 newPaint->setHinting(flags.fHinting);
2094 const SkPaint& paint() const { return *fPaint; }
2097 const SkPaint* fPaint;
2101 void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2102 const SkRect& r, SkScalar textSize) {
2103 if (paint.getStyle() == SkPaint::kFill_Style) {
2104 draw.fDevice->drawRect(draw, r, paint);
2107 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
2108 draw.fDevice->drawRect(draw, r, p);
2112 void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2113 const char text[], size_t byteLength,
2114 SkScalar x, SkScalar y) {
2115 SkASSERT(byteLength == 0 || text != NULL);
2118 if (text == NULL || byteLength == 0 ||
2119 draw.fClip->isEmpty() ||
2120 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2127 start.set(0, 0); // to avoid warning
2128 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2129 SkPaint::kStrikeThruText_Flag)) {
2130 width = paint.measureText(text, byteLength);
2132 SkScalar offsetX = 0;
2133 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2134 offsetX = SkScalarHalf(width);
2135 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2138 start.set(x - offsetX, y);
2145 uint32_t flags = paint.getFlags();
2147 if (flags & (SkPaint::kUnderlineText_Flag |
2148 SkPaint::kStrikeThruText_Flag)) {
2149 SkScalar textSize = paint.getTextSize();
2150 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2154 r.fRight = start.fX + width;
2156 if (flags & SkPaint::kUnderlineText_Flag) {
2157 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2160 r.fBottom = offset + height;
2161 DrawRect(draw, paint, r, textSize);
2163 if (flags & SkPaint::kStrikeThruText_Flag) {
2164 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2167 r.fBottom = offset + height;
2168 DrawRect(draw, paint, r, textSize);
2173 void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2174 const SkPaint& paint) {
2175 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2177 while (iter.next()) {
2178 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2179 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
2180 DrawTextDecorations(iter, dfp.paint(),
2181 static_cast<const char*>(text), byteLength, x, y);
2187 void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2188 const SkPaint& paint) {
2189 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2191 while (iter.next()) {
2192 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2193 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
2200 void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2201 SkScalar constY, const SkPaint& paint) {
2202 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2204 while (iter.next()) {
2205 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2206 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
2213 void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2214 const SkMatrix* matrix, const SkPaint& paint) {
2215 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2217 while (iter.next()) {
2218 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
2219 matrix, looper.paint());
2225 // These will become non-virtual, so they always call the (virtual) onDraw... method
2226 void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2227 const SkPaint& paint) {
2228 this->onDrawText(text, byteLength, x, y, paint);
2230 void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2231 const SkPaint& paint) {
2232 this->onDrawPosText(text, byteLength, pos, paint);
2234 void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2235 SkScalar constY, const SkPaint& paint) {
2236 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2238 void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2239 const SkMatrix* matrix, const SkPaint& paint) {
2240 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2243 void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
2244 const SkPoint verts[], const SkPoint texs[],
2245 const SkColor colors[], SkXfermode* xmode,
2246 const uint16_t indices[], int indexCount,
2247 const SkPaint& paint) {
2248 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
2250 while (iter.next()) {
2251 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
2252 colors, xmode, indices, indexCount,
2259 void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2260 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2261 if (NULL == cubics) {
2265 // Since a patch is always within the convex hull of the control points, we discard it when its
2266 // bounding rectangle is completely outside the current clip.
2268 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
2269 if (this->quickReject(bounds)) {
2273 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2276 void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2277 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2279 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
2281 while (iter.next()) {
2282 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
2288 //////////////////////////////////////////////////////////////////////////////
2289 // These methods are NOT virtual, and therefore must call back into virtual
2290 // methods, rather than actually drawing themselves.
2291 //////////////////////////////////////////////////////////////////////////////
2293 void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
2294 SkXfermode::Mode mode) {
2297 paint.setARGB(a, r, g, b);
2298 if (SkXfermode::kSrcOver_Mode != mode) {
2299 paint.setXfermodeMode(mode);
2301 this->drawPaint(paint);
2304 void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
2308 if (SkXfermode::kSrcOver_Mode != mode) {
2309 paint.setXfermodeMode(mode);
2311 this->drawPaint(paint);
2314 void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
2318 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2321 void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
2326 paint.setColor(color);
2327 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2330 void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2331 const SkPaint& paint) {
2336 this->drawPoints(kLines_PointMode, 2, pts, paint);
2339 void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2340 SkScalar right, SkScalar bottom,
2341 const SkPaint& paint) {
2344 r.set(left, top, right, bottom);
2345 this->drawRect(r, paint);
2348 void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2349 const SkPaint& paint) {
2355 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
2356 this->drawOval(r, paint);
2359 void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2360 const SkPaint& paint) {
2361 if (rx > 0 && ry > 0) {
2362 if (paint.canComputeFastBounds()) {
2364 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
2369 rrect.setRectXY(r, rx, ry);
2370 this->drawRRect(rrect, paint);
2372 this->drawRect(r, paint);
2376 void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2377 SkScalar sweepAngle, bool useCenter,
2378 const SkPaint& paint) {
2379 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2380 this->drawOval(oval, paint);
2384 path.moveTo(oval.centerX(), oval.centerY());
2386 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2390 this->drawPath(path, paint);
2394 void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2395 const SkPath& path, SkScalar hOffset,
2396 SkScalar vOffset, const SkPaint& paint) {
2399 matrix.setTranslate(hOffset, vOffset);
2400 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2403 ///////////////////////////////////////////////////////////////////////////////
2404 void SkCanvas::EXPERIMENTAL_optimize(const SkPicture* picture) {
2405 SkBaseDevice* device = this->getDevice();
2406 if (NULL != device) {
2407 device->EXPERIMENTAL_optimize(picture);
2411 void SkCanvas::drawPicture(const SkPicture* picture) {
2412 if (NULL != picture) {
2413 this->onDrawPicture(picture, NULL, NULL);
2417 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
2418 if (NULL != picture) {
2419 if (matrix && matrix->isIdentity()) {
2422 this->onDrawPicture(picture, matrix, paint);
2426 void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2427 const SkPaint* paint) {
2428 SkBaseDevice* device = this->getTopDevice();
2429 if (NULL != device) {
2430 // Canvas has to first give the device the opportunity to render
2431 // the picture itself.
2432 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
2433 return; // the device has rendered the entire picture
2437 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->width(), picture->height());
2439 picture->draw(this);
2442 ///////////////////////////////////////////////////////////////////////////////
2443 ///////////////////////////////////////////////////////////////////////////////
2445 SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
2446 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
2450 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2451 fDone = !fImpl->next();
2454 SkCanvas::LayerIter::~LayerIter() {
2455 fImpl->~SkDrawIter();
2458 void SkCanvas::LayerIter::next() {
2459 fDone = !fImpl->next();
2462 SkBaseDevice* SkCanvas::LayerIter::device() const {
2463 return fImpl->getDevice();
2466 const SkMatrix& SkCanvas::LayerIter::matrix() const {
2467 return fImpl->getMatrix();
2470 const SkPaint& SkCanvas::LayerIter::paint() const {
2471 const SkPaint* paint = fImpl->getPaint();
2472 if (NULL == paint) {
2473 paint = &fDefaultPaint;
2478 const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2479 int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2480 int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
2482 ///////////////////////////////////////////////////////////////////////////////
2484 SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
2486 ///////////////////////////////////////////////////////////////////////////////
2488 static bool supported_for_raster_canvas(const SkImageInfo& info) {
2489 switch (info.alphaType()) {
2490 case kPremul_SkAlphaType:
2491 case kOpaque_SkAlphaType:
2497 switch (info.colorType()) {
2498 case kAlpha_8_SkColorType:
2499 case kRGB_565_SkColorType:
2500 case kN32_SkColorType:
2509 SkCanvas* SkCanvas::NewRaster(const SkImageInfo& info) {
2510 if (!supported_for_raster_canvas(info)) {
2515 if (!bitmap.allocPixels(info)) {
2519 // should this functionality be moved into allocPixels()?
2520 if (!bitmap.info().isOpaque()) {
2521 bitmap.eraseColor(0);
2523 return SkNEW_ARGS(SkCanvas, (bitmap));
2526 SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2527 if (!supported_for_raster_canvas(info)) {
2532 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2535 return SkNEW_ARGS(SkCanvas, (bitmap));
2538 ///////////////////////////////////////////////////////////////////////////////
2540 SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
2541 const SkPaint* paint, int width, int height)
2543 , fSaveCount(canvas->getSaveCount())
2545 if (NULL != paint) {
2546 SkRect bounds = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
2548 matrix->mapRect(&bounds);
2550 canvas->saveLayer(&bounds, paint);
2551 } else if (NULL != matrix) {
2555 if (NULL != matrix) {
2556 canvas->concat(*matrix);
2560 SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2561 fCanvas->restoreToCount(fSaveCount);