Upstream version 8.37.180.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 #include "SkGr.h"
178
179 class GrGLSweepGradient : public GrGLGradientEffect {
180 public:
181
182     GrGLSweepGradient(const GrBackendEffectFactory& factory,
183                       const GrDrawEffect&) : INHERITED (factory) { }
184     virtual ~GrGLSweepGradient() { }
185
186     virtual void emitCode(GrGLShaderBuilder*,
187                           const GrDrawEffect&,
188                           EffectKey,
189                           const char* outputColor,
190                           const char* inputColor,
191                           const TransformedCoordsArray&,
192                           const TextureSamplerArray&) SK_OVERRIDE;
193
194     static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
195         return GenBaseGradientKey(drawEffect);
196     }
197
198 private:
199
200     typedef GrGLGradientEffect INHERITED;
201
202 };
203
204 /////////////////////////////////////////////////////////////////////
205
206 class GrSweepGradient : public GrGradientEffect {
207 public:
208     static GrEffectRef* Create(GrContext* ctx,
209                                const SkSweepGradient& shader,
210                                const SkMatrix& matrix) {
211         AutoEffectUnref effect(SkNEW_ARGS(GrSweepGradient, (ctx, shader, matrix)));
212         return CreateEffectRef(effect);
213     }
214     virtual ~GrSweepGradient() { }
215
216     static const char* Name() { return "Sweep Gradient"; }
217     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
218         return GrTBackendEffectFactory<GrSweepGradient>::getInstance();
219     }
220
221     typedef GrGLSweepGradient GLEffect;
222
223 private:
224     GrSweepGradient(GrContext* ctx,
225                     const SkSweepGradient& shader,
226                     const SkMatrix& matrix)
227     : INHERITED(ctx, shader, matrix, SkShader::kClamp_TileMode) { }
228     GR_DECLARE_EFFECT_TEST;
229
230     typedef GrGradientEffect INHERITED;
231 };
232
233 /////////////////////////////////////////////////////////////////////
234
235 GR_DEFINE_EFFECT_TEST(GrSweepGradient);
236
237 GrEffectRef* GrSweepGradient::TestCreate(SkRandom* random,
238                                          GrContext* context,
239                                          const GrDrawTargetCaps&,
240                                          GrTexture**) {
241     SkPoint center = {random->nextUScalar1(), random->nextUScalar1()};
242
243     SkColor colors[kMaxRandomGradientColors];
244     SkScalar stopsArray[kMaxRandomGradientColors];
245     SkScalar* stops = stopsArray;
246     SkShader::TileMode tmIgnored;
247     int colorCount = RandomGradientParams(random, colors, &stops, &tmIgnored);
248     SkAutoTUnref<SkShader> shader(SkGradientShader::CreateSweep(center.fX, center.fY,
249                                                                 colors, stops, colorCount));
250     SkPaint paint;
251     GrEffectRef* effect;
252     GrColor grColor;
253     shader->asNewEffect(context, paint, NULL, &grColor, &effect);
254     return effect;
255 }
256
257 /////////////////////////////////////////////////////////////////////
258
259 void GrGLSweepGradient::emitCode(GrGLShaderBuilder* builder,
260                                  const GrDrawEffect&,
261                                  EffectKey key,
262                                  const char* outputColor,
263                                  const char* inputColor,
264                                  const TransformedCoordsArray& coords,
265                                  const TextureSamplerArray& samplers) {
266     this->emitUniforms(builder, key);
267     SkString coords2D = builder->ensureFSCoords2D(coords, 0);
268     const GrGLContextInfo ctxInfo = builder->ctxInfo();
269     SkString t;
270     // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi]
271     // On Intel GPU there is an issue where it reads the second arguement to atan "- %s.x" as an int
272     // thus must us -1.0 * %s.x to work correctly
273     if (kIntel_GrGLVendor != ctxInfo.vendor()){
274         t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5",
275                  coords2D.c_str(), coords2D.c_str());
276     } else {
277         t.printf("atan(- %s.y, -1.0 * %s.x) * 0.1591549430918 + 0.5",
278                  coords2D.c_str(), coords2D.c_str());
279     }
280     this->emitColor(builder, t.c_str(), key,
281                           outputColor, inputColor, samplers);
282 }
283
284 /////////////////////////////////////////////////////////////////////
285
286 bool SkSweepGradient::asNewEffect(GrContext* context, const SkPaint& paint,
287                                   const SkMatrix* localMatrix, GrColor* grColor,
288                                   GrEffectRef** grEffect)  const {
289     
290     SkMatrix matrix;
291     if (!this->getLocalMatrix().invert(&matrix)) {
292         return false;
293     }
294     if (localMatrix) {
295         SkMatrix inv;
296         if (!localMatrix->invert(&inv)) {
297             return false;
298         }
299         matrix.postConcat(inv);
300     }
301     matrix.postConcat(fPtsToUnit);
302     
303     *grEffect = GrSweepGradient::Create(context, *this, matrix);
304     *grColor = SkColor2GrColorJustAlpha(paint.getColor());
305     
306     return true;
307 }
308
309 #else
310
311 bool SkSweepGradient::asNewEffect(GrContext* context, const SkPaint& paint,
312                                   const SkMatrix* localMatrix, GrColor* grColor,
313                                   GrEffectRef** grEffect)  const {
314     SkDEBUGFAIL("Should not call in GPU-less build");
315     return false;
316 }
317
318 #endif
319
320 #ifndef SK_IGNORE_TO_STRING
321 void SkSweepGradient::toString(SkString* str) const {
322     str->append("SkSweepGradient: (");
323
324     str->append("center: (");
325     str->appendScalar(fCenter.fX);
326     str->append(", ");
327     str->appendScalar(fCenter.fY);
328     str->append(") ");
329
330     this->INHERITED::toString(str);
331
332     str->append(")");
333 }
334 #endif