add srgb gamma colorfilters
... faster and more accurate than using SkTableColorFilter

todo: update blink after this lands

Bug:737981
Change-Id: I55b5c60dd23b9d2cbe9d60f83c74be1a8f3dcfcf
Reviewed-on: https://skia-review.googlesource.com/21368
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
diff --git a/include/core/SkColorFilter.h b/include/core/SkColorFilter.h
index 1033a72..68142a2 100644
--- a/include/core/SkColorFilter.h
+++ b/include/core/SkColorFilter.h
@@ -113,6 +113,14 @@
      */
     static sk_sp<SkColorFilter> MakeMatrixFilterRowMajor255(const SkScalar array[20]);
 
+    /** Construct a colorfilter that applies the srgb gamma curve to the RGB channels */
+    static sk_sp<SkColorFilter> MakeLinearToSRGBGamma();
+
+    /** Construct a colorfilter that applies the inverse of the srgb gamma curve to the
+     *  RGB channels
+     */
+    static sk_sp<SkColorFilter> MakeSRGBToLinearGamma();
+
 #if SK_SUPPORT_GPU
     /**
      *  A subclass may implement this factory function to work with the GPU backend. It returns
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index dde939b..1676fc3 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -370,7 +370,7 @@
             SkPaint gammaPaint;
             gammaPaint.setBlendMode(SkBlendMode::kSrc);
             if (doGamma) {
-                gammaPaint.setColorFilter(sk_tool_utils::MakeLinearToSRGBColorFilter());
+                gammaPaint.setColorFilter(SkColorFilter::MakeLinearToSRGBGamma());
             }
 
             gpuCanvas->drawImage(offscreenImage, 0, 0, &gammaPaint);
diff --git a/src/core/SkColorFilter.cpp b/src/core/SkColorFilter.cpp
index a107a06..3da812a 100644
--- a/src/core/SkColorFilter.cpp
+++ b/src/core/SkColorFilter.cpp
@@ -174,8 +174,6 @@
     return MakeComposeFilter(std::move(outer), std::move(inner));
 }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
 sk_sp<SkColorFilter> SkColorFilter::MakeComposeFilter(sk_sp<SkColorFilter> outer,
                                                       sk_sp<SkColorFilter> inner) {
     if (!outer) {
@@ -198,9 +196,91 @@
     return sk_sp<SkColorFilter>(new SkComposeColorFilter(std::move(outer), std::move(inner),count));
 }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+#if SK_SUPPORT_GPU
+#include "../gpu/effects/GrSRGBEffect.h"
+#endif
+
+class SkSRGBGammaColorFilter : public SkColorFilter {
+public:
+    enum class Direction {
+        kLinearToSRGB,
+        kSRGBToLinear,
+    };
+    SkSRGBGammaColorFilter(Direction dir) : fDir(dir) {}
+
+#if SK_SUPPORT_GPU
+    sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext* x, SkColorSpace* cs) const override {
+        switch (fDir) {
+            case Direction::kLinearToSRGB:
+                return GrSRGBEffect::Make(GrSRGBEffect::Mode::kLinearToSRGB);
+            case Direction::kSRGBToLinear:
+                return GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear);
+        }
+        return nullptr;
+    }
+#endif
+
+    SK_TO_STRING_OVERRIDE()
+
+    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSRGBGammaColorFilter)
+
+    void onAppendStages(SkRasterPipeline* p, SkColorSpace*, SkArenaAlloc* alloc,
+                        bool shaderIsOpaque) const override {
+        switch (fDir) {
+            case Direction::kLinearToSRGB:
+                p->append(SkRasterPipeline::to_srgb);
+                break;
+            case Direction::kSRGBToLinear:
+                p->append_from_srgb(shaderIsOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
+                break;
+        }
+    }
+
+protected:
+    void flatten(SkWriteBuffer& buffer) const override {
+        buffer.write32(static_cast<uint32_t>(fDir));
+    }
+
+private:
+    const Direction fDir;
+
+    friend class SkColorFilter;
+    typedef SkColorFilter INHERITED;
+};
+
+sk_sp<SkFlattenable> SkSRGBGammaColorFilter::CreateProc(SkReadBuffer& buffer) {
+    uint32_t dir = buffer.read32();
+    if (dir <= 1) {
+        return sk_sp<SkFlattenable>(new SkSRGBGammaColorFilter(static_cast<Direction>(dir)));
+    }
+    buffer.validate(false);
+    return nullptr;
+}
+
+#ifndef SK_IGNORE_TO_STRING
+void SkSRGBGammaColorFilter::toString(SkString* str) const {
+    str->append("srgbgamma");
+}
+#endif
+
+sk_sp<SkColorFilter> SkColorFilter::MakeLinearToSRGBGamma() {
+    return sk_sp<SkColorFilter>(new SkSRGBGammaColorFilter(
+                                               SkSRGBGammaColorFilter::Direction::kLinearToSRGB));
+}
+
+sk_sp<SkColorFilter> SkColorFilter::MakeSRGBToLinearGamma() {
+    return sk_sp<SkColorFilter>(new SkSRGBGammaColorFilter(
+                                               SkSRGBGammaColorFilter::Direction::kSRGBToLinear));
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
 #include "SkModeColorFilter.h"
 
 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkColorFilter)
 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeColorFilter)
 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkModeColorFilter)
+SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSRGBGammaColorFilter)
 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index d44c8bd..da0071d 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -546,16 +546,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-#ifdef SK_CPU_BENDIAN
-#else
-    #define SK_A32_INDEX    (3 - (SK_A32_SHIFT >> 3))
-    #define SK_R32_INDEX    (3 - (SK_R32_SHIFT >> 3))
-    #define SK_G32_INDEX    (3 - (SK_G32_SHIFT >> 3))
-    #define SK_B32_INDEX    (3 - (SK_B32_SHIFT >> 3))
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-
 sk_sp<SkColorFilter> SkTableColorFilter::Make(const uint8_t table[256]) {
     return sk_make_sp<SkTable_ColorFilter>(table, table, table, table);
 }
diff --git a/tests/ApplyGammaTest.cpp b/tests/ApplyGammaTest.cpp
index dbb7210..79dbfc7 100644
--- a/tests/ApplyGammaTest.cpp
+++ b/tests/ApplyGammaTest.cpp
@@ -15,7 +15,6 @@
 #include "SkColorFilter.h"
 #include "SkSurface.h"
 #include "SkUtils.h"
-#include "sk_tool_utils.h"
 
 /** convert 0..1 linear value to 0..1 srgb */
 static float linear_to_srgb(float linear) {
@@ -112,8 +111,8 @@
 
         SkPaint gammaPaint;
         gammaPaint.setBlendMode(SkBlendMode::kSrc);
-        gammaPaint.setColorFilter(toSRGB ? sk_tool_utils::MakeLinearToSRGBColorFilter()
-                                         : sk_tool_utils::MakeSRGBToLinearColorFilter());
+        gammaPaint.setColorFilter(toSRGB ? SkColorFilter::MakeLinearToSRGBGamma()
+                                         : SkColorFilter::MakeSRGBToLinearGamma());
 
         dstCanvas->drawBitmap(bm, 0, 0, &gammaPaint);
         dstCanvas->flush();
diff --git a/tools/sk_tool_utils.cpp b/tools/sk_tool_utils.cpp
index f4257f0..dff5d70 100644
--- a/tools/sk_tool_utils.cpp
+++ b/tools/sk_tool_utils.cpp
@@ -22,38 +22,6 @@
 
 DEFINE_bool(portableFonts, false, "Use portable fonts");
 
-#if SK_SUPPORT_GPU
-#include "effects/GrSRGBEffect.h"
-#include "SkColorFilter.h"
-
-// Color filter that just wraps GrSRGBEffect
-class SkSRGBColorFilter : public SkColorFilter {
-public:
-    static sk_sp<SkColorFilter> Make(GrSRGBEffect::Mode mode) {
-        return sk_sp<SkColorFilter>(new SkSRGBColorFilter(mode));
-    }
-
-    sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*, SkColorSpace*) const override {
-        return GrSRGBEffect::Make(fMode);
-    }
-
-    void onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, bool) const override {
-        SK_ABORT("SkSRGBColorFilter is only implemented for GPU");
-    }
-    Factory getFactory() const override { return nullptr; }
-
-#ifndef SK_IGNORE_TO_STRING
-    void toString(SkString* str) const override {}
-#endif
-
-private:
-    SkSRGBColorFilter(GrSRGBEffect::Mode mode) : fMode(mode) {}
-
-    GrSRGBEffect::Mode fMode;
-    typedef SkColorFilter INHERITED;
-};
-#endif
-
 namespace sk_tool_utils {
 
 /* these are the default fonts chosen by Chrome for serif, sans-serif, and monospace */
@@ -655,14 +623,4 @@
     }
 }
 
-#if SK_SUPPORT_GPU
-sk_sp<SkColorFilter> MakeLinearToSRGBColorFilter() {
-    return SkSRGBColorFilter::Make(GrSRGBEffect::Mode::kLinearToSRGB);
-}
-
-sk_sp<SkColorFilter> MakeSRGBToLinearColorFilter() {
-    return SkSRGBColorFilter::Make(GrSRGBEffect::Mode::kSRGBToLinear);
-}
-#endif
-
 }  // namespace sk_tool_utils
diff --git a/tools/sk_tool_utils.h b/tools/sk_tool_utils.h
index 111f966..6283225 100644
--- a/tools/sk_tool_utils.h
+++ b/tools/sk_tool_utils.h
@@ -256,11 +256,6 @@
     bool copy_to(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src);
     void copy_to_g8(SkBitmap* dst, const SkBitmap& src);
 
-#if SK_SUPPORT_GPU
-    sk_sp<SkColorFilter> MakeLinearToSRGBColorFilter();
-    sk_sp<SkColorFilter> MakeSRGBToLinearColorFilter();
-#endif
-
 }  // namespace sk_tool_utils
 
 #endif  // sk_tool_utils_DEFINED