Added support for focal points in RadialGradient
Updated RadialGradient API to accept optional starting (focal) point parameters. Internally create a two point conical shader if focal points are provided. Fixes: 167695230 Test: Added CTS test to verify focal points on RadialGradient Change-Id: I18baba3d0a7285c3f787af8f441c797414bae2cf
This commit is contained in:
@@ -15443,6 +15443,7 @@ package android.graphics {
|
||||
public class RadialGradient extends android.graphics.Shader {
|
||||
ctor public RadialGradient(float, float, float, @ColorInt @NonNull int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
|
||||
ctor public RadialGradient(float, float, float, @ColorLong @NonNull long[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
|
||||
ctor public RadialGradient(float, float, @FloatRange(from=0.0f) float, float, float, @FloatRange(from=0.0f, fromInclusive=false) float, @ColorLong @NonNull long[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
|
||||
ctor public RadialGradient(float, float, float, @ColorInt int, @ColorInt int, @NonNull android.graphics.Shader.TileMode);
|
||||
ctor public RadialGradient(float, float, float, @ColorLong long, @ColorLong long, @NonNull android.graphics.Shader.TileMode);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.graphics;
|
||||
|
||||
import android.annotation.ColorInt;
|
||||
import android.annotation.ColorLong;
|
||||
import android.annotation.FloatRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
@@ -34,6 +35,10 @@ public class RadialGradient extends Shader {
|
||||
@UnsupportedAppUsage
|
||||
private TileMode mTileMode;
|
||||
|
||||
private final float mFocalX;
|
||||
private final float mFocalY;
|
||||
private final float mFocalRadius;
|
||||
|
||||
// @ColorInts are replaced by @ColorLongs, but these remain due to @UnsupportedAppUsage.
|
||||
@UnsupportedAppUsage
|
||||
@ColorInt
|
||||
@@ -64,8 +69,8 @@ public class RadialGradient extends Shader {
|
||||
public RadialGradient(float centerX, float centerY, float radius,
|
||||
@NonNull @ColorInt int[] colors, @Nullable float[] stops,
|
||||
@NonNull TileMode tileMode) {
|
||||
this(centerX, centerY, radius, convertColors(colors), stops, tileMode,
|
||||
ColorSpace.get(ColorSpace.Named.SRGB));
|
||||
this(centerX, centerY, 0f, centerX, centerY, radius, convertColors(colors),
|
||||
stops, tileMode, ColorSpace.get(ColorSpace.Named.SRGB));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,27 +93,79 @@ public class RadialGradient extends Shader {
|
||||
public RadialGradient(float centerX, float centerY, float radius,
|
||||
@NonNull @ColorLong long[] colors, @Nullable float[] stops,
|
||||
@NonNull TileMode tileMode) {
|
||||
this(centerX, centerY, radius, colors.clone(), stops, tileMode, detectColorSpace(colors));
|
||||
this(centerX, centerY, 0f, centerX, centerY, radius, colors.clone(), stops,
|
||||
tileMode, detectColorSpace(colors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a shader that draws a radial gradient given the start and end points as well as
|
||||
* starting and ending radii. The starting point is often referred to as the focal center and
|
||||
* represents the starting circle of the radial gradient.
|
||||
*
|
||||
* @param startX The x-coordinate of the center of the starting circle of the radial gradient,
|
||||
* often referred to as the focal point.
|
||||
* @param startY The y-coordinate of the center of the starting circle of the radial gradient,
|
||||
* often referred to as the focal point.
|
||||
* @param startRadius The radius of the starting circle of the radial gradient, often referred
|
||||
* to as the focal radius. Must be greater than or equal to zero.
|
||||
* @param endX The x-coordinate of the center of the radius for the end circle of the
|
||||
* radial gradient
|
||||
* @param endY The y-coordinate of the center of the radius for the end circle of the
|
||||
* radial gradient
|
||||
* @param endRadius The radius of the ending circle for this gradient. This must be strictly
|
||||
* greater than zero. A radius value equal to zero is not allowed.
|
||||
* @param colors The colors to be distributed between the center and edge of the circle
|
||||
* @param stops May be <code>null</code>. Valid values are between <code>0.0f</code> and
|
||||
* <code>1.0f</code>. The relative position of each corresponding color in
|
||||
* the colors array. If <code>null</code>, colors are distributed evenly
|
||||
* between the center and edge of the circle.
|
||||
* @param tileMode The Shader tiling mode
|
||||
*
|
||||
* @throws IllegalArgumentException If one of the following circumstances:
|
||||
* - There are less than two colors
|
||||
* - The colors do not share the same {@link ColorSpace}
|
||||
* - The colors do not use a valid {@link ColorSpace}
|
||||
* - The {@code stops} parameter is not {@code null} and has a different length
|
||||
* from {@code colors}.
|
||||
* - The {@param startRadius} is negative
|
||||
* - The {@param endRadius} is less than or equal to zero
|
||||
*/
|
||||
public 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) {
|
||||
this(startX, startY, startRadius, endX, endY, endRadius, colors.clone(), stops, tileMode,
|
||||
detectColorSpace(colors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Base constructor. Assumes @param colors is a copy that this object can hold onto,
|
||||
* and all colors share @param colorSpace.
|
||||
*/
|
||||
private RadialGradient(float centerX, float centerY, float radius,
|
||||
@NonNull @ColorLong long[] colors, @Nullable float[] stops,
|
||||
@NonNull TileMode tileMode, ColorSpace colorSpace) {
|
||||
private 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
|
||||
) {
|
||||
super(colorSpace);
|
||||
|
||||
if (radius <= 0) {
|
||||
throw new IllegalArgumentException("radius must be > 0");
|
||||
// A focal or starting radius of zero with a focal point that matches the center is
|
||||
// identical to a regular radial gradient
|
||||
if (startRadius < 0) {
|
||||
throw new IllegalArgumentException("starting/focal radius must be >= 0");
|
||||
}
|
||||
|
||||
if (endRadius <= 0) {
|
||||
throw new IllegalArgumentException("ending radius must be > 0");
|
||||
}
|
||||
|
||||
if (stops != null && colors.length != stops.length) {
|
||||
throw new IllegalArgumentException("color and position arrays must be of equal length");
|
||||
}
|
||||
mX = centerX;
|
||||
mY = centerY;
|
||||
mRadius = radius;
|
||||
mX = endX;
|
||||
mY = endY;
|
||||
mRadius = endRadius;
|
||||
mFocalX = startX;
|
||||
mFocalY = startY;
|
||||
mFocalRadius = startRadius;
|
||||
mColorLongs = colors;
|
||||
mPositions = stops != null ? stops.clone() : null;
|
||||
mTileMode = tileMode;
|
||||
@@ -150,12 +207,12 @@ public class RadialGradient extends Shader {
|
||||
/** @hide */
|
||||
@Override
|
||||
protected long createNativeInstance(long nativeMatrix) {
|
||||
return nativeCreate(nativeMatrix, mX, mY, mRadius,
|
||||
mColorLongs, mPositions, mTileMode.nativeInt,
|
||||
colorSpace().getNativeInstance());
|
||||
return nativeCreate(nativeMatrix, mFocalX, mFocalY, mFocalRadius, mX, mY, mRadius,
|
||||
mColorLongs, mPositions, mTileMode.nativeInt, colorSpace().getNativeInstance());
|
||||
}
|
||||
|
||||
private static native long nativeCreate(long matrix, float x, float y, float radius,
|
||||
@ColorLong long[] colors, float[] positions, int tileMode, long colorSpaceHandle);
|
||||
private static native long nativeCreate(long matrix, float startX, float startY,
|
||||
float startRadius, float endX, float endY, float endRadius, @ColorLong long[] colors,
|
||||
float[] positions, int tileMode, long colorSpaceHandle);
|
||||
}
|
||||
|
||||
|
||||
@@ -133,11 +133,25 @@ static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static jlong RadialGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
|
||||
jfloat radius, jlongArray colorArray, jfloatArray posArray, jint tileMode,
|
||||
static jlong RadialGradient_create(JNIEnv* env,
|
||||
jobject,
|
||||
jlong matrixPtr,
|
||||
jfloat startX,
|
||||
jfloat startY,
|
||||
jfloat startRadius,
|
||||
jfloat endX,
|
||||
jfloat endY,
|
||||
jfloat endRadius,
|
||||
jlongArray colorArray,
|
||||
jfloatArray posArray,
|
||||
jint tileMode,
|
||||
jlong colorSpaceHandle) {
|
||||
SkPoint center;
|
||||
center.set(x, y);
|
||||
|
||||
SkPoint start;
|
||||
start.set(startX, startY);
|
||||
|
||||
SkPoint end;
|
||||
end.set(endX, endY);
|
||||
|
||||
std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
|
||||
|
||||
@@ -148,11 +162,17 @@ static jlong RadialGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat
|
||||
#error Need to convert float array to SkScalar array before calling the following function.
|
||||
#endif
|
||||
|
||||
sk_sp<SkShader> shader = SkGradientShader::MakeRadial(center, radius, &colors[0],
|
||||
GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
|
||||
static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr);
|
||||
auto colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
|
||||
auto skTileMode = static_cast<SkTileMode>(tileMode);
|
||||
sk_sp<SkShader> shader = SkGradientShader::MakeTwoPointConical(start, startRadius, end,
|
||||
endRadius, &colors[0], std::move(colorSpace), pos, colors.size(), skTileMode,
|
||||
sGradientShaderFlags, nullptr);
|
||||
ThrowIAE_IfNull(env, shader);
|
||||
|
||||
// Explicitly create a new shader with the specified matrix to match existing behavior.
|
||||
// Passing in the matrix in the instantiation above can throw exceptions for non-invertible
|
||||
// matrices. However, makeWithLocalMatrix will still allow for the shader to be created
|
||||
// and skia handles null-shaders internally (i.e. is ignored)
|
||||
const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
|
||||
if (matrix) {
|
||||
shader = shader->makeWithLocalMatrix(*matrix);
|
||||
@@ -279,7 +299,7 @@ static const JNINativeMethod gLinearGradientMethods[] = {
|
||||
};
|
||||
|
||||
static const JNINativeMethod gRadialGradientMethods[] = {
|
||||
{ "nativeCreate", "(JFFF[J[FIJ)J", (void*)RadialGradient_create },
|
||||
{ "nativeCreate", "(JFFFFFF[J[FIJ)J", (void*)RadialGradient_create },
|
||||
};
|
||||
|
||||
static const JNINativeMethod gSweepGradientMethods[] = {
|
||||
|
||||
@@ -15425,6 +15425,7 @@ package android.graphics {
|
||||
public class RadialGradient extends android.graphics.Shader {
|
||||
ctor public RadialGradient(float, float, float, @ColorInt @NonNull int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
|
||||
ctor public RadialGradient(float, float, float, @ColorLong @NonNull long[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
|
||||
ctor public RadialGradient(float, float, @FloatRange(from=0.0f) float, float, float, @FloatRange(from=0.0f, fromInclusive=false) float, @ColorLong @NonNull long[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
|
||||
ctor public RadialGradient(float, float, float, @ColorInt int, @ColorInt int, @NonNull android.graphics.Shader.TileMode);
|
||||
ctor public RadialGradient(float, float, float, @ColorLong long, @ColorLong long, @NonNull android.graphics.Shader.TileMode);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user