1 /* 2 * Copyright (C) 2007 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.annotation.ColorInt; 20 import android.annotation.ColorLong; 21 import android.annotation.FloatRange; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.compat.annotation.UnsupportedAppUsage; 25 import android.os.Build; 26 27 public class RadialGradient extends Shader { 28 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 29 private float mX; 30 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 31 private float mY; 32 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 33 private float mRadius; 34 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 35 private float[] mPositions; 36 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 37 private TileMode mTileMode; 38 39 private final float mFocalX; 40 private final float mFocalY; 41 private final float mFocalRadius; 42 43 // @ColorInts are replaced by @ColorLongs, but these remain due to @UnsupportedAppUsage. 44 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 45 @ColorInt 46 private int[] mColors; 47 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 48 @ColorInt 49 private int mCenterColor; 50 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 51 @ColorInt 52 private int mEdgeColor; 53 54 @ColorLong 55 private final long[] mColorLongs; 56 57 /** 58 * Create a shader that draws a radial gradient given the center and radius. 59 * 60 * @param centerX The x-coordinate of the center of the radius 61 * @param centerY The y-coordinate of the center of the radius 62 * @param radius Must be positive. The radius of the circle for this gradient. 63 * @param colors The sRGB colors to be distributed between the center and edge of the circle 64 * @param stops May be <code>null</code>. Valid values are between <code>0.0f</code> and 65 * <code>1.0f</code>. The relative position of each corresponding color in 66 * the colors array. If <code>null</code>, colors are distributed evenly 67 * between the center and edge of the circle. 68 * @param tileMode The Shader tiling mode 69 */ RadialGradient(float centerX, float centerY, float radius, @NonNull @ColorInt int[] colors, @Nullable float[] stops, @NonNull TileMode tileMode)70 public RadialGradient(float centerX, float centerY, float radius, 71 @NonNull @ColorInt int[] colors, @Nullable float[] stops, 72 @NonNull TileMode tileMode) { 73 this(centerX, centerY, 0f, centerX, centerY, radius, convertColors(colors), 74 stops, tileMode, ColorSpace.get(ColorSpace.Named.SRGB)); 75 } 76 77 /** 78 * Create a shader that draws a radial gradient given the center and radius. 79 * 80 * @param centerX The x-coordinate of the center of the radius 81 * @param centerY The y-coordinate of the center of the radius 82 * @param radius Must be positive. The radius of the circle for this gradient. 83 * @param colors The colors to be distributed between the center and edge of the circle 84 * @param stops May be <code>null</code>. Valid values are between <code>0.0f</code> and 85 * <code>1.0f</code>. The relative position of each corresponding color in 86 * the colors array. If <code>null</code>, colors are distributed evenly 87 * between the center and edge of the circle. 88 * @param tileMode The Shader tiling mode 89 * 90 * @throws IllegalArgumentException if there are less than two colors, the colors do 91 * not share the same {@link ColorSpace} or do not use a valid one, or {@code stops} 92 * is not {@code null} and has a different length from {@code colors}. 93 */ RadialGradient(float centerX, float centerY, float radius, @NonNull @ColorLong long[] colors, @Nullable float[] stops, @NonNull TileMode tileMode)94 public RadialGradient(float centerX, float centerY, float radius, 95 @NonNull @ColorLong long[] colors, @Nullable float[] stops, 96 @NonNull TileMode tileMode) { 97 this(centerX, centerY, 0f, centerX, centerY, radius, colors.clone(), stops, 98 tileMode, detectColorSpace(colors)); 99 } 100 101 /** 102 * Create a shader that draws a radial gradient given the start and end points as well as 103 * starting and ending radii. The starting point is often referred to as the focal center and 104 * represents the starting circle of the radial gradient. 105 * 106 * @param startX The x-coordinate of the center of the starting circle of the radial gradient, 107 * often referred to as the focal point. 108 * @param startY The y-coordinate of the center of the starting circle of the radial gradient, 109 * often referred to as the focal point. 110 * @param startRadius The radius of the starting circle of the radial gradient, often referred 111 * to as the focal radius. Must be greater than or equal to zero. 112 * @param endX The x-coordinate of the center of the radius for the end circle of the 113 * radial gradient 114 * @param endY The y-coordinate of the center of the radius for the end circle of the 115 * radial gradient 116 * @param endRadius The radius of the ending circle for this gradient. This must be strictly 117 * greater than zero. A radius value equal to zero is not allowed. 118 * @param colors The colors to be distributed between the center and edge of the circle 119 * @param stops May be <code>null</code>. Valid values are between <code>0.0f</code> and 120 * <code>1.0f</code>. The relative position of each corresponding color in 121 * the colors array. If <code>null</code>, colors are distributed evenly 122 * between the center and edge of the circle. 123 * @param tileMode The Shader tiling mode 124 * 125 * @throws IllegalArgumentException In one of the following circumstances: 126 * <ul> 127 * <li>There are less than two colors</li> 128 * <li>The colors do not share the same {@link ColorSpace}</li> 129 * <li>The colors do not use a valid {@link ColorSpace}</li> 130 * <li> 131 * The {@code stops} parameter is not {@code null} and has a different length from 132 * {@code colors}. 133 * </li> 134 * <li>The {@code startRadius} is negative</li> 135 * <li>The {@code endRadius} is less than or equal to zero</li> 136 * </ul> 137 */ RadialGradient(float startX, float startY, @FloatRange(from = 0.0f) float startRadius, float endX, float endY, @FloatRange(from = 0.0f, fromInclusive = false) float endRadius, @NonNull @ColorLong long[] colors, @Nullable float[] stops, @NonNull TileMode tileMode)138 public RadialGradient(float startX, float startY, @FloatRange(from = 0.0f) float startRadius, 139 float endX, float endY, @FloatRange(from = 0.0f, fromInclusive = false) float endRadius, 140 @NonNull @ColorLong long[] colors, @Nullable float[] stops, 141 @NonNull TileMode tileMode) { 142 this(startX, startY, startRadius, endX, endY, endRadius, colors.clone(), stops, tileMode, 143 detectColorSpace(colors)); 144 } 145 146 /** 147 * Base constructor. Assumes @param colors is a copy that this object can hold onto, 148 * and all colors share @param colorSpace. 149 */ RadialGradient(float startX, float startY, float startRadius, float endX, float endY, float endRadius, @NonNull @ColorLong long[] colors, @Nullable float[] stops, @NonNull TileMode tileMode, ColorSpace colorSpace )150 private RadialGradient(float startX, float startY, float startRadius, float endX, float endY, 151 float endRadius, @NonNull @ColorLong long[] colors, @Nullable float[] stops, 152 @NonNull TileMode tileMode, ColorSpace colorSpace 153 ) { 154 super(colorSpace); 155 // A focal or starting radius of zero with a focal point that matches the center is 156 // identical to a regular radial gradient 157 if (startRadius < 0) { 158 throw new IllegalArgumentException("starting/focal radius must be >= 0"); 159 } 160 161 if (endRadius <= 0) { 162 throw new IllegalArgumentException("ending radius must be > 0"); 163 } 164 165 if (stops != null && colors.length != stops.length) { 166 throw new IllegalArgumentException("color and position arrays must be of equal length"); 167 } 168 mX = endX; 169 mY = endY; 170 mRadius = endRadius; 171 mFocalX = startX; 172 mFocalY = startY; 173 mFocalRadius = startRadius; 174 mColorLongs = colors; 175 mPositions = stops != null ? stops.clone() : null; 176 mTileMode = tileMode; 177 } 178 179 /** 180 * Create a shader that draws a radial gradient given the center and radius. 181 * 182 * @param centerX The x-coordinate of the center of the radius 183 * @param centerY The y-coordinate of the center of the radius 184 * @param radius Must be positive. The radius of the circle for this gradient 185 * @param centerColor The sRGB color at the center of the circle. 186 * @param edgeColor The sRGB color at the edge of the circle. 187 * @param tileMode The Shader tiling mode 188 */ RadialGradient(float centerX, float centerY, float radius, @ColorInt int centerColor, @ColorInt int edgeColor, @NonNull TileMode tileMode)189 public RadialGradient(float centerX, float centerY, float radius, 190 @ColorInt int centerColor, @ColorInt int edgeColor, @NonNull TileMode tileMode) { 191 this(centerX, centerY, radius, Color.pack(centerColor), Color.pack(edgeColor), tileMode); 192 } 193 194 /** 195 * Create a shader that draws a radial gradient given the center and radius. 196 * 197 * @param centerX The x-coordinate of the center of the radius 198 * @param centerY The y-coordinate of the center of the radius 199 * @param radius Must be positive. The radius of the circle for this gradient 200 * @param centerColor The color at the center of the circle. 201 * @param edgeColor The color at the edge of the circle. 202 * @param tileMode The Shader tiling mode 203 * 204 * @throws IllegalArgumentException if the colors do 205 * not share the same {@link ColorSpace} or do not use a valid one. 206 */ RadialGradient(float centerX, float centerY, float radius, @ColorLong long centerColor, @ColorLong long edgeColor, @NonNull TileMode tileMode)207 public RadialGradient(float centerX, float centerY, float radius, 208 @ColorLong long centerColor, @ColorLong long edgeColor, @NonNull TileMode tileMode) { 209 this(centerX, centerY, radius, new long[] {centerColor, edgeColor}, null, tileMode); 210 } 211 212 /** @hide */ 213 @Override createNativeInstance(long nativeMatrix, boolean filterFromPaint)214 protected long createNativeInstance(long nativeMatrix, boolean filterFromPaint) { 215 return nativeCreate(nativeMatrix, mFocalX, mFocalY, mFocalRadius, mX, mY, mRadius, 216 mColorLongs, mPositions, mTileMode.nativeInt, colorSpace().getNativeInstance()); 217 } 218 nativeCreate(long matrix, float startX, float startY, float startRadius, float endX, float endY, float endRadius, @ColorLong long[] colors, float[] positions, int tileMode, long colorSpaceHandle)219 private static native long nativeCreate(long matrix, float startX, float startY, 220 float startRadius, float endX, float endY, float endRadius, @ColorLong long[] colors, 221 float[] positions, int tileMode, long colorSpaceHandle); 222 } 223 224