Reland "Base Gradient FP Refactor"

This reverts commit 1ea5656a285bcfef445d6f69eaab477e68595b54.

Reason for revert: Fixed google3 build failure

Original change's description:
> Revert "Base Gradient FP Refactor"
> 
> This reverts commit 10f7a1e07554a362aef979d32ba288a009bdff90.
> 
> Reason for revert: broke google3 roll
> Original change's description:
> > Base Gradient FP Refactor
> > 
> > --
> > 
> > Redefines how gradients will be written in the GPU back-end:
> > 
> > They are split into three fragment processor components: master, layout, and colorizer.
> > The layout FP is responsible for converting the fragment position into an interpolant value, t.
> > Each high-level gradient--such as linear, radial, etc.--are implemented solely in a layout FP.
> > The colorizer FP is responsible for converting t into a color.
> > The master FP invokes the layout, clamps t into the proper domain, and then invokes the colorizer.
> > GrGradientShader provides factory functions to create FP graphs from SkGradientShader instances.
> > This pattern is documented in gpu/gradients/README.md.
> > 
> > Goals for current CL
> > ====================
> > 
> > Outline the FP components by providing .fp implementations for the simplest gradients.
> > Defines a two-color single interval colorizer and a linear gradient layout, and the master effect.
> > A MakeLinear() factory function is provided that can convert SkGradientShaders that fit these constraints.
> > SkLinearGradient first attempts to use the new system, falling back to the original GrGradientEffect.
> > 
> > Future CLs
> > ==========
> > 
> > To keep the CL reviews manageable, additional dependent CLs will be added that gradually replace past functionality.
> > A CL for each layout will be defined.
> > CLs for the different analytic colorizer cases and the textured gradient case will be defined.
> > Once the new system supports all current layouts and colorizer capabilities, all old GPU gradient code will be removed.
> > After this clean-up, analytic colorization can hopefully be expanded to reduce the usage of textured gradients.
> > 
> > Bug: skia:
> > Change-Id: Iafe7b8b4071491a71c473babcd7bedda659150c1
> > Reviewed-on: https://skia-review.googlesource.com/148120
> > Commit-Queue: Michael Ludwig <michaelludwig@google.com>
> > Reviewed-by: Brian Salomon <bsalomon@google.com>
> 
> TBR=bsalomon@google.com,michaelludwig@google.com
> 
> Change-Id: Ib735e323795ac8874cb00b007a915786b50517a6
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: skia:
> Reviewed-on: https://skia-review.googlesource.com/153600
> Reviewed-by: Cary Clark <caryclark@google.com>
> Commit-Queue: Cary Clark <caryclark@google.com>

TBR=bsalomon@google.com,caryclark@google.com,michaelludwig@google.com

Change-Id: Ibf6ffbcb1af0dfbdac7317151aeb08f18f84c7fd
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:
Reviewed-on: https://skia-review.googlesource.com/153887
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/gpu/gradients/GrGradientShader.cpp b/src/gpu/gradients/GrGradientShader.cpp
new file mode 100644
index 0000000..83397a0
--- /dev/null
+++ b/src/gpu/gradients/GrGradientShader.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrGradientShader.h"
+
+#include "GrClampedGradientEffect.h"
+#include "GrTiledGradientEffect.h"
+
+#include "GrLinearGradientLayout.h"
+#include "GrSingleIntervalGradientColorizer.h"
+
+#include "SkGradientShaderPriv.h"
+#include "GrColor.h"
+
+// Analyze the shader's color stops and positions and chooses an appropriate colorizer to represent
+// the gradient.
+static std::unique_ptr<GrFragmentProcessor> make_colorizer(const SkGradientShaderBase& shader,
+        const GrFPArgs& args, const GrColor4f* colors) {
+    // If there are hard stops at the beginning or end, the first and/or last color should be
+    // ignored by the colorizer since it should only be used in a clamped border color. By detecting
+    // and removing these stops at the beginning, it makes optimizing the remaining color stops
+    // simpler.
+
+    // SkGradientShaderBase guarantees that fOrigPos[0] == 0 by adding a dummy
+    bool bottomHardStop = shader.fOrigPos && SkScalarNearlyEqual(shader.fOrigPos[0],
+                                                                 shader.fOrigPos[1]);
+    // The same is true for fOrigPos[end] == 1
+    bool topHardStop = shader.fOrigPos &&
+            SkScalarNearlyEqual(shader.fOrigPos[shader.fColorCount - 2],
+                                shader.fOrigPos[shader.fColorCount - 1]);
+
+    int offset = 0;
+    int count = shader.fColorCount;
+    if (bottomHardStop) {
+        offset += 1;
+        count--;
+    }
+    if (topHardStop) {
+        count--;
+    }
+
+    // Currently only supports 2-color single intervals. However, when the gradient has hard stops
+    // and is clamped, certain 3 or 4 color gradients are equivalent to a two color interval
+    if (count == 2) {
+        return GrSingleIntervalGradientColorizer::Make(colors[offset], colors[offset + 1]);
+    }
+
+    return nullptr;
+}
+
+// Combines the colorizer and layout with an appropriately configured master effect based on the
+// gradient's tile mode
+static std::unique_ptr<GrFragmentProcessor> make_gradient(const SkGradientShaderBase& shader,
+        const GrFPArgs& args, std::unique_ptr<GrFragmentProcessor> layout) {
+    // No shader is possible if a layout couldn't be created, e.g. a layout-specific Make() returned
+    // null.
+    if (layout == nullptr) {
+        return nullptr;
+    }
+
+    // Convert all colors into destination space and into GrColor4fs, and handle
+    // premul issues depending on the interpolation mode
+    bool inputPremul = shader.getGradFlags() & SkGradientShader::kInterpolateColorsInPremul_Flag;
+    SkAutoSTMalloc<4, GrColor4f> colors(shader.fColorCount);
+    SkColor4fXformer xformedColors(shader.fOrigColors4f, shader.fColorCount,
+            shader.fColorSpace.get(), args.fDstColorSpaceInfo->colorSpace());
+    for (int i = 0; i < shader.fColorCount; i++) {
+        colors[i] = GrColor4f::FromSkColor4f(xformedColors.fColors[i]);
+        if (inputPremul) {
+            colors[i] = colors[i].premul();
+        }
+    }
+
+    // All gradients are colorized the same way, regardless of layout
+    std::unique_ptr<GrFragmentProcessor> colorizer = make_colorizer(shader, args, colors.get());
+    if (colorizer == nullptr) {
+        return nullptr;
+    }
+
+    // All tile modes are supported (unless something was added to SkShader)
+    std::unique_ptr<GrFragmentProcessor> master;
+    switch(shader.getTileMode()) {
+        case SkShader::kRepeat_TileMode:
+            master = GrTiledGradientEffect::Make(std::move(colorizer), std::move(layout),
+                                                 /* mirror */ false);
+            break;
+        case SkShader::kMirror_TileMode:
+            master = GrTiledGradientEffect::Make(std::move(colorizer), std::move(layout),
+                                                 /* mirror */ true);
+            break;
+        case SkShader::kClamp_TileMode:
+            // For the clamped mode, the border colors are the first and last colors, corresponding
+            // to t=0 and t=1, because SkGradientShaderBase enforces that by adding color stops as
+            // appropriate. If there is a hard stop, this grabs the expected outer colors for the
+            // border.
+            master = GrClampedGradientEffect::Make(std::move(colorizer), std::move(layout),
+                                                   colors[0], colors[shader.fColorCount - 1]);
+            break;
+        case SkShader::kDecal_TileMode:
+            master = GrClampedGradientEffect::Make(std::move(colorizer), std::move(layout),
+                                                   GrColor4f::TransparentBlack(),
+                                                   GrColor4f::TransparentBlack());
+            break;
+    }
+
+    if (master == nullptr) {
+        // Unexpected tile mode
+        return nullptr;
+    }
+
+    if (!inputPremul) {
+        // When interpolating unpremul colors, the output of the gradient
+        // effect fp's will also be unpremul, so wrap it to ensure its premul.
+        // - this is unnecessary when interpolating premul colors since the
+        //   output color is premul by nature
+        master = GrFragmentProcessor::PremulOutput(std::move(master));
+    }
+
+    return GrFragmentProcessor::MulChildByInputAlpha(std::move(master));
+}
+
+namespace GrGradientShader {
+
+std::unique_ptr<GrFragmentProcessor> MakeLinear(const SkLinearGradient& shader,
+                                                const GrFPArgs& args) {
+    return make_gradient(shader, args, GrLinearGradientLayout::Make(shader, args));
+}
+
+}