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