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