aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar senorblanco <senorblanco@chromium.org>2016-04-05 04:43:45 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-04-05 04:43:45 -0700
commit6a93fa1a4526ba14782f7f17a73479ca5a4a8e3a (patch)
treef5d771e8c0cae2aef3ff50e07fd5e69ad6351bd0
parent3b37545bc594a96de45eba62dea0ce478750f2a9 (diff)
Fix failed filter followed by an affects-transparent-black filter.
When an upstream filter returns null, either through failure or clipping, a downstream affects-transparent-black filter should still produce non-transparent pixels. This patch fixes SkColorFilterImageFilter. Note: this will affect the results of the imagefilterscropexpand GM. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1844593002 Review URL: https://codereview.chromium.org/1844593002
-rw-r--r--src/effects/SkColorFilterImageFilter.cpp35
-rw-r--r--tests/ImageFilterTest.cpp64
2 files changed, 89 insertions, 10 deletions
diff --git a/src/effects/SkColorFilterImageFilter.cpp b/src/effects/SkColorFilterImageFilter.cpp
index c1637d8128..1fdc668f9b 100644
--- a/src/effects/SkColorFilterImageFilter.cpp
+++ b/src/effects/SkColorFilterImageFilter.cpp
@@ -57,13 +57,19 @@ sk_sp<SkSpecialImage> SkColorFilterImageFilter::onFilterImage(SkSpecialImage* so
SkIPoint* offset) const {
SkIPoint inputOffset = SkIPoint::Make(0, 0);
sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
- if (!input) {
+
+ SkIRect inputBounds;
+ if (fColorFilter->affectsTransparentBlack()) {
+ // If the color filter affects transparent black, the bounds are the entire clip.
+ inputBounds = ctx.clipBounds();
+ } else if (!input) {
return nullptr;
+ } else {
+ inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
+ input->width(), input->height());
}
SkIRect bounds;
- const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.fX, inputOffset.fY,
- input->width(), input->height());
if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
return nullptr;
}
@@ -77,18 +83,27 @@ sk_sp<SkSpecialImage> SkColorFilterImageFilter::onFilterImage(SkSpecialImage* so
SkCanvas* canvas = surf->getCanvas();
SkASSERT(canvas);
- // TODO: it seems like this clear shouldn't be necessary (see skbug.com/5075)
- canvas->clear(0x0);
-
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
paint.setColorFilter(fColorFilter);
- input->draw(canvas,
- SkIntToScalar(inputOffset.fX - bounds.fLeft),
- SkIntToScalar(inputOffset.fY - bounds.fTop),
- &paint);
+ // TODO: it may not be necessary to clear or drawPaint inside the input bounds
+ // (see skbug.com/5075)
+ if (fColorFilter->affectsTransparentBlack()) {
+ // The subsequent input->draw() call may not fill the entire canvas. For filters which
+ // affect transparent black, ensure that the filter is applied everywhere.
+ canvas->drawPaint(paint);
+ } else {
+ canvas->clear(0x0);
+ }
+
+ if (input) {
+ input->draw(canvas,
+ SkIntToScalar(inputOffset.fX - bounds.fLeft),
+ SkIntToScalar(inputOffset.fY - bounds.fTop),
+ &paint);
+ }
offset->fX = bounds.fLeft;
offset->fY = bounds.fTop;
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index e6430b4d87..21ddc162d2 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -86,6 +86,36 @@ private:
typedef SkImageFilter INHERITED;
};
+class FailImageFilter : public SkImageFilter {
+public:
+ FailImageFilter() : SkImageFilter(0, nullptr) {
+ }
+
+ sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
+ const Context& ctx,
+ SkIPoint* offset) const override {
+ return nullptr;
+ }
+
+ SK_TO_STRING_OVERRIDE()
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
+
+private:
+ typedef SkImageFilter INHERITED;
+};
+
+sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
+ SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
+ return sk_sp<SkFlattenable>(new FailImageFilter());
+}
+
+#ifndef SK_IGNORE_TO_STRING
+void FailImageFilter::toString(SkString* str) const {
+ str->appendf("FailImageFilter: (");
+ str->append(")");
+}
+#endif
+
void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
SkScalar x = SkIntToScalar(width / 2);
SkScalar y = SkIntToScalar(height / 2);
@@ -673,6 +703,40 @@ DEF_GPUTEST_FOR_NATIVE_CONTEXT(TestZeroBlurSigma_Gpu, reporter, context) {
}
#endif
+
+// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
+// downstream filter that affects transparent black still does so even with a nullptr input.
+static void test_fail_affects_transparent_black(SkImageFilter::Proxy* proxy,
+ skiatest::Reporter* reporter,
+ GrContext* context) {
+ sk_sp<FailImageFilter> failFilter(new FailImageFilter());
+ sk_sp<SkSpecialImage> source(create_empty_special_image(context, proxy, 5));
+ SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr);
+ sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkXfermode::kSrc_Mode));
+ SkASSERT(green->affectsTransparentBlack());
+ sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Create(green.get(),
+ failFilter.get()));
+ SkIPoint offset;
+ sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
+ REPORTER_ASSERT(reporter, nullptr != result.get());
+ if (result.get()) {
+ SkBitmap resultBM;
+ TestingSpecialImageAccess::GetROPixels(result.get(), &resultBM);
+ SkAutoLockPixels lock(resultBM);
+ REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
+ }
+}
+
+DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
+ run_raster_test(reporter, 100, test_fail_affects_transparent_black);
+}
+
+#if SK_SUPPORT_GPU
+DEF_GPUTEST_FOR_NATIVE_CONTEXT(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, context) {
+ run_gpu_test(reporter, context, 100, test_fail_affects_transparent_black);
+}
+#endif
+
DEF_TEST(ImageFilterDrawTiled, reporter) {
// Check that all filters when drawn tiled (with subsequent clip rects) exactly
// match the same filters drawn with a single full-canvas bitmap draw.