rough clamped tracking in SkRasterPipeline

This should make srgb_color_filter draw correctly in software.
Previously the Rec2020 block would overflow.

Change-Id: Ied4516728039e54214886d55bba92662beee9a26
Reviewed-on: https://skia-review.googlesource.com/26562
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Mike Klein <mtklein@chromium.org>
diff --git a/src/core/SkRasterPipeline.cpp b/src/core/SkRasterPipeline.cpp
index a7b25d7..5484c9f 100644
--- a/src/core/SkRasterPipeline.cpp
+++ b/src/core/SkRasterPipeline.cpp
@@ -15,6 +15,7 @@
     fStages      = nullptr;
     fNumStages   = 0;
     fSlotsNeeded = 1;  // We always need one extra slot for just_return().
+    fClamped     = true;
 }
 
 void SkRasterPipeline::append(StockStage stage, void* ctx) {
@@ -46,6 +47,7 @@
     fStages = &stages[src.fNumStages - 1];
     fNumStages   += src.fNumStages;
     fSlotsNeeded += src.fSlotsNeeded - 1;  // Don't double count just_returns().
+    fClamped = fClamped && src.fClamped;
 }
 
 void SkRasterPipeline::dump() const {
@@ -162,3 +164,12 @@
         }
     }
 }
+
+void SkRasterPipeline::clamp_if_unclamped(SkAlphaType alphaType) {
+    if (!fClamped) {
+        this->append(SkRasterPipeline::clamp_0);
+        this->append(alphaType == kPremul_SkAlphaType ? SkRasterPipeline::clamp_a
+                                                      : SkRasterPipeline::clamp_1);
+        fClamped = true;
+    }
+}
diff --git a/src/core/SkRasterPipeline.h b/src/core/SkRasterPipeline.h
index 4e2feb3..e9cb886 100644
--- a/src/core/SkRasterPipeline.h
+++ b/src/core/SkRasterPipeline.h
@@ -138,6 +138,11 @@
 
     bool empty() const { return fStages == nullptr; }
 
+    // Used to track if we're handling values outside [0.0f, 1.0f],
+    // and to clamp back to [0.0f, 1.0f] if so.
+    void set_clamped(bool clamped) { fClamped = clamped; }
+    void clamp_if_unclamped(SkAlphaType);
+
 private:
     struct StageList {
         StageList* prev;
@@ -152,6 +157,7 @@
     StageList*    fStages;
     int           fNumStages;
     int           fSlotsNeeded;
+    bool          fClamped;
 };
 
 template <size_t bytes>
diff --git a/src/core/SkRasterPipelineBlitter.cpp b/src/core/SkRasterPipelineBlitter.cpp
index 993d735..158217e 100644
--- a/src/core/SkRasterPipelineBlitter.cpp
+++ b/src/core/SkRasterPipelineBlitter.cpp
@@ -256,6 +256,10 @@
         p->append(SkRasterPipeline::dither, &fDitherRate);
     }
 
+    if (fDst.info().colorType() != kRGBA_F16_SkColorType) {
+        p->clamp_if_unclamped(kPremul_SkAlphaType);
+    }
+
     switch (fDst.info().colorType()) {
         case kGray_8_SkColorType:    p->append(SkRasterPipeline::luminance_to_alpha); // fallthru
         case kAlpha_8_SkColorType:   p->append(SkRasterPipeline::store_a8,   &fDstPtr); break;
@@ -318,6 +322,7 @@
                 && !fDst.colorSpace()
                 && fDst.info().alphaType() != kUnpremul_SkAlphaType
                 && fDitherRate == 0.0f) {
+            p.clamp_if_unclamped(kPremul_SkAlphaType);
             p.append(SkRasterPipeline::srcover_rgba_8888, &fDstPtr);
         } else {
             if (fBlend != SkBlendMode::kSrc) {
diff --git a/src/effects/SkToSRGBColorFilter.cpp b/src/effects/SkToSRGBColorFilter.cpp
index 7b96fcc..f2ffc08 100644
--- a/src/effects/SkToSRGBColorFilter.cpp
+++ b/src/effects/SkToSRGBColorFilter.cpp
@@ -39,11 +39,18 @@
     }
 
     // Step 2: Transform to sRGB gamut, without clamping.
+    float* gamut_transform = alloc->makeArrayDefault<float>(12);
     (void)append_gamut_transform_noclamp(p,
-                                         alloc->makeArrayDefault<float>(12),
+                                         gamut_transform,
                                          fSrcColorSpace.get(),
                                          SkColorSpace::MakeSRGB().get());
 
+    bool needs_clamp_0, needs_clamp_1;
+    analyze_3x4_matrix(gamut_transform, &needs_clamp_0, &needs_clamp_1);
+    if (needs_clamp_0 || needs_clamp_1) {
+        p->set_clamped(false);
+    }
+
     // Step 3: Back to sRGB encoding.
     p->append(SkRasterPipeline::to_srgb);
 }