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
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index e6430b4..21ddc16 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -86,6 +86,36 @@
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 @@
}
#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.