Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / effects / GrOvalEffect.cpp
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 #include "GrOvalEffect.h"
9
10 #include "gl/GrGLEffect.h"
11 #include "gl/GrGLSL.h"
12 #include "GrTBackendEffectFactory.h"
13
14 #include "SkRect.h"
15
16 //////////////////////////////////////////////////////////////////////////////
17
18 class GLCircleEffect;
19
20 class CircleEffect : public GrEffect {
21 public:
22     static GrEffectRef* Create(GrEffectEdgeType, const SkPoint& center, SkScalar radius);
23
24     virtual ~CircleEffect() {};
25     static const char* Name() { return "Circle"; }
26
27     const SkPoint& getCenter() const { return fCenter; }
28     SkScalar getRadius() const { return fRadius; }
29
30     GrEffectEdgeType getEdgeType() const { return fEdgeType; }
31
32     typedef GLCircleEffect GLEffect;
33
34     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
35
36     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
37
38 private:
39     CircleEffect(GrEffectEdgeType, const SkPoint& center, SkScalar radius);
40
41     virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
42
43     SkPoint             fCenter;
44     SkScalar            fRadius;
45     GrEffectEdgeType    fEdgeType;
46
47     GR_DECLARE_EFFECT_TEST;
48
49     typedef GrEffect INHERITED;
50 };
51
52 GrEffectRef* CircleEffect::Create(GrEffectEdgeType edgeType,
53                                   const SkPoint& center,
54                                   SkScalar radius) {
55     SkASSERT(radius >= 0);
56     return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircleEffect,
57                                                       (edgeType, center, radius))));
58 }
59
60 void CircleEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
61     *validFlags = 0;
62 }
63
64 const GrBackendEffectFactory& CircleEffect::getFactory() const {
65     return GrTBackendEffectFactory<CircleEffect>::getInstance();
66 }
67
68 CircleEffect::CircleEffect(GrEffectEdgeType edgeType, const SkPoint& c, SkScalar r)
69     : fCenter(c)
70     , fRadius(r)
71     , fEdgeType(edgeType) {
72     this->setWillReadFragmentPosition();
73 }
74
75 bool CircleEffect::onIsEqual(const GrEffect& other) const {
76     const CircleEffect& ce = CastEffect<CircleEffect>(other);
77     return fEdgeType == ce.fEdgeType && fCenter == ce.fCenter && fRadius == ce.fRadius;
78 }
79
80 //////////////////////////////////////////////////////////////////////////////
81
82 GR_DEFINE_EFFECT_TEST(CircleEffect);
83
84 GrEffectRef* CircleEffect::TestCreate(SkRandom* random,
85                                       GrContext*,
86                                       const GrDrawTargetCaps& caps,
87                                       GrTexture*[]) {
88     SkPoint center;
89     center.fX = random->nextRangeScalar(0.f, 1000.f);
90     center.fY = random->nextRangeScalar(0.f, 1000.f);
91     SkScalar radius = random->nextRangeF(0.f, 1000.f);
92     GrEffectEdgeType et;
93     do {
94         et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt);
95     } while (kHairlineAA_GrEffectEdgeType == et);
96     return CircleEffect::Create(et, center, radius);
97 }
98
99 //////////////////////////////////////////////////////////////////////////////
100
101 class GLCircleEffect : public GrGLEffect {
102 public:
103     GLCircleEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
104
105     virtual void emitCode(GrGLShaderBuilder* builder,
106                           const GrDrawEffect& drawEffect,
107                           EffectKey key,
108                           const char* outputColor,
109                           const char* inputColor,
110                           const TransformedCoordsArray&,
111                           const TextureSamplerArray&) SK_OVERRIDE;
112
113     static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
114
115     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
116
117 private:
118     GrGLUniformManager::UniformHandle   fCircleUniform;
119     SkPoint                             fPrevCenter;
120     SkScalar                            fPrevRadius;
121
122     typedef GrGLEffect INHERITED;
123 };
124
125 GLCircleEffect::GLCircleEffect(const GrBackendEffectFactory& factory,
126                                const GrDrawEffect& drawEffect)
127     : INHERITED (factory) {
128     fPrevRadius = -1.f;
129 }
130
131 void GLCircleEffect::emitCode(GrGLShaderBuilder* builder,
132                               const GrDrawEffect& drawEffect,
133                               EffectKey key,
134                               const char* outputColor,
135                               const char* inputColor,
136                               const TransformedCoordsArray&,
137                               const TextureSamplerArray& samplers) {
138     const CircleEffect& ce = drawEffect.castEffect<CircleEffect>();
139     const char *circleName;
140     // The circle uniform is (center.x, center.y, radius + 0.5) for regular fills and
141     // (... ,radius - 0.5) for inverse fills.
142     fCircleUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
143                                          kVec3f_GrSLType,
144                                          "circle",
145                                          &circleName);
146     const char* fragmentPos = builder->fragmentPosition();
147
148     SkASSERT(kHairlineAA_GrEffectEdgeType != ce.getEdgeType());
149     if (GrEffectEdgeTypeIsInverseFill(ce.getEdgeType())) {
150         builder->fsCodeAppendf("\t\tfloat d = length(%s.xy - %s.xy) - %s.z;\n",
151                                 circleName, fragmentPos, circleName);
152     } else {
153         builder->fsCodeAppendf("\t\tfloat d = %s.z - length(%s.xy - %s.xy);\n",
154                                circleName, fragmentPos, circleName);
155     }
156     if (GrEffectEdgeTypeIsAA(ce.getEdgeType())) {
157         builder->fsCodeAppend("\t\td = clamp(d, 0.0, 1.0);\n");
158     } else {
159         builder->fsCodeAppend("\t\td = d > 0.5 ? 1.0 : 0.0;\n");
160     }
161
162     builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
163                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("d")).c_str());
164 }
165
166 GrGLEffect::EffectKey GLCircleEffect::GenKey(const GrDrawEffect& drawEffect,
167                                              const GrGLCaps&) {
168     const CircleEffect& ce = drawEffect.castEffect<CircleEffect>();
169     return ce.getEdgeType();
170 }
171
172 void GLCircleEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) {
173     const CircleEffect& ce = drawEffect.castEffect<CircleEffect>();
174     if (ce.getRadius() != fPrevRadius || ce.getCenter() != fPrevCenter) {
175         SkScalar radius = ce.getRadius();
176         if (GrEffectEdgeTypeIsInverseFill(ce.getEdgeType())) {
177             radius -= 0.5f;
178         } else {
179             radius += 0.5f;
180         }
181         uman.set3f(fCircleUniform, ce.getCenter().fX, ce.getCenter().fY, radius);
182         fPrevCenter = ce.getCenter();
183         fPrevRadius = ce.getRadius();
184     }
185 }
186
187 //////////////////////////////////////////////////////////////////////////////
188
189 class GLEllipseEffect;
190
191 class EllipseEffect : public GrEffect {
192 public:
193     static GrEffectRef* Create(GrEffectEdgeType, const SkPoint& center, SkScalar rx, SkScalar ry);
194
195     virtual ~EllipseEffect() {};
196     static const char* Name() { return "Ellipse"; }
197
198     const SkPoint& getCenter() const { return fCenter; }
199     SkVector getRadii() const { return fRadii; }
200
201     GrEffectEdgeType getEdgeType() const { return fEdgeType; }
202
203     typedef GLEllipseEffect GLEffect;
204
205     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
206
207     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
208
209 private:
210     EllipseEffect(GrEffectEdgeType, const SkPoint& center, SkScalar rx, SkScalar ry);
211
212     virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
213
214     SkPoint             fCenter;
215     SkVector            fRadii;
216     GrEffectEdgeType    fEdgeType;
217
218     GR_DECLARE_EFFECT_TEST;
219
220     typedef GrEffect INHERITED;
221 };
222
223 GrEffectRef* EllipseEffect::Create(GrEffectEdgeType edgeType,
224                                    const SkPoint& center,
225                                    SkScalar rx,
226                                    SkScalar ry) {
227     SkASSERT(rx >= 0 && ry >= 0);
228     return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipseEffect,
229                                                       (edgeType, center, rx, ry))));
230 }
231
232 void EllipseEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
233     *validFlags = 0;
234 }
235
236 const GrBackendEffectFactory& EllipseEffect::getFactory() const {
237     return GrTBackendEffectFactory<EllipseEffect>::getInstance();
238 }
239
240 EllipseEffect::EllipseEffect(GrEffectEdgeType edgeType, const SkPoint& c, SkScalar rx, SkScalar ry)
241     : fCenter(c)
242     , fRadii(SkVector::Make(rx, ry))
243     , fEdgeType(edgeType) {
244     this->setWillReadFragmentPosition();
245 }
246
247 bool EllipseEffect::onIsEqual(const GrEffect& other) const {
248     const EllipseEffect& ee = CastEffect<EllipseEffect>(other);
249     return fEdgeType == ee.fEdgeType && fCenter == ee.fCenter && fRadii == ee.fRadii;
250 }
251
252 //////////////////////////////////////////////////////////////////////////////
253
254 GR_DEFINE_EFFECT_TEST(EllipseEffect);
255
256 GrEffectRef* EllipseEffect::TestCreate(SkRandom* random,
257                                        GrContext*,
258                                        const GrDrawTargetCaps& caps,
259                                        GrTexture*[]) {
260     SkPoint center;
261     center.fX = random->nextRangeScalar(0.f, 1000.f);
262     center.fY = random->nextRangeScalar(0.f, 1000.f);
263     SkScalar rx = random->nextRangeF(0.f, 1000.f);
264     SkScalar ry = random->nextRangeF(0.f, 1000.f);
265     GrEffectEdgeType et;
266     do {
267         et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt);
268     } while (kHairlineAA_GrEffectEdgeType == et);
269     return EllipseEffect::Create(et, center, rx, ry);
270 }
271
272 //////////////////////////////////////////////////////////////////////////////
273
274 class GLEllipseEffect : public GrGLEffect {
275 public:
276     GLEllipseEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
277
278     virtual void emitCode(GrGLShaderBuilder* builder,
279                           const GrDrawEffect& drawEffect,
280                           EffectKey key,
281                           const char* outputColor,
282                           const char* inputColor,
283                           const TransformedCoordsArray&,
284                           const TextureSamplerArray&) SK_OVERRIDE;
285
286     static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
287
288     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
289
290 private:
291     GrGLUniformManager::UniformHandle   fEllipseUniform;
292     SkPoint                             fPrevCenter;
293     SkVector                            fPrevRadii;
294
295     typedef GrGLEffect INHERITED;
296 };
297
298 GLEllipseEffect::GLEllipseEffect(const GrBackendEffectFactory& factory,
299                                  const GrDrawEffect& drawEffect)
300     : INHERITED (factory) {
301     fPrevRadii.fX = -1.f;
302 }
303
304 void GLEllipseEffect::emitCode(GrGLShaderBuilder* builder,
305                                const GrDrawEffect& drawEffect,
306                                EffectKey key,
307                                const char* outputColor,
308                                const char* inputColor,
309                                const TransformedCoordsArray&,
310                                const TextureSamplerArray& samplers) {
311     const EllipseEffect& ee = drawEffect.castEffect<EllipseEffect>();
312     const char *ellipseName;
313     // The ellipse uniform is (center.x, center.y, 1 / rx^2, 1 / ry^2)
314     fEllipseUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
315                                          kVec4f_GrSLType,
316                                          "ellipse",
317                                          &ellipseName);
318     const char* fragmentPos = builder->fragmentPosition();
319
320     // d is the offset to the ellipse center
321     builder->fsCodeAppendf("\t\tvec2 d = %s.xy - %s.xy;\n", fragmentPos, ellipseName);
322     builder->fsCodeAppendf("\t\tvec2 Z = d * %s.zw;\n", ellipseName);
323     // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1.
324     builder->fsCodeAppend("\t\tfloat implicit = dot(Z, d) - 1.0;\n");
325     // grad_dot is the squared length of the gradient of the implicit.
326     builder->fsCodeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n");
327     // avoid calling inversesqrt on zero.
328     builder->fsCodeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n");
329     builder->fsCodeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n");
330
331     switch (ee.getEdgeType()) {
332         case kFillAA_GrEffectEdgeType:
333             builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n");
334             break;
335         case kInverseFillAA_GrEffectEdgeType:
336             builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n");
337             break;
338         case kFillBW_GrEffectEdgeType:
339             builder->fsCodeAppend("\t\tfloat alpha = approx_dist > 0.0 ? 0.0 : 1.0;\n");
340             break;
341         case kInverseFillBW_GrEffectEdgeType:
342             builder->fsCodeAppend("\t\tfloat alpha = approx_dist > 0.0 ? 1.0 : 0.0;\n");
343             break;
344         case kHairlineAA_GrEffectEdgeType:
345             SkFAIL("Hairline not expected here.");
346     }
347
348     builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
349                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
350 }
351
352 GrGLEffect::EffectKey GLEllipseEffect::GenKey(const GrDrawEffect& drawEffect,
353                                               const GrGLCaps&) {
354     const EllipseEffect& ee = drawEffect.castEffect<EllipseEffect>();
355     return ee.getEdgeType();
356 }
357
358 void GLEllipseEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) {
359     const EllipseEffect& ee = drawEffect.castEffect<EllipseEffect>();
360     if (ee.getRadii() != fPrevRadii || ee.getCenter() != fPrevCenter) {
361         SkScalar invRXSqd = 1.f / (ee.getRadii().fX * ee.getRadii().fX);
362         SkScalar invRYSqd = 1.f / (ee.getRadii().fY * ee.getRadii().fY);
363         uman.set4f(fEllipseUniform, ee.getCenter().fX, ee.getCenter().fY, invRXSqd, invRYSqd);
364         fPrevCenter = ee.getCenter();
365         fPrevRadii = ee.getRadii();
366     }
367 }
368
369 //////////////////////////////////////////////////////////////////////////////
370
371 GrEffectRef* GrOvalEffect::Create(GrEffectEdgeType edgeType, const SkRect& oval) {
372     if (kHairlineAA_GrEffectEdgeType == edgeType) {
373         return NULL;
374     }
375     SkScalar w = oval.width();
376     SkScalar h = oval.height();
377     if (SkScalarNearlyEqual(w, h)) {
378         w /= 2;
379         return CircleEffect::Create(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + w), w);
380     } else {
381         w /= 2;
382         h /= 2;
383         return EllipseEffect::Create(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + h), w, h);
384     }
385
386     return NULL;
387 }