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