1/* 2 * Copyright 2021 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "include/core/SkCanvas.h" 9#include "include/core/SkColor.h" 10#include "include/core/SkPaint.h" 11#include "include/core/SkRRect.h" 12#include "include/core/SkShader.h" 13#include "modules/androidkit/src/Utils.h" 14 15#include <jni.h> 16 17namespace { 18 19jint Canvas_GetWidth(JNIEnv* env, jobject, jlong native_instance) { 20 const auto* canvas = reinterpret_cast<const SkCanvas*>(native_instance); 21 return canvas ? canvas->imageInfo().width() : 0; 22} 23 24jint Canvas_GetHeight(JNIEnv* env, jobject, jlong native_instance) { 25 const auto* canvas = reinterpret_cast<const SkCanvas*>(native_instance); 26 return canvas ? canvas->imageInfo().height() : 0; 27} 28 29jint Canvas_Save(JNIEnv* env, jobject, jlong native_instance) { 30 if (auto* canvas = reinterpret_cast<SkCanvas*>(native_instance)) { 31 return canvas->save(); 32 } 33 return 0; 34} 35 36void Canvas_Restore(JNIEnv* env, jobject, jlong native_instance) { 37 if (auto* canvas = reinterpret_cast<SkCanvas*>(native_instance)) { 38 canvas->restore(); 39 } 40} 41 42void Canvas_RestoreToCount(JNIEnv* env, jobject, jlong native_instance, jint count) { 43 if (auto* canvas = reinterpret_cast<SkCanvas*>(native_instance)) { 44 canvas->restoreToCount(count); 45 } 46} 47 48jint Canvas_SaveLayer(JNIEnv* env, jobject, jlong native_instance, jlong native_paint) { 49 auto* paint = reinterpret_cast<SkPaint* >(native_paint); 50 if (auto* canvas = reinterpret_cast<SkCanvas*>(native_instance)) { 51 return canvas->saveLayer(nullptr, paint); 52 } 53 return 0; 54} 55 56jlong Canvas_LocalToDevice(JNIEnv* env, jobject, jlong native_instance) { 57 if (auto* canvas = reinterpret_cast<SkCanvas*>(native_instance)) { 58 SkM44* m = new SkM44(canvas->getLocalToDevice()); 59 return reinterpret_cast<jlong>(m); 60 } 61 return 0; 62} 63 64void Canvas_Concat(JNIEnv* env, jobject, jlong native_instance, jlong native_matrix) { 65 auto* canvas = reinterpret_cast<SkCanvas*>(native_instance); 66 auto* matrix = reinterpret_cast<SkM44* >(native_matrix); 67 68 if (canvas && matrix) { 69 canvas->concat(*matrix); 70 } 71} 72 73void Canvas_Concat16f(JNIEnv* env, jobject, jlong native_instance, jfloatArray jmatrix) { 74 SkASSERT(env->GetArrayLength(jmatrix) == 16); 75 76 if (auto* canvas = reinterpret_cast<SkCanvas*>(native_instance)) { 77 auto* m = env->GetFloatArrayElements(jmatrix, nullptr); 78 canvas->concat(SkM44::RowMajor(m)); 79 env->ReleaseFloatArrayElements(jmatrix, m, 0); 80 } 81} 82 83void Canvas_Translate(JNIEnv* env, jobject, jlong native_instance, 84 jfloat tx, jfloat ty, jfloat tz) { 85 if (auto* canvas = reinterpret_cast<SkCanvas*>(native_instance)) { 86 canvas->concat(SkM44::Translate(tx, ty, tz)); 87 } 88} 89 90void Canvas_Scale(JNIEnv* env, jobject, jlong native_instance, jfloat sx, jfloat sy, jfloat sz) { 91 if (auto* canvas = reinterpret_cast<SkCanvas*>(native_instance)) { 92 canvas->concat(SkM44::Scale(sx, sy, sz)); 93 } 94} 95 96void Canvas_ClipPath(JNIEnv* env, jobject, jlong native_instance, jlong native_path, 97 jint native_clipOp, jboolean doAA) { 98 if (auto* canvas = reinterpret_cast<SkCanvas*>(native_instance)) { 99 if (auto* path = reinterpret_cast<SkPath*>(native_path)) { 100 canvas->clipPath(*path, static_cast<SkClipOp>(native_clipOp), doAA); 101 } 102 } 103} 104 105void Canvas_ClipRect(JNIEnv* env, jobject, jlong native_instance, jfloat l, jfloat t, jfloat r, jfloat b, 106 jint native_clipOp, jboolean doAA) { 107 if (auto* canvas = reinterpret_cast<SkCanvas*>(native_instance)) { 108 canvas->clipRect(SkRect::MakeLTRB(l, t, r, b), static_cast<SkClipOp>(native_clipOp), doAA); 109 } 110} 111 112void Canvas_ClipRRect(JNIEnv* env, jobject, jlong native_instance, jfloat l, jfloat t, jfloat r, jfloat b, 113 jfloat xRad, jfloat yRad, 114 jint native_clipOp, jboolean doAA) { 115 if (auto* canvas = reinterpret_cast<SkCanvas*>(native_instance)) { 116 canvas->clipRRect(SkRRect::MakeRectXY(SkRect::MakeLTRB(l, t, r, b), xRad, yRad), 117 static_cast<SkClipOp>(native_clipOp), doAA); 118 } 119} 120 121void Canvas_ClipShader(JNIEnv* env, jobject, jlong native_instance, jlong native_shader, jint native_clipOp) { 122 if (auto* canvas = reinterpret_cast<SkCanvas*>(native_instance)) { 123 if (auto* shader = reinterpret_cast<SkShader*>(native_shader)) { 124 canvas->clipShader(sk_ref_sp(shader), static_cast<SkClipOp>(native_clipOp)); 125 } 126 } 127} 128 129void Canvas_DrawColor(JNIEnv* env, jobject, jlong native_instance, 130 float r, float g, float b, float a) { 131 if (auto* canvas = reinterpret_cast<SkCanvas*>(native_instance)) { 132 canvas->drawColor(SkColor4f{r, g, b, a}); 133 } 134} 135 136void Canvas_DrawRect(JNIEnv* env, jobject, jlong native_instance, 137 jfloat left, jfloat top, jfloat right, jfloat bottom, 138 jlong native_paint) { 139 auto* canvas = reinterpret_cast<SkCanvas*>(native_instance); 140 auto* paint = reinterpret_cast<SkPaint* >(native_paint); 141 if (canvas && paint) { 142 canvas->drawRect(SkRect::MakeLTRB(left, top, right, bottom), *paint); 143 } 144} 145 146void Canvas_DrawImage(JNIEnv* env, jobject, jlong native_instance, jlong native_image, 147 jfloat x, jfloat y, 148 jint sampling_desc, jfloat sampling_b, jfloat sampling_c) { 149 auto* canvas = reinterpret_cast<SkCanvas*>(native_instance); 150 auto* image = reinterpret_cast<SkImage *>(native_image); 151 152 if (canvas && image) { 153 canvas->drawImage(image, x, y, 154 androidkit::utils::SamplingOptions(sampling_desc, sampling_b, sampling_c)); 155 } 156} 157 158void Canvas_DrawPath(JNIEnv* env, jobject, jlong native_instance, jlong native_path, 159 jlong native_paint) { 160 auto* canvas = reinterpret_cast<SkCanvas*>(native_instance); 161 auto* path = reinterpret_cast<SkPath* >(native_path); 162 auto* paint = reinterpret_cast<SkPaint* >(native_paint); 163 if (canvas && paint && path) { 164 canvas->drawPath(*path, *paint); 165 } 166} 167 168// jPos: a composite array in the form of [x1, y1, x2, y2, ... ,xn, yn] 169// callers of this function check should throw IllegalArgumentException in Java 170void Canvas_DrawGlyphs(JNIEnv* env, jobject, jlong native_instance, jcharArray jglyphs, 171 jfloatArray jPos, jfloat xOrigin, jfloat yOrigin, 172 jlong native_font, jlong native_paint) { 173 auto* canvas = reinterpret_cast<SkCanvas*>(native_instance); 174 auto* font = reinterpret_cast<SkFont*>(native_font); 175 auto* paint = reinterpret_cast<SkPaint* >(native_paint); 176 if (canvas && font && paint) { 177 int count = env->GetArrayLength(jglyphs); 178 auto* compositePositions = env->GetFloatArrayElements(jPos, nullptr); 179 auto* positions = reinterpret_cast<SkPoint*>(compositePositions); 180 auto* glyphs = env->GetCharArrayElements(jglyphs, nullptr); 181 canvas->drawGlyphs(count, glyphs, positions, {xOrigin, yOrigin}, *font, *paint); 182 183 env->ReleaseCharArrayElements(jglyphs, glyphs, 0); 184 env->ReleaseFloatArrayElements(jPos, compositePositions, 0); 185 } 186} 187 188} // namespace 189 190int register_androidkit_Canvas(JNIEnv* env) { 191 static const JNINativeMethod methods[] = { 192 {"nGetWidth" , "(J)I" , reinterpret_cast<void*>(Canvas_GetWidth) }, 193 {"nGetHeight" , "(J)I" , reinterpret_cast<void*>(Canvas_GetHeight) }, 194 {"nSave" , "(J)I" , reinterpret_cast<void*>(Canvas_Save) }, 195 {"nSaveLayer" , "(JJ)I" , reinterpret_cast<void*>(Canvas_SaveLayer) }, 196 {"nRestore" , "(J)V" , reinterpret_cast<void*>(Canvas_Restore) }, 197 {"nRestoreToCount" , "(JI)V" , reinterpret_cast<void*>(Canvas_RestoreToCount)}, 198 {"nGetLocalToDevice", "(J)J" , reinterpret_cast<void*>(Canvas_LocalToDevice) }, 199 {"nConcat" , "(JJ)V" , reinterpret_cast<void*>(Canvas_Concat) }, 200 {"nConcat16f" , "(J[F)V" , reinterpret_cast<void*>(Canvas_Concat16f) }, 201 {"nTranslate" , "(JFFF)V" , reinterpret_cast<void*>(Canvas_Translate) }, 202 {"nScale" , "(JFFF)V" , reinterpret_cast<void*>(Canvas_Scale) }, 203 {"nClipPath" , "(JJIZ)V" , reinterpret_cast<void*>(Canvas_ClipPath) }, 204 {"nClipRect" , "(JFFFFIZ)V" , reinterpret_cast<void*>(Canvas_ClipRect) }, 205 {"nClipRRect" , "(JFFFFFFIZ)V" , reinterpret_cast<void*>(Canvas_ClipRRect) }, 206 {"nClipShader" , "(JJI)V" , reinterpret_cast<void*>(Canvas_ClipShader) }, 207 {"nDrawColor" , "(JFFFF)V" , reinterpret_cast<void*>(Canvas_DrawColor) }, 208 {"nDrawRect" , "(JFFFFJ)V" , reinterpret_cast<void*>(Canvas_DrawRect) }, 209 {"nDrawImage" , "(JJFFIFF)V" , reinterpret_cast<void*>(Canvas_DrawImage) }, 210 {"nDrawPath" , "(JJJ)V" , reinterpret_cast<void*>(Canvas_DrawPath) }, 211 {"nDrawGlyphs" , "(J[C[FFFJJ)V", reinterpret_cast<void*>(Canvas_DrawGlyphs) }, 212 213 }; 214 215 const auto clazz = env->FindClass("org/skia/androidkit/Canvas"); 216 return clazz 217 ? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods)) 218 : JNI_ERR; 219} 220