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

Commit eb4e0c3c authored by Romain Guy's avatar Romain Guy Committed by Android (Google) Code Review
Browse files

Merge "Refactor Skia shaders handling."

parents e2e5e674 06f96e26
Loading
Loading
Loading
Loading
+11 −23
Original line number Diff line number Diff line
@@ -17,21 +17,17 @@
package android.view;

import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.DrawFilter;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Picture;
import android.graphics.PorterDuff;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.graphics.TemporaryBuffer;
import android.text.GraphicsOperations;
import android.text.SpannableString;
@@ -593,7 +589,9 @@ class GLES20Canvas extends Canvas {
        if ((index | count | (index + count) | (text.length - index - count)) < 0) {
            throw new IndexOutOfBoundsException();
        }
        boolean hasShader = setupShader(paint);
        nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
        if (hasShader) nResetShader(mRenderer);
    }
    
    private native void nDrawText(int renderer, char[] text, int index, int count, float x, float y,
@@ -601,6 +599,7 @@ class GLES20Canvas extends Canvas {

    @Override
    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
        boolean hasShader = setupShader(paint);
        if (text instanceof String || text instanceof SpannedString ||
                text instanceof SpannableString) {
            nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
@@ -614,6 +613,7 @@ class GLES20Canvas extends Canvas {
            nDrawText(mRenderer, buf, 0, end - start, x, y, paint.mBidiFlags, paint.mNativePaint);
            TemporaryBuffer.recycle(buf);
        }
        if (hasShader) nResetShader(mRenderer);
    }

    @Override
@@ -621,7 +621,9 @@ class GLES20Canvas extends Canvas {
        if ((start | end | (end - start) | (text.length() - end)) < 0) {
            throw new IndexOutOfBoundsException();
        }
        boolean hasShader = setupShader(paint);
        nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
        if (hasShader) nResetShader(mRenderer);
    }

    private native void nDrawText(int renderer, String text, int start, int end, float x, float y,
@@ -629,7 +631,9 @@ class GLES20Canvas extends Canvas {

    @Override
    public void drawText(String text, float x, float y, Paint paint) {
        boolean hasShader = setupShader(paint);
        nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags, paint.mNativePaint);
        if (hasShader) nResetShader(mRenderer);
    }

    @Override
@@ -665,28 +669,12 @@ class GLES20Canvas extends Canvas {
    private boolean setupShader(Paint paint) {
        final Shader shader = paint.getShader();
        if (shader != null) {
            if (shader instanceof BitmapShader) {
                final BitmapShader bs = (BitmapShader) shader;
                nSetupBitmapShader(mRenderer, bs.native_instance, bs.mBitmap.mNativeBitmap,
                        bs.mTileX, bs.mTileY, bs.mLocalMatrix);
                return true;
            } else if (shader instanceof LinearGradient) {
                final LinearGradient ls = (LinearGradient) shader;
                nSetupLinearShader(mRenderer, ls.native_instance, ls.bounds, ls.colors,
                        ls.positions, ls.count, ls.tileMode, ls.mLocalMatrix);
            nSetupShader(mRenderer, shader.native_shader);
            return true;
            } else if (shader instanceof RadialGradient) {
                // TODO: Implement
            } else if (shader instanceof SweepGradient) {
                // TODO: Implement
            }
        }
        return false;
    }

    private native void nSetupLinearShader(int renderer, int shader, int bounds,
            int colors, int positions, int count, int tileMode, int localMatrix);
    private native void nSetupBitmapShader(int renderer, int shader, int bitmap,
            int tileX, int tileY, int matrix);
    private native void nSetupShader(int renderer, int shader);
    private native void nResetShader(int renderer);
}
+116 −75
Original line number Diff line number Diff line
@@ -8,12 +8,14 @@
#include "SkTemplates.h"
#include "SkXfermode.h"

#include <SkiaShader.h>

using namespace android::uirenderer;

static struct {
    jclass clazz;
    jfieldID bounds;
    jfieldID colors;
    jfieldID positions;
} gLinearGradientClassInfo;
    jfieldID shader;
} gShaderClassInfo;

static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
    if (NULL == ptr) {
@@ -48,8 +50,9 @@ static int Color_HSVToColor(JNIEnv* env, jobject, int alpha, jfloatArray hsvArra

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

static void Shader_destructor(JNIEnv* env, jobject, SkShader* shader)
static void Shader_destructor(JNIEnv* env, jobject o, SkShader* shader, SkiaShader* skiaShader)
{
    delete skiaShader;
    shader->safeUnref();
}

@@ -58,7 +61,8 @@ static bool Shader_getLocalMatrix(JNIEnv* env, jobject, const SkShader* shader,
    return shader ? shader->getLocalMatrix(matrix) : false;
}
 
static void Shader_setLocalMatrix(JNIEnv* env, jobject, SkShader* shader, const SkMatrix* matrix)
static void Shader_setLocalMatrix(JNIEnv* env, jobject o, SkShader* shader, SkiaShader* skiaShader,
        const SkMatrix* matrix)
{
    if (shader) {
        if (NULL == matrix) {
@@ -67,30 +71,33 @@ static void Shader_setLocalMatrix(JNIEnv* env, jobject, SkShader* shader, const
        else {
            shader->setLocalMatrix(*matrix);
        }
        skiaShader->setMatrix(const_cast<SkMatrix*>(matrix));
    }
}

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

static SkShader* BitmapShader_constructor(JNIEnv* env, jobject, const SkBitmap* bitmap,
static SkShader* BitmapShader_constructor(JNIEnv* env, jobject o, const SkBitmap* bitmap,
                                          int tileModeX, int tileModeY)
{
    SkShader* s = SkShader::CreateBitmapShader(*bitmap,
                                        (SkShader::TileMode)tileModeX,
                                        (SkShader::TileMode)tileModeY);

    ThrowIAE_IfNull(env, s);
    return s;
}

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

static void LinearGradient_destructor(JNIEnv* env, jobject o, SkShader* shader)
{
    delete reinterpret_cast<jfloat*>(env->GetIntField(o, gLinearGradientClassInfo.bounds));
    delete reinterpret_cast<jint*>(env->GetIntField(o, gLinearGradientClassInfo.colors));
    delete reinterpret_cast<jfloat*>(env->GetIntField(o, gLinearGradientClassInfo.positions));
static SkiaShader* BitmapShader_postConstructor(JNIEnv* env, jobject o, SkShader* shader,
        SkBitmap* bitmap, int tileModeX, int tileModeY) {
    SkiaShader* skiaShader = new SkiaBitmapShader(bitmap, shader,
            static_cast<SkShader::TileMode>(tileModeX), static_cast<SkShader::TileMode>(tileModeY),
            NULL, (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
    return skiaShader;
}
    
///////////////////////////////////////////////////////////////////////////////////////////////

static SkShader* LinearGradient_create1(JNIEnv* env, jobject o,
                                        float x0, float y0, float x1, float y1,
                                        jintArray colorArray, jfloatArray posArray, int tileMode)
@@ -105,19 +112,43 @@ static SkShader* LinearGradient_create1(JNIEnv* env, jobject o,
    SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
    SkScalar*                   pos = NULL;

    if (posArray) {
        AutoJavaFloatArray autoPos(env, posArray, count);
        const float* posValues = autoPos.ptr();
        pos = (SkScalar*)storage.get();
        for (size_t i = 0; i < count; i++) {
            pos[i] = SkFloatToScalar(posValues[i]);
        }
    }
    
    SkShader* shader = SkGradientShader::CreateLinear(pts,
                                reinterpret_cast<const SkColor*>(colorValues),
                                pos, count,
                                static_cast<SkShader::TileMode>(tileMode));

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

static SkiaShader* LinearGradient_postCreate1(JNIEnv* env, jobject o, SkShader* shader,
        float x0, float y0, float x1, float y1, jintArray colorArray,
        jfloatArray posArray, int tileMode) {

    size_t count = env->GetArrayLength(colorArray);
    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);

    jfloat* storedBounds = new jfloat[4];
    storedBounds[0] = x0; storedBounds[1] = y0;
    storedBounds[2] = x1; storedBounds[3] = y1;
    jfloat* storedPositions = new jfloat[count];
    jint* storedColors = new jint[count];
    uint32_t* storedColors = new uint32_t[count];
    memcpy(storedColors, colorValues, count);

    if (posArray) {
        AutoJavaFloatArray autoPos(env, posArray, count);
        const float* posValues = autoPos.ptr();
        pos = (SkScalar*)storage.get();
        for (size_t i = 0; i < count; i++) {
            pos[i] = SkFloatToScalar(posValues[i]);
            storedPositions[i] = posValues[i];
        }
    } else {
@@ -125,32 +156,16 @@ static SkShader* LinearGradient_create1(JNIEnv* env, jobject o,
        storedPositions[1] = 1.0f;
    }

    env->SetIntField(o, gLinearGradientClassInfo.bounds, reinterpret_cast<jint>(storedBounds));
    env->SetIntField(o, gLinearGradientClassInfo.colors, reinterpret_cast<jint>(storedColors));
    env->SetIntField(o, gLinearGradientClassInfo.positions, reinterpret_cast<jint>(storedPositions));
    SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors,
            storedPositions, count, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
            (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);

    SkShader* shader = SkGradientShader::CreateLinear(pts,
                                reinterpret_cast<const SkColor*>(colorValues),
                                pos, count,
                                static_cast<SkShader::TileMode>(tileMode));
    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
                                 JNI_ABORT);
    ThrowIAE_IfNull(env, shader);
    return shader;
    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
    return skiaShader;
}

static SkShader* LinearGradient_create2(JNIEnv* env, jobject o,
                                        float x0, float y0, float x1, float y1,
                                        int color0, int color1, int tileMode)
{
    SkPoint pts[2];
    pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0));
    pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1));

    SkColor colors[2];
    colors[0] = color0;
    colors[1] = color1;
    
static SkiaShader* LinearGradient_postCreate2(JNIEnv* env, jobject o, SkShader* shader,
        float x0, float y0, float x1, float y1, int color0, int color1, int tileMode) {
    float* storedBounds = new float[4];
    storedBounds[0] = x0; storedBounds[1] = y0;
    storedBounds[2] = x1; storedBounds[3] = y1;
@@ -163,11 +178,27 @@ static SkShader* LinearGradient_create2(JNIEnv* env, jobject o,
    storedColors[0] = color0;
    storedColors[1] = color1;

    env->SetIntField(o, gLinearGradientClassInfo.bounds, reinterpret_cast<jint>(storedBounds));
    env->SetIntField(o, gLinearGradientClassInfo.colors, reinterpret_cast<jint>(storedColors));
    env->SetIntField(o, gLinearGradientClassInfo.positions, reinterpret_cast<jint>(storedPositions));
    SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors,
            storedPositions, 2, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
            (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);

    return skiaShader;
}

static SkShader* LinearGradient_create2(JNIEnv* env, jobject o,
                                        float x0, float y0, float x1, float y1,
                                        int color0, int color1, int tileMode)
{
    SkPoint pts[2];
    pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0));
    pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1));

    SkColor colors[2];
    colors[0] = color0;
    colors[1] = color1;
    
    SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);

    ThrowIAE_IfNull(env, s);
    return s;
}
@@ -268,18 +299,38 @@ static SkShader* SweepGradient_create2(JNIEnv* env, jobject, float x, float y,

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

static SkShader* ComposeShader_create1(JNIEnv* env, jobject,
static SkShader* ComposeShader_create1(JNIEnv* env, jobject o,
        SkShader* shaderA, SkShader* shaderB, SkXfermode* mode)
{
    return new SkComposeShader(shaderA, shaderB, mode);
}

static SkShader* ComposeShader_create2(JNIEnv* env, jobject,
                                       SkShader* shaderA, SkShader* shaderB, SkPorterDuff::Mode mode)
static SkShader* ComposeShader_create2(JNIEnv* env, jobject o,
        SkShader* shaderA, SkShader* shaderB, SkPorterDuff::Mode porterDuffMode)
{
    SkAutoUnref au(SkPorterDuff::CreateXfermode(mode));
    SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
    SkXfermode* mode = (SkXfermode*) au.get();
    return new SkComposeShader(shaderA, shaderB, mode);
}

    return new SkComposeShader(shaderA, shaderB, (SkXfermode*)au.get());
static SkiaShader* ComposeShader_postCreate2(JNIEnv* env, jobject o, SkShader* shader,
        SkiaShader* shaderA, SkiaShader* shaderB, SkPorterDuff::Mode porterDuffMode) {
    SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
    SkXfermode* mode = (SkXfermode*) au.get();
    SkXfermode::Mode skiaMode;
    if (!SkXfermode::IsMode(mode, &skiaMode)) {
        skiaMode = SkXfermode::kSrcOver_Mode;
    }
    return new SkiaComposeShader(shaderA, shaderB, skiaMode, shader);
}

static SkiaShader* ComposeShader_postCreate1(JNIEnv* env, jobject o, SkShader* shader,
        SkiaShader* shaderA, SkiaShader* shaderB, SkXfermode* mode) {
    SkXfermode::Mode skiaMode;
    if (!SkXfermode::IsMode(mode, &skiaMode)) {
        skiaMode = SkXfermode::kSrcOver_Mode;
    }
    return new SkiaComposeShader(shaderA, shaderB, skiaMode, shader);
}

///////////////////////////////////////////////////////////////////////////////////////////////
@@ -290,19 +341,21 @@ static JNINativeMethod gColorMethods[] = {
};

static JNINativeMethod gShaderMethods[] = {
    { "nativeDestructor",        "(I)V",     (void*)Shader_destructor        },
    { "nativeDestructor",        "(II)V",    (void*)Shader_destructor        },
    { "nativeGetLocalMatrix",    "(II)Z",    (void*)Shader_getLocalMatrix    },
    { "nativeSetLocalMatrix",    "(II)V",    (void*)Shader_setLocalMatrix    }
    { "nativeSetLocalMatrix",    "(III)V",   (void*)Shader_setLocalMatrix    }
};

static JNINativeMethod gBitmapShaderMethods[] = {
    { "nativeCreate",   "(III)I",  (void*)BitmapShader_constructor }
    { "nativeCreate",     "(III)I",  (void*)BitmapShader_constructor },
    { "nativePostCreate", "(IIII)I", (void*)BitmapShader_postConstructor }
};

static JNINativeMethod gLinearGradientMethods[] = {
    { "nativeDestructor", "(I)V",         (void*)LinearGradient_destructor },
    { "nativeCreate1",     "(FFFF[I[FI)I",  (void*)LinearGradient_create1     },
    { "nativeCreate2",    "(FFFFIII)I",   (void*)LinearGradient_create2    }
    { "nativeCreate2",     "(FFFFIII)I",    (void*)LinearGradient_create2     },
    { "nativePostCreate1", "(IFFFF[I[FI)I", (void*)LinearGradient_postCreate1 },
    { "nativePostCreate2", "(IFFFFIII)I",   (void*)LinearGradient_postCreate2 }
};

static JNINativeMethod gRadialGradientMethods[] = {
@@ -317,7 +370,9 @@ static JNINativeMethod gSweepGradientMethods[] = {

static JNINativeMethod gComposeShaderMethods[] = {
    {"nativeCreate1",      "(III)I",   (void*)ComposeShader_create1     },
    {"nativeCreate2",  "(III)I",    (void*)ComposeShader_create2 }
    {"nativeCreate2",      "(III)I",   (void*)ComposeShader_create2     },
    {"nativePostCreate1",  "(IIII)I",  (void*)ComposeShader_postCreate1 },
    {"nativePostCreate2",  "(IIII)I",  (void*)ComposeShader_postCreate2 }
};

#include <android_runtime/AndroidRuntime.h>
@@ -326,15 +381,6 @@ static JNINativeMethod gComposeShaderMethods[] = {
    result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array));  \
    if (result < 0) return result

#define FIND_CLASS(var, className) \
        var = env->FindClass(className); \
        LOG_FATAL_IF(! var, "Unable to find class " className); \
        var = jclass(env->NewGlobalRef(var));

#define GET_FIELD_ID(var, clazz, fieldName, fieldType) \
        var = env->GetFieldID(clazz, fieldName, fieldType); \
        LOG_FATAL_IF(! var, "Unable to find field " fieldName);

int register_android_graphics_Shader(JNIEnv* env);
int register_android_graphics_Shader(JNIEnv* env)
{
@@ -348,11 +394,6 @@ int register_android_graphics_Shader(JNIEnv* env)
    REG(env, "android/graphics/SweepGradient", gSweepGradientMethods);
    REG(env, "android/graphics/ComposeShader", gComposeShaderMethods);
    
    FIND_CLASS(gLinearGradientClassInfo.clazz, "android/graphics/LinearGradient");
    GET_FIELD_ID(gLinearGradientClassInfo.bounds, gLinearGradientClassInfo.clazz, "bounds", "I");
    GET_FIELD_ID(gLinearGradientClassInfo.colors, gLinearGradientClassInfo.clazz, "colors", "I");
    GET_FIELD_ID(gLinearGradientClassInfo.positions, gLinearGradientClassInfo.clazz, "positions", "I");
    
    return result;
}
+5 −14
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <SkXfermode.h>

#include <OpenGLRenderer.h>
#include <SkiaShader.h>
#include <Rect.h>
#include <ui/Rect.h>

@@ -235,18 +236,9 @@ static void android_view_GLES20Canvas_resetShader(JNIEnv* env, jobject canvas,
    renderer->resetShader();
}

static void android_view_GLES20Canvas_setupBitmapShader(JNIEnv* env, jobject canvas,
        OpenGLRenderer* renderer, SkShader* shader, SkBitmap* bitmap,
        SkShader::TileMode tileX, SkShader::TileMode tileY, SkMatrix* matrix) {
    renderer->setupBitmapShader(bitmap, tileX, tileY, matrix,
            (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
}

static void android_view_GLES20Canvas_setupLinearShader(JNIEnv* env, jobject canvas,
        OpenGLRenderer* renderer, SkShader* shader, float* bounds, uint32_t* colors,
        float* positions, int count, SkShader::TileMode tileMode, SkMatrix* matrix) {
    renderer->setupLinearGradientShader(shader, bounds, colors, positions, count,
            tileMode, matrix, (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
static void android_view_GLES20Canvas_setupShader(JNIEnv* env, jobject canvas,
        OpenGLRenderer* renderer, SkiaShader* shader) {
    renderer->setupShader(shader);
}

// ----------------------------------------------------------------------------
@@ -320,8 +312,7 @@ static JNINativeMethod gMethods[] = {
    {   "nDrawRect",          "(IFFFFI)V",       (void*) android_view_GLES20Canvas_drawRect },

    {   "nResetShader",       "(I)V",            (void*) android_view_GLES20Canvas_resetShader },
    {   "nSetupBitmapShader", "(IIIIII)V",       (void*) android_view_GLES20Canvas_setupBitmapShader },
    {   "nSetupLinearShader", "(IIIIIIII)V",     (void*) android_view_GLES20Canvas_setupLinearShader },
    {   "nSetupShader",       "(II)V",           (void*) android_view_GLES20Canvas_setupShader },

    {   "nDrawText",          "(I[CIIFFII)V",    (void*) android_view_GLES20Canvas_drawTextArray },
    {   "nDrawText",          "(ILjava/lang/String;IIFFII)V",
+6 −20
Original line number Diff line number Diff line
@@ -21,21 +21,6 @@ package android.graphics;
 * mirrored by setting the tiling mode.
 */
public class BitmapShader extends Shader {
    /**
     * We hold on just for the GC, since our native counterpart is using it.
     * 
     * @hide 
     */
    public Bitmap mBitmap;
    /**
     * @hide 
     */
    public int mTileX;
    /**
     * @hide 
     */
    public int mTileY;

    /**
     * Call this to create a new shader that will draw with a bitmap.
     *
@@ -44,12 +29,13 @@ public class BitmapShader extends Shader {
     * @param tileY             The tiling mode for y to draw the bitmap in.
     */
    public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) {
        mBitmap = bitmap;
        mTileX = tileX.nativeInt;
        mTileY = tileY.nativeInt;
        native_instance = nativeCreate(bitmap.ni(), mTileX, mTileY);
        final int b = bitmap.ni();
        native_instance = nativeCreate(b, tileX.nativeInt, tileY.nativeInt);
        native_shader = nativePostCreate(native_instance, b, tileX.nativeInt, tileY.nativeInt);
    }

    private static native int nativeCreate(int native_bitmap, int shaderTileModeX,
            int shaderTileModeY);
    private static native int nativePostCreate(int native_shader, int native_bitmap,
            int shaderTileModeX, int shaderTileModeY);
}
+14 −5
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ public class ComposeShader extends Shader {
    public ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode) {
        native_instance = nativeCreate1(shaderA.native_instance, shaderB.native_instance,
                (mode != null) ? mode.native_instance : 0);
        native_shader = nativePostCreate1(native_instance, shaderA.native_shader,
                shaderB.native_shader, (mode != null) ? mode.native_instance : 0);
    }

    /** Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.
@@ -43,9 +45,16 @@ public class ComposeShader extends Shader {
    public ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode) {
        native_instance = nativeCreate2(shaderA.native_instance, shaderB.native_instance,
                mode.nativeInt);
        native_shader = nativePostCreate2(native_instance, shaderA.native_shader,
                shaderB.native_shader, mode.nativeInt);
    }

    private static native int nativeCreate1(int native_shaderA, int native_shaderB, int native_mode);
    private static native int nativeCreate2(int native_shaderA, int native_shaderB, int porterDuffMode);
    private static native int nativeCreate1(int native_shaderA, int native_shaderB,
            int native_mode);
    private static native int nativeCreate2(int native_shaderA, int native_shaderB,
            int porterDuffMode);
    private static native int nativePostCreate1(int native_shader, int native_skiaShaderA,
            int native_skiaShaderB, int native_mode);
    private static native int nativePostCreate2(int native_shader, int native_skiaShaderA,
            int native_skiaShaderB, int porterDuffMode);
}
Loading