LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/effects/gradients - SkTwoPointConicalGradient_gpu.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 556 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 97 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13