Add output format properties to SkImageFilter::Context

For now, this is just the color space (of the original
requesting device). This is used when constructing
intermediate rendering surfaces, so that we ensure we
land in a surface that's similar/compatible to the
final consumer of the DAG's output.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2357273002

Review-Url: https://codereview.chromium.org/2357273002
diff --git a/include/core/SkImageFilter.h b/include/core/SkImageFilter.h
index 97f84dc..9188a89 100644
--- a/include/core/SkImageFilter.h
+++ b/include/core/SkImageFilter.h
@@ -34,22 +34,42 @@
  */
 class SK_API SkImageFilter : public SkFlattenable {
 public:
+    // Extra information about the output of a filter DAG. For now, this is just the color space
+    // (of the original requesting device). This is used when constructing intermediate rendering
+    // surfaces, so that we ensure we land in a surface that's similar/compatible to the final
+    // consumer of the DAG's output.
+    class OutputProperties {
+    public:
+        explicit OutputProperties(SkColorSpace* colorSpace) : fColorSpace(colorSpace) {}
+
+        SkColorSpace* colorSpace() const { return fColorSpace; }
+
+    private:
+        // This will be a pointer to the device's color space, and our lifetime is bounded by
+        // the device, so we can store a bare pointer.
+        SkColorSpace* fColorSpace;
+    };
+
     class Context {
     public:
-        Context(const SkMatrix& ctm, const SkIRect& clipBounds, SkImageFilterCache* cache)
+        Context(const SkMatrix& ctm, const SkIRect& clipBounds, SkImageFilterCache* cache,
+                const OutputProperties& outputProperties)
             : fCTM(ctm)
             , fClipBounds(clipBounds)
             , fCache(cache)
+            , fOutputProperties(outputProperties)
         {}
 
         const SkMatrix& ctm() const { return fCTM; }
         const SkIRect& clipBounds() const { return fClipBounds; }
         SkImageFilterCache* cache() const { return fCache; }
+        const OutputProperties& outputProperties() const { return fOutputProperties; }
 
     private:
         SkMatrix               fCTM;
         SkIRect                fClipBounds;
         SkImageFilterCache*    fCache;
+        OutputProperties       fOutputProperties;
     };
 
     class CropRect {
@@ -130,10 +150,10 @@
                          MapDirection = kReverse_MapDirection) const;
 
 #if SK_SUPPORT_GPU
-    static sk_sp<SkSpecialImage> DrawWithFP(GrContext* context, 
+    static sk_sp<SkSpecialImage> DrawWithFP(GrContext* context,
                                             sk_sp<GrFragmentProcessor> fp,
                                             const SkIRect& bounds,
-                                            sk_sp<SkColorSpace> colorSpace);
+                                            const OutputProperties& outputProperties);
 #endif
 
     /**
diff --git a/include/effects/SkXfermodeImageFilter.h b/include/effects/SkXfermodeImageFilter.h
index 96d4fef..135c0f6 100644
--- a/include/effects/SkXfermodeImageFilter.h
+++ b/include/effects/SkXfermodeImageFilter.h
@@ -63,7 +63,8 @@
                                          const SkIPoint& backgroundOffset,
                                          sk_sp<SkSpecialImage> foreground,
                                          const SkIPoint& foregroundOffset,
-                                         const SkIRect& bounds) const;
+                                         const SkIRect& bounds,
+                                         const OutputProperties& outputProperties) const;
 #endif
 
     SkXfermodeImageFilter(sk_sp<SkXfermode> mode, sk_sp<SkImageFilter> inputs[2],
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index 4f8074d..440de68 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -395,7 +395,8 @@
         matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
         const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-x, -y);
         SkAutoTUnref<SkImageFilterCache> cache(this->getImageFilterCache());
-        SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
+        SkImageFilter::OutputProperties outputProperties(fBitmap.colorSpace());
+        SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
         
         sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset));
         if (resultImg) {
diff --git a/src/core/SkBlurImageFilter.cpp b/src/core/SkBlurImageFilter.cpp
index ccb3ed8..78fa071 100644
--- a/src/core/SkBlurImageFilter.cpp
+++ b/src/core/SkBlurImageFilter.cpp
@@ -157,6 +157,9 @@
         offset->fY = dstBounds.fTop;
         inputBounds.offset(-inputOffset);
         dstBounds.offset(-inputOffset);
+        // We intentionally use the source's color space, not the destination's (from ctx). We
+        // always blur in the source's config, so we need a compatible color space. We also want to
+        // avoid doing gamut conversion on every fetch of the texture.
         sk_sp<GrDrawContext> drawContext(SkGpuBlurUtils::GaussianBlur(
                                                                 context,
                                                                 inputTexture.get(),
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
index 64b6275..9ec6f2c 100644
--- a/src/core/SkImageFilter.cpp
+++ b/src/core/SkImageFilter.cpp
@@ -278,11 +278,12 @@
 sk_sp<SkSpecialImage> SkImageFilter::DrawWithFP(GrContext* context,
                                                 sk_sp<GrFragmentProcessor> fp,
                                                 const SkIRect& bounds,
-                                                sk_sp<SkColorSpace> colorSpace) {
+                                                const OutputProperties& outputProperties) {
     GrPaint paint;
     paint.addColorFragmentProcessor(std::move(fp));
     paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
 
+    sk_sp<SkColorSpace> colorSpace = sk_ref_sp(outputProperties.colorSpace());
     GrPixelConfig config = GrRenderableConfigForColorSpace(colorSpace.get());
     sk_sp<GrDrawContext> drawContext(context->makeDrawContext(SkBackingFit::kApprox,
                                                               bounds.width(), bounds.height(),
@@ -416,7 +417,7 @@
 SkImageFilter::Context SkImageFilter::mapContext(const Context& ctx) const {
     SkIRect clipBounds = this->onFilterNodeBounds(ctx.clipBounds(), ctx.ctm(),
                                                   MapDirection::kReverse_MapDirection);
-    return Context(ctx.ctm(), clipBounds, ctx.cache());
+    return Context(ctx.ctm(), clipBounds, ctx.cache(), ctx.outputProperties());
 }
 
 sk_sp<SkImageFilter> SkImageFilter::MakeMatrixFilter(const SkMatrix& matrix,
diff --git a/src/core/SkLocalMatrixImageFilter.cpp b/src/core/SkLocalMatrixImageFilter.cpp
index b4d5bb2..864b24b 100644
--- a/src/core/SkLocalMatrixImageFilter.cpp
+++ b/src/core/SkLocalMatrixImageFilter.cpp
@@ -45,7 +45,8 @@
 sk_sp<SkSpecialImage> SkLocalMatrixImageFilter::onFilterImage(SkSpecialImage* source,
                                                               const Context& ctx,
                                                               SkIPoint* offset) const {
-    Context localCtx(SkMatrix::Concat(ctx.ctm(), fLocalM), ctx.clipBounds(), ctx.cache());
+    Context localCtx(SkMatrix::Concat(ctx.ctm(), fLocalM), ctx.clipBounds(), ctx.cache(),
+                     ctx.outputProperties());
     return this->filterInput(0, source, localCtx, offset);
 }
 
diff --git a/src/effects/SkAlphaThresholdFilter.cpp b/src/effects/SkAlphaThresholdFilter.cpp
index 1f9a9cc..1d92aa5 100644
--- a/src/effects/SkAlphaThresholdFilter.cpp
+++ b/src/effects/SkAlphaThresholdFilter.cpp
@@ -177,7 +177,7 @@
             return nullptr;
         }
 
-        return DrawWithFP(context, std::move(fp), bounds, sk_ref_sp(input->getColorSpace()));
+        return DrawWithFP(context, std::move(fp), bounds, ctx.outputProperties());
     }
 #endif
 
diff --git a/src/effects/SkComposeImageFilter.cpp b/src/effects/SkComposeImageFilter.cpp
index a54e53b..a5b9190 100644
--- a/src/effects/SkComposeImageFilter.cpp
+++ b/src/effects/SkComposeImageFilter.cpp
@@ -38,7 +38,7 @@
     // filter requires as input. This matters if the outer filter moves pixels.
     SkIRect innerClipBounds;
     innerClipBounds = this->getInput(0)->filterBounds(ctx.clipBounds(), ctx.ctm());
-    Context innerContext(ctx.ctm(), innerClipBounds, ctx.cache());
+    Context innerContext(ctx.ctm(), innerClipBounds, ctx.cache(), ctx.outputProperties());
     SkIPoint innerOffset = SkIPoint::Make(0, 0);
     sk_sp<SkSpecialImage> inner(this->filterInput(1, source, innerContext, &innerOffset));
     if (!inner) {
@@ -49,7 +49,7 @@
     outerMatrix.postTranslate(SkIntToScalar(-innerOffset.x()), SkIntToScalar(-innerOffset.y()));
     SkIRect clipBounds = ctx.clipBounds();
     clipBounds.offset(-innerOffset.x(), -innerOffset.y());
-    Context outerContext(outerMatrix, clipBounds, ctx.cache());
+    Context outerContext(outerMatrix, clipBounds, ctx.cache(), ctx.outputProperties());
 
     SkIPoint outerOffset = SkIPoint::Make(0, 0);
     sk_sp<SkSpecialImage> outer(this->filterInput(0, inner.get(), outerContext, &outerOffset));
diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp
index 0f49a99..8fc0ec1 100644
--- a/src/effects/SkDisplacementMapEffect.cpp
+++ b/src/effects/SkDisplacementMapEffect.cpp
@@ -336,10 +336,11 @@
         SkMatrix matrix;
         matrix.setTranslate(-SkIntToScalar(colorBounds.x()), -SkIntToScalar(colorBounds.y()));
 
+        SkColorSpace* colorSpace = ctx.outputProperties().colorSpace();
         sk_sp<GrDrawContext> drawContext(
             context->makeDrawContext(SkBackingFit::kApprox, bounds.width(), bounds.height(),
-                                     GrRenderableConfigForColorSpace(source->getColorSpace()),
-                                     sk_ref_sp(source->getColorSpace())));
+                                     GrRenderableConfigForColorSpace(colorSpace),
+                                     sk_ref_sp(colorSpace)));
         if (!drawContext) {
             return nullptr;
         }
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index 3485bd8..138ba8b 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -360,7 +360,8 @@
     sk_sp<SkSpecialImage> filterImageGPU(SkSpecialImage* source, 
                                          SkSpecialImage* input,
                                          const SkIRect& bounds,
-                                         const SkMatrix& matrix) const;
+                                         const SkMatrix& matrix,
+                                         const OutputProperties& outputProperties) const;
     virtual sk_sp<GrFragmentProcessor> makeFragmentProcessor(GrTexture*,
                                                              const SkMatrix&,
                                                              const SkIRect* srcBounds,
@@ -399,10 +400,12 @@
     drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
 }
 
-sk_sp<SkSpecialImage> SkLightingImageFilterInternal::filterImageGPU(SkSpecialImage* source,
-                                                                    SkSpecialImage* input,
-                                                                    const SkIRect& offsetBounds,
-                                                                    const SkMatrix& matrix) const {
+sk_sp<SkSpecialImage> SkLightingImageFilterInternal::filterImageGPU(
+                                                   SkSpecialImage* source,
+                                                   SkSpecialImage* input,
+                                                   const SkIRect& offsetBounds,
+                                                   const SkMatrix& matrix,
+                                                   const OutputProperties& outputProperties) const {
     SkASSERT(source->isTextureBacked());
 
     GrContext* context = source->getContext();
@@ -412,8 +415,8 @@
 
     sk_sp<GrDrawContext> drawContext(
         context->makeDrawContext(SkBackingFit::kApprox,offsetBounds.width(), offsetBounds.height(),
-                                 GrRenderableConfigForColorSpace(source->getColorSpace()),
-                                 sk_ref_sp(source->getColorSpace())));
+                                 GrRenderableConfigForColorSpace(outputProperties.colorSpace()),
+                                 sk_ref_sp(outputProperties.colorSpace())));
     if (!drawContext) {
         return nullptr;
     }
@@ -1260,7 +1263,7 @@
         SkMatrix matrix(ctx.ctm());
         matrix.postTranslate(SkIntToScalar(-offset->fX), SkIntToScalar(-offset->fY));
 
-        return this->filterImageGPU(source, input.get(), bounds, matrix);
+        return this->filterImageGPU(source, input.get(), bounds, matrix, ctx.outputProperties());
     }
 #endif
 
@@ -1425,7 +1428,7 @@
         SkMatrix matrix(ctx.ctm());
         matrix.postTranslate(SkIntToScalar(-offset->fX), SkIntToScalar(-offset->fY));
 
-        return this->filterImageGPU(source, input.get(), bounds, matrix);
+        return this->filterImageGPU(source, input.get(), bounds, matrix, ctx.outputProperties());
     }
 #endif
 
diff --git a/src/effects/SkMagnifierImageFilter.cpp b/src/effects/SkMagnifierImageFilter.cpp
index eee9ce2..4b03125 100644
--- a/src/effects/SkMagnifierImageFilter.cpp
+++ b/src/effects/SkMagnifierImageFilter.cpp
@@ -337,7 +337,7 @@
             return nullptr;
         }
 
-        return DrawWithFP(context, std::move(fp), bounds, sk_ref_sp(input->getColorSpace()));
+        return DrawWithFP(context, std::move(fp), bounds, ctx.outputProperties());
     }
 #endif
 
diff --git a/src/effects/SkMatrixConvolutionImageFilter.cpp b/src/effects/SkMatrixConvolutionImageFilter.cpp
index 5e5f20b..5477d7a 100644
--- a/src/effects/SkMatrixConvolutionImageFilter.cpp
+++ b/src/effects/SkMatrixConvolutionImageFilter.cpp
@@ -328,7 +328,7 @@
             return nullptr;
         }
 
-        return DrawWithFP(context, std::move(fp), bounds, sk_ref_sp(input->getColorSpace()));
+        return DrawWithFP(context, std::move(fp), bounds, ctx.outputProperties());
     }
 #endif
 
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index f6d4001..b8d4884 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -469,14 +469,16 @@
     }
 }
 
-static sk_sp<SkSpecialImage> apply_morphology(GrContext* context,
-                                              SkSpecialImage* input,
-                                              const SkIRect& rect,
-                                              GrMorphologyEffect::MorphologyType morphType,
-                                              SkISize radius) {
+static sk_sp<SkSpecialImage> apply_morphology(
+                                          GrContext* context,
+                                          SkSpecialImage* input,
+                                          const SkIRect& rect,
+                                          GrMorphologyEffect::MorphologyType morphType,
+                                          SkISize radius,
+                                          const SkImageFilter::OutputProperties& outputProperties) {
     sk_sp<GrTexture> srcTexture(input->asTextureRef(context));
     SkASSERT(srcTexture);
-    sk_sp<SkColorSpace> colorSpace = sk_ref_sp(input->getColorSpace());
+    sk_sp<SkColorSpace> colorSpace = sk_ref_sp(outputProperties.colorSpace());
     GrPixelConfig config = GrRenderableConfigForColorSpace(colorSpace.get());
 
     // setup new clip
@@ -571,7 +573,8 @@
         auto type = (kDilate_Op == this->op()) ? GrMorphologyEffect::kDilate_MorphologyType
                                                : GrMorphologyEffect::kErode_MorphologyType;
         sk_sp<SkSpecialImage> result(apply_morphology(context, input.get(), srcBounds, type,
-                                                      SkISize::Make(width, height)));
+                                                      SkISize::Make(width, height),
+                                                      ctx.outputProperties()));
         if (result) {
             offset->fX = bounds.left();
             offset->fY = bounds.top();
diff --git a/src/effects/SkXfermodeImageFilter.cpp b/src/effects/SkXfermodeImageFilter.cpp
index 537175b..62daa5a 100644
--- a/src/effects/SkXfermodeImageFilter.cpp
+++ b/src/effects/SkXfermodeImageFilter.cpp
@@ -91,7 +91,7 @@
         return this->filterImageGPU(source,
                                     background, backgroundOffset, 
                                     foreground, foregroundOffset,
-                                    bounds);
+                                    bounds, ctx.outputProperties());
     }
 #endif
 
@@ -159,12 +159,14 @@
 
 #include "SkXfermode_proccoeff.h"
 
-sk_sp<SkSpecialImage> SkXfermodeImageFilter::filterImageGPU(SkSpecialImage* source,
-                                                            sk_sp<SkSpecialImage> background,
-                                                            const SkIPoint& backgroundOffset,
-                                                            sk_sp<SkSpecialImage> foreground,
-                                                            const SkIPoint& foregroundOffset,
-                                                            const SkIRect& bounds) const {
+sk_sp<SkSpecialImage> SkXfermodeImageFilter::filterImageGPU(
+                                                   SkSpecialImage* source,
+                                                   sk_sp<SkSpecialImage> background,
+                                                   const SkIPoint& backgroundOffset,
+                                                   sk_sp<SkSpecialImage> foreground,
+                                                   const SkIPoint& foregroundOffset,
+                                                   const SkIRect& bounds,
+                                                   const OutputProperties& outputProperties) const {
     SkASSERT(source->isTextureBacked());
 
     GrContext* context = source->getContext();
@@ -243,8 +245,8 @@
 
     sk_sp<GrDrawContext> drawContext(
         context->makeDrawContext(SkBackingFit::kApprox, bounds.width(), bounds.height(),
-                                 GrRenderableConfigForColorSpace(source->getColorSpace()),
-                                 sk_ref_sp(source->getColorSpace())));
+                                 GrRenderableConfigForColorSpace(outputProperties.colorSpace()),
+                                 sk_ref_sp(outputProperties.colorSpace())));
     if (!drawContext) {
         return nullptr;
     }
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 79b358c..a50b5c6 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -189,7 +189,8 @@
     matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top));
     const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-left, -top);
     SkAutoTUnref<SkImageFilterCache> cache(this->getImageFilterCache());
-    SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
+    SkImageFilter::OutputProperties outputProperties(fDrawContext->getColorSpace());
+    SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
 
     return filter->filterImage(srcImg, ctx, offset);
 }
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index 6e65050..2870f31 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -346,7 +346,9 @@
 
     SkAutoTUnref<SkImageFilterCache> cache(
         SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize));
-    SkImageFilter::Context context(SkMatrix::I(), clipBounds, cache.get());
+    SkImageFilter::OutputProperties outputProperties(as_IB(this)->onImageInfo().colorSpace());
+    SkImageFilter::Context context(SkMatrix::I(), clipBounds, cache.get(), outputProperties);
+
     sk_sp<SkSpecialImage> result =
         filter->filterImage(srcSpecialImage.get(), context, offset);
 
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index e79c915..eed4992 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -2288,7 +2288,10 @@
         matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
         const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-x, -y);
         SkAutoTUnref<SkImageFilterCache> cache(this->getImageFilterCache());
-        SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
+        // TODO: Should PDF be operating in a specified color space? For now, run the filter
+        // in the same color space as the source (this is different from all other backends).
+        SkImageFilter::OutputProperties outputProperties(srcImg->getColorSpace());
+        SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
 
         sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset));
         if (resultImg) {
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index 65ea8cf..fd83a6c 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -538,7 +538,8 @@
     for (int i = 0; i < filters.count(); ++i) {
         SkImageFilter* filter = filters.getFilter(i);
         SkIPoint offset;
-        SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
+        SkImageFilter::OutputProperties noColorSpace(nullptr);
+        SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
         sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
         REPORTER_ASSERT_MESSAGE(reporter, resultImg, filters.getName(i));
         REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
@@ -560,7 +561,8 @@
                                                                 gradient));
 
     SkIPoint offset;
-    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr);
+    SkImageFilter::OutputProperties noColorSpace(nullptr);
+    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
 
     sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
     REPORTER_ASSERT(reporter, positiveResult1);
@@ -570,7 +572,8 @@
 
     SkMatrix negativeScale;
     negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
-    SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr);
+    SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
+                                       noColorSpace);
 
     sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
                                                                       negativeCTX,
@@ -641,7 +644,8 @@
     sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
 
     SkIPoint offset;
-    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr);
+    SkImageFilter::OutputProperties noColorSpace(nullptr);
+    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
 
     sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
     REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
@@ -680,7 +684,8 @@
 static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
     sk_sp<FailImageFilter> failFilter(new FailImageFilter());
     sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
-    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr);
+    SkImageFilter::OutputProperties noColorSpace(nullptr);
+    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
     sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkXfermode::kSrc_Mode));
     SkASSERT(green->affectsTransparentBlack());
     sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
@@ -959,7 +964,9 @@
 
     sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
 
-    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr);
+    SkImageFilter::OutputProperties noColorSpace(nullptr);
+    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
+                               noColorSpace);
     SkIPoint offset;
 
     sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
@@ -1128,7 +1135,8 @@
     SkASSERT(srcImg);
 
     SkIPoint offset;
-    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
+    SkImageFilter::OutputProperties noColorSpace(nullptr);
+    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
     sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
     REPORTER_ASSERT(reporter, resultImg);
     REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
@@ -1262,7 +1270,8 @@
     sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
 
     SkIPoint offset;
-    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr);
+    SkImageFilter::OutputProperties noColorSpace(nullptr);
+    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
 
     sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
     REPORTER_ASSERT(reporter, !resultImage);
@@ -1518,7 +1527,8 @@
     sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
                                                                    std::move(offsetFilter)));
     SkIPoint offset;
-    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
+    SkImageFilter::OutputProperties noColorSpace(nullptr);
+    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
 
     sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
     REPORTER_ASSERT(reporter, resultImg);
@@ -1554,7 +1564,8 @@
                                                                    std::move(pictureFilter)));
 
     sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
-    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
+    SkImageFilter::OutputProperties noColorSpace(nullptr);
+    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
     SkIPoint offset;
     sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
     REPORTER_ASSERT(reporter, offset.isZero());
@@ -1584,7 +1595,8 @@
         SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
     sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
     SkIPoint offset;
-    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
+    SkImageFilter::OutputProperties noColorSpace(nullptr);
+    SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
 
     sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
     REPORTER_ASSERT(reporter, resultImg);