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