Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / effects / gradients / SkGradientShaderPriv.h
1 /*
2  * Copyright 2012 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 #ifndef SkGradientShaderPriv_DEFINED
9 #define SkGradientShaderPriv_DEFINED
10
11 #include "SkGradientShader.h"
12 #include "SkClampRange.h"
13 #include "SkColorPriv.h"
14 #include "SkReadBuffer.h"
15 #include "SkWriteBuffer.h"
16 #include "SkMallocPixelRef.h"
17 #include "SkUtils.h"
18 #include "SkTemplates.h"
19 #include "SkBitmapCache.h"
20 #include "SkShader.h"
21 #include "SkOnce.h"
22
23 static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
24                                int count) {
25     if (count > 0) {
26         if (v0 == v1) {
27             sk_memset32(dst, v0, count);
28         } else {
29             int pairs = count >> 1;
30             for (int i = 0; i < pairs; i++) {
31                 *dst++ = v0;
32                 *dst++ = v1;
33             }
34             if (count & 1) {
35                 *dst = v0;
36             }
37         }
38     }
39 }
40
41 //  Clamp
42
43 static inline SkFixed clamp_tileproc(SkFixed x) {
44     return SkClampMax(x, 0xFFFF);
45 }
46
47 // Repeat
48
49 static inline SkFixed repeat_tileproc(SkFixed x) {
50     return x & 0xFFFF;
51 }
52
53 // Mirror
54
55 // Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly.
56 // See http://code.google.com/p/skia/issues/detail?id=472
57 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
58 #pragma optimize("", off)
59 #endif
60
61 static inline SkFixed mirror_tileproc(SkFixed x) {
62     int s = x << 15 >> 31;
63     return (x ^ s) & 0xFFFF;
64 }
65
66 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
67 #pragma optimize("", on)
68 #endif
69
70 ///////////////////////////////////////////////////////////////////////////////
71
72 typedef SkFixed (*TileProc)(SkFixed);
73
74 ///////////////////////////////////////////////////////////////////////////////
75
76 static const TileProc gTileProcs[] = {
77     clamp_tileproc,
78     repeat_tileproc,
79     mirror_tileproc
80 };
81
82 ///////////////////////////////////////////////////////////////////////////////
83
84 class SkGradientShaderBase : public SkShader {
85 public:
86     struct Descriptor {
87         Descriptor() {
88             sk_bzero(this, sizeof(*this));
89             fTileMode = SkShader::kClamp_TileMode;
90         }
91
92         const SkMatrix*     fLocalMatrix;
93         const SkColor*      fColors;
94         const SkScalar*     fPos;
95         int                 fCount;
96         SkShader::TileMode  fTileMode;
97         uint32_t            fGradFlags;
98     };
99
100 public:
101     SkGradientShaderBase(const Descriptor& desc);
102     virtual ~SkGradientShaderBase();
103
104     // The cache is initialized on-demand when getCache16/32 is called.
105     class GradientShaderCache : public SkRefCnt {
106     public:
107         GradientShaderCache(U8CPU alpha, const SkGradientShaderBase& shader);
108         ~GradientShaderCache();
109
110         const uint16_t*     getCache16();
111         const SkPMColor*    getCache32();
112
113         SkMallocPixelRef* getCache32PixelRef() const { return fCache32PixelRef; }
114
115         unsigned getAlpha() const { return fCacheAlpha; }
116
117     private:
118         // Working pointers. If either is NULL, we need to recompute the corresponding cache values.
119         uint16_t*   fCache16;
120         SkPMColor*  fCache32;
121
122         uint16_t*         fCache16Storage;    // Storage for fCache16, allocated on demand.
123         SkMallocPixelRef* fCache32PixelRef;
124         const unsigned    fCacheAlpha;        // The alpha value we used when we computed the cache.
125                                               // Larger than 8bits so we can store uninitialized
126                                               // value.
127
128         const SkGradientShaderBase& fShader;
129
130         // Make sure we only initialize the caches once.
131         bool    fCache16Inited, fCache32Inited;
132         SkMutex fCache16Mutex, fCache32Mutex;
133
134         static void initCache16(GradientShaderCache* cache);
135         static void initCache32(GradientShaderCache* cache);
136
137         static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count);
138         static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
139                                     U8CPU alpha, uint32_t gradFlags);
140     };
141
142     class GradientShaderBaseContext : public SkShader::Context {
143     public:
144         GradientShaderBaseContext(const SkGradientShaderBase& shader, const ContextRec&);
145
146         virtual uint32_t getFlags() const SK_OVERRIDE { return fFlags; }
147
148     protected:
149         SkMatrix    fDstToIndex;
150         SkMatrix::MapXYProc fDstToIndexProc;
151         uint8_t     fDstToIndexClass;
152         uint8_t     fFlags;
153
154         SkAutoTUnref<GradientShaderCache> fCache;
155
156     private:
157         typedef SkShader::Context INHERITED;
158     };
159
160     virtual bool isOpaque() const SK_OVERRIDE;
161
162     void getGradientTableBitmap(SkBitmap*) const;
163
164     enum {
165         /// Seems like enough for visual accuracy. TODO: if pos[] deserves
166         /// it, use a larger cache.
167         kCache16Bits    = 8,
168         kCache16Count = (1 << kCache16Bits),
169         kCache16Shift   = 16 - kCache16Bits,
170         kSqrt16Shift    = 8 - kCache16Bits,
171
172         /// Seems like enough for visual accuracy. TODO: if pos[] deserves
173         /// it, use a larger cache.
174         kCache32Bits    = 8,
175         kCache32Count   = (1 << kCache32Bits),
176         kCache32Shift   = 16 - kCache32Bits,
177         kSqrt32Shift    = 8 - kCache32Bits,
178
179         /// This value is used to *read* the dither cache; it may be 0
180         /// if dithering is disabled.
181         kDitherStride32 = kCache32Count,
182         kDitherStride16 = kCache16Count,
183     };
184
185     enum GpuColorType {
186         kTwo_GpuColorType,
187         kThree_GpuColorType, // Symmetric three color
188         kTexture_GpuColorType
189     };
190
191     // Determines and returns the gradient is a two color gradient, symmetric three color gradient
192     // or other (texture gradient). If it is two or symmetric three color, the colors array will
193     // also be filled with the gradient colors
194     GpuColorType getGpuColorType(SkColor colors[3]) const;
195
196     uint32_t getGradFlags() const { return fGradFlags; }
197
198 protected:
199     SkGradientShaderBase(SkReadBuffer& );
200     virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
201     SK_TO_STRING_OVERRIDE()
202
203     SkMatrix    fPtsToUnit;     // set by subclass
204     TileMode    fTileMode;
205     TileProc    fTileProc;
206     int         fColorCount;
207     uint8_t     fGradFlags;
208
209     struct Rec {
210         SkFixed     fPos;   // 0...1
211         uint32_t    fScale; // (1 << 24) / range
212     };
213     Rec*        fRecs;
214
215     void commonAsAGradient(GradientInfo*, bool flipGrad = false) const;
216
217     /*
218      * Takes in pointers to gradient color and Rec info as colorSrc and recSrc respectively.
219      * Count is the number of colors in the gradient
220      * It will then flip all the color and rec information and return in their respective Dst
221      * pointers. It is assumed that space has already been allocated for the Dst pointers.
222      * The rec src and dst are only assumed to be valid if count > 2
223      */
224     static void FlipGradientColors(SkColor* colorDst, Rec* recDst,
225                                    SkColor* colorSrc, Rec* recSrc,
226                                    int count);
227
228     // V23_COMPATIBILITY_CODE
229     // Used for 2-pt conical gradients since we sort start/end cirlces by radius
230     // Assumes space has already been allocated for fOrigColors
231     void flipGradientColors();
232
233 private:
234     enum {
235         kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
236
237         kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(Rec))
238     };
239     SkColor     fStorage[(kStorageSize + 3) >> 2];
240     SkColor*    fOrigColors; // original colors, before modulation by paint in context.
241     bool        fColorsAreOpaque;
242
243     GradientShaderCache* refCache(U8CPU alpha) const;
244     mutable SkMutex                           fCacheMutex;
245     mutable SkAutoTUnref<GradientShaderCache> fCache;
246
247     void initCommon();
248
249     typedef SkShader INHERITED;
250 };
251
252 static inline int init_dither_toggle(int x, int y) {
253     x &= 1;
254     y = (y & 1) << 1;
255     return (x | y) * SkGradientShaderBase::kDitherStride32;
256 }
257
258 static inline int next_dither_toggle(int toggle) {
259     return toggle ^ SkGradientShaderBase::kDitherStride32;
260 }
261
262 static inline int init_dither_toggle16(int x, int y) {
263     return ((x ^ y) & 1) * SkGradientShaderBase::kDitherStride16;
264 }
265
266 static inline int next_dither_toggle16(int toggle) {
267     return toggle ^ SkGradientShaderBase::kDitherStride16;
268 }
269
270 ///////////////////////////////////////////////////////////////////////////////
271
272 #if SK_SUPPORT_GPU
273
274 #include "GrCoordTransform.h"
275 #include "gl/GrGLEffect.h"
276
277 class GrEffectStage;
278 class GrBackendEffectFactory;
279
280 /*
281  * The interpretation of the texture matrix depends on the sample mode. The
282  * texture matrix is applied both when the texture coordinates are explicit
283  * and  when vertex positions are used as texture  coordinates. In the latter
284  * case the texture matrix is applied to the pre-view-matrix position
285  * values.
286  *
287  * Normal SampleMode
288  *  The post-matrix texture coordinates are in normalize space with (0,0) at
289  *  the top-left and (1,1) at the bottom right.
290  * RadialGradient
291  *  The matrix specifies the radial gradient parameters.
292  *  (0,0) in the post-matrix space is center of the radial gradient.
293  * Radial2Gradient
294  *   Matrix transforms to space where first circle is centered at the
295  *   origin. The second circle will be centered (x, 0) where x may be
296  *   0 and is provided by setRadial2Params. The post-matrix space is
297  *   normalized such that 1 is the second radius - first radius.
298  * SweepGradient
299  *  The angle from the origin of texture coordinates in post-matrix space
300  *  determines the gradient value.
301  */
302
303  class GrTextureStripAtlas;
304
305 // Base class for Gr gradient effects
306 class GrGradientEffect : public GrEffect {
307 public:
308
309     GrGradientEffect(GrContext* ctx,
310                      const SkGradientShaderBase& shader,
311                      const SkMatrix& matrix,
312                      SkShader::TileMode tileMode);
313
314     virtual ~GrGradientEffect();
315
316     bool useAtlas() const { return SkToBool(-1 != fRow); }
317     SkScalar getYCoord() const { return fYCoord; };
318
319     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
320
321     SkGradientShaderBase::GpuColorType getColorType() const { return fColorType; }
322
323     enum PremulType {
324         kBeforeInterp_PremulType,
325         kAfterInterp_PremulType,
326     };
327
328     PremulType getPremulType() const { return fPremulType; }
329
330     const SkColor* getColors(int pos) const {
331         SkASSERT(fColorType != SkGradientShaderBase::kTexture_GpuColorType);
332         SkASSERT((pos-1) <= fColorType);
333         return &fColors[pos];
334     }
335
336 protected:
337
338     /** Populates a pair of arrays with colors and stop info to construct a random gradient.
339         The function decides whether stop values should be used or not. The return value indicates
340         the number of colors, which will be capped by kMaxRandomGradientColors. colors should be
341         sized to be at least kMaxRandomGradientColors. stops is a pointer to an array of at least
342         size kMaxRandomGradientColors. It may be updated to NULL, indicating that NULL should be
343         passed to the gradient factory rather than the array.
344     */
345     static const int kMaxRandomGradientColors = 4;
346     static int RandomGradientParams(SkRandom* r,
347                                     SkColor colors[kMaxRandomGradientColors],
348                                     SkScalar** stops,
349                                     SkShader::TileMode* tm);
350
351     virtual bool onIsEqual(const GrEffect& effect) const SK_OVERRIDE;
352
353     const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
354
355 private:
356     static const GrCoordSet kCoordSet = kLocal_GrCoordSet;
357
358     GrCoordTransform fCoordTransform;
359     GrTextureAccess fTextureAccess;
360     SkScalar fYCoord;
361     GrTextureStripAtlas* fAtlas;
362     int fRow;
363     bool fIsOpaque;
364     SkGradientShaderBase::GpuColorType fColorType;
365     SkColor fColors[3]; // More than 3 colors we use texture
366     PremulType fPremulType; // This only changes behavior for two and three color special cases.
367                             // It is already baked into to the table for texture gradients.
368     typedef GrEffect INHERITED;
369
370 };
371
372 ///////////////////////////////////////////////////////////////////////////////
373
374 // Base class for GL gradient effects
375 class GrGLGradientEffect : public GrGLEffect {
376 public:
377     GrGLGradientEffect(const GrBackendEffectFactory& factory);
378     virtual ~GrGLGradientEffect();
379
380     virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
381
382 protected:
383     /**
384      * Subclasses must call this. It will return a key for the part of the shader code controlled
385      * by the base class. The subclasses must stick it in their key and then pass it to the below
386      * emit* functions from their emitCode function.
387      */
388     static uint32_t GenBaseGradientKey(const GrDrawEffect&);
389
390     // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
391     // should call this method from their emitCode().
392     void emitUniforms(GrGLShaderBuilder* builder, uint32_t baseKey);
393
394
395     // emit code that gets a fragment's color from an expression for t; Has branches for 3 separate
396     // control flows inside -- 2 color gradients, 3 color symmetric gradients (both using
397     // native GLSL mix), and 4+ color gradients that use the traditional texture lookup.
398     void emitColor(GrGLShaderBuilder* builder,
399                    const char* gradientTValue,
400                    uint32_t baseKey,
401                    const char* outputColor,
402                    const char* inputColor,
403                    const TextureSamplerArray& samplers);
404
405 private:
406     enum {
407         kPremulTypeKeyBitCnt = 1,
408         kPremulTypeMask = 1,
409         kPremulBeforeInterpKey = kPremulTypeMask,
410
411         kTwoColorKey = 2 << kPremulTypeKeyBitCnt,
412         kThreeColorKey = 3 << kPremulTypeKeyBitCnt,
413         kColorKeyMask = kTwoColorKey | kThreeColorKey,
414         kColorKeyBitCnt = 2,
415
416         // Subclasses must shift any key bits they produce up by this amount
417         // and combine with the result of GenBaseGradientKey.
418         kBaseKeyBitCnt = (kPremulTypeKeyBitCnt + kColorKeyBitCnt)
419     };
420     GR_STATIC_ASSERT(kBaseKeyBitCnt <= 32);
421
422     static SkGradientShaderBase::GpuColorType ColorTypeFromKey(uint32_t baseKey){
423         if (kTwoColorKey == (baseKey & kColorKeyMask)) {
424             return SkGradientShaderBase::kTwo_GpuColorType;
425         } else if (kThreeColorKey == (baseKey & kColorKeyMask)) {
426             return SkGradientShaderBase::kThree_GpuColorType;
427         } else {return SkGradientShaderBase::kTexture_GpuColorType;}
428     }
429
430     static GrGradientEffect::PremulType PremulTypeFromKey(uint32_t baseKey){
431         if (kPremulBeforeInterpKey == (baseKey & kPremulTypeMask)) {
432             return GrGradientEffect::kBeforeInterp_PremulType;
433         } else {
434             return GrGradientEffect::kAfterInterp_PremulType;
435         }
436     }
437
438     SkScalar fCachedYCoord;
439     GrGLProgramDataManager::UniformHandle fFSYUni;
440     GrGLProgramDataManager::UniformHandle fColorStartUni;
441     GrGLProgramDataManager::UniformHandle fColorMidUni;
442     GrGLProgramDataManager::UniformHandle fColorEndUni;
443
444     typedef GrGLEffect INHERITED;
445 };
446
447 #endif
448
449 #endif