Clean up GrColorSpaceXformEffect to allow a null child FP.

Previously, GrColorSpaceXformEffect had separate Make methods; one took
a child FP, the other did not, and they had slightly different color-
transform inputs (the destination alpha type was assumed to be premul
when a child FP was provided). A null FP was considered invalid.

This has been updated to work more like other FPs. An childFP must
always be supplied, and nullptr is interpreted as "use the sk_InColor".
The destination alpha type is now always supplied. Existing call sites
were fixed up as needed.

Previously, the child-FP path would actually render the product of the
child FP and the sk_InColor. This extra multiplication step no longer
occurs; the sk_InColor is simply ignored when a child FP is used. In
practice, this did not affect any existing GM tests.

Change-Id: Id53449234948255cbdaab9b88b1c94201eeb0a0d
Bug: skia:10217
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/299576
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
diff --git a/src/core/SkColorFilter.cpp b/src/core/SkColorFilter.cpp
index a0800f3..31f58ba 100644
--- a/src/core/SkColorFilter.cpp
+++ b/src/core/SkColorFilter.cpp
@@ -255,10 +255,12 @@
         SkAlphaType at = kPremul_SkAlphaType;
         switch (fDir) {
             case Direction::kLinearToSRGB:
-                return GrColorSpaceXformEffect::Make(sk_srgb_linear_singleton(), at,
+                return GrColorSpaceXformEffect::Make(/*childFP=*/nullptr,
+                                                     sk_srgb_linear_singleton(), at,
                                                      sk_srgb_singleton(),        at);
             case Direction::kSRGBToLinear:
-                return GrColorSpaceXformEffect::Make(sk_srgb_singleton(),        at,
+                return GrColorSpaceXformEffect::Make(/*childFP=*/nullptr,
+                                                     sk_srgb_singleton(),        at,
                                                      sk_srgb_linear_singleton(), at);
         }
         return nullptr;
diff --git a/src/effects/imagefilters/SkAlphaThresholdFilter.cpp b/src/effects/imagefilters/SkAlphaThresholdFilter.cpp
index 3f43373..0df8dc1 100644
--- a/src/effects/imagefilters/SkAlphaThresholdFilter.cpp
+++ b/src/effects/imagefilters/SkAlphaThresholdFilter.cpp
@@ -168,8 +168,9 @@
         auto textureFP = GrTextureEffect::Make(
                 std::move(inputView), input->alphaType(),
                 SkMatrix::Translate(input->subset().x(), input->subset().y()));
-        textureFP = GrColorSpaceXformEffect::Make(std::move(textureFP), input->getColorSpace(),
-                                                  input->alphaType(), ctx.colorSpace());
+        textureFP = GrColorSpaceXformEffect::Make(std::move(textureFP),
+                                                  input->getColorSpace(), input->alphaType(),
+                                                  ctx.colorSpace(), kPremul_SkAlphaType);
         if (!textureFP) {
             return nullptr;
         }
diff --git a/src/effects/imagefilters/SkArithmeticImageFilter.cpp b/src/effects/imagefilters/SkArithmeticImageFilter.cpp
index ae7ff48..2d61cf0 100644
--- a/src/effects/imagefilters/SkArithmeticImageFilter.cpp
+++ b/src/effects/imagefilters/SkArithmeticImageFilter.cpp
@@ -358,9 +358,9 @@
                 SkIntToScalar(bgSubset.top()  - backgroundOffset.fY));
         bgFP = GrTextureEffect::MakeSubset(std::move(backgroundView), background->alphaType(),
                                            backgroundMatrix, sampler, bgSubset, caps);
-        bgFP = GrColorSpaceXformEffect::Make(std::move(bgFP), background->getColorSpace(),
-                                             background->alphaType(),
-                                             ctx.colorSpace());
+        bgFP = GrColorSpaceXformEffect::Make(std::move(bgFP),
+                                             background->getColorSpace(), background->alphaType(),
+                                             ctx.colorSpace(), kPremul_SkAlphaType);
     } else {
         bgFP = GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT,
                                            GrConstColorProcessor::InputMode::kIgnore);
@@ -374,9 +374,8 @@
         auto fgFP = GrTextureEffect::MakeSubset(std::move(foregroundView), foreground->alphaType(),
                                                 foregroundMatrix, sampler, fgSubset, caps);
         fgFP = GrColorSpaceXformEffect::Make(std::move(fgFP),
-                                             foreground->getColorSpace(),
-                                             foreground->alphaType(),
-                                             ctx.colorSpace());
+                                             foreground->getColorSpace(), foreground->alphaType(),
+                                             ctx.colorSpace(), kPremul_SkAlphaType);
         paint.addColorFragmentProcessor(std::move(fgFP));
 
         static auto effect = std::get<0>(SkRuntimeEffect::Make(SkString(SKSL_ARITHMETIC_SRC)));
diff --git a/src/effects/imagefilters/SkDisplacementMapEffect.cpp b/src/effects/imagefilters/SkDisplacementMapEffect.cpp
index febbf41..d50d2ad 100644
--- a/src/effects/imagefilters/SkDisplacementMapEffect.cpp
+++ b/src/effects/imagefilters/SkDisplacementMapEffect.cpp
@@ -346,8 +346,9 @@
                                               std::move(colorView),
                                               color->subset(),
                                               *context->priv().caps());
-        fp = GrColorSpaceXformEffect::Make(std::move(fp), color->getColorSpace(),
-                                           color->alphaType(), ctx.colorSpace());
+        fp = GrColorSpaceXformEffect::Make(std::move(fp),
+                                           color->getColorSpace(), color->alphaType(),
+                                           ctx.colorSpace(), kPremul_SkAlphaType);
 
         GrPaint paint;
         paint.addColorFragmentProcessor(std::move(fp));
diff --git a/src/effects/imagefilters/SkMagnifierImageFilter.cpp b/src/effects/imagefilters/SkMagnifierImageFilter.cpp
index 4300a39..aaabc3b 100644
--- a/src/effects/imagefilters/SkMagnifierImageFilter.cpp
+++ b/src/effects/imagefilters/SkMagnifierImageFilter.cpp
@@ -144,8 +144,9 @@
                                           invYZoom,
                                           bounds.width() * invInset,
                                           bounds.height() * invInset);
-        fp = GrColorSpaceXformEffect::Make(std::move(fp), input->getColorSpace(),
-                                           input->alphaType(), ctx.colorSpace());
+        fp = GrColorSpaceXformEffect::Make(std::move(fp),
+                                           input->getColorSpace(), input->alphaType(),
+                                           ctx.colorSpace(), kPremul_SkAlphaType);
         if (!fp) {
             return nullptr;
         }
diff --git a/src/effects/imagefilters/SkXfermodeImageFilter.cpp b/src/effects/imagefilters/SkXfermodeImageFilter.cpp
index 7569e17..89fe7f2 100644
--- a/src/effects/imagefilters/SkXfermodeImageFilter.cpp
+++ b/src/effects/imagefilters/SkXfermodeImageFilter.cpp
@@ -268,9 +268,9 @@
                 SkIntToScalar(bgSubset.top()  - backgroundOffset.fY));
         bgFP = GrTextureEffect::MakeSubset(std::move(backgroundView), background->alphaType(),
                                            bgMatrix, sampler, bgSubset, caps);
-        bgFP = GrColorSpaceXformEffect::Make(std::move(bgFP), background->getColorSpace(),
-                                             background->alphaType(),
-                                             ctx.colorSpace());
+        bgFP = GrColorSpaceXformEffect::Make(std::move(bgFP),
+                                             background->getColorSpace(), background->alphaType(),
+                                             ctx.colorSpace(), kPremul_SkAlphaType);
     } else {
         bgFP = GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT,
                                            GrConstColorProcessor::InputMode::kIgnore);
@@ -284,9 +284,8 @@
         auto fgFP = GrTextureEffect::MakeSubset(std::move(foregroundView), foreground->alphaType(),
                                                 fgMatrix, sampler, fgSubset, caps);
         fgFP = GrColorSpaceXformEffect::Make(std::move(fgFP),
-                                             foreground->getColorSpace(),
-                                             foreground->alphaType(),
-                                             ctx.colorSpace());
+                                             foreground->getColorSpace(), foreground->alphaType(),
+                                             ctx.colorSpace(), kPremul_SkAlphaType);
         paint.addColorFragmentProcessor(std::move(fgFP));
 
         std::unique_ptr<GrFragmentProcessor> xferFP = this->makeFGFrag(std::move(bgFP));
diff --git a/src/gpu/GrColorSpaceXform.cpp b/src/gpu/GrColorSpaceXform.cpp
index b602b32..8b1d234 100644
--- a/src/gpu/GrColorSpaceXform.cpp
+++ b/src/gpu/GrColorSpaceXform.cpp
@@ -58,31 +58,26 @@
 class GrGLColorSpaceXformEffect : public GrGLSLFragmentProcessor {
 public:
     void emitCode(EmitArgs& args) override {
-        const GrColorSpaceXformEffect& csxe = args.fFp.cast<GrColorSpaceXformEffect>();
+        const GrColorSpaceXformEffect& proc = args.fFp.cast<GrColorSpaceXformEffect>();
         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
         GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
 
-        fColorSpaceHelper.emitCode(uniformHandler, csxe.colorXform());
+        fColorSpaceHelper.emitCode(uniformHandler, proc.colorXform());
 
-        if (this->numChildProcessors()) {
-            SkString childColor = this->invokeChild(0, args);
+        SkString childColor = this->numChildProcessors()
+                     ? this->invokeChild(0, args.fInputColor, args)
+                     : SkString(args.fInputColor);
 
-            SkString xformedColor;
-            fragBuilder->appendColorGamutXform(&xformedColor, childColor.c_str(), &fColorSpaceHelper);
-            fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputColor, xformedColor.c_str(),
-                                     args.fInputColor);
-        } else {
-            SkString xformedColor;
-            fragBuilder->appendColorGamutXform(&xformedColor, args.fInputColor, &fColorSpaceHelper);
-            fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, xformedColor.c_str());
-        }
+        SkString xformedColor;
+        fragBuilder->appendColorGamutXform(&xformedColor, childColor.c_str(), &fColorSpaceHelper);
+        fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, xformedColor.c_str());
     }
 
 private:
     void onSetData(const GrGLSLProgramDataManager& pdman,
-                   const GrFragmentProcessor& processor) override {
-        const GrColorSpaceXformEffect& csxe = processor.cast<GrColorSpaceXformEffect>();
-        fColorSpaceHelper.setData(pdman, csxe.colorXform());
+                   const GrFragmentProcessor& fp) override {
+        const GrColorSpaceXformEffect& proc = fp.cast<GrColorSpaceXformEffect>();
+        fColorSpaceHelper.setData(pdman, proc.colorXform());
     }
 
     GrGLSLColorSpaceXformHelper fColorSpaceHelper;
@@ -101,11 +96,14 @@
     }
 }
 
+GrColorSpaceXformEffect::GrColorSpaceXformEffect(const GrColorSpaceXformEffect& that)
+        : INHERITED(kGrColorSpaceXformEffect_ClassID, that.optimizationFlags())
+        , fColorXform(that.fColorXform) {
+    this->cloneAndRegisterAllChildProcessors(that);
+}
+
 std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::clone() const {
-    std::unique_ptr<GrFragmentProcessor> child =
-            this->numChildProcessors() ? this->childProcessor(0).clone() : nullptr;
-    return std::unique_ptr<GrFragmentProcessor>(
-            new GrColorSpaceXformEffect(std::move(child), fColorXform));
+    return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(*this));
 }
 
 bool GrColorSpaceXformEffect::onIsEqual(const GrFragmentProcessor& s) const {
@@ -124,23 +122,10 @@
 
 GrFragmentProcessor::OptimizationFlags GrColorSpaceXformEffect::OptFlags(
         const GrFragmentProcessor* child) {
-    if (child) {
-        OptimizationFlags flags = kNone_OptimizationFlags;
-        if (child->compatibleWithCoverageAsAlpha()) {
-            flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag;
-        }
-        if (child->preservesOpaqueInput()) {
-            flags |= kPreservesOpaqueInput_OptimizationFlag;
-        }
-        if (child->hasConstantOutputForConstantInput()) {
-            flags |= kConstantOutputForConstantInput_OptimizationFlag;
-        }
-        return flags;
-    } else {
-        return kCompatibleWithCoverageAsAlpha_OptimizationFlag |
+    return (child ? ProcessorOptimizationFlags(child) : kAll_OptimizationFlags) &
+              (kCompatibleWithCoverageAsAlpha_OptimizationFlag |
                kPreservesOpaqueInput_OptimizationFlag |
-               kConstantOutputForConstantInput_OptimizationFlag;
-    }
+               kConstantOutputForConstantInput_OptimizationFlag);
 }
 
 SkPMColor4f GrColorSpaceXformEffect::constantOutputForConstantInput(
@@ -151,42 +136,16 @@
     return this->fColorXform->apply(c0.unpremul()).premul();
 }
 
-std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(SkColorSpace* src,
-                                                                   SkAlphaType srcAT,
-                                                                   SkColorSpace* dst,
-                                                                   SkAlphaType dstAT) {
-    auto xform = GrColorSpaceXform::Make(src, srcAT,
-                                         dst, dstAT);
-    if (!xform) {
-        return nullptr;
-    }
-
-    return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(nullptr,
-                                                                            std::move(xform)));
+std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
+        std::unique_ptr<GrFragmentProcessor> child,
+        SkColorSpace* src, SkAlphaType srcAT,
+        SkColorSpace* dst, SkAlphaType dstAT) {
+    return Make(std::move(child), GrColorSpaceXform::Make(src, srcAT, dst, dstAT));
 }
 
 std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
         std::unique_ptr<GrFragmentProcessor> child,
-        SkColorSpace* src, SkAlphaType srcAT, SkColorSpace* dst) {
-    if (!child) {
-        return nullptr;
-    }
-
-    auto xform = GrColorSpaceXform::Make(src, srcAT,
-                                         dst, kPremul_SkAlphaType);
-    if (!xform) {
-        return child;
-    }
-
-    return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(std::move(child),
-                                                                            std::move(xform)));
-}
-
-std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
-        std::unique_ptr<GrFragmentProcessor> child, sk_sp<GrColorSpaceXform> colorXform) {
-    if (!child) {
-        return nullptr;
-    }
+        sk_sp<GrColorSpaceXform> colorXform) {
     if (!colorXform) {
         return child;
     }
diff --git a/src/gpu/GrColorSpaceXform.h b/src/gpu/GrColorSpaceXform.h
index 9d540e4..63b5aa0 100644
--- a/src/gpu/GrColorSpaceXform.h
+++ b/src/gpu/GrColorSpaceXform.h
@@ -60,22 +60,17 @@
 class GrColorSpaceXformEffect : public GrFragmentProcessor {
 public:
     /**
-     *  Returns a fragment processor that converts the input's color space from src to dst.
-     */
-    static std::unique_ptr<GrFragmentProcessor> Make(SkColorSpace* src, SkAlphaType srcAT,
-                                                     SkColorSpace* dst, SkAlphaType dstAT);
-
-    /**
      *  Returns a fragment processor that calls the passed in fragment processor, and then converts
-     *  the color space of the output from src to dst.
+     *  the color space of the output from src to dst. If the child is null, sk_InColor is used.
      */
     static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child,
                                                      SkColorSpace* src, SkAlphaType srcAT,
-                                                     SkColorSpace* dst);
+                                                     SkColorSpace* dst, SkAlphaType dstAT);
 
     /**
      * Returns a fragment processor that calls the passed in FP and then converts it with the given
-     * color xform. Returns null if child is null, returns child if the xform is null (e.g. noop).
+     * color xform. If the child is null, sk_InColor is used. Returns child as-is if the xform is
+     * null (i.e. a no-op).
      */
     static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child,
                                                      sk_sp<GrColorSpaceXform> colorXform);
@@ -89,6 +84,8 @@
     GrColorSpaceXformEffect(std::unique_ptr<GrFragmentProcessor> child,
                             sk_sp<GrColorSpaceXform> colorXform);
 
+    GrColorSpaceXformEffect(const GrColorSpaceXformEffect& that);
+
     static OptimizationFlags OptFlags(const GrFragmentProcessor* child);
     SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override;
 
diff --git a/src/gpu/GrImageTextureMaker.cpp b/src/gpu/GrImageTextureMaker.cpp
index 6ff41e3..ebd12c4 100644
--- a/src/gpu/GrImageTextureMaker.cpp
+++ b/src/gpu/GrImageTextureMaker.cpp
@@ -104,8 +104,9 @@
                                    GrBicubicEffect::Direction::kXY);
     }
     if (fImage->fFromColorSpace) {
-        fp = GrColorSpaceXformEffect::Make(std::move(fp), fImage->fFromColorSpace.get(),
-                                           fImage->alphaType(), fImage->colorSpace());
+        fp = GrColorSpaceXformEffect::Make(std::move(fp),
+                                           fImage->fFromColorSpace.get(), fImage->alphaType(),
+                                           fImage->colorSpace(), kPremul_SkAlphaType);
     }
     return fp;
 }
diff --git a/src/gpu/GrYUVProvider.cpp b/src/gpu/GrYUVProvider.cpp
index 3d5668c..2efe8ed 100644
--- a/src/gpu/GrYUVProvider.cpp
+++ b/src/gpu/GrYUVProvider.cpp
@@ -172,18 +172,16 @@
 
     GrPaint paint;
     const auto& caps = *ctx->priv().caps();
-    auto yuvToRgbProcessor = GrYUVtoRGBEffect::Make(yuvViews, yuvaIndices, yuvColorSpace,
-                                                    GrSamplerState::Filter::kNearest, caps);
-    paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor));
+    std::unique_ptr<GrFragmentProcessor> yuvToRgbProcessor = GrYUVtoRGBEffect::Make(
+            yuvViews, yuvaIndices, yuvColorSpace, GrSamplerState::Filter::kNearest, caps);
 
     // If the caller expects the pixels in a different color space than the one from the image,
     // apply a color conversion to do this.
     std::unique_ptr<GrFragmentProcessor> colorConversionProcessor =
-            GrColorSpaceXformEffect::Make(srcColorSpace, kOpaque_SkAlphaType,
+            GrColorSpaceXformEffect::Make(std::move(yuvToRgbProcessor),
+                                          srcColorSpace, kOpaque_SkAlphaType,
                                           dstColorSpace, kOpaque_SkAlphaType);
-    if (colorConversionProcessor) {
-        paint.addColorFragmentProcessor(std::move(colorConversionProcessor));
-    }
+    paint.addColorFragmentProcessor(std::move(colorConversionProcessor));
 
     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
     const SkRect r = SkRect::MakeIWH(yuvSizeInfo.fSizes[0].fWidth,
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 585b530..700ef68 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -663,8 +663,10 @@
     tmpUnfiltered.setImageFilter(nullptr);
 
     auto fp = GrTextureEffect::Make(std::move(view), special->alphaType());
-    fp = GrColorSpaceXformEffect::Make(std::move(fp), result->getColorSpace(), result->alphaType(),
-                                       fRenderTargetContext->colorInfo().colorSpace());
+    fp = GrColorSpaceXformEffect::Make(
+            std::move(fp),
+            result->getColorSpace(), result->alphaType(),
+            fRenderTargetContext->colorInfo().colorSpace(), kPremul_SkAlphaType);
     if (GrColorTypeIsAlphaOnly(SkColorTypeToGrColorType(result->colorType()))) {
         fp = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp));
     } else {
diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp
index 4c4a2aa..f68abf3 100644
--- a/src/gpu/SkGpuDevice_drawTexture.cpp
+++ b/src/gpu/SkGpuDevice_drawTexture.cpp
@@ -462,8 +462,9 @@
     }
     auto fp = producer->createFragmentProcessor(textureMatrix, src, constraintMode,
                                                 coordsAllInsideSrcRect, wm, wm, filterMode);
-    fp = GrColorSpaceXformEffect::Make(std::move(fp), producer->colorSpace(), producer->alphaType(),
-                                       rtc->colorInfo().colorSpace());
+    fp = GrColorSpaceXformEffect::Make(std::move(fp),
+                                       producer->colorSpace(), producer->alphaType(),
+                                       rtc->colorInfo().colorSpace(), kPremul_SkAlphaType);
     if (!fp) {
         return;
     }
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index 914810d..1ce084f 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -87,7 +87,8 @@
         return nullptr;
     }
 
-    auto xform = GrColorSpaceXformEffect::Make(this->colorSpace(), this->alphaType(),
+    auto xform = GrColorSpaceXformEffect::Make(/*childFP=*/nullptr,
+                                               this->colorSpace(), this->alphaType(),
                                                targetCS.get(), this->alphaType());
     SkASSERT(xform || targetCT != this->colorType());
 
diff --git a/src/shaders/SkImageShader.cpp b/src/shaders/SkImageShader.cpp
index f697b74..698f22a 100755
--- a/src/shaders/SkImageShader.cpp
+++ b/src/shaders/SkImageShader.cpp
@@ -246,7 +246,7 @@
         inner = GrTextureEffect::Make(std::move(view), srcAlphaType, lmInverse, samplerState, caps);
     }
     inner = GrColorSpaceXformEffect::Make(std::move(inner), fImage->colorSpace(), srcAlphaType,
-                                          args.fDstColorInfo->colorSpace());
+                                          args.fDstColorInfo->colorSpace(), kPremul_SkAlphaType);
 
     bool isAlphaOnly = SkColorTypeIsAlphaOnly(fImage->colorType());
     if (isAlphaOnly) {