Apply the CTM to filter parameters for SkBlurImageFilter, SkDropShadowImageFilter, SkDisplacementMapEffect and SkMorphologyImageFilter. I had resisted this (and may later put in an assert that the CTM contains no rotation, skew or perspective), but it just makes the filters play better with Skia generally.
This revealed that the displacement map was not handling clipping or upstream cropping at all well (the color would "swim" through the displacement at the edge of the clip rect). Fixed by passing through the correct offsets to the bitmap accesses in both raster and GPU paths. Same for morphology.
R=sugoi@google.com
Review URL: https://codereview.chromium.org/137053003
git-svn-id: http://skia.googlecode.com/svn/trunk@13127 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp
index e9a9acb..8264ec8 100644
--- a/src/effects/SkDisplacementMapEffect.cpp
+++ b/src/effects/SkDisplacementMapEffect.cpp
@@ -47,22 +47,28 @@
template<SkDisplacementMapEffect::ChannelSelectorType typeX,
SkDisplacementMapEffect::ChannelSelectorType typeY>
-void computeDisplacement(SkScalar scale, SkBitmap* dst, SkBitmap* displ, SkBitmap* src, const SkIRect& bounds)
+void computeDisplacement(const SkVector& scale, SkBitmap* dst,
+ SkBitmap* displ, const SkIPoint& offset,
+ SkBitmap* src,
+ const SkIRect& bounds)
{
static const SkScalar Inv8bit = SkScalarDiv(SK_Scalar1, 255.0f);
const int srcW = src->width();
const int srcH = src->height();
- const SkScalar scaleForColor = SkScalarMul(scale, Inv8bit);
- const SkScalar scaleAdj = SK_ScalarHalf - SkScalarMul(scale, SK_ScalarHalf);
+ const SkVector scaleForColor = SkVector::Make(SkScalarMul(scale.fX, Inv8bit),
+ SkScalarMul(scale.fY, Inv8bit));
+ const SkVector scaleAdj = SkVector::Make(SK_ScalarHalf - SkScalarMul(scale.fX, SK_ScalarHalf),
+ SK_ScalarHalf - SkScalarMul(scale.fY, SK_ScalarHalf));
const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
SkPMColor* dstPtr = dst->getAddr32(0, 0);
for (int y = bounds.top(); y < bounds.bottom(); ++y) {
- const SkPMColor* displPtr = displ->getAddr32(bounds.left(), y);
+ const SkPMColor* displPtr = displ->getAddr32(bounds.left() + offset.fX,
+ y + offset.fY);
for (int x = bounds.left(); x < bounds.right(); ++x, ++displPtr) {
- const SkScalar displX = SkScalarMul(scaleForColor,
- SkIntToScalar(getValue<typeX>(*displPtr, table))) + scaleAdj;
- const SkScalar displY = SkScalarMul(scaleForColor,
- SkIntToScalar(getValue<typeY>(*displPtr, table))) + scaleAdj;
+ const SkScalar displX = SkScalarMul(scaleForColor.fX,
+ SkIntToScalar(getValue<typeX>(*displPtr, table))) + scaleAdj.fX;
+ const SkScalar displY = SkScalarMul(scaleForColor.fY,
+ SkIntToScalar(getValue<typeY>(*displPtr, table))) + scaleAdj.fY;
// Truncate the displacement values
const int srcX = x + SkScalarTruncToInt(displX);
const int srcY = y + SkScalarTruncToInt(displY);
@@ -74,24 +80,27 @@
template<SkDisplacementMapEffect::ChannelSelectorType typeX>
void computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
- SkScalar scale, SkBitmap* dst, SkBitmap* displ, SkBitmap* src, const SkIRect& bounds)
+ const SkVector& scale, SkBitmap* dst,
+ SkBitmap* displ, const SkIPoint& offset,
+ SkBitmap* src,
+ const SkIRect& bounds)
{
switch (yChannelSelector) {
case SkDisplacementMapEffect::kR_ChannelSelectorType:
computeDisplacement<typeX, SkDisplacementMapEffect::kR_ChannelSelectorType>(
- scale, dst, displ, src, bounds);
+ scale, dst, displ, offset, src, bounds);
break;
case SkDisplacementMapEffect::kG_ChannelSelectorType:
computeDisplacement<typeX, SkDisplacementMapEffect::kG_ChannelSelectorType>(
- scale, dst, displ, src, bounds);
+ scale, dst, displ, offset, src, bounds);
break;
case SkDisplacementMapEffect::kB_ChannelSelectorType:
computeDisplacement<typeX, SkDisplacementMapEffect::kB_ChannelSelectorType>(
- scale, dst, displ, src, bounds);
+ scale, dst, displ, offset, src, bounds);
break;
case SkDisplacementMapEffect::kA_ChannelSelectorType:
computeDisplacement<typeX, SkDisplacementMapEffect::kA_ChannelSelectorType>(
- scale, dst, displ, src, bounds);
+ scale, dst, displ, offset, src, bounds);
break;
case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
default:
@@ -101,24 +110,27 @@
void computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
- SkScalar scale, SkBitmap* dst, SkBitmap* displ, SkBitmap* src, const SkIRect& bounds)
+ const SkVector& scale, SkBitmap* dst,
+ SkBitmap* displ, const SkIPoint& offset,
+ SkBitmap* src,
+ const SkIRect& bounds)
{
switch (xChannelSelector) {
case SkDisplacementMapEffect::kR_ChannelSelectorType:
computeDisplacement<SkDisplacementMapEffect::kR_ChannelSelectorType>(
- yChannelSelector, scale, dst, displ, src, bounds);
+ yChannelSelector, scale, dst, displ, offset, src, bounds);
break;
case SkDisplacementMapEffect::kG_ChannelSelectorType:
computeDisplacement<SkDisplacementMapEffect::kG_ChannelSelectorType>(
- yChannelSelector, scale, dst, displ, src, bounds);
+ yChannelSelector, scale, dst, displ, offset, src, bounds);
break;
case SkDisplacementMapEffect::kB_ChannelSelectorType:
computeDisplacement<SkDisplacementMapEffect::kB_ChannelSelectorType>(
- yChannelSelector, scale, dst, displ, src, bounds);
+ yChannelSelector, scale, dst, displ, offset, src, bounds);
break;
case SkDisplacementMapEffect::kA_ChannelSelectorType:
computeDisplacement<SkDisplacementMapEffect::kA_ChannelSelectorType>(
- yChannelSelector, scale, dst, displ, src, bounds);
+ yChannelSelector, scale, dst, displ, offset, src, bounds);
break;
case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
default:
@@ -185,9 +197,10 @@
SkIPoint* offset) {
SkBitmap displ = src, color = src;
SkImageFilter* colorInput = getColorInput();
- SkImageFilter* displacementInput = getDisplacementInput();
- if ((colorInput && !colorInput->filterImage(proxy, src, ctm, &color, offset)) ||
- (displacementInput && !displacementInput->filterImage(proxy, src, ctm, &displ, offset))) {
+ SkImageFilter* displInput = getDisplacementInput();
+ SkIPoint colorOffset = SkIPoint::Make(0, 0), displOffset = SkIPoint::Make(0, 0);
+ if ((colorInput && !colorInput->filterImage(proxy, src, ctm, &color, &colorOffset)) ||
+ (displInput && !displInput->filterImage(proxy, src, ctm, &displ, &displOffset))) {
return false;
}
if ((displ.config() != SkBitmap::kARGB_8888_Config) ||
@@ -201,11 +214,13 @@
}
SkIRect bounds;
color.getBounds(&bounds);
+ bounds.offset(colorOffset);
if (!this->applyCropRect(&bounds, ctm)) {
return false;
}
SkIRect displBounds;
displ.getBounds(&displBounds);
+ displBounds.offset(displOffset);
if (!this->applyCropRect(&displBounds, ctm)) {
return false;
}
@@ -219,7 +234,13 @@
return false;
}
- computeDisplacement(fXChannelSelector, fYChannelSelector, fScale, dst, &displ, &color, bounds);
+ SkVector scale = SkVector::Make(fScale, fScale);
+ ctm.mapVectors(&scale, 1);
+ SkIRect colorBounds = bounds;
+ colorBounds.offset(-colorOffset);
+
+ computeDisplacement(fXChannelSelector, fYChannelSelector, scale, dst,
+ &displ, colorOffset - displOffset, &color, colorBounds);
offset->fX = bounds.left();
offset->fY = bounds.top();
@@ -261,11 +282,14 @@
public:
static GrEffectRef* Create(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
- SkScalar scale, GrTexture* displacement, GrTexture* color) {
+ SkVector scale,
+ GrTexture* displacement, const SkMatrix& offsetMatrix,
+ GrTexture* color) {
AutoEffectUnref effect(SkNEW_ARGS(GrDisplacementMapEffect, (xChannelSelector,
yChannelSelector,
scale,
displacement,
+ offsetMatrix,
color)));
return CreateEffectRef(effect);
}
@@ -277,7 +301,7 @@
{ return fXChannelSelector; }
SkDisplacementMapEffect::ChannelSelectorType yChannelSelector() const
{ return fYChannelSelector; }
- SkScalar scale() const { return fScale; }
+ const SkVector& scale() const { return fScale; }
typedef GrGLDisplacementMapEffect GLEffect;
static const char* Name() { return "DisplacementMap"; }
@@ -289,7 +313,9 @@
GrDisplacementMapEffect(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
- SkScalar scale, GrTexture* displacement, GrTexture* color);
+ const SkVector& scale,
+ GrTexture* displacement, const SkMatrix& offsetMatrix,
+ GrTexture* color);
GR_DECLARE_EFFECT_TEST;
@@ -299,7 +325,7 @@
GrTextureAccess fColorAccess;
SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
- SkScalar fScale;
+ SkVector fScale;
typedef GrEffect INHERITED;
};
@@ -324,8 +350,8 @@
GrTextureDesc desc;
desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
- desc.fWidth = src.width();
- desc.fHeight = src.height();
+ desc.fWidth = colorBM.width();
+ desc.fHeight = colorBM.height();
desc.fConfig = kSkia8888_GrPixelConfig;
GrAutoScratchTexture ast(context, desc);
@@ -333,29 +359,43 @@
GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
- GrPaint paint;
- paint.addColorEffect(
- GrDisplacementMapEffect::Create(fXChannelSelector,
- fYChannelSelector,
- fScale,
- displacement,
- color))->unref();
+ SkVector scale = SkVector::Make(fScale, fScale);
+ ctm.mapVectors(&scale, 1);
SkIRect bounds;
- src.getBounds(&bounds);
+ colorBM.getBounds(&bounds);
+ bounds.offset(colorOffset);
if (!this->applyCropRect(&bounds, ctm)) {
return false;
}
SkIRect displBounds;
displacementBM.getBounds(&displBounds);
+ displBounds.offset(displacementOffset);
if (!this->applyCropRect(&displBounds, ctm)) {
return false;
}
if (!bounds.intersect(displBounds)) {
return false;
}
- SkRect srcRect = SkRect::Make(bounds);
- SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
- context->drawRectToRect(paint, dstRect, srcRect);
+
+ GrPaint paint;
+ SkMatrix offsetMatrix = GrEffect::MakeDivByTextureWHMatrix(displacement);
+ offsetMatrix.preTranslate(SkIntToScalar(colorOffset.fX - displacementOffset.fX),
+ SkIntToScalar(colorOffset.fY - displacementOffset.fY));
+
+ paint.addColorEffect(
+ GrDisplacementMapEffect::Create(fXChannelSelector,
+ fYChannelSelector,
+ scale,
+ displacement,
+ offsetMatrix,
+ color))->unref();
+ SkIRect colorBounds = bounds;
+ colorBounds.offset(-colorOffset);
+ SkMatrix matrix;
+ matrix.setTranslate(-SkIntToScalar(colorBounds.x()),
+ -SkIntToScalar(colorBounds.y()));
+ context->concatMatrix(matrix);
+ context->drawRect(paint, SkRect::Make(colorBounds));
offset->fX = bounds.left();
offset->fY = bounds.top();
return SkImageFilterUtils::WrapTexture(dst, bounds.width(), bounds.height(), result);
@@ -366,10 +406,11 @@
GrDisplacementMapEffect::GrDisplacementMapEffect(
SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
- SkScalar scale,
+ const SkVector& scale,
GrTexture* displacement,
+ const SkMatrix& offsetMatrix,
GrTexture* color)
- : fDisplacementTransform(kLocal_GrCoordSet, displacement)
+ : fDisplacementTransform(kLocal_GrCoordSet, offsetMatrix, displacement)
, fDisplacementAccess(displacement)
, fColorTransform(kLocal_GrCoordSet, color)
, fColorAccess(color)
@@ -428,10 +469,12 @@
SkDisplacementMapEffect::ChannelSelectorType yChannelSelector =
static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
random->nextRangeU(1, kMaxComponent));
- SkScalar scale = random->nextRangeScalar(0, 100.0f);
+ SkVector scale = SkVector::Make(random->nextRangeScalar(0, 100.0f),
+ random->nextRangeScalar(0, 100.0f));
return GrDisplacementMapEffect::Create(xChannelSelector, yChannelSelector, scale,
- textures[texIdxDispl], textures[texIdxColor]);
+ textures[texIdxDispl], SkMatrix::I(),
+ textures[texIdxColor]);
}
///////////////////////////////////////////////////////////////////////////////
@@ -528,8 +571,8 @@
const GrDisplacementMapEffect& displacementMap =
drawEffect.castEffect<GrDisplacementMapEffect>();
GrTexture* colorTex = displacementMap.texture(1);
- SkScalar scaleX = SkScalarDiv(displacementMap.scale(), SkIntToScalar(colorTex->width()));
- SkScalar scaleY = SkScalarDiv(displacementMap.scale(), SkIntToScalar(colorTex->height()));
+ SkScalar scaleX = SkScalarDiv(displacementMap.scale().fX, SkIntToScalar(colorTex->width()));
+ SkScalar scaleY = SkScalarDiv(displacementMap.scale().fY, SkIntToScalar(colorTex->height()));
uman.set2f(fScaleUni, SkScalarToFloat(scaleX),
colorTex->origin() == kTopLeft_GrSurfaceOrigin ?
SkScalarToFloat(scaleY) : SkScalarToFloat(-scaleY));