1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "GraphicsJNI.h"
18#include "jni.h"
19#include "core_jni_helpers.h"
20
21#include "PathParser.h"
22#include "VectorDrawable.h"
23
24#include <hwui/Paint.h>
25
26namespace android {
27using namespace uirenderer;
28using namespace uirenderer::VectorDrawable;
29
30/**
31 * VectorDrawable's pre-draw construction.
32 */
33static jlong createTree(JNIEnv*, jobject, jlong groupPtr) {
34    VectorDrawable::Group* rootGroup = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
35    VectorDrawable::Tree* tree = new VectorDrawable::Tree(rootGroup);
36    return reinterpret_cast<jlong>(tree);
37}
38
39static jlong createTreeFromCopy(JNIEnv*, jobject, jlong treePtr, jlong groupPtr) {
40    VectorDrawable::Group* rootGroup = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
41    VectorDrawable::Tree* treeToCopy = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
42    VectorDrawable::Tree* tree = new VectorDrawable::Tree(treeToCopy, rootGroup);
43    return reinterpret_cast<jlong>(tree);
44}
45
46static jlong createEmptyFullPath(JNIEnv*, jobject) {
47    VectorDrawable::FullPath* newPath = new VectorDrawable::FullPath();
48    return reinterpret_cast<jlong>(newPath);
49}
50
51static jlong createFullPath(JNIEnv*, jobject, jlong srcFullPathPtr) {
52    VectorDrawable::FullPath* srcFullPath =
53            reinterpret_cast<VectorDrawable::FullPath*>(srcFullPathPtr);
54    VectorDrawable::FullPath* newPath = new VectorDrawable::FullPath(*srcFullPath);
55    return reinterpret_cast<jlong>(newPath);
56}
57
58static jlong createEmptyClipPath(JNIEnv*, jobject) {
59    VectorDrawable::ClipPath* newPath = new VectorDrawable::ClipPath();
60    return reinterpret_cast<jlong>(newPath);
61}
62
63static jlong createClipPath(JNIEnv*, jobject, jlong srcClipPathPtr) {
64    VectorDrawable::ClipPath* srcClipPath =
65            reinterpret_cast<VectorDrawable::ClipPath*>(srcClipPathPtr);
66    VectorDrawable::ClipPath* newPath = new VectorDrawable::ClipPath(*srcClipPath);
67    return reinterpret_cast<jlong>(newPath);
68}
69
70static jlong createEmptyGroup(JNIEnv*, jobject) {
71    VectorDrawable::Group* newGroup = new VectorDrawable::Group();
72    return reinterpret_cast<jlong>(newGroup);
73}
74
75static jlong createGroup(JNIEnv*, jobject, jlong srcGroupPtr) {
76    VectorDrawable::Group* srcGroup = reinterpret_cast<VectorDrawable::Group*>(srcGroupPtr);
77    VectorDrawable::Group* newGroup = new VectorDrawable::Group(*srcGroup);
78    return reinterpret_cast<jlong>(newGroup);
79}
80
81static void setNodeName(JNIEnv* env, jobject, jlong nodePtr, jstring nameStr) {
82    VectorDrawable::Node* node = reinterpret_cast<VectorDrawable::Node*>(nodePtr);
83    const char* nodeName = env->GetStringUTFChars(nameStr, NULL);
84    node->setName(nodeName);
85    env->ReleaseStringUTFChars(nameStr, nodeName);
86}
87
88static void addChild(JNIEnv*, jobject, jlong groupPtr, jlong childPtr) {
89    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
90    VectorDrawable::Node* child = reinterpret_cast<VectorDrawable::Node*>(childPtr);
91    group->addChild(child);
92}
93
94static void setAllowCaching(JNIEnv*, jobject, jlong treePtr, jboolean allowCaching) {
95    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
96    tree->setAllowCaching(allowCaching);
97}
98
99/**
100 * Draw
101 */
102static int draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr,
103        jlong colorFilterPtr, jobject jrect, jboolean needsMirroring, jboolean canReuseCache) {
104    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
105    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
106    SkRect rect;
107    GraphicsJNI::jrect_to_rect(env, jrect, &rect);
108    SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
109    return tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache);
110}
111
112/**
113 * Setters and getters for updating staging properties that can happen both pre-draw and post draw.
114 */
115static void setTreeViewportSize(JNIEnv*, jobject, jlong treePtr,
116        jfloat viewportWidth, jfloat viewportHeight) {
117    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
118    tree->mutateStagingProperties()->setViewportSize(viewportWidth, viewportHeight);
119}
120
121static jboolean setRootAlpha(JNIEnv*, jobject, jlong treePtr, jfloat alpha) {
122    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
123    return tree->mutateStagingProperties()->setRootAlpha(alpha);
124}
125
126static jfloat getRootAlpha(JNIEnv*, jobject, jlong treePtr) {
127    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
128    return tree->stagingProperties()->getRootAlpha();
129}
130
131static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong fullPathPtr,
132        jfloat strokeWidth, jint strokeColor, jfloat strokeAlpha, jint fillColor, jfloat fillAlpha,
133        jfloat trimPathStart, jfloat trimPathEnd, jfloat trimPathOffset, jfloat strokeMiterLimit,
134        jint strokeLineCap, jint strokeLineJoin, jint fillType) {
135    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
136    fullPath->mutateStagingProperties()->updateProperties(strokeWidth, strokeColor, strokeAlpha,
137            fillColor, fillAlpha, trimPathStart, trimPathEnd, trimPathOffset, strokeMiterLimit,
138            strokeLineCap, strokeLineJoin, fillType);
139}
140
141static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
142    VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
143    SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
144    path->mutateStagingProperties()->setFillGradient(fillShader);
145}
146
147static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
148    VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
149    SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
150    path->mutateStagingProperties()->setStrokeGradient(strokeShader);
151}
152
153static jboolean getFullPathProperties(JNIEnv* env, jobject, jlong fullPathPtr,
154        jbyteArray outProperties, jint length) {
155    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
156    int8_t pathProperties[length];
157    bool success = fullPath->stagingProperties()->copyProperties(pathProperties, length);
158    env->SetByteArrayRegion(outProperties, 0, length, reinterpret_cast<int8_t*>(&pathProperties));
159    return success;
160}
161
162static jboolean getGroupProperties(JNIEnv* env, jobject, jlong groupPtr,
163        jfloatArray outProperties, jint length) {
164    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
165    float groupProperties[length];
166    bool success = group->stagingProperties()->copyProperties(groupProperties, length);
167    env->SetFloatArrayRegion(outProperties, 0, length, reinterpret_cast<float*>(&groupProperties));
168    return success;
169}
170
171static void updateGroupProperties(JNIEnv*, jobject, jlong groupPtr, jfloat rotate, jfloat pivotX,
172        jfloat pivotY, jfloat scaleX, jfloat scaleY, jfloat translateX, jfloat translateY) {
173    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
174    group->mutateStagingProperties()->updateProperties(rotate, pivotX, pivotY, scaleX, scaleY,
175            translateX, translateY);
176}
177
178static void setPathString(JNIEnv* env, jobject, jlong pathPtr, jstring inputStr,
179        jint stringLength) {
180    VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
181    const char* pathString = env->GetStringUTFChars(inputStr, NULL);
182
183    PathParser::ParseResult result;
184    PathData data;
185    PathParser::getPathDataFromAsciiString(&data, &result, pathString, stringLength);
186    if (result.failureOccurred) {
187        doThrowIAE(env, result.failureMessage.c_str());
188    }
189    path->mutateStagingProperties()->setData(data);
190    env->ReleaseStringUTFChars(inputStr, pathString);
191}
192
193/**
194 * Setters and getters that should only be called from animation thread for animation purpose.
195 */
196static jfloat getRotation(JNIEnv*, jobject, jlong groupPtr) {
197    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
198    return group->stagingProperties()->getRotation();
199}
200
201static void setRotation(JNIEnv*, jobject, jlong groupPtr, jfloat rotation) {
202    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
203    group->mutateStagingProperties()->setRotation(rotation);
204}
205
206static jfloat getPivotX(JNIEnv*, jobject, jlong groupPtr) {
207    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
208    return group->stagingProperties()->getPivotX();
209}
210
211static void setPivotX(JNIEnv*, jobject, jlong groupPtr, jfloat pivotX) {
212    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
213    group->mutateStagingProperties()->setPivotX(pivotX);
214}
215
216static jfloat getPivotY(JNIEnv*, jobject, jlong groupPtr) {
217    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
218    return group->stagingProperties()->getPivotY();
219}
220
221static void setPivotY(JNIEnv*, jobject, jlong groupPtr, jfloat pivotY) {
222    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
223    group->mutateStagingProperties()->setPivotY(pivotY);
224}
225
226static jfloat getScaleX(JNIEnv*, jobject, jlong groupPtr) {
227    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
228    return group->stagingProperties()->getScaleX();
229}
230
231static void setScaleX(JNIEnv*, jobject, jlong groupPtr, jfloat scaleX) {
232    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
233    group->mutateStagingProperties()->setScaleX(scaleX);
234}
235
236static jfloat getScaleY(JNIEnv*, jobject, jlong groupPtr) {
237    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
238    return group->stagingProperties()->getScaleY();
239}
240
241static void setScaleY(JNIEnv*, jobject, jlong groupPtr, jfloat scaleY) {
242    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
243    group->mutateStagingProperties()->setScaleY(scaleY);
244}
245
246static jfloat getTranslateX(JNIEnv*, jobject, jlong groupPtr) {
247    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
248    return group->stagingProperties()->getTranslateX();
249}
250
251static void setTranslateX(JNIEnv*, jobject, jlong groupPtr, jfloat translateX) {
252    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
253    group->mutateStagingProperties()->setTranslateX(translateX);
254}
255
256static jfloat getTranslateY(JNIEnv*, jobject, jlong groupPtr) {
257    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
258    return group->stagingProperties()->getTranslateY();
259}
260
261static void setTranslateY(JNIEnv*, jobject, jlong groupPtr, jfloat translateY) {
262    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
263    group->mutateStagingProperties()->setTranslateY(translateY);
264}
265
266static void setPathData(JNIEnv*, jobject, jlong pathPtr, jlong pathDataPtr) {
267    VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
268    PathData* pathData = reinterpret_cast<PathData*>(pathDataPtr);
269    path->mutateStagingProperties()->setData(*pathData);
270}
271
272static jfloat getStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr) {
273    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
274    return fullPath->stagingProperties()->getStrokeWidth();
275}
276
277static void setStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeWidth) {
278    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
279    fullPath->mutateStagingProperties()->setStrokeWidth(strokeWidth);
280}
281
282static jint getStrokeColor(JNIEnv*, jobject, jlong fullPathPtr) {
283    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
284    return fullPath->stagingProperties()->getStrokeColor();
285}
286
287static void setStrokeColor(JNIEnv*, jobject, jlong fullPathPtr, jint strokeColor) {
288    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
289    fullPath->mutateStagingProperties()->setStrokeColor(strokeColor);
290}
291
292static jfloat getStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
293    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
294    return fullPath->stagingProperties()->getStrokeAlpha();
295}
296
297static void setStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeAlpha) {
298    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
299    fullPath->mutateStagingProperties()->setStrokeAlpha(strokeAlpha);
300}
301
302static jint getFillColor(JNIEnv*, jobject, jlong fullPathPtr) {
303    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
304    return fullPath->stagingProperties()->getFillColor();
305}
306
307static void setFillColor(JNIEnv*, jobject, jlong fullPathPtr, jint fillColor) {
308    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
309    fullPath->mutateStagingProperties()->setFillColor(fillColor);
310}
311
312static jfloat getFillAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
313    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
314    return fullPath->stagingProperties()->getFillAlpha();
315}
316
317static void setFillAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat fillAlpha) {
318    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
319    fullPath->mutateStagingProperties()->setFillAlpha(fillAlpha);
320}
321
322static jfloat getTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr) {
323    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
324    return fullPath->stagingProperties()->getTrimPathStart();
325}
326
327static void setTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathStart) {
328    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
329    fullPath->mutateStagingProperties()->setTrimPathStart(trimPathStart);
330}
331
332static jfloat getTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr) {
333    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
334    return fullPath->stagingProperties()->getTrimPathEnd();
335}
336
337static void setTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathEnd) {
338    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
339    fullPath->mutateStagingProperties()->setTrimPathEnd(trimPathEnd);
340}
341
342static jfloat getTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr) {
343    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
344    return fullPath->stagingProperties()->getTrimPathOffset();
345}
346
347static void setTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathOffset) {
348    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
349    fullPath->mutateStagingProperties()->setTrimPathOffset(trimPathOffset);
350}
351
352static const JNINativeMethod gMethods[] = {
353        {"nDraw", "(JJJLandroid/graphics/Rect;ZZ)I", (void*)draw},
354        {"nGetFullPathProperties", "(J[BI)Z", (void*)getFullPathProperties},
355        {"nGetGroupProperties", "(J[FI)Z", (void*)getGroupProperties},
356        {"nSetPathString", "(JLjava/lang/String;I)V", (void*)setPathString},
357        {"nSetName", "(JLjava/lang/String;)V", (void*)setNodeName},
358
359        // ------------- @FastNative ----------------
360
361        {"nCreateTree", "(J)J", (void*)createTree},
362        {"nCreateTreeFromCopy", "(JJ)J", (void*)createTreeFromCopy},
363        {"nSetRendererViewportSize", "(JFF)V", (void*)setTreeViewportSize},
364        {"nSetRootAlpha", "(JF)Z", (void*)setRootAlpha},
365        {"nGetRootAlpha", "(J)F", (void*)getRootAlpha},
366        {"nSetAllowCaching", "(JZ)V", (void*)setAllowCaching},
367
368        {"nCreateFullPath", "()J", (void*)createEmptyFullPath},
369        {"nCreateFullPath", "(J)J", (void*)createFullPath},
370        {"nUpdateFullPathProperties", "(JFIFIFFFFFIII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
371        {"nUpdateFullPathFillGradient", "(JJ)V", (void*)updateFullPathFillGradient},
372        {"nUpdateFullPathStrokeGradient", "(JJ)V", (void*)updateFullPathStrokeGradient},
373
374        {"nCreateClipPath", "()J", (void*)createEmptyClipPath},
375        {"nCreateClipPath", "(J)J", (void*)createClipPath},
376        {"nCreateGroup", "()J", (void*)createEmptyGroup},
377        {"nCreateGroup", "(J)J", (void*)createGroup},
378        {"nUpdateGroupProperties", "(JFFFFFFF)V", (void*)updateGroupProperties},
379
380        {"nAddChild", "(JJ)V", (void*)addChild},
381        {"nGetRotation", "(J)F", (void*)getRotation},
382        {"nSetRotation", "(JF)V", (void*)setRotation},
383        {"nGetPivotX", "(J)F", (void*)getPivotX},
384        {"nSetPivotX", "(JF)V", (void*)setPivotX},
385        {"nGetPivotY", "(J)F", (void*)getPivotY},
386        {"nSetPivotY", "(JF)V", (void*)setPivotY},
387        {"nGetScaleX", "(J)F", (void*)getScaleX},
388        {"nSetScaleX", "(JF)V", (void*)setScaleX},
389        {"nGetScaleY", "(J)F", (void*)getScaleY},
390        {"nSetScaleY", "(JF)V", (void*)setScaleY},
391        {"nGetTranslateX", "(J)F", (void*)getTranslateX},
392        {"nSetTranslateX", "(JF)V", (void*)setTranslateX},
393        {"nGetTranslateY", "(J)F", (void*)getTranslateY},
394        {"nSetTranslateY", "(JF)V", (void*)setTranslateY},
395
396        {"nSetPathData", "(JJ)V", (void*)setPathData},
397        {"nGetStrokeWidth", "(J)F", (void*)getStrokeWidth},
398        {"nSetStrokeWidth", "(JF)V", (void*)setStrokeWidth},
399        {"nGetStrokeColor", "(J)I", (void*)getStrokeColor},
400        {"nSetStrokeColor", "(JI)V", (void*)setStrokeColor},
401        {"nGetStrokeAlpha", "(J)F", (void*)getStrokeAlpha},
402        {"nSetStrokeAlpha", "(JF)V", (void*)setStrokeAlpha},
403        {"nGetFillColor", "(J)I", (void*)getFillColor},
404        {"nSetFillColor", "(JI)V", (void*)setFillColor},
405        {"nGetFillAlpha", "(J)F", (void*)getFillAlpha},
406        {"nSetFillAlpha", "(JF)V", (void*)setFillAlpha},
407        {"nGetTrimPathStart", "(J)F", (void*)getTrimPathStart},
408        {"nSetTrimPathStart", "(JF)V", (void*)setTrimPathStart},
409        {"nGetTrimPathEnd", "(J)F", (void*)getTrimPathEnd},
410        {"nSetTrimPathEnd", "(JF)V", (void*)setTrimPathEnd},
411        {"nGetTrimPathOffset", "(J)F", (void*)getTrimPathOffset},
412        {"nSetTrimPathOffset", "(JF)V", (void*)setTrimPathOffset},
413};
414
415int register_android_graphics_drawable_VectorDrawable(JNIEnv* env) {
416    return RegisterMethodsOrDie(env, "android/graphics/drawable/VectorDrawable", gMethods, NELEM(gMethods));
417}
418
419}; // namespace android
420