OSDN Git Service

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