Merge "Added ability to build for coverage for target" into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / event / common / object-impl.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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
18 // CLASS HEADER
19 #include <dali/internal/event/common/object-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23
24 // INTERNAL INCLUDES
25 #include <dali/integration-api/debug.h>
26 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
27 #include <dali/internal/update/common/animatable-property.h>
28 #include <dali/internal/update/common/property-owner-messages.h>
29 #include <dali/internal/update/common/uniform-map.h>
30 #include <dali/internal/event/animation/constraint-impl.h>
31 #include <dali/internal/event/common/stage-impl.h>
32 #include <dali/internal/event/common/property-notification-impl.h>
33 #include <dali/internal/event/common/type-registry-impl.h>
34
35 using Dali::Internal::SceneGraph::AnimatableProperty;
36 using Dali::Internal::SceneGraph::PropertyBase;
37
38 namespace Dali
39 {
40
41 namespace Internal
42 {
43
44 namespace // unnamed namespace
45 {
46 const int SUPPORTED_CAPABILITIES = Dali::Handle::DYNAMIC_PROPERTIES;  // Object provides this capability
47 typedef Dali::Vector<Object::Observer*>::Iterator ObserverIter;
48 typedef Dali::Vector<Object::Observer*>::ConstIterator ConstObserverIter;
49
50 #if defined(DEBUG_ENABLED)
51 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_OBJECT" );
52 #endif
53
54
55 } // unnamed namespace
56
57 Object::Object()
58 : mEventThreadServices( *Stage::GetCurrent() ),
59   mTypeInfo( NULL ),
60   mConstraints( NULL ),
61   mPropertyNotifications( NULL )
62 {
63 }
64
65 void Object::AddObserver(Observer& observer)
66 {
67   // make sure an observer doesn't observe the same object twice
68   // otherwise it will get multiple calls to OnSceneObjectAdd(), OnSceneObjectRemove() and ObjectDestroyed()
69   DALI_ASSERT_DEBUG( mObservers.End() == std::find( mObservers.Begin(), mObservers.End(), &observer));
70
71   mObservers.PushBack( &observer );
72 }
73
74 void Object::RemoveObserver(Observer& observer)
75 {
76   // Find the observer...
77   const ConstObserverIter endIter =  mObservers.End();
78   for( ObserverIter iter = mObservers.Begin(); iter != endIter; ++iter)
79   {
80     if( (*iter) == &observer)
81     {
82       mObservers.Erase( iter );
83       break;
84     }
85   }
86   DALI_ASSERT_DEBUG(endIter != mObservers.End());
87 }
88
89 void Object::OnSceneObjectAdd()
90 {
91   // Notification for observers
92   for( ConstObserverIter iter = mObservers.Begin(),  endIter =  mObservers.End(); iter != endIter; ++iter)
93   {
94     (*iter)->SceneObjectAdded(*this);
95   }
96
97   // enable property notifications in scene graph
98   EnablePropertyNotifications();
99 }
100
101 void Object::OnSceneObjectRemove()
102 {
103   // Notification for observers
104   for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter )
105   {
106     (*iter)->SceneObjectRemoved(*this);
107   }
108
109   // disable property notifications in scene graph
110   DisablePropertyNotifications();
111 }
112
113 int Object::GetPropertyComponentIndex( Property::Index index ) const
114 {
115   int componentIndex = Property::INVALID_COMPONENT_INDEX;
116
117   const TypeInfo* typeInfo( GetTypeInfo() );
118   if ( typeInfo )
119   {
120     componentIndex = typeInfo->GetComponentIndex(index);
121   }
122
123   // For animatable property, check whether it is registered already and register it if not yet.
124   if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) && ( NULL == RegisterAnimatableProperty(index) ) )
125   {
126     componentIndex = Property::INVALID_COMPONENT_INDEX;
127   }
128
129   return componentIndex;
130 }
131
132 bool Object::Supports( Capability capability ) const
133 {
134   return (capability & SUPPORTED_CAPABILITIES);
135 }
136
137 unsigned int Object::GetPropertyCount() const
138 {
139   unsigned int count = GetDefaultPropertyCount();
140
141   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Default Properties: %d\n", count );
142
143   const TypeInfo* typeInfo( GetTypeInfo() );
144   if ( typeInfo )
145   {
146     unsigned int manual( typeInfo->GetPropertyCount() );
147     count += manual;
148
149     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Manual Properties:  %d\n", manual );
150   }
151
152   unsigned int custom( mCustomProperties.Count() );
153   count += custom;
154   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Custom Properties:  %d\n", custom );
155
156   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Total Properties:   %d\n", count );
157
158   return count;
159 }
160
161 std::string Object::GetPropertyName( Property::Index index ) const
162 {
163   DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index out of bounds" );
164
165   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
166   {
167     std::string string;
168
169     const char * propertyName = GetDefaultPropertyName( index );
170     if( propertyName )
171     {
172       string = propertyName;
173     }
174     return string;
175   }
176
177   if ( ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
178     || ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) ) )
179   {
180     const TypeInfo* typeInfo( GetTypeInfo() );
181     if ( typeInfo )
182     {
183       return typeInfo->GetPropertyName( index );
184     }
185     else
186     {
187       DALI_ASSERT_ALWAYS( ! "Property index is invalid" );
188     }
189   }
190
191   CustomPropertyMetadata* custom = FindCustomProperty( index );
192   if( custom )
193   {
194     return custom->name;
195   }
196   return "";
197 }
198
199 Property::Index Object::GetPropertyIndex(const std::string& name) const
200 {
201   Property::Index index = GetDefaultPropertyIndex( name );
202
203   if(index == Property::INVALID_INDEX)
204   {
205     const TypeInfo* typeInfo( GetTypeInfo() );
206     if ( typeInfo )
207     {
208       index = typeInfo->GetPropertyIndex( name );
209       if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
210       {
211         // check whether the animatable property is registered already, if not then register one.
212         if ( NULL == RegisterAnimatableProperty(index) )
213         {
214           index = Property::INVALID_INDEX;
215         }
216       }
217     }
218   }
219
220   if( (index == Property::INVALID_INDEX)&&( mCustomProperties.Count() > 0 ) )
221   {
222     Property::Index count = PROPERTY_CUSTOM_START_INDEX;
223     const PropertyMetadataLookup::ConstIterator end = mCustomProperties.End();
224     for( PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
225     {
226       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
227       if ( custom->name == name )
228       {
229         if ( custom->childPropertyIndex != Property::INVALID_INDEX )
230         {
231           // If it is a child property, return the child property index
232           index = custom->childPropertyIndex;
233         }
234         else
235         {
236           index = count;
237         }
238         break;
239       }
240     }
241   }
242
243   return index;
244 }
245
246 bool Object::IsPropertyWritable( Property::Index index ) const
247 {
248   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
249
250   bool writable = false;
251
252   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
253   {
254     writable = IsDefaultPropertyWritable( index );
255   }
256   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
257   {
258     const TypeInfo* typeInfo( GetTypeInfo() );
259     if ( typeInfo )
260     {
261       writable = typeInfo->IsPropertyWritable( index );
262     }
263     else
264     {
265       DALI_ASSERT_ALWAYS( ! "Invalid property index" );
266     }
267   }
268   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
269   {
270     // Type Registry scene-graph properties are writable.
271     writable = true;
272   }
273   else
274   {
275     CustomPropertyMetadata* custom = FindCustomProperty( index );
276     if( custom )
277     {
278       writable = custom->IsWritable();
279     }
280   }
281
282   return writable;
283 }
284
285 bool Object::IsPropertyAnimatable( Property::Index index ) const
286 {
287   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
288
289   bool animatable = false;
290
291   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
292   {
293     animatable = IsDefaultPropertyAnimatable( index );
294   }
295   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
296   {
297     // Type Registry event-thread only properties are not animatable.
298     animatable = false;
299   }
300   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
301   {
302     // Type Registry scene-graph properties are animatable.
303     animatable = true;
304   }
305   else
306   {
307     CustomPropertyMetadata* custom = FindCustomProperty( index );
308     if( custom )
309     {
310       animatable = custom->IsAnimatable();
311     }
312   }
313
314   return animatable;
315 }
316
317 bool Object::IsPropertyAConstraintInput( Property::Index index ) const
318 {
319   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
320
321   bool isConstraintInput = false;
322
323   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
324   {
325     isConstraintInput = IsDefaultPropertyAConstraintInput( index );
326   }
327   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
328   {
329     // Type Registry event-thread only properties cannot be used as an input to a constraint.
330     isConstraintInput = false;
331   }
332   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
333   {
334     // scene graph properties can be used as input to a constraint.
335     isConstraintInput = true;
336   }
337   else
338   {
339     CustomPropertyMetadata* custom = FindCustomProperty( index );
340     if( custom )
341     {
342       // ... custom properties can be used as input to a constraint.
343       isConstraintInput = true;
344     }
345   }
346
347   return isConstraintInput;
348 }
349
350 Property::Type Object::GetPropertyType( Property::Index index ) const
351 {
352   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
353
354   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
355   {
356     return GetDefaultPropertyType( index );
357   }
358
359   if ( ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
360     || ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) ) )
361   {
362     const TypeInfo* typeInfo( GetTypeInfo() );
363     if ( typeInfo )
364     {
365       return typeInfo->GetPropertyType( index );
366     }
367     else
368     {
369       DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
370     }
371   }
372
373   CustomPropertyMetadata* custom = FindCustomProperty( index );
374   if( custom )
375   {
376     return custom->GetType();
377   }
378
379   return Property::NONE;
380 }
381
382 void Object::SetProperty( Property::Index index, const Property::Value& propertyValue )
383 {
384   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
385
386   bool propertySet( true );
387
388   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
389   {
390     SetDefaultProperty( index, propertyValue );
391   }
392   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
393   {
394     const TypeInfo* typeInfo( GetTypeInfo() );
395     if ( typeInfo )
396     {
397       typeInfo->SetProperty( this, index, propertyValue );
398     }
399     else
400     {
401       DALI_LOG_ERROR("Cannot find property index\n");
402       propertySet = false;
403     }
404   }
405   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
406   {
407     // check whether the animatable property is registered already, if not then register one.
408     AnimatablePropertyMetadata* animatableProperty = RegisterAnimatableProperty( index );
409     if(!animatableProperty)
410     {
411       DALI_LOG_ERROR("Cannot find property index\n");
412       propertySet = false;
413     }
414     else
415     {
416       // set the scene graph property value
417       SetSceneGraphProperty( index, *animatableProperty, propertyValue );
418     }
419   }
420   else
421   {
422     CustomPropertyMetadata* custom = FindCustomProperty( index );
423
424     if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
425     {
426       if( !custom )
427       {
428         // If the child property is not registered yet, register it.
429         custom = new CustomPropertyMetadata( "", propertyValue, Property::READ_WRITE );
430         mCustomProperties.PushBack( custom );
431       }
432
433       custom->childPropertyIndex = index;
434
435       // Resolve name for the child property
436       Object* parent = GetParentObject();
437       if( parent )
438       {
439         const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
440         if( parentTypeInfo )
441         {
442           custom->name = parentTypeInfo->GetChildPropertyName( index );
443         }
444       }
445     }
446
447     if( custom )
448     {
449       if( custom->IsAnimatable() )
450       {
451         // set the scene graph property value
452         SetSceneGraphProperty( index, *custom, propertyValue );
453       }
454       else if( custom->IsWritable() )
455       {
456         custom->value = propertyValue;
457       }
458       else
459       {
460         // trying to set value on read only property is no-op
461         propertySet = false;
462       }
463     }
464     else
465     {
466       DALI_LOG_ERROR("Invalid property index\n");
467       propertySet = false;
468     }
469   }
470
471   // Let derived classes know that a property has been set
472   // TODO: We should not call this for read-only properties, SetDefaultProperty() && TypeInfo::SetProperty() should return a bool, which would be true if the property is set
473   if ( propertySet )
474   {
475     OnPropertySet(index, propertyValue);
476   }
477 }
478
479 Property::Value Object::GetProperty(Property::Index index) const
480 {
481   DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
482
483   Property::Value value;
484
485   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
486   {
487     value = GetDefaultProperty( index );
488   }
489   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
490   {
491     const TypeInfo* typeInfo( GetTypeInfo() );
492     if ( typeInfo )
493     {
494       value = typeInfo->GetProperty( this, index );
495     }
496     else
497     {
498       DALI_LOG_ERROR("Cannot find property index\n");
499     }
500   }
501   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
502   {
503     // check whether the animatable property is registered already, if not then register one.
504     AnimatablePropertyMetadata* animatableProperty = RegisterAnimatableProperty( index );
505     if(!animatableProperty)
506     {
507       DALI_LOG_ERROR("Cannot find property index\n");
508     }
509     else
510     {
511       // get the animatable property value
512       value = GetPropertyValue( animatableProperty );
513     }
514   }
515   else if(mCustomProperties.Count() > 0)
516   {
517     CustomPropertyMetadata* custom = FindCustomProperty( index );
518     if(custom)
519     {
520       // get the custom property value
521       value = GetPropertyValue( custom );
522     }
523     else
524     {
525       DALI_LOG_ERROR("Invalid property index\n");
526     }
527   } // if custom
528
529   return value;
530 }
531
532 void Object::GetPropertyIndices( Property::IndexContainer& indices ) const
533 {
534   indices.Clear();
535
536   // Default Properties
537   GetDefaultPropertyIndices( indices );
538
539   // Manual Properties
540   const TypeInfo* typeInfo( GetTypeInfo() );
541   if ( typeInfo )
542   {
543     typeInfo->GetPropertyIndices( indices );
544   }
545
546   // Custom Properties
547   if ( mCustomProperties.Count() > 0 )
548   {
549     indices.Reserve( indices.Size() + mCustomProperties.Count() );
550
551     PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin();
552     const PropertyMetadataLookup::ConstIterator endIter = mCustomProperties.End();
553     int i=0;
554     for ( ; iter != endIter; ++iter, ++i )
555     {
556       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( *iter );
557       if ( custom->childPropertyIndex != Property::INVALID_INDEX )
558       {
559         // If it is a child property, add the child property index
560         indices.PushBack( custom->childPropertyIndex );
561       }
562       else
563       {
564         indices.PushBack( PROPERTY_CUSTOM_START_INDEX + i );
565       }
566     }
567   }
568 }
569
570 Property::Index Object::RegisterSceneGraphProperty(const std::string& name, Property::Index index, const Property::Value& propertyValue) const
571 {
572   // Create a new property
573   Dali::Internal::OwnerPointer<PropertyBase> newProperty;
574
575   switch ( propertyValue.GetType() )
576   {
577     case Property::BOOLEAN:
578     {
579       newProperty = new AnimatableProperty<bool>( propertyValue.Get<bool>() );
580       break;
581     }
582
583     case Property::INTEGER:
584     {
585       newProperty = new AnimatableProperty<int>( propertyValue.Get<int>() );
586       break;
587     }
588
589     case Property::FLOAT:
590     {
591       newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
592       break;
593     }
594
595     case Property::VECTOR2:
596     {
597       newProperty = new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>() );
598       break;
599     }
600
601     case Property::VECTOR3:
602     {
603       newProperty = new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>() );
604       break;
605     }
606
607     case Property::VECTOR4:
608     {
609       newProperty = new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>() );
610       break;
611     }
612
613     case Property::MATRIX:
614     {
615       newProperty = new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>() );
616       break;
617     }
618
619     case Property::MATRIX3:
620     {
621       newProperty = new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>() );
622       break;
623     }
624
625     case Property::ROTATION:
626     {
627       newProperty = new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>() );
628       break;
629     }
630
631     case Property::RECTANGLE:
632     case Property::STRING:
633     case Property::ARRAY:
634     case Property::MAP:
635     case Property::NONE:
636     {
637       DALI_ASSERT_ALWAYS( !"PropertyType is not animatable" );
638       break;
639     }
640   }
641
642   // get the scene property owner from derived class
643   const SceneGraph::PropertyOwner* scenePropertyOwner = GetPropertyOwner();
644   // we can only pass properties to scene graph side if there is a scene object
645   if( scenePropertyOwner )
646   {
647     // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
648     const PropertyBase* property = newProperty.Get();
649     if(index >= PROPERTY_CUSTOM_START_INDEX)
650     {
651       mCustomProperties.PushBack( new CustomPropertyMetadata( name, propertyValue.GetType(), property ) );
652     }
653     else
654     {
655       mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, Property::INVALID_COMPONENT_INDEX, propertyValue.GetType(), property ) ); // base property
656     }
657
658     // queue a message to add the property
659     InstallCustomPropertyMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *scenePropertyOwner, newProperty.Release() ); // Message takes ownership
660
661     // notify the derived class (optional) method in case it needs to do some more work on the new property
662     // note! have to use the local pointer as OwnerPointer now points to NULL as it handed over its ownership
663     NotifyScenePropertyInstalled( *property, name, index );
664
665     return index;
666   }
667   else
668   {
669     // property was orphaned and killed so return invalid index
670     return Property::INVALID_INDEX;
671   }
672 }
673
674 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue )
675 {
676   return RegisterProperty( name, propertyValue, Property::ANIMATABLE );
677 }
678
679 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode )
680 {
681   // If property with the required name already exists, then just set it.
682   Property::Index index = GetPropertyIndex( name );
683   if( index != Property::INVALID_INDEX )
684   {
685     SetProperty( index, propertyValue );
686   }
687   else
688   {
689     // Otherwise register the property
690
691     if(Property::ANIMATABLE == accessMode)
692     {
693       index = RegisterSceneGraphProperty( name, PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count(), propertyValue );
694       AddUniformMapping( index, name );
695     }
696     else
697     {
698       // Add entry to the property lookup
699       index = PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count();
700
701       CustomPropertyMetadata* customProperty = new CustomPropertyMetadata( name, propertyValue, accessMode );
702
703       // Resolve index for the child property
704       Object* parent = GetParentObject();
705       if( parent )
706       {
707         const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
708         if( parentTypeInfo )
709         {
710           Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( name );
711           if( childPropertyIndex != Property::INVALID_INDEX )
712           {
713             customProperty->childPropertyIndex = childPropertyIndex;
714             index = childPropertyIndex;
715           }
716         }
717       }
718
719       mCustomProperties.PushBack( customProperty );
720     }
721   }
722
723   return index;
724 }
725
726 Dali::PropertyNotification Object::AddPropertyNotification(Property::Index index,
727                                                                 int componentIndex,
728                                                                 const Dali::PropertyCondition& condition)
729 {
730   if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
731   {
732     if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
733     {
734       DALI_ASSERT_ALWAYS( false && "Property notification added to event side only property." );
735     }
736     else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
737     {
738       // check whether the animatable property is registered already, if not then register one.
739       AnimatablePropertyMetadata* animatable = RegisterAnimatableProperty( index );
740       DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
741     }
742     else if ( mCustomProperties.Count() > 0 )
743     {
744       CustomPropertyMetadata* custom = FindCustomProperty( index );
745       DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
746       DALI_ASSERT_ALWAYS( custom->IsAnimatable() && "Property notification added to event side only property." );
747     }
748   }
749
750   Dali::Handle self(this);
751   Property target( self, index );
752
753   PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
754   Dali::PropertyNotification propertyNotification(internal.Get());
755
756   if( !mPropertyNotifications )
757   {
758     mPropertyNotifications = new PropertyNotificationContainer;
759   }
760   mPropertyNotifications->push_back(propertyNotification);
761
762   return propertyNotification;
763 }
764
765 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
766 {
767   if( mPropertyNotifications )
768   {
769     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
770     while(iter != mPropertyNotifications->end() )
771     {
772       if(*iter == propertyNotification)
773       {
774         mPropertyNotifications->erase(iter);
775         // As we can't ensure all references are removed, we can just disable
776         // the notification.
777         GetImplementation(propertyNotification).Disable();
778         return;
779       }
780       ++iter;
781     }
782   }
783 }
784
785 void Object::RemovePropertyNotifications()
786 {
787   if( mPropertyNotifications )
788   {
789     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
790     while(iter != mPropertyNotifications->end() )
791     {
792       // As we can't ensure all references are removed, we can just disable
793       // the notification.
794       GetImplementation(*iter).Disable();
795       ++iter;
796     }
797
798     mPropertyNotifications->clear();
799   }
800 }
801
802 void Object::EnablePropertyNotifications()
803 {
804   if( mPropertyNotifications )
805   {
806     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
807     PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
808
809     for( ; iter != endIter; ++iter )
810     {
811       GetImplementation(*iter).Enable();
812     }
813   }
814 }
815
816 void Object::DisablePropertyNotifications()
817 {
818   if( mPropertyNotifications )
819   {
820     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
821     PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
822
823     for( ; iter != endIter; ++iter )
824     {
825       GetImplementation(*iter).Disable();
826     }
827   }
828 }
829
830 void Object::AddUniformMapping( Property::Index propertyIndex, const std::string& uniformName ) const
831 {
832   // Get the address of the property if it's a scene property
833   const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty( propertyIndex );
834
835   // Check instead for newly registered properties
836   if( propertyPtr == NULL )
837   {
838     PropertyMetadata* animatable = FindAnimatableProperty( propertyIndex );
839     if( animatable != NULL )
840     {
841       propertyPtr = animatable->GetSceneGraphProperty();
842     }
843   }
844
845   if( propertyPtr == NULL )
846   {
847     PropertyMetadata* custom = FindCustomProperty( propertyIndex );
848     if( custom != NULL )
849     {
850       propertyPtr = custom->GetSceneGraphProperty();
851     }
852   }
853
854   if( propertyPtr != NULL )
855   {
856     const SceneGraph::PropertyOwner* sceneObject = GetPropertyOwner();
857
858     if( sceneObject != NULL )
859     {
860       SceneGraph::UniformPropertyMapping* map = new SceneGraph::UniformPropertyMapping( uniformName, propertyPtr );
861       // Message takes ownership of Uniform map (and will delete it after copy)
862       AddUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *sceneObject, map);
863     }
864     else
865     {
866       DALI_ASSERT_ALWAYS(0 && "MESH_REWORK - Need to store property whilst off-stage" );
867     }
868   }
869 }
870
871 void Object::RemoveUniformMapping( const std::string& uniformName )
872 {
873   const SceneGraph::PropertyOwner* sceneObject = GetSceneObject();
874   RemoveUniformMapMessage( GetEventThreadServices(), *sceneObject, uniformName);
875 }
876
877 Property::Value Object::GetPropertyValue( const PropertyMetadata* entry ) const
878 {
879   Property::Value value;
880
881   DALI_ASSERT_ALWAYS( entry && "Invalid property metadata" );
882
883   if( !entry->IsAnimatable() )
884   {
885     value = entry->value;
886   }
887   else
888   {
889     BufferIndex bufferIndex( GetEventThreadServices().GetEventBufferIndex() );
890
891     switch ( entry->GetType() )
892     {
893       case Property::BOOLEAN:
894       {
895         const AnimatableProperty<bool>* property = static_cast< const AnimatableProperty<bool>* >( entry->GetSceneGraphProperty() );
896         DALI_ASSERT_DEBUG( NULL != property );
897
898         value = (*property)[ bufferIndex ];
899         break;
900       }
901
902       case Property::INTEGER:
903       {
904         const AnimatableProperty<int>* property = static_cast< const AnimatableProperty<int>* >( entry->GetSceneGraphProperty() );
905         DALI_ASSERT_DEBUG( NULL != property );
906
907         value = (*property)[ bufferIndex ];
908         break;
909       }
910
911       case Property::FLOAT:
912       {
913         const AnimatableProperty<float>* property = static_cast< const AnimatableProperty<float>* >( entry->GetSceneGraphProperty() );
914         DALI_ASSERT_DEBUG( NULL != property );
915
916         value = (*property)[ bufferIndex ];
917         break;
918       }
919
920       case Property::VECTOR2:
921       {
922         const AnimatableProperty<Vector2>* property = static_cast< const AnimatableProperty<Vector2>* >( entry->GetSceneGraphProperty() );
923         DALI_ASSERT_DEBUG( NULL != property );
924
925         if(entry->componentIndex == 0)
926         {
927           value = (*property)[ bufferIndex ].x;
928         }
929         else if(entry->componentIndex == 1)
930         {
931           value = (*property)[ bufferIndex ].y;
932         }
933         else
934         {
935           value = (*property)[ bufferIndex ];
936         }
937         break;
938       }
939
940       case Property::VECTOR3:
941       {
942         const AnimatableProperty<Vector3>* property = static_cast< const AnimatableProperty<Vector3>* >( entry->GetSceneGraphProperty() );
943         DALI_ASSERT_DEBUG( NULL != property );
944
945         if(entry->componentIndex == 0)
946         {
947           value = (*property)[ bufferIndex ].x;
948         }
949         else if(entry->componentIndex == 1)
950         {
951           value = (*property)[ bufferIndex ].y;
952         }
953         else if(entry->componentIndex == 2)
954         {
955           value = (*property)[ bufferIndex ].z;
956         }
957         else
958         {
959           value = (*property)[ bufferIndex ];
960         }
961         break;
962       }
963
964       case Property::VECTOR4:
965       {
966         const AnimatableProperty<Vector4>* property = static_cast< const AnimatableProperty<Vector4>* >( entry->GetSceneGraphProperty() );
967         DALI_ASSERT_DEBUG( NULL != property );
968
969         if(entry->componentIndex == 0)
970         {
971           value = (*property)[ bufferIndex ].x;
972         }
973         else if(entry->componentIndex == 1)
974         {
975           value = (*property)[ bufferIndex ].y;
976         }
977         else if(entry->componentIndex == 2)
978         {
979           value = (*property)[ bufferIndex ].z;
980         }
981         else if(entry->componentIndex == 3)
982         {
983           value = (*property)[ bufferIndex ].w;
984         }
985         else
986         {
987           value = (*property)[ bufferIndex ];
988         }
989         break;
990       }
991
992       case Property::MATRIX:
993       {
994         const AnimatableProperty<Matrix>* property = static_cast< const AnimatableProperty<Matrix>* >( entry->GetSceneGraphProperty() );
995         DALI_ASSERT_DEBUG( NULL != property );
996
997         value = (*property)[ bufferIndex ];
998         break;
999       }
1000
1001       case Property::MATRIX3:
1002       {
1003         const AnimatableProperty<Matrix3>* property = static_cast< const AnimatableProperty<Matrix3>* >( entry->GetSceneGraphProperty() );
1004         DALI_ASSERT_DEBUG( NULL != property );
1005
1006         value = (*property)[ bufferIndex ];
1007         break;
1008       }
1009
1010       case Property::ROTATION:
1011       {
1012         const AnimatableProperty<Quaternion>* property = static_cast< const AnimatableProperty<Quaternion>* >( entry->GetSceneGraphProperty() );
1013         DALI_ASSERT_DEBUG( NULL != property );
1014
1015         value = (*property)[ bufferIndex ];
1016         break;
1017       }
1018
1019       default:
1020       {
1021         DALI_ASSERT_ALWAYS( false && "PropertyType enumeration is out of bounds" );
1022         break;
1023       }
1024     } // switch(type)
1025   } // if animatable
1026
1027   return value;
1028 }
1029
1030 void Object::SetSceneGraphProperty( Property::Index index, const PropertyMetadata& entry, const Property::Value& value )
1031 {
1032   switch ( entry.GetType() )
1033   {
1034     case Property::BOOLEAN:
1035     {
1036       const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1037       DALI_ASSERT_DEBUG( NULL != property );
1038
1039       // property is being used in a separate thread; queue a message to set the property
1040       BakeMessage<bool>( GetEventThreadServices(), *property, value.Get<bool>() );
1041       break;
1042     }
1043
1044     case Property::INTEGER:
1045     {
1046       const AnimatableProperty<int>* property = dynamic_cast< const AnimatableProperty<int>* >( entry.GetSceneGraphProperty() );
1047       DALI_ASSERT_DEBUG( NULL != property );
1048
1049       // property is being used in a separate thread; queue a message to set the property
1050       BakeMessage<int>( GetEventThreadServices(), *property, value.Get<int>() );
1051       break;
1052     }
1053
1054     case Property::FLOAT:
1055     {
1056       const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1057       DALI_ASSERT_DEBUG( NULL != property );
1058
1059       // property is being used in a separate thread; queue a message to set the property
1060       BakeMessage<float>( GetEventThreadServices(), *property, value.Get<float>() );
1061       break;
1062     }
1063
1064     case Property::VECTOR2:
1065     {
1066       const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1067       DALI_ASSERT_DEBUG( NULL != property );
1068
1069       // property is being used in a separate thread; queue a message to set the property
1070       if(entry.componentIndex == 0)
1071       {
1072         SetXComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1073       }
1074       else if(entry.componentIndex == 1)
1075       {
1076         SetYComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1077       }
1078       else
1079       {
1080         BakeMessage<Vector2>( GetEventThreadServices(), *property, value.Get<Vector2>() );
1081       }
1082       break;
1083     }
1084
1085     case Property::VECTOR3:
1086     {
1087       const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1088       DALI_ASSERT_DEBUG( NULL != property );
1089
1090       // property is being used in a separate thread; queue a message to set the property
1091       if(entry.componentIndex == 0)
1092       {
1093         SetXComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1094       }
1095       else if(entry.componentIndex == 1)
1096       {
1097         SetYComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1098       }
1099       else if(entry.componentIndex == 2)
1100       {
1101         SetZComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1102       }
1103       else
1104       {
1105         BakeMessage<Vector3>( GetEventThreadServices(), *property, value.Get<Vector3>() );
1106       }
1107
1108       break;
1109     }
1110
1111     case Property::VECTOR4:
1112     {
1113       const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
1114       DALI_ASSERT_DEBUG( NULL != property );
1115
1116       // property is being used in a separate thread; queue a message to set the property
1117       if(entry.componentIndex == 0)
1118       {
1119         SetXComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1120       }
1121       else if(entry.componentIndex == 1)
1122       {
1123         SetYComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1124       }
1125       else if(entry.componentIndex == 2)
1126       {
1127         SetZComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1128       }
1129       else if(entry.componentIndex == 3)
1130       {
1131         SetWComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1132       }
1133       else
1134       {
1135         BakeMessage<Vector4>( GetEventThreadServices(), *property, value.Get<Vector4>() );
1136       }
1137       break;
1138     }
1139
1140     case Property::ROTATION:
1141     {
1142       const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1143       DALI_ASSERT_DEBUG( NULL != property );
1144
1145       // property is being used in a separate thread; queue a message to set the property
1146       BakeMessage<Quaternion>( GetEventThreadServices(), *property, value.Get<Quaternion>() );
1147       break;
1148     }
1149
1150     case Property::MATRIX:
1151     {
1152       const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1153       DALI_ASSERT_DEBUG( NULL != property );
1154
1155       // property is being used in a separate thread; queue a message to set the property
1156       BakeMessage<Matrix>( GetEventThreadServices(), *property, value.Get<Matrix>() );
1157       break;
1158     }
1159
1160     case Property::MATRIX3:
1161     {
1162       const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1163       DALI_ASSERT_DEBUG( NULL != property );
1164
1165       // property is being used in a separate thread; queue a message to set the property
1166       BakeMessage<Matrix3>( GetEventThreadServices(), *property, value.Get<Matrix3>() );
1167       break;
1168     }
1169
1170     default:
1171     {
1172       // non-animatable scene graph property, do nothing
1173     }
1174   }
1175 }
1176
1177 const TypeInfo* Object::GetTypeInfo() const
1178 {
1179   if ( !mTypeInfo )
1180   {
1181     // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1182     // especially as the type-info does not change during the life-time of an application
1183
1184     Dali::TypeInfo typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
1185     if ( typeInfoHandle )
1186     {
1187       mTypeInfo = &GetImplementation( typeInfoHandle );
1188     }
1189   }
1190
1191   return mTypeInfo;
1192 }
1193
1194 void Object::ApplyConstraint( ConstraintBase& constraint )
1195 {
1196   if( !mConstraints )
1197   {
1198     mConstraints = new ConstraintContainer;
1199   }
1200   mConstraints->push_back( Dali::Constraint( &constraint ) );
1201 }
1202
1203 void Object::RemoveConstraint( ConstraintBase& constraint )
1204 {
1205   // NULL if the Constraint sources are destroyed before Constraint::Apply()
1206   if( mConstraints )
1207   {
1208     ConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), Dali::Constraint( &constraint ) ) );
1209     if( it != mConstraints->end() )
1210     {
1211       mConstraints->erase( it );
1212     }
1213   }
1214 }
1215
1216 void Object::RemoveConstraints()
1217 {
1218   // guard against constraint sending messages during core destruction
1219   if( mConstraints && Stage::IsInstalled() )
1220   {
1221     // If we have nothing in the scene-graph, just clear constraint containers
1222     const SceneGraph::PropertyOwner* propertyOwner = GetSceneObject();
1223     if ( NULL != propertyOwner )
1224     {
1225       const ConstraintConstIter endIter = mConstraints->end();
1226       for ( ConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
1227       {
1228         GetImplementation( *iter ).RemoveInternal();
1229       }
1230     }
1231
1232     delete mConstraints;
1233     mConstraints = NULL;
1234   }
1235 }
1236
1237 void Object::RemoveConstraints( unsigned int tag )
1238 {
1239   // guard against constraint sending messages during core destruction
1240   if( mConstraints && Stage::IsInstalled() )
1241   {
1242     ConstraintIter iter( mConstraints->begin() );
1243     while(iter != mConstraints->end() )
1244     {
1245       ConstraintBase& constraint = GetImplementation( *iter );
1246       if( constraint.GetTag() == tag )
1247       {
1248         GetImplementation( *iter ).RemoveInternal();
1249         iter = mConstraints->erase( iter );
1250       }
1251       else
1252       {
1253         ++iter;
1254       }
1255     }
1256
1257     if ( mConstraints->empty() )
1258     {
1259       delete mConstraints;
1260       mConstraints = NULL;
1261     }
1262   }
1263 }
1264
1265 void Object::SetTypeInfo( const TypeInfo* typeInfo )
1266 {
1267   mTypeInfo = typeInfo;
1268 }
1269
1270 Object::~Object()
1271 {
1272   // Notification for observers
1273   for( ConstObserverIter iter = mObservers.Begin(), endIter =  mObservers.End(); iter != endIter; ++iter)
1274   {
1275     (*iter)->ObjectDestroyed(*this);
1276   }
1277
1278   delete mConstraints;
1279   delete mPropertyNotifications;
1280 }
1281
1282 CustomPropertyMetadata* Object::FindCustomProperty( Property::Index index ) const
1283 {
1284   CustomPropertyMetadata* property( NULL );
1285   int arrayIndex;
1286   if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
1287   {
1288     for ( arrayIndex = 0; arrayIndex < (int)mCustomProperties.Count(); arrayIndex++ )
1289     {
1290       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
1291       if( custom->childPropertyIndex == index )
1292       {
1293         property = custom;
1294       }
1295     }
1296   }
1297   else
1298   {
1299     arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1300     if( arrayIndex >= 0 )
1301     {
1302       if( arrayIndex < (int)mCustomProperties.Count() ) // we can only access the first 2 billion custom properties
1303       {
1304         property = static_cast<CustomPropertyMetadata*>(mCustomProperties[ arrayIndex ]);
1305       }
1306     }
1307   }
1308   return property;
1309 }
1310
1311 AnimatablePropertyMetadata* Object::FindAnimatableProperty( Property::Index index ) const
1312 {
1313   for ( int arrayIndex = 0; arrayIndex < (int)mAnimatableProperties.Count(); arrayIndex++ )
1314   {
1315     AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>( mAnimatableProperties[ arrayIndex ] );
1316     if( property->index == index )
1317     {
1318       return property;
1319     }
1320   }
1321   return NULL;
1322 }
1323
1324 AnimatablePropertyMetadata* Object::RegisterAnimatableProperty(Property::Index index) const
1325 {
1326   DALI_ASSERT_ALWAYS( (( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ))
1327                       && "Property index is out of bounds" );
1328
1329   // check whether the animatable property is registered already, if not then register one.
1330   AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
1331   if(!animatableProperty)
1332   {
1333     const TypeInfo* typeInfo( GetTypeInfo() );
1334     if (typeInfo)
1335     {
1336       Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex(index);
1337       if(basePropertyIndex == Property::INVALID_INDEX)
1338       {
1339         // If the property is not a component of a base property, register the whole property itself.
1340         const  std::string& propertyName = typeInfo->GetPropertyName(index);
1341         RegisterSceneGraphProperty(propertyName, index, typeInfo->GetPropertyDefaultValue(index));
1342         AddUniformMapping( index, propertyName );
1343       }
1344       else
1345       {
1346         // Since the property is a component of a base property, check whether the base property is regsitered.
1347         animatableProperty = FindAnimatableProperty( basePropertyIndex );
1348         if(!animatableProperty)
1349         {
1350           // If the base property is not registered yet, register the base property first.
1351           const  std::string& basePropertyName = typeInfo->GetPropertyName(basePropertyIndex);
1352           if(Property::INVALID_INDEX != RegisterSceneGraphProperty(basePropertyName, basePropertyIndex, Property::Value(typeInfo->GetPropertyType(basePropertyIndex))))
1353           {
1354             animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1355             AddUniformMapping( basePropertyIndex, basePropertyName );
1356           }
1357         }
1358
1359         if(animatableProperty)
1360         {
1361           // Create the metadata for the property component.
1362           mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, typeInfo->GetComponentIndex(index), animatableProperty->GetType(), animatableProperty->GetSceneGraphProperty() ) );
1363         }
1364       }
1365
1366       // The metadata has just been added and therefore should be in the end of the vector.
1367       animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1368     }
1369   }
1370
1371   return animatableProperty;
1372 }
1373
1374 void Object::ResolveChildProperties()
1375 {
1376   // Resolve index for the child property
1377   Object* parent = GetParentObject();
1378   if( parent )
1379   {
1380     const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
1381     if( parentTypeInfo )
1382     {
1383       // Go through each custom property
1384       for ( int arrayIndex = 0; arrayIndex < (int)mCustomProperties.Count(); arrayIndex++ )
1385       {
1386         CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
1387
1388         if( customProperty->name == "" )
1389         {
1390           if( customProperty->childPropertyIndex != Property::INVALID_INDEX )
1391           {
1392             // Resolve name for any child property with no name
1393             customProperty->name = parentTypeInfo->GetChildPropertyName( customProperty->childPropertyIndex );
1394           }
1395         }
1396         else
1397         {
1398           Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( customProperty->name );
1399           if( childPropertyIndex != Property::INVALID_INDEX )
1400           {
1401             // Resolve index for any property with a name that matches the parent's child property name
1402             customProperty->childPropertyIndex = childPropertyIndex;
1403           }
1404         }
1405       }
1406     }
1407   }
1408 }
1409
1410 } // namespace Internal
1411
1412 } // namespace Dali