OSDN Git Service

Remove stale temporary ASEC containers
[android-x86/frameworks-base.git] / tools / layoutlib / bridge / src / android / graphics / Gradient_Delegate.java
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package android.graphics;
18
19 import android.graphics.Shader.TileMode;
20
21 /**
22  * Base class for true Gradient shader delegate.
23  */
24 public abstract class Gradient_Delegate extends Shader_Delegate {
25
26     protected final int[] mColors;
27     protected final float[] mPositions;
28
29     @Override
30     public boolean isSupported() {
31         // all gradient shaders are supported.
32         return true;
33     }
34
35     @Override
36     public String getSupportMessage() {
37         // all gradient shaders are supported, no need for a gradient support
38         return null;
39     }
40
41     /**
42      * Creates the base shader and do some basic test on the parameters.
43      *
44      * @param colors The colors to be distributed along the gradient line
45      * @param positions May be null. The relative positions [0..1] of each
46      *            corresponding color in the colors array. If this is null, the
47      *            the colors are distributed evenly along the gradient line.
48      */
49     protected Gradient_Delegate(int colors[], float positions[]) {
50         if (colors.length < 2) {
51             throw new IllegalArgumentException("needs >= 2 number of colors");
52         }
53         if (positions != null && colors.length != positions.length) {
54             throw new IllegalArgumentException("color and position arrays must be of equal length");
55         }
56
57         if (positions == null) {
58             float spacing = 1.f / (colors.length - 1);
59             positions = new float[colors.length];
60             positions[0] = 0.f;
61             positions[colors.length-1] = 1.f;
62             for (int i = 1; i < colors.length - 1 ; i++) {
63                 positions[i] = spacing * i;
64             }
65         }
66
67         mColors = colors;
68         mPositions = positions;
69     }
70
71     /**
72      * Base class for (Java) Gradient Paints. This handles computing the gradient colors based
73      * on the color and position lists, as well as the {@link TileMode}
74      *
75      */
76     protected abstract static class GradientPaint implements java.awt.Paint {
77         private final static int GRADIENT_SIZE = 100;
78
79         private final int[] mColors;
80         private final float[] mPositions;
81         private final TileMode mTileMode;
82         private int[] mGradient;
83
84         protected GradientPaint(int[] colors, float[] positions, TileMode tileMode) {
85             mColors = colors;
86             mPositions = positions;
87             mTileMode = tileMode;
88         }
89
90         public int getTransparency() {
91             return java.awt.Paint.TRANSLUCENT;
92         }
93
94         /**
95          * Pre-computes the colors for the gradient. This must be called once before any call
96          * to {@link #getGradientColor(float)}
97          */
98         protected void precomputeGradientColors() {
99             if (mGradient == null) {
100                 // actually create an array with an extra size, so that we can really go
101                 // from 0 to SIZE (100%), or currentPos in the loop below will never equal 1.0
102                 mGradient = new int[GRADIENT_SIZE+1];
103
104                 int prevPos = 0;
105                 int nextPos = 1;
106                 for (int i  = 0 ; i <= GRADIENT_SIZE ; i++) {
107                     // compute current position
108                     float currentPos = (float)i/GRADIENT_SIZE;
109                     while (currentPos > mPositions[nextPos]) {
110                         prevPos = nextPos++;
111                     }
112
113                     float percent = (currentPos - mPositions[prevPos]) /
114                             (mPositions[nextPos] - mPositions[prevPos]);
115
116                     mGradient[i] = computeColor(mColors[prevPos], mColors[nextPos], percent);
117                 }
118             }
119         }
120
121         /**
122          * Returns the color based on the position in the gradient.
123          * <var>pos</var> can be anything, even &lt; 0 or &gt; > 1, as the gradient
124          * will use {@link TileMode} value to convert it into a [0,1] value.
125          */
126         protected int getGradientColor(float pos) {
127             if (pos < 0.f) {
128                 if (mTileMode != null) {
129                     switch (mTileMode) {
130                         case CLAMP:
131                             pos = 0.f;
132                             break;
133                         case REPEAT:
134                             // remove the integer part to stay in the [0,1] range.
135                             // we also need to invert the value from [-1,0] to [0, 1]
136                             pos = pos - (float)Math.floor(pos);
137                             break;
138                         case MIRROR:
139                             // this is the same as the positive side, just make the value positive
140                             // first.
141                             pos = Math.abs(pos);
142
143                             // get the integer and the decimal part
144                             int intPart = (int)Math.floor(pos);
145                             pos = pos - intPart;
146                             // 0 -> 1 : normal order
147                             // 1 -> 2: mirrored
148                             // etc..
149                             // this means if the intpart is odd we invert
150                             if ((intPart % 2) == 1) {
151                                 pos = 1.f - pos;
152                             }
153                             break;
154                     }
155                 } else {
156                     pos = 0.0f;
157                 }
158             } else if (pos > 1f) {
159                 if (mTileMode != null) {
160                     switch (mTileMode) {
161                         case CLAMP:
162                             pos = 1.f;
163                             break;
164                         case REPEAT:
165                             // remove the integer part to stay in the [0,1] range
166                             pos = pos - (float)Math.floor(pos);
167                             break;
168                         case MIRROR:
169                             // get the integer and the decimal part
170                             int intPart = (int)Math.floor(pos);
171                             pos = pos - intPart;
172                             // 0 -> 1 : normal order
173                             // 1 -> 2: mirrored
174                             // etc..
175                             // this means if the intpart is odd we invert
176                             if ((intPart % 2) == 1) {
177                                 pos = 1.f - pos;
178                             }
179                             break;
180                     }
181                 } else {
182                     pos = 1.0f;
183                 }
184             }
185
186             int index = (int)((pos * GRADIENT_SIZE) + .5);
187
188             return mGradient[index];
189         }
190
191         /**
192          * Returns the color between c1, and c2, based on the percent of the distance
193          * between c1 and c2.
194          */
195         private int computeColor(int c1, int c2, float percent) {
196             int a = computeChannel((c1 >> 24) & 0xFF, (c2 >> 24) & 0xFF, percent);
197             int r = computeChannel((c1 >> 16) & 0xFF, (c2 >> 16) & 0xFF, percent);
198             int g = computeChannel((c1 >>  8) & 0xFF, (c2 >>  8) & 0xFF, percent);
199             int b = computeChannel((c1      ) & 0xFF, (c2      ) & 0xFF, percent);
200             return a << 24 | r << 16 | g << 8 | b;
201         }
202
203         /**
204          * Returns the channel value between 2 values based on the percent of the distance between
205          * the 2 values..
206          */
207         private int computeChannel(int c1, int c2, float percent) {
208             return c1 + (int)((percent * (c2-c1)) + .5);
209         }
210     }
211 }