Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b0aecc22 authored by Leon Scroggins III's avatar Leon Scroggins III
Browse files

Use ColorLongs in Linear-, Radial-, and Sweep-Gradient

Bug: 122844033
Test: Id1809aef84eca0ccc61bafc2476ad52ed78d5f22

Add APIs that mirror the existing creation APIs, but use @ColorLongs
instead of @ColorInts. Note that call-sites that used a null array (but
not a variable "int[]" pointing to a null array) are now ambiguous. It
is unlikely that there are any such call-sites, though, since they would
throw NullPointerException.

Consolidate constructors. Those that take two color endpoints now create
two-member long-arrays and call the more general constructor, saving
lots of code. The additional cost of small arrays is not as much as it
used to be, in the early days of Android, when this class was written.

In *Gradient#copy, there is no longer any need to clone the colors
array, since the mColorLongs was created by the Gradient. Similarly,
there never was any need to clone mPositions, which was always a clone
of the user-supplied array anyway.

Clean up Shader.cpp:
 - Throw and return if the pointer is null before dereferencing it.
 - Simplify and put together matrix-related code.

Change-Id: Ib71c5e85b2a398959bf687bce33980d3429bcbc3
parent bee5e204
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -14240,7 +14240,9 @@ package android.graphics {
  public class LinearGradient extends android.graphics.Shader {
  public class LinearGradient extends android.graphics.Shader {
    ctor public LinearGradient(float, float, float, float, @NonNull @ColorInt int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
    ctor public LinearGradient(float, float, float, float, @NonNull @ColorInt int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
    ctor public LinearGradient(float, float, float, float, @NonNull @ColorLong long[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
    ctor public LinearGradient(float, float, float, float, @ColorInt int, @ColorInt int, @NonNull android.graphics.Shader.TileMode);
    ctor public LinearGradient(float, float, float, float, @ColorInt int, @ColorInt int, @NonNull android.graphics.Shader.TileMode);
    ctor public LinearGradient(float, float, float, float, @ColorLong long, @ColorLong long, @NonNull android.graphics.Shader.TileMode);
  }
  }
  public class MaskFilter {
  public class MaskFilter {
@@ -14765,7 +14767,9 @@ package android.graphics {
  public class RadialGradient extends android.graphics.Shader {
  public class RadialGradient extends android.graphics.Shader {
    ctor public RadialGradient(float, float, float, @NonNull @ColorInt int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
    ctor public RadialGradient(float, float, float, @NonNull @ColorInt int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
    ctor public RadialGradient(float, float, float, @NonNull @ColorLong 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, @ColorInt int, @ColorInt int, @NonNull android.graphics.Shader.TileMode);
    ctor public RadialGradient(float, float, float, @ColorLong long, @ColorLong long, @NonNull android.graphics.Shader.TileMode);
  }
  }
  public final class RecordingCanvas extends android.graphics.Canvas {
  public final class RecordingCanvas extends android.graphics.Canvas {
@@ -15025,7 +15029,9 @@ package android.graphics {
  public class SweepGradient extends android.graphics.Shader {
  public class SweepGradient extends android.graphics.Shader {
    ctor public SweepGradient(float, float, @NonNull @ColorInt int[], @Nullable float[]);
    ctor public SweepGradient(float, float, @NonNull @ColorInt int[], @Nullable float[]);
    ctor public SweepGradient(float, float, @NonNull @ColorLong long[], @Nullable float[]);
    ctor public SweepGradient(float, float, @ColorInt int, @ColorInt int);
    ctor public SweepGradient(float, float, @ColorInt int, @ColorInt int);
    ctor public SweepGradient(float, float, @ColorLong long, @ColorLong long);
  }
  }
  public class Typeface {
  public class Typeface {
+56 −128
Original line number Original line Diff line number Diff line
@@ -8,6 +8,8 @@


#include <jni.h>
#include <jni.h>


#include <vector>

using namespace android::uirenderer;
using namespace android::uirenderer;


/**
/**
@@ -18,10 +20,10 @@ using namespace android::uirenderer;
 */
 */
static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;


static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
#define ThrowIAE_IfNull(env, ptr)   \
    if (NULL == ptr) {
    if (nullptr == ptr) {           \
        doThrowIAE(env);
        doThrowIAE(env);            \
    }
        return 0;                   \
    }
    }


static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
@@ -76,186 +78,115 @@ static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, j
    }
    }
    sk_sp<SkShader> shader = image->makeShader(
    sk_sp<SkShader> shader = image->makeShader(
            (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY);
            (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY);
    ThrowIAE_IfNull(env, shader.get());


    if (matrix) {
    if (matrix) {
        shader = shader->makeWithLocalMatrix(*matrix);
        shader = shader->makeWithLocalMatrix(*matrix);
    }
    }


    ThrowIAE_IfNull(env, shader.get());
    return reinterpret_cast<jlong>(shader.release());
    return reinterpret_cast<jlong>(shader.release());
}
}


///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////


static jlong LinearGradient_create1(JNIEnv* env, jobject o, jlong matrixPtr,
static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
        jfloat x0, jfloat y0, jfloat x1, jfloat y1,
    const size_t count = env->GetArrayLength(colorArray);
        jintArray colorArray, jfloatArray posArray, jint tileMode) {
    const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);

    std::vector<SkColor4f> colors(count);
    for (size_t i = 0; i < count; ++i) {
        colors[i] = GraphicsJNI::convertColorLong(colorValues[i]);
    }

    env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT);
    return colors;
}

///////////////////////////////////////////////////////////////////////////////////////////////

static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
        jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray,
        jfloatArray posArray, jint tileMode, long colorSpaceHandle) {
    SkPoint pts[2];
    SkPoint pts[2];
    pts[0].set(x0, y0);
    pts[0].set(x0, y0);
    pts[1].set(x1, y1);
    pts[1].set(x1, y1);


    size_t count = env->GetArrayLength(colorArray);
    std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);


    AutoJavaFloatArray autoPos(env, posArray, count);
    AutoJavaFloatArray autoPos(env, posArray, colors.size());
#ifdef SK_SCALAR_IS_FLOAT
#ifdef SK_SCALAR_IS_FLOAT
    SkScalar* pos = autoPos.ptr();
    SkScalar* pos = autoPos.ptr();
#else
#else
    #error Need to convert float array to SkScalar array before calling the following function.
    #error Need to convert float array to SkScalar array before calling the following function.
#endif
#endif


    sk_sp<SkShader> baseShader(SkGradientShader::MakeLinear(pts,
    sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
            reinterpret_cast<const SkColor*>(colorValues), pos, count,
                GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL));
                static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, nullptr));

    SkShader* shader;
    if (matrix) {
        shader = baseShader->makeWithLocalMatrix(*matrix).release();
    } else {
        shader = baseShader.release();
    }

    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
    ThrowIAE_IfNull(env, shader);
    ThrowIAE_IfNull(env, shader);
    return reinterpret_cast<jlong>(shader);
}


static jlong LinearGradient_create2(JNIEnv* env, jobject o, jlong matrixPtr,
        jfloat x0, jfloat y0, jfloat x1, jfloat y1, jint color0, jint color1, jint tileMode) {
    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);

    SkPoint pts[2];
    pts[0].set(x0, y0);
    pts[1].set(x1, y1);

    SkColor colors[2];
    colors[0] = color0;
    colors[1] = color1;

    sk_sp<SkShader> baseShader(SkGradientShader::MakeLinear(pts, colors, NULL, 2,
            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL));

    SkShader* s;
    if (matrix) {
    if (matrix) {
        s = baseShader->makeWithLocalMatrix(*matrix).release();
        shader = shader->makeWithLocalMatrix(*matrix);
    } else {
        s = baseShader.release();
    }
    }


    ThrowIAE_IfNull(env, s);
    return reinterpret_cast<jlong>(shader.release());
    return reinterpret_cast<jlong>(s);
}
}


///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////


static jlong RadialGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
static jlong RadialGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
        jfloat radius, jintArray colorArray, jfloatArray posArray, jint tileMode) {
        jfloat radius, jlongArray colorArray, jfloatArray posArray, jint tileMode,
    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
        jlong colorSpaceHandle) {
    SkPoint center;
    SkPoint center;
    center.set(x, y);
    center.set(x, y);


    size_t      count = env->GetArrayLength(colorArray);
    std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);


    AutoJavaFloatArray autoPos(env, posArray, count);
    AutoJavaFloatArray autoPos(env, posArray, colors.size());
#ifdef SK_SCALAR_IS_FLOAT
#ifdef SK_SCALAR_IS_FLOAT
    SkScalar* pos = autoPos.ptr();
    SkScalar* pos = autoPos.ptr();
#else
#else
    #error Need to convert float array to SkScalar array before calling the following function.
    #error Need to convert float array to SkScalar array before calling the following function.
#endif
#endif


    sk_sp<SkShader> baseShader = SkGradientShader::MakeRadial(center, radius,
    sk_sp<SkShader> shader = SkGradientShader::MakeRadial(center, radius, &colors[0],
            reinterpret_cast<const SkColor*>(colorValues), pos, count,
            GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL);
            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, nullptr);

    SkShader* shader;
    if (matrix) {
        shader = baseShader->makeWithLocalMatrix(*matrix).release();
    } else {
        shader = baseShader.release();
    }

    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
                                 JNI_ABORT);

    ThrowIAE_IfNull(env, shader);
    ThrowIAE_IfNull(env, shader);
    return reinterpret_cast<jlong>(shader);
}


static jlong RadialGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y, jfloat radius,
        jint color0, jint color1, jint tileMode) {
    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    SkPoint center;
    center.set(x, y);

    SkColor colors[2];
    colors[0] = color0;
    colors[1] = color1;

    sk_sp<SkShader> baseShader = SkGradientShader::MakeRadial(center, radius, colors, NULL, 2,
            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL);

    SkShader* shader;
    if (matrix) {
    if (matrix) {
        shader = baseShader->makeWithLocalMatrix(*matrix).release();
        shader = shader->makeWithLocalMatrix(*matrix);
    } else {
        shader = baseShader.release();
    }
    }
    ThrowIAE_IfNull(env, shader);

    return reinterpret_cast<jlong>(shader);
    return reinterpret_cast<jlong>(shader.release());
}
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////


static jlong SweepGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
        jintArray jcolors, jfloatArray jpositions) {
        jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) {
    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
    size_t      count = env->GetArrayLength(jcolors);
    const jint* colors = env->GetIntArrayElements(jcolors, NULL);


    AutoJavaFloatArray autoPos(env, jpositions, count);
    AutoJavaFloatArray autoPos(env, jpositions, colors.size());
#ifdef SK_SCALAR_IS_FLOAT
#ifdef SK_SCALAR_IS_FLOAT
    SkScalar* pos = autoPos.ptr();
    SkScalar* pos = autoPos.ptr();
#else
#else
    #error Need to convert float array to SkScalar array before calling the following function.
    #error Need to convert float array to SkScalar array before calling the following function.
#endif
#endif


    sk_sp<SkShader> baseShader = SkGradientShader::MakeSweep(x, y,
    sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
            reinterpret_cast<const SkColor*>(colors), pos, count,
            GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
            sGradientShaderFlags, NULL);
            sGradientShaderFlags, nullptr);

    SkShader* shader;
    if (matrix) {
        shader = baseShader->makeWithLocalMatrix(*matrix).release();
    } else {
        shader = baseShader.release();
    }

    env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
                                 JNI_ABORT);
    ThrowIAE_IfNull(env, shader);
    ThrowIAE_IfNull(env, shader);
    return reinterpret_cast<jlong>(shader);
}


static jlong SweepGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
        int color0, int color1) {
    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    SkColor colors[2];
    colors[0] = color0;
    colors[1] = color1;

    sk_sp<SkShader> baseShader = SkGradientShader::MakeSweep(x, y, colors,
            NULL, 2, sGradientShaderFlags, NULL);

    SkShader* shader;
    if (matrix) {
    if (matrix) {
        shader = baseShader->makeWithLocalMatrix(*matrix).release();
        shader = shader->makeWithLocalMatrix(*matrix);
    } else {
        shader = baseShader.release();
    }
    }
    ThrowIAE_IfNull(env, shader);

    return reinterpret_cast<jlong>(shader);
    return reinterpret_cast<jlong>(shader.release());
}
}


///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -295,18 +226,15 @@ static const JNINativeMethod gBitmapShaderMethods[] = {
};
};


static const JNINativeMethod gLinearGradientMethods[] = {
static const JNINativeMethod gLinearGradientMethods[] = {
    { "nativeCreate1",     "(JFFFF[I[FI)J",  (void*)LinearGradient_create1     },
    { "nativeCreate",     "(JFFFF[J[FIJ)J",  (void*)LinearGradient_create     },
    { "nativeCreate2",     "(JFFFFIII)J",    (void*)LinearGradient_create2     },
};
};


static const JNINativeMethod gRadialGradientMethods[] = {
static const JNINativeMethod gRadialGradientMethods[] = {
    { "nativeCreate1",     "(JFFF[I[FI)J",  (void*)RadialGradient_create1     },
    { "nativeCreate",     "(JFFF[J[FIJ)J",  (void*)RadialGradient_create     },
    { "nativeCreate2",     "(JFFFIII)J",    (void*)RadialGradient_create2     },
};
};


static const JNINativeMethod gSweepGradientMethods[] = {
static const JNINativeMethod gSweepGradientMethods[] = {
    { "nativeCreate1",     "(JFF[I[F)J",  (void*)SweepGradient_create1     },
    { "nativeCreate",     "(JFF[J[FJ)J",  (void*)SweepGradient_create     },
    { "nativeCreate2",     "(JFFII)J",    (void*)SweepGradient_create2     },
};
};


static const JNINativeMethod gComposeShaderMethods[] = {
static const JNINativeMethod gComposeShaderMethods[] = {
+83 −52
Original line number Original line Diff line number Diff line
@@ -17,21 +17,13 @@
package android.graphics;
package android.graphics;


import android.annotation.ColorInt;
import android.annotation.ColorInt;
import android.annotation.ColorLong;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.annotation.UnsupportedAppUsage;


public class LinearGradient extends Shader {

    private static final int TYPE_COLORS_AND_POSITIONS = 1;
    private static final int TYPE_COLOR_START_AND_COLOR_END = 2;

    /**
     * Type of the LinearGradient: can be either TYPE_COLORS_AND_POSITIONS or
     * TYPE_COLOR_START_AND_COLOR_END.
     */
    private int mType;


public class LinearGradient extends Shader {
    @UnsupportedAppUsage
    @UnsupportedAppUsage
    private float mX0;
    private float mX0;
    @UnsupportedAppUsage
    @UnsupportedAppUsage
@@ -41,16 +33,43 @@ public class LinearGradient extends Shader {
    @UnsupportedAppUsage
    @UnsupportedAppUsage
    private float mY1;
    private float mY1;
    @UnsupportedAppUsage
    @UnsupportedAppUsage
    private int[] mColors;
    @UnsupportedAppUsage
    private float[] mPositions;
    private float[] mPositions;
    @UnsupportedAppUsage
    @UnsupportedAppUsage
    private TileMode mTileMode;

    // @ColorInts are replaced by @ColorLongs, but these remain due to @UnsupportedAppUsage.
    @UnsupportedAppUsage
    @ColorInt
    private int[] mColors;
    @UnsupportedAppUsage
    @ColorInt
    private int mColor0;
    private int mColor0;
    @UnsupportedAppUsage
    @UnsupportedAppUsage
    @ColorInt
    private int mColor1;
    private int mColor1;


    @UnsupportedAppUsage
    @ColorLong
    private TileMode mTileMode;
    private final long[] mColorLongs;


    /**
     * Create a shader that draws a linear gradient along a line.
     *
     * @param x0           The x-coordinate for the start of the gradient line
     * @param y0           The y-coordinate for the start of the gradient line
     * @param x1           The x-coordinate for the end of the gradient line
     * @param y1           The y-coordinate for the end of the gradient line
     * @param colors       The sRGB colors to be distributed along the gradient line
     * @param positions    May be null. The relative positions [0..1] of
     *                     each corresponding color in the colors array. If this is null,
     *                     the the colors are distributed evenly along the gradient line.
     * @param tile         The Shader tiling mode
     */
    public LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int[] colors,
            @Nullable float[] positions, @NonNull TileMode tile) {
        this(x0, y0, x1, y1, convertColors(colors), positions, tile,
                ColorSpace.get(ColorSpace.Named.SRGB));
    }


    /**
    /**
     * Create a shader that draws a linear gradient along a line.
     * Create a shader that draws a linear gradient along a line.
@@ -64,25 +83,54 @@ public class LinearGradient extends Shader {
     *                     each corresponding color in the colors array. If this is null,
     *                     each corresponding color in the colors array. If this is null,
     *                     the the colors are distributed evenly along the gradient line.
     *                     the the colors are distributed evenly along the gradient line.
     * @param tile         The Shader tiling mode
     * @param tile         The Shader tiling mode
     *
     * @throws IllegalArgumentException if there are less than two colors, the colors do
     *      not share the same {@link ColorSpace} or do not use a valid one, or {@code positions}
     *      is not {@code null} and has a different length from {@code colors}.
     */
     */
    public LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int colors[],
    public LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorLong long[] colors,
            @Nullable float positions[], @NonNull TileMode tile) {
            @Nullable float[] positions, @NonNull TileMode tile) {
        if (colors.length < 2) {
        this(x0, y0, x1, y1, colors.clone(), positions, tile, detectColorSpace(colors));
            throw new IllegalArgumentException("needs >= 2 number of colors");
    }
    }

    /**
     * Base constructor. Assumes @param colors is a copy that this object can hold onto,
     * and all colors share @param colorSpace.
     */
    private LinearGradient(float x0, float y0, float x1, float y1,
            @NonNull @ColorLong long[] colors, @Nullable float[] positions, @NonNull TileMode tile,
            @NonNull ColorSpace colorSpace) {
        super(colorSpace);

        if (positions != null && colors.length != positions.length) {
        if (positions != null && colors.length != positions.length) {
            throw new IllegalArgumentException("color and position arrays must be of equal length");
            throw new IllegalArgumentException("color and position arrays must be of equal length");
        }
        }
        mType = TYPE_COLORS_AND_POSITIONS;
        mX0 = x0;
        mX0 = x0;
        mY0 = y0;
        mY0 = y0;
        mX1 = x1;
        mX1 = x1;
        mY1 = y1;
        mY1 = y1;
        mColors = colors.clone();
        mColorLongs = colors;
        mPositions = positions != null ? positions.clone() : null;
        mPositions = positions != null ? positions.clone() : null;
        mTileMode = tile;
        mTileMode = tile;
    }
    }


    /**
     * Create a shader that draws a linear gradient along a line.
     *
     * @param x0       The x-coordinate for the start of the gradient line
     * @param y0       The y-coordinate for the start of the gradient line
     * @param x1       The x-coordinate for the end of the gradient line
     * @param y1       The y-coordinate for the end of the gradient line
     * @param color0   The sRGB color at the start of the gradient line.
     * @param color1   The sRGB color at the end of the gradient line.
     * @param tile     The Shader tiling mode
     */
    public LinearGradient(float x0, float y0, float x1, float y1,
            @ColorInt int color0, @ColorInt int color1,
            @NonNull TileMode tile) {
        this(x0, y0, x1, y1, Color.pack(color0), Color.pack(color1), tile);
    }

    /**
    /**
     * Create a shader that draws a linear gradient along a line.
     * Create a shader that draws a linear gradient along a line.
     *
     *
@@ -93,31 +141,21 @@ public class LinearGradient extends Shader {
     * @param color0   The color at the start of the gradient line.
     * @param color0   The color at the start of the gradient line.
     * @param color1   The color at the end of the gradient line.
     * @param color1   The color at the end of the gradient line.
     * @param tile     The Shader tiling mode
     * @param tile     The Shader tiling mode
     *
     * @throws IllegalArgumentException if the colors do
     *      not share the same {@link ColorSpace} or do not use a valid one.
     */
     */
    public LinearGradient(float x0, float y0, float x1, float y1,
    public LinearGradient(float x0, float y0, float x1, float y1,
            @ColorInt int color0, @ColorInt int color1,
            @ColorLong long color0, @ColorLong long color1,
            @NonNull TileMode tile) {
            @NonNull TileMode tile) {
        mType = TYPE_COLOR_START_AND_COLOR_END;
        this(x0, y0, x1, y1, new long[] {color0, color1}, null, tile);
        mX0 = x0;
        mY0 = y0;
        mX1 = x1;
        mY1 = y1;
        mColor0 = color0;
        mColor1 = color1;
        mColors = null;
        mPositions = null;
        mTileMode = tile;
    }
    }


    @Override
    @Override
    long createNativeInstance(long nativeMatrix) {
    long createNativeInstance(long nativeMatrix) {
        if (mType == TYPE_COLORS_AND_POSITIONS) {
        return nativeCreate(nativeMatrix, mX0, mY0, mX1, mY1,
            return nativeCreate1(nativeMatrix, mX0, mY0, mX1, mY1,
                mColorLongs, mPositions, mTileMode.nativeInt,
                    mColors, mPositions, mTileMode.nativeInt);
                colorSpace().getNativeInstance());
        } else { // TYPE_COLOR_START_AND_COLOR_END
            return nativeCreate2(nativeMatrix, mX0, mY0, mX1, mY1,
                    mColor0, mColor1, mTileMode.nativeInt);
        }
    }
    }


    /**
    /**
@@ -125,19 +163,12 @@ public class LinearGradient extends Shader {
     */
     */
    @Override
    @Override
    protected Shader copy() {
    protected Shader copy() {
        final LinearGradient copy;
        final LinearGradient copy = new LinearGradient(mX0, mY0, mX1, mY1, mColorLongs,
        if (mType == TYPE_COLORS_AND_POSITIONS) {
                mPositions, mTileMode, colorSpace());
            copy = new LinearGradient(mX0, mY0, mX1, mY1, mColors.clone(),
                    mPositions != null ? mPositions.clone() : null, mTileMode);
        } else { // TYPE_COLOR_START_AND_COLOR_END
            copy = new LinearGradient(mX0, mY0, mX1, mY1, mColor0, mColor1, mTileMode);
        }
        copyLocalMatrix(copy);
        copyLocalMatrix(copy);
        return copy;
        return copy;
    }
    }


    private native long nativeCreate1(long matrix, float x0, float y0, float x1, float y1,
    private native long nativeCreate(long matrix, float x0, float y0, float x1, float y1,
            int colors[], float positions[], int tileMode);
            long[] colors, float[] positions, int tileMode, long colorSpaceHandle);
    private native long nativeCreate2(long matrix, float x0, float y0, float x1, float y1,
            int color0, int color1, int tileMode);
}
}
+78 −50

File changed.

Preview size limit exceeded, changes collapsed.

+65 −1
Original line number Original line Diff line number Diff line
@@ -16,6 +16,8 @@


package android.graphics;
package android.graphics;


import android.annotation.ColorInt;
import android.annotation.ColorLong;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.annotation.UnsupportedAppUsage;
@@ -39,7 +41,32 @@ public class Shader {
     * @deprecated Use subclass constructors directly instead.
     * @deprecated Use subclass constructors directly instead.
     */
     */
    @Deprecated
    @Deprecated
    public Shader() {}
    public Shader() {
        mColorSpace = null;
    }

    /**
     * @hide
     */
    public Shader(ColorSpace colorSpace) {
        mColorSpace = colorSpace;
        if (colorSpace == null) {
            throw new IllegalArgumentException(
                    "Use Shader() to create a Shader with no ColorSpace");
        }

        // This just ensures that if the ColorSpace is invalid, the Exception will be thrown now.
        mColorSpace.getNativeInstance();
    }

    private final ColorSpace mColorSpace;

    /**
     * @hide
     */
    protected ColorSpace colorSpace() {
        return mColorSpace;
    }


    /**
    /**
     * Current native shader instance. Created and updated lazily when {@link #getNativeInstance()}
     * Current native shader instance. Created and updated lazily when {@link #getNativeInstance()}
@@ -169,6 +196,43 @@ public class Shader {
        return mNativeInstance;
        return mNativeInstance;
    }
    }


    /**
     * @hide
     */
    public static @ColorLong long[] convertColors(@NonNull @ColorInt int[] colors) {
        if (colors.length < 2) {
            throw new IllegalArgumentException("needs >= 2 number of colors");
        }

        long[] colorLongs = new long[colors.length];
        for (int i = 0; i < colors.length; ++i) {
            colorLongs[i] = Color.pack(colors[i]);
        }

        return colorLongs;
    }

    /**
     * Detect the ColorSpace that the {@code colors} share.
     *
     * @throws IllegalArgumentException if the colors do not all share the same,
     *      valid ColorSpace, or if there are less than 2 colors.
     *
     * @hide
     */
    public static ColorSpace detectColorSpace(@NonNull @ColorLong long[] colors) {
        if (colors.length < 2) {
            throw new IllegalArgumentException("needs >= 2 number of colors");
        }
        final ColorSpace colorSpace = Color.colorSpace(colors[0]);
        for (int i = 1; i < colors.length; ++i) {
            if (Color.colorSpace(colors[i]) != colorSpace) {
                throw new IllegalArgumentException("All colors must be in the same ColorSpace!");
            }
        }
        return colorSpace;
    }

    private static native long nativeGetFinalizer();
    private static native long nativeGetFinalizer();


}
}
Loading