| Index: src/effects/SkMagnifierImageFilter.cpp
|
| diff --git a/src/effects/SkMagnifierImageFilter.cpp b/src/effects/SkMagnifierImageFilter.cpp
|
| index 50e17d424672cd72895c8b29347b6e63616a0d9f..9ab18a7582ccf975d60458b2f0e04e3fde444e6b 100644
|
| --- a/src/effects/SkMagnifierImageFilter.cpp
|
| +++ b/src/effects/SkMagnifierImageFilter.cpp
|
| @@ -5,16 +5,19 @@
|
| * found in the LICENSE file.
|
| */
|
|
|
| -#include "SkBitmap.h"
|
| #include "SkMagnifierImageFilter.h"
|
| +
|
| +#include "SkBitmap.h"
|
| #include "SkColorPriv.h"
|
| -#include "SkDevice.h"
|
| #include "SkReadBuffer.h"
|
| +#include "SkSpecialImage.h"
|
| #include "SkWriteBuffer.h"
|
| #include "SkValidationUtils.h"
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| #if SK_SUPPORT_GPU
|
| +#include "GrContext.h"
|
| +#include "GrDrawContext.h"
|
| #include "GrInvariantOutput.h"
|
| #include "effects/GrSingleTextureEffect.h"
|
| #include "glsl/GrGLSLFragmentProcessor.h"
|
| @@ -33,26 +36,28 @@ public:
|
| float yInvZoom,
|
| float xInvInset,
|
| float yInvInset) {
|
| - return new GrMagnifierEffect(texture, bounds, xOffset, yOffset, xInvZoom, yInvZoom, xInvInset,
|
| - yInvInset);
|
| + return new GrMagnifierEffect(texture, bounds,
|
| + xOffset, yOffset,
|
| + xInvZoom, yInvZoom,
|
| + xInvInset, yInvInset);
|
| }
|
|
|
| - virtual ~GrMagnifierEffect() {};
|
| + ~GrMagnifierEffect() override {};
|
|
|
| const char* name() const override { return "Magnifier"; }
|
|
|
| const SkRect& bounds() const { return fBounds; } // Bounds of source image.
|
| // Offset to apply to zoomed pixels, (srcRect position / texture size).
|
| - float x_offset() const { return fXOffset; }
|
| - float y_offset() const { return fYOffset; }
|
| + float xOffset() const { return fXOffset; }
|
| + float yOffset() const { return fYOffset; }
|
|
|
| // Scale to apply to zoomed pixels (srcRect size / bounds size).
|
| - float x_inv_zoom() const { return fXInvZoom; }
|
| - float y_inv_zoom() const { return fYInvZoom; }
|
| + float xInvZoom() const { return fXInvZoom; }
|
| + float yInvZoom() const { return fYInvZoom; }
|
|
|
| // 1/radius over which to transition from unzoomed to zoomed pixels (bounds size / inset).
|
| - float x_inv_inset() const { return fXInvInset; }
|
| - float y_inv_inset() const { return fYInvInset; }
|
| + float xInvInset() const { return fXInvInset; }
|
| + float yInvInset() const { return fYInvInset; }
|
|
|
| private:
|
| GrMagnifierEffect(GrTexture* texture,
|
| @@ -167,9 +172,9 @@ void GrGLMagnifierEffect::emitCode(EmitArgs& args) {
|
| void GrGLMagnifierEffect::onSetData(const GrGLSLProgramDataManager& pdman,
|
| const GrProcessor& effect) {
|
| const GrMagnifierEffect& zoom = effect.cast<GrMagnifierEffect>();
|
| - pdman.set2f(fOffsetVar, zoom.x_offset(), zoom.y_offset());
|
| - pdman.set2f(fInvZoomVar, zoom.x_inv_zoom(), zoom.y_inv_zoom());
|
| - pdman.set2f(fInvInsetVar, zoom.x_inv_inset(), zoom.y_inv_inset());
|
| + pdman.set2f(fOffsetVar, zoom.xOffset(), zoom.yOffset());
|
| + pdman.set2f(fInvZoomVar, zoom.xInvZoom(), zoom.yInvZoom());
|
| + pdman.set2f(fInvInsetVar, zoom.xInvInset(), zoom.yInvInset());
|
| pdman.set4f(fBoundsVar, zoom.bounds().x(), zoom.bounds().y(),
|
| zoom.bounds().width(), zoom.bounds().height());
|
| }
|
| @@ -233,7 +238,8 @@ void GrMagnifierEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const
|
| ////////////////////////////////////////////////////////////////////////////////
|
|
|
| sk_sp<SkImageFilter> SkMagnifierImageFilter::Make(const SkRect& srcRect, SkScalar inset,
|
| - sk_sp<SkImageFilter> input) {
|
| + sk_sp<SkImageFilter> input,
|
| + const CropRect* cropRect) {
|
|
|
| if (!SkScalarIsFinite(inset) || !SkIsValidRect(srcRect)) {
|
| return nullptr;
|
| @@ -242,52 +248,27 @@ sk_sp<SkImageFilter> SkMagnifierImageFilter::Make(const SkRect& srcRect, SkScala
|
| if (srcRect.fLeft < 0 || srcRect.fTop < 0) {
|
| return nullptr;
|
| }
|
| - return sk_sp<SkImageFilter>(new SkMagnifierImageFilter(srcRect, inset, std::move(input)));
|
| + return sk_sp<SkImageFilter>(new SkMagnifierImageFilter(srcRect, inset,
|
| + std::move(input),
|
| + cropRect));
|
| }
|
|
|
|
|
| -SkMagnifierImageFilter::SkMagnifierImageFilter(const SkRect& srcRect, SkScalar inset,
|
| - sk_sp<SkImageFilter> input)
|
| - : INHERITED(&input, 1, nullptr)
|
| +SkMagnifierImageFilter::SkMagnifierImageFilter(const SkRect& srcRect,
|
| + SkScalar inset,
|
| + sk_sp<SkImageFilter> input,
|
| + const CropRect* cropRect)
|
| + : INHERITED(&input, 1, cropRect)
|
| , fSrcRect(srcRect)
|
| , fInset(inset) {
|
| SkASSERT(srcRect.x() >= 0 && srcRect.y() >= 0 && inset >= 0);
|
| }
|
|
|
| -#if SK_SUPPORT_GPU
|
| -bool SkMagnifierImageFilter::asFragmentProcessor(GrFragmentProcessor** fp,
|
| - GrTexture* texture, const SkMatrix&,
|
| - const SkIRect&bounds) const {
|
| - if (fp) {
|
| - SkScalar yOffset = texture->origin() == kTopLeft_GrSurfaceOrigin ? fSrcRect.y() :
|
| - texture->height() - fSrcRect.height() * texture->height() / bounds.height()
|
| - - fSrcRect.y();
|
| - int boundsY = (texture->origin() == kTopLeft_GrSurfaceOrigin) ? bounds.y() :
|
| - (texture->height() - bounds.height());
|
| - SkRect effectBounds = SkRect::MakeXYWH(
|
| - SkIntToScalar(bounds.x()) / texture->width(),
|
| - SkIntToScalar(boundsY) / texture->height(),
|
| - SkIntToScalar(texture->width()) / bounds.width(),
|
| - SkIntToScalar(texture->height()) / bounds.height());
|
| - SkScalar invInset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1;
|
| - *fp = GrMagnifierEffect::Create(texture,
|
| - effectBounds,
|
| - fSrcRect.x() / texture->width(),
|
| - yOffset / texture->height(),
|
| - fSrcRect.width() / bounds.width(),
|
| - fSrcRect.height() / bounds.height(),
|
| - bounds.width() * invInset,
|
| - bounds.height() * invInset);
|
| - }
|
| - return true;
|
| -}
|
| -#endif
|
| -
|
| sk_sp<SkFlattenable> SkMagnifierImageFilter::CreateProc(SkReadBuffer& buffer) {
|
| SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
|
| SkRect src;
|
| buffer.readRect(&src);
|
| - return Make(src, buffer.readScalar(), common.getInput(0));
|
| + return Make(src, buffer.readScalar(), common.getInput(0), &common.cropRect());
|
| }
|
|
|
| void SkMagnifierImageFilter::flatten(SkWriteBuffer& buffer) const {
|
| @@ -296,40 +277,102 @@ void SkMagnifierImageFilter::flatten(SkWriteBuffer& buffer) const {
|
| buffer.writeScalar(fInset);
|
| }
|
|
|
| -bool SkMagnifierImageFilter::onFilterImageDeprecated(Proxy* proxy, const SkBitmap& src,
|
| - const Context&, SkBitmap* dst,
|
| - SkIPoint* offset) const {
|
| - if ((src.colorType() != kN32_SkColorType) ||
|
| - (fSrcRect.width() >= src.width()) ||
|
| - (fSrcRect.height() >= src.height())) {
|
| - return false;
|
| +sk_sp<SkSpecialImage> SkMagnifierImageFilter::onFilterImage(SkSpecialImage* source,
|
| + const Context& ctx,
|
| + SkIPoint* offset) const {
|
| + SkIPoint inputOffset = SkIPoint::Make(0, 0);
|
| + sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
|
| + if (!input) {
|
| + return nullptr;
|
| + }
|
| +
|
| + const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
|
| + input->width(), input->height());
|
| +
|
| + SkIRect bounds;
|
| + if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
|
| + return nullptr;
|
| + }
|
| +
|
| + SkScalar invInset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1;
|
| +
|
| + SkScalar invXZoom = fSrcRect.width() / bounds.width();
|
| + SkScalar invYZoom = fSrcRect.height() / bounds.height();
|
| +
|
| +
|
| +#if SK_SUPPORT_GPU
|
| + if (source->isTextureBacked()) {
|
| + GrContext* context = source->getContext();
|
| +
|
| + sk_sp<GrTexture> inputTexture(input->asTextureRef(context));
|
| + SkASSERT(inputTexture);
|
| +
|
| + offset->fX = bounds.left();
|
| + offset->fY = bounds.top();
|
| + bounds.offset(-inputOffset);
|
| +
|
| + SkScalar yOffset = inputTexture->origin() == kTopLeft_GrSurfaceOrigin
|
| + ? fSrcRect.y()
|
| + : inputTexture->height() -
|
| + fSrcRect.height() * inputTexture->height() / bounds.height() - fSrcRect.y();
|
| + int boundsY = inputTexture->origin() == kTopLeft_GrSurfaceOrigin
|
| + ? bounds.y()
|
| + : inputTexture->height() - bounds.height();
|
| + SkRect effectBounds = SkRect::MakeXYWH(
|
| + SkIntToScalar(bounds.x()) / inputTexture->width(),
|
| + SkIntToScalar(boundsY) / inputTexture->height(),
|
| + SkIntToScalar(inputTexture->width()) / bounds.width(),
|
| + SkIntToScalar(inputTexture->height()) / bounds.height());
|
| + // SRGBTODO: Handle sRGB here
|
| + sk_sp<GrFragmentProcessor> fp(GrMagnifierEffect::Create(
|
| + inputTexture.get(),
|
| + effectBounds,
|
| + fSrcRect.x() / inputTexture->width(),
|
| + yOffset / inputTexture->height(),
|
| + invXZoom,
|
| + invYZoom,
|
| + bounds.width() * invInset,
|
| + bounds.height() * invInset));
|
| + if (!fp) {
|
| + return nullptr;
|
| + }
|
| +
|
| + return DrawWithFP(context, std::move(fp), bounds, source->internal_getProxy());
|
| }
|
| +#endif
|
|
|
| - SkAutoLockPixels alp(src);
|
| - SkASSERT(src.getPixels());
|
| - if (!src.getPixels() || src.width() <= 0 || src.height() <= 0) {
|
| - return false;
|
| + SkBitmap inputBM;
|
| +
|
| + if (!input->getROPixels(&inputBM)) {
|
| + return nullptr;
|
| }
|
|
|
| - SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(src.width(), src.height()));
|
| - if (!device) {
|
| - return false;
|
| + if ((inputBM.colorType() != kN32_SkColorType) ||
|
| + (fSrcRect.width() >= inputBM.width()) || (fSrcRect.height() >= inputBM.height())) {
|
| + return nullptr;
|
| + }
|
| +
|
| + SkAutoLockPixels alp(inputBM);
|
| + SkASSERT(inputBM.getPixels());
|
| + if (!inputBM.getPixels() || inputBM.width() <= 0 || inputBM.height() <= 0) {
|
| + return nullptr;
|
| }
|
| - *dst = device->accessBitmap(false);
|
| - SkAutoLockPixels alp_dst(*dst);
|
|
|
| - SkScalar inv_inset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1;
|
| + const SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height());
|
|
|
| - SkScalar inv_x_zoom = fSrcRect.width() / src.width();
|
| - SkScalar inv_y_zoom = fSrcRect.height() / src.height();
|
| + SkBitmap dst;
|
| + if (!dst.tryAllocPixels(info)) {
|
| + return nullptr;
|
| + }
|
|
|
| - SkColor* sptr = src.getAddr32(0, 0);
|
| - SkColor* dptr = dst->getAddr32(0, 0);
|
| - int width = src.width(), height = src.height();
|
| - for (int y = 0; y < height; ++y) {
|
| - for (int x = 0; x < width; ++x) {
|
| - SkScalar x_dist = SkMin32(x, width - x - 1) * inv_inset;
|
| - SkScalar y_dist = SkMin32(y, height - y - 1) * inv_inset;
|
| + SkAutoLockPixels dstLock(dst);
|
| +
|
| + SkColor* dptr = dst.getAddr32(0, 0);
|
| + int dstWidth = dst.width(), dstHeight = dst.height();
|
| + for (int y = 0; y < dstHeight; ++y) {
|
| + for (int x = 0; x < dstWidth; ++x) {
|
| + SkScalar x_dist = SkMin32(x, dstWidth - x - 1) * invInset;
|
| + SkScalar y_dist = SkMin32(y, dstHeight - y - 1) * invInset;
|
| SkScalar weight = 0;
|
|
|
| static const SkScalar kScalar2 = SkScalar(2);
|
| @@ -350,19 +393,24 @@ bool SkMagnifierImageFilter::onFilterImageDeprecated(Proxy* proxy, const SkBitma
|
| weight = SkMinScalar(sqDist, SK_Scalar1);
|
| }
|
|
|
| - SkScalar x_interp = SkScalarMul(weight, (fSrcRect.x() + x * inv_x_zoom)) +
|
| + SkScalar x_interp = SkScalarMul(weight, (fSrcRect.x() + x * invXZoom)) +
|
| (SK_Scalar1 - weight) * x;
|
| - SkScalar y_interp = SkScalarMul(weight, (fSrcRect.y() + y * inv_y_zoom)) +
|
| + SkScalar y_interp = SkScalarMul(weight, (fSrcRect.y() + y * invYZoom)) +
|
| (SK_Scalar1 - weight) * y;
|
|
|
| - int x_val = SkTPin(SkScalarFloorToInt(x_interp), 0, width - 1);
|
| - int y_val = SkTPin(SkScalarFloorToInt(y_interp), 0, height - 1);
|
| + int x_val = SkTPin(bounds.x() + SkScalarFloorToInt(x_interp), 0, inputBM.width() - 1);
|
| + int y_val = SkTPin(bounds.y() + SkScalarFloorToInt(y_interp), 0, inputBM.height() - 1);
|
|
|
| - *dptr = sptr[y_val * width + x_val];
|
| + *dptr = *inputBM.getAddr32(x_val, y_val);
|
| dptr++;
|
| }
|
| }
|
| - return true;
|
| +
|
| + offset->fX = bounds.left();
|
| + offset->fY = bounds.top();
|
| + return SkSpecialImage::MakeFromRaster(source->internal_getProxy(),
|
| + SkIRect::MakeWH(bounds.width(), bounds.height()),
|
| + dst);
|
| }
|
|
|
| #ifndef SK_IGNORE_TO_STRING
|
|
|