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"
28 #include "SkTraceEvent.h"
32 #include "GrRenderTarget.h"
35 // experimental for faster tiled drawing...
36 //#define SK_ENABLE_CLIP_QUICKREJECT
38 //#define SK_TRACE_SAVERESTORE
40 #ifdef SK_TRACE_SAVERESTORE
41 static int gLayerCounter;
42 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
43 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
45 static int gRecCounter;
46 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
47 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
49 static int gCanvasCounter;
50 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
51 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
61 typedef SkTLazy<SkPaint> SkLazyPaint;
63 void SkCanvas::predrawNotify() {
65 fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode);
69 ///////////////////////////////////////////////////////////////////////////////
71 static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
72 const uint32_t propFlags = props.flags();
73 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
74 flags &= ~SkPaint::kDither_Flag;
76 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
77 flags &= ~SkPaint::kAntiAlias_Flag;
82 ///////////////////////////////////////////////////////////////////////////////
84 /* This is the record we keep for each SkBaseDevice that the user installs.
85 The clip/matrix/proc are fields that reflect the top of the save/restore
86 stack. Whenever the canvas changes, it marks a dirty flag, and then before
87 these are used (assuming we're not on a layer) we rebuild these cache
88 values: they reflect the top of the save stack, but translated and clipped
89 by the device's XY offset and bitmap-bounds.
93 SkBaseDevice* fDevice;
95 const SkMatrix* fMatrix;
96 SkPaint* fPaint; // may be null (in the future)
98 DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas,
99 bool conservativeRasterClip)
101 , fClip(conservativeRasterClip)
103 if (NULL != device) {
105 device->onAttachToCanvas(canvas);
108 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
113 fDevice->onDetachFromCanvas();
119 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
120 const SkClipStack& clipStack, SkRasterClip* updateClip) {
121 int x = fDevice->getOrigin().x();
122 int y = fDevice->getOrigin().y();
123 int width = fDevice->width();
124 int height = fDevice->height();
127 fMatrix = &totalMatrix;
130 fMatrixStorage = totalMatrix;
131 fMatrixStorage.postTranslate(SkIntToScalar(-x),
133 fMatrix = &fMatrixStorage;
135 totalClip.translate(-x, -y, &fClip);
138 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
140 // intersect clip, but don't translate it (yet)
143 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
144 SkRegion::kDifference_Op);
147 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
150 if (!fClip.isEmpty()) {
152 deviceR.set(0, 0, width, height);
153 SkASSERT(deviceR.contains(fClip.getBounds()));
159 SkMatrix fMatrixStorage;
162 /* This is the record we keep for each save/restore level in the stack.
163 Since a level optionally copies the matrix and/or stack, we have pointers
164 for these fields. If the value is copied for this level, the copy is
165 stored in the ...Storage field, and the pointer points to that. If the
166 value is not copied for this level, we ignore ...Storage, and just point
167 at the corresponding value in the previous level in the stack.
169 class SkCanvas::MCRec {
171 SkRasterClip fRasterClip;
173 SkDrawFilter* fFilter; // the current filter (or null)
175 /* If there are any layers in the stack, this points to the top-most
176 one that is at or below this level in the stack (so we know what
177 bitmap/device to draw into from this level. This value is NOT
178 reference counted, since the real owner is either our fLayer field,
179 or a previous one in a lower level.)
183 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
189 // don't bother initializing fNext
192 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip) {
193 fMatrix = prev.fMatrix;
194 fFilter = SkSafeRef(prev.fFilter);
196 fTopLayer = prev.fTopLayer;
198 // don't bother initializing fNext
202 SkSafeUnref(fFilter);
208 class SkDrawIter : public SkDraw {
210 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
211 canvas = canvas->canvasForDrawIter();
213 canvas->updateDeviceCMCache();
215 fClipStack = &canvas->fClipStack;
216 fCurrLayer = canvas->fMCRec->fTopLayer;
217 fSkipEmptyClips = skipEmptyClips;
221 // skip over recs with empty clips
222 if (fSkipEmptyClips) {
223 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
224 fCurrLayer = fCurrLayer->fNext;
228 const DeviceCM* rec = fCurrLayer;
229 if (rec && rec->fDevice) {
231 fMatrix = rec->fMatrix;
232 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
234 fDevice = rec->fDevice;
235 fBitmap = &fDevice->accessBitmap(true);
236 fPaint = rec->fPaint;
237 SkDEBUGCODE(this->validate();)
239 fCurrLayer = rec->fNext;
240 // fCurrLayer may be NULL now
247 SkBaseDevice* getDevice() const { return fDevice; }
248 int getX() const { return fDevice->getOrigin().x(); }
249 int getY() const { return fDevice->getOrigin().y(); }
250 const SkMatrix& getMatrix() const { return *fMatrix; }
251 const SkRegion& getClip() const { return *fClip; }
252 const SkPaint* getPaint() const { return fPaint; }
256 const DeviceCM* fCurrLayer;
257 const SkPaint* fPaint; // May be null.
258 SkBool8 fSkipEmptyClips;
260 typedef SkDraw INHERITED;
263 /////////////////////////////////////////////////////////////////////////////
265 class AutoDrawLooper {
267 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
268 bool skipLayerForImageFilter = false,
269 const SkRect* bounds = NULL) : fOrigPaint(paint) {
271 fFilter = canvas->getDrawFilter();
272 fPaint = &fOrigPaint;
273 fSaveCount = canvas->getSaveCount();
274 fDoClearImageFilter = false;
277 if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
279 tmp.setImageFilter(fOrigPaint.getImageFilter());
280 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
281 true, SkCanvas::kFullLayer_SaveLayerStrategy);
282 // we'll clear the imageFilter for the actual draws in next(), so
283 // it will only be applied during the restore().
284 fDoClearImageFilter = true;
287 if (SkDrawLooper* looper = paint.getLooper()) {
288 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
289 looper->contextSize());
290 fLooperContext = looper->createContext(canvas, buffer);
293 fLooperContext = NULL;
294 // can we be marked as simple?
295 fIsSimple = !fFilter && !fDoClearImageFilter;
298 uint32_t oldFlags = paint.getFlags();
299 fNewPaintFlags = filter_paint_flags(props, oldFlags);
300 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
301 SkPaint* paint = fLazyPaint.set(fOrigPaint);
302 paint->setFlags(fNewPaintFlags);
304 // if we're not simple, doNext() will take care of calling setFlags()
309 if (fDoClearImageFilter) {
310 fCanvas->internalRestore();
312 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
315 const SkPaint& paint() const {
320 bool next(SkDrawFilter::Type drawType) {
323 } else if (fIsSimple) {
325 return !fPaint->nothingToDraw();
327 return this->doNext(drawType);
332 SkLazyPaint fLazyPaint;
334 const SkPaint& fOrigPaint;
335 SkDrawFilter* fFilter;
336 const SkPaint* fPaint;
338 uint32_t fNewPaintFlags;
339 bool fDoClearImageFilter;
342 SkDrawLooper::Context* fLooperContext;
343 SkSmallAllocator<1, 32> fLooperContextAllocator;
345 bool doNext(SkDrawFilter::Type drawType);
348 bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
350 SkASSERT(!fIsSimple);
351 SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
353 SkPaint* paint = fLazyPaint.set(fOrigPaint);
354 paint->setFlags(fNewPaintFlags);
356 if (fDoClearImageFilter) {
357 paint->setImageFilter(NULL);
360 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
365 if (!fFilter->filter(paint, drawType)) {
369 if (NULL == fLooperContext) {
370 // no looper means we only draw once
376 // if we only came in here for the imagefilter, mark us as done
377 if (!fLooperContext && !fFilter) {
381 // call this after any possible paint modifiers
382 if (fPaint->nothingToDraw()) {
389 ////////// macros to place around the internal draw calls //////////////////
391 #define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
392 this->predrawNotify(); \
393 AutoDrawLooper looper(this, fProps, paint, true); \
394 while (looper.next(type)) { \
395 SkDrawIter iter(this);
397 #define LOOPER_BEGIN(paint, type, bounds) \
398 this->predrawNotify(); \
399 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
400 while (looper.next(type)) { \
401 SkDrawIter iter(this);
405 ////////////////////////////////////////////////////////////////////////////
407 void SkCanvas::setupDevice(SkBaseDevice* device) {
408 device->setPixelGeometry(fProps.pixelGeometry());
411 SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
412 fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
413 fCachedLocalClipBounds.setEmpty();
414 fCachedLocalClipBoundsDirty = true;
415 fAllowSoftClip = true;
416 fAllowSimplifyClip = false;
417 fDeviceCMDirty = true;
422 fMCRec = (MCRec*)fMCStack.push_back();
423 new (fMCRec) MCRec(fConservativeRasterClip);
425 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL, fConservativeRasterClip));
426 fMCRec->fTopLayer = fMCRec->fLayer;
431 this->setupDevice(device);
432 if (device->forceConservativeRasterClip()) {
433 fConservativeRasterClip = true;
435 device->onAttachToCanvas(this);
436 fMCRec->fLayer->fDevice = SkRef(device);
437 fMCRec->fRasterClip.setRect(SkIRect::MakeWH(device->width(), device->height()));
443 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
444 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
448 this->init(NULL, kDefault_InitFlags);
451 static SkBitmap make_nopixels(int width, int height) {
453 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
457 class SkNoPixelsBitmapDevice : public SkBitmapDevice {
459 SkNoPixelsBitmapDevice(int width, int height) : INHERITED(make_nopixels(width, height)) {}
463 typedef SkBitmapDevice INHERITED;
466 SkCanvas::SkCanvas(int width, int height)
467 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
468 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
472 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (width, height)), kDefault_InitFlags)->unref();
475 SkCanvas::SkCanvas(int width, int height, InitFlags flags)
476 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
477 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
481 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (width, height)), flags)->unref();
484 SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
485 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
486 , fProps(SkSurfacePropsCopyOrDefault(props))
490 this->init(device, flags);
493 SkCanvas::SkCanvas(SkBaseDevice* device)
494 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
495 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
499 this->init(device, kDefault_InitFlags);
502 SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
503 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
508 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
509 this->init(device, kDefault_InitFlags);
512 SkCanvas::SkCanvas(const SkBitmap& bitmap)
513 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
514 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
518 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
519 this->init(device, kDefault_InitFlags);
522 SkCanvas::~SkCanvas() {
523 // free up the contents of our deque
524 this->restoreToCount(1); // restore everything but the last
525 SkASSERT(0 == fSaveLayerCount);
527 this->internalRestore(); // restore the last, since we're going away
534 SkDrawFilter* SkCanvas::getDrawFilter() const {
535 return fMCRec->fFilter;
538 SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
539 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
543 SkMetaData& SkCanvas::getMetaData() {
544 // metadata users are rare, so we lazily allocate it. If that changes we
545 // can decide to just make it a field in the device (rather than a ptr)
546 if (NULL == fMetaData) {
547 fMetaData = new SkMetaData;
552 ///////////////////////////////////////////////////////////////////////////////
554 void SkCanvas::flush() {
555 SkBaseDevice* device = this->getDevice();
561 SkISize SkCanvas::getTopLayerSize() const {
562 SkBaseDevice* d = this->getTopDevice();
563 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
566 SkIPoint SkCanvas::getTopLayerOrigin() const {
567 SkBaseDevice* d = this->getTopDevice();
568 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
571 SkISize SkCanvas::getBaseLayerSize() const {
572 SkBaseDevice* d = this->getDevice();
573 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
576 SkBaseDevice* SkCanvas::getDevice() const {
577 // return root device
578 MCRec* rec = (MCRec*) fMCStack.front();
579 SkASSERT(rec && rec->fLayer);
580 return rec->fLayer->fDevice;
583 SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
584 if (updateMatrixClip) {
585 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
587 return fMCRec->fTopLayer->fDevice;
590 SkBaseDevice* SkCanvas::setRootDevice(SkBaseDevice* device) {
591 // return root device
592 SkDeque::F2BIter iter(fMCStack);
593 MCRec* rec = (MCRec*)iter.next();
594 SkASSERT(rec && rec->fLayer);
595 SkBaseDevice* rootDevice = rec->fLayer->fDevice;
597 if (rootDevice == device) {
602 device->onAttachToCanvas(this);
605 rootDevice->onDetachFromCanvas();
608 SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
610 this->setupDevice(device);
612 fDeviceCMDirty = true;
614 /* Now we update our initial region to have the bounds of the new device,
615 and then intersect all of the clips in our stack with these bounds,
616 to ensure that we can't draw outside of the device's bounds (and trash
619 NOTE: this is only a partial-fix, since if the new device is larger than
620 the previous one, we don't know how to "enlarge" the clips in our stack,
621 so drawing may be artificially restricted. Without keeping a history of
622 all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
623 reconstruct the correct clips, so this approximation will have to do.
624 The caller really needs to restore() back to the base if they want to
625 accurately take advantage of the new device bounds.
630 bounds.set(0, 0, device->width(), device->height());
634 // now jam our 1st clip to be bounds, and intersect the rest with that
635 rec->fRasterClip.setRect(bounds);
636 while ((rec = (MCRec*)iter.next()) != NULL) {
637 (void)rec->fRasterClip.op(bounds, SkRegion::kIntersect_Op);
643 bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
644 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
648 bool weAllocated = false;
649 if (NULL == bitmap->pixelRef()) {
650 if (!bitmap->tryAllocPixels()) {
656 SkBitmap bm(*bitmap);
658 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
663 bitmap->setPixelRef(NULL);
668 bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
670 const SkISize size = this->getBaseLayerSize();
671 if (!r.intersect(0, 0, size.width(), size.height())) {
676 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
677 // bitmap will already be reset.
680 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
687 bool SkCanvas::readPixels(const SkImageInfo& origInfo, void* dstP, size_t rowBytes, int x, int y) {
688 switch (origInfo.colorType()) {
689 case kUnknown_SkColorType:
690 case kIndex_8_SkColorType:
695 if (NULL == dstP || rowBytes < origInfo.minRowBytes()) {
698 if (0 == origInfo.width() || 0 == origInfo.height()) {
702 SkBaseDevice* device = this->getDevice();
707 const SkISize size = this->getBaseLayerSize();
708 SkIRect srcR = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
709 if (!srcR.intersect(0, 0, size.width(), size.height())) {
713 // the intersect may have shrunk info's logical size
714 const SkImageInfo info = origInfo.makeWH(srcR.width(), srcR.height());
716 // if x or y are negative, then we have to adjust pixels
723 // here x,y are either 0 or negative
724 dstP = ((char*)dstP - y * rowBytes - x * info.bytesPerPixel());
726 // The device can assert that the requested area is always contained in its bounds
727 return device->readPixels(info, dstP, rowBytes, srcR.x(), srcR.y());
730 bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
731 if (bitmap.getTexture()) {
736 if (bm.getPixels()) {
737 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
742 bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
744 switch (origInfo.colorType()) {
745 case kUnknown_SkColorType:
746 case kIndex_8_SkColorType:
751 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
755 const SkISize size = this->getBaseLayerSize();
756 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
757 if (!target.intersect(0, 0, size.width(), size.height())) {
761 SkBaseDevice* device = this->getDevice();
766 // the intersect may have shrunk info's logical size
767 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
769 // if x or y are negative, then we have to adjust pixels
776 // here x,y are either 0 or negative
777 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
779 // Tell our owning surface to bump its generation ID
780 this->predrawNotify();
782 // The device can assert that the requested area is always contained in its bounds
783 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
786 SkCanvas* SkCanvas::canvasForDrawIter() {
790 //////////////////////////////////////////////////////////////////////////////
792 void SkCanvas::updateDeviceCMCache() {
793 if (fDeviceCMDirty) {
794 const SkMatrix& totalMatrix = this->getTotalMatrix();
795 const SkRasterClip& totalClip = fMCRec->fRasterClip;
796 DeviceCM* layer = fMCRec->fTopLayer;
798 if (NULL == layer->fNext) { // only one layer
799 layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
801 SkRasterClip clip(totalClip);
803 layer->updateMC(totalMatrix, clip, fClipStack, &clip);
804 } while ((layer = layer->fNext) != NULL);
806 fDeviceCMDirty = false;
810 ///////////////////////////////////////////////////////////////////////////////
812 int SkCanvas::internalSave() {
813 int saveCount = this->getSaveCount(); // record this before the actual save
815 MCRec* newTop = (MCRec*)fMCStack.push_back();
816 new (newTop) MCRec(*fMCRec); // balanced in restore()
824 int SkCanvas::save() {
826 return this->internalSave();
829 static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
830 #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
831 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
837 bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
838 SkIRect* intersection, const SkImageFilter* imageFilter) {
840 SkRegion::Op op = SkRegion::kIntersect_Op;
841 if (!this->getClipDeviceBounds(&clipBounds)) {
846 imageFilter->filterBounds(clipBounds, fMCRec->fMatrix, &clipBounds);
847 // Filters may grow the bounds beyond the device bounds.
848 op = SkRegion::kReplace_Op;
854 this->getTotalMatrix().mapRect(&r, *bounds);
856 // early exit if the layer's bounds are clipped out
857 if (!ir.intersect(clipBounds)) {
858 if (bounds_affects_clip(flags)) {
859 fMCRec->fRasterClip.setEmpty();
863 } else { // no user bounds, so just use the clip
867 if (bounds_affects_clip(flags)) {
868 fClipStack.clipDevRect(ir, op);
869 // early exit if the clip is now empty
870 if (!fMCRec->fRasterClip.op(ir, op)) {
881 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
882 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
883 return this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, false, strategy);
886 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
888 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
889 return this->internalSaveLayer(bounds, paint, flags, false, strategy);
892 int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
893 bool justForImageFilter, SaveLayerStrategy strategy) {
894 #ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
895 flags |= kClipToLayer_SaveFlag;
898 // do this before we create the layer. We don't call the public save() since
899 // that would invoke a possibly overridden virtual
900 int count = this->internalSave();
902 fDeviceCMDirty = true;
905 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
909 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
910 // the clipRectBounds() call above?
911 if (kNoLayer_SaveLayerStrategy == strategy) {
915 // Kill the imagefilter if our device doesn't allow it
917 if (paint && paint->getImageFilter()) {
918 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
919 if (justForImageFilter) {
920 // early exit if the layer was just for the imageFilter
923 SkPaint* p = lazyP.set(*paint);
924 p->setImageFilter(NULL);
929 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
930 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
931 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
933 SkBaseDevice* device;
934 if (paint && paint->getImageFilter()) {
935 device = this->getDevice();
937 device = device->createCompatibleDeviceForImageFilter(info);
940 device = this->createLayerDevice(info);
942 if (NULL == device) {
943 SkDebugf("Unable to create device for layer.");
946 this->setupDevice(device);
948 device->setOrigin(ir.fLeft, ir.fTop);
949 DeviceCM* layer = SkNEW_ARGS(DeviceCM,
950 (device, ir.fLeft, ir.fTop, paint, this, fConservativeRasterClip));
953 layer->fNext = fMCRec->fTopLayer;
954 fMCRec->fLayer = layer;
955 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
957 fSaveLayerCount += 1;
961 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
962 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
965 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
968 return this->saveLayer(bounds, NULL, flags);
971 tmpPaint.setAlpha(alpha);
972 return this->saveLayer(bounds, &tmpPaint, flags);
976 void SkCanvas::restore() {
977 // check for underflow
978 if (fMCStack.count() > 1) {
980 this->internalRestore();
985 void SkCanvas::internalRestore() {
986 SkASSERT(fMCStack.count() != 0);
988 fDeviceCMDirty = true;
989 fCachedLocalClipBoundsDirty = true;
991 fClipStack.restore();
993 // reserve our layer (if any)
994 DeviceCM* layer = fMCRec->fLayer; // may be null
995 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
996 fMCRec->fLayer = NULL;
998 // now do the normal restore()
999 fMCRec->~MCRec(); // balanced in save()
1000 fMCStack.pop_back();
1001 fMCRec = (MCRec*)fMCStack.back();
1003 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1004 since if we're being recorded, we don't want to record this (the
1005 recorder will have already recorded the restore).
1009 const SkIPoint& origin = layer->fDevice->getOrigin();
1010 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
1012 // reset this, since internalDrawDevice will have set it to true
1013 fDeviceCMDirty = true;
1015 SkASSERT(fSaveLayerCount > 0);
1016 fSaveLayerCount -= 1;
1022 int SkCanvas::getSaveCount() const {
1023 return fMCStack.count();
1026 void SkCanvas::restoreToCount(int count) {
1032 int n = this->getSaveCount() - count;
1033 for (int i = 0; i < n; ++i) {
1038 bool SkCanvas::isDrawingToLayer() const {
1039 return fSaveLayerCount > 0;
1042 SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1043 if (NULL == props) {
1046 return this->onNewSurface(info, *props);
1049 SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1050 SkBaseDevice* dev = this->getDevice();
1051 return dev ? dev->newSurface(info, props) : NULL;
1054 SkImageInfo SkCanvas::imageInfo() const {
1055 SkBaseDevice* dev = this->getDevice();
1057 return dev->imageInfo();
1059 return SkImageInfo::MakeUnknown(0, 0);
1063 const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1064 return this->onPeekPixels(info, rowBytes);
1067 const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1068 SkBaseDevice* dev = this->getDevice();
1069 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1072 void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1073 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1074 if (pixels && origin) {
1075 *origin = this->getTopDevice(false)->getOrigin();
1080 void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1081 SkBaseDevice* dev = this->getTopDevice();
1082 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1085 SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1086 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1087 if (NULL == fAddr) {
1088 fInfo = canvas->imageInfo();
1089 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
1090 return; // failure, fAddr is NULL
1092 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1093 return; // failure, fAddr is NULL
1095 fAddr = fBitmap.getPixels();
1096 fRowBytes = fBitmap.rowBytes();
1098 SkASSERT(fAddr); // success
1101 bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1103 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
1110 void SkCanvas::onPushCull(const SkRect& cullRect) {
1111 // do nothing. Subclasses may do something
1114 void SkCanvas::onPopCull() {
1115 // do nothing. Subclasses may do something
1118 /////////////////////////////////////////////////////////////////////////////
1120 // Ensure that cull rects are monotonically nested in device space.
1121 void SkCanvas::validateCull(const SkIRect& devCull) {
1122 if (fCullStack.isEmpty()
1123 || devCull.isEmpty()
1124 || fCullStack.top().contains(devCull)) {
1128 SkDEBUGF(("Invalid cull: [%d %d %d %d] (previous cull: [%d %d %d %d])\n",
1129 devCull.x(), devCull.y(), devCull.right(), devCull.bottom(),
1130 fCullStack.top().x(), fCullStack.top().y(),
1131 fCullStack.top().right(), fCullStack.top().bottom()));
1133 #ifdef ASSERT_NESTED_CULLING
1134 SkDEBUGFAIL("Invalid cull.");
1139 void SkCanvas::pushCull(const SkRect& cullRect) {
1141 this->onPushCull(cullRect);
1144 // Map the cull rect into device space.
1146 this->getTotalMatrix().mapRect(&mappedCull, cullRect);
1148 // Take clipping into account.
1149 SkIRect devClip, devCull;
1150 mappedCull.roundOut(&devCull);
1151 this->getClipDeviceBounds(&devClip);
1152 if (!devCull.intersect(devClip)) {
1156 this->validateCull(devCull);
1157 fCullStack.push(devCull); // balanced in popCull
1161 void SkCanvas::popCull() {
1162 SkASSERT(fCullStack.count() == fCullCount);
1164 if (fCullCount > 0) {
1168 SkDEBUGCODE(fCullStack.pop());
1172 /////////////////////////////////////////////////////////////////////////////
1174 void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
1175 const SkMatrix& matrix, const SkPaint* paint) {
1176 if (bitmap.drawsNothing()) {
1181 if (NULL == paint) {
1182 paint = lazy.init();
1185 SkDEBUGCODE(bitmap.validate();)
1188 const SkRect* bounds = NULL;
1189 if (paint && paint->canComputeFastBounds()) {
1190 bitmap.getBounds(&storage);
1191 matrix.mapRect(&storage);
1192 bounds = &paint->computeFastBounds(storage, &storage);
1195 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
1197 while (iter.next()) {
1198 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1204 void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
1205 const SkPaint* paint) {
1207 if (NULL == paint) {
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 TRACE_EVENT0("skia", "SkCanvas::drawSprite()");
1243 if (bitmap.drawsNothing()) {
1246 SkDEBUGCODE(bitmap.validate();)
1249 if (NULL == paint) {
1253 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
1255 while (iter.next()) {
1256 paint = &looper.paint();
1257 SkImageFilter* filter = paint->getImageFilter();
1258 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1259 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
1260 SkDeviceImageFilterProxy proxy(iter.fDevice);
1262 SkIPoint offset = SkIPoint::Make(0, 0);
1263 SkMatrix matrix = *iter.fMatrix;
1264 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
1265 const SkIRect clipBounds = bitmap.bounds();
1266 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
1267 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
1268 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
1269 SkPaint tmpUnfiltered(*paint);
1270 tmpUnfiltered.setImageFilter(NULL);
1271 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1275 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1281 /////////////////////////////////////////////////////////////////////////////
1282 void SkCanvas::translate(SkScalar dx, SkScalar dy) {
1284 m.setTranslate(dx, dy);
1288 void SkCanvas::scale(SkScalar sx, SkScalar sy) {
1294 void SkCanvas::rotate(SkScalar degrees) {
1296 m.setRotate(degrees);
1300 void SkCanvas::skew(SkScalar sx, SkScalar sy) {
1306 void SkCanvas::concat(const SkMatrix& matrix) {
1307 if (matrix.isIdentity()) {
1311 fDeviceCMDirty = true;
1312 fCachedLocalClipBoundsDirty = true;
1313 fMCRec->fMatrix.preConcat(matrix);
1315 this->didConcat(matrix);
1318 void SkCanvas::setMatrix(const SkMatrix& matrix) {
1319 fDeviceCMDirty = true;
1320 fCachedLocalClipBoundsDirty = true;
1321 fMCRec->fMatrix = matrix;
1322 this->didSetMatrix(matrix);
1325 void SkCanvas::resetMatrix() {
1329 this->setMatrix(matrix);
1332 //////////////////////////////////////////////////////////////////////////////
1334 void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
1335 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1336 this->onClipRect(rect, op, edgeStyle);
1339 void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1340 #ifdef SK_ENABLE_CLIP_QUICKREJECT
1341 if (SkRegion::kIntersect_Op == op) {
1342 if (fMCRec->fRasterClip.isEmpty()) {
1346 if (this->quickReject(rect)) {
1347 fDeviceCMDirty = true;
1348 fCachedLocalClipBoundsDirty = true;
1350 fClipStack.clipEmpty();
1351 return fMCRec->fRasterClip.setEmpty();
1356 AutoValidateClip avc(this);
1358 fDeviceCMDirty = true;
1359 fCachedLocalClipBoundsDirty = true;
1360 if (!fAllowSoftClip) {
1361 edgeStyle = kHard_ClipEdgeStyle;
1364 if (fMCRec->fMatrix.rectStaysRect()) {
1365 // for these simpler matrices, we can stay a rect even after applying
1366 // the matrix. This means we don't have to a) make a path, and b) tell
1367 // the region code to scan-convert the path, only to discover that it
1368 // is really just a rect.
1371 fMCRec->fMatrix.mapRect(&r, rect);
1372 fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
1373 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
1375 // since we're rotated or some such thing, we convert the rect to a path
1376 // and clip against that, since it can handle any matrix. However, to
1377 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1378 // we explicitly call "our" version of clipPath.
1382 this->SkCanvas::onClipPath(path, op, edgeStyle);
1386 static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1387 SkRegion::Op op, bool doAA) {
1388 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
1391 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
1392 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1393 if (rrect.isRect()) {
1394 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1396 this->onClipRRect(rrect, op, edgeStyle);
1400 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1401 SkRRect transformedRRect;
1402 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
1403 AutoValidateClip avc(this);
1405 fDeviceCMDirty = true;
1406 fCachedLocalClipBoundsDirty = true;
1407 if (!fAllowSoftClip) {
1408 edgeStyle = kHard_ClipEdgeStyle;
1411 fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
1414 devPath.addRRect(transformedRRect);
1416 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
1421 path.addRRect(rrect);
1422 // call the non-virtual version
1423 this->SkCanvas::onClipPath(path, op, edgeStyle);
1426 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
1427 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1429 if (!path.isInverseFillType() && path.isRect(&r)) {
1430 this->onClipRect(r, op, edgeStyle);
1432 this->onClipPath(path, op, edgeStyle);
1436 void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1437 #ifdef SK_ENABLE_CLIP_QUICKREJECT
1438 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
1439 if (fMCRec->fRasterClip.isEmpty()) {
1443 if (this->quickReject(path.getBounds())) {
1444 fDeviceCMDirty = true;
1445 fCachedLocalClipBoundsDirty = true;
1447 fClipStack.clipEmpty();
1448 return fMCRec->fRasterClip.setEmpty();
1453 AutoValidateClip avc(this);
1455 fDeviceCMDirty = true;
1456 fCachedLocalClipBoundsDirty = true;
1457 if (!fAllowSoftClip) {
1458 edgeStyle = kHard_ClipEdgeStyle;
1462 path.transform(fMCRec->fMatrix, &devPath);
1464 // Check if the transfomation, or the original path itself
1465 // made us empty. Note this can also happen if we contained NaN
1466 // values. computing the bounds detects this, and will set our
1467 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1468 if (devPath.getBounds().isEmpty()) {
1469 // resetting the path will remove any NaN or other wanky values
1470 // that might upset our scan converter.
1474 // if we called path.swap() we could avoid a deep copy of this path
1475 fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
1477 if (fAllowSimplifyClip) {
1479 devPath.setFillType(SkPath::kInverseEvenOdd_FillType);
1480 const SkClipStack* clipStack = getClipStack();
1481 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
1482 const SkClipStack::Element* element;
1483 while ((element = iter.next())) {
1484 SkClipStack::Element::Type type = element->getType();
1486 if (type != SkClipStack::Element::kEmpty_Type) {
1487 element->asPath(&operand);
1489 SkRegion::Op elementOp = element->getOp();
1490 if (elementOp == SkRegion::kReplace_Op) {
1493 Op(devPath, operand, (SkPathOp) elementOp, &devPath);
1495 // if the prev and curr clips disagree about aa -vs- not, favor the aa request.
1496 // perhaps we need an API change to avoid this sort of mixed-signals about
1498 if (element->isAA()) {
1499 edgeStyle = kSoft_ClipEdgeStyle;
1502 op = SkRegion::kReplace_Op;
1505 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
1508 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
1509 this->onClipRegion(rgn, op);
1512 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
1513 AutoValidateClip avc(this);
1515 fDeviceCMDirty = true;
1516 fCachedLocalClipBoundsDirty = true;
1518 // todo: signal fClipStack that we have a region, and therefore (I guess)
1519 // we have to ignore it, and use the region directly?
1520 fClipStack.clipDevRect(rgn.getBounds(), op);
1522 fMCRec->fRasterClip.op(rgn, op);
1526 void SkCanvas::validateClip() const {
1527 // construct clipRgn from the clipstack
1528 const SkBaseDevice* device = this->getDevice();
1530 SkASSERT(this->isClipEmpty());
1535 ir.set(0, 0, device->width(), device->height());
1536 SkRasterClip tmpClip(ir, fConservativeRasterClip);
1538 SkClipStack::B2TIter iter(fClipStack);
1539 const SkClipStack::Element* element;
1540 while ((element = iter.next()) != NULL) {
1541 switch (element->getType()) {
1542 case SkClipStack::Element::kRect_Type:
1543 element->getRect().round(&ir);
1544 tmpClip.op(ir, element->getOp());
1546 case SkClipStack::Element::kEmpty_Type:
1551 element->asPath(&path);
1552 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
1560 void SkCanvas::replayClips(ClipVisitor* visitor) const {
1561 SkClipStack::B2TIter iter(fClipStack);
1562 const SkClipStack::Element* element;
1564 while ((element = iter.next()) != NULL) {
1565 element->replay(visitor);
1569 ///////////////////////////////////////////////////////////////////////////////
1571 bool SkCanvas::isClipEmpty() const {
1572 return fMCRec->fRasterClip.isEmpty();
1575 bool SkCanvas::isClipRect() const {
1576 return fMCRec->fRasterClip.isRect();
1579 bool SkCanvas::quickReject(const SkRect& rect) const {
1580 if (!rect.isFinite())
1583 if (fMCRec->fRasterClip.isEmpty()) {
1587 if (fMCRec->fMatrix.hasPerspective()) {
1589 fMCRec->fMatrix.mapRect(&dst, rect);
1591 dst.roundOut(&idst);
1592 return !SkIRect::Intersects(idst, fMCRec->fRasterClip.getBounds());
1594 const SkRect& clipR = this->getLocalClipBounds();
1596 // for speed, do the most likely reject compares first
1597 // TODO: should we use | instead, or compare all 4 at once?
1598 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
1601 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
1608 bool SkCanvas::quickReject(const SkPath& path) const {
1609 return path.isEmpty() || this->quickReject(path.getBounds());
1612 bool SkCanvas::getClipBounds(SkRect* bounds) const {
1614 if (!this->getClipDeviceBounds(&ibounds)) {
1619 // if we can't invert the CTM, we can't return local clip bounds
1620 if (!fMCRec->fMatrix.invert(&inverse)) {
1629 // adjust it outwards in case we are antialiasing
1630 const int inset = 1;
1632 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1633 ibounds.fRight + inset, ibounds.fBottom + inset);
1634 inverse.mapRect(bounds, r);
1639 bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
1640 const SkRasterClip& clip = fMCRec->fRasterClip;
1641 if (clip.isEmpty()) {
1649 *bounds = clip.getBounds();
1654 const SkMatrix& SkCanvas::getTotalMatrix() const {
1655 return fMCRec->fMatrix;
1658 const SkRegion& SkCanvas::internal_private_getTotalClip() const {
1659 return fMCRec->fRasterClip.forceGetBW();
1662 GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1663 SkBaseDevice* dev = this->getTopDevice();
1664 return dev ? dev->accessRenderTarget() : NULL;
1667 SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) {
1668 SkBaseDevice* device = this->getTopDevice();
1669 return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL;
1672 GrContext* SkCanvas::getGrContext() {
1674 SkBaseDevice* device = this->getTopDevice();
1676 GrRenderTarget* renderTarget = device->accessRenderTarget();
1678 return renderTarget->getContext();
1687 void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1688 const SkPaint& paint) {
1689 TRACE_EVENT0("skia", "SkCanvas::drawDRRect()");
1690 if (outer.isEmpty()) {
1693 if (inner.isEmpty()) {
1694 this->drawRRect(outer, paint);
1698 // We don't have this method (yet), but technically this is what we should
1699 // be able to assert...
1700 // SkASSERT(outer.contains(inner));
1702 // For now at least check for containment of bounds
1703 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1705 this->onDrawDRRect(outer, inner, paint);
1708 //////////////////////////////////////////////////////////////////////////////
1709 // These are the virtual drawing methods
1710 //////////////////////////////////////////////////////////////////////////////
1712 void SkCanvas::clear(SkColor color) {
1713 SkDrawIter iter(this);
1714 this->predrawNotify();
1715 while (iter.next()) {
1716 iter.fDevice->clear(color);
1720 void SkCanvas::onDiscard() {
1722 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1726 void SkCanvas::drawPaint(const SkPaint& paint) {
1727 TRACE_EVENT0("skia", "SkCanvas::drawPaint()");
1728 this->internalDrawPaint(paint);
1731 void SkCanvas::internalDrawPaint(const SkPaint& paint) {
1732 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
1734 while (iter.next()) {
1735 iter.fDevice->drawPaint(iter, looper.paint());
1741 void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
1742 const SkPaint& paint) {
1743 TRACE_EVENT1("skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
1744 if ((long)count <= 0) {
1749 const SkRect* bounds = NULL;
1750 if (paint.canComputeFastBounds()) {
1751 // special-case 2 points (common for drawing a single line)
1753 r.set(pts[0], pts[1]);
1755 r.set(pts, SkToInt(count));
1757 bounds = &paint.computeFastStrokeBounds(r, &storage);
1758 if (this->quickReject(*bounds)) {
1763 SkASSERT(pts != NULL);
1765 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
1767 while (iter.next()) {
1768 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
1774 void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1775 TRACE_EVENT0("skia", "SkCanvas::drawRect()");
1777 const SkRect* bounds = NULL;
1778 if (paint.canComputeFastBounds()) {
1779 bounds = &paint.computeFastBounds(r, &storage);
1780 if (this->quickReject(*bounds)) {
1785 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
1787 while (iter.next()) {
1788 iter.fDevice->drawRect(iter, r, looper.paint());
1794 void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
1795 TRACE_EVENT0("skia", "SkCanvas::drawOval()");
1797 const SkRect* bounds = NULL;
1798 if (paint.canComputeFastBounds()) {
1799 bounds = &paint.computeFastBounds(oval, &storage);
1800 if (this->quickReject(*bounds)) {
1805 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
1807 while (iter.next()) {
1808 iter.fDevice->drawOval(iter, oval, looper.paint());
1814 void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1815 TRACE_EVENT0("skia", "SkCanvas::drawRRect()");
1817 const SkRect* bounds = NULL;
1818 if (paint.canComputeFastBounds()) {
1819 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1820 if (this->quickReject(*bounds)) {
1825 if (rrect.isRect()) {
1826 // call the non-virtual version
1827 this->SkCanvas::drawRect(rrect.getBounds(), paint);
1829 } else if (rrect.isOval()) {
1830 // call the non-virtual version
1831 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1835 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
1837 while (iter.next()) {
1838 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1844 void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1845 const SkPaint& paint) {
1847 const SkRect* bounds = NULL;
1848 if (paint.canComputeFastBounds()) {
1849 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1850 if (this->quickReject(*bounds)) {
1855 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
1857 while (iter.next()) {
1858 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1864 void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1865 TRACE_EVENT0("skia", "SkCanvas::drawPath()");
1866 if (!path.isFinite()) {
1871 const SkRect* bounds = NULL;
1872 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
1873 const SkRect& pathBounds = path.getBounds();
1874 bounds = &paint.computeFastBounds(pathBounds, &storage);
1875 if (this->quickReject(*bounds)) {
1880 const SkRect& r = path.getBounds();
1881 if (r.width() <= 0 && r.height() <= 0) {
1882 if (path.isInverseFillType()) {
1883 this->internalDrawPaint(paint);
1888 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
1890 while (iter.next()) {
1891 iter.fDevice->drawPath(iter, path, looper.paint());
1897 void SkCanvas::drawImage(const SkImage* image, SkScalar left, SkScalar top,
1898 const SkPaint* paint) {
1899 TRACE_EVENT0("skia", "SkCanvas::drawImage()");
1900 image->draw(this, left, top, paint);
1903 void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src,
1905 const SkPaint* paint) {
1906 TRACE_EVENT0("skia", "SkCanvas::drawImageRect()");
1907 image->drawRect(this, src, dst, paint);
1910 void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
1911 const SkPaint* paint) {
1912 TRACE_EVENT0("skia", "SkCanvas::drawBitmap()");
1913 SkDEBUGCODE(bitmap.validate();)
1915 if (NULL == paint || paint->canComputeFastBounds()) {
1918 x + SkIntToScalar(bitmap.width()),
1919 y + SkIntToScalar(bitmap.height())
1922 (void)paint->computeFastBounds(bounds, &bounds);
1924 if (this->quickReject(bounds)) {
1930 matrix.setTranslate(x, y);
1931 this->internalDrawBitmap(bitmap, matrix, paint);
1934 // this one is non-virtual, so it can be called safely by other canvas apis
1935 void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
1936 const SkRect& dst, const SkPaint* paint,
1937 DrawBitmapRectFlags flags) {
1938 if (bitmap.drawsNothing() || dst.isEmpty()) {
1943 const SkRect* bounds = &dst;
1944 if (NULL == paint || paint->canComputeFastBounds()) {
1946 bounds = &paint->computeFastBounds(dst, &storage);
1948 if (this->quickReject(*bounds)) {
1954 if (NULL == paint) {
1955 paint = lazy.init();
1958 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
1960 while (iter.next()) {
1961 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
1967 void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
1968 const SkRect& dst, const SkPaint* paint,
1969 DrawBitmapRectFlags flags) {
1970 TRACE_EVENT0("skia", "SkCanvas::drawBitmapRectToRect()");
1971 SkDEBUGCODE(bitmap.validate();)
1972 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
1975 void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
1976 const SkPaint* paint) {
1977 TRACE_EVENT0("skia", "SkCanvas::drawBitmapMatrix()");
1978 SkDEBUGCODE(bitmap.validate();)
1979 this->internalDrawBitmap(bitmap, matrix, paint);
1982 void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1983 const SkIRect& center, const SkRect& dst,
1984 const SkPaint* paint) {
1985 if (bitmap.drawsNothing()) {
1988 if (NULL == paint || paint->canComputeFastBounds()) {
1990 const SkRect* bounds = &dst;
1992 bounds = &paint->computeFastBounds(dst, &storage);
1994 if (this->quickReject(*bounds)) {
1999 const int32_t w = bitmap.width();
2000 const int32_t h = bitmap.height();
2003 // pin center to the bounds of the bitmap
2004 c.fLeft = SkMax32(0, center.fLeft);
2005 c.fTop = SkMax32(0, center.fTop);
2006 c.fRight = SkPin32(center.fRight, c.fLeft, w);
2007 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
2009 const SkScalar srcX[4] = {
2010 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
2012 const SkScalar srcY[4] = {
2013 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
2015 SkScalar dstX[4] = {
2016 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2017 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2019 SkScalar dstY[4] = {
2020 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2021 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2024 if (dstX[1] > dstX[2]) {
2025 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2029 if (dstY[1] > dstY[2]) {
2030 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2034 for (int y = 0; y < 3; y++) {
2038 s.fBottom = srcY[y+1];
2040 d.fBottom = dstY[y+1];
2041 for (int x = 0; x < 3; x++) {
2043 s.fRight = srcX[x+1];
2045 d.fRight = dstX[x+1];
2046 this->internalDrawBitmapRect(bitmap, &s, d, paint,
2047 kNone_DrawBitmapRectFlag);
2052 void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
2053 const SkRect& dst, const SkPaint* paint) {
2054 TRACE_EVENT0("skia", "SkCanvas::drawBitmapNine()");
2055 SkDEBUGCODE(bitmap.validate();)
2057 // Need a device entry-point, so gpu can use a mesh
2058 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2061 class SkDeviceFilteredPaint {
2063 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
2064 SkBaseDevice::TextFlags flags;
2065 if (device->filterTextFlags(paint, &flags)) {
2066 SkPaint* newPaint = fLazy.set(paint);
2067 newPaint->setFlags(flags.fFlags);
2074 const SkPaint& paint() const { return *fPaint; }
2077 const SkPaint* fPaint;
2081 void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2082 const SkRect& r, SkScalar textSize) {
2083 if (paint.getStyle() == SkPaint::kFill_Style) {
2084 draw.fDevice->drawRect(draw, r, paint);
2087 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
2088 draw.fDevice->drawRect(draw, r, p);
2092 void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2093 const char text[], size_t byteLength,
2094 SkScalar x, SkScalar y) {
2095 SkASSERT(byteLength == 0 || text != NULL);
2098 if (text == NULL || byteLength == 0 ||
2099 draw.fClip->isEmpty() ||
2100 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2107 start.set(0, 0); // to avoid warning
2108 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2109 SkPaint::kStrikeThruText_Flag)) {
2110 width = paint.measureText(text, byteLength);
2112 SkScalar offsetX = 0;
2113 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2114 offsetX = SkScalarHalf(width);
2115 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2118 start.set(x - offsetX, y);
2125 uint32_t flags = paint.getFlags();
2127 if (flags & (SkPaint::kUnderlineText_Flag |
2128 SkPaint::kStrikeThruText_Flag)) {
2129 SkScalar textSize = paint.getTextSize();
2130 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2134 r.fRight = start.fX + width;
2136 if (flags & SkPaint::kUnderlineText_Flag) {
2137 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2140 r.fBottom = offset + height;
2141 DrawRect(draw, paint, r, textSize);
2143 if (flags & SkPaint::kStrikeThruText_Flag) {
2144 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2147 r.fBottom = offset + height;
2148 DrawRect(draw, paint, r, textSize);
2153 void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
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->drawText(iter, text, byteLength, x, y, dfp.paint());
2160 DrawTextDecorations(iter, dfp.paint(),
2161 static_cast<const char*>(text), byteLength, x, y);
2167 void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2168 const SkPaint& paint) {
2169 SkPoint textOffset = SkPoint::Make(0, 0);
2171 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2173 while (iter.next()) {
2174 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2175 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
2182 void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2183 SkScalar constY, const SkPaint& paint) {
2185 SkPoint textOffset = SkPoint::Make(0, constY);
2187 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2189 while (iter.next()) {
2190 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2191 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
2198 void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2199 const SkMatrix* matrix, const SkPaint& paint) {
2200 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2202 while (iter.next()) {
2203 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
2204 matrix, looper.paint());
2210 void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2211 const SkPaint& paint) {
2213 if (paint.canComputeFastBounds()) {
2216 if (this->quickReject(paint.computeFastBounds(blob->bounds().makeOffset(x, y), &storage))) {
2221 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
2223 while (iter.next()) {
2224 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2225 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint());
2231 // These will become non-virtual, so they always call the (virtual) onDraw... method
2232 void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2233 const SkPaint& paint) {
2234 TRACE_EVENT0("skia", "SkCanvas::drawText()");
2235 this->onDrawText(text, byteLength, x, y, paint);
2237 void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2238 const SkPaint& paint) {
2239 TRACE_EVENT0("skia", "SkCanvas::drawPosText()");
2240 this->onDrawPosText(text, byteLength, pos, paint);
2242 void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2243 SkScalar constY, const SkPaint& paint) {
2244 TRACE_EVENT0("skia", "SkCanvas::drawPosTextH()");
2245 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2247 void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2248 const SkMatrix* matrix, const SkPaint& paint) {
2249 TRACE_EVENT0("skia", "SkCanvas::drawTextOnPath()");
2250 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2252 void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2253 const SkPaint& paint) {
2254 TRACE_EVENT0("skia", "SkCanvas::drawTextBlob()");
2256 this->onDrawTextBlob(blob, x, y, paint);
2260 void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
2261 const SkPoint verts[], const SkPoint texs[],
2262 const SkColor colors[], SkXfermode* xmode,
2263 const uint16_t indices[], int indexCount,
2264 const SkPaint& paint) {
2265 TRACE_EVENT0("skia", "SkCanvas::drawVertices()");
2266 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
2268 while (iter.next()) {
2269 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
2270 colors, xmode, indices, indexCount,
2277 void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2278 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2279 TRACE_EVENT0("skia", "SkCanvas::drawPatch()");
2280 if (NULL == cubics) {
2284 // Since a patch is always within the convex hull of the control points, we discard it when its
2285 // bounding rectangle is completely outside the current clip.
2287 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
2288 if (this->quickReject(bounds)) {
2292 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2295 void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2296 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2298 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
2300 while (iter.next()) {
2301 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
2307 //////////////////////////////////////////////////////////////////////////////
2308 // These methods are NOT virtual, and therefore must call back into virtual
2309 // methods, rather than actually drawing themselves.
2310 //////////////////////////////////////////////////////////////////////////////
2312 void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
2313 SkXfermode::Mode mode) {
2314 TRACE_EVENT0("skia", "SkCanvas::drawARGB()");
2317 paint.setARGB(a, r, g, b);
2318 if (SkXfermode::kSrcOver_Mode != mode) {
2319 paint.setXfermodeMode(mode);
2321 this->drawPaint(paint);
2324 void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
2325 TRACE_EVENT0("skia", "SkCanvas::drawColor()");
2329 if (SkXfermode::kSrcOver_Mode != mode) {
2330 paint.setXfermodeMode(mode);
2332 this->drawPaint(paint);
2335 void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
2336 TRACE_EVENT0("skia", "SkCanvas::drawPoint(SkPaint)");
2340 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2343 void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
2344 TRACE_EVENT0("skia", "SkCanvas::drawPoint(SkColor)");
2349 paint.setColor(color);
2350 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2353 void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2354 const SkPaint& paint) {
2355 TRACE_EVENT0("skia", "SkCanvas::drawLine()");
2360 this->drawPoints(kLines_PointMode, 2, pts, paint);
2363 void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2364 SkScalar right, SkScalar bottom,
2365 const SkPaint& paint) {
2366 TRACE_EVENT0("skia", "SkCanvas::drawRectCoords()");
2369 r.set(left, top, right, bottom);
2370 this->drawRect(r, paint);
2373 void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2374 const SkPaint& paint) {
2375 TRACE_EVENT0("skia", "SkCanvas::drawCircle()");
2381 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
2382 this->drawOval(r, paint);
2385 void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2386 const SkPaint& paint) {
2387 TRACE_EVENT0("skia", "SkCanvas::drawRoundRect()");
2388 if (rx > 0 && ry > 0) {
2389 if (paint.canComputeFastBounds()) {
2391 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
2396 rrect.setRectXY(r, rx, ry);
2397 this->drawRRect(rrect, paint);
2399 this->drawRect(r, paint);
2403 void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2404 SkScalar sweepAngle, bool useCenter,
2405 const SkPaint& paint) {
2406 TRACE_EVENT0("skia", "SkCanvas::drawArc()");
2407 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2408 this->drawOval(oval, paint);
2412 path.moveTo(oval.centerX(), oval.centerY());
2414 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2418 this->drawPath(path, paint);
2422 void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2423 const SkPath& path, SkScalar hOffset,
2424 SkScalar vOffset, const SkPaint& paint) {
2425 TRACE_EVENT0("skia", "SkCanvas::drawTextOnPathHV()");
2428 matrix.setTranslate(hOffset, vOffset);
2429 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2432 ///////////////////////////////////////////////////////////////////////////////
2433 void SkCanvas::EXPERIMENTAL_optimize(const SkPicture* picture) {
2434 SkBaseDevice* device = this->getDevice();
2436 device->EXPERIMENTAL_optimize(picture);
2440 void SkCanvas::drawPicture(const SkPicture* picture) {
2441 TRACE_EVENT0("skia", "SkCanvas::drawPicture()");
2443 this->onDrawPicture(picture, NULL, NULL);
2447 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
2448 TRACE_EVENT0("skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)");
2450 if (matrix && matrix->isIdentity()) {
2453 this->onDrawPicture(picture, matrix, paint);
2457 void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2458 const SkPaint* paint) {
2459 SkBaseDevice* device = this->getTopDevice();
2461 // Canvas has to first give the device the opportunity to render
2462 // the picture itself.
2463 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
2464 return; // the device has rendered the entire picture
2468 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2470 picture->playback(this);
2473 ///////////////////////////////////////////////////////////////////////////////
2474 ///////////////////////////////////////////////////////////////////////////////
2476 SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
2477 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
2481 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2482 fDone = !fImpl->next();
2485 SkCanvas::LayerIter::~LayerIter() {
2486 fImpl->~SkDrawIter();
2489 void SkCanvas::LayerIter::next() {
2490 fDone = !fImpl->next();
2493 SkBaseDevice* SkCanvas::LayerIter::device() const {
2494 return fImpl->getDevice();
2497 const SkMatrix& SkCanvas::LayerIter::matrix() const {
2498 return fImpl->getMatrix();
2501 const SkPaint& SkCanvas::LayerIter::paint() const {
2502 const SkPaint* paint = fImpl->getPaint();
2503 if (NULL == paint) {
2504 paint = &fDefaultPaint;
2509 const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2510 int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2511 int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
2513 ///////////////////////////////////////////////////////////////////////////////
2515 SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
2517 ///////////////////////////////////////////////////////////////////////////////
2519 static bool supported_for_raster_canvas(const SkImageInfo& info) {
2520 switch (info.alphaType()) {
2521 case kPremul_SkAlphaType:
2522 case kOpaque_SkAlphaType:
2528 switch (info.colorType()) {
2529 case kAlpha_8_SkColorType:
2530 case kRGB_565_SkColorType:
2531 case kN32_SkColorType:
2540 SkCanvas* SkCanvas::NewRaster(const SkImageInfo& info) {
2541 if (!supported_for_raster_canvas(info)) {
2546 if (!bitmap.tryAllocPixels(info)) {
2550 // should this functionality be moved into allocPixels()?
2551 if (!bitmap.info().isOpaque()) {
2552 bitmap.eraseColor(0);
2554 return SkNEW_ARGS(SkCanvas, (bitmap));
2557 SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2558 if (!supported_for_raster_canvas(info)) {
2563 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2566 return SkNEW_ARGS(SkCanvas, (bitmap));
2569 ///////////////////////////////////////////////////////////////////////////////
2571 SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
2572 const SkPaint* paint, const SkRect& bounds)
2574 , fSaveCount(canvas->getSaveCount())
2577 SkRect newBounds = bounds;
2579 matrix->mapRect(&newBounds);
2581 canvas->saveLayer(&newBounds, paint);
2582 } else if (matrix) {
2587 canvas->concat(*matrix);
2591 SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2592 fCanvas->restoreToCount(fSaveCount);