extend compose-colorfilter to 4f

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1664663003

Review URL: https://codereview.chromium.org/1664663003
diff --git a/gm/color4f.cpp b/gm/color4f.cpp
index 98ce082..e912654 100644
--- a/gm/color4f.cpp
+++ b/gm/color4f.cpp
@@ -32,10 +32,23 @@
     return SkColorMatrixFilter::Create(cm);
 }
 
+static SkColorFilter* make_cf1() {
+    SkColorMatrix cm;
+    cm.setSaturation(0.75f);
+    SkAutoTUnref<SkColorFilter> a(SkColorMatrixFilter::Create(cm));
+    // CreateComposedFilter will try to concat these two matrices, resulting in a single
+    // filter (which is good for speed). For this test, we want to force a real compose of
+    // these two, so our inner filter has a scale-up, which disables the optimization of
+    // combining the two matrices.
+    cm.setScale(1.1f, 0.9f, 1);
+    SkAutoTUnref<SkColorFilter> b(SkColorMatrixFilter::Create(cm));
+    return SkColorFilter::CreateComposeFilter(a, b);
+}
+
 static void draw_into_canvas(SkCanvas* canvas) {
     const SkRect r = SkRect::MakeWH(100, 100);
     SkShader* (*shaders[])() { make_opaque_color, make_alpha_color };
-    SkColorFilter* (*filters[])() { make_cf_null, make_cf0 };
+    SkColorFilter* (*filters[])() { make_cf_null, make_cf0, make_cf1 };
     
     SkPaint paint;
     for (auto shProc : shaders) {
@@ -48,7 +61,7 @@
     }
 }
 
-DEF_SIMPLE_GM(color4f, canvas, 510, 250) {
+DEF_SIMPLE_GM(color4f, canvas, 620, 260) {
     canvas->translate(20, 20);
 
     SkPaint bg;
@@ -58,7 +71,7 @@
 
     SkColorProfileType const profiles[] { kLinear_SkColorProfileType, kSRGB_SkColorProfileType };
     for (auto profile : profiles) {
-        const SkImageInfo info = SkImageInfo::Make(500, 100, kN32_SkColorType, kPremul_SkAlphaType,
+        const SkImageInfo info = SkImageInfo::Make(600, 100, kN32_SkColorType, kPremul_SkAlphaType,
                                                    profile);
         SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
         surface->getCanvas()->drawPaint(bg);
diff --git a/include/core/SkColor.h b/include/core/SkColor.h
index 461a538..90453f5 100644
--- a/include/core/SkColor.h
+++ b/include/core/SkColor.h
@@ -160,6 +160,8 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
+struct SkColor4f;
+
 /*
  *  The float values are 0...1 premultiplied
  */
@@ -174,6 +176,8 @@
 
     float a() const { return fVec[A]; }
 
+    SkColor4f unpremul() const;
+
     static SkPM4f FromPMColor(SkPMColor);
 
 #ifdef SK_DEBUG
diff --git a/include/core/SkColorFilter.h b/include/core/SkColorFilter.h
index 14192c5..ad97a73 100644
--- a/include/core/SkColorFilter.h
+++ b/include/core/SkColorFilter.h
@@ -102,6 +102,11 @@
      */
     SkColor filterColor(SkColor) const;
 
+    /**
+     *  Filters a single color.
+     */
+    SkColor4f filterColor4f(const SkColor4f&) const;
+
     /** Create a colorfilter that uses the specified color and mode.
         If the Mode is DST, this function will return NULL (since that
         mode will have no effect on the result).
diff --git a/src/core/SkColor.cpp b/src/core/SkColor.cpp
index 865fe0d..87e3a9d 100644
--- a/src/core/SkColor.cpp
+++ b/src/core/SkColor.cpp
@@ -111,6 +111,16 @@
     return c4;
 }
 
+SkColor4f SkPM4f::unpremul() const {
+    float alpha = fVec[A];
+    if (0 == alpha) {
+        return { 0, 0, 0, 0 };
+    } else {
+        float invAlpha = 1 / alpha;
+        return { alpha, fVec[R] * invAlpha, fVec[G] * invAlpha, fVec[B] * invAlpha };
+    }
+}
+
 SkColor4f SkColor4f::FromColor(SkColor c) {
     Sk4f value = SkNx_shuffle<3,2,1,0>(SkNx_cast<float>(Sk4b::Load(&c)));
     SkColor4f c4;
diff --git a/src/core/SkColorFilter.cpp b/src/core/SkColorFilter.cpp
index 4bfacfe..72f5470 100644
--- a/src/core/SkColorFilter.cpp
+++ b/src/core/SkColorFilter.cpp
@@ -29,14 +29,24 @@
     return false;
 }
 
+void SkColorFilter::filterSpan4f(const SkPM4f[], int count, SkPM4f[]) const {
+    if (this->supports4f()) {
+        SkASSERT(false && "colorfilter supports4f but didn't override");
+    } else {
+        SkASSERT(false && "filterSpan4f called but not supported");
+    }
+}
+
 SkColor SkColorFilter::filterColor(SkColor c) const {
     SkPMColor dst, src = SkPreMultiplyColor(c);
     this->filterSpan(&src, 1, &dst);
     return SkUnPreMultiply::PMColorToColor(dst);
 }
 
-void SkColorFilter::filterSpan4f(const SkPM4f[], int count, SkPM4f[]) const {
-    SkASSERT(false && "filterSpan4f called but not implemented");
+SkColor4f SkColorFilter::filterColor4f(const SkColor4f& c) const {
+    SkPM4f dst, src = c.premul();
+    this->filterSpan4f(&src, 1, &dst);
+    return dst.unpremul();
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -54,7 +64,7 @@
 class SkComposeColorFilter : public SkColorFilter {
 public:
     uint32_t getFlags() const override {
-        // Can only claim alphaunchanged and 16bit support if both our proxys do.
+        // Can only claim alphaunchanged and SkPM4f support if both our proxys do.
         return fOuter->getFlags() & fInner->getFlags();
     }
     
@@ -63,6 +73,13 @@
         fOuter->filterSpan(result, count, result);
     }
     
+    void filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const override {
+        SkASSERT(fInner->supports4f());
+        SkASSERT(fOuter->supports4f());
+        fInner->filterSpan4f(shader, count, result);
+        fOuter->filterSpan4f(result, count, result);
+    }
+    
 #ifndef SK_IGNORE_TO_STRING
     void toString(SkString* str) const override {
         SkString outerS, innerS;