xref: /aosp_15_r20/frameworks/base/libs/hwui/jni/android_graphics_RenderNode.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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 ATRACE_TAG ATRACE_TAG_VIEW
18 #include <Animator.h>
19 #include <DamageAccumulator.h>
20 #include <Matrix.h>
21 #include <RenderNode.h>
22 #include <TreeInfo.h>
23 #include <effects/StretchEffect.h>
24 #include <gui/TraceUtils.h>
25 #include <hwui/Paint.h>
26 #include <renderthread/CanvasContext.h>
27 
28 #include "GraphicsJNI.h"
29 
30 namespace android {
31 
32 using namespace uirenderer;
33 
34 #define SET_AND_DIRTY(prop, val, dirtyFlag) \
35     (reinterpret_cast<RenderNode*>(renderNodePtr)->mutateStagingProperties().prop(val) \
36         ? (reinterpret_cast<RenderNode*>(renderNodePtr)->setPropertyFieldsDirty(dirtyFlag), true) \
37         : false)
38 
39 // ----------------------------------------------------------------------------
40 // DisplayList view properties
41 // ----------------------------------------------------------------------------
42 
android_view_RenderNode_output(JNIEnv * env,jobject clazz,jlong renderNodePtr)43 static void android_view_RenderNode_output(JNIEnv* env, jobject clazz, jlong renderNodePtr) {
44     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
45     renderNode->output();
46 }
47 
android_view_RenderNode_getUsageSize(JNIEnv * env,jobject clazz,jlong renderNodePtr)48 static jint android_view_RenderNode_getUsageSize(JNIEnv* env, jobject clazz, jlong renderNodePtr) {
49     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
50     return renderNode->getUsageSize();
51 }
52 
android_view_RenderNode_getAllocatedSize(JNIEnv * env,jobject clazz,jlong renderNodePtr)53 static jint android_view_RenderNode_getAllocatedSize(JNIEnv* env, jobject clazz, jlong renderNodePtr) {
54     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
55     return renderNode->getAllocatedSize();
56 }
57 
android_view_RenderNode_create(JNIEnv * env,jobject,jstring name)58 static jlong android_view_RenderNode_create(JNIEnv* env, jobject, jstring name) {
59     RenderNode* renderNode = new RenderNode();
60     renderNode->incStrong(0);
61     if (name != NULL) {
62         const char* textArray = env->GetStringUTFChars(name, NULL);
63         renderNode->setName(textArray);
64         env->ReleaseStringUTFChars(name, textArray);
65     }
66     return reinterpret_cast<jlong>(renderNode);
67 }
68 
releaseRenderNode(RenderNode * renderNode)69 static void releaseRenderNode(RenderNode* renderNode) {
70     renderNode->decStrong(0);
71 }
72 
android_view_RenderNode_getNativeFinalizer(JNIEnv * env,jobject clazz)73 static jlong android_view_RenderNode_getNativeFinalizer(JNIEnv* env,
74         jobject clazz) {
75     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&releaseRenderNode));
76 }
77 
android_view_RenderNode_discardDisplayList(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)78 static void android_view_RenderNode_discardDisplayList(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
79     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
80     renderNode->discardStagingDisplayList();
81 }
82 
android_view_RenderNode_isValid(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)83 static jboolean android_view_RenderNode_isValid(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
84     return reinterpret_cast<RenderNode*>(renderNodePtr)->isValid();
85 }
86 
87 // ----------------------------------------------------------------------------
88 // RenderProperties - setters
89 // ----------------------------------------------------------------------------
90 
android_view_RenderNode_setLayerType(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jint jlayerType)91 static jboolean android_view_RenderNode_setLayerType(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jint jlayerType) {
92     LayerType layerType = static_cast<LayerType>(jlayerType);
93     return SET_AND_DIRTY(mutateLayerProperties().setType, layerType, RenderNode::GENERIC);
94 }
95 
android_view_RenderNode_setLayerPaint(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jlong paintPtr)96 static jboolean android_view_RenderNode_setLayerPaint(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jlong paintPtr) {
97     Paint* paint = reinterpret_cast<Paint*>(paintPtr);
98     return SET_AND_DIRTY(mutateLayerProperties().setFromPaint, paint, RenderNode::GENERIC);
99 }
100 
android_view_RenderNode_setStaticMatrix(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jlong matrixPtr)101 static jboolean android_view_RenderNode_setStaticMatrix(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jlong matrixPtr) {
102     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
103     return SET_AND_DIRTY(setStaticMatrix, matrix, RenderNode::GENERIC);
104 }
105 
android_view_RenderNode_setAnimationMatrix(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jlong matrixPtr)106 static jboolean android_view_RenderNode_setAnimationMatrix(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jlong matrixPtr) {
107     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
108     return SET_AND_DIRTY(setAnimationMatrix, matrix, RenderNode::GENERIC);
109 }
110 
android_view_RenderNode_setClipToBounds(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jboolean clipToBounds)111 static jboolean android_view_RenderNode_setClipToBounds(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
112         jboolean clipToBounds) {
113     return SET_AND_DIRTY(setClipToBounds, clipToBounds, RenderNode::GENERIC);
114 }
115 
android_view_RenderNode_setClipBounds(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jint left,jint top,jint right,jint bottom)116 static jboolean android_view_RenderNode_setClipBounds(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
117         jint left, jint top, jint right, jint bottom) {
118     android::uirenderer::Rect clipBounds(left, top, right, bottom);
119     return SET_AND_DIRTY(setClipBounds, clipBounds, RenderNode::GENERIC);
120 }
121 
android_view_RenderNode_setClipBoundsEmpty(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)122 static jboolean android_view_RenderNode_setClipBoundsEmpty(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
123     return SET_AND_DIRTY(setClipBoundsEmpty,, RenderNode::GENERIC);
124 }
125 
android_view_RenderNode_setProjectBackwards(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jboolean shouldProject)126 static jboolean android_view_RenderNode_setProjectBackwards(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
127         jboolean shouldProject) {
128     return SET_AND_DIRTY(setProjectBackwards, shouldProject, RenderNode::GENERIC);
129 }
130 
android_view_RenderNode_setProjectionReceiver(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jboolean shouldRecieve)131 static jboolean android_view_RenderNode_setProjectionReceiver(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
132         jboolean shouldRecieve) {
133     return SET_AND_DIRTY(setProjectionReceiver, shouldRecieve, RenderNode::GENERIC);
134 }
135 
android_view_RenderNode_setOutlineRoundRect(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jint left,jint top,jint right,jint bottom,jfloat radius,jfloat alpha)136 static jboolean android_view_RenderNode_setOutlineRoundRect(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
137         jint left, jint top, jint right, jint bottom, jfloat radius, jfloat alpha) {
138     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
139     renderNode->mutateStagingProperties().mutableOutline().setRoundRect(left, top, right, bottom,
140             radius, alpha);
141     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
142     return true;
143 }
144 
android_view_RenderNode_setOutlinePath(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jlong outlinePathPtr,jfloat alpha)145 static jboolean android_view_RenderNode_setOutlinePath(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
146         jlong outlinePathPtr, jfloat alpha) {
147     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
148     SkPath* outlinePath = reinterpret_cast<SkPath*>(outlinePathPtr);
149     renderNode->mutateStagingProperties().mutableOutline().setPath(outlinePath, alpha);
150     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
151     return true;
152 }
153 
android_view_RenderNode_setOutlineEmpty(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)154 static jboolean android_view_RenderNode_setOutlineEmpty(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
155     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
156     renderNode->mutateStagingProperties().mutableOutline().setEmpty();
157     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
158     return true;
159 }
160 
android_view_RenderNode_setOutlineNone(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)161 static jboolean android_view_RenderNode_setOutlineNone(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
162     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
163     renderNode->mutateStagingProperties().mutableOutline().setNone();
164     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
165     return true;
166 }
167 
android_view_RenderNode_clearStretch(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)168 static jboolean android_view_RenderNode_clearStretch(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
169     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
170     auto& stretch = renderNode->mutateStagingProperties()
171             .mutateLayerProperties().mutableStretchEffect();
172     if (stretch.isEmpty()) {
173         return false;
174     }
175     stretch.setEmpty();
176     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
177     return true;
178 }
179 
android_view_RenderNode_stretch(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jfloat vX,jfloat vY,jfloat maxX,jfloat maxY)180 static jboolean android_view_RenderNode_stretch(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
181                                                 jfloat vX, jfloat vY, jfloat maxX,
182                                                 jfloat maxY) {
183     auto* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
184     StretchEffect effect = StretchEffect({.fX = vX, .fY = vY}, maxX, maxY);
185     renderNode->mutateStagingProperties().mutateLayerProperties().mutableStretchEffect().mergeWith(
186             effect);
187     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
188     return true;
189 }
190 
android_view_RenderNode_hasShadow(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)191 static jboolean android_view_RenderNode_hasShadow(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
192     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
193     return renderNode->stagingProperties().hasShadow();
194 }
195 
android_view_RenderNode_setSpotShadowColor(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jint shadowColor)196 static jboolean android_view_RenderNode_setSpotShadowColor(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jint shadowColor) {
197     return SET_AND_DIRTY(setSpotShadowColor,
198             static_cast<SkColor>(shadowColor), RenderNode::GENERIC);
199 }
200 
android_view_RenderNode_getSpotShadowColor(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)201 static jint android_view_RenderNode_getSpotShadowColor(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
202     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
203     return renderNode->stagingProperties().getSpotShadowColor();
204 }
205 
android_view_RenderNode_setAmbientShadowColor(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jint shadowColor)206 static jboolean android_view_RenderNode_setAmbientShadowColor(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
207         jint shadowColor) {
208     return SET_AND_DIRTY(setAmbientShadowColor,
209             static_cast<SkColor>(shadowColor), RenderNode::GENERIC);
210 }
211 
android_view_RenderNode_getAmbientShadowColor(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)212 static jint android_view_RenderNode_getAmbientShadowColor(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
213     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
214     return renderNode->stagingProperties().getAmbientShadowColor();
215 }
216 
android_view_RenderNode_setClipToOutline(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jboolean clipToOutline)217 static jboolean android_view_RenderNode_setClipToOutline(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
218         jboolean clipToOutline) {
219     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
220     renderNode->mutateStagingProperties().mutableOutline().setShouldClip(clipToOutline);
221     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
222     return true;
223 }
224 
android_view_RenderNode_setRevealClip(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jboolean shouldClip,jfloat x,jfloat y,jfloat radius)225 static jboolean android_view_RenderNode_setRevealClip(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jboolean shouldClip,
226         jfloat x, jfloat y, jfloat radius) {
227     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
228     renderNode->mutateStagingProperties().mutableRevealClip().set(
229             shouldClip, x, y, radius);
230     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
231     return true;
232 }
233 
android_view_RenderNode_setAlpha(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,float alpha)234 static jboolean android_view_RenderNode_setAlpha(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, float alpha) {
235     return SET_AND_DIRTY(setAlpha, alpha, RenderNode::ALPHA);
236 }
237 
android_view_RenderNode_setRenderEffect(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jlong renderEffectPtr)238 static jboolean android_view_RenderNode_setRenderEffect(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
239         jlong renderEffectPtr) {
240     SkImageFilter* imageFilter = reinterpret_cast<SkImageFilter*>(renderEffectPtr);
241     return SET_AND_DIRTY(mutateLayerProperties().setImageFilter, imageFilter, RenderNode::GENERIC);
242 }
243 
android_view_RenderNode_setBackdropRenderEffect(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jlong renderEffectPtr)244 static jboolean android_view_RenderNode_setBackdropRenderEffect(
245         CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jlong renderEffectPtr) {
246     SkImageFilter* imageFilter = reinterpret_cast<SkImageFilter*>(renderEffectPtr);
247     return SET_AND_DIRTY(mutateLayerProperties().setBackdropImageFilter, imageFilter,
248                          RenderNode::GENERIC);
249 }
250 
android_view_RenderNode_setHasOverlappingRendering(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,bool hasOverlappingRendering)251 static jboolean android_view_RenderNode_setHasOverlappingRendering(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
252         bool hasOverlappingRendering) {
253     return SET_AND_DIRTY(setHasOverlappingRendering, hasOverlappingRendering,
254             RenderNode::GENERIC);
255 }
256 
android_view_RenderNode_setUsageHint(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jint usageHint)257 static void android_view_RenderNode_setUsageHint(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jint usageHint) {
258     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
259     renderNode->setUsageHint(static_cast<UsageHint>(usageHint));
260 }
261 
android_view_RenderNode_setElevation(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,float elevation)262 static jboolean android_view_RenderNode_setElevation(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, float elevation) {
263     return SET_AND_DIRTY(setElevation, elevation, RenderNode::Z);
264 }
265 
android_view_RenderNode_setTranslationX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,float tx)266 static jboolean android_view_RenderNode_setTranslationX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, float tx) {
267     return SET_AND_DIRTY(setTranslationX, tx, RenderNode::TRANSLATION_X | RenderNode::X);
268 }
269 
android_view_RenderNode_setTranslationY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,float ty)270 static jboolean android_view_RenderNode_setTranslationY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, float ty) {
271     return SET_AND_DIRTY(setTranslationY, ty, RenderNode::TRANSLATION_Y | RenderNode::Y);
272 }
273 
android_view_RenderNode_setTranslationZ(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,float tz)274 static jboolean android_view_RenderNode_setTranslationZ(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, float tz) {
275     return SET_AND_DIRTY(setTranslationZ, tz, RenderNode::TRANSLATION_Z | RenderNode::Z);
276 }
277 
android_view_RenderNode_setRotation(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,float rotation)278 static jboolean android_view_RenderNode_setRotation(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, float rotation) {
279     return SET_AND_DIRTY(setRotation, rotation, RenderNode::ROTATION);
280 }
281 
android_view_RenderNode_setRotationX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,float rx)282 static jboolean android_view_RenderNode_setRotationX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, float rx) {
283     return SET_AND_DIRTY(setRotationX, rx, RenderNode::ROTATION_X);
284 }
285 
android_view_RenderNode_setRotationY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,float ry)286 static jboolean android_view_RenderNode_setRotationY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, float ry) {
287     return SET_AND_DIRTY(setRotationY, ry, RenderNode::ROTATION_Y);
288 }
289 
android_view_RenderNode_setScaleX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,float sx)290 static jboolean android_view_RenderNode_setScaleX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, float sx) {
291     return SET_AND_DIRTY(setScaleX, sx, RenderNode::SCALE_X);
292 }
293 
android_view_RenderNode_setScaleY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,float sy)294 static jboolean android_view_RenderNode_setScaleY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, float sy) {
295     return SET_AND_DIRTY(setScaleY, sy, RenderNode::SCALE_Y);
296 }
297 
android_view_RenderNode_setPivotX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,float px)298 static jboolean android_view_RenderNode_setPivotX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, float px) {
299     return SET_AND_DIRTY(setPivotX, px, RenderNode::GENERIC);
300 }
301 
android_view_RenderNode_setPivotY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,float py)302 static jboolean android_view_RenderNode_setPivotY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, float py) {
303     return SET_AND_DIRTY(setPivotY, py, RenderNode::GENERIC);
304 }
305 
android_view_RenderNode_resetPivot(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)306 static jboolean android_view_RenderNode_resetPivot(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
307     return SET_AND_DIRTY(resetPivot, /* void */, RenderNode::GENERIC);
308 }
309 
android_view_RenderNode_setCameraDistance(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,float distance)310 static jboolean android_view_RenderNode_setCameraDistance(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, float distance) {
311     return SET_AND_DIRTY(setCameraDistance, distance, RenderNode::GENERIC);
312 }
313 
android_view_RenderNode_setLeft(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,int left)314 static jboolean android_view_RenderNode_setLeft(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, int left) {
315     return SET_AND_DIRTY(setLeft, left, RenderNode::X);
316 }
317 
android_view_RenderNode_setTop(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,int top)318 static jboolean android_view_RenderNode_setTop(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, int top) {
319     return SET_AND_DIRTY(setTop, top, RenderNode::Y);
320 }
321 
android_view_RenderNode_setRight(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,int right)322 static jboolean android_view_RenderNode_setRight(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, int right) {
323     return SET_AND_DIRTY(setRight, right, RenderNode::X);
324 }
325 
android_view_RenderNode_setBottom(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,int bottom)326 static jboolean android_view_RenderNode_setBottom(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, int bottom) {
327     return SET_AND_DIRTY(setBottom, bottom, RenderNode::Y);
328 }
329 
android_view_RenderNode_getLeft(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)330 static jint android_view_RenderNode_getLeft(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
331     return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getLeft();
332 }
333 
android_view_RenderNode_getTop(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)334 static jint android_view_RenderNode_getTop(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
335     return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getTop();
336 }
337 
android_view_RenderNode_getRight(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)338 static jint android_view_RenderNode_getRight(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
339     return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getRight();
340 }
341 
android_view_RenderNode_getBottom(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)342 static jint android_view_RenderNode_getBottom(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
343     return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getBottom();
344 }
345 
android_view_RenderNode_setLeftTopRightBottom(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,int left,int top,int right,int bottom)346 static jboolean android_view_RenderNode_setLeftTopRightBottom(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
347         int left, int top, int right, int bottom) {
348     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
349     if (renderNode->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom)) {
350         renderNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
351         return true;
352     }
353     return false;
354 }
355 
android_view_RenderNode_offsetLeftAndRight(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jint offset)356 static jboolean android_view_RenderNode_offsetLeftAndRight(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jint offset) {
357     return SET_AND_DIRTY(offsetLeftRight, offset, RenderNode::X);
358 }
359 
android_view_RenderNode_offsetTopAndBottom(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jint offset)360 static jboolean android_view_RenderNode_offsetTopAndBottom(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jint offset) {
361     return SET_AND_DIRTY(offsetTopBottom, offset, RenderNode::Y);
362 }
363 
364 // ----------------------------------------------------------------------------
365 // RenderProperties - getters
366 // ----------------------------------------------------------------------------
367 
android_view_RenderNode_hasOverlappingRendering(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)368 static jboolean android_view_RenderNode_hasOverlappingRendering(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
369     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
370     return renderNode->stagingProperties().hasOverlappingRendering();
371 }
372 
android_view_RenderNode_getAnimationMatrix(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jlong outMatrixPtr)373 static jboolean android_view_RenderNode_getAnimationMatrix(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jlong outMatrixPtr) {
374     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
375     SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr);
376 
377     const SkMatrix* animationMatrix = renderNode->stagingProperties().getAnimationMatrix();
378 
379     if (animationMatrix) {
380         *outMatrix = *animationMatrix;
381         return JNI_TRUE;
382     }
383     return JNI_FALSE;
384 }
385 
android_view_RenderNode_getClipToBounds(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)386 static jboolean android_view_RenderNode_getClipToBounds(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
387     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
388     return renderNode->stagingProperties().getClipToBounds();
389 }
390 
android_view_RenderNode_getClipToOutline(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)391 static jboolean android_view_RenderNode_getClipToOutline(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
392     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
393     return renderNode->stagingProperties().getOutline().getShouldClip();
394 }
395 
android_view_RenderNode_getAlpha(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)396 static jfloat android_view_RenderNode_getAlpha(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
397     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
398     return renderNode->stagingProperties().getAlpha();
399 }
400 
android_view_RenderNode_getCameraDistance(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)401 static jfloat android_view_RenderNode_getCameraDistance(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
402     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
403     return renderNode->stagingProperties().getCameraDistance();
404 }
405 
android_view_RenderNode_getScaleX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)406 static jfloat android_view_RenderNode_getScaleX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
407     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
408     return renderNode->stagingProperties().getScaleX();
409 }
410 
android_view_RenderNode_getScaleY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)411 static jfloat android_view_RenderNode_getScaleY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
412     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
413     return renderNode->stagingProperties().getScaleY();
414 }
415 
android_view_RenderNode_getElevation(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)416 static jfloat android_view_RenderNode_getElevation(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
417     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
418     return renderNode->stagingProperties().getElevation();
419 }
420 
android_view_RenderNode_getTranslationX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)421 static jfloat android_view_RenderNode_getTranslationX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
422     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
423     return renderNode->stagingProperties().getTranslationX();
424 }
425 
android_view_RenderNode_getTranslationY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)426 static jfloat android_view_RenderNode_getTranslationY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
427     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
428     return renderNode->stagingProperties().getTranslationY();
429 }
430 
android_view_RenderNode_getTranslationZ(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)431 static jfloat android_view_RenderNode_getTranslationZ(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
432     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
433     return renderNode->stagingProperties().getTranslationZ();
434 }
435 
android_view_RenderNode_getRotation(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)436 static jfloat android_view_RenderNode_getRotation(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
437     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
438     return renderNode->stagingProperties().getRotation();
439 }
440 
android_view_RenderNode_getRotationX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)441 static jfloat android_view_RenderNode_getRotationX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
442     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
443     return renderNode->stagingProperties().getRotationX();
444 }
445 
android_view_RenderNode_getRotationY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)446 static jfloat android_view_RenderNode_getRotationY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
447     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
448     return renderNode->stagingProperties().getRotationY();
449 }
450 
android_view_RenderNode_isPivotExplicitlySet(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)451 static jboolean android_view_RenderNode_isPivotExplicitlySet(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
452     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
453     return renderNode->stagingProperties().isPivotExplicitlySet();
454 }
455 
android_view_RenderNode_hasIdentityMatrix(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)456 static jboolean android_view_RenderNode_hasIdentityMatrix(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
457     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
458     renderNode->mutateStagingProperties().updateMatrix();
459     return !renderNode->stagingProperties().hasTransformMatrix();
460 }
461 
android_view_RenderNode_getLayerType(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)462 static jint android_view_RenderNode_getLayerType(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
463     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
464     return static_cast<int>(renderNode->stagingProperties().layerProperties().type());
465 }
466 
467 // ----------------------------------------------------------------------------
468 // RenderProperties - computed getters
469 // ----------------------------------------------------------------------------
470 
getTransformMatrix(jlong renderNodePtr,jlong outMatrixPtr)471 static void getTransformMatrix(jlong renderNodePtr, jlong outMatrixPtr) {
472     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
473     SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr);
474 
475     renderNode->mutateStagingProperties().updateMatrix();
476     const SkMatrix* transformMatrix = renderNode->stagingProperties().getTransformMatrix();
477 
478     if (transformMatrix) {
479         *outMatrix = *transformMatrix;
480     } else {
481         outMatrix->setIdentity();
482     }
483 }
484 
android_view_RenderNode_getTransformMatrix(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jlong outMatrixPtr)485 static void android_view_RenderNode_getTransformMatrix(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jlong outMatrixPtr) {
486     getTransformMatrix(renderNodePtr, outMatrixPtr);
487 }
488 
android_view_RenderNode_getInverseTransformMatrix(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jlong outMatrixPtr)489 static void android_view_RenderNode_getInverseTransformMatrix(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
490         jlong outMatrixPtr) {
491     // load transform matrix
492     getTransformMatrix(renderNodePtr, outMatrixPtr);
493     SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr);
494 
495     // return it inverted
496     if (!outMatrix->invert(outMatrix)) {
497         // failed to load inverse, pass back identity
498         outMatrix->setIdentity();
499     }
500 }
501 
android_view_RenderNode_getPivotX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)502 static jfloat android_view_RenderNode_getPivotX(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
503     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
504     renderNode->mutateStagingProperties().updateMatrix();
505     return renderNode->stagingProperties().getPivotX();
506 }
507 
android_view_RenderNode_getPivotY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)508 static jfloat android_view_RenderNode_getPivotY(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
509     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
510     renderNode->mutateStagingProperties().updateMatrix();
511     return renderNode->stagingProperties().getPivotY();
512 }
513 
android_view_RenderNode_getWidth(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)514 static jint android_view_RenderNode_getWidth(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
515     return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getWidth();
516 }
517 
android_view_RenderNode_getHeight(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)518 static jint android_view_RenderNode_getHeight(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
519     return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getHeight();
520 }
521 
android_view_RenderNode_setAllowForceDark(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,jboolean allow)522 static jboolean android_view_RenderNode_setAllowForceDark(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jboolean allow) {
523     return SET_AND_DIRTY(setAllowForceDark, allow, RenderNode::GENERIC);
524 }
525 
android_view_RenderNode_getAllowForceDark(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)526 static jboolean android_view_RenderNode_getAllowForceDark(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
527     return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getAllowForceDark();
528 }
529 
android_view_RenderNode_getUniqueId(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)530 static jlong android_view_RenderNode_getUniqueId(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
531     return reinterpret_cast<RenderNode*>(renderNodePtr)->uniqueId();
532 }
533 
android_view_RenderNode_setIsTextureView(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr)534 static void android_view_RenderNode_setIsTextureView(
535         CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr) {
536     reinterpret_cast<RenderNode*>(renderNodePtr)->setIsTextureView();
537 }
538 
539 // ----------------------------------------------------------------------------
540 // RenderProperties - Animations
541 // ----------------------------------------------------------------------------
542 
android_view_RenderNode_addAnimator(JNIEnv * env,jobject clazz,jlong renderNodePtr,jlong animatorPtr)543 static void android_view_RenderNode_addAnimator(JNIEnv* env, jobject clazz, jlong renderNodePtr,
544         jlong animatorPtr) {
545     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
546     RenderPropertyAnimator* animator = reinterpret_cast<RenderPropertyAnimator*>(animatorPtr);
547     renderNode->addAnimator(animator);
548 }
549 
android_view_RenderNode_endAllAnimators(JNIEnv * env,jobject clazz,jlong renderNodePtr)550 static void android_view_RenderNode_endAllAnimators(JNIEnv* env, jobject clazz,
551         jlong renderNodePtr) {
552     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
553     renderNode->animators().endAllStagingAnimators();
554 }
555 
android_view_RenderNode_forceEndAnimators(JNIEnv * env,jobject clazz,jlong renderNodePtr)556 static void android_view_RenderNode_forceEndAnimators(JNIEnv* env, jobject clazz,
557                                                       jlong renderNodePtr) {
558     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
559     renderNode->animators().forceEndAnimators();
560 }
561 
562 // ----------------------------------------------------------------------------
563 // SurfaceView position callback
564 // ----------------------------------------------------------------------------
565 
566 struct {
567     jclass clazz;
568     jmethodID callPositionChanged;
569     jmethodID callPositionChanged2;
570     jmethodID callApplyStretch;
571     jmethodID callPositionLost;
572 } gPositionListener;
573 
android_view_RenderNode_requestPositionUpdates(JNIEnv * env,jobject,jlong renderNodePtr,jobject listener)574 static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
575         jlong renderNodePtr, jobject listener) {
576     class PositionListenerTrampoline : public RenderNode::PositionListener {
577     public:
578         PositionListenerTrampoline(JNIEnv* env, jobject listener) {
579             env->GetJavaVM(&mVm);
580             mListener = env->NewGlobalRef(listener);
581         }
582 
583         virtual ~PositionListenerTrampoline() {
584             jnienv()->DeleteGlobalRef(mListener);
585             mListener = nullptr;
586         }
587 
588         virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) override {
589             if (CC_UNLIKELY(!mListener || !info.updateWindowPositions)) return;
590 
591             const RenderProperties& props = node.properties();
592             const bool enableClip = Properties::clipSurfaceViews;
593 
594             Matrix4 transform;
595             SkIRect clipBounds;
596             uirenderer::Rect initialClipBounds;
597             if (enableClip) {
598                 // SurfaceView never draws beyond its bounds regardless of if it can or not,
599                 // so if clip-to-bounds is disabled just use the bounds as the starting point
600                 // regardless
601                 const auto clipFlags = props.getClippingFlags();
602                 props.getClippingRectForFlags(clipFlags | CLIP_TO_BOUNDS, &initialClipBounds);
603                 clipBounds =
604                         info.damageAccumulator
605                                 ->computeClipAndTransform(initialClipBounds.toSkRect(), &transform)
606                                 .roundOut();
607             } else {
608                 info.damageAccumulator->computeCurrentTransform(&transform);
609             }
610             bool useStretchShader =
611                     Properties::getStretchEffectBehavior() != StretchEffectBehavior::UniformScale;
612             // Compute the transform bounds first before calculating the stretch
613             uirenderer::Rect bounds(props.getWidth(), props.getHeight());
614             transform.mapRect(bounds);
615 
616             bool hasStretch = useStretchShader && info.stretchEffectCount;
617             if (hasStretch) {
618                 handleStretchEffect(info, bounds);
619             }
620 
621             if (CC_LIKELY(transform.isPureTranslate()) && !hasStretch) {
622                 // snap/round the computed bounds, so they match the rounding behavior
623                 // of the clear done in SurfaceView#draw().
624                 bounds.snapGeometryToPixelBoundaries(false);
625             } else {
626                 // Conservatively round out so the punched hole (in the ZOrderOnTop = true case)
627                 // doesn't extend beyond the other window
628                 bounds.roundOut();
629             }
630 
631             if (mPreviousPosition == bounds && mPreviousClip == clipBounds) {
632                 return;
633             }
634             mPreviousPosition = bounds;
635             mPreviousClip = clipBounds;
636 
637             ATRACE_NAME("Update SurfaceView position");
638 
639             JNIEnv* env = jnienv();
640             // Update the new position synchronously. We cannot defer this to
641             // a worker pool to process asynchronously because the UI thread
642             // may be unblocked by the time a worker thread can process this,
643             // In particular if the app removes a view from the view tree before
644             // this callback is dispatched, then we lose the position
645             // information for this frame.
646             jboolean keepListening;
647             if (!enableClip) {
648                 keepListening = env->CallStaticBooleanMethod(
649                         gPositionListener.clazz, gPositionListener.callPositionChanged, mListener,
650                         static_cast<jlong>(info.canvasContext.getFrameNumber()),
651                         static_cast<jint>(bounds.left), static_cast<jint>(bounds.top),
652                         static_cast<jint>(bounds.right), static_cast<jint>(bounds.bottom));
653             } else {
654                 keepListening = env->CallStaticBooleanMethod(
655                         gPositionListener.clazz, gPositionListener.callPositionChanged2, mListener,
656                         static_cast<jlong>(info.canvasContext.getFrameNumber()),
657                         static_cast<jint>(bounds.left), static_cast<jint>(bounds.top),
658                         static_cast<jint>(bounds.right), static_cast<jint>(bounds.bottom),
659                         static_cast<jint>(clipBounds.fLeft), static_cast<jint>(clipBounds.fTop),
660                         static_cast<jint>(clipBounds.fRight), static_cast<jint>(clipBounds.fBottom),
661                         static_cast<jint>(props.getWidth()), static_cast<jint>(props.getHeight()));
662             }
663             if (!keepListening) {
664                 env->DeleteGlobalRef(mListener);
665                 mListener = nullptr;
666             }
667         }
668 
669         virtual void onPositionLost(RenderNode& node, const TreeInfo* info) override {
670             if (CC_UNLIKELY(!mListener || (info && !info->updateWindowPositions))) return;
671 
672             if (mPreviousPosition.isEmpty()) {
673                 return;
674             }
675             mPreviousPosition.setEmpty();
676 
677             ATRACE_NAME("SurfaceView position lost");
678             JNIEnv* env = jnienv();
679             // Update the lost position synchronously. We cannot defer this to
680             // a worker pool to process asynchronously because the UI thread
681             // may be unblocked by the time a worker thread can process this,
682             // In particular if a view's rendernode is readded to the scene
683             // before this callback is dispatched, then we report that we lost
684             // position information on the wrong frame, which can be problematic
685             // for views like SurfaceView which rely on RenderNode callbacks
686             // for driving visibility.
687             jboolean keepListening = env->CallStaticBooleanMethod(
688                     gPositionListener.clazz, gPositionListener.callPositionLost, mListener,
689                     info ? info->canvasContext.getFrameNumber() : 0);
690             if (!keepListening) {
691                 env->DeleteGlobalRef(mListener);
692                 mListener = nullptr;
693             }
694         }
695 
696     private:
697         JNIEnv* jnienv() {
698             JNIEnv* env;
699             if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
700                 LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", mVm);
701             }
702             return env;
703         }
704 
705         void handleStretchEffect(const TreeInfo& info, uirenderer::Rect& targetBounds) {
706             // Search up to find the nearest stretcheffect parent
707             const DamageAccumulator::StretchResult result =
708                 info.damageAccumulator->findNearestStretchEffect();
709             const StretchEffect* effect = result.stretchEffect;
710             if (effect) {
711                 // Compute the number of pixels that the stretching container
712                 // scales by.
713                 // Then compute the scale factor that the child would need
714                 // to scale in order to occupy the same pixel bounds.
715                 auto& parentBounds = result.parentBounds;
716                 auto parentWidth = parentBounds.width();
717                 auto parentHeight = parentBounds.height();
718                 auto& stretchDirection = effect->getStretchDirection();
719                 auto stretchX = stretchDirection.x();
720                 auto stretchY = stretchDirection.y();
721                 auto stretchXPixels = parentWidth * std::abs(stretchX);
722                 auto stretchYPixels = parentHeight * std::abs(stretchY);
723                 SkMatrix stretchMatrix;
724 
725                 auto childScaleX = 1 + (stretchXPixels / targetBounds.getWidth());
726                 auto childScaleY = 1 + (stretchYPixels / targetBounds.getHeight());
727                 auto pivotX = stretchX > 0 ? targetBounds.left : targetBounds.right;
728                 auto pivotY = stretchY > 0 ? targetBounds.top : targetBounds.bottom;
729                 stretchMatrix.setScale(childScaleX, childScaleY, pivotX, pivotY);
730                 SkRect rect = SkRect::MakeLTRB(targetBounds.left, targetBounds.top,
731                                                targetBounds.right, targetBounds.bottom);
732                 SkRect dst = stretchMatrix.mapRect(rect);
733                 targetBounds.left = dst.left();
734                 targetBounds.top = dst.top();
735                 targetBounds.right = dst.right();
736                 targetBounds.bottom = dst.bottom();
737             } else {
738                 return;
739             }
740 
741             if (Properties::getStretchEffectBehavior() ==
742                 StretchEffectBehavior::Shader) {
743                 JNIEnv* env = jnienv();
744 
745                 SkVector stretchDirection = effect->getStretchDirection();
746                 jboolean keepListening = env->CallStaticBooleanMethod(
747                         gPositionListener.clazz, gPositionListener.callApplyStretch, mListener,
748                         info.canvasContext.getFrameNumber(), result.width, result.height,
749                         stretchDirection.fX, stretchDirection.fY, effect->maxStretchAmountX,
750                         effect->maxStretchAmountY, targetBounds.left, targetBounds.top,
751                         targetBounds.right, targetBounds.bottom);
752                 if (!keepListening) {
753                     env->DeleteGlobalRef(mListener);
754                     mListener = nullptr;
755                 }
756             }
757         }
758 
759         JavaVM* mVm;
760         jobject mListener;
761         uirenderer::Rect mPreviousPosition;
762         uirenderer::Rect mPreviousClip;
763     };
764 
765     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
766     renderNode->setPositionListener(new PositionListenerTrampoline(env, listener));
767 }
768 
769 // ----------------------------------------------------------------------------
770 // JNI Glue
771 // ----------------------------------------------------------------------------
772 
773 const char* const kClassPathName = "android/graphics/RenderNode";
774 
775 static const JNINativeMethod gMethods[] = {
776         // ----------------------------------------------------------------------------
777         // Regular JNI
778         // ----------------------------------------------------------------------------
779         {"nCreate", "(Ljava/lang/String;)J", (void*)android_view_RenderNode_create},
780         {"nGetNativeFinalizer", "()J", (void*)android_view_RenderNode_getNativeFinalizer},
781         {"nOutput", "(J)V", (void*)android_view_RenderNode_output},
782         {"nGetUsageSize", "(J)I", (void*)android_view_RenderNode_getUsageSize},
783         {"nGetAllocatedSize", "(J)I", (void*)android_view_RenderNode_getAllocatedSize},
784         {"nAddAnimator", "(JJ)V", (void*)android_view_RenderNode_addAnimator},
785         {"nEndAllAnimators", "(J)V", (void*)android_view_RenderNode_endAllAnimators},
786         {"nForceEndAnimators", "(J)V", (void*)android_view_RenderNode_forceEndAnimators},
787         {"nRequestPositionUpdates", "(JLjava/lang/ref/WeakReference;)V",
788          (void*)android_view_RenderNode_requestPositionUpdates},
789 
790         // ----------------------------------------------------------------------------
791         // Critical JNI via @CriticalNative annotation in RenderNode.java
792         // ----------------------------------------------------------------------------
793         {"nDiscardDisplayList", "(J)V", (void*)android_view_RenderNode_discardDisplayList},
794         {"nIsValid", "(J)Z", (void*)android_view_RenderNode_isValid},
795         {"nSetLayerType", "(JI)Z", (void*)android_view_RenderNode_setLayerType},
796         {"nGetLayerType", "(J)I", (void*)android_view_RenderNode_getLayerType},
797         {"nSetLayerPaint", "(JJ)Z", (void*)android_view_RenderNode_setLayerPaint},
798         {"nSetStaticMatrix", "(JJ)Z", (void*)android_view_RenderNode_setStaticMatrix},
799         {"nSetAnimationMatrix", "(JJ)Z", (void*)android_view_RenderNode_setAnimationMatrix},
800         {"nGetAnimationMatrix", "(JJ)Z", (void*)android_view_RenderNode_getAnimationMatrix},
801         {"nSetClipToBounds", "(JZ)Z", (void*)android_view_RenderNode_setClipToBounds},
802         {"nGetClipToBounds", "(J)Z", (void*)android_view_RenderNode_getClipToBounds},
803         {"nSetClipBounds", "(JIIII)Z", (void*)android_view_RenderNode_setClipBounds},
804         {"nSetClipBoundsEmpty", "(J)Z", (void*)android_view_RenderNode_setClipBoundsEmpty},
805         {"nSetProjectBackwards", "(JZ)Z", (void*)android_view_RenderNode_setProjectBackwards},
806         {"nSetProjectionReceiver", "(JZ)Z", (void*)android_view_RenderNode_setProjectionReceiver},
807 
808         {"nSetOutlineRoundRect", "(JIIIIFF)Z", (void*)android_view_RenderNode_setOutlineRoundRect},
809         {"nSetOutlinePath", "(JJF)Z", (void*)android_view_RenderNode_setOutlinePath},
810         {"nSetOutlineEmpty", "(J)Z", (void*)android_view_RenderNode_setOutlineEmpty},
811         {"nSetOutlineNone", "(J)Z", (void*)android_view_RenderNode_setOutlineNone},
812         {"nClearStretch", "(J)Z", (void*)android_view_RenderNode_clearStretch},
813         {"nStretch", "(JFFFF)Z", (void*)android_view_RenderNode_stretch},
814         {"nHasShadow", "(J)Z", (void*)android_view_RenderNode_hasShadow},
815         {"nSetSpotShadowColor", "(JI)Z", (void*)android_view_RenderNode_setSpotShadowColor},
816         {"nGetSpotShadowColor", "(J)I", (void*)android_view_RenderNode_getSpotShadowColor},
817         {"nSetAmbientShadowColor", "(JI)Z", (void*)android_view_RenderNode_setAmbientShadowColor},
818         {"nGetAmbientShadowColor", "(J)I", (void*)android_view_RenderNode_getAmbientShadowColor},
819         {"nSetClipToOutline", "(JZ)Z", (void*)android_view_RenderNode_setClipToOutline},
820         {"nSetRevealClip", "(JZFFF)Z", (void*)android_view_RenderNode_setRevealClip},
821 
822         {"nSetAlpha", "(JF)Z", (void*)android_view_RenderNode_setAlpha},
823         {"nSetRenderEffect", "(JJ)Z", (void*)android_view_RenderNode_setRenderEffect},
824         {"nSetBackdropRenderEffect", "(JJ)Z",
825          (void*)android_view_RenderNode_setBackdropRenderEffect},
826         {"nSetHasOverlappingRendering", "(JZ)Z",
827          (void*)android_view_RenderNode_setHasOverlappingRendering},
828         {"nSetUsageHint", "(JI)V", (void*)android_view_RenderNode_setUsageHint},
829         {"nSetElevation", "(JF)Z", (void*)android_view_RenderNode_setElevation},
830         {"nSetTranslationX", "(JF)Z", (void*)android_view_RenderNode_setTranslationX},
831         {"nSetTranslationY", "(JF)Z", (void*)android_view_RenderNode_setTranslationY},
832         {"nSetTranslationZ", "(JF)Z", (void*)android_view_RenderNode_setTranslationZ},
833         {"nSetRotation", "(JF)Z", (void*)android_view_RenderNode_setRotation},
834         {"nSetRotationX", "(JF)Z", (void*)android_view_RenderNode_setRotationX},
835         {"nSetRotationY", "(JF)Z", (void*)android_view_RenderNode_setRotationY},
836         {"nSetScaleX", "(JF)Z", (void*)android_view_RenderNode_setScaleX},
837         {"nSetScaleY", "(JF)Z", (void*)android_view_RenderNode_setScaleY},
838         {"nSetPivotX", "(JF)Z", (void*)android_view_RenderNode_setPivotX},
839         {"nSetPivotY", "(JF)Z", (void*)android_view_RenderNode_setPivotY},
840         {"nResetPivot", "(J)Z", (void*)android_view_RenderNode_resetPivot},
841         {"nSetCameraDistance", "(JF)Z", (void*)android_view_RenderNode_setCameraDistance},
842         {"nSetLeft", "(JI)Z", (void*)android_view_RenderNode_setLeft},
843         {"nSetTop", "(JI)Z", (void*)android_view_RenderNode_setTop},
844         {"nSetRight", "(JI)Z", (void*)android_view_RenderNode_setRight},
845         {"nSetBottom", "(JI)Z", (void*)android_view_RenderNode_setBottom},
846         {"nGetLeft", "(J)I", (void*)android_view_RenderNode_getLeft},
847         {"nGetTop", "(J)I", (void*)android_view_RenderNode_getTop},
848         {"nGetRight", "(J)I", (void*)android_view_RenderNode_getRight},
849         {"nGetBottom", "(J)I", (void*)android_view_RenderNode_getBottom},
850         {"nSetLeftTopRightBottom", "(JIIII)Z",
851          (void*)android_view_RenderNode_setLeftTopRightBottom},
852         {"nOffsetLeftAndRight", "(JI)Z", (void*)android_view_RenderNode_offsetLeftAndRight},
853         {"nOffsetTopAndBottom", "(JI)Z", (void*)android_view_RenderNode_offsetTopAndBottom},
854 
855         {"nHasOverlappingRendering", "(J)Z",
856          (void*)android_view_RenderNode_hasOverlappingRendering},
857         {"nGetClipToOutline", "(J)Z", (void*)android_view_RenderNode_getClipToOutline},
858         {"nGetAlpha", "(J)F", (void*)android_view_RenderNode_getAlpha},
859         {"nGetCameraDistance", "(J)F", (void*)android_view_RenderNode_getCameraDistance},
860         {"nGetScaleX", "(J)F", (void*)android_view_RenderNode_getScaleX},
861         {"nGetScaleY", "(J)F", (void*)android_view_RenderNode_getScaleY},
862         {"nGetElevation", "(J)F", (void*)android_view_RenderNode_getElevation},
863         {"nGetTranslationX", "(J)F", (void*)android_view_RenderNode_getTranslationX},
864         {"nGetTranslationY", "(J)F", (void*)android_view_RenderNode_getTranslationY},
865         {"nGetTranslationZ", "(J)F", (void*)android_view_RenderNode_getTranslationZ},
866         {"nGetRotation", "(J)F", (void*)android_view_RenderNode_getRotation},
867         {"nGetRotationX", "(J)F", (void*)android_view_RenderNode_getRotationX},
868         {"nGetRotationY", "(J)F", (void*)android_view_RenderNode_getRotationY},
869         {"nIsPivotExplicitlySet", "(J)Z", (void*)android_view_RenderNode_isPivotExplicitlySet},
870         {"nHasIdentityMatrix", "(J)Z", (void*)android_view_RenderNode_hasIdentityMatrix},
871 
872         {"nGetTransformMatrix", "(JJ)V", (void*)android_view_RenderNode_getTransformMatrix},
873         {"nGetInverseTransformMatrix", "(JJ)V",
874          (void*)android_view_RenderNode_getInverseTransformMatrix},
875 
876         {"nGetPivotX", "(J)F", (void*)android_view_RenderNode_getPivotX},
877         {"nGetPivotY", "(J)F", (void*)android_view_RenderNode_getPivotY},
878         {"nGetWidth", "(J)I", (void*)android_view_RenderNode_getWidth},
879         {"nGetHeight", "(J)I", (void*)android_view_RenderNode_getHeight},
880         {"nSetAllowForceDark", "(JZ)Z", (void*)android_view_RenderNode_setAllowForceDark},
881         {"nGetAllowForceDark", "(J)Z", (void*)android_view_RenderNode_getAllowForceDark},
882         {"nGetUniqueId", "(J)J", (void*)android_view_RenderNode_getUniqueId},
883         {"nSetIsTextureView", "(J)V", (void*)android_view_RenderNode_setIsTextureView},
884 };
885 
register_android_view_RenderNode(JNIEnv * env)886 int register_android_view_RenderNode(JNIEnv* env) {
887     jclass clazz = FindClassOrDie(env, "android/graphics/RenderNode$PositionUpdateListener");
888     gPositionListener.clazz = MakeGlobalRefOrDie(env, clazz);
889     gPositionListener.callPositionChanged = GetStaticMethodIDOrDie(
890             env, clazz, "callPositionChanged", "(Ljava/lang/ref/WeakReference;JIIII)Z");
891     gPositionListener.callPositionChanged2 = GetStaticMethodIDOrDie(
892             env, clazz, "callPositionChanged2", "(Ljava/lang/ref/WeakReference;JIIIIIIIIII)Z");
893     gPositionListener.callApplyStretch = GetStaticMethodIDOrDie(
894             env, clazz, "callApplyStretch", "(Ljava/lang/ref/WeakReference;JFFFFFFFFFF)Z");
895     gPositionListener.callPositionLost = GetStaticMethodIDOrDie(
896             env, clazz, "callPositionLost", "(Ljava/lang/ref/WeakReference;J)Z");
897     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
898 }
899 
900 };
901 
902