Implement support for non-scale/translate CTM in image filters.

Implemented by extracting out the non-scale/translate components
and applying that post-filter as an SkMatrixImageFilter.

BUG=skia:

Review URL: https://codereview.chromium.org/1120043002
This commit is contained in:
reed 2015-05-13 13:34:57 -07:00 committed by Commit bot
parent 231c5fd590
commit 4f12b8bd2c
2 changed files with 35 additions and 7 deletions

View File

@ -1261,7 +1261,7 @@ private:
enum {
kMCRecSize = 128, // most recent measurement
kMCRecCount = 8, // common depth for save/restores
kDeviceCMSize = 136, // most recent measurement
kDeviceCMSize = 176, // most recent measurement
};
intptr_t fMCRecStorage[kMCRecSize * kMCRecCount / sizeof(intptr_t)];
intptr_t fDeviceCMStorage[kDeviceCMSize / sizeof(intptr_t)];
@ -1285,6 +1285,7 @@ private:
void doSave();
void checkForDeferredSave();
void internalSetMatrix(const SkMatrix& matrix);
friend class SkDrawIter; // needs setupDrawForLayerDevice()
friend class AutoDrawLooper;

View File

@ -115,12 +115,14 @@ struct DeviceCM {
SkPaint* fPaint; // may be null (in the future)
const SkMatrix* fMatrix;
SkMatrix fMatrixStorage;
SkMatrix fStashedMatrix; // Original CTM; used by imageFilter at saveLayer time
const bool fDeviceIsBitmapDevice;
DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
bool conservativeRasterClip, bool deviceIsBitmapDevice)
bool conservativeRasterClip, bool deviceIsBitmapDevice, const SkMatrix& stashed)
: fNext(NULL)
, fClip(conservativeRasterClip)
, fStashedMatrix(stashed)
, fDeviceIsBitmapDevice(deviceIsBitmapDevice)
{
if (NULL != device) {
@ -528,7 +530,8 @@ SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
new (fDeviceCMStorage) DeviceCM(NULL, NULL, NULL, fConservativeRasterClip, false);
new (fDeviceCMStorage) DeviceCM(NULL, NULL, NULL, fConservativeRasterClip, false,
fMCRec->fMatrix);
fMCRec->fTopLayer = fMCRec->fLayer;
@ -991,6 +994,22 @@ void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Sav
#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
flags |= kClipToLayer_SaveFlag;
#endif
SkLazyPaint lazyP;
SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
SkMatrix stashedMatrix = fMCRec->fMatrix;
SkMatrix remainder;
SkSize scale;
if (imageFilter &&
!stashedMatrix.isScaleTranslate() && stashedMatrix.decomposeScale(&scale, &remainder)) {
// We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
SkAutoTUnref<SkImageFilter> matrixFilter(SkImageFilter::CreateMatrixFilter(
remainder, SkFilterQuality::kLow_SkFilterQuality, imageFilter));
imageFilter = matrixFilter.get();
SkPaint* p = lazyP.set(*paint);
p->setImageFilter(imageFilter);
paint = p;
}
// do this before we create the layer. We don't call the public save() since
// that would invoke a possibly overridden virtual
@ -999,7 +1018,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)) {
return;
}
@ -1047,7 +1066,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,
forceSpriteOnRestore));
forceSpriteOnRestore, stashedMatrix));
device->unref();
layer->fNext = fMCRec->fTopLayer;
@ -1105,6 +1124,10 @@ void SkCanvas::internalRestore() {
SkASSERT(layer == (void*)fDeviceCMStorage);
layer->~DeviceCM();
}
if (fMCRec) {
// restore what we smashed in internalSaveLayer
fMCRec->fMatrix = layer->fStashedMatrix;
}
}
}
@ -1332,11 +1355,15 @@ void SkCanvas::concat(const SkMatrix& matrix) {
this->didConcat(matrix);
}
void SkCanvas::setMatrix(const SkMatrix& matrix) {
this->checkForDeferredSave();
void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
fDeviceCMDirty = true;
fCachedLocalClipBoundsDirty = true;
fMCRec->fMatrix = matrix;
}
void SkCanvas::setMatrix(const SkMatrix& matrix) {
this->checkForDeferredSave();
this->internalSetMatrix(matrix);
this->didSetMatrix(matrix);
}