[NUI.Scene3D] Fix exception when ModelNode don't have ModelNode as child
authorEunki, Hong <eunkiki.hong@samsung.com>
Tue, 14 Nov 2023 08:17:11 +0000 (17:17 +0900)
committerJaehyun Cho <jaehyun0cho@gmail.com>
Wed, 15 Nov 2023 07:09:04 +0000 (16:09 +0900)
If ModelNode don't have ModelNod as child, it might have
some null handle exception when we DownCast to ModelNode.
(For example, user try to get child ModelNode, but failed.)

Currently, a lots of app don't consider ModelNode now. But in future
we might need to add something under each ModelNode.

To make Scene3D more safety, let we check null or invalidate,
and then get/set the value internally.

Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
src/Tizen.NUI.Scene3D/src/public/Controls/Model.cs
src/Tizen.NUI.Scene3D/src/public/ModelComponents/ModelNode.cs

index 125e0d3..2b15638 100755 (executable)
@@ -209,12 +209,17 @@ namespace Tizen.NUI.Scene3D
             {
                 // Store the value of PositionUsesAnchorPoint from dali object (Since View object automatically change PositionUsesPivotPoint value as false, we need to keep value.)
                 HandleRef handle = new HandleRef(this, cPtr);
-                bool originalPositionUsesAnchorPoint = Object.InternalGetPropertyBool(handle, View.Property.PositionUsesAnchorPoint);
+
+                // Use original value as 'true' if we got invalid ModelNode.
+                bool originalPositionUsesAnchorPoint = (cPtr == global::System.IntPtr.Zero || !Tizen.NUI.Interop.BaseHandle.HasBody(handle)) || Object.InternalGetPropertyBool(handle, View.Property.PositionUsesAnchorPoint);
                 handle = new HandleRef(null, IntPtr.Zero);
 
                 // Register new animatable into Registry.
                 ret = new ModelNode(cPtr, true);
-                ret.PositionUsesPivotPoint = originalPositionUsesAnchorPoint;
+                if (ret != null)
+                {
+                    ret.PositionUsesPivotPoint = originalPositionUsesAnchorPoint;
+                }
             }
             else
             {
@@ -585,12 +590,17 @@ namespace Tizen.NUI.Scene3D
             {
                 // Store the value of PositionUsesAnchorPoint from dali object (Since View object automatically change PositionUsesPivotPoint value as false, we need to keep value.)
                 HandleRef handle = new HandleRef(this, cPtr);
-                bool originalPositionUsesAnchorPoint = Object.InternalGetPropertyBool(handle, View.Property.PositionUsesAnchorPoint);
+
+                // Use original value as 'true' if we got invalid ModelNode.
+                bool originalPositionUsesAnchorPoint = (cPtr == global::System.IntPtr.Zero || !Tizen.NUI.Interop.BaseHandle.HasBody(handle)) || Object.InternalGetPropertyBool(handle, View.Property.PositionUsesAnchorPoint);
                 handle = new HandleRef(null, IntPtr.Zero);
 
                 // Register new animatable into Registry.
                 ret = new ModelNode(cPtr, true);
-                ret.PositionUsesPivotPoint = originalPositionUsesAnchorPoint;
+                if (ret != null)
+                {
+                    ret.PositionUsesPivotPoint = originalPositionUsesAnchorPoint;
+                }
             }
             else
             {
@@ -626,7 +636,7 @@ namespace Tizen.NUI.Scene3D
 
         private void OnResourcesLoaded(object sender, EventArgs e)
         {
-            if(!isBuilt && this.ModelRoot != null)
+            if (!isBuilt && this.ModelRoot != null)
             {
                 this.ModelRoot.Build();
                 isBuilt = true;
index c0dc91b..64f15bb 100755 (executable)
@@ -180,12 +180,17 @@ namespace Tizen.NUI.Scene3D
             {
                 // Store the value of PositionUsesAnchorPoint from dali object (Since View object automatically change PositionUsesPivotPoint value as false, we need to keep value.)
                 HandleRef handle = new HandleRef(this, cPtr);
-                bool originalPositionUsesAnchorPoint = Object.InternalGetPropertyBool(handle, View.Property.PositionUsesAnchorPoint);
+
+                // Use original value as 'true' if we got invalid ModelNode.
+                bool originalPositionUsesAnchorPoint = (cPtr == global::System.IntPtr.Zero || !Tizen.NUI.Interop.BaseHandle.HasBody(handle)) || Object.InternalGetPropertyBool(handle, View.Property.PositionUsesAnchorPoint);
                 handle = new HandleRef(null, IntPtr.Zero);
 
                 // Register new animatable into Registry.
                 ret = new ModelNode(cPtr, true);
-                ret.PositionUsesPivotPoint = originalPositionUsesAnchorPoint;
+                if (ret != null)
+                {
+                    ret.PositionUsesPivotPoint = originalPositionUsesAnchorPoint;
+                }
             }
             else
             {
@@ -219,14 +224,17 @@ namespace Tizen.NUI.Scene3D
         {
             List<ModelNode> childModelNodes = new List<ModelNode>();
             uint childModelNodeCount = GetChildModelNodeCount();
-            for(uint i = 0; i < childModelNodeCount; ++i)
+            for (uint i = 0; i < childModelNodeCount; ++i)
             {
                 ModelNode modelNode = GetChildModelNodeAt(i);
-                childModelNodes.Add(modelNode);
-                modelNode.Build();
+                if (modelNode != null)
+                {
+                    childModelNodes.Add(modelNode);
+                    modelNode.Build();
+                }
             }
 
-            foreach(ModelNode node in childModelNodes)
+            foreach (ModelNode node in childModelNodes)
             {
                 this.Add(node);
             }
@@ -260,12 +268,17 @@ namespace Tizen.NUI.Scene3D
             {
                 // Store the value of PositionUsesAnchorPoint from dali object (Since View object automatically change PositionUsesPivotPoint value as false, we need to keep value.)
                 HandleRef handle = new HandleRef(this, cPtr);
-                bool originalPositionUsesAnchorPoint = Object.InternalGetPropertyBool(handle, View.Property.PositionUsesAnchorPoint);
+
+                // Use original value as 'true' if we got invalid ModelNode.
+                bool originalPositionUsesAnchorPoint = (cPtr == global::System.IntPtr.Zero || !Tizen.NUI.Interop.BaseHandle.HasBody(handle)) || Object.InternalGetPropertyBool(handle, View.Property.PositionUsesAnchorPoint);
                 handle = new HandleRef(null, IntPtr.Zero);
 
                 // Register new animatable into Registry.
                 ret = new ModelNode(cPtr, true);
-                ret.PositionUsesPivotPoint = originalPositionUsesAnchorPoint;
+                if (ret != null)
+                {
+                    ret.PositionUsesPivotPoint = originalPositionUsesAnchorPoint;
+                }
             }
             else
             {