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
99static void setAntiAlias(JNIEnv*, jobject, jlong treePtr, jboolean aa) {
100    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
101    tree->setAntiAlias(aa);
102}
103
104/**
105 * Draw
106 */
107static int draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr,
108        jlong colorFilterPtr, jobject jrect, jboolean needsMirroring, jboolean canReuseCache) {
109    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
110    Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
111    SkRect rect;
112    GraphicsJNI::jrect_to_rect(env, jrect, &rect);
113    SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
114    return tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache);
115}
116
117/**
118 * Setters and getters for updating staging properties that can happen both pre-draw and post draw.
119 */
120static void setTreeViewportSize(JNIEnv*, jobject, jlong treePtr,
121        jfloat viewportWidth, jfloat viewportHeight) {
122    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
123    tree->mutateStagingProperties()->setViewportSize(viewportWidth, viewportHeight);
124}
125
126static jboolean setRootAlpha(JNIEnv*, jobject, jlong treePtr, jfloat alpha) {
127    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
128    return tree->mutateStagingProperties()->setRootAlpha(alpha);
129}
130
131static jfloat getRootAlpha(JNIEnv*, jobject, jlong treePtr) {
132    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
133    return tree->stagingProperties()->getRootAlpha();
134}
135
136static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong fullPathPtr,
137        jfloat strokeWidth, jint strokeColor, jfloat strokeAlpha, jint fillColor, jfloat fillAlpha,
138        jfloat trimPathStart, jfloat trimPathEnd, jfloat trimPathOffset, jfloat strokeMiterLimit,
139        jint strokeLineCap, jint strokeLineJoin, jint fillType) {
140    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
141    fullPath->mutateStagingProperties()->updateProperties(strokeWidth, strokeColor, strokeAlpha,
142            fillColor, fillAlpha, trimPathStart, trimPathEnd, trimPathOffset, strokeMiterLimit,
143            strokeLineCap, strokeLineJoin, fillType);
144}
145
146static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
147    VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
148    SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
149    path->mutateStagingProperties()->setFillGradient(fillShader);
150}
151
152static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
153    VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
154    SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
155    path->mutateStagingProperties()->setStrokeGradient(strokeShader);
156}
157
158static jboolean getFullPathProperties(JNIEnv* env, jobject, jlong fullPathPtr,
159        jbyteArray outProperties, jint length) {
160    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
161    int8_t pathProperties[length];
162    bool success = fullPath->stagingProperties()->copyProperties(pathProperties, length);
163    env->SetByteArrayRegion(outProperties, 0, length, reinterpret_cast<int8_t*>(&pathProperties));
164    return success;
165}
166
167static jboolean getGroupProperties(JNIEnv* env, jobject, jlong groupPtr,
168        jfloatArray outProperties, jint length) {
169    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
170    float groupProperties[length];
171    bool success = group->stagingProperties()->copyProperties(groupProperties, length);
172    env->SetFloatArrayRegion(outProperties, 0, length, reinterpret_cast<float*>(&groupProperties));
173    return success;
174}
175
176static void updateGroupProperties(JNIEnv*, jobject, jlong groupPtr, jfloat rotate, jfloat pivotX,
177        jfloat pivotY, jfloat scaleX, jfloat scaleY, jfloat translateX, jfloat translateY) {
178    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
179    group->mutateStagingProperties()->updateProperties(rotate, pivotX, pivotY, scaleX, scaleY,
180            translateX, translateY);
181}
182
183static void setPathString(JNIEnv* env, jobject, jlong pathPtr, jstring inputStr,
184        jint stringLength) {
185    VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
186    const char* pathString = env->GetStringUTFChars(inputStr, NULL);
187
188    PathParser::ParseResult result;
189    PathData data;
190    PathParser::getPathDataFromAsciiString(&data, &result, pathString, stringLength);
191    if (result.failureOccurred) {
192        doThrowIAE(env, result.failureMessage.c_str());
193    }
194    path->mutateStagingProperties()->setData(data);
195    env->ReleaseStringUTFChars(inputStr, pathString);
196}
197
198/**
199 * Setters and getters that should only be called from animation thread for animation purpose.
200 */
201static jfloat getRotation(JNIEnv*, jobject, jlong groupPtr) {
202    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
203    return group->stagingProperties()->getRotation();
204}
205
206static void setRotation(JNIEnv*, jobject, jlong groupPtr, jfloat rotation) {
207    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
208    group->mutateStagingProperties()->setRotation(rotation);
209}
210
211static jfloat getPivotX(JNIEnv*, jobject, jlong groupPtr) {
212    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
213    return group->stagingProperties()->getPivotX();
214}
215
216static void setPivotX(JNIEnv*, jobject, jlong groupPtr, jfloat pivotX) {
217    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
218    group->mutateStagingProperties()->setPivotX(pivotX);
219}
220
221static jfloat getPivotY(JNIEnv*, jobject, jlong groupPtr) {
222    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
223    return group->stagingProperties()->getPivotY();
224}
225
226static void setPivotY(JNIEnv*, jobject, jlong groupPtr, jfloat pivotY) {
227    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
228    group->mutateStagingProperties()->setPivotY(pivotY);
229}
230
231static jfloat getScaleX(JNIEnv*, jobject, jlong groupPtr) {
232    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
233    return group->stagingProperties()->getScaleX();
234}
235
236static void setScaleX(JNIEnv*, jobject, jlong groupPtr, jfloat scaleX) {
237    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
238    group->mutateStagingProperties()->setScaleX(scaleX);
239}
240
241static jfloat getScaleY(JNIEnv*, jobject, jlong groupPtr) {
242    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
243    return group->stagingProperties()->getScaleY();
244}
245
246static void setScaleY(JNIEnv*, jobject, jlong groupPtr, jfloat scaleY) {
247    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
248    group->mutateStagingProperties()->setScaleY(scaleY);
249}
250
251static jfloat getTranslateX(JNIEnv*, jobject, jlong groupPtr) {
252    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
253    return group->stagingProperties()->getTranslateX();
254}
255
256static void setTranslateX(JNIEnv*, jobject, jlong groupPtr, jfloat translateX) {
257    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
258    group->mutateStagingProperties()->setTranslateX(translateX);
259}
260
261static jfloat getTranslateY(JNIEnv*, jobject, jlong groupPtr) {
262    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
263    return group->stagingProperties()->getTranslateY();
264}
265
266static void setTranslateY(JNIEnv*, jobject, jlong groupPtr, jfloat translateY) {
267    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
268    group->mutateStagingProperties()->setTranslateY(translateY);
269}
270
271static void setPathData(JNIEnv*, jobject, jlong pathPtr, jlong pathDataPtr) {
272    VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
273    PathData* pathData = reinterpret_cast<PathData*>(pathDataPtr);
274    path->mutateStagingProperties()->setData(*pathData);
275}
276
277static jfloat getStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr) {
278    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
279    return fullPath->stagingProperties()->getStrokeWidth();
280}
281
282static void setStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeWidth) {
283    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
284    fullPath->mutateStagingProperties()->setStrokeWidth(strokeWidth);
285}
286
287static jint getStrokeColor(JNIEnv*, jobject, jlong fullPathPtr) {
288    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
289    return fullPath->stagingProperties()->getStrokeColor();
290}
291
292static void setStrokeColor(JNIEnv*, jobject, jlong fullPathPtr, jint strokeColor) {
293    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
294    fullPath->mutateStagingProperties()->setStrokeColor(strokeColor);
295}
296
297static jfloat getStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
298    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
299    return fullPath->stagingProperties()->getStrokeAlpha();
300}
301
302static void setStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeAlpha) {
303    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
304    fullPath->mutateStagingProperties()->setStrokeAlpha(strokeAlpha);
305}
306
307static jint getFillColor(JNIEnv*, jobject, jlong fullPathPtr) {
308    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
309    return fullPath->stagingProperties()->getFillColor();
310}
311
312static void setFillColor(JNIEnv*, jobject, jlong fullPathPtr, jint fillColor) {
313    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
314    fullPath->mutateStagingProperties()->setFillColor(fillColor);
315}
316
317static jfloat getFillAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
318    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
319    return fullPath->stagingProperties()->getFillAlpha();
320}
321
322static void setFillAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat fillAlpha) {
323    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
324    fullPath->mutateStagingProperties()->setFillAlpha(fillAlpha);
325}
326
327static jfloat getTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr) {
328    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
329    return fullPath->stagingProperties()->getTrimPathStart();
330}
331
332static void setTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathStart) {
333    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
334    fullPath->mutateStagingProperties()->setTrimPathStart(trimPathStart);
335}
336
337static jfloat getTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr) {
338    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
339    return fullPath->stagingProperties()->getTrimPathEnd();
340}
341
342static void setTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathEnd) {
343    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
344    fullPath->mutateStagingProperties()->setTrimPathEnd(trimPathEnd);
345}
346
347static jfloat getTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr) {
348    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
349    return fullPath->stagingProperties()->getTrimPathOffset();
350}
351
352static void setTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathOffset) {
353    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
354    fullPath->mutateStagingProperties()->setTrimPathOffset(trimPathOffset);
355}
356
357static const JNINativeMethod gMethods[] = {
358        {"nDraw", "(JJJLandroid/graphics/Rect;ZZ)I", (void*)draw},
359        {"nGetFullPathProperties", "(J[BI)Z", (void*)getFullPathProperties},
360        {"nGetGroupProperties", "(J[FI)Z", (void*)getGroupProperties},
361        {"nSetPathString", "(JLjava/lang/String;I)V", (void*)setPathString},
362        {"nSetName", "(JLjava/lang/String;)V", (void*)setNodeName},
363
364        // ------------- @FastNative ----------------
365
366        {"nCreateTree", "(J)J", (void*)createTree},
367        {"nCreateTreeFromCopy", "(JJ)J", (void*)createTreeFromCopy},
368        {"nSetRendererViewportSize", "(JFF)V", (void*)setTreeViewportSize},
369        {"nSetRootAlpha", "(JF)Z", (void*)setRootAlpha},
370        {"nGetRootAlpha", "(J)F", (void*)getRootAlpha},
371        {"nSetAntiAlias", "(JZ)V", (void*)setAntiAlias},
372        {"nSetAllowCaching", "(JZ)V", (void*)setAllowCaching},
373
374        {"nCreateFullPath", "()J", (void*)createEmptyFullPath},
375        {"nCreateFullPath", "(J)J", (void*)createFullPath},
376        {"nUpdateFullPathProperties", "(JFIFIFFFFFIII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
377        {"nUpdateFullPathFillGradient", "(JJ)V", (void*)updateFullPathFillGradient},
378        {"nUpdateFullPathStrokeGradient", "(JJ)V", (void*)updateFullPathStrokeGradient},
379
380        {"nCreateClipPath", "()J", (void*)createEmptyClipPath},
381        {"nCreateClipPath", "(J)J", (void*)createClipPath},
382        {"nCreateGroup", "()J", (void*)createEmptyGroup},
383        {"nCreateGroup", "(J)J", (void*)createGroup},
384        {"nUpdateGroupProperties", "(JFFFFFFF)V", (void*)updateGroupProperties},
385
386        {"nAddChild", "(JJ)V", (void*)addChild},
387        {"nGetRotation", "(J)F", (void*)getRotation},
388        {"nSetRotation", "(JF)V", (void*)setRotation},
389        {"nGetPivotX", "(J)F", (void*)getPivotX},
390        {"nSetPivotX", "(JF)V", (void*)setPivotX},
391        {"nGetPivotY", "(J)F", (void*)getPivotY},
392        {"nSetPivotY", "(JF)V", (void*)setPivotY},
393        {"nGetScaleX", "(J)F", (void*)getScaleX},
394        {"nSetScaleX", "(JF)V", (void*)setScaleX},
395        {"nGetScaleY", "(J)F", (void*)getScaleY},
396        {"nSetScaleY", "(JF)V", (void*)setScaleY},
397        {"nGetTranslateX", "(J)F", (void*)getTranslateX},
398        {"nSetTranslateX", "(JF)V", (void*)setTranslateX},
399        {"nGetTranslateY", "(J)F", (void*)getTranslateY},
400        {"nSetTranslateY", "(JF)V", (void*)setTranslateY},
401
402        {"nSetPathData", "(JJ)V", (void*)setPathData},
403        {"nGetStrokeWidth", "(J)F", (void*)getStrokeWidth},
404        {"nSetStrokeWidth", "(JF)V", (void*)setStrokeWidth},
405        {"nGetStrokeColor", "(J)I", (void*)getStrokeColor},
406        {"nSetStrokeColor", "(JI)V", (void*)setStrokeColor},
407        {"nGetStrokeAlpha", "(J)F", (void*)getStrokeAlpha},
408        {"nSetStrokeAlpha", "(JF)V", (void*)setStrokeAlpha},
409        {"nGetFillColor", "(J)I", (void*)getFillColor},
410        {"nSetFillColor", "(JI)V", (void*)setFillColor},
411        {"nGetFillAlpha", "(J)F", (void*)getFillAlpha},
412        {"nSetFillAlpha", "(JF)V", (void*)setFillAlpha},
413        {"nGetTrimPathStart", "(J)F", (void*)getTrimPathStart},
414        {"nSetTrimPathStart", "(JF)V", (void*)setTrimPathStart},
415        {"nGetTrimPathEnd", "(J)F", (void*)getTrimPathEnd},
416        {"nSetTrimPathEnd", "(JF)V", (void*)setTrimPathEnd},
417        {"nGetTrimPathOffset", "(J)F", (void*)getTrimPathOffset},
418        {"nSetTrimPathOffset", "(JF)V", (void*)setTrimPathOffset},
419};
420
421int register_android_graphics_drawable_VectorDrawable(JNIEnv* env) {
422    return RegisterMethodsOrDie(env, "android/graphics/drawable/VectorDrawable", gMethods, NELEM(gMethods));
423}
424
425}; // namespace android
426