This patch implements a crop rect for SkImageFilter. It has been implemented for SkColorFilterImageFilter and SkBlurImageFilter as examples.
In order to preserve the immutability of SkImageFilters, the crop rect is passed as a constructor parameter. If NULL (the default), the bounds of the input image are used, as before.
This also tightens up the boundary handling for SkImageBlurFilter on the GPU backend. Where we were previously using clamping semantics, we now respect decal semantics (so we don't oversaturate the edges). This brings the GPU and raster backends into closer alignment, but will require some new baselines for the GPU tests.
At a minimum, the following tests will need new baselines: imageblur, imagefiltersbase, imagefilterscropped, spritebitmap.
R=reed@google.com
Review URL: https://codereview.chromium.org/19775006
git-svn-id: http://skia.googlecode.com/svn/trunk@10251 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
index ddd6449..ff060a1 100644
--- a/src/core/SkImageFilter.cpp
+++ b/src/core/SkImageFilter.cpp
@@ -18,22 +18,27 @@
SK_DEFINE_INST_COUNT(SkImageFilter)
-SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs)
- : fInputCount(inputCount), fInputs(new SkImageFilter*[inputCount]) {
+SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const SkIRect* cropRect)
+ : fInputCount(inputCount),
+ fInputs(new SkImageFilter*[inputCount]),
+ fCropRect(cropRect ? *cropRect : SkIRect::MakeLargest()) {
for (int i = 0; i < inputCount; ++i) {
fInputs[i] = inputs[i];
SkSafeRef(fInputs[i]);
}
}
-SkImageFilter::SkImageFilter(SkImageFilter* input)
- : fInputCount(1), fInputs(new SkImageFilter*[1]) {
+SkImageFilter::SkImageFilter(SkImageFilter* input, const SkIRect* cropRect)
+ : fInputCount(1),
+ fInputs(new SkImageFilter*[1]),
+ fCropRect(cropRect ? *cropRect : SkIRect::MakeLargest()) {
fInputs[0] = input;
SkSafeRef(fInputs[0]);
}
-SkImageFilter::SkImageFilter(SkImageFilter* input1, SkImageFilter* input2)
- : fInputCount(2), fInputs(new SkImageFilter*[2]) {
+SkImageFilter::SkImageFilter(SkImageFilter* input1, SkImageFilter* input2, const SkIRect* cropRect)
+ : fInputCount(2), fInputs(new SkImageFilter*[2]),
+ fCropRect(cropRect ? *cropRect : SkIRect::MakeLargest()) {
fInputs[0] = input1;
fInputs[1] = input2;
SkSafeRef(fInputs[0]);
@@ -56,6 +61,7 @@
fInputs[i] = NULL;
}
}
+ buffer.readIRect(&fCropRect);
}
void SkImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
@@ -67,6 +73,7 @@
buffer.writeFlattenable(input);
}
}
+ buffer.writeIRect(fCropRect);
}
bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
@@ -137,6 +144,10 @@
#endif
}
+bool SkImageFilter::applyCropRect(SkIRect* rect) const {
+ return rect->intersect(fCropRect);
+}
+
bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
SkIRect* dst) {
*dst = src;
diff --git a/src/effects/SkBlurImageFilter.cpp b/src/effects/SkBlurImageFilter.cpp
index 157a0c3..0f0c809 100644
--- a/src/effects/SkBlurImageFilter.cpp
+++ b/src/effects/SkBlurImageFilter.cpp
@@ -21,8 +21,11 @@
fSigma.fHeight = buffer.readScalar();
}
-SkBlurImageFilter::SkBlurImageFilter(SkScalar sigmaX, SkScalar sigmaY, SkImageFilter* input)
- : INHERITED(input), fSigma(SkSize::Make(sigmaX, sigmaY)) {
+SkBlurImageFilter::SkBlurImageFilter(SkScalar sigmaX,
+ SkScalar sigmaY,
+ SkImageFilter* input,
+ const SkIRect* cropRect)
+ : INHERITED(input, cropRect), fSigma(SkSize::Make(sigmaX, sigmaY)) {
SkASSERT(sigmaX >= 0 && sigmaY >= 0);
}
@@ -33,13 +36,13 @@
}
static void boxBlurX(const SkBitmap& src, SkBitmap* dst, int kernelSize,
- int leftOffset, int rightOffset)
+ int leftOffset, int rightOffset, const SkIRect& bounds)
{
- int width = src.width(), height = src.height();
+ int width = bounds.width(), height = bounds.height();
int rightBorder = SkMin32(rightOffset + 1, width);
for (int y = 0; y < height; ++y) {
int sumA = 0, sumR = 0, sumG = 0, sumB = 0;
- SkPMColor* p = src.getAddr32(0, y);
+ SkPMColor* p = src.getAddr32(bounds.fLeft, y + bounds.fTop);
for (int i = 0; i < rightBorder; ++i) {
sumA += SkGetPackedA32(*p);
sumR += SkGetPackedR32(*p);
@@ -48,7 +51,7 @@
p++;
}
- const SkColor* sptr = src.getAddr32(0, y);
+ const SkColor* sptr = src.getAddr32(bounds.fLeft, bounds.fTop + y);
SkColor* dptr = dst->getAddr32(0, y);
for (int x = 0; x < width; ++x) {
*dptr = SkPackARGB32(sumA / kernelSize,
@@ -76,15 +79,15 @@
}
static void boxBlurY(const SkBitmap& src, SkBitmap* dst, int kernelSize,
- int topOffset, int bottomOffset)
+ int topOffset, int bottomOffset, const SkIRect& bounds)
{
- int width = src.width(), height = src.height();
+ int width = bounds.width(), height = bounds.height();
int bottomBorder = SkMin32(bottomOffset + 1, height);
int srcStride = src.rowBytesAsPixels();
int dstStride = dst->rowBytesAsPixels();
for (int x = 0; x < width; ++x) {
int sumA = 0, sumR = 0, sumG = 0, sumB = 0;
- SkColor* p = src.getAddr32(x, 0);
+ SkColor* p = src.getAddr32(bounds.fLeft + x, bounds.fTop);
for (int i = 0; i < bottomBorder; ++i) {
sumA += SkGetPackedA32(*p);
sumR += SkGetPackedR32(*p);
@@ -93,7 +96,7 @@
p += srcStride;
}
- const SkColor* sptr = src.getAddr32(x, 0);
+ const SkColor* sptr = src.getAddr32(bounds.fLeft + x, bounds.fTop);
SkColor* dptr = dst->getAddr32(x, 0);
for (int y = 0; y < height; ++y) {
*dptr = SkPackARGB32(sumA / kernelSize,
@@ -153,7 +156,14 @@
return false;
}
- dst->setConfig(src.config(), src.width(), src.height());
+ SkIRect srcBounds, dstBounds;
+ src.getBounds(&srcBounds);
+ if (!this->applyCropRect(&srcBounds)) {
+ return false;
+ }
+
+ dst->setConfig(src.config(), srcBounds.width(), srcBounds.height());
+ dst->getBounds(&dstBounds);
dst->allocPixels();
int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX;
int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY;
@@ -176,21 +186,23 @@
}
if (kernelSizeX > 0 && kernelSizeY > 0) {
- boxBlurX(src, &temp, kernelSizeX, lowOffsetX, highOffsetX);
- boxBlurY(temp, dst, kernelSizeY, lowOffsetY, highOffsetY);
- boxBlurX(*dst, &temp, kernelSizeX, highOffsetX, lowOffsetX);
- boxBlurY(temp, dst, kernelSizeY, highOffsetY, lowOffsetY);
- boxBlurX(*dst, &temp, kernelSizeX3, highOffsetX, highOffsetX);
- boxBlurY(temp, dst, kernelSizeY3, highOffsetY, highOffsetY);
+ boxBlurX(src, &temp, kernelSizeX, lowOffsetX, highOffsetX, srcBounds);
+ boxBlurY(temp, dst, kernelSizeY, lowOffsetY, highOffsetY, dstBounds);
+ boxBlurX(*dst, &temp, kernelSizeX, highOffsetX, lowOffsetX, dstBounds);
+ boxBlurY(temp, dst, kernelSizeY, highOffsetY, lowOffsetY, dstBounds);
+ boxBlurX(*dst, &temp, kernelSizeX3, highOffsetX, highOffsetX, dstBounds);
+ boxBlurY(temp, dst, kernelSizeY3, highOffsetY, highOffsetY, dstBounds);
} else if (kernelSizeX > 0) {
- boxBlurX(src, dst, kernelSizeX, lowOffsetX, highOffsetX);
- boxBlurX(*dst, &temp, kernelSizeX, highOffsetX, lowOffsetX);
- boxBlurX(temp, dst, kernelSizeX3, highOffsetX, highOffsetX);
+ boxBlurX(src, dst, kernelSizeX, lowOffsetX, highOffsetX, srcBounds);
+ boxBlurX(*dst, &temp, kernelSizeX, highOffsetX, lowOffsetX, dstBounds);
+ boxBlurX(temp, dst, kernelSizeX3, highOffsetX, highOffsetX, dstBounds);
} else if (kernelSizeY > 0) {
- boxBlurY(src, dst, kernelSizeY, lowOffsetY, highOffsetY);
- boxBlurY(*dst, &temp, kernelSizeY, highOffsetY, lowOffsetY);
- boxBlurY(temp, dst, kernelSizeY3, highOffsetY, highOffsetY);
+ boxBlurY(src, dst, kernelSizeY, lowOffsetY, highOffsetY, srcBounds);
+ boxBlurY(*dst, &temp, kernelSizeY, highOffsetY, lowOffsetY, dstBounds);
+ boxBlurY(temp, dst, kernelSizeY3, highOffsetY, highOffsetY, dstBounds);
}
+ offset->fX += srcBounds.fLeft;
+ offset->fY += srcBounds.fTop;
return true;
}
@@ -202,12 +214,17 @@
return false;
}
GrTexture* source = input.getTexture();
- SkRect rect;
+ SkIRect rect;
src.getBounds(&rect);
- SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(source->getContext(),
- source, false, rect,
+ if (!this->applyCropRect(&rect)) {
+ return false;
+ }
+ SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(source->getContext(),
+ source, false, SkRect::Make(rect),
fSigma.width(), fSigma.height()));
- return SkImageFilterUtils::WrapTexture(tex, src.width(), src.height(), result);
+ offset->fX += rect.fLeft;
+ offset->fY += rect.fTop;
+ return SkImageFilterUtils::WrapTexture(tex, rect.width(), rect.height(), result);
#else
SkDEBUGFAIL("Should not call in GPU-less build");
return false;
diff --git a/src/effects/SkColorFilterImageFilter.cpp b/src/effects/SkColorFilterImageFilter.cpp
index 1d3cfee..a24934e 100755
--- a/src/effects/SkColorFilterImageFilter.cpp
+++ b/src/effects/SkColorFilterImageFilter.cpp
@@ -57,7 +57,7 @@
};
SkColorFilterImageFilter* SkColorFilterImageFilter::Create(SkColorFilter* cf,
- SkImageFilter* input) {
+ SkImageFilter* input, const SkIRect* cropRect) {
SkASSERT(cf);
SkScalar colorMatrix[20], inputMatrix[20];
SkColorFilter* inputColorFilter;
@@ -69,13 +69,15 @@
SkScalar combinedMatrix[20];
mult_color_matrix(inputMatrix, colorMatrix, combinedMatrix);
SkAutoTUnref<SkColorFilter> newCF(SkNEW_ARGS(SkColorMatrixFilter, (combinedMatrix)));
- return SkNEW_ARGS(SkColorFilterImageFilter, (newCF, input->getInput(0)));
+ return SkNEW_ARGS(SkColorFilterImageFilter, (newCF, input->getInput(0), cropRect));
}
}
- return SkNEW_ARGS(SkColorFilterImageFilter, (cf, input));
+ return SkNEW_ARGS(SkColorFilterImageFilter, (cf, input, cropRect));
}
-SkColorFilterImageFilter::SkColorFilterImageFilter(SkColorFilter* cf, SkImageFilter* input) : INHERITED(input), fColorFilter(cf) {
+SkColorFilterImageFilter::SkColorFilterImageFilter(SkColorFilter* cf,
+ SkImageFilter* input, const SkIRect* cropRect)
+ : INHERITED(input, cropRect), fColorFilter(cf) {
SkASSERT(cf);
SkSafeRef(cf);
}
@@ -103,22 +105,31 @@
return false;
}
- SkAutoTUnref<SkDevice> device(proxy->createDevice(src.width(), src.height()));
+ SkIRect bounds;
+ src.getBounds(&bounds);
+ if (!this->applyCropRect(&bounds)) {
+ return false;
+ }
+
+ SkAutoTUnref<SkDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
SkCanvas canvas(device.get());
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
paint.setColorFilter(fColorFilter);
- canvas.drawSprite(src, 0, 0, &paint);
+ canvas.drawSprite(src, -bounds.fLeft, -bounds.fTop, &paint);
*result = device.get()->accessBitmap(false);
+ loc->fX += bounds.fLeft;
+ loc->fY += bounds.fTop;
return true;
}
bool SkColorFilterImageFilter::asColorFilter(SkColorFilter** filter) const {
- if (filter) {
+ if (filter && cropRect().isLargest()) {
*filter = fColorFilter;
fColorFilter->ref();
+ return true;
}
- return true;
+ return false;
}
diff --git a/src/effects/SkGpuBlurUtils.cpp b/src/effects/SkGpuBlurUtils.cpp
index 4796488..5b52ad3 100644
--- a/src/effects/SkGpuBlurUtils.cpp
+++ b/src/effects/SkGpuBlurUtils.cpp
@@ -11,6 +11,7 @@
#if SK_SUPPORT_GPU
#include "effects/GrConvolutionEffect.h"
+#include "effects/GrTextureDomainEffect.h"
#include "GrContext.h"
#endif
@@ -40,18 +41,29 @@
static void convolve_gaussian(GrContext* context,
GrTexture* texture,
- const SkRect& rect,
+ const SkRect& srcRect,
+ const SkRect& dstRect,
float sigma,
int radius,
Gr1DKernelEffect::Direction direction) {
GrPaint paint;
+ paint.reset();
+ float cropRect[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
+ if (direction == Gr1DKernelEffect::kX_Direction) {
+ cropRect[0] = SkScalarToFloat(srcRect.left()) / texture->width();
+ cropRect[1] = SkScalarToFloat(srcRect.right()) / texture->width();
+ } else {
+ cropRect[2] = SkScalarToFloat(srcRect.top()) / texture->height();
+ cropRect[3] = SkScalarToFloat(srcRect.bottom()) / texture->height();
+ }
SkAutoTUnref<GrEffectRef> conv(GrConvolutionEffect::CreateGaussian(texture,
direction,
radius,
- sigma));
+ sigma,
+ cropRect));
paint.addColorEffect(conv);
- context->drawRect(paint, rect);
+ context->drawRectToRect(paint, dstRect, srcRect);
}
GrTexture* GaussianBlur(GrContext* context,
@@ -79,7 +91,7 @@
scale_rect(&srcRect, static_cast<float>(scaleFactorX),
static_cast<float>(scaleFactorY));
- GrContext::AutoClip acs(context, srcRect);
+ GrContext::AutoClip acs(context, SkRect::MakeWH(srcRect.width(), srcRect.height()));
GrAssert(kBGRA_8888_GrPixelConfig == srcTexture->config() ||
kRGBA_8888_GrPixelConfig == srcTexture->config() ||
@@ -104,10 +116,25 @@
matrix.setIDiv(srcTexture->width(), srcTexture->height());
context->setRenderTarget(dstTexture->asRenderTarget());
SkRect dstRect(srcRect);
+ if (i == 1) {
+ dstRect.offset(-dstRect.fLeft, -dstRect.fTop);
+ SkRect domain;
+ matrix.mapRect(&domain, rect);
+ domain.inset(i < scaleFactorX ? SK_ScalarHalf / srcTexture->width() : 0.0f,
+ i < scaleFactorY ? SK_ScalarHalf / srcTexture->height() : 0.0f);
+ SkAutoTUnref<GrEffectRef> effect(GrTextureDomainEffect::Create(
+ srcTexture,
+ matrix,
+ domain,
+ GrTextureDomainEffect::kDecal_WrapMode,
+ true));
+ paint.addColorEffect(effect);
+ } else {
+ GrTextureParams params(SkShader::kClamp_TileMode, true);
+ paint.addColorTextureEffect(srcTexture, matrix, params);
+ }
scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
i < scaleFactorY ? 0.5f : 1.0f);
- GrTextureParams params(SkShader::kClamp_TileMode, true);
- paint.addColorTextureEffect(srcTexture, matrix, params);
context->drawRectToRect(paint, dstRect, srcRect);
srcRect = dstRect;
srcTexture = dstTexture;
@@ -126,9 +153,11 @@
context->clear(&clearRect, 0x0);
}
context->setRenderTarget(dstTexture->asRenderTarget());
- convolve_gaussian(context, srcTexture, srcRect, sigmaX, radiusX,
+ SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
+ convolve_gaussian(context, srcTexture, srcRect, dstRect, sigmaX, radiusX,
Gr1DKernelEffect::kX_Direction);
srcTexture = dstTexture;
+ srcRect = dstRect;
SkTSwap(dstTexture, tempTexture);
}
@@ -142,9 +171,11 @@
}
context->setRenderTarget(dstTexture->asRenderTarget());
- convolve_gaussian(context, srcTexture, srcRect, sigmaY, radiusY,
+ SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
+ convolve_gaussian(context, srcTexture, srcRect, dstRect, sigmaY, radiusY,
Gr1DKernelEffect::kY_Direction);
srcTexture = dstTexture;
+ srcRect = dstRect;
SkTSwap(dstTexture, tempTexture);
}
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index eaac5ab..4456f51 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1387,7 +1387,7 @@
SkAutoCachedTexture act(this, bitmap, NULL, &texture);
SkImageFilter* filter = paint.getImageFilter();
- SkIPoint offset = SkIPoint::Make(0, 0);
+ SkIPoint offset = SkIPoint::Make(left, top);
// This bitmap will own the filtered result as a texture.
SkBitmap filteredBitmap;
@@ -1396,6 +1396,8 @@
texture = (GrTexture*) filteredBitmap.getTexture();
w = filteredBitmap.width();
h = filteredBitmap.height();
+ } else {
+ return;
}
}
@@ -1407,12 +1409,12 @@
}
fContext->drawRectToRect(grPaint,
- SkRect::MakeXYWH(SkIntToScalar(left),
- SkIntToScalar(top),
- SkIntToScalar(w),
- SkIntToScalar(h)),
SkRect::MakeXYWH(SkIntToScalar(offset.fX),
SkIntToScalar(offset.fY),
+ SkIntToScalar(w),
+ SkIntToScalar(h)),
+ SkRect::MakeXYWH(0,
+ 0,
SK_Scalar1 * w / texture->width(),
SK_Scalar1 * h / texture->height()));
}
@@ -1481,6 +1483,8 @@
h = filteredBitmap.height();
x += offset.fX;
y += offset.fY;
+ } else {
+ return;
}
}
diff --git a/src/gpu/effects/GrConvolutionEffect.cpp b/src/gpu/effects/GrConvolutionEffect.cpp
index 380581f..5682b9c 100644
--- a/src/gpu/effects/GrConvolutionEffect.cpp
+++ b/src/gpu/effects/GrConvolutionEffect.cpp
@@ -37,6 +37,7 @@
int fRadius;
UniformHandle fKernelUni;
UniformHandle fImageIncrementUni;
+ UniformHandle fCropRectUni;
GrGLEffectMatrix fEffectMatrix;
typedef GrGLEffect INHERITED;
@@ -47,6 +48,7 @@
: INHERITED(factory)
, fKernelUni(kInvalidUniformHandle)
, fImageIncrementUni(kInvalidUniformHandle)
+ , fCropRectUni(kInvalidUniformHandle)
, fEffectMatrix(drawEffect.castEffect<GrConvolutionEffect>().coordsType()) {
const GrConvolutionEffect& c = drawEffect.castEffect<GrConvolutionEffect>();
fRadius = c.radius();
@@ -62,6 +64,8 @@
fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
kVec2f_GrSLType, "ImageIncrement");
+ fCropRectUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+ kVec4f_GrSLType, "CropRect");
fKernelUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_ShaderType,
kFloat_GrSLType, "Kernel", this->width());
@@ -70,6 +74,7 @@
int width = this ->width();
const GrGLShaderVar& kernel = builder->getUniformVariable(fKernelUni);
const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
+ const char* cropRect = builder->getUniformCStr(fCropRectUni);
builder->fsCodeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords, fRadius, imgInc);
@@ -81,9 +86,11 @@
kernel.appendArrayAccess(index.c_str(), &kernelIndex);
builder->fsCodeAppendf("\t\t%s += ", outputColor);
builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "coord");
- builder->fsCodeAppendf(" * %s;\n", kernelIndex.c_str());
+ builder->fsCodeAppendf(" * float(coord.x >= %s.x && coord.x <= %s.y && coord.y >= %s.z && coord.y <= %s.w) * %s;\n",
+ cropRect, cropRect, cropRect, cropRect, kernelIndex.c_str());
builder->fsCodeAppendf("\t\tcoord += %s;\n", imgInc);
}
+
SkString modulate;
GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
builder->fsCodeAppend(modulate.c_str());
@@ -96,17 +103,26 @@
// the code we generated was for a specific kernel radius
GrAssert(conv.radius() == fRadius);
float imageIncrement[2] = { 0 };
+ float ySign = texture.origin() != kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f;
switch (conv.direction()) {
case Gr1DKernelEffect::kX_Direction:
imageIncrement[0] = 1.0f / texture.width();
break;
case Gr1DKernelEffect::kY_Direction:
- imageIncrement[1] = 1.0f / texture.height();
+ imageIncrement[1] = ySign / texture.height();
break;
default:
GrCrash("Unknown filter direction.");
}
uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
+ float c[4];
+ memcpy(c, conv.cropRect(), sizeof(c));
+ if (texture.origin() != kTopLeft_GrSurfaceOrigin) {
+ float tmp = 1.0f - c[2];
+ c[2] = 1.0f - c[3];
+ c[3] = tmp;
+ }
+ uman.set4fv(fCropRectUni, 0, 1, c);
uman.set1fv(fKernelUni, 0, this->width(), conv.kernel());
fEffectMatrix.setData(uman, conv.getMatrix(), drawEffect, conv.texture(0));
}
@@ -128,7 +144,8 @@
GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture,
Direction direction,
int radius,
- const float* kernel)
+ const float* kernel,
+ float cropRect[4])
: Gr1DKernelEffect(texture, direction, radius) {
GrAssert(radius <= kMaxKernelRadius);
GrAssert(NULL != kernel);
@@ -136,12 +153,14 @@
for (int i = 0; i < width; i++) {
fKernel[i] = kernel[i];
}
+ memcpy(fCropRect, cropRect, sizeof(fCropRect));
}
GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture,
Direction direction,
int radius,
- float gaussianSigma)
+ float gaussianSigma,
+ float cropRect[4])
: Gr1DKernelEffect(texture, direction, radius) {
GrAssert(radius <= kMaxKernelRadius);
int width = this->width();
@@ -160,6 +179,7 @@
for (int i = 0; i < width; ++i) {
fKernel[i] *= scale;
}
+ memcpy(fCropRect, cropRect, sizeof(fCropRect));
}
GrConvolutionEffect::~GrConvolutionEffect() {
@@ -174,6 +194,7 @@
return (this->texture(0) == s.texture(0) &&
this->radius() == s.radius() &&
this->direction() == s.direction() &&
+ 0 == memcmp(fCropRect, s.fCropRect, sizeof(fCropRect)) &&
0 == memcmp(fKernel, s.fKernel, this->width() * sizeof(float)));
}
@@ -190,9 +211,13 @@
Direction dir = random->nextBool() ? kX_Direction : kY_Direction;
int radius = random->nextRangeU(1, kMaxKernelRadius);
float kernel[kMaxKernelRadius];
+ float cropRect[4];
for (int i = 0; i < kMaxKernelRadius; ++i) {
kernel[i] = random->nextSScalar1();
}
+ for (int i = 0; i < 4; ++i) {
+ cropRect[i] = random->nextF();
+ }
- return GrConvolutionEffect::Create(textures[texIdx], dir, radius,kernel);
+ return GrConvolutionEffect::Create(textures[texIdx], dir, radius, kernel, cropRect);
}
diff --git a/src/gpu/effects/GrConvolutionEffect.h b/src/gpu/effects/GrConvolutionEffect.h
index e4faa94..f75cfe9 100644
--- a/src/gpu/effects/GrConvolutionEffect.h
+++ b/src/gpu/effects/GrConvolutionEffect.h
@@ -22,11 +22,16 @@
public:
/// Convolve with an arbitrary user-specified kernel
- static GrEffectRef* Create(GrTexture* tex, Direction dir, int halfWidth, const float* kernel) {
+ static GrEffectRef* Create(GrTexture* tex,
+ Direction dir,
+ int halfWidth,
+ const float* kernel,
+ float cropRect[4]) {
AutoEffectUnref effect(SkNEW_ARGS(GrConvolutionEffect, (tex,
dir,
halfWidth,
- kernel)));
+ kernel,
+ cropRect)));
return CreateEffectRef(effect);
}
@@ -34,11 +39,13 @@
static GrEffectRef* CreateGaussian(GrTexture* tex,
Direction dir,
int halfWidth,
- float gaussianSigma) {
+ float gaussianSigma,
+ float cropRect[4]) {
AutoEffectUnref effect(SkNEW_ARGS(GrConvolutionEffect, (tex,
dir,
halfWidth,
- gaussianSigma)));
+ gaussianSigma,
+ cropRect)));
return CreateEffectRef(effect);
}
@@ -46,6 +53,8 @@
const float* kernel() const { return fKernel; }
+ const float* cropRect() const { return fCropRect; }
+
static const char* Name() { return "Convolution"; }
typedef GrGLConvolutionEffect GLEffect;
@@ -72,15 +81,17 @@
protected:
float fKernel[kMaxKernelWidth];
+ float fCropRect[4];
private:
GrConvolutionEffect(GrTexture*, Direction,
- int halfWidth, const float* kernel);
+ int halfWidth, const float* kernel, float cropRect[4]);
/// Convolve with a Gaussian kernel
GrConvolutionEffect(GrTexture*, Direction,
int halfWidth,
- float gaussianSigma);
+ float gaussianSigma,
+ float cropRect[4]);
virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;