Home | History | Annotate | Download | only in gradients
      1 /*
      2  * Copyright 2014 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 
      9 #include "SkTwoPointConicalGradient.h"
     10 
     11 #if SK_SUPPORT_GPU
     12 #include "GrCoordTransform.h"
     13 #include "GrPaint.h"
     14 #include "glsl/GrGLSLFragmentShaderBuilder.h"
     15 #include "glsl/GrGLSLProgramDataManager.h"
     16 #include "glsl/GrGLSLUniformHandler.h"
     17 #include "SkTwoPointConicalGradient_gpu.h"
     18 
     19 // For brevity
     20 typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
     21 
     22 static const SkScalar kErrorTol = 0.00001f;
     23 static const SkScalar kEdgeErrorTol = 5.f * kErrorTol;
     24 
     25 /**
     26  * We have three general cases for 2pt conical gradients. First we always assume that
     27  * the start radius <= end radius. Our first case (kInside_) is when the start circle
     28  * is completely enclosed by the end circle. The second case (kOutside_) is the case
     29  * when the start circle is either completely outside the end circle or the circles
     30  * overlap. The final case (kEdge_) is when the start circle is inside the end one,
     31  * but the two are just barely touching at 1 point along their edges.
     32  */
     33 enum ConicalType {
     34     kInside_ConicalType,
     35     kOutside_ConicalType,
     36     kEdge_ConicalType,
     37 };
     38 
     39 //////////////////////////////////////////////////////////////////////////////
     40 
     41 static void set_matrix_edge_conical(const SkTwoPointConicalGradient& shader,
     42                                     SkMatrix* invLMatrix) {
     43     // Inverse of the current local matrix is passed in then,
     44     // translate to center1, rotate so center2 is on x axis.
     45     const SkPoint& center1 = shader.getStartCenter();
     46     const SkPoint& center2 = shader.getEndCenter();
     47 
     48     invLMatrix->postTranslate(-center1.fX, -center1.fY);
     49 
     50     SkPoint diff = center2 - center1;
     51     SkScalar diffLen = diff.length();
     52     if (0 != diffLen) {
     53         SkScalar invDiffLen = SkScalarInvert(diffLen);
     54         SkMatrix rot;
     55         rot.setSinCos(-invDiffLen * diff.fY, invDiffLen * diff.fX);
     56         invLMatrix->postConcat(rot);
     57     }
     58 }
     59 
     60 class Edge2PtConicalEffect : public GrGradientEffect {
     61 public:
     62     class GLSLEdge2PtConicalProcessor;
     63 
     64     static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args) {
     65         auto processor = sk_sp<Edge2PtConicalEffect>(new Edge2PtConicalEffect(args));
     66         return processor->isValid() ? std::move(processor) : nullptr;
     67     }
     68 
     69     ~Edge2PtConicalEffect() override {}
     70 
     71     const char* name() const override {
     72         return "Two-Point Conical Gradient Edge Touching";
     73     }
     74 
     75     // The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
     76     SkScalar center() const { return fCenterX1; }
     77     SkScalar diffRadius() const { return fDiffRadius; }
     78     SkScalar radius() const { return fRadius0; }
     79 
     80 private:
     81     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
     82 
     83     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
     84 
     85     bool onIsEqual(const GrFragmentProcessor& sBase) const override {
     86         const Edge2PtConicalEffect& s = sBase.cast<Edge2PtConicalEffect>();
     87         return (INHERITED::onIsEqual(sBase) &&
     88                 this->fCenterX1 == s.fCenterX1 &&
     89                 this->fRadius0 == s.fRadius0 &&
     90                 this->fDiffRadius == s.fDiffRadius);
     91     }
     92 
     93     Edge2PtConicalEffect(const CreateArgs& args)
     94             : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */) {
     95         const SkTwoPointConicalGradient& shader =
     96             *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
     97         fCenterX1 = shader.getCenterX1();
     98         fRadius0 = shader.getStartRadius();
     99         fDiffRadius = shader.getDiffRadius();
    100         this->initClassID<Edge2PtConicalEffect>();
    101         // We should only be calling this shader if we are degenerate case with touching circles
    102         // When deciding if we are in edge case, we scaled by the end radius for cases when the
    103         // start radius was close to zero, otherwise we scaled by the start radius.  In addition
    104         // Our test for the edge case in set_matrix_circle_conical has a higher tolerance so we
    105         // need the sqrt value below
    106         SkASSERT(SkScalarAbs(SkScalarAbs(fDiffRadius) - fCenterX1) <
    107                  (fRadius0 < kErrorTol ? shader.getEndRadius() * kEdgeErrorTol :
    108                                          fRadius0 * sqrt(kEdgeErrorTol)));
    109 
    110         // We pass the linear part of the quadratic as a varying.
    111         //    float b = -2.0 * (fCenterX1 * x + fRadius0 * fDiffRadius * z)
    112         fBTransform = this->getCoordTransform();
    113         SkMatrix& bMatrix = *fBTransform.accessMatrix();
    114         SkScalar r0dr = fRadius0 * fDiffRadius;
    115         bMatrix[SkMatrix::kMScaleX] = -2 * (fCenterX1 * bMatrix[SkMatrix::kMScaleX] +
    116                                             r0dr * bMatrix[SkMatrix::kMPersp0]);
    117         bMatrix[SkMatrix::kMSkewX] = -2 * (fCenterX1 * bMatrix[SkMatrix::kMSkewX] +
    118                                            r0dr * bMatrix[SkMatrix::kMPersp1]);
    119         bMatrix[SkMatrix::kMTransX] = -2 * (fCenterX1 * bMatrix[SkMatrix::kMTransX] +
    120                                             r0dr * bMatrix[SkMatrix::kMPersp2]);
    121         this->addCoordTransform(&fBTransform);
    122     }
    123 
    124     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
    125 
    126     // @{
    127     // Cache of values - these can change arbitrarily, EXCEPT
    128     // we shouldn't change between degenerate and non-degenerate?!
    129 
    130     GrCoordTransform fBTransform;
    131     SkScalar         fCenterX1;
    132     SkScalar         fRadius0;
    133     SkScalar         fDiffRadius;
    134 
    135     // @}
    136 
    137     typedef GrGradientEffect INHERITED;
    138 };
    139 
    140 class Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor : public GrGradientEffect::GLSLProcessor {
    141 public:
    142     GLSLEdge2PtConicalProcessor(const GrProcessor&);
    143     ~GLSLEdge2PtConicalProcessor() override {}
    144 
    145     virtual void emitCode(EmitArgs&) override;
    146 
    147     static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
    148 
    149 protected:
    150     void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
    151 
    152     UniformHandle fParamUni;
    153 
    154     const char* fVSVaryingName;
    155     const char* fFSVaryingName;
    156 
    157     // @{
    158     /// Values last uploaded as uniforms
    159 
    160     SkScalar fCachedRadius;
    161     SkScalar fCachedDiffRadius;
    162 
    163     // @}
    164 
    165 private:
    166     typedef GrGradientEffect::GLSLProcessor INHERITED;
    167 
    168 };
    169 
    170 void Edge2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
    171                                                  GrProcessorKeyBuilder* b) const {
    172     Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GenKey(*this, caps, b);
    173 }
    174 
    175 GrGLSLFragmentProcessor* Edge2PtConicalEffect::onCreateGLSLInstance() const {
    176     return new Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor(*this);
    177 }
    178 
    179 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(Edge2PtConicalEffect);
    180 
    181 /*
    182  * All Two point conical gradient test create functions may occasionally create edge case shaders
    183  */
    184 #if GR_TEST_UTILS
    185 sk_sp<GrFragmentProcessor> Edge2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
    186     SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
    187     SkScalar radius1 = d->fRandom->nextUScalar1();
    188     SkPoint center2;
    189     SkScalar radius2;
    190     do {
    191         center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
    192         // If the circles are identical the factory will give us an empty shader.
    193         // This will happen if we pick identical centers
    194     } while (center1 == center2);
    195 
    196     // Below makes sure that circle one is contained within circle two
    197     // and both circles are touching on an edge
    198     SkPoint diff = center2 - center1;
    199     SkScalar diffLen = diff.length();
    200     radius2 = radius1 + diffLen;
    201 
    202     RandomGradientParams params(d->fRandom);
    203     auto shader = params.fUseColors4f ?
    204         SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
    205                                               params.fColors4f, params.fColorSpace, params.fStops,
    206                                               params.fColorCount, params.fTileMode) :
    207         SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
    208                                               params.fColors, params.fStops,
    209                                               params.fColorCount, params.fTileMode);
    210     GrTest::TestAsFPArgs asFPArgs(d);
    211     sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
    212     GrAlwaysAssert(fp);
    213     return fp;
    214 }
    215 #endif
    216 
    217 Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GLSLEdge2PtConicalProcessor(const GrProcessor&)
    218     : fVSVaryingName(nullptr)
    219     , fFSVaryingName(nullptr)
    220     , fCachedRadius(-SK_ScalarMax)
    221     , fCachedDiffRadius(-SK_ScalarMax) {}
    222 
    223 void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::emitCode(EmitArgs& args) {
    224     const Edge2PtConicalEffect& ge = args.fFp.cast<Edge2PtConicalEffect>();
    225     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
    226     this->emitUniforms(uniformHandler, ge);
    227     fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
    228                                            kVec3f_GrSLType, kDefault_GrSLPrecision,
    229                                            "Conical2FSParams");
    230 
    231     SkString cName("c");
    232     SkString tName("t");
    233     SkString p0; // start radius
    234     SkString p1; // start radius squared
    235     SkString p2; // difference in radii (r1 - r0)
    236 
    237 
    238     p0.appendf("%s.x", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
    239     p1.appendf("%s.y", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
    240     p2.appendf("%s.z", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
    241 
    242     // We interpolate the linear component in coords[1].
    243     SkASSERT(args.fTransformedCoords[0].getType() == args.fTransformedCoords[1].getType());
    244     const char* coords2D;
    245     SkString bVar;
    246     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
    247     if (kVec3f_GrSLType == args.fTransformedCoords[0].getType()) {
    248         fragBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
    249                                  args.fTransformedCoords[0].c_str(),
    250                                  args.fTransformedCoords[0].c_str(),
    251                                  args.fTransformedCoords[1].c_str(),
    252                                  args.fTransformedCoords[1].c_str());
    253         coords2D = "interpolants.xy";
    254         bVar = "interpolants.z";
    255     } else {
    256         coords2D = args.fTransformedCoords[0].c_str();
    257         bVar.printf("%s.x", args.fTransformedCoords[1].c_str());
    258     }
    259 
    260     // output will default to transparent black (we simply won't write anything
    261     // else to it if invalid, instead of discarding or returning prematurely)
    262     fragBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", args.fOutputColor);
    263 
    264     // c = (x^2)+(y^2) - params[1]
    265     fragBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
    266                            cName.c_str(), coords2D, coords2D, p1.c_str());
    267 
    268     // linear case: t = -c/b
    269     fragBuilder->codeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
    270                            cName.c_str(), bVar.c_str());
    271 
    272     // if r(t) > 0, then t will be the x coordinate
    273     fragBuilder->codeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
    274                            p2.c_str(), p0.c_str());
    275     fragBuilder->codeAppend("\t");
    276     this->emitColor(fragBuilder,
    277                     uniformHandler,
    278                     args.fShaderCaps,
    279                     ge,
    280                     tName.c_str(),
    281                     args.fOutputColor,
    282                     args.fInputColor,
    283                     args.fTexSamplers);
    284     fragBuilder->codeAppend("\t}\n");
    285 }
    286 
    287 void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::onSetData(
    288         const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) {
    289     INHERITED::onSetData(pdman, processor);
    290     const Edge2PtConicalEffect& data = processor.cast<Edge2PtConicalEffect>();
    291     SkScalar radius0 = data.radius();
    292     SkScalar diffRadius = data.diffRadius();
    293 
    294     if (fCachedRadius != radius0 ||
    295         fCachedDiffRadius != diffRadius) {
    296 
    297         pdman.set3f(fParamUni, radius0, radius0 * radius0, diffRadius);
    298         fCachedRadius = radius0;
    299         fCachedDiffRadius = diffRadius;
    300     }
    301 }
    302 
    303 void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GenKey(const GrProcessor& processor,
    304                                     const GrShaderCaps&, GrProcessorKeyBuilder* b) {
    305     b->add32(GenBaseGradientKey(processor));
    306 }
    307 
    308 //////////////////////////////////////////////////////////////////////////////
    309 // Focal Conical Gradients
    310 //////////////////////////////////////////////////////////////////////////////
    311 
    312 static ConicalType set_matrix_focal_conical(const SkTwoPointConicalGradient& shader,
    313                                             SkMatrix* invLMatrix, SkScalar* focalX) {
    314     // Inverse of the current local matrix is passed in then,
    315     // translate, scale, and rotate such that endCircle is unit circle on x-axis,
    316     // and focal point is at the origin.
    317     ConicalType conicalType;
    318     const SkPoint& focal = shader.getStartCenter();
    319     const SkPoint& centerEnd = shader.getEndCenter();
    320     SkScalar radius = shader.getEndRadius();
    321     SkScalar invRadius = 1.f / radius;
    322 
    323     SkMatrix matrix;
    324 
    325     matrix.setTranslate(-centerEnd.fX, -centerEnd.fY);
    326     matrix.postScale(invRadius, invRadius);
    327 
    328     SkPoint focalTrans;
    329     matrix.mapPoints(&focalTrans, &focal, 1);
    330     *focalX = focalTrans.length();
    331 
    332     if (0.f != *focalX) {
    333         SkScalar invFocalX = SkScalarInvert(*focalX);
    334         SkMatrix rot;
    335         rot.setSinCos(-invFocalX * focalTrans.fY, invFocalX * focalTrans.fX);
    336         matrix.postConcat(rot);
    337     }
    338 
    339     matrix.postTranslate(-(*focalX), 0.f);
    340 
    341     // If the focal point is touching the edge of the circle it will
    342     // cause a degenerate case that must be handled separately
    343     // kEdgeErrorTol = 5 * kErrorTol was picked after manual testing the
    344     // stability trade off versus the linear approx used in the Edge Shader
    345     if (SkScalarAbs(1.f - (*focalX)) < kEdgeErrorTol) {
    346         return kEdge_ConicalType;
    347     }
    348 
    349     // Scale factor 1 / (1 - focalX * focalX)
    350     SkScalar oneMinusF2 = 1.f - *focalX * *focalX;
    351     SkScalar s = SkScalarInvert(oneMinusF2);
    352 
    353 
    354     if (s >= 0.f) {
    355         conicalType = kInside_ConicalType;
    356         matrix.postScale(s, s * SkScalarSqrt(oneMinusF2));
    357     } else {
    358         conicalType = kOutside_ConicalType;
    359         matrix.postScale(s, s);
    360     }
    361 
    362     invLMatrix->postConcat(matrix);
    363 
    364     return conicalType;
    365 }
    366 
    367 //////////////////////////////////////////////////////////////////////////////
    368 
    369 class FocalOutside2PtConicalEffect : public GrGradientEffect {
    370 public:
    371     class GLSLFocalOutside2PtConicalProcessor;
    372 
    373     static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar focalX) {
    374         auto processor =
    375                 sk_sp<FocalOutside2PtConicalEffect>(new FocalOutside2PtConicalEffect(args, focalX));
    376         return processor->isValid() ? std::move(processor) : nullptr;
    377     }
    378 
    379     ~FocalOutside2PtConicalEffect() override {}
    380 
    381     const char* name() const override {
    382         return "Two-Point Conical Gradient Focal Outside";
    383     }
    384 
    385     bool isFlipped() const { return fIsFlipped; }
    386     SkScalar focal() const { return fFocalX; }
    387 
    388 private:
    389     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
    390 
    391     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
    392 
    393     bool onIsEqual(const GrFragmentProcessor& sBase) const override {
    394         const FocalOutside2PtConicalEffect& s = sBase.cast<FocalOutside2PtConicalEffect>();
    395         return (INHERITED::onIsEqual(sBase) &&
    396                 this->fFocalX == s.fFocalX &&
    397                 this->fIsFlipped == s.fIsFlipped);
    398     }
    399 
    400     static bool IsFlipped(const CreateArgs& args) {
    401         // eww.
    402         return static_cast<const SkTwoPointConicalGradient*>(args.fShader)->isFlippedGrad();
    403     }
    404 
    405     FocalOutside2PtConicalEffect(const CreateArgs& args, SkScalar focalX)
    406             : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */)
    407             , fFocalX(focalX)
    408             , fIsFlipped(IsFlipped(args)) {
    409         this->initClassID<FocalOutside2PtConicalEffect>();
    410     }
    411 
    412     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
    413 
    414     SkScalar         fFocalX;
    415     bool             fIsFlipped;
    416 
    417     typedef GrGradientEffect INHERITED;
    418 };
    419 
    420 class FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor
    421     : public GrGradientEffect::GLSLProcessor {
    422 public:
    423     GLSLFocalOutside2PtConicalProcessor(const GrProcessor&);
    424     ~GLSLFocalOutside2PtConicalProcessor() override {}
    425 
    426     virtual void emitCode(EmitArgs&) override;
    427 
    428     static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
    429 
    430 protected:
    431     void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
    432 
    433     UniformHandle fParamUni;
    434 
    435     const char* fVSVaryingName;
    436     const char* fFSVaryingName;
    437 
    438     bool fIsFlipped;
    439 
    440     // @{
    441     /// Values last uploaded as uniforms
    442 
    443     SkScalar fCachedFocal;
    444 
    445     // @}
    446 
    447 private:
    448     typedef GrGradientEffect::GLSLProcessor INHERITED;
    449 
    450 };
    451 
    452 void FocalOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
    453                                                          GrProcessorKeyBuilder* b) const {
    454     FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::GenKey(*this, caps, b);
    455 }
    456 
    457 GrGLSLFragmentProcessor* FocalOutside2PtConicalEffect::onCreateGLSLInstance() const {
    458     return new FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor(*this);
    459 }
    460 
    461 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalOutside2PtConicalEffect);
    462 
    463 /*
    464  * All Two point conical gradient test create functions may occasionally create edge case shaders
    465  */
    466 #if GR_TEST_UTILS
    467 sk_sp<GrFragmentProcessor> FocalOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
    468     SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
    469     SkScalar radius1 = 0.f;
    470     SkPoint center2;
    471     SkScalar radius2;
    472     do {
    473         center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
    474         // Need to make sure the centers are not the same or else focal point will be inside
    475     } while (center1 == center2);
    476 
    477     SkPoint diff = center2 - center1;
    478     SkScalar diffLen = diff.length();
    479     // Below makes sure that the focal point is not contained within circle two
    480     radius2 = d->fRandom->nextRangeF(0.f, diffLen);
    481 
    482     RandomGradientParams params(d->fRandom);
    483     auto shader = params.fUseColors4f ?
    484         SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
    485                                               params.fColors4f, params.fColorSpace, params.fStops,
    486                                               params.fColorCount, params.fTileMode) :
    487         SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
    488                                               params.fColors, params.fStops,
    489                                               params.fColorCount, params.fTileMode);
    490     GrTest::TestAsFPArgs asFPArgs(d);
    491     sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
    492     GrAlwaysAssert(fp);
    493     return fp;
    494 }
    495 #endif
    496 
    497 FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor
    498                             ::GLSLFocalOutside2PtConicalProcessor(const GrProcessor& processor)
    499     : fVSVaryingName(nullptr)
    500     , fFSVaryingName(nullptr)
    501     , fCachedFocal(SK_ScalarMax) {
    502     const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
    503     fIsFlipped = data.isFlipped();
    504 }
    505 
    506 void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::emitCode(EmitArgs& args) {
    507     const FocalOutside2PtConicalEffect& ge = args.fFp.cast<FocalOutside2PtConicalEffect>();
    508     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
    509     this->emitUniforms(uniformHandler, ge);
    510     fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
    511                                            kVec2f_GrSLType, kDefault_GrSLPrecision,
    512                                            "Conical2FSParams");
    513     SkString tName("t");
    514     SkString p0; // focalX
    515     SkString p1; // 1 - focalX * focalX
    516 
    517     p0.appendf("%s.x", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
    518     p1.appendf("%s.y", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
    519 
    520     // if we have a vec3 from being in perspective, convert it to a vec2 first
    521     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
    522     SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
    523     const char* coords2D = coords2DString.c_str();
    524 
    525     // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
    526 
    527     // output will default to transparent black (we simply won't write anything
    528     // else to it if invalid, instead of discarding or returning prematurely)
    529     fragBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", args.fOutputColor);
    530 
    531     fragBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
    532     fragBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
    533     fragBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
    534 
    535     // Must check to see if we flipped the circle order (to make sure start radius < end radius)
    536     // If so we must also flip sign on sqrt
    537     if (!fIsFlipped) {
    538         fragBuilder->codeAppendf("\tfloat %s = %s.x * %s  + sqrt(d);\n", tName.c_str(),
    539                                  coords2D, p0.c_str());
    540     } else {
    541         fragBuilder->codeAppendf("\tfloat %s = %s.x * %s  - sqrt(d);\n", tName.c_str(),
    542                                  coords2D, p0.c_str());
    543     }
    544 
    545     fragBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
    546     fragBuilder->codeAppend("\t\t");
    547     this->emitColor(fragBuilder,
    548                     uniformHandler,
    549                     args.fShaderCaps,
    550                     ge,
    551                     tName.c_str(),
    552                     args.fOutputColor,
    553                     args.fInputColor,
    554                     args.fTexSamplers);
    555     fragBuilder->codeAppend("\t}\n");
    556 }
    557 
    558 void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::onSetData(
    559         const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) {
    560     INHERITED::onSetData(pdman, processor);
    561     const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
    562     SkASSERT(data.isFlipped() == fIsFlipped);
    563     SkScalar focal = data.focal();
    564 
    565     if (fCachedFocal != focal) {
    566         SkScalar oneMinus2F = 1.f - focal * focal;
    567 
    568         pdman.set2f(fParamUni, SkScalarToFloat(focal), SkScalarToFloat(oneMinus2F));
    569         fCachedFocal = focal;
    570     }
    571 }
    572 
    573 void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::GenKey(
    574                                             const GrProcessor& processor,
    575                                             const GrShaderCaps&, GrProcessorKeyBuilder* b) {
    576     uint32_t* key = b->add32n(2);
    577     key[0] = GenBaseGradientKey(processor);
    578     key[1] = processor.cast<FocalOutside2PtConicalEffect>().isFlipped();
    579 }
    580 
    581 //////////////////////////////////////////////////////////////////////////////
    582 
    583 class FocalInside2PtConicalEffect : public GrGradientEffect {
    584 public:
    585     class GLSLFocalInside2PtConicalProcessor;
    586 
    587     static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar focalX) {
    588         auto processor =
    589                 sk_sp<FocalInside2PtConicalEffect>(new FocalInside2PtConicalEffect(args, focalX));
    590         return processor->isValid() ? std::move(processor) : nullptr;
    591     }
    592 
    593     ~FocalInside2PtConicalEffect() override {}
    594 
    595     const char* name() const override {
    596         return "Two-Point Conical Gradient Focal Inside";
    597     }
    598 
    599     SkScalar focal() const { return fFocalX; }
    600 
    601     typedef FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor GLSLProcessor;
    602 
    603 private:
    604     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
    605 
    606     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
    607 
    608     bool onIsEqual(const GrFragmentProcessor& sBase) const override {
    609         const FocalInside2PtConicalEffect& s = sBase.cast<FocalInside2PtConicalEffect>();
    610         return (INHERITED::onIsEqual(sBase) &&
    611                 this->fFocalX == s.fFocalX);
    612     }
    613 
    614     FocalInside2PtConicalEffect(const CreateArgs& args, SkScalar focalX)
    615             : INHERITED(args, args.fShader->colorsAreOpaque()), fFocalX(focalX) {
    616         this->initClassID<FocalInside2PtConicalEffect>();
    617     }
    618 
    619     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
    620 
    621     SkScalar         fFocalX;
    622 
    623     typedef GrGradientEffect INHERITED;
    624 };
    625 
    626 class FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor
    627     : public GrGradientEffect::GLSLProcessor {
    628 public:
    629     GLSLFocalInside2PtConicalProcessor(const GrProcessor&);
    630     ~GLSLFocalInside2PtConicalProcessor() override {}
    631 
    632     virtual void emitCode(EmitArgs&) override;
    633 
    634     static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
    635 
    636 protected:
    637     void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
    638 
    639     UniformHandle fFocalUni;
    640 
    641     const char* fVSVaryingName;
    642     const char* fFSVaryingName;
    643 
    644     // @{
    645     /// Values last uploaded as uniforms
    646 
    647     SkScalar fCachedFocal;
    648 
    649     // @}
    650 
    651 private:
    652     typedef GrGradientEffect::GLSLProcessor INHERITED;
    653 
    654 };
    655 
    656 void FocalInside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
    657                                                         GrProcessorKeyBuilder* b) const {
    658     FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::GenKey(*this, caps, b);
    659 }
    660 
    661 GrGLSLFragmentProcessor* FocalInside2PtConicalEffect::onCreateGLSLInstance() const {
    662     return new FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor(*this);
    663 }
    664 
    665 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalInside2PtConicalEffect);
    666 
    667 /*
    668  * All Two point conical gradient test create functions may occasionally create edge case shaders
    669  */
    670 #if GR_TEST_UTILS
    671 sk_sp<GrFragmentProcessor> FocalInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
    672     SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
    673     SkScalar radius1 = 0.f;
    674     SkPoint center2;
    675     SkScalar radius2;
    676     do {
    677         center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
    678         // Below makes sure radius2 is larger enouch such that the focal point
    679         // is inside the end circle
    680         SkScalar increase = d->fRandom->nextUScalar1();
    681         SkPoint diff = center2 - center1;
    682         SkScalar diffLen = diff.length();
    683         radius2 = diffLen + increase;
    684         // If the circles are identical the factory will give us an empty shader.
    685     } while (radius1 == radius2 && center1 == center2);
    686 
    687     RandomGradientParams params(d->fRandom);
    688     auto shader = params.fUseColors4f ?
    689         SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
    690                                               params.fColors4f, params.fColorSpace, params.fStops,
    691                                               params.fColorCount, params.fTileMode) :
    692         SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
    693                                               params.fColors, params.fStops,
    694                                               params.fColorCount, params.fTileMode);
    695     GrTest::TestAsFPArgs asFPArgs(d);
    696     sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
    697     GrAlwaysAssert(fp);
    698     return fp;
    699 }
    700 #endif
    701 
    702 FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor
    703                            ::GLSLFocalInside2PtConicalProcessor(const GrProcessor&)
    704     : fVSVaryingName(nullptr)
    705     , fFSVaryingName(nullptr)
    706     , fCachedFocal(SK_ScalarMax) {}
    707 
    708 void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::emitCode(EmitArgs& args) {
    709     const FocalInside2PtConicalEffect& ge = args.fFp.cast<FocalInside2PtConicalEffect>();
    710     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
    711     this->emitUniforms(uniformHandler, ge);
    712     fFocalUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
    713                                            kFloat_GrSLType, kDefault_GrSLPrecision,
    714                                            "Conical2FSParams");
    715     SkString tName("t");
    716 
    717     // this is the distance along x-axis from the end center to focal point in
    718     // transformed coordinates
    719     GrShaderVar focal = uniformHandler->getUniformVariable(fFocalUni);
    720 
    721     // if we have a vec3 from being in perspective, convert it to a vec2 first
    722     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
    723     SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
    724     const char* coords2D = coords2DString.c_str();
    725 
    726     // t = p.x * focalX + length(p)
    727     fragBuilder->codeAppendf("\tfloat %s = %s.x * %s  + length(%s);\n", tName.c_str(),
    728                              coords2D, focal.c_str(), coords2D);
    729 
    730     this->emitColor(fragBuilder,
    731                     uniformHandler,
    732                     args.fShaderCaps,
    733                     ge,
    734                     tName.c_str(),
    735                     args.fOutputColor,
    736                     args.fInputColor,
    737                     args.fTexSamplers);
    738 }
    739 
    740 void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::onSetData(
    741         const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) {
    742     INHERITED::onSetData(pdman, processor);
    743     const FocalInside2PtConicalEffect& data = processor.cast<FocalInside2PtConicalEffect>();
    744     SkScalar focal = data.focal();
    745 
    746     if (fCachedFocal != focal) {
    747         pdman.set1f(fFocalUni, SkScalarToFloat(focal));
    748         fCachedFocal = focal;
    749     }
    750 }
    751 
    752 void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::GenKey(
    753                                             const GrProcessor& processor,
    754                                             const GrShaderCaps&, GrProcessorKeyBuilder* b) {
    755     b->add32(GenBaseGradientKey(processor));
    756 }
    757 
    758 //////////////////////////////////////////////////////////////////////////////
    759 // Circle Conical Gradients
    760 //////////////////////////////////////////////////////////////////////////////
    761 
    762 struct CircleConicalInfo {
    763     SkPoint fCenterEnd;
    764     SkScalar fA;
    765     SkScalar fB;
    766     SkScalar fC;
    767 };
    768 
    769 // Returns focal distance along x-axis in transformed coords
    770 static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
    771                                              SkMatrix* invLMatrix, CircleConicalInfo* info) {
    772     // Inverse of the current local matrix is passed in then,
    773     // translate and scale such that start circle is on the origin and has radius 1
    774     const SkPoint& centerStart = shader.getStartCenter();
    775     const SkPoint& centerEnd = shader.getEndCenter();
    776     SkScalar radiusStart = shader.getStartRadius();
    777     SkScalar radiusEnd = shader.getEndRadius();
    778 
    779     SkMatrix matrix;
    780 
    781     matrix.setTranslate(-centerStart.fX, -centerStart.fY);
    782 
    783     SkScalar invStartRad = 1.f / radiusStart;
    784     matrix.postScale(invStartRad, invStartRad);
    785 
    786     radiusEnd /= radiusStart;
    787 
    788     SkPoint centerEndTrans;
    789     matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
    790 
    791     SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
    792                  - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
    793 
    794     // Check to see if start circle is inside end circle with edges touching.
    795     // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
    796     // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
    797     // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
    798     // still accurate.
    799     if (SkScalarAbs(A) < kEdgeErrorTol) {
    800         return kEdge_ConicalType;
    801     }
    802 
    803     SkScalar C = 1.f / A;
    804     SkScalar B = (radiusEnd - 1.f) * C;
    805 
    806     matrix.postScale(C, C);
    807 
    808     invLMatrix->postConcat(matrix);
    809 
    810     info->fCenterEnd = centerEndTrans;
    811     info->fA = A;
    812     info->fB = B;
    813     info->fC = C;
    814 
    815     // if A ends up being negative, the start circle is contained completely inside the end cirlce
    816     if (A < 0.f) {
    817         return kInside_ConicalType;
    818     }
    819     return kOutside_ConicalType;
    820 }
    821 
    822 class CircleInside2PtConicalEffect : public GrGradientEffect {
    823 public:
    824     class GLSLCircleInside2PtConicalProcessor;
    825 
    826     static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, const CircleConicalInfo& info) {
    827         auto processor =
    828                 sk_sp<CircleInside2PtConicalEffect>(new CircleInside2PtConicalEffect(args, info));
    829         return processor->isValid() ? std::move(processor) : nullptr;
    830     }
    831 
    832     ~CircleInside2PtConicalEffect() override {}
    833 
    834     const char* name() const override { return "Two-Point Conical Gradient Inside"; }
    835 
    836     SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
    837     SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
    838     SkScalar A() const { return fInfo.fA; }
    839     SkScalar B() const { return fInfo.fB; }
    840     SkScalar C() const { return fInfo.fC; }
    841 
    842 private:
    843     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
    844 
    845     virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
    846                                        GrProcessorKeyBuilder* b) const override;
    847 
    848     bool onIsEqual(const GrFragmentProcessor& sBase) const override {
    849         const CircleInside2PtConicalEffect& s = sBase.cast<CircleInside2PtConicalEffect>();
    850         return (INHERITED::onIsEqual(sBase) &&
    851                 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
    852                 this->fInfo.fA == s.fInfo.fA &&
    853                 this->fInfo.fB == s.fInfo.fB &&
    854                 this->fInfo.fC == s.fInfo.fC);
    855     }
    856 
    857     CircleInside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
    858             : INHERITED(args, args.fShader->colorsAreOpaque()), fInfo(info) {
    859         this->initClassID<CircleInside2PtConicalEffect>();
    860     }
    861 
    862     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
    863 
    864     const CircleConicalInfo fInfo;
    865 
    866     typedef GrGradientEffect INHERITED;
    867 };
    868 
    869 class CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor
    870     : public GrGradientEffect::GLSLProcessor {
    871 public:
    872     GLSLCircleInside2PtConicalProcessor(const GrProcessor&);
    873     ~GLSLCircleInside2PtConicalProcessor() override {}
    874 
    875     virtual void emitCode(EmitArgs&) override;
    876 
    877     static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
    878 
    879 protected:
    880     void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
    881 
    882     UniformHandle fCenterUni;
    883     UniformHandle fParamUni;
    884 
    885     const char* fVSVaryingName;
    886     const char* fFSVaryingName;
    887 
    888     // @{
    889     /// Values last uploaded as uniforms
    890 
    891     SkScalar fCachedCenterX;
    892     SkScalar fCachedCenterY;
    893     SkScalar fCachedA;
    894     SkScalar fCachedB;
    895     SkScalar fCachedC;
    896 
    897     // @}
    898 
    899 private:
    900     typedef GrGradientEffect::GLSLProcessor INHERITED;
    901 
    902 };
    903 
    904 void CircleInside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
    905                                                          GrProcessorKeyBuilder* b) const {
    906     CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey(*this, caps, b);
    907 }
    908 
    909 GrGLSLFragmentProcessor* CircleInside2PtConicalEffect::onCreateGLSLInstance() const {
    910     return new CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor(*this);
    911 }
    912 
    913 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect);
    914 
    915 /*
    916  * All Two point conical gradient test create functions may occasionally create edge case shaders
    917  */
    918 #if GR_TEST_UTILS
    919 sk_sp<GrFragmentProcessor> CircleInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
    920     SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
    921     SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
    922     SkPoint center2;
    923     SkScalar radius2;
    924     do {
    925         center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
    926         // Below makes sure that circle one is contained within circle two
    927         SkScalar increase = d->fRandom->nextUScalar1();
    928         SkPoint diff = center2 - center1;
    929         SkScalar diffLen = diff.length();
    930         radius2 = radius1 + diffLen + increase;
    931         // If the circles are identical the factory will give us an empty shader.
    932     } while (radius1 == radius2 && center1 == center2);
    933 
    934     RandomGradientParams params(d->fRandom);
    935     auto shader = params.fUseColors4f ?
    936         SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
    937                                               params.fColors4f, params.fColorSpace, params.fStops,
    938                                               params.fColorCount, params.fTileMode) :
    939         SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
    940                                               params.fColors, params.fStops,
    941                                               params.fColorCount, params.fTileMode);
    942     GrTest::TestAsFPArgs asFPArgs(d);
    943     sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
    944     GrAlwaysAssert(fp);
    945     return fp;
    946 }
    947 #endif
    948 
    949 CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor
    950                             ::GLSLCircleInside2PtConicalProcessor(const GrProcessor& processor)
    951     : fVSVaryingName(nullptr)
    952     , fFSVaryingName(nullptr)
    953     , fCachedCenterX(SK_ScalarMax)
    954     , fCachedCenterY(SK_ScalarMax)
    955     , fCachedA(SK_ScalarMax)
    956     , fCachedB(SK_ScalarMax)
    957     , fCachedC(SK_ScalarMax) {}
    958 
    959 void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::emitCode(EmitArgs& args) {
    960     const CircleInside2PtConicalEffect& ge = args.fFp.cast<CircleInside2PtConicalEffect>();
    961     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
    962     this->emitUniforms(uniformHandler, ge);
    963     fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
    964                                             kVec2f_GrSLType, kDefault_GrSLPrecision,
    965                                             "Conical2FSCenter");
    966     fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
    967                                            kVec3f_GrSLType, kDefault_GrSLPrecision,
    968                                            "Conical2FSParams");
    969     SkString tName("t");
    970 
    971     GrShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
    972     // params.x = A
    973     // params.y = B
    974     // params.z = C
    975     GrShaderVar params = uniformHandler->getUniformVariable(fParamUni);
    976 
    977     // if we have a vec3 from being in perspective, convert it to a vec2 first
    978     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
    979     SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
    980     const char* coords2D = coords2DString.c_str();
    981 
    982     // p = coords2D
    983     // e = center end
    984     // r = radius end
    985     // A = dot(e, e) - r^2 + 2 * r - 1
    986     // B = (r -1) / A
    987     // C = 1 / A
    988     // d = dot(e, p) + B
    989     // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
    990     fragBuilder->codeAppendf("\tfloat pDotp = dot(%s,  %s);\n", coords2D, coords2D);
    991     fragBuilder->codeAppendf("\tfloat d = dot(%s,  %s) + %s.y;\n", coords2D, center.c_str(),
    992                              params.c_str());
    993     fragBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
    994                              tName.c_str(), params.c_str(), params.c_str());
    995 
    996     this->emitColor(fragBuilder,
    997                     uniformHandler,
    998                     args.fShaderCaps,
    999                     ge,
   1000                     tName.c_str(),
   1001                     args.fOutputColor,
   1002                     args.fInputColor,
   1003                     args.fTexSamplers);
   1004 }
   1005 
   1006 void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::onSetData(
   1007         const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) {
   1008     INHERITED::onSetData(pdman, processor);
   1009     const CircleInside2PtConicalEffect& data = processor.cast<CircleInside2PtConicalEffect>();
   1010     SkScalar centerX = data.centerX();
   1011     SkScalar centerY = data.centerY();
   1012     SkScalar A = data.A();
   1013     SkScalar B = data.B();
   1014     SkScalar C = data.C();
   1015 
   1016     if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
   1017         fCachedA != A || fCachedB != B || fCachedC != C) {
   1018 
   1019         pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
   1020         pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
   1021 
   1022         fCachedCenterX = centerX;
   1023         fCachedCenterY = centerY;
   1024         fCachedA = A;
   1025         fCachedB = B;
   1026         fCachedC = C;
   1027     }
   1028 }
   1029 
   1030 void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey(
   1031                                             const GrProcessor& processor,
   1032                                             const GrShaderCaps&, GrProcessorKeyBuilder* b) {
   1033     b->add32(GenBaseGradientKey(processor));
   1034 }
   1035 
   1036 //////////////////////////////////////////////////////////////////////////////
   1037 
   1038 class CircleOutside2PtConicalEffect : public GrGradientEffect {
   1039 public:
   1040     class GLSLCircleOutside2PtConicalProcessor;
   1041 
   1042     static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, const CircleConicalInfo& info) {
   1043         return sk_sp<GrFragmentProcessor>(
   1044             new CircleOutside2PtConicalEffect(args, info));
   1045     }
   1046 
   1047     ~CircleOutside2PtConicalEffect() override {}
   1048 
   1049     const char* name() const override { return "Two-Point Conical Gradient Outside"; }
   1050 
   1051     SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
   1052     SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
   1053     SkScalar A() const { return fInfo.fA; }
   1054     SkScalar B() const { return fInfo.fB; }
   1055     SkScalar C() const { return fInfo.fC; }
   1056     SkScalar tLimit() const { return fTLimit; }
   1057     bool isFlipped() const { return fIsFlipped; }
   1058 
   1059 private:
   1060     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
   1061 
   1062     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
   1063 
   1064     bool onIsEqual(const GrFragmentProcessor& sBase) const override {
   1065         const CircleOutside2PtConicalEffect& s = sBase.cast<CircleOutside2PtConicalEffect>();
   1066         return (INHERITED::onIsEqual(sBase) &&
   1067                 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
   1068                 this->fInfo.fA == s.fInfo.fA &&
   1069                 this->fInfo.fB == s.fInfo.fB &&
   1070                 this->fInfo.fC == s.fInfo.fC &&
   1071                 this->fTLimit == s.fTLimit &&
   1072                 this->fIsFlipped == s.fIsFlipped);
   1073     }
   1074 
   1075     CircleOutside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
   1076             : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */)
   1077             , fInfo(info) {
   1078         this->initClassID<CircleOutside2PtConicalEffect>();
   1079         const SkTwoPointConicalGradient& shader =
   1080             *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
   1081         if (shader.getStartRadius() != shader.getEndRadius()) {
   1082             fTLimit = shader.getStartRadius() / (shader.getStartRadius() - shader.getEndRadius());
   1083         } else {
   1084             fTLimit = SK_ScalarMin;
   1085         }
   1086 
   1087         fIsFlipped = shader.isFlippedGrad();
   1088     }
   1089 
   1090     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
   1091 
   1092     const CircleConicalInfo fInfo;
   1093     SkScalar fTLimit;
   1094     bool fIsFlipped;
   1095 
   1096     typedef GrGradientEffect INHERITED;
   1097 };
   1098 
   1099 class CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor
   1100     : public GrGradientEffect::GLSLProcessor {
   1101 public:
   1102     GLSLCircleOutside2PtConicalProcessor(const GrProcessor&);
   1103     ~GLSLCircleOutside2PtConicalProcessor() override {}
   1104 
   1105     virtual void emitCode(EmitArgs&) override;
   1106 
   1107     static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
   1108 
   1109 protected:
   1110     void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
   1111 
   1112     UniformHandle fCenterUni;
   1113     UniformHandle fParamUni;
   1114 
   1115     const char* fVSVaryingName;
   1116     const char* fFSVaryingName;
   1117 
   1118     bool fIsFlipped;
   1119 
   1120     // @{
   1121     /// Values last uploaded as uniforms
   1122 
   1123     SkScalar fCachedCenterX;
   1124     SkScalar fCachedCenterY;
   1125     SkScalar fCachedA;
   1126     SkScalar fCachedB;
   1127     SkScalar fCachedC;
   1128     SkScalar fCachedTLimit;
   1129 
   1130     // @}
   1131 
   1132 private:
   1133     typedef GrGradientEffect::GLSLProcessor INHERITED;
   1134 
   1135 };
   1136 
   1137 void CircleOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
   1138                                                           GrProcessorKeyBuilder* b) const {
   1139     CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey(*this, caps, b);
   1140 }
   1141 
   1142 GrGLSLFragmentProcessor* CircleOutside2PtConicalEffect::onCreateGLSLInstance() const {
   1143     return new CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor(*this);
   1144 }
   1145 
   1146 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect);
   1147 
   1148 /*
   1149  * All Two point conical gradient test create functions may occasionally create edge case shaders
   1150  */
   1151 #if GR_TEST_UTILS
   1152 sk_sp<GrFragmentProcessor> CircleOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
   1153     SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
   1154     SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
   1155     SkPoint center2;
   1156     SkScalar radius2;
   1157     SkScalar diffLen;
   1158     do {
   1159         center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
   1160         // If the circles share a center than we can't be in the outside case
   1161     } while (center1 == center2);
   1162     SkPoint diff = center2 - center1;
   1163     diffLen = diff.length();
   1164     // Below makes sure that circle one is not contained within circle two
   1165     // and have radius2 >= radius to match sorting on cpu side
   1166     radius2 = radius1 + d->fRandom->nextRangeF(0.f, diffLen);
   1167 
   1168     RandomGradientParams params(d->fRandom);
   1169     auto shader = params.fUseColors4f ?
   1170         SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
   1171                                               params.fColors4f, params.fColorSpace, params.fStops,
   1172                                               params.fColorCount, params.fTileMode) :
   1173         SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
   1174                                               params.fColors, params.fStops,
   1175                                               params.fColorCount, params.fTileMode);
   1176     GrTest::TestAsFPArgs asFPArgs(d);
   1177     sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
   1178     GrAlwaysAssert(fp);
   1179     return fp;
   1180 }
   1181 #endif
   1182 
   1183 CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor
   1184                              ::GLSLCircleOutside2PtConicalProcessor(const GrProcessor& processor)
   1185     : fVSVaryingName(nullptr)
   1186     , fFSVaryingName(nullptr)
   1187     , fCachedCenterX(SK_ScalarMax)
   1188     , fCachedCenterY(SK_ScalarMax)
   1189     , fCachedA(SK_ScalarMax)
   1190     , fCachedB(SK_ScalarMax)
   1191     , fCachedC(SK_ScalarMax)
   1192     , fCachedTLimit(SK_ScalarMax) {
   1193     const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
   1194     fIsFlipped = data.isFlipped();
   1195     }
   1196 
   1197 void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::emitCode(EmitArgs& args) {
   1198     const CircleOutside2PtConicalEffect& ge = args.fFp.cast<CircleOutside2PtConicalEffect>();
   1199     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
   1200     this->emitUniforms(uniformHandler, ge);
   1201     fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
   1202                                             kVec2f_GrSLType, kDefault_GrSLPrecision,
   1203                                             "Conical2FSCenter");
   1204     fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
   1205                                            kVec4f_GrSLType, kDefault_GrSLPrecision,
   1206                                            "Conical2FSParams");
   1207     SkString tName("t");
   1208 
   1209     GrShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
   1210     // params.x = A
   1211     // params.y = B
   1212     // params.z = C
   1213     GrShaderVar params = uniformHandler->getUniformVariable(fParamUni);
   1214 
   1215     // if we have a vec3 from being in perspective, convert it to a vec2 first
   1216     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
   1217     SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
   1218     const char* coords2D = coords2DString.c_str();
   1219 
   1220     // output will default to transparent black (we simply won't write anything
   1221     // else to it if invalid, instead of discarding or returning prematurely)
   1222     fragBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", args.fOutputColor);
   1223 
   1224     // p = coords2D
   1225     // e = center end
   1226     // r = radius end
   1227     // A = dot(e, e) - r^2 + 2 * r - 1
   1228     // B = (r -1) / A
   1229     // C = 1 / A
   1230     // d = dot(e, p) + B
   1231     // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
   1232 
   1233     fragBuilder->codeAppendf("\tfloat pDotp = dot(%s,  %s);\n", coords2D, coords2D);
   1234     fragBuilder->codeAppendf("\tfloat d = dot(%s,  %s) + %s.y;\n", coords2D, center.c_str(),
   1235                              params.c_str());
   1236     fragBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
   1237                              params.c_str());
   1238 
   1239     // Must check to see if we flipped the circle order (to make sure start radius < end radius)
   1240     // If so we must also flip sign on sqrt
   1241     if (!fIsFlipped) {
   1242         fragBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
   1243     } else {
   1244         fragBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
   1245     }
   1246 
   1247     fragBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n",
   1248                              tName.c_str(), params.c_str());
   1249     fragBuilder->codeAppend("\t\t");
   1250     this->emitColor(fragBuilder,
   1251                     uniformHandler,
   1252                     args.fShaderCaps,
   1253                     ge,
   1254                     tName.c_str(),
   1255                     args.fOutputColor,
   1256                     args.fInputColor,
   1257                     args.fTexSamplers);
   1258     fragBuilder->codeAppend("\t}\n");
   1259 }
   1260 
   1261 void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::onSetData(
   1262         const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) {
   1263     INHERITED::onSetData(pdman, processor);
   1264     const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
   1265     SkASSERT(data.isFlipped() == fIsFlipped);
   1266     SkScalar centerX = data.centerX();
   1267     SkScalar centerY = data.centerY();
   1268     SkScalar A = data.A();
   1269     SkScalar B = data.B();
   1270     SkScalar C = data.C();
   1271     SkScalar tLimit = data.tLimit();
   1272 
   1273     if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
   1274         fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
   1275 
   1276         pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
   1277         pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
   1278                    SkScalarToFloat(tLimit));
   1279 
   1280         fCachedCenterX = centerX;
   1281         fCachedCenterY = centerY;
   1282         fCachedA = A;
   1283         fCachedB = B;
   1284         fCachedC = C;
   1285         fCachedTLimit = tLimit;
   1286     }
   1287 }
   1288 
   1289 void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey(
   1290                                             const GrProcessor& processor,
   1291                                             const GrShaderCaps&, GrProcessorKeyBuilder* b) {
   1292     uint32_t* key = b->add32n(2);
   1293     key[0] = GenBaseGradientKey(processor);
   1294     key[1] = processor.cast<CircleOutside2PtConicalEffect>().isFlipped();
   1295 }
   1296 
   1297 //////////////////////////////////////////////////////////////////////////////
   1298 
   1299 sk_sp<GrFragmentProcessor> Gr2PtConicalGradientEffect::Make(
   1300                                                          const GrGradientEffect::CreateArgs& args) {
   1301     const SkTwoPointConicalGradient& shader =
   1302         *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
   1303 
   1304     SkMatrix matrix;
   1305     if (!shader.getLocalMatrix().invert(&matrix)) {
   1306         return nullptr;
   1307     }
   1308     if (args.fMatrix) {
   1309         SkMatrix inv;
   1310         if (!args.fMatrix->invert(&inv)) {
   1311             return nullptr;
   1312         }
   1313         matrix.postConcat(inv);
   1314     }
   1315 
   1316     GrGradientEffect::CreateArgs newArgs(args.fContext, args.fShader, &matrix, args.fTileMode,
   1317                                          std::move(args.fColorSpaceXform), args.fGammaCorrect);
   1318 
   1319     if (shader.getStartRadius() < kErrorTol) {
   1320         SkScalar focalX;
   1321         ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
   1322         if (type == kInside_ConicalType) {
   1323             return FocalInside2PtConicalEffect::Make(newArgs, focalX);
   1324         } else if(type == kEdge_ConicalType) {
   1325             set_matrix_edge_conical(shader, &matrix);
   1326             return Edge2PtConicalEffect::Make(newArgs);
   1327         } else {
   1328             return FocalOutside2PtConicalEffect::Make(newArgs, focalX);
   1329         }
   1330     }
   1331 
   1332     CircleConicalInfo info;
   1333     ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
   1334 
   1335     if (type == kInside_ConicalType) {
   1336         return CircleInside2PtConicalEffect::Make(newArgs, info);
   1337     } else if (type == kEdge_ConicalType) {
   1338         set_matrix_edge_conical(shader, &matrix);
   1339         return Edge2PtConicalEffect::Make(newArgs);
   1340     } else {
   1341         return CircleOutside2PtConicalEffect::Make(newArgs, info);
   1342     }
   1343 }
   1344 
   1345 #endif
   1346