Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / effects / gradients / SkSweepGradient.cpp
1
2 /*
3  * Copyright 2012 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 "SkSweepGradient.h"
10
11 SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy,
12                                  const Descriptor& desc, const SkMatrix* localMatrix)
13     : SkGradientShaderBase(desc, localMatrix)
14     , fCenter(SkPoint::Make(cx, cy))
15 {
16     fPtsToUnit.setTranslate(-cx, -cy);
17
18     // overwrite the tilemode to a canonical value (since sweep ignores it)
19     fTileMode = SkShader::kClamp_TileMode;
20 }
21
22 SkShader::BitmapType SkSweepGradient::asABitmap(SkBitmap* bitmap,
23     SkMatrix* matrix, SkShader::TileMode* xy) const {
24     if (bitmap) {
25         this->getGradientTableBitmap(bitmap);
26     }
27     if (matrix) {
28         *matrix = fPtsToUnit;
29     }
30     if (xy) {
31         xy[0] = fTileMode;
32         xy[1] = kClamp_TileMode;
33     }
34     return kSweep_BitmapType;
35 }
36
37 SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const {
38     if (info) {
39         commonAsAGradient(info);
40         info->fPoint[0] = fCenter;
41     }
42     return kSweep_GradientType;
43 }
44
45 SkSweepGradient::SkSweepGradient(SkReadBuffer& buffer)
46     : INHERITED(buffer),
47       fCenter(buffer.readPoint()) {
48 }
49
50 void SkSweepGradient::flatten(SkWriteBuffer& buffer) const {
51     this->INHERITED::flatten(buffer);
52     buffer.writePoint(fCenter);
53 }
54
55 size_t SkSweepGradient::contextSize() const {
56     return sizeof(SweepGradientContext);
57 }
58
59 SkShader::Context* SkSweepGradient::onCreateContext(const ContextRec& rec, void* storage) const {
60     return SkNEW_PLACEMENT_ARGS(storage, SweepGradientContext, (*this, rec));
61 }
62
63 SkSweepGradient::SweepGradientContext::SweepGradientContext(
64         const SkSweepGradient& shader, const ContextRec& rec)
65     : INHERITED(shader, rec) {}
66
67 //  returns angle in a circle [0..2PI) -> [0..255]
68 static unsigned SkATan2_255(float y, float x) {
69     //    static const float g255Over2PI = 255 / (2 * SK_ScalarPI);
70     static const float g255Over2PI = 40.584510488433314f;
71
72     float result = sk_float_atan2(y, x);
73     if (result < 0) {
74         result += 2 * SK_ScalarPI;
75     }
76     SkASSERT(result >= 0);
77     // since our value is always >= 0, we can cast to int, which is faster than
78     // calling floorf()
79     int ir = (int)(result * g255Over2PI);
80     SkASSERT(ir >= 0 && ir <= 255);
81     return ir;
82 }
83
84 void SkSweepGradient::SweepGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
85                                                       int count) {
86     SkMatrix::MapXYProc proc = fDstToIndexProc;
87     const SkMatrix&     matrix = fDstToIndex;
88     const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
89     int                 toggle = init_dither_toggle(x, y);
90     SkPoint             srcPt;
91
92     if (fDstToIndexClass != kPerspective_MatrixClass) {
93         proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
94                      SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
95         SkScalar dx, fx = srcPt.fX;
96         SkScalar dy, fy = srcPt.fY;
97
98         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
99             SkFixed storage[2];
100             (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
101                                       &storage[0], &storage[1]);
102             dx = SkFixedToScalar(storage[0]);
103             dy = SkFixedToScalar(storage[1]);
104         } else {
105             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
106             dx = matrix.getScaleX();
107             dy = matrix.getSkewY();
108         }
109
110         for (; count > 0; --count) {
111             *dstC++ = cache[toggle + SkATan2_255(fy, fx)];
112             fx += dx;
113             fy += dy;
114             toggle = next_dither_toggle(toggle);
115         }
116     } else {  // perspective case
117         for (int stop = x + count; x < stop; x++) {
118             proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
119                          SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
120             *dstC++ = cache[toggle + SkATan2_255(srcPt.fY, srcPt.fX)];
121             toggle = next_dither_toggle(toggle);
122         }
123     }
124 }
125
126 void SkSweepGradient::SweepGradientContext::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
127                                                         int count) {
128     SkMatrix::MapXYProc proc = fDstToIndexProc;
129     const SkMatrix&     matrix = fDstToIndex;
130     const uint16_t* SK_RESTRICT cache = fCache->getCache16();
131     int                 toggle = init_dither_toggle16(x, y);
132     SkPoint             srcPt;
133
134     if (fDstToIndexClass != kPerspective_MatrixClass) {
135         proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
136                      SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
137         SkScalar dx, fx = srcPt.fX;
138         SkScalar dy, fy = srcPt.fY;
139
140         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
141             SkFixed storage[2];
142             (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
143                                       &storage[0], &storage[1]);
144             dx = SkFixedToScalar(storage[0]);
145             dy = SkFixedToScalar(storage[1]);
146         } else {
147             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
148             dx = matrix.getScaleX();
149             dy = matrix.getSkewY();
150         }
151
152         for (; count > 0; --count) {
153             int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits);
154             *dstC++ = cache[toggle + index];
155             toggle = next_dither_toggle16(toggle);
156             fx += dx;
157             fy += dy;
158         }
159     } else {  // perspective case
160         for (int stop = x + count; x < stop; x++) {
161             proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
162                          SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
163
164             int index = SkATan2_255(srcPt.fY, srcPt.fX);
165             index >>= (8 - kCache16Bits);
166             *dstC++ = cache[toggle + index];
167             toggle = next_dither_toggle16(toggle);
168         }
169     }
170 }
171
172 /////////////////////////////////////////////////////////////////////
173
174 #if SK_SUPPORT_GPU
175
176 #include "GrTBackendEffectFactory.h"
177
178 class GrGLSweepGradient : public GrGLGradientEffect {
179 public:
180
181     GrGLSweepGradient(const GrBackendEffectFactory& factory,
182                       const GrDrawEffect&) : INHERITED (factory) { }
183     virtual ~GrGLSweepGradient() { }
184
185     virtual void emitCode(GrGLShaderBuilder*,
186                           const GrDrawEffect&,
187                           EffectKey,
188                           const char* outputColor,
189                           const char* inputColor,
190                           const TransformedCoordsArray&,
191                           const TextureSamplerArray&) SK_OVERRIDE;
192
193     static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
194         return GenBaseGradientKey(drawEffect);
195     }
196
197 private:
198
199     typedef GrGLGradientEffect INHERITED;
200
201 };
202
203 /////////////////////////////////////////////////////////////////////
204
205 class GrSweepGradient : public GrGradientEffect {
206 public:
207     static GrEffectRef* Create(GrContext* ctx,
208                                const SkSweepGradient& shader,
209                                const SkMatrix& matrix) {
210         AutoEffectUnref effect(SkNEW_ARGS(GrSweepGradient, (ctx, shader, matrix)));
211         return CreateEffectRef(effect);
212     }
213     virtual ~GrSweepGradient() { }
214
215     static const char* Name() { return "Sweep Gradient"; }
216     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
217         return GrTBackendEffectFactory<GrSweepGradient>::getInstance();
218     }
219
220     typedef GrGLSweepGradient GLEffect;
221
222 private:
223     GrSweepGradient(GrContext* ctx,
224                     const SkSweepGradient& shader,
225                     const SkMatrix& matrix)
226     : INHERITED(ctx, shader, matrix, SkShader::kClamp_TileMode) { }
227     GR_DECLARE_EFFECT_TEST;
228
229     typedef GrGradientEffect INHERITED;
230 };
231
232 /////////////////////////////////////////////////////////////////////
233
234 GR_DEFINE_EFFECT_TEST(GrSweepGradient);
235
236 GrEffectRef* GrSweepGradient::TestCreate(SkRandom* random,
237                                          GrContext* context,
238                                          const GrDrawTargetCaps&,
239                                          GrTexture**) {
240     SkPoint center = {random->nextUScalar1(), random->nextUScalar1()};
241
242     SkColor colors[kMaxRandomGradientColors];
243     SkScalar stopsArray[kMaxRandomGradientColors];
244     SkScalar* stops = stopsArray;
245     SkShader::TileMode tmIgnored;
246     int colorCount = RandomGradientParams(random, colors, &stops, &tmIgnored);
247     SkAutoTUnref<SkShader> shader(SkGradientShader::CreateSweep(center.fX, center.fY,
248                                                                 colors, stops, colorCount));
249     SkPaint paint;
250     return shader->asNewEffect(context, paint);
251 }
252
253 /////////////////////////////////////////////////////////////////////
254
255 void GrGLSweepGradient::emitCode(GrGLShaderBuilder* builder,
256                                  const GrDrawEffect&,
257                                  EffectKey key,
258                                  const char* outputColor,
259                                  const char* inputColor,
260                                  const TransformedCoordsArray& coords,
261                                  const TextureSamplerArray& samplers) {
262     this->emitUniforms(builder, key);
263     SkString coords2D = builder->ensureFSCoords2D(coords, 0);
264     const GrGLContextInfo ctxInfo = builder->ctxInfo();
265     SkString t;
266     // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi]
267     // On Intel GPU there is an issue where it reads the second arguement to atan "- %s.x" as an int
268     // thus must us -1.0 * %s.x to work correctly
269     if (kIntel_GrGLVendor != ctxInfo.vendor()){
270         t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5",
271                  coords2D.c_str(), coords2D.c_str());
272     } else {
273         t.printf("atan(- %s.y, -1.0 * %s.x) * 0.1591549430918 + 0.5",
274                  coords2D.c_str(), coords2D.c_str());
275     }
276     this->emitColor(builder, t.c_str(), key,
277                           outputColor, inputColor, samplers);
278 }
279
280 /////////////////////////////////////////////////////////////////////
281
282 GrEffectRef* SkSweepGradient::asNewEffect(GrContext* context, const SkPaint&) const {
283     SkMatrix matrix;
284     if (!this->getLocalMatrix().invert(&matrix)) {
285         return NULL;
286     }
287     matrix.postConcat(fPtsToUnit);
288     return GrSweepGradient::Create(context, *this, matrix);
289 }
290
291 #else
292
293 GrEffectRef* SkSweepGradient::asNewEffect(GrContext*, const SkPaint&) const {
294     SkDEBUGFAIL("Should not call in GPU-less build");
295     return NULL;
296 }
297
298 #endif
299
300 #ifndef SK_IGNORE_TO_STRING
301 void SkSweepGradient::toString(SkString* str) const {
302     str->append("SkSweepGradient: (");
303
304     str->append("center: (");
305     str->appendScalar(fCenter.fX);
306     str->append(", ");
307     str->appendScalar(fCenter.fY);
308     str->append(") ");
309
310     this->INHERITED::toString(str);
311
312     str->append(")");
313 }
314 #endif