|  | /* | 
|  | * 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/SkM44.h" | 
|  | #include "include/effects/SkGradientShader.h" | 
|  | #include "modules/androidkit/src/Utils.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Helper for common gradient data access. | 
|  | class GradientData { | 
|  | public: | 
|  | GradientData(JNIEnv* env, const jfloatArray& jcolors, const jfloatArray& jpos, | 
|  | jint jtm, jlong native_lm) | 
|  | : fEnv(env) | 
|  | , fJColors(jcolors) | 
|  | , fJPos(jpos) | 
|  | , fColors(env->GetFloatArrayElements(jcolors, nullptr)) | 
|  | , fPos(env->GetFloatArrayElements(jpos, nullptr)) | 
|  | , fCount(env->GetArrayLength(jpos)) | 
|  | , fTileMode(androidkit::utils::TileMode(jtm)) | 
|  | , fLocalMatrix(native_lm ? reinterpret_cast<const SkM44*>(native_lm)->asM33() : SkMatrix()) | 
|  | { | 
|  | SkASSERT(env->GetArrayLength(jcolors) == 4*fCount); | 
|  | } | 
|  |  | 
|  | ~GradientData() { | 
|  | fEnv->ReleaseFloatArrayElements(fJPos, fPos, 0); | 
|  | fEnv->ReleaseFloatArrayElements(fJColors, fColors, 0); | 
|  | } | 
|  |  | 
|  | int count() const { return fCount; } | 
|  |  | 
|  | const SkColor4f*  colors()      const { return reinterpret_cast<const SkColor4f*>(fColors); } | 
|  | const float*      pos()         const { return fPos; } | 
|  | const SkTileMode& tileMode()    const { return fTileMode; } | 
|  | const SkMatrix&   localMatrix() const { return fLocalMatrix; } | 
|  |  | 
|  | private: | 
|  | JNIEnv*            fEnv; | 
|  | const jfloatArray& fJColors; | 
|  | const jfloatArray& fJPos; | 
|  | float*             fColors; | 
|  | float*             fPos; | 
|  | const int          fCount; | 
|  | const SkTileMode   fTileMode; | 
|  | const SkMatrix     fLocalMatrix; | 
|  | }; | 
|  |  | 
|  | static jlong MakeLinear(JNIEnv* env, jobject, jfloat x0, jfloat y0, jfloat x1, jfloat y1, | 
|  | jfloatArray jcolors, jfloatArray jpos, jint jtm, jlong native_lm) { | 
|  | const GradientData gdata(env, jcolors, jpos, jtm, native_lm); | 
|  | const SkPoint pts[] = {{x0, y0}, {x1, y1}}; | 
|  |  | 
|  | auto shader = SkGradientShader::MakeLinear(pts, | 
|  | gdata.colors(), | 
|  | nullptr, | 
|  | gdata.pos(), | 
|  | gdata.count(), | 
|  | gdata.tileMode(), | 
|  | 0, | 
|  | &gdata.localMatrix()); | 
|  |  | 
|  | return reinterpret_cast<jlong>(shader.release()); | 
|  | } | 
|  |  | 
|  | static jlong MakeRadial(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat r, | 
|  | jfloatArray jcolors, jfloatArray jpos, jint jtm, jlong native_lm) { | 
|  | const GradientData gdata(env, jcolors, jpos, jtm, native_lm); | 
|  |  | 
|  | auto shader = SkGradientShader::MakeRadial({x,y}, r, | 
|  | gdata.colors(), | 
|  | nullptr, | 
|  | gdata.pos(), | 
|  | gdata.count(), | 
|  | gdata.tileMode(), | 
|  | 0, | 
|  | &gdata.localMatrix()); | 
|  |  | 
|  | return reinterpret_cast<jlong>(shader.release()); | 
|  | } | 
|  |  | 
|  | static jlong MakeTwoPointConical(JNIEnv* env, jobject, | 
|  | jfloat x0, jfloat y0, jfloat r0, | 
|  | jfloat x1, jfloat y1, jfloat r1, | 
|  | jfloatArray jcolors, jfloatArray jpos, jint jtm, jlong native_lm) { | 
|  | const GradientData gdata(env, jcolors, jpos, jtm, native_lm); | 
|  |  | 
|  | auto shader = SkGradientShader::MakeTwoPointConical({x0,y0}, r0, | 
|  | {x1,y1}, r1, | 
|  | gdata.colors(), | 
|  | nullptr, | 
|  | gdata.pos(), | 
|  | gdata.count(), | 
|  | gdata.tileMode(), | 
|  | 0, | 
|  | &gdata.localMatrix()); | 
|  |  | 
|  | return reinterpret_cast<jlong>(shader.release()); | 
|  | } | 
|  |  | 
|  | static jlong MakeSweep(JNIEnv* env, jobject, jfloat x, jfloat y, jfloat sa, jfloat ea, | 
|  | jfloatArray jcolors, jfloatArray jpos, jint jtm, jlong native_lm) { | 
|  | const GradientData gdata(env, jcolors, jpos, jtm, native_lm); | 
|  |  | 
|  | auto shader = SkGradientShader::MakeSweep(x, y, | 
|  | gdata.colors(), | 
|  | nullptr, | 
|  | gdata.pos(), | 
|  | gdata.count(), | 
|  | gdata.tileMode(), | 
|  | sa, ea, | 
|  | 0, | 
|  | &gdata.localMatrix()); | 
|  |  | 
|  | return reinterpret_cast<jlong>(shader.release()); | 
|  | } | 
|  |  | 
|  | } // namespace | 
|  |  | 
|  | int register_androidkit_LinearGradient(JNIEnv* env) { | 
|  | static const JNINativeMethod methods[] = { | 
|  | {"nMakeLinear", "(FFFF[F[FIJ)J", reinterpret_cast<void*>(MakeLinear)}, | 
|  | }; | 
|  |  | 
|  | const auto clazz = env->FindClass("org/skia/androidkit/LinearGradient"); | 
|  | return clazz | 
|  | ? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods)) | 
|  | : JNI_ERR; | 
|  | } | 
|  |  | 
|  | int register_androidkit_RadialGradient(JNIEnv* env) { | 
|  | static const JNINativeMethod methods[] = { | 
|  | {"nMakeRadial", "(FFF[F[FIJ)J", reinterpret_cast<void*>(MakeRadial)}, | 
|  | }; | 
|  |  | 
|  | const auto clazz = env->FindClass("org/skia/androidkit/RadialGradient"); | 
|  | return clazz | 
|  | ? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods)) | 
|  | : JNI_ERR; | 
|  | } | 
|  |  | 
|  | int register_androidkit_TwoPointConicalGradient(JNIEnv* env) { | 
|  | static const JNINativeMethod methods[] = { | 
|  | {"nMakeTwoPointConical", "(FFFFFF[F[FIJ)J", reinterpret_cast<void*>(MakeTwoPointConical)}, | 
|  | }; | 
|  |  | 
|  | const auto clazz = env->FindClass("org/skia/androidkit/TwoPointConicalGradient"); | 
|  | return clazz | 
|  | ? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods)) | 
|  | : JNI_ERR; | 
|  | } | 
|  |  | 
|  | int register_androidkit_SweepGradient(JNIEnv* env) { | 
|  | static const JNINativeMethod methods[] = { | 
|  | {"nMakeSweep", "(FFFF[F[FIJ)J", reinterpret_cast<void*>(MakeSweep)}, | 
|  | }; | 
|  |  | 
|  | const auto clazz = env->FindClass("org/skia/androidkit/SweepGradient"); | 
|  | return clazz | 
|  | ? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods)) | 
|  | : JNI_ERR; | 
|  | } |