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