1 /*
2  * Copyright (C) 2012 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 #define LOG_TAG "OpenGLRenderer"
18 #define ATRACE_TAG ATRACE_TAG_VIEW
19 
20 #include <EGL/egl.h>
21 
22 #include "jni.h"
23 #include "GraphicsJNI.h"
24 #include <nativehelper/JNIHelp.h>
25 #include <android_runtime/AndroidRuntime.h>
26 
27 #include <Animator.h>
28 #include <DamageAccumulator.h>
29 #include <Matrix.h>
30 #include <RenderNode.h>
31 #include <renderthread/CanvasContext.h>
32 #include <TreeInfo.h>
33 #include <hwui/Paint.h>
34 
35 #include "core_jni_helpers.h"
36 
37 namespace android {
38 
39 using namespace uirenderer;
40 
41 #define SET_AND_DIRTY(prop, val, dirtyFlag) \
42     (reinterpret_cast<RenderNode*>(renderNodePtr)->mutateStagingProperties().prop(val) \
43         ? (reinterpret_cast<RenderNode*>(renderNodePtr)->setPropertyFieldsDirty(dirtyFlag), true) \
44         : false)
45 
46 // ----------------------------------------------------------------------------
47 // DisplayList view properties
48 // ----------------------------------------------------------------------------
49 
android_view_RenderNode_output(JNIEnv * env,jobject clazz,jlong renderNodePtr)50 static void android_view_RenderNode_output(JNIEnv* env, jobject clazz, jlong renderNodePtr) {
51     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
52     renderNode->output();
53 }
54 
android_view_RenderNode_getDebugSize(JNIEnv * env,jobject clazz,jlong renderNodePtr)55 static jint android_view_RenderNode_getDebugSize(JNIEnv* env, jobject clazz, jlong renderNodePtr) {
56     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
57     return renderNode->getDebugSize();
58 }
59 
android_view_RenderNode_create(JNIEnv * env,jobject,jstring name)60 static jlong android_view_RenderNode_create(JNIEnv* env, jobject, jstring name) {
61     RenderNode* renderNode = new RenderNode();
62     renderNode->incStrong(0);
63     if (name != NULL) {
64         const char* textArray = env->GetStringUTFChars(name, NULL);
65         renderNode->setName(textArray);
66         env->ReleaseStringUTFChars(name, textArray);
67     }
68     return reinterpret_cast<jlong>(renderNode);
69 }
70 
releaseRenderNode(RenderNode * renderNode)71 static void releaseRenderNode(RenderNode* renderNode) {
72     renderNode->decStrong(0);
73 }
74 
android_view_RenderNode_getNativeFinalizer(JNIEnv * env,jobject clazz)75 static jlong android_view_RenderNode_getNativeFinalizer(JNIEnv* env,
76         jobject clazz) {
77     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&releaseRenderNode));
78 }
79 
android_view_RenderNode_setDisplayList(JNIEnv * env,jobject clazz,jlong renderNodePtr,jlong displayListPtr)80 static void android_view_RenderNode_setDisplayList(JNIEnv* env,
81         jobject clazz, jlong renderNodePtr, jlong displayListPtr) {
82     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
83     DisplayList* newData = reinterpret_cast<DisplayList*>(displayListPtr);
84     renderNode->setStagingDisplayList(newData);
85 }
86 
android_view_RenderNode_isValid(jlong renderNodePtr)87 static jboolean android_view_RenderNode_isValid(jlong renderNodePtr) {
88     return reinterpret_cast<RenderNode*>(renderNodePtr)->isValid();
89 }
90 
91 // ----------------------------------------------------------------------------
92 // RenderProperties - setters
93 // ----------------------------------------------------------------------------
94 
android_view_RenderNode_setLayerType(jlong renderNodePtr,jint jlayerType)95 static jboolean android_view_RenderNode_setLayerType(jlong renderNodePtr, jint jlayerType) {
96     LayerType layerType = static_cast<LayerType>(jlayerType);
97     return SET_AND_DIRTY(mutateLayerProperties().setType, layerType, RenderNode::GENERIC);
98 }
99 
android_view_RenderNode_setLayerPaint(jlong renderNodePtr,jlong paintPtr)100 static jboolean android_view_RenderNode_setLayerPaint(jlong renderNodePtr, jlong paintPtr) {
101     Paint* paint = reinterpret_cast<Paint*>(paintPtr);
102     return SET_AND_DIRTY(mutateLayerProperties().setFromPaint, paint, RenderNode::GENERIC);
103 }
104 
android_view_RenderNode_setStaticMatrix(jlong renderNodePtr,jlong matrixPtr)105 static jboolean android_view_RenderNode_setStaticMatrix(jlong renderNodePtr, jlong matrixPtr) {
106     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
107     return SET_AND_DIRTY(setStaticMatrix, matrix, RenderNode::GENERIC);
108 }
109 
android_view_RenderNode_setAnimationMatrix(jlong renderNodePtr,jlong matrixPtr)110 static jboolean android_view_RenderNode_setAnimationMatrix(jlong renderNodePtr, jlong matrixPtr) {
111     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
112     return SET_AND_DIRTY(setAnimationMatrix, matrix, RenderNode::GENERIC);
113 }
114 
android_view_RenderNode_setClipToBounds(jlong renderNodePtr,jboolean clipToBounds)115 static jboolean android_view_RenderNode_setClipToBounds(jlong renderNodePtr,
116         jboolean clipToBounds) {
117     return SET_AND_DIRTY(setClipToBounds, clipToBounds, RenderNode::GENERIC);
118 }
119 
android_view_RenderNode_setClipBounds(jlong renderNodePtr,jint left,jint top,jint right,jint bottom)120 static jboolean android_view_RenderNode_setClipBounds(jlong renderNodePtr,
121         jint left, jint top, jint right, jint bottom) {
122     android::uirenderer::Rect clipBounds(left, top, right, bottom);
123     return SET_AND_DIRTY(setClipBounds, clipBounds, RenderNode::GENERIC);
124 }
125 
android_view_RenderNode_setClipBoundsEmpty(jlong renderNodePtr)126 static jboolean android_view_RenderNode_setClipBoundsEmpty(jlong renderNodePtr) {
127     return SET_AND_DIRTY(setClipBoundsEmpty,, RenderNode::GENERIC);
128 }
129 
android_view_RenderNode_setProjectBackwards(jlong renderNodePtr,jboolean shouldProject)130 static jboolean android_view_RenderNode_setProjectBackwards(jlong renderNodePtr,
131         jboolean shouldProject) {
132     return SET_AND_DIRTY(setProjectBackwards, shouldProject, RenderNode::GENERIC);
133 }
134 
android_view_RenderNode_setProjectionReceiver(jlong renderNodePtr,jboolean shouldRecieve)135 static jboolean android_view_RenderNode_setProjectionReceiver(jlong renderNodePtr,
136         jboolean shouldRecieve) {
137     return SET_AND_DIRTY(setProjectionReceiver, shouldRecieve, RenderNode::GENERIC);
138 }
139 
android_view_RenderNode_setOutlineRoundRect(jlong renderNodePtr,jint left,jint top,jint right,jint bottom,jfloat radius,jfloat alpha)140 static jboolean android_view_RenderNode_setOutlineRoundRect(jlong renderNodePtr,
141         jint left, jint top, jint right, jint bottom, jfloat radius, jfloat alpha) {
142     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
143     renderNode->mutateStagingProperties().mutableOutline().setRoundRect(left, top, right, bottom,
144             radius, alpha);
145     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
146     return true;
147 }
148 
android_view_RenderNode_setOutlineConvexPath(jlong renderNodePtr,jlong outlinePathPtr,jfloat alpha)149 static jboolean android_view_RenderNode_setOutlineConvexPath(jlong renderNodePtr,
150         jlong outlinePathPtr, jfloat alpha) {
151     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
152     SkPath* outlinePath = reinterpret_cast<SkPath*>(outlinePathPtr);
153     renderNode->mutateStagingProperties().mutableOutline().setConvexPath(outlinePath, alpha);
154     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
155     return true;
156 }
157 
android_view_RenderNode_setOutlineEmpty(jlong renderNodePtr)158 static jboolean android_view_RenderNode_setOutlineEmpty(jlong renderNodePtr) {
159     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
160     renderNode->mutateStagingProperties().mutableOutline().setEmpty();
161     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
162     return true;
163 }
164 
android_view_RenderNode_setOutlineNone(jlong renderNodePtr)165 static jboolean android_view_RenderNode_setOutlineNone(jlong renderNodePtr) {
166     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
167     renderNode->mutateStagingProperties().mutableOutline().setNone();
168     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
169     return true;
170 }
171 
android_view_RenderNode_hasShadow(jlong renderNodePtr)172 static jboolean android_view_RenderNode_hasShadow(jlong renderNodePtr) {
173     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
174     return renderNode->stagingProperties().hasShadow();
175 }
176 
android_view_RenderNode_setClipToOutline(jlong renderNodePtr,jboolean clipToOutline)177 static jboolean android_view_RenderNode_setClipToOutline(jlong renderNodePtr,
178         jboolean clipToOutline) {
179     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
180     renderNode->mutateStagingProperties().mutableOutline().setShouldClip(clipToOutline);
181     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
182     return true;
183 }
184 
android_view_RenderNode_setRevealClip(jlong renderNodePtr,jboolean shouldClip,jfloat x,jfloat y,jfloat radius)185 static jboolean android_view_RenderNode_setRevealClip(jlong renderNodePtr, jboolean shouldClip,
186         jfloat x, jfloat y, jfloat radius) {
187     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
188     renderNode->mutateStagingProperties().mutableRevealClip().set(
189             shouldClip, x, y, radius);
190     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
191     return true;
192 }
193 
android_view_RenderNode_setAlpha(jlong renderNodePtr,float alpha)194 static jboolean android_view_RenderNode_setAlpha(jlong renderNodePtr, float alpha) {
195     return SET_AND_DIRTY(setAlpha, alpha, RenderNode::ALPHA);
196 }
197 
android_view_RenderNode_setHasOverlappingRendering(jlong renderNodePtr,bool hasOverlappingRendering)198 static jboolean android_view_RenderNode_setHasOverlappingRendering(jlong renderNodePtr,
199         bool hasOverlappingRendering) {
200     return SET_AND_DIRTY(setHasOverlappingRendering, hasOverlappingRendering,
201             RenderNode::GENERIC);
202 }
203 
android_view_RenderNode_setElevation(jlong renderNodePtr,float elevation)204 static jboolean android_view_RenderNode_setElevation(jlong renderNodePtr, float elevation) {
205     return SET_AND_DIRTY(setElevation, elevation, RenderNode::Z);
206 }
207 
android_view_RenderNode_setTranslationX(jlong renderNodePtr,float tx)208 static jboolean android_view_RenderNode_setTranslationX(jlong renderNodePtr, float tx) {
209     return SET_AND_DIRTY(setTranslationX, tx, RenderNode::TRANSLATION_X | RenderNode::X);
210 }
211 
android_view_RenderNode_setTranslationY(jlong renderNodePtr,float ty)212 static jboolean android_view_RenderNode_setTranslationY(jlong renderNodePtr, float ty) {
213     return SET_AND_DIRTY(setTranslationY, ty, RenderNode::TRANSLATION_Y | RenderNode::Y);
214 }
215 
android_view_RenderNode_setTranslationZ(jlong renderNodePtr,float tz)216 static jboolean android_view_RenderNode_setTranslationZ(jlong renderNodePtr, float tz) {
217     return SET_AND_DIRTY(setTranslationZ, tz, RenderNode::TRANSLATION_Z | RenderNode::Z);
218 }
219 
android_view_RenderNode_setRotation(jlong renderNodePtr,float rotation)220 static jboolean android_view_RenderNode_setRotation(jlong renderNodePtr, float rotation) {
221     return SET_AND_DIRTY(setRotation, rotation, RenderNode::ROTATION);
222 }
223 
android_view_RenderNode_setRotationX(jlong renderNodePtr,float rx)224 static jboolean android_view_RenderNode_setRotationX(jlong renderNodePtr, float rx) {
225     return SET_AND_DIRTY(setRotationX, rx, RenderNode::ROTATION_X);
226 }
227 
android_view_RenderNode_setRotationY(jlong renderNodePtr,float ry)228 static jboolean android_view_RenderNode_setRotationY(jlong renderNodePtr, float ry) {
229     return SET_AND_DIRTY(setRotationY, ry, RenderNode::ROTATION_Y);
230 }
231 
android_view_RenderNode_setScaleX(jlong renderNodePtr,float sx)232 static jboolean android_view_RenderNode_setScaleX(jlong renderNodePtr, float sx) {
233     return SET_AND_DIRTY(setScaleX, sx, RenderNode::SCALE_X);
234 }
235 
android_view_RenderNode_setScaleY(jlong renderNodePtr,float sy)236 static jboolean android_view_RenderNode_setScaleY(jlong renderNodePtr, float sy) {
237     return SET_AND_DIRTY(setScaleY, sy, RenderNode::SCALE_Y);
238 }
239 
android_view_RenderNode_setPivotX(jlong renderNodePtr,float px)240 static jboolean android_view_RenderNode_setPivotX(jlong renderNodePtr, float px) {
241     return SET_AND_DIRTY(setPivotX, px, RenderNode::GENERIC);
242 }
243 
android_view_RenderNode_setPivotY(jlong renderNodePtr,float py)244 static jboolean android_view_RenderNode_setPivotY(jlong renderNodePtr, float py) {
245     return SET_AND_DIRTY(setPivotY, py, RenderNode::GENERIC);
246 }
247 
android_view_RenderNode_setCameraDistance(jlong renderNodePtr,float distance)248 static jboolean android_view_RenderNode_setCameraDistance(jlong renderNodePtr, float distance) {
249     return SET_AND_DIRTY(setCameraDistance, distance, RenderNode::GENERIC);
250 }
251 
android_view_RenderNode_setLeft(jlong renderNodePtr,int left)252 static jboolean android_view_RenderNode_setLeft(jlong renderNodePtr, int left) {
253     return SET_AND_DIRTY(setLeft, left, RenderNode::X);
254 }
255 
android_view_RenderNode_setTop(jlong renderNodePtr,int top)256 static jboolean android_view_RenderNode_setTop(jlong renderNodePtr, int top) {
257     return SET_AND_DIRTY(setTop, top, RenderNode::Y);
258 }
259 
android_view_RenderNode_setRight(jlong renderNodePtr,int right)260 static jboolean android_view_RenderNode_setRight(jlong renderNodePtr, int right) {
261     return SET_AND_DIRTY(setRight, right, RenderNode::X);
262 }
263 
android_view_RenderNode_setBottom(jlong renderNodePtr,int bottom)264 static jboolean android_view_RenderNode_setBottom(jlong renderNodePtr, int bottom) {
265     return SET_AND_DIRTY(setBottom, bottom, RenderNode::Y);
266 }
267 
android_view_RenderNode_setLeftTopRightBottom(jlong renderNodePtr,int left,int top,int right,int bottom)268 static jboolean android_view_RenderNode_setLeftTopRightBottom(jlong renderNodePtr,
269         int left, int top, int right, int bottom) {
270     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
271     if (renderNode->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom)) {
272         renderNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
273         return true;
274     }
275     return false;
276 }
277 
android_view_RenderNode_offsetLeftAndRight(jlong renderNodePtr,jint offset)278 static jboolean android_view_RenderNode_offsetLeftAndRight(jlong renderNodePtr, jint offset) {
279     return SET_AND_DIRTY(offsetLeftRight, offset, RenderNode::X);
280 }
281 
android_view_RenderNode_offsetTopAndBottom(jlong renderNodePtr,jint offset)282 static jboolean android_view_RenderNode_offsetTopAndBottom(jlong renderNodePtr, jint offset) {
283     return SET_AND_DIRTY(offsetTopBottom, offset, RenderNode::Y);
284 }
285 
286 // ----------------------------------------------------------------------------
287 // RenderProperties - getters
288 // ----------------------------------------------------------------------------
289 
android_view_RenderNode_hasOverlappingRendering(jlong renderNodePtr)290 static jboolean android_view_RenderNode_hasOverlappingRendering(jlong renderNodePtr) {
291     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
292     return renderNode->stagingProperties().hasOverlappingRendering();
293 }
294 
android_view_RenderNode_getClipToOutline(jlong renderNodePtr)295 static jboolean android_view_RenderNode_getClipToOutline(jlong renderNodePtr) {
296     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
297     return renderNode->stagingProperties().getOutline().getShouldClip();
298 }
299 
android_view_RenderNode_getAlpha(jlong renderNodePtr)300 static jfloat android_view_RenderNode_getAlpha(jlong renderNodePtr) {
301     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
302     return renderNode->stagingProperties().getAlpha();
303 }
304 
android_view_RenderNode_getCameraDistance(jlong renderNodePtr)305 static jfloat android_view_RenderNode_getCameraDistance(jlong renderNodePtr) {
306     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
307     return renderNode->stagingProperties().getCameraDistance();
308 }
309 
android_view_RenderNode_getScaleX(jlong renderNodePtr)310 static jfloat android_view_RenderNode_getScaleX(jlong renderNodePtr) {
311     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
312     return renderNode->stagingProperties().getScaleX();
313 }
314 
android_view_RenderNode_getScaleY(jlong renderNodePtr)315 static jfloat android_view_RenderNode_getScaleY(jlong renderNodePtr) {
316     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
317     return renderNode->stagingProperties().getScaleY();
318 }
319 
android_view_RenderNode_getElevation(jlong renderNodePtr)320 static jfloat android_view_RenderNode_getElevation(jlong renderNodePtr) {
321     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
322     return renderNode->stagingProperties().getElevation();
323 }
324 
android_view_RenderNode_getTranslationX(jlong renderNodePtr)325 static jfloat android_view_RenderNode_getTranslationX(jlong renderNodePtr) {
326     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
327     return renderNode->stagingProperties().getTranslationX();
328 }
329 
android_view_RenderNode_getTranslationY(jlong renderNodePtr)330 static jfloat android_view_RenderNode_getTranslationY(jlong renderNodePtr) {
331     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
332     return renderNode->stagingProperties().getTranslationY();
333 }
334 
android_view_RenderNode_getTranslationZ(jlong renderNodePtr)335 static jfloat android_view_RenderNode_getTranslationZ(jlong renderNodePtr) {
336     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
337     return renderNode->stagingProperties().getTranslationZ();
338 }
339 
android_view_RenderNode_getRotation(jlong renderNodePtr)340 static jfloat android_view_RenderNode_getRotation(jlong renderNodePtr) {
341     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
342     return renderNode->stagingProperties().getRotation();
343 }
344 
android_view_RenderNode_getRotationX(jlong renderNodePtr)345 static jfloat android_view_RenderNode_getRotationX(jlong renderNodePtr) {
346     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
347     return renderNode->stagingProperties().getRotationX();
348 }
349 
android_view_RenderNode_getRotationY(jlong renderNodePtr)350 static jfloat android_view_RenderNode_getRotationY(jlong renderNodePtr) {
351     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
352     return renderNode->stagingProperties().getRotationY();
353 }
354 
android_view_RenderNode_isPivotExplicitlySet(jlong renderNodePtr)355 static jboolean android_view_RenderNode_isPivotExplicitlySet(jlong renderNodePtr) {
356     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
357     return renderNode->stagingProperties().isPivotExplicitlySet();
358 }
359 
android_view_RenderNode_hasIdentityMatrix(jlong renderNodePtr)360 static jboolean android_view_RenderNode_hasIdentityMatrix(jlong renderNodePtr) {
361     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
362     renderNode->mutateStagingProperties().updateMatrix();
363     return !renderNode->stagingProperties().hasTransformMatrix();
364 }
365 
366 // ----------------------------------------------------------------------------
367 // RenderProperties - computed getters
368 // ----------------------------------------------------------------------------
369 
android_view_RenderNode_getTransformMatrix(jlong renderNodePtr,jlong outMatrixPtr)370 static void android_view_RenderNode_getTransformMatrix(jlong renderNodePtr, jlong outMatrixPtr) {
371     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
372     SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr);
373 
374     renderNode->mutateStagingProperties().updateMatrix();
375     const SkMatrix* transformMatrix = renderNode->stagingProperties().getTransformMatrix();
376 
377     if (transformMatrix) {
378         *outMatrix = *transformMatrix;
379     } else {
380         outMatrix->setIdentity();
381     }
382 }
383 
android_view_RenderNode_getInverseTransformMatrix(jlong renderNodePtr,jlong outMatrixPtr)384 static void android_view_RenderNode_getInverseTransformMatrix(jlong renderNodePtr,
385         jlong outMatrixPtr) {
386     // load transform matrix
387     android_view_RenderNode_getTransformMatrix(renderNodePtr, outMatrixPtr);
388     SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr);
389 
390     // return it inverted
391     if (!outMatrix->invert(outMatrix)) {
392         // failed to load inverse, pass back identity
393         outMatrix->setIdentity();
394     }
395 }
396 
android_view_RenderNode_getPivotX(jlong renderNodePtr)397 static jfloat android_view_RenderNode_getPivotX(jlong renderNodePtr) {
398     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
399     renderNode->mutateStagingProperties().updateMatrix();
400     return renderNode->stagingProperties().getPivotX();
401 }
402 
android_view_RenderNode_getPivotY(jlong renderNodePtr)403 static jfloat android_view_RenderNode_getPivotY(jlong renderNodePtr) {
404     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
405     renderNode->mutateStagingProperties().updateMatrix();
406     return renderNode->stagingProperties().getPivotY();
407 }
408 
409 // ----------------------------------------------------------------------------
410 // RenderProperties - Animations
411 // ----------------------------------------------------------------------------
412 
android_view_RenderNode_addAnimator(JNIEnv * env,jobject clazz,jlong renderNodePtr,jlong animatorPtr)413 static void android_view_RenderNode_addAnimator(JNIEnv* env, jobject clazz, jlong renderNodePtr,
414         jlong animatorPtr) {
415     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
416     RenderPropertyAnimator* animator = reinterpret_cast<RenderPropertyAnimator*>(animatorPtr);
417     renderNode->addAnimator(animator);
418 }
419 
android_view_RenderNode_endAllAnimators(JNIEnv * env,jobject clazz,jlong renderNodePtr)420 static void android_view_RenderNode_endAllAnimators(JNIEnv* env, jobject clazz,
421         jlong renderNodePtr) {
422     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
423     renderNode->animators().endAllStagingAnimators();
424 }
425 
426 // ----------------------------------------------------------------------------
427 // SurfaceView position callback
428 // ----------------------------------------------------------------------------
429 
430 jmethodID gSurfaceViewPositionUpdateMethod;
431 jmethodID gSurfaceViewPositionLostMethod;
432 
android_view_RenderNode_requestPositionUpdates(JNIEnv * env,jobject,jlong renderNodePtr,jobject surfaceview)433 static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
434         jlong renderNodePtr, jobject surfaceview) {
435     class SurfaceViewPositionUpdater : public RenderNode::PositionListener {
436     public:
437         SurfaceViewPositionUpdater(JNIEnv* env, jobject surfaceview) {
438             env->GetJavaVM(&mVm);
439             mWeakRef = env->NewWeakGlobalRef(surfaceview);
440         }
441 
442         virtual ~SurfaceViewPositionUpdater() {
443             jnienv()->DeleteWeakGlobalRef(mWeakRef);
444             mWeakRef = nullptr;
445         }
446 
447         virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) override {
448             if (CC_UNLIKELY(!mWeakRef || !info.updateWindowPositions)) return;
449 
450             Matrix4 transform;
451             info.damageAccumulator->computeCurrentTransform(&transform);
452             const RenderProperties& props = node.properties();
453             uirenderer::Rect bounds(props.getWidth(), props.getHeight());
454             transform.mapRect(bounds);
455 
456             if (CC_LIKELY(transform.isPureTranslate())) {
457                 // snap/round the computed bounds, so they match the rounding behavior
458                 // of the clear done in SurfaceView#draw().
459                 bounds.snapToPixelBoundaries();
460             } else {
461                 // Conservatively round out so the punched hole (in the ZOrderOnTop = true case)
462                 // doesn't extend beyond the other window
463                 bounds.roundOut();
464             }
465 
466             incStrong(0);
467             auto functor = std::bind(
468                 std::mem_fn(&SurfaceViewPositionUpdater::doUpdatePositionAsync), this,
469                 (jlong) info.canvasContext.getFrameNumber(),
470                 (jint) bounds.left, (jint) bounds.top,
471                 (jint) bounds.right, (jint) bounds.bottom);
472 
473             info.canvasContext.enqueueFrameWork(std::move(functor));
474         }
475 
476         virtual void onPositionLost(RenderNode& node, const TreeInfo* info) override {
477             if (CC_UNLIKELY(!mWeakRef || (info && !info->updateWindowPositions))) return;
478 
479             ATRACE_NAME("SurfaceView position lost");
480             JNIEnv* env = jnienv();
481             jobject localref = env->NewLocalRef(mWeakRef);
482             if (CC_UNLIKELY(!localref)) {
483                 jnienv()->DeleteWeakGlobalRef(mWeakRef);
484                 mWeakRef = nullptr;
485                 return;
486             }
487 
488             env->CallVoidMethod(localref, gSurfaceViewPositionLostMethod,
489                     info ? info->canvasContext.getFrameNumber() : 0);
490             env->DeleteLocalRef(localref);
491         }
492 
493     private:
494         JNIEnv* jnienv() {
495             JNIEnv* env;
496             if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
497                 LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", mVm);
498             }
499             return env;
500         }
501 
502         void doUpdatePositionAsync(jlong frameNumber, jint left, jint top,
503                 jint right, jint bottom) {
504             ATRACE_NAME("Update SurfaceView position");
505 
506             JNIEnv* env = jnienv();
507             jobject localref = env->NewLocalRef(mWeakRef);
508             if (CC_UNLIKELY(!localref)) {
509                 env->DeleteWeakGlobalRef(mWeakRef);
510                 mWeakRef = nullptr;
511             } else {
512                 env->CallVoidMethod(localref, gSurfaceViewPositionUpdateMethod,
513                         frameNumber, left, top, right, bottom);
514                 env->DeleteLocalRef(localref);
515             }
516 
517             // We need to release ourselves here
518             decStrong(0);
519         }
520 
521         JavaVM* mVm;
522         jobject mWeakRef;
523     };
524 
525     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
526     renderNode->setPositionListener(new SurfaceViewPositionUpdater(env, surfaceview));
527 }
528 
529 // ----------------------------------------------------------------------------
530 // JNI Glue
531 // ----------------------------------------------------------------------------
532 
533 const char* const kClassPathName = "android/view/RenderNode";
534 
535 static const JNINativeMethod gMethods[] = {
536 // ----------------------------------------------------------------------------
537 // Regular JNI
538 // ----------------------------------------------------------------------------
539     { "nCreate",               "(Ljava/lang/String;)J", (void*) android_view_RenderNode_create },
540     { "nGetNativeFinalizer",   "()J",    (void*) android_view_RenderNode_getNativeFinalizer },
541     { "nOutput",               "(J)V",    (void*) android_view_RenderNode_output },
542     { "nGetDebugSize",         "(J)I",    (void*) android_view_RenderNode_getDebugSize },
543     { "nAddAnimator",              "(JJ)V", (void*) android_view_RenderNode_addAnimator },
544     { "nEndAllAnimators",          "(J)V", (void*) android_view_RenderNode_endAllAnimators },
545     { "nRequestPositionUpdates",   "(JLandroid/view/SurfaceView;)V", (void*) android_view_RenderNode_requestPositionUpdates },
546     { "nSetDisplayList",       "(JJ)V",   (void*) android_view_RenderNode_setDisplayList },
547 
548 
549 // ----------------------------------------------------------------------------
550 // Fast JNI via @CriticalNative annotation in RenderNode.java
551 // ----------------------------------------------------------------------------
552     { "nSetDisplayList",       "(JJ)V",   (void*) android_view_RenderNode_setDisplayList },
553 
554 
555 // ----------------------------------------------------------------------------
556 // Critical JNI via @CriticalNative annotation in RenderNode.java
557 // ----------------------------------------------------------------------------
558     { "nIsValid",              "(J)Z",   (void*) android_view_RenderNode_isValid },
559     { "nSetLayerType",         "(JI)Z",  (void*) android_view_RenderNode_setLayerType },
560     { "nSetLayerPaint",        "(JJ)Z",  (void*) android_view_RenderNode_setLayerPaint },
561     { "nSetStaticMatrix",      "(JJ)Z",  (void*) android_view_RenderNode_setStaticMatrix },
562     { "nSetAnimationMatrix",   "(JJ)Z",  (void*) android_view_RenderNode_setAnimationMatrix },
563     { "nSetClipToBounds",      "(JZ)Z",  (void*) android_view_RenderNode_setClipToBounds },
564     { "nSetClipBounds",        "(JIIII)Z", (void*) android_view_RenderNode_setClipBounds },
565     { "nSetClipBoundsEmpty",   "(J)Z",   (void*) android_view_RenderNode_setClipBoundsEmpty },
566     { "nSetProjectBackwards",  "(JZ)Z",  (void*) android_view_RenderNode_setProjectBackwards },
567     { "nSetProjectionReceiver","(JZ)Z",  (void*) android_view_RenderNode_setProjectionReceiver },
568 
569     { "nSetOutlineRoundRect",  "(JIIIIFF)Z", (void*) android_view_RenderNode_setOutlineRoundRect },
570     { "nSetOutlineConvexPath", "(JJF)Z", (void*) android_view_RenderNode_setOutlineConvexPath },
571     { "nSetOutlineEmpty",      "(J)Z",   (void*) android_view_RenderNode_setOutlineEmpty },
572     { "nSetOutlineNone",       "(J)Z",   (void*) android_view_RenderNode_setOutlineNone },
573     { "nHasShadow",            "(J)Z",   (void*) android_view_RenderNode_hasShadow },
574     { "nSetClipToOutline",     "(JZ)Z",  (void*) android_view_RenderNode_setClipToOutline },
575     { "nSetRevealClip",        "(JZFFF)Z", (void*) android_view_RenderNode_setRevealClip },
576 
577     { "nSetAlpha",             "(JF)Z",  (void*) android_view_RenderNode_setAlpha },
578     { "nSetHasOverlappingRendering", "(JZ)Z",
579             (void*) android_view_RenderNode_setHasOverlappingRendering },
580     { "nSetElevation",         "(JF)Z",  (void*) android_view_RenderNode_setElevation },
581     { "nSetTranslationX",      "(JF)Z",  (void*) android_view_RenderNode_setTranslationX },
582     { "nSetTranslationY",      "(JF)Z",  (void*) android_view_RenderNode_setTranslationY },
583     { "nSetTranslationZ",      "(JF)Z",  (void*) android_view_RenderNode_setTranslationZ },
584     { "nSetRotation",          "(JF)Z",  (void*) android_view_RenderNode_setRotation },
585     { "nSetRotationX",         "(JF)Z",  (void*) android_view_RenderNode_setRotationX },
586     { "nSetRotationY",         "(JF)Z",  (void*) android_view_RenderNode_setRotationY },
587     { "nSetScaleX",            "(JF)Z",  (void*) android_view_RenderNode_setScaleX },
588     { "nSetScaleY",            "(JF)Z",  (void*) android_view_RenderNode_setScaleY },
589     { "nSetPivotX",            "(JF)Z",  (void*) android_view_RenderNode_setPivotX },
590     { "nSetPivotY",            "(JF)Z",  (void*) android_view_RenderNode_setPivotY },
591     { "nSetCameraDistance",    "(JF)Z",  (void*) android_view_RenderNode_setCameraDistance },
592     { "nSetLeft",              "(JI)Z",  (void*) android_view_RenderNode_setLeft },
593     { "nSetTop",               "(JI)Z",  (void*) android_view_RenderNode_setTop },
594     { "nSetRight",             "(JI)Z",  (void*) android_view_RenderNode_setRight },
595     { "nSetBottom",            "(JI)Z",  (void*) android_view_RenderNode_setBottom },
596     { "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom },
597     { "nOffsetLeftAndRight",   "(JI)Z",  (void*) android_view_RenderNode_offsetLeftAndRight },
598     { "nOffsetTopAndBottom",   "(JI)Z",  (void*) android_view_RenderNode_offsetTopAndBottom },
599 
600     { "nHasOverlappingRendering", "(J)Z",  (void*) android_view_RenderNode_hasOverlappingRendering },
601     { "nGetClipToOutline",        "(J)Z",  (void*) android_view_RenderNode_getClipToOutline },
602     { "nGetAlpha",                "(J)F",  (void*) android_view_RenderNode_getAlpha },
603     { "nGetCameraDistance",       "(J)F",  (void*) android_view_RenderNode_getCameraDistance },
604     { "nGetScaleX",               "(J)F",  (void*) android_view_RenderNode_getScaleX },
605     { "nGetScaleY",               "(J)F",  (void*) android_view_RenderNode_getScaleY },
606     { "nGetElevation",            "(J)F",  (void*) android_view_RenderNode_getElevation },
607     { "nGetTranslationX",         "(J)F",  (void*) android_view_RenderNode_getTranslationX },
608     { "nGetTranslationY",         "(J)F",  (void*) android_view_RenderNode_getTranslationY },
609     { "nGetTranslationZ",         "(J)F",  (void*) android_view_RenderNode_getTranslationZ },
610     { "nGetRotation",             "(J)F",  (void*) android_view_RenderNode_getRotation },
611     { "nGetRotationX",            "(J)F",  (void*) android_view_RenderNode_getRotationX },
612     { "nGetRotationY",            "(J)F",  (void*) android_view_RenderNode_getRotationY },
613     { "nIsPivotExplicitlySet",    "(J)Z",  (void*) android_view_RenderNode_isPivotExplicitlySet },
614     { "nHasIdentityMatrix",       "(J)Z",  (void*) android_view_RenderNode_hasIdentityMatrix },
615 
616     { "nGetTransformMatrix",       "(JJ)V", (void*) android_view_RenderNode_getTransformMatrix },
617     { "nGetInverseTransformMatrix","(JJ)V", (void*) android_view_RenderNode_getInverseTransformMatrix },
618 
619     { "nGetPivotX",                "(J)F",  (void*) android_view_RenderNode_getPivotX },
620     { "nGetPivotY",                "(J)F",  (void*) android_view_RenderNode_getPivotY },
621 };
622 
register_android_view_RenderNode(JNIEnv * env)623 int register_android_view_RenderNode(JNIEnv* env) {
624     jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
625     gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
626             "updateSurfacePosition_renderWorker", "(JIIII)V");
627     gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz,
628             "surfacePositionLost_uiRtSync", "(J)V");
629     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
630 }
631 
632 };
633 
634