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