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

Commit 1bd8c8bb authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

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

parents a9ca57ca b0aecc22
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -14249,7 +14249,9 @@ package android.graphics {
  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 @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, @ColorLong long, @ColorLong long, @NonNull android.graphics.Shader.TileMode);
  }
  public class MaskFilter {
@@ -14778,7 +14780,9 @@ package android.graphics {
  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 @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, @ColorLong long, @ColorLong long, @NonNull android.graphics.Shader.TileMode);
  }
  public final class RecordingCanvas extends android.graphics.Canvas {
@@ -15038,7 +15042,9 @@ package android.graphics {
  public class SweepGradient extends android.graphics.Shader {
    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, @ColorLong long, @ColorLong long);
  }
  public class Typeface {
+56 −128
Original line number Diff line number Diff line
@@ -8,6 +8,8 @@

#include <jni.h>

#include <vector>

using namespace android::uirenderer;

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

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

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(
            (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY);
    ThrowIAE_IfNull(env, shader.get());

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

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

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

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

    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];
    pts[0].set(x0, y0);
    pts[1].set(x1, y1);

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

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

    sk_sp<SkShader> baseShader(SkGradientShader::MakeLinear(pts,
            reinterpret_cast<const SkColor*>(colorValues), pos, count,
            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL));

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

    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
    sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
                GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
                static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, nullptr));
    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);

    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) {
        s = baseShader->makeWithLocalMatrix(*matrix).release();
    } else {
        s = baseShader.release();
        shader = shader->makeWithLocalMatrix(*matrix);
    }

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

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

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

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

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

    sk_sp<SkShader> baseShader = SkGradientShader::MakeRadial(center, radius,
            reinterpret_cast<const SkColor*>(colorValues), pos, count,
            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, NULL);

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

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

    sk_sp<SkShader> shader = SkGradientShader::MakeRadial(center, radius, &colors[0],
            GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, nullptr);
    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);
    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) {
        shader = baseShader->makeWithLocalMatrix(*matrix).release();
    } else {
        shader = baseShader.release();
        shader = shader->makeWithLocalMatrix(*matrix);
    }
    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,
        jintArray jcolors, jfloatArray jpositions) {
    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    size_t      count = env->GetArrayLength(jcolors);
    const jint* colors = env->GetIntArrayElements(jcolors, NULL);
static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
        jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) {
    std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);

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

    sk_sp<SkShader> baseShader = SkGradientShader::MakeSweep(x, y,
            reinterpret_cast<const SkColor*>(colors), pos, count,
            sGradientShaderFlags, NULL);

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

    env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
                                 JNI_ABORT);
    sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
            GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
            sGradientShaderFlags, nullptr);
    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);
    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) {
        shader = baseShader->makeWithLocalMatrix(*matrix).release();
    } else {
        shader = baseShader.release();
        shader = shader->makeWithLocalMatrix(*matrix);
    }
    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[] = {
    { "nativeCreate1",     "(JFFFF[I[FI)J",  (void*)LinearGradient_create1     },
    { "nativeCreate2",     "(JFFFFIII)J",    (void*)LinearGradient_create2     },
    { "nativeCreate",     "(JFFFF[J[FIJ)J",  (void*)LinearGradient_create     },
};

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

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

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

import android.annotation.ColorInt;
import android.annotation.ColorLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
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
    private float mX0;
    @UnsupportedAppUsage
@@ -41,16 +33,43 @@ public class LinearGradient extends Shader {
    @UnsupportedAppUsage
    private float mY1;
    @UnsupportedAppUsage
    private int[] mColors;
    @UnsupportedAppUsage
    private float[] mPositions;
    @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;
    @UnsupportedAppUsage
    @ColorInt
    private int mColor1;

    @UnsupportedAppUsage
    private TileMode mTileMode;
    @ColorLong
    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.
@@ -64,25 +83,54 @@ public class LinearGradient extends Shader {
     *                     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
     *
     * @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[],
            @Nullable float positions[], @NonNull TileMode tile) {
        if (colors.length < 2) {
            throw new IllegalArgumentException("needs >= 2 number of colors");
    public LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorLong long[] colors,
            @Nullable float[] positions, @NonNull TileMode tile) {
        this(x0, y0, x1, y1, colors.clone(), positions, tile, detectColorSpace(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) {
            throw new IllegalArgumentException("color and position arrays must be of equal length");
        }
        mType = TYPE_COLORS_AND_POSITIONS;
        mX0 = x0;
        mY0 = y0;
        mX1 = x1;
        mY1 = y1;
        mColors = colors.clone();
        mColorLongs = colors;
        mPositions = positions != null ? positions.clone() : null;
        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.
     *
@@ -93,31 +141,21 @@ public class LinearGradient extends Shader {
     * @param color0   The color at the start of the gradient line.
     * @param color1   The color at the end of the gradient line.
     * @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,
            @ColorInt int color0, @ColorInt int color1,
            @ColorLong long color0, @ColorLong long color1,
            @NonNull TileMode tile) {
        mType = TYPE_COLOR_START_AND_COLOR_END;
        mX0 = x0;
        mY0 = y0;
        mX1 = x1;
        mY1 = y1;
        mColor0 = color0;
        mColor1 = color1;
        mColors = null;
        mPositions = null;
        mTileMode = tile;
        this(x0, y0, x1, y1, new long[] {color0, color1}, null, tile);
    }

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

    /**
@@ -125,19 +163,12 @@ public class LinearGradient extends Shader {
     */
    @Override
    protected Shader copy() {
        final LinearGradient copy;
        if (mType == TYPE_COLORS_AND_POSITIONS) {
            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);
        }
        final LinearGradient copy = new LinearGradient(mX0, mY0, mX1, mY1, mColorLongs,
                mPositions, mTileMode, colorSpace());
        copyLocalMatrix(copy);
        return copy;
    }

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

File changed.

Preview size limit exceeded, changes collapsed.

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

package android.graphics;

import android.annotation.ColorInt;
import android.annotation.ColorLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
@@ -39,7 +41,32 @@ public class Shader {
     * @deprecated Use subclass constructors directly instead.
     */
    @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()}
@@ -169,6 +196,43 @@ public class Shader {
        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();

}
Loading