[androidkit] Color filter support
Add MatrixColorFilter, HSLAMatrixColorFilter and ComposeColorFilter. Change-Id: I047368adcd13452566a40e91a6f594dd525efd5f Reviewed-on: https://skia-review.googlesource.com/c/skia/+/422517 Commit-Queue: Florin Malita <fmalita@google.com> Reviewed-by: Jorge Betancourt <jmbetancourt@google.com>
This commit is contained in:
parent
78af79e98d
commit
1df8756419
1
BUILD.gn
1
BUILD.gn
@ -2519,6 +2519,7 @@ if (skia_enable_tools) {
|
||||
sources = [
|
||||
"modules/androidkit/src/AndroidKit.cpp",
|
||||
"modules/androidkit/src/Canvas.cpp",
|
||||
"modules/androidkit/src/ColorFilters.cpp",
|
||||
"modules/androidkit/src/Gradients.cpp",
|
||||
"modules/androidkit/src/Image.cpp",
|
||||
"modules/androidkit/src/ImageFilter.cpp",
|
||||
|
@ -24,10 +24,14 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(Canvas)
|
||||
REGISTER_NATIVES(ColorFilter)
|
||||
REGISTER_NATIVES(ComposeColorFilter)
|
||||
REGISTER_NATIVES(HSLAMatrixColorFilter)
|
||||
REGISTER_NATIVES(Image)
|
||||
REGISTER_NATIVES(ImageFilter)
|
||||
REGISTER_NATIVES(LinearGradient)
|
||||
REGISTER_NATIVES(Matrix)
|
||||
REGISTER_NATIVES(MatrixColorFilter)
|
||||
REGISTER_NATIVES(Paint)
|
||||
REGISTER_NATIVES(Path)
|
||||
REGISTER_NATIVES(PathBuilder)
|
||||
|
86
modules/androidkit/src/ColorFilters.cpp
Normal file
86
modules/androidkit/src/ColorFilters.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2021 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "include/core/SkColorFilter.h"
|
||||
#include "modules/androidkit/src/Utils.h"
|
||||
|
||||
namespace {
|
||||
|
||||
static jlong MakeMatrix(JNIEnv* env, jobject, jfloatArray jcm) {
|
||||
SkASSERT(env->GetArrayLength(jcm) == 20);
|
||||
|
||||
auto cf = SkColorFilters::Matrix(androidkit::utils::CFloats(env, jcm));
|
||||
|
||||
return reinterpret_cast<jlong>(cf.release());
|
||||
}
|
||||
|
||||
static jlong MakeHSLAMatrix(JNIEnv* env, jobject, jfloatArray jcm) {
|
||||
SkASSERT(env->GetArrayLength(jcm) == 20);
|
||||
|
||||
auto cf = SkColorFilters::HSLAMatrix(androidkit::utils::CFloats(env, jcm));
|
||||
|
||||
return reinterpret_cast<jlong>(cf.release());
|
||||
}
|
||||
|
||||
static jlong MakeCompose(JNIEnv*, jobject, jlong outer, jlong inner) {
|
||||
auto cf = SkColorFilters::Compose(sk_ref_sp(reinterpret_cast<SkColorFilter*>(outer)),
|
||||
sk_ref_sp(reinterpret_cast<SkColorFilter*>(inner)));
|
||||
|
||||
return reinterpret_cast<jlong>(cf.release());
|
||||
}
|
||||
|
||||
static void ColorFilter_Release(JNIEnv*, jobject, jlong native_cf) {
|
||||
SkSafeUnref(reinterpret_cast<SkColorFilter*>(native_cf));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int register_androidkit_ColorFilter(JNIEnv* env) {
|
||||
static const JNINativeMethod methods[] = {
|
||||
{"nRelease" , "(J)V" , reinterpret_cast<void*>(ColorFilter_Release) },
|
||||
};
|
||||
|
||||
const auto clazz = env->FindClass("org/skia/androidkit/ColorFilter");
|
||||
return clazz
|
||||
? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods))
|
||||
: JNI_ERR;
|
||||
}
|
||||
|
||||
int register_androidkit_MatrixColorFilter(JNIEnv* env) {
|
||||
static const JNINativeMethod methods[] = {
|
||||
{"nMakeMatrix", "([F)J", reinterpret_cast<void*>(MakeMatrix)},
|
||||
};
|
||||
|
||||
const auto clazz = env->FindClass("org/skia/androidkit/MatrixColorFilter");
|
||||
return clazz
|
||||
? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods))
|
||||
: JNI_ERR;
|
||||
}
|
||||
|
||||
int register_androidkit_HSLAMatrixColorFilter(JNIEnv* env) {
|
||||
static const JNINativeMethod methods[] = {
|
||||
{"nMakeHSLAMatrix", "([F)J", reinterpret_cast<void*>(MakeHSLAMatrix)},
|
||||
};
|
||||
|
||||
const auto clazz = env->FindClass("org/skia/androidkit/HSLAMatrixColorFilter");
|
||||
return clazz
|
||||
? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods))
|
||||
: JNI_ERR;
|
||||
}
|
||||
|
||||
int register_androidkit_ComposeColorFilter(JNIEnv* env) {
|
||||
static const JNINativeMethod methods[] = {
|
||||
{"nMakeCompose", "(JJ)J", reinterpret_cast<void*>(MakeCompose)},
|
||||
};
|
||||
|
||||
const auto clazz = env->FindClass("org/skia/androidkit/ComposeColorFilter");
|
||||
return clazz
|
||||
? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods))
|
||||
: JNI_ERR;
|
||||
}
|
@ -7,34 +7,35 @@
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "include/core/SkColorFilter.h"
|
||||
#include "include/core/SkPaint.h"
|
||||
#include "include/core/SkShader.h"
|
||||
#include "include/effects/SkImageFilters.h"
|
||||
|
||||
namespace {
|
||||
|
||||
static jlong Paint_Create(JNIEnv* env, jobject) {
|
||||
static jlong Paint_Create(JNIEnv*, jobject) {
|
||||
return reinterpret_cast<jlong>(new SkPaint);
|
||||
}
|
||||
|
||||
static void Paint_Release(JNIEnv* env, jobject, jlong native_paint) {
|
||||
static void Paint_Release(JNIEnv*, jobject, jlong native_paint) {
|
||||
delete reinterpret_cast<SkPaint*>(native_paint);
|
||||
}
|
||||
|
||||
static void Paint_SetColor(JNIEnv* env, jobject, jlong native_paint,
|
||||
static void Paint_SetColor(JNIEnv*, jobject, jlong native_paint,
|
||||
float r, float g, float b, float a) {
|
||||
if (auto* paint = reinterpret_cast<SkPaint*>(native_paint)) {
|
||||
paint->setColor4f({r, g, b, a});
|
||||
}
|
||||
}
|
||||
|
||||
static void Paint_SetStroke(JNIEnv* env, jobject, jlong native_paint, jboolean stroke) {
|
||||
static void Paint_SetStroke(JNIEnv*, jobject, jlong native_paint, jboolean stroke) {
|
||||
if (auto* paint = reinterpret_cast<SkPaint*>(native_paint)) {
|
||||
paint->setStroke(stroke);
|
||||
}
|
||||
}
|
||||
|
||||
static void Paint_SetStrokeWidth(JNIEnv* env, jobject, jlong native_paint, jfloat width) {
|
||||
static void Paint_SetStrokeWidth(JNIEnv*, jobject, jlong native_paint, jfloat width) {
|
||||
if (auto* paint = reinterpret_cast<SkPaint*>(native_paint)) {
|
||||
paint->setStrokeWidth(width);
|
||||
}
|
||||
@ -84,13 +85,19 @@ static void Paint_SetStrokeMiter(JNIEnv* env, jobject, jlong native_paint, jfloa
|
||||
}
|
||||
}
|
||||
|
||||
static void Paint_SetShader(JNIEnv* env, jobject, jlong native_paint, jlong native_shader) {
|
||||
static void Paint_SetColorFilter(JNIEnv*, jobject, jlong native_paint, jlong native_cf) {
|
||||
if (auto* paint = reinterpret_cast<SkPaint*>(native_paint)) {
|
||||
paint->setColorFilter(sk_ref_sp(reinterpret_cast<SkColorFilter*>(native_cf)));
|
||||
}
|
||||
}
|
||||
|
||||
static void Paint_SetShader(JNIEnv*, jobject, jlong native_paint, jlong native_shader) {
|
||||
if (auto* paint = reinterpret_cast<SkPaint*>(native_paint)) {
|
||||
paint->setShader(sk_ref_sp(reinterpret_cast<SkShader*>(native_shader)));
|
||||
}
|
||||
}
|
||||
|
||||
static void Paint_SetImageFilter(JNIEnv* env, jobject, jlong native_paint, jlong native_filter) {
|
||||
static void Paint_SetImageFilter(JNIEnv*, jobject, jlong native_paint, jlong native_filter) {
|
||||
if (auto* paint = reinterpret_cast<SkPaint*>(native_paint)) {
|
||||
paint->setImageFilter(sk_ref_sp(reinterpret_cast<SkImageFilter*>(native_filter)));
|
||||
}
|
||||
@ -108,6 +115,7 @@ int register_androidkit_Paint(JNIEnv* env) {
|
||||
{"nSetStrokeCap" , "(JI)V" , reinterpret_cast<void*>(Paint_SetStrokeCap)},
|
||||
{"nSetStrokeJoin" , "(JI)V" , reinterpret_cast<void*>(Paint_SetStrokeJoin)},
|
||||
{"nSetStrokeMiter" , "(JF)V" , reinterpret_cast<void*>(Paint_SetStrokeMiter)},
|
||||
{"nSetColorFilter" , "(JJ)V" , reinterpret_cast<void*>(Paint_SetColorFilter)},
|
||||
{"nSetShader" , "(JJ)V" , reinterpret_cast<void*>(Paint_SetShader)},
|
||||
{"nSetImageFilter" , "(JJ)V" , reinterpret_cast<void*>(Paint_SetImageFilter)},
|
||||
};
|
||||
|
@ -40,6 +40,33 @@ private:
|
||||
CString& operator=(const CString&) = delete;
|
||||
};
|
||||
|
||||
// RAII helper for float array access
|
||||
class CFloats {
|
||||
public:
|
||||
CFloats(JNIEnv* env, const jfloatArray& jfloats)
|
||||
: fEnv(env)
|
||||
, fJFloats(jfloats)
|
||||
, fCFloats(env->GetFloatArrayElements(jfloats, nullptr))
|
||||
{}
|
||||
|
||||
~CFloats() {
|
||||
fEnv->ReleaseFloatArrayElements(fJFloats, fCFloats, 0);
|
||||
}
|
||||
|
||||
operator const float*() const { return fCFloats; }
|
||||
|
||||
private:
|
||||
JNIEnv* fEnv;
|
||||
const jfloatArray& fJFloats;
|
||||
float* fCFloats;
|
||||
|
||||
|
||||
CFloats(CFloats&&) = delete;
|
||||
CFloats(const CFloats&) = delete;
|
||||
CFloats& operator=(CFloats&&) = delete;
|
||||
CFloats& operator=(const CFloats&) = delete;
|
||||
};
|
||||
|
||||
SkSamplingOptions SamplingOptions(jint, jfloat, jfloat);
|
||||
SkTileMode TileMode(jint);
|
||||
|
||||
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2021 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package org.skia.androidkit;
|
||||
|
||||
public class ColorFilter {
|
||||
private long mNativeInstance;
|
||||
|
||||
/**
|
||||
* Releases any resources associated with this ColorFilter.
|
||||
*/
|
||||
public void release() {
|
||||
nRelease(mNativeInstance);
|
||||
mNativeInstance = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
release();
|
||||
}
|
||||
|
||||
protected ColorFilter(long native_instance) {
|
||||
mNativeInstance = native_instance;
|
||||
}
|
||||
|
||||
long getNativeInstance() { return mNativeInstance; }
|
||||
|
||||
private static native void nRelease(long nativeInstance);
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2021 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package org.skia.androidkit;
|
||||
|
||||
public class ComposeColorFilter extends ColorFilter {
|
||||
public ComposeColorFilter(ColorFilter outer, ColorFilter inner) {
|
||||
super(nMakeCompose(outer.getNativeInstance(), inner.getNativeInstance()));
|
||||
}
|
||||
|
||||
private static native long nMakeCompose(long outer, long inner);
|
||||
};
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2021 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package org.skia.androidkit;
|
||||
|
||||
import java.lang.IllegalArgumentException;
|
||||
|
||||
public class HSLAMatrixColorFilter extends ColorFilter {
|
||||
public HSLAMatrixColorFilter(float[] m) throws IllegalArgumentException {
|
||||
super(makeNative(m));
|
||||
}
|
||||
|
||||
private static long makeNative(float[] m) throws IllegalArgumentException {
|
||||
if (m.length != 20) {
|
||||
throw new IllegalArgumentException("Expecting an array of 20 floats.");
|
||||
}
|
||||
|
||||
return nMakeHSLAMatrix(m);
|
||||
}
|
||||
|
||||
private static native long nMakeHSLAMatrix(float[] m);
|
||||
};
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2021 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package org.skia.androidkit;
|
||||
|
||||
import java.lang.IllegalArgumentException;
|
||||
|
||||
public class MatrixColorFilter extends ColorFilter {
|
||||
public MatrixColorFilter(float[] m) throws IllegalArgumentException {
|
||||
super(makeNative(m));
|
||||
}
|
||||
|
||||
private static long makeNative(float[] m) throws IllegalArgumentException {
|
||||
if (m.length != 20) {
|
||||
throw new IllegalArgumentException("Expecting an array of 20 floats.");
|
||||
}
|
||||
|
||||
return nMakeMatrix(m);
|
||||
}
|
||||
|
||||
private static native long nMakeMatrix(float[] m);
|
||||
};
|
@ -26,6 +26,11 @@ public class Paint {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Paint setColorFilter(@Nullable ColorFilter filter) {
|
||||
nSetColorFilter(mNativeInstance, filter != null ? filter.getNativeInstance() : 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Paint setShader(@Nullable Shader shader) {
|
||||
nSetShader(mNativeInstance, shader != null ? shader.getNativeInstance() : 0);
|
||||
return this;
|
||||
@ -107,6 +112,7 @@ public class Paint {
|
||||
private static native void nSetStrokeCap(long nativeInstance, int native_cap);
|
||||
private static native void nSetStrokeJoin(long nativeInstance, int native_join);
|
||||
private static native void nSetStrokeMiter(long nativeInstance, float limit);
|
||||
private static native void nSetColorFilter(long nativeInstance, long nativeCF);
|
||||
private static native void nSetShader(long nativeInstance, long nativeShader);
|
||||
private static native void nSetImageFilter(long nativeInstance, long nativeFilter);
|
||||
}
|
||||
|
@ -19,6 +19,12 @@ class AnimationRenderer extends SurfaceRenderer {
|
||||
mRadialGradient,
|
||||
mConicalGradient,
|
||||
mSweepGradient;
|
||||
private ColorFilter mColorFilter = new MatrixColorFilter(new float[]{
|
||||
0.75f, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 0.5f,
|
||||
0, 0, 1, 0, 0,
|
||||
0, 0, 0, 1, 0,
|
||||
});
|
||||
|
||||
@Override
|
||||
protected void onSurfaceInitialized(Surface surface) {
|
||||
@ -38,8 +44,8 @@ class AnimationRenderer extends SurfaceRenderer {
|
||||
|
||||
float[] pos = {0, 0.5f, 1};
|
||||
|
||||
mLinearGradient = new LinearGradient(0, 0, sw, 0,
|
||||
colors1, pos, TileMode.CLAMP);
|
||||
mLinearGradient = new LinearGradient(0, 0, sw/4, 0,
|
||||
colors1, pos, TileMode.REPEAT);
|
||||
mRadialGradient = new RadialGradient(sw/2, sh/4, Math.min(sw, sh)/2,
|
||||
colors2, pos, TileMode.REPEAT);
|
||||
mConicalGradient = new TwoPointConicalGradient(sw/4, sh/2, sw/4,
|
||||
@ -72,7 +78,7 @@ class AnimationRenderer extends SurfaceRenderer {
|
||||
kHeight = 200;
|
||||
|
||||
canvas.drawRect(cx - kWidth/2, cy - kHeight/2, cx + kWidth/2, cy + kHeight/2,
|
||||
new Paint().setShader(shader));
|
||||
new Paint().setShader(shader).setColorFilter(mColorFilter));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user