Index: src/core/SkCanvas.cpp |
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp |
index 11dc739f4c4dc6aa0509f8ba404a56fa246817e4..f9eb0ebbfef45e2823a9bb91443fa18b60fcd5e3 100644 |
--- a/src/core/SkCanvas.cpp |
+++ b/src/core/SkCanvas.cpp |
@@ -113,11 +113,16 @@ struct DeviceCM { |
SkRasterClip fClip; |
const SkMatrix* fMatrix; |
SkPaint* fPaint; // may be null (in the future) |
+ SkMatrix fStashedMatrix; |
+ SkMatrix fExtraMatrix; |
DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas, |
- bool conservativeRasterClip) |
+ bool conservativeRasterClip, const SkMatrix& stashedMatrix, |
+ const SkMatrix& extraMatrix) |
: fNext(NULL) |
, fClip(conservativeRasterClip) |
+ , fStashedMatrix(stashedMatrix) |
+ , fExtraMatrix(extraMatrix) |
{ |
if (NULL != device) { |
device->ref(); |
@@ -438,7 +443,7 @@ SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) { |
fMCRec = (MCRec*)fMCStack.push_back(); |
new (fMCRec) MCRec(fConservativeRasterClip); |
- fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, NULL, NULL, fConservativeRasterClip)); |
+ fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, NULL, NULL, fConservativeRasterClip, fMCRec->fMatrix, SkMatrix::I())); |
fMCRec->fTopLayer = fMCRec->fLayer; |
fSurfaceBase = NULL; |
@@ -831,7 +836,8 @@ static bool bounds_affects_clip(SkCanvas::SaveFlags flags) { |
} |
bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, |
- SkIRect* intersection, const SkImageFilter* imageFilter) { |
+ SkIRect* intersection, const SkImageFilter* imageFilter, |
+ const SkMatrix* shearAndRotateMatrix) { |
SkIRect clipBounds; |
if (!this->getClipDeviceBounds(&clipBounds)) { |
return false; |
@@ -840,8 +846,24 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, |
const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix() |
if (imageFilter) { |
+ if (shearAndRotateMatrix) { |
+ SkMatrix shearAndRotateInverse; |
+ if (!shearAndRotateMatrix->invert(&shearAndRotateInverse)) { |
+ return false; |
+ } |
+ SkMatrix matrix; |
+ if (!ctm.invert(&matrix)) { |
+ return false; |
+ } |
+ matrix.postConcat(shearAndRotateInverse); |
+ matrix.postConcat(ctm); |
+ SkRect floatBounds; |
+ matrix.mapRect(&floatBounds, SkRect::Make(clipBounds)); |
+ clipBounds = floatBounds.roundOut(); |
+ } |
imageFilter->filterBounds(clipBounds, ctm, &clipBounds); |
} |
+ |
SkIRect ir; |
if (bounds) { |
SkRect r; |
@@ -899,6 +921,23 @@ void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Sav |
#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG |
flags |= kClipToLayer_SaveFlag; |
#endif |
+ SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL; |
+ SkMatrix matrix = fMCRec->fMatrix; |
+ SkMatrix shearAndRotate = SkMatrix::I(); |
+ bool doShearAndRotate = false; |
+ if (imageFilter && !matrix.isScaleTranslate()) { |
+ doShearAndRotate = true; |
+ SkMatrix scaleAndTranslate; |
+ scaleAndTranslate.setTranslate(matrix.getTranslateX(), matrix.getTranslateY()); |
+ SkScalar xScale = SkScalarSqrt(matrix[0] * matrix[0] + matrix[3] * matrix[3]); |
+ SkScalar yScale = SkScalarSqrt(matrix[1] * matrix[1] + matrix[4] * matrix[4]); |
+ scaleAndTranslate.postScale(xScale, yScale); |
+ if (!scaleAndTranslate.invert(&shearAndRotate)) { |
+ SkASSERT(false); |
+ } |
+ shearAndRotate.preConcat(matrix); |
+ fMCRec->fMatrix = scaleAndTranslate; |
+ } |
// do this before we create the layer. We don't call the public save() since |
// that would invoke a possibly overridden virtual |
@@ -907,7 +946,7 @@ void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Sav |
fDeviceCMDirty = true; |
SkIRect ir; |
- if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) { |
+ if (!this->clipRectBounds(bounds, flags, &ir, imageFilter, doShearAndRotate ? &shearAndRotate : NULL)) { |
return; |
} |
@@ -951,7 +990,7 @@ void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Sav |
} |
device->setOrigin(ir.fLeft, ir.fTop); |
- DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip)); |
+ DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip, matrix, shearAndRotate)); |
device->unref(); |
layer->fNext = fMCRec->fTopLayer; |
@@ -1000,10 +1039,13 @@ void SkCanvas::internalRestore() { |
if (layer->fNext) { |
const SkIPoint& origin = layer->fDevice->getOrigin(); |
this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), |
- layer->fPaint); |
+ layer->fPaint, layer->fExtraMatrix); |
// reset this, since internalDrawDevice will have set it to true |
fDeviceCMDirty = true; |
} |
+ if (layer->fPaint && layer->fPaint->fImageFilter) { |
+ fMCRec->fMatrix = layer->fStashedMatrix; |
+ } |
SkDELETE(layer); |
} |
} |
@@ -1108,7 +1150,7 @@ void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, |
} |
void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, |
- const SkPaint* paint) { |
+ const SkPaint* paint, const SkMatrix& extraMatrix) { |
SkPaint tmp; |
if (NULL == paint) { |
paint = &tmp; |
@@ -1133,8 +1175,16 @@ void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, |
if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) { |
SkPaint tmpUnfiltered(*paint); |
tmpUnfiltered.setImageFilter(NULL); |
- dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(), |
- tmpUnfiltered); |
+ if (extraMatrix.isIdentity()) { |
+ offset += pos; |
+ dstDev->drawSprite(iter, dst, offset.x(), offset.y(), |
+ tmpUnfiltered); |
+ } else { |
+ SkMatrix matrix = extraMatrix; |
+ matrix.preTranslate(offset.x(), offset.y()); |
+ dstDev->drawBitmap(iter, dst, matrix, |
+ tmpUnfiltered); |
+ } |
} |
} else { |
dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint); |