[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 = [
|
sources = [
|
||||||
"modules/androidkit/src/AndroidKit.cpp",
|
"modules/androidkit/src/AndroidKit.cpp",
|
||||||
"modules/androidkit/src/Canvas.cpp",
|
"modules/androidkit/src/Canvas.cpp",
|
||||||
|
"modules/androidkit/src/ColorFilters.cpp",
|
||||||
"modules/androidkit/src/Gradients.cpp",
|
"modules/androidkit/src/Gradients.cpp",
|
||||||
"modules/androidkit/src/Image.cpp",
|
"modules/androidkit/src/Image.cpp",
|
||||||
"modules/androidkit/src/ImageFilter.cpp",
|
"modules/androidkit/src/ImageFilter.cpp",
|
||||||
|
@ -24,10 +24,14 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
REGISTER_NATIVES(Canvas)
|
REGISTER_NATIVES(Canvas)
|
||||||
|
REGISTER_NATIVES(ColorFilter)
|
||||||
|
REGISTER_NATIVES(ComposeColorFilter)
|
||||||
|
REGISTER_NATIVES(HSLAMatrixColorFilter)
|
||||||
REGISTER_NATIVES(Image)
|
REGISTER_NATIVES(Image)
|
||||||
REGISTER_NATIVES(ImageFilter)
|
REGISTER_NATIVES(ImageFilter)
|
||||||
REGISTER_NATIVES(LinearGradient)
|
REGISTER_NATIVES(LinearGradient)
|
||||||
REGISTER_NATIVES(Matrix)
|
REGISTER_NATIVES(Matrix)
|
||||||
|
REGISTER_NATIVES(MatrixColorFilter)
|
||||||
REGISTER_NATIVES(Paint)
|
REGISTER_NATIVES(Paint)
|
||||||
REGISTER_NATIVES(Path)
|
REGISTER_NATIVES(Path)
|
||||||
REGISTER_NATIVES(PathBuilder)
|
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 <jni.h>
|
||||||
|
|
||||||
|
#include "include/core/SkColorFilter.h"
|
||||||
#include "include/core/SkPaint.h"
|
#include "include/core/SkPaint.h"
|
||||||
#include "include/core/SkShader.h"
|
#include "include/core/SkShader.h"
|
||||||
#include "include/effects/SkImageFilters.h"
|
#include "include/effects/SkImageFilters.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
static jlong Paint_Create(JNIEnv* env, jobject) {
|
static jlong Paint_Create(JNIEnv*, jobject) {
|
||||||
return reinterpret_cast<jlong>(new SkPaint);
|
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);
|
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) {
|
float r, float g, float b, float a) {
|
||||||
if (auto* paint = reinterpret_cast<SkPaint*>(native_paint)) {
|
if (auto* paint = reinterpret_cast<SkPaint*>(native_paint)) {
|
||||||
paint->setColor4f({r, g, b, a});
|
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)) {
|
if (auto* paint = reinterpret_cast<SkPaint*>(native_paint)) {
|
||||||
paint->setStroke(stroke);
|
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)) {
|
if (auto* paint = reinterpret_cast<SkPaint*>(native_paint)) {
|
||||||
paint->setStrokeWidth(width);
|
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)) {
|
if (auto* paint = reinterpret_cast<SkPaint*>(native_paint)) {
|
||||||
paint->setShader(sk_ref_sp(reinterpret_cast<SkShader*>(native_shader)));
|
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)) {
|
if (auto* paint = reinterpret_cast<SkPaint*>(native_paint)) {
|
||||||
paint->setImageFilter(sk_ref_sp(reinterpret_cast<SkImageFilter*>(native_filter)));
|
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)},
|
{"nSetStrokeCap" , "(JI)V" , reinterpret_cast<void*>(Paint_SetStrokeCap)},
|
||||||
{"nSetStrokeJoin" , "(JI)V" , reinterpret_cast<void*>(Paint_SetStrokeJoin)},
|
{"nSetStrokeJoin" , "(JI)V" , reinterpret_cast<void*>(Paint_SetStrokeJoin)},
|
||||||
{"nSetStrokeMiter" , "(JF)V" , reinterpret_cast<void*>(Paint_SetStrokeMiter)},
|
{"nSetStrokeMiter" , "(JF)V" , reinterpret_cast<void*>(Paint_SetStrokeMiter)},
|
||||||
|
{"nSetColorFilter" , "(JJ)V" , reinterpret_cast<void*>(Paint_SetColorFilter)},
|
||||||
{"nSetShader" , "(JJ)V" , reinterpret_cast<void*>(Paint_SetShader)},
|
{"nSetShader" , "(JJ)V" , reinterpret_cast<void*>(Paint_SetShader)},
|
||||||
{"nSetImageFilter" , "(JJ)V" , reinterpret_cast<void*>(Paint_SetImageFilter)},
|
{"nSetImageFilter" , "(JJ)V" , reinterpret_cast<void*>(Paint_SetImageFilter)},
|
||||||
};
|
};
|
||||||
|
@ -40,6 +40,33 @@ private:
|
|||||||
CString& operator=(const CString&) = delete;
|
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);
|
SkSamplingOptions SamplingOptions(jint, jfloat, jfloat);
|
||||||
SkTileMode TileMode(jint);
|
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;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Paint setColorFilter(@Nullable ColorFilter filter) {
|
||||||
|
nSetColorFilter(mNativeInstance, filter != null ? filter.getNativeInstance() : 0);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Paint setShader(@Nullable Shader shader) {
|
public Paint setShader(@Nullable Shader shader) {
|
||||||
nSetShader(mNativeInstance, shader != null ? shader.getNativeInstance() : 0);
|
nSetShader(mNativeInstance, shader != null ? shader.getNativeInstance() : 0);
|
||||||
return this;
|
return this;
|
||||||
@ -107,6 +112,7 @@ public class Paint {
|
|||||||
private static native void nSetStrokeCap(long nativeInstance, int native_cap);
|
private static native void nSetStrokeCap(long nativeInstance, int native_cap);
|
||||||
private static native void nSetStrokeJoin(long nativeInstance, int native_join);
|
private static native void nSetStrokeJoin(long nativeInstance, int native_join);
|
||||||
private static native void nSetStrokeMiter(long nativeInstance, float limit);
|
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 nSetShader(long nativeInstance, long nativeShader);
|
||||||
private static native void nSetImageFilter(long nativeInstance, long nativeFilter);
|
private static native void nSetImageFilter(long nativeInstance, long nativeFilter);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,12 @@ class AnimationRenderer extends SurfaceRenderer {
|
|||||||
mRadialGradient,
|
mRadialGradient,
|
||||||
mConicalGradient,
|
mConicalGradient,
|
||||||
mSweepGradient;
|
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
|
@Override
|
||||||
protected void onSurfaceInitialized(Surface surface) {
|
protected void onSurfaceInitialized(Surface surface) {
|
||||||
@ -38,8 +44,8 @@ class AnimationRenderer extends SurfaceRenderer {
|
|||||||
|
|
||||||
float[] pos = {0, 0.5f, 1};
|
float[] pos = {0, 0.5f, 1};
|
||||||
|
|
||||||
mLinearGradient = new LinearGradient(0, 0, sw, 0,
|
mLinearGradient = new LinearGradient(0, 0, sw/4, 0,
|
||||||
colors1, pos, TileMode.CLAMP);
|
colors1, pos, TileMode.REPEAT);
|
||||||
mRadialGradient = new RadialGradient(sw/2, sh/4, Math.min(sw, sh)/2,
|
mRadialGradient = new RadialGradient(sw/2, sh/4, Math.min(sw, sh)/2,
|
||||||
colors2, pos, TileMode.REPEAT);
|
colors2, pos, TileMode.REPEAT);
|
||||||
mConicalGradient = new TwoPointConicalGradient(sw/4, sh/2, sw/4,
|
mConicalGradient = new TwoPointConicalGradient(sw/4, sh/2, sw/4,
|
||||||
@ -72,7 +78,7 @@ class AnimationRenderer extends SurfaceRenderer {
|
|||||||
kHeight = 200;
|
kHeight = 200;
|
||||||
|
|
||||||
canvas.drawRect(cx - kWidth/2, cy - kHeight/2, cx + kWidth/2, cy + kHeight/2,
|
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