Merge "Add plumbing to support gradients in OpenGL renderer."

This commit is contained in:
Romain Guy
2010-07-16 17:13:26 -07:00
committed by Android (Google) Code Review
7 changed files with 161 additions and 37 deletions

View File

@@ -631,7 +631,10 @@ class GLES20Canvas extends Canvas {
bs.mTileX, bs.mTileY, bs.mLocalMatrix);
return true;
} else if (shader instanceof LinearGradient) {
// TODO: Implement
final LinearGradient ls = (LinearGradient) shader;
nSetupLinearShader(mRenderer, ls.native_instance, ls.bounds, ls.colors,
ls.positions, ls.tileMode, ls.mLocalMatrix);
return true;
} else if (shader instanceof RadialGradient) {
// TODO: Implement
} else if (shader instanceof SweepGradient) {
@@ -640,8 +643,10 @@ class GLES20Canvas extends Canvas {
}
return false;
}
private native void nSetupLinearShader(int renderer, int shader, int bounds,
int colors, int positions, int tileMode, int localMatrix);
private native void nSetupBitmapShader(int renderer, int shader, int bitmap,
int tileX, int tileY, int matrix);
private native void nResetShader(int renderer);
private native void nResetShader(int renderer);
}

View File

@@ -8,6 +8,13 @@
#include "SkTemplates.h"
#include "SkXfermode.h"
static struct {
jclass clazz;
jfieldID bounds;
jfieldID colors;
jfieldID positions;
} gLinearGradientClassInfo;
static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
if (NULL == ptr) {
doThrowIAE(env);
@@ -77,7 +84,14 @@ static SkShader* BitmapShader_constructor(JNIEnv* env, jobject, const SkBitmap*
///////////////////////////////////////////////////////////////////////////////////////////////
static SkShader* LinearGradient_create1(JNIEnv* env, jobject,
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 SkShader* LinearGradient_create1(JNIEnv* env, jobject o,
float x0, float y0, float x1, float y1,
jintArray colorArray, jfloatArray posArray, int tileMode)
{
@@ -90,15 +104,31 @@ static SkShader* LinearGradient_create1(JNIEnv* env, jobject,
SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
SkScalar* pos = 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];
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++)
for (size_t i = 0; i < count; i++) {
pos[i] = SkFloatToScalar(posValues[i]);
storedPositions[i] = posValues[i];
}
} else {
storedPositions[0] = 0.0f;
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));
SkShader* shader = SkGradientShader::CreateLinear(pts,
reinterpret_cast<const SkColor*>(colorValues),
pos, count,
@@ -109,7 +139,7 @@ static SkShader* LinearGradient_create1(JNIEnv* env, jobject,
return shader;
}
static SkShader* LinearGradient_create2(JNIEnv* env, jobject,
static SkShader* LinearGradient_create2(JNIEnv* env, jobject o,
float x0, float y0, float x1, float y1,
int color0, int color1, int tileMode)
{
@@ -120,6 +150,22 @@ static SkShader* LinearGradient_create2(JNIEnv* env, jobject,
SkColor colors[2];
colors[0] = color0;
colors[1] = color1;
float* storedBounds = new float[4];
storedBounds[0] = x0; storedBounds[1] = y0;
storedBounds[2] = x1; storedBounds[3] = y1;
float* storedPositions = new float[2];
storedPositions[0] = 0.0f;
storedPositions[1] = 1.0f;
uint32_t* storedColors = new uint32_t[2];
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));
SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
ThrowIAE_IfNull(env, s);
@@ -254,8 +300,9 @@ static JNINativeMethod gBitmapShaderMethods[] = {
};
static JNINativeMethod gLinearGradientMethods[] = {
{ "nativeCreate1", "(FFFF[I[FI)I", (void*)LinearGradient_create1 },
{ "nativeCreate2", "(FFFFIII)I", (void*)LinearGradient_create2 }
{ "nativeDestructor", "(I)V", (void*)LinearGradient_destructor },
{ "nativeCreate1", "(FFFF[I[FI)I", (void*)LinearGradient_create1 },
{ "nativeCreate2", "(FFFFIII)I", (void*)LinearGradient_create2 }
};
static JNINativeMethod gRadialGradientMethods[] = {
@@ -278,6 +325,15 @@ static JNINativeMethod gComposeShaderMethods[] = {
#define REG(env, name, array) \
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)
@@ -292,6 +348,11 @@ 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;
}

View File

@@ -201,7 +201,6 @@ static void android_view_GLES20Canvas_drawBitmapMatrix(JNIEnv* env, jobject canv
static void android_view_GLES20Canvas_drawPatch(JNIEnv* env, jobject canvas,
OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray chunks,
float left, float top, float right, float bottom, SkPaint* paint) {
jbyte* storage = env->GetByteArrayElements(chunks, NULL);
Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(storage);
Res_png_9patch::deserialize(patch);
@@ -239,6 +238,13 @@ static void android_view_GLES20Canvas_setupBitmapShader(JNIEnv* env, jobject can
(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, SkShader::TileMode tileMode, SkMatrix* matrix) {
renderer->setupLinearGradientShader(bounds, colors, positions, tileMode, matrix,
(shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
}
// ----------------------------------------------------------------------------
// JNI Glue
// ----------------------------------------------------------------------------
@@ -280,6 +286,7 @@ static JNINativeMethod gMethods[] = {
{ "nResetShader", "(I)V", (void*) android_view_GLES20Canvas_resetShader },
{ "nSetupBitmapShader", "(IIIIII)V", (void*) android_view_GLES20Canvas_setupBitmapShader },
{ "nSetupLinearShader", "(IIIIIII)V", (void*) android_view_GLES20Canvas_setupLinearShader },
{ "nGetClipBounds", "(ILandroid/graphics/Rect;)Z",
(void*) android_view_GLES20Canvas_getClipBounds },

View File

@@ -17,6 +17,27 @@
package android.graphics;
public class LinearGradient extends Shader {
/**
* These fields are manipulated by the JNI layer, don't touch!
* @hide
*/
public int bounds;
/**
* @hide
*/
public int colors;
/**
* @hide
*/
public int positions;
/**
* @hide
*/
public int count;
/**
* @hide
*/
public int tileMode;
/** Create a shader that draws a linear gradient along a line.
@param x0 The x-coordinate for the start of the gradient line
@@ -38,6 +59,8 @@ public class LinearGradient extends Shader {
throw new IllegalArgumentException("color and position arrays must be of equal length");
}
native_instance = nativeCreate1(x0, y0, x1, y1, colors, positions, tile.nativeInt);
count = colors.length;
tileMode = tile.nativeInt;
}
/** Create a shader that draws a linear gradient along a line.
@@ -52,12 +75,18 @@ public class LinearGradient extends Shader {
public LinearGradient(float x0, float y0, float x1, float y1,
int color0, int color1, TileMode tile) {
native_instance = nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt);
count = 2;
tileMode = tile.nativeInt;
}
protected void finalize() throws Throwable {
super.finalize();
nativeDestructor(native_instance);
}
private static native int nativeCreate1(float x0, float y0, float x1, float y1,
int colors[], float positions[], int tileMode);
private static native int nativeCreate2(float x0, float y0, float x1, float y1,
int color0, int color1, int tileMode);
private native void nativeDestructor(int native_shader);
private native int nativeCreate1(float x0, float y0, float x1, float y1,
int colors[], float positions[], int tileMode);
private native int nativeCreate2(float x0, float y0, float x1, float y1,
int color0, int color1, int tileMode);
}

View File

@@ -528,7 +528,7 @@ void OpenGLRenderer::resetShader() {
void OpenGLRenderer::setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tileX,
SkShader::TileMode tileY, SkMatrix* matrix, bool hasAlpha) {
mShader = kShaderBitmap;
mShader = OpenGLRenderer::kShaderBitmap;
mShaderBlend = hasAlpha;
mShaderBitmap = bitmap;
mShaderTileX = tileX;
@@ -536,6 +536,18 @@ void OpenGLRenderer::setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tile
mShaderMatrix = matrix;
}
void OpenGLRenderer::setupLinearGradientShader(float* bounds, uint32_t* colors,
float* positions, SkShader::TileMode tileMode, SkMatrix* matrix, bool hasAlpha) {
mShader = OpenGLRenderer::kShaderLinearGradient;
mShaderBlend = hasAlpha;
mShaderTileX = tileMode;
mShaderTileY = tileMode;
mShaderMatrix = matrix;
mShaderBounds = bounds;
mShaderColors = colors;
mShaderPositions = positions;
}
///////////////////////////////////////////////////////////////////////////////
// Drawing implementation
///////////////////////////////////////////////////////////////////////////////
@@ -555,9 +567,12 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
const GLfloat b = a * ((color ) & 0xFF) / 255.0f;
switch (mShader) {
case kShaderBitmap:
case OpenGLRenderer::kShaderBitmap:
drawBitmapShader(left, top, right, bottom, a, mode);
return;
case OpenGLRenderer::kShaderLinearGradient:
// TODO: Generate gradient texture, set appropriate shader
break;
default:
break;
}

View File

@@ -103,6 +103,8 @@ public:
void resetShader();
void setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tileX, SkShader::TileMode tileY,
SkMatrix* matrix, bool hasAlpha);
void setupLinearGradientShader(float* bounds, uint32_t* colors, float* positions,
SkShader::TileMode tileMode, SkMatrix* matrix, bool hasAlpha);
private:
/**
@@ -319,13 +321,18 @@ private:
GLenum mLastSrcMode;
GLenum mLastDstMode;
// Skia shader
// Skia shaders
ShaderType mShader;
bool mShaderBlend;
SkBitmap* mShaderBitmap;
SkShader::TileMode mShaderTileX;
SkShader::TileMode mShaderTileY;
SkMatrix* mShaderMatrix;
// Bitmaps
SkBitmap* mShaderBitmap;
// Gradients
float* mShaderBounds;
uint32_t* mShaderColors;
float* mShaderPositions;
// Various caches
TextureCache mTextureCache;

View File

@@ -90,22 +90,22 @@ public:
transform.mapRect(r);
switch (op) {
case SkRegion::kDifference_Op:
break;
case SkRegion::kIntersect_Op:
clipped = clipRect.intersect(r);
break;
case SkRegion::kUnion_Op:
clipped = clipRect.unionWith(r);
break;
case SkRegion::kXOR_Op:
break;
case SkRegion::kReverseDifference_Op:
break;
case SkRegion::kReplace_Op:
clipRect.set(r);
clipped = true;
break;
case SkRegion::kDifference_Op:
break;
case SkRegion::kIntersect_Op:
clipped = clipRect.intersect(r);
break;
case SkRegion::kUnion_Op:
clipped = clipRect.unionWith(r);
break;
case SkRegion::kXOR_Op:
break;
case SkRegion::kReverseDifference_Op:
break;
case SkRegion::kReplace_Op:
clipRect.set(r);
clipped = true;
break;
}
if (clipped) {