2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package android.graphics;
19 import android.graphics.Shader.TileMode;
22 * Base class for true Gradient shader delegate.
24 public abstract class Gradient_Delegate extends Shader_Delegate {
26 protected final int[] mColors;
27 protected final float[] mPositions;
30 public boolean isSupported() {
31 // all gradient shaders are supported.
36 public String getSupportMessage() {
37 // all gradient shaders are supported, no need for a gradient support
42 * Creates the base shader and do some basic test on the parameters.
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.
49 protected Gradient_Delegate(int colors[], float positions[]) {
50 if (colors.length < 2) {
51 throw new IllegalArgumentException("needs >= 2 number of colors");
53 if (positions != null && colors.length != positions.length) {
54 throw new IllegalArgumentException("color and position arrays must be of equal length");
57 if (positions == null) {
58 float spacing = 1.f / (colors.length - 1);
59 positions = new float[colors.length];
61 positions[colors.length-1] = 1.f;
62 for (int i = 1; i < colors.length - 1 ; i++) {
63 positions[i] = spacing * i;
68 mPositions = positions;
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}
76 protected abstract static class GradientPaint implements java.awt.Paint {
77 private final static int GRADIENT_SIZE = 100;
79 private final int[] mColors;
80 private final float[] mPositions;
81 private final TileMode mTileMode;
82 private int[] mGradient;
84 protected GradientPaint(int[] colors, float[] positions, TileMode tileMode) {
86 mPositions = positions;
90 public int getTransparency() {
91 return java.awt.Paint.TRANSLUCENT;
95 * Pre-computes the colors for the gradient. This must be called once before any call
96 * to {@link #getGradientColor(float)}
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];
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]) {
113 float percent = (currentPos - mPositions[prevPos]) /
114 (mPositions[nextPos] - mPositions[prevPos]);
116 mGradient[i] = computeColor(mColors[prevPos], mColors[nextPos], percent);
122 * Returns the color based on the position in the gradient.
123 * <var>pos</var> can be anything, even < 0 or > > 1, as the gradient
124 * will use {@link TileMode} value to convert it into a [0,1] value.
126 protected int getGradientColor(float pos) {
128 if (mTileMode != null) {
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);
139 // this is the same as the positive side, just make the value positive
143 // get the integer and the decimal part
144 int intPart = (int)Math.floor(pos);
146 // 0 -> 1 : normal order
149 // this means if the intpart is odd we invert
150 if ((intPart % 2) == 1) {
158 } else if (pos > 1f) {
159 if (mTileMode != null) {
165 // remove the integer part to stay in the [0,1] range
166 pos = pos - (float)Math.floor(pos);
169 // get the integer and the decimal part
170 int intPart = (int)Math.floor(pos);
172 // 0 -> 1 : normal order
175 // this means if the intpart is odd we invert
176 if ((intPart % 2) == 1) {
186 int index = (int)((pos * GRADIENT_SIZE) + .5);
188 return mGradient[index];
192 * Returns the color between c1, and c2, based on the percent of the distance
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;
204 * Returns the channel value between 2 values based on the percent of the distance between
207 private int computeChannel(int c1, int c2, float percent) {
208 return c1 + (int)((percent * (c2-c1)) + .5);