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