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