Switch AlphaThresholdFilter over to new onFilterImage interface
authorrobertphillips <robertphillips@google.com>
Tue, 12 Apr 2016 18:02:25 +0000 (11:02 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 12 Apr 2016 18:02:25 +0000 (11:02 -0700)
This CL also alters the raster path in two ways:
  it now respects the sRGB/linear distinction of its input
  it now respects the clip

TBR=reed@google.com

GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1879643003

Review URL: https://codereview.chromium.org/1879643003

gm/imagealphathreshold.cpp
include/core/SkImageFilter.h
include/effects/SkAlphaThresholdFilter.h
src/core/SkImageFilter.cpp
src/effects/SkAlphaThresholdFilter.cpp

index fdd93bd2105cc1ffa5a02e2fc455be26e4e90ed5..2b65202c1067856228984d1507203aca5f97c344 100644 (file)
@@ -27,7 +27,7 @@ void draw_rects(SkCanvas* canvas) {
     canvas->drawRect(SkRect::MakeXYWH(WIDTH / 2, HEIGHT / 2, WIDTH / 2, HEIGHT / 2), rectPaint);
 }
 
-SkPaint create_filter_paint() {
+SkPaint create_filter_paint(SkImageFilter::CropRect* cropRect = nullptr) {
     SkIRect rects[2];
     rects[0] = SkIRect::MakeXYWH(0, 150, WIDTH, HEIGHT - 300);
     rects[1] = SkIRect::MakeXYWH(150, 0, WIDTH - 300, HEIGHT);
@@ -35,7 +35,7 @@ SkPaint create_filter_paint() {
     region.setRects(rects, 2);
 
     SkPaint paint;
-    paint.setImageFilter(SkAlphaThresholdFilter::Make(region, 0.2f, 0.7f, nullptr));
+    paint.setImageFilter(SkAlphaThresholdFilter::Make(region, 0.2f, 0.7f, nullptr, cropRect));
     return paint;
 }
 
@@ -45,13 +45,17 @@ namespace skiagm {
 
 class ImageAlphaThresholdGM : public GM {
 public:
-    ImageAlphaThresholdGM() {
+    ImageAlphaThresholdGM(bool useCropRect) : fUseCropRect(true) { 
         this->setBGColor(0xFFFFFFFF);
     }
 
 protected:
 
     SkString onShortName() override {
+        if (fUseCropRect) {
+            return SkString("imagealphathreshold_crop");
+        }
+
         return SkString("imagealphathreshold");
     }
 
@@ -67,7 +71,10 @@ protected:
 
         canvas->concat(matrix);
 
-        SkPaint paint = create_filter_paint();
+        SkRect r = SkRect::MakeLTRB(100, 100, WIDTH - 100, HEIGHT - 100);
+        SkImageFilter::CropRect cropRect(r);
+
+        SkPaint paint = create_filter_paint(fUseCropRect ? &cropRect : nullptr);
         canvas->saveLayer(nullptr, &paint);
         draw_rects(canvas);
 
@@ -75,9 +82,12 @@ protected:
     }
 
 private:
+    bool fUseCropRect;
+
     typedef GM INHERITED;
 };
 
+
 class ImageAlphaThresholdSurfaceGM : public GM {
 public:
     ImageAlphaThresholdSurfaceGM() {
@@ -113,7 +123,8 @@ private:
 
 //////////////////////////////////////////////////////////////////////////////
 
-DEF_GM(return new ImageAlphaThresholdGM();)
+DEF_GM(return new ImageAlphaThresholdGM(true);)
+DEF_GM(return new ImageAlphaThresholdGM(false);)
 DEF_GM(return new ImageAlphaThresholdSurfaceGM();)
 
 }
index 8a8e512254f2e42e8515fee9844b18898416f319..d90e74de7749dec99cbfca9e10213c667b170957 100644 (file)
@@ -17,6 +17,7 @@
 #include "SkRect.h"
 #include "SkSurfaceProps.h"
 
+class GrContext;
 class GrFragmentProcessor;
 class GrTexture;
 class SkBaseDevice;
@@ -196,6 +197,13 @@ public:
     virtual bool filterImageGPUDeprecated(Proxy*, const SkBitmap& src, const Context&,
                                           SkBitmap* result, SkIPoint* offset) const;
 
+#if SK_SUPPORT_GPU
+    static sk_sp<SkSpecialImage> DrawWithFP(GrContext* context, 
+                                            sk_sp<GrFragmentProcessor> fp,
+                                            const SkIRect& bounds,
+                                            SkImageFilter::Proxy* proxy);
+#endif
+
     /**
      *  Returns whether this image filter is a color filter and puts the color filter into the
      *  "filterPtr" parameter if it can. Does nothing otherwise.
@@ -418,13 +426,12 @@ protected:
         return false;
     }
 
-    /** Given a "srcBounds" rect, computes destination bounds for this
-     *  destination bounds for this filter. "dstBounds" are computed by
-     *  transforming the crop rect by the context's CTM, applying it to the
-     *  initial bounds, and intersecting the result with the context's clip
-     *  bounds.  "srcBounds" (if non-null) are computed by intersecting the
-     *  initial bounds with "dstBounds", to ensure that we never sample
-     *  outside of the crop rect (this restriction may be relaxed in the
+    /** Given a "srcBounds" rect, computes destination bounds for this filter.
+     *  "dstBounds" are computed by transforming the crop rect by the context's
+     *  CTM, applying it to the initial bounds, and intersecting the result with
+     *  the context's clip bounds.  "srcBounds" (if non-null) are computed by
+     *  intersecting the initial bounds with "dstBounds", to ensure that we never
+     *  sample outside of the crop rect (this restriction may be relaxed in the
      *  future).
      */
     bool applyCropRect(const Context&, const SkIRect& srcBounds, SkIRect* dstBounds) const;
index aee365f99986b8f996f699bc3433e4c5895a03f9..a125b3c501088a8d77c0e725ad473b8fb0d4feaf 100644 (file)
@@ -21,7 +21,8 @@ public:
      * source image.
      */
     static sk_sp<SkImageFilter> Make(const SkRegion& region, SkScalar innerMin,
-                                     SkScalar outerMax, sk_sp<SkImageFilter> input);
+                                     SkScalar outerMax, sk_sp<SkImageFilter> input,
+                                     const SkImageFilter::CropRect* cropRect = nullptr);
 
 
 #ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR
index 6cbdf625fbd868c14aaae6a7a71c0b9396039237..af2b278e3d8721a4aa9a477da1ebed66ce2ca773 100644 (file)
@@ -414,7 +414,7 @@ bool SkImageFilter::filterImageGPUDeprecated(Proxy* proxy, const SkBitmap& src,
     GrContext* context = srcTexture->getContext();
 
     GrSurfaceDesc desc;
-    desc.fFlags = kRenderTarget_GrSurfaceFlag,
+    desc.fFlags = kRenderTarget_GrSurfaceFlag;
     desc.fWidth = bounds.width();
     desc.fHeight = bounds.height();
     desc.fConfig = kRGBA_8888_GrPixelConfig;
@@ -452,6 +452,44 @@ bool SkImageFilter::filterImageGPUDeprecated(Proxy* proxy, const SkBitmap& src,
     return false;
 }
 
+#if SK_SUPPORT_GPU
+sk_sp<SkSpecialImage> SkImageFilter::DrawWithFP(GrContext* context,
+                                                sk_sp<GrFragmentProcessor> fp,
+                                                const SkIRect& bounds,
+                                                SkImageFilter::Proxy* proxy) {
+    GrPaint paint;
+    paint.addColorFragmentProcessor(fp.get());
+    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+
+    GrSurfaceDesc desc;
+    desc.fFlags = kRenderTarget_GrSurfaceFlag;
+    desc.fWidth = bounds.width();
+    desc.fHeight = bounds.height();
+    desc.fConfig = kRGBA_8888_GrPixelConfig;
+
+    sk_sp<GrTexture> dst(context->textureProvider()->createApproxTexture(desc));
+    if (!dst) {
+        return nullptr;
+    }
+
+    sk_sp<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
+    if (!drawContext) {
+        return nullptr;
+    }
+
+    SkRect srcRect = SkRect::Make(bounds);
+    SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
+    GrClip clip(dstRect);
+    drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
+
+    return SkSpecialImage::MakeFromGpu(proxy,
+                                       SkIRect::MakeWH(bounds.width(), bounds.height()),
+                                       kNeedNewImageUniqueID_SpecialImage,
+                                       dst.get());
+
+}
+#endif
+
 bool SkImageFilter::asAColorFilter(SkColorFilter** filterPtr) const {
     SkASSERT(nullptr != filterPtr);
     if (!this->isColorFilterNode(filterPtr)) {
@@ -530,8 +568,8 @@ sk_sp<SkSpecialImage> SkImageFilter::applyCropRect(const Context& ctx,
                                                    SkSpecialImage* src,
                                                    SkIPoint* srcOffset,
                                                    SkIRect* bounds) const {
-    SkIRect srcBounds;
-    srcBounds = SkIRect::MakeXYWH(srcOffset->fX, srcOffset->fY, src->width(), src->height());
+    const SkIRect srcBounds = SkIRect::MakeXYWH(srcOffset->x(), srcOffset->y(),
+                                                src->width(), src->height());
 
     SkIRect dstBounds = this->onFilterNodeBounds(srcBounds, ctx.ctm(), kForward_MapDirection);
     fCropRect.applyTo(dstBounds, ctx.ctm(), this->affectsTransparentBlack(), bounds);
index 0b65188e83a52703974217045bfbf425d6c9b94e..832fcb39e7636b75f733ec20969b3ac4d1941cea 100644 (file)
@@ -8,8 +8,8 @@
 #include "SkAlphaThresholdFilter.h"
 
 #include "SkBitmap.h"
-#include "SkDevice.h"
 #include "SkReadBuffer.h"
+#include "SkSpecialImage.h"
 #include "SkWriteBuffer.h"
 #include "SkRegion.h"
 #if SK_SUPPORT_GPU
@@ -19,7 +19,8 @@
 class SK_API SkAlphaThresholdFilterImpl : public SkImageFilter {
 public:
     SkAlphaThresholdFilterImpl(const SkRegion& region, SkScalar innerThreshold,
-                               SkScalar outerThreshold, sk_sp<SkImageFilter> input);
+                               SkScalar outerThreshold, sk_sp<SkImageFilter> input,
+                               const CropRect* cropRect = nullptr);
 
     SK_TO_STRING_OVERRIDE()
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkAlphaThresholdFilterImpl)
@@ -28,11 +29,11 @@ public:
 protected:
     void flatten(SkWriteBuffer&) const override;
 
-    bool onFilterImageDeprecated(Proxy*, const SkBitmap& src, const Context&,
-                                 SkBitmap* result, SkIPoint* offset) const override;
+    sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
+                                        SkIPoint* offset) const override;
+
 #if SK_SUPPORT_GPU
-    bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
-                             const SkIRect& bounds) const override;
+    sk_sp<GrTexture> createMaskTexture(GrContext*, const SkMatrix&, const SkIRect& bounds) const;
 #endif
 
 private:
@@ -53,14 +54,17 @@ static SkScalar pin_0_1(SkScalar x) {
 sk_sp<SkImageFilter> SkAlphaThresholdFilter::Make(const SkRegion& region,
                                                   SkScalar innerThreshold,
                                                   SkScalar outerThreshold,
-                                                  sk_sp<SkImageFilter> input) {
+                                                  sk_sp<SkImageFilter> input,
+                                                  const SkImageFilter::CropRect* cropRect) {
     innerThreshold = pin_0_1(innerThreshold);
     outerThreshold = pin_0_1(outerThreshold);
     if (!SkScalarIsFinite(innerThreshold) || !SkScalarIsFinite(outerThreshold)) {
         return nullptr;
     }
     return sk_sp<SkImageFilter>(new SkAlphaThresholdFilterImpl(region, innerThreshold,
-                                                               outerThreshold, std::move(input)));
+                                                               outerThreshold,
+                                                               std::move(input),
+                                                               cropRect));
 }
 
 #if SK_SUPPORT_GPU
@@ -271,66 +275,59 @@ sk_sp<SkFlattenable> SkAlphaThresholdFilterImpl::CreateProc(SkReadBuffer& buffer
     SkScalar outer = buffer.readScalar();
     SkRegion rgn;
     buffer.readRegion(&rgn);
-    return SkAlphaThresholdFilter::Make(rgn, inner, outer, common.getInput(0));
+    return SkAlphaThresholdFilter::Make(rgn, inner, outer, common.getInput(0),
+                                        &common.cropRect());
 }
 
 SkAlphaThresholdFilterImpl::SkAlphaThresholdFilterImpl(const SkRegion& region,
                                                        SkScalar innerThreshold,
                                                        SkScalar outerThreshold,
-                                                       sk_sp<SkImageFilter> input)
-    : INHERITED(&input, 1, nullptr)
+                                                       sk_sp<SkImageFilter> input,
+                                                       const CropRect* cropRect)
+    : INHERITED(&input, 1, cropRect)
     , fRegion(region)
     , fInnerThreshold(innerThreshold)
     , fOuterThreshold(outerThreshold) {
 }
 
 #if SK_SUPPORT_GPU
-bool SkAlphaThresholdFilterImpl::asFragmentProcessor(GrFragmentProcessor** fp,
-                                                     GrTexture* texture,
-                                                     const SkMatrix& inMatrix,
-                                                     const SkIRect& bounds) const {
-    if (fp) {
-        GrContext* context = texture->getContext();
-        GrSurfaceDesc maskDesc;
-        if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
-            maskDesc.fConfig = kAlpha_8_GrPixelConfig;
-        } else {
-            maskDesc.fConfig = kRGBA_8888_GrPixelConfig;
-        }
-        maskDesc.fFlags = kRenderTarget_GrSurfaceFlag;
-        // Add one pixel of border to ensure that clamp mode will be all zeros
-        // the outside.
-        maskDesc.fWidth = bounds.width();
-        maskDesc.fHeight = bounds.height();
-        SkAutoTUnref<GrTexture> maskTexture(
-            context->textureProvider()->createApproxTexture(maskDesc));
-        if (!maskTexture) {
-            return false;
-        }
+sk_sp<GrTexture> SkAlphaThresholdFilterImpl::createMaskTexture(GrContext* context,
+                                                               const SkMatrix& inMatrix,
+                                                               const SkIRect& bounds) const {
+    GrSurfaceDesc maskDesc;
+    if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
+        maskDesc.fConfig = kAlpha_8_GrPixelConfig;
+    } else {
+        maskDesc.fConfig = kRGBA_8888_GrPixelConfig;
+    }
+    maskDesc.fFlags = kRenderTarget_GrSurfaceFlag;
+    // Add one pixel of border to ensure that clamp mode will be all zeros
+    // the outside.
+    maskDesc.fWidth = bounds.width();
+    maskDesc.fHeight = bounds.height();
+    sk_sp<GrTexture> maskTexture(context->textureProvider()->createApproxTexture(maskDesc));
+    if (!maskTexture) {
+        return nullptr;
+    }
 
-        SkAutoTUnref<GrDrawContext> drawContext(
-                                            context->drawContext(maskTexture->asRenderTarget()));
-        if (drawContext) {
-            GrPaint grPaint;
-            grPaint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
-            SkRegion::Iterator iter(fRegion);
-            drawContext->clear(nullptr, 0x0, true);
-
-            GrClip clip(SkRect::Make(SkIRect::MakeWH(bounds.width(), bounds.height())));
-            while (!iter.done()) {
-                SkRect rect = SkRect::Make(iter.rect());
-                drawContext->drawRect(clip, grPaint, inMatrix, rect);
-                iter.next();
-            }
-        }
+    sk_sp<GrDrawContext> drawContext(context->drawContext(maskTexture->asRenderTarget()));
+    if (!drawContext) {
+        return nullptr;
+    }
 
-        *fp = AlphaThresholdEffect::Create(texture,
-                                           maskTexture,
-                                           fInnerThreshold,
-                                           fOuterThreshold,
-                                           bounds);
+    GrPaint grPaint;
+    grPaint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+    SkRegion::Iterator iter(fRegion);
+    drawContext->clear(nullptr, 0x0, true);
+
+    GrClip clip(SkRect::Make(SkIRect::MakeWH(bounds.width(), bounds.height())));
+    while (!iter.done()) {
+        SkRect rect = SkRect::Make(iter.rect());
+        drawContext->drawRect(clip, grPaint, inMatrix, rect);
+        iter.next();
     }
-    return true;
+
+    return maskTexture;
 }
 #endif
 
@@ -341,50 +338,109 @@ void SkAlphaThresholdFilterImpl::flatten(SkWriteBuffer& buffer) const {
     buffer.writeRegion(fRegion);
 }
 
-bool SkAlphaThresholdFilterImpl::onFilterImageDeprecated(Proxy* proxy, const SkBitmap& src,
-                                                         const Context& ctx, SkBitmap* dst,
-                                                         SkIPoint* offset) const {
+sk_sp<SkSpecialImage> SkAlphaThresholdFilterImpl::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;
+    }
+
+#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();
 
-    if (src.colorType() != kN32_SkColorType) {
-        return false;
+        bounds.offset(-inputOffset);
+
+        SkMatrix matrix(ctx.ctm());
+        matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
+
+        sk_sp<GrTexture> maskTexture(this->createMaskTexture(context, matrix, bounds));
+        if (!maskTexture) {
+            return nullptr;
+        }
+
+        // SRGBTODO: handle sRGB here
+        sk_sp<GrFragmentProcessor> fp(AlphaThresholdEffect::Create(inputTexture.get(),
+                                                                   maskTexture.get(),
+                                                                   fInnerThreshold,
+                                                                   fOuterThreshold,
+                                                                   bounds));
+        if (!fp) {
+            return nullptr;
+        }
+
+        return DrawWithFP(context, std::move(fp), bounds, source->internal_getProxy());
+    }
+#endif
+
+    SkBitmap inputBM;
+
+    if (!input->getROPixels(&inputBM)) {
+        return nullptr;
     }
 
+    if (inputBM.colorType() != kN32_SkColorType) {
+        return nullptr;
+    }
+
+    SkAutoLockPixels inputLock(inputBM);
+
+    if (!inputBM.getPixels() || inputBM.width() <= 0 || inputBM.height() <= 0) {
+        return nullptr;
+    }
+
+
     SkMatrix localInverse;
     if (!ctx.ctm().invert(&localInverse)) {
-        return false;
+        return nullptr;
     }
 
-    SkAutoLockPixels alp(src);
-    SkASSERT(src.getPixels());
-    if (!src.getPixels() || src.width() <= 0 || src.height() <= 0) {
-        return false;
-    }
+    SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(),
+                                            inputBM.alphaType());
 
-    SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(src.width(), src.height()));
-    if (!device) {
-        return false;
+    SkBitmap dst;
+    if (!dst.tryAllocPixels(info)) {
+        return nullptr;
     }
-    *dst = device->accessBitmap(false);
-    SkAutoLockPixels alp_dst(*dst);
+
+    SkAutoLockPixels dstLock(dst);
 
     U8CPU innerThreshold = (U8CPU)(fInnerThreshold * 0xFF);
     U8CPU outerThreshold = (U8CPU)(fOuterThreshold * 0xFF);
-    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) {
-            const SkColor& source = sptr[y * width + x];
-            SkColor output_color(source);
+    SkColor* dptr = dst.getAddr32(0, 0);
+    int dstWidth = dst.width(), dstHeight = dst.height();
+    for (int y = 0; y < dstHeight; ++y) {
+        const SkColor* sptr = inputBM.getAddr32(bounds.fLeft, bounds.fTop+y);
+
+        for (int x = 0; x < dstWidth; ++x) {
+            const SkColor& source = sptr[x];
+            SkColor outputColor(source);
             SkPoint position;
-            localInverse.mapXY((SkScalar)x, (SkScalar)y, &position);
+            localInverse.mapXY((SkScalar)x + bounds.fLeft, (SkScalar)y + bounds.fTop, &position);
             if (fRegion.contains((int32_t)position.x(), (int32_t)position.y())) {
                 if (SkColorGetA(source) < innerThreshold) {
                     U8CPU alpha = SkColorGetA(source);
-                    if (alpha == 0)
+                    if (alpha == 0) {
                         alpha = 1;
+                    }
                     float scale = (float)innerThreshold / alpha;
-                    output_color = SkColorSetARGB(innerThreshold,
+                    outputColor = SkColorSetARGB(innerThreshold,
                                                   (U8CPU)(SkColorGetR(source) * scale),
                                                   (U8CPU)(SkColorGetG(source) * scale),
                                                   (U8CPU)(SkColorGetB(source) * scale));
@@ -392,17 +448,21 @@ bool SkAlphaThresholdFilterImpl::onFilterImageDeprecated(Proxy* proxy, const SkB
             } else {
                 if (SkColorGetA(source) > outerThreshold) {
                     float scale = (float)outerThreshold / SkColorGetA(source);
-                    output_color = SkColorSetARGB(outerThreshold,
+                    outputColor = SkColorSetARGB(outerThreshold,
                                                   (U8CPU)(SkColorGetR(source) * scale),
                                                   (U8CPU)(SkColorGetG(source) * scale),
                                                   (U8CPU)(SkColorGetB(source) * scale));
                 }
             }
-            dptr[y * dst->width() + x] = output_color;
+            dptr[y * dstWidth + x] = outputColor;
         }
     }
 
-    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