Added test cases and fixed bugs
[platform/core/uifw/dali-core.git] / dali / internal / event / common / property-buffer-impl.cpp
1 /*
2  * Copyright (c) 2015 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/property-buffer-impl.h>  // Dali::Internal::PropertyBuffer
20
21 // EXTERNAL INCLUDE
22 #include <algorithm> // std::sort
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/object/property-buffer.h> // Dali::Internal::PropertyBuffer
26 #include <dali/internal/event/common/object-impl-helper.h> // Dali::Internal::ObjectHelper
27 #include <dali/internal/event/common/property-helper.h> // DALI_PROPERTY_TABLE_BEGIN, DALI_PROPERTY, DALI_PROPERTY_TABLE_END
28 #include <dali/internal/update/common/scene-graph-property-buffer.h>
29 #include <dali/internal/update/manager/update-manager.h>
30
31 namespace Dali
32 {
33 namespace Internal
34 {
35
36 using SceneGraph::PropertyBufferMetadata::Format;
37 using SceneGraph::PropertyBufferMetadata::Component;
38
39 namespace
40 {
41
42 /**
43  *            |name    |type             |writable|animatable|constraint-input|enum for index-checking|
44  */
45 DALI_PROPERTY_TABLE_BEGIN
46 DALI_PROPERTY( "size",          UNSIGNED_INTEGER, true, false,  true,   Dali::PropertyBuffer::Property::SIZE )
47 DALI_PROPERTY( "buffer-format", MAP,              false, false, false,  Dali::PropertyBuffer::Property::BUFFER_FORMAT )
48 DALI_PROPERTY_TABLE_END( DEFAULT_ACTOR_PROPERTY_START_INDEX )
49
50 const ObjectImplHelper<DEFAULT_PROPERTY_COUNT> PROPERTY_BUFFER_IMPL = { DEFAULT_PROPERTY_DETAILS };
51
52 /**
53  * Calculate the alignment requirements of a type
54  *
55  * This is used to calculate the memory alignment requirements of a type
56  * It creates a structure with a dummy char and a member of the type we want to check
57  * this will cause the second member to be aligned by it's alignment requirement.
58  */
59 template<Property::Type type>
60 struct PropertyImplementationTypeAlignment
61 {
62   // Create a structure that forces alignment of the data type
63   struct TestStructure
64   {
65     char oneChar;  ///< Member with sizeof() == 1
66     typename PropertyImplementationType<type>::Type data;
67   };
68   enum { VALUE = offsetof( TestStructure, data ) };
69 };
70
71 unsigned int GetPropertyImplementationAlignment( Property::Type& propertyType )
72 {
73   unsigned int alignment = 0u;
74
75   switch( propertyType )
76   {
77     case Property::NONE:
78     case Property::TYPE_COUNT:
79     case Property::STRING:
80     case Property::ARRAY:
81     case Property::MAP:
82     {
83       DALI_ASSERT_ALWAYS( "No size for properties with no type, or dynamic sizes" );
84       break;
85     }
86     case Property::BOOLEAN:
87     {
88       alignment = PropertyImplementationTypeAlignment< Property::BOOLEAN >::VALUE;
89       break;
90     }
91     case Property::INTEGER:
92     {
93       alignment = PropertyImplementationTypeAlignment< Property::INTEGER >::VALUE;
94       break;
95     }
96     case Property::UNSIGNED_INTEGER:
97     {
98       alignment = PropertyImplementationTypeAlignment< Property::UNSIGNED_INTEGER >::VALUE;
99       break;
100     }
101     case Property::FLOAT:
102     {
103       alignment = PropertyImplementationTypeAlignment< Property::FLOAT >::VALUE;
104       break;
105     }
106     case Property::VECTOR2:
107     {
108       alignment = PropertyImplementationTypeAlignment< Property::VECTOR2 >::VALUE;
109       break;
110     }
111     case Property::VECTOR3:
112     {
113       alignment = PropertyImplementationTypeAlignment< Property::VECTOR3 >::VALUE;
114       break;
115     }
116     case Property::VECTOR4:
117     {
118       alignment = PropertyImplementationTypeAlignment< Property::VECTOR4 >::VALUE;
119       break;
120     }
121     case Property::MATRIX3:
122     {
123       alignment = PropertyImplementationTypeAlignment< Property::MATRIX3 >::VALUE;
124       break;
125     }
126     case Property::MATRIX:
127     {
128       alignment = PropertyImplementationTypeAlignment< Property::MATRIX >::VALUE;
129       break;
130     }
131     case Property::RECTANGLE:
132     {
133       alignment = PropertyImplementationTypeAlignment< Property::RECTANGLE >::VALUE;
134       break;
135     }
136     case Property::ROTATION:
137     {
138       alignment = PropertyImplementationTypeAlignment< Property::ROTATION >::VALUE;
139       break;
140     }
141   }
142
143   return alignment;
144 }
145
146 } // unnamed namespace
147
148 PropertyBufferPtr PropertyBuffer::New()
149 {
150   PropertyBufferPtr propertyBuffer( new PropertyBuffer() );
151   propertyBuffer->Initialize();
152
153   return propertyBuffer;
154 }
155
156 void PropertyBuffer::SetSize( std::size_t size )
157 {
158   mSize = size;
159
160   SizeChanged();
161
162   SceneGraph::SetSizeMessage( GetEventThreadServices(),
163                               *mSceneObject,
164                               mSize );
165 }
166
167 std::size_t PropertyBuffer::GetSize() const
168 {
169   return mSize;
170 }
171
172 void PropertyBuffer::SetData( const void* data )
173 {
174   DALI_ASSERT_DEBUG( mFormat.Count() && "Format must be set before setting the data." );
175
176   DALI_ASSERT_ALWAYS( mSize && "Size of the buffer must be set before setting the data." );
177
178   const char* source = static_cast<const char*>( data );
179   std::copy( source, source + mBuffer.Size(), &mBuffer[0] );
180
181   SceneGraph::SetDataMessage( GetEventThreadServices(),
182                               *mSceneObject,
183                               new SceneGraph::PropertyBuffer::BufferType( mBuffer ) );
184 }
185
186 Dali::Property::Index PropertyBuffer::GetPropertyIndex( const std::string name, std::size_t index )
187 {
188   //TODO: MESH_REWORK
189   DALI_ASSERT_ALWAYS( false && "MESH_REWORK" );
190   return 0;
191 }
192
193 const SceneGraph::PropertyBuffer* PropertyBuffer::GetPropertyBufferSceneObject() const
194 {
195   return mSceneObject;
196 }
197
198 void PropertyBuffer::SetType( Dali::PropertyBuffer::Type type )
199 {
200   DALI_ASSERT_DEBUG( mType == Dali::PropertyBuffer::TYPE_COUNT && "Type can only be set once." );
201   DALI_ASSERT_DEBUG( type != Dali::PropertyBuffer::TYPE_COUNT && "Type must be set to a valid value." );
202
203   mType = type;
204 }
205
206 void PropertyBuffer::SetFormat( Dali::Property::Map& format )
207 {
208   DALI_ASSERT_ALWAYS( format.Count() && "Format cannot be empty." );
209
210   DALI_ASSERT_DEBUG( 0 == mFormat.Count() && "Format of property buffer can only be set once." );
211
212   mFormat = format;
213
214   FormatChanged();
215 }
216
217 unsigned int PropertyBuffer::GetDefaultPropertyCount() const
218 {
219   return PROPERTY_BUFFER_IMPL.GetDefaultPropertyCount();
220 }
221
222 void PropertyBuffer::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
223 {
224   PROPERTY_BUFFER_IMPL.GetDefaultPropertyIndices( indices );
225 }
226
227 const char* PropertyBuffer::GetDefaultPropertyName(Property::Index index) const
228 {
229   return PROPERTY_BUFFER_IMPL.GetDefaultPropertyName( index );
230 }
231
232 Property::Index PropertyBuffer::GetDefaultPropertyIndex( const std::string& name ) const
233 {
234   return PROPERTY_BUFFER_IMPL.GetDefaultPropertyIndex( name );
235 }
236
237 bool PropertyBuffer::IsDefaultPropertyWritable( Property::Index index ) const
238 {
239   return PROPERTY_BUFFER_IMPL.IsDefaultPropertyWritable( index );
240 }
241
242 bool PropertyBuffer::IsDefaultPropertyAnimatable( Property::Index index ) const
243 {
244   return PROPERTY_BUFFER_IMPL.IsDefaultPropertyAnimatable( index );
245 }
246
247 bool PropertyBuffer::IsDefaultPropertyAConstraintInput( Property::Index index ) const
248 {
249   return PROPERTY_BUFFER_IMPL.IsDefaultPropertyAConstraintInput( index );
250 }
251
252 Property::Type PropertyBuffer::GetDefaultPropertyType( Property::Index index ) const
253 {
254   return PROPERTY_BUFFER_IMPL.GetDefaultPropertyType( index );
255 }
256
257 void PropertyBuffer::SetDefaultProperty( Property::Index index,
258                                          const Property::Value& propertyValue )
259 {
260   switch( index )
261   {
262     case Dali::PropertyBuffer::Property::SIZE:
263     {
264       SetSize( propertyValue.Get<int>() );
265       break;
266     }
267     case Dali::PropertyBuffer::Property::BUFFER_FORMAT:
268     {
269       DALI_ASSERT_ALWAYS( 0 && "MESH_REWORK" );
270       break;
271     }
272   }
273 }
274
275 void PropertyBuffer::SetSceneGraphProperty( Property::Index index,
276                                             const PropertyMetadata& entry,
277                                             const Property::Value& value )
278 {
279   PROPERTY_BUFFER_IMPL.SetSceneGraphProperty( GetEventThreadServices(), this, index, entry, value );
280 }
281
282 Property::Value PropertyBuffer::GetDefaultProperty( Property::Index index ) const
283 {
284   Property::Value value;
285
286   switch( index )
287   {
288     case Dali::PropertyBuffer::Property::SIZE:
289     {
290       value = static_cast<int>( GetSize() ); // @todo MESH_REWORK Add a size_t type to PropertyValue
291       break;
292     }
293     case Dali::PropertyBuffer::Property::BUFFER_FORMAT:
294     {
295       DALI_ASSERT_ALWAYS( 0 && "MESH_REWORK" );
296       break;
297     }
298   }
299   return value;
300 }
301
302 const SceneGraph::PropertyOwner* PropertyBuffer::GetPropertyOwner() const
303 {
304   return mSceneObject;
305 }
306
307 const SceneGraph::PropertyOwner* PropertyBuffer::GetSceneObject() const
308 {
309   return mSceneObject;
310 }
311
312 const SceneGraph::PropertyBase* PropertyBuffer::GetSceneObjectAnimatableProperty( Property::Index index ) const
313 {
314   DALI_ASSERT_ALWAYS( IsPropertyAnimatable(index) && "Property is not animatable" );
315   const SceneGraph::PropertyBase* property = NULL;
316
317   if( OnStage() )
318   {
319     property = PROPERTY_BUFFER_IMPL.GetRegisteredSceneGraphProperty(
320       this,
321       &PropertyBuffer::FindAnimatableProperty,
322       &PropertyBuffer::FindCustomProperty,
323       index );
324
325     if( property == NULL && index < DEFAULT_PROPERTY_MAX_COUNT )
326     {
327       DALI_ASSERT_ALWAYS( 0 && "Property is not animatable" );
328     }
329   }
330
331   return property;
332 }
333
334 const PropertyInputImpl* PropertyBuffer::GetSceneObjectInputProperty( Property::Index index ) const
335 {
336   const PropertyInputImpl* property = NULL;
337
338   if( OnStage() )
339   {
340     const SceneGraph::PropertyBase* baseProperty =
341       PROPERTY_BUFFER_IMPL.GetRegisteredSceneGraphProperty( this,
342                                                             &PropertyBuffer::FindAnimatableProperty,
343                                                             &PropertyBuffer::FindCustomProperty,
344                                                             index );
345     property = static_cast<const PropertyInputImpl*>( baseProperty );
346
347     if( property == NULL && index < DEFAULT_PROPERTY_MAX_COUNT )
348     {
349       if( index == Dali::PropertyBuffer::Property::SIZE )
350       {
351         // @todo MESH_REWORK
352         DALI_ASSERT_ALWAYS( 0 && "MESH_REWORK" );
353       }
354     }
355   }
356
357   return property;
358 }
359
360 int PropertyBuffer::GetPropertyComponentIndex( Property::Index index ) const
361 {
362   return Property::INVALID_COMPONENT_INDEX;
363 }
364
365 bool PropertyBuffer::OnStage() const
366 {
367   return mOnStage;
368 }
369
370 void PropertyBuffer::Connect()
371 {
372   mOnStage = true;
373 }
374
375 void PropertyBuffer::Disconnect()
376 {
377   mOnStage = false;
378 }
379
380 PropertyBuffer::~PropertyBuffer()
381 {
382 }
383
384 PropertyBuffer::PropertyBuffer()
385 : mSceneObject( NULL ),
386   mBufferFormat( NULL ),
387   mSize( 0 ),
388   mType( Dali::PropertyBuffer::TYPE_COUNT ),
389   mOnStage( false )
390 {
391 }
392
393 void PropertyBuffer::Initialize()
394 {
395   EventThreadServices& eventThreadServices = GetEventThreadServices();
396   SceneGraph::UpdateManager& updateManager = eventThreadServices.GetUpdateManager();
397
398   DALI_ASSERT_ALWAYS( EventThreadServices::IsCoreRunning() && "Core is not running" );
399
400   mSceneObject = new SceneGraph::PropertyBuffer();
401   AddMessage( updateManager, updateManager.GetPropertyBufferOwner(), *mSceneObject );
402 }
403
404 void PropertyBuffer::FormatChanged()
405 {
406   size_t numComponents = mFormat.Count();
407
408   // Create the format
409   DALI_ASSERT_DEBUG( mBufferFormat == NULL && "PropertyFormat should not be set yet" );
410   Format* bufferFormat = new Format();
411   bufferFormat->components.resize( numComponents );
412
413   unsigned int currentAlignment = 0u;
414   unsigned int maxAlignmentRequired = 0u;
415
416   for( size_t i = 0u; i < numComponents; ++i )
417   {
418     StringValuePair component = mFormat.GetPair( i );
419
420     // Get the name
421     bufferFormat->components[i].name = component.first;
422
423     // enums are stored in the map as int
424     Property::Type type = Property::Type( component.second.Get<int>() );
425
426     // Get the size and alignment
427     unsigned int elementSize = GetPropertyImplementationSize( type );
428     unsigned int elementAlignment = GetPropertyImplementationAlignment( type );
429
430     // check if current alignment is compatible with new member
431     if( unsigned int offset = currentAlignment % elementAlignment )
432     {
433       // Not compatible, realign
434       currentAlignment = currentAlignment + elementSize - offset;
435     }
436
437     // write to the format
438     bufferFormat->components[i].size = elementSize;
439     bufferFormat->components[i].offset = currentAlignment;
440     bufferFormat->components[i].type = type;
441
442     // update offset
443     currentAlignment += elementSize;
444
445     // update max alignment requirement
446     if( elementAlignment > maxAlignmentRequired )
447     {
448       maxAlignmentRequired = elementAlignment;
449     }
450
451   }
452
453   // Check the alignment for the maxAlignment required to calculate the size of the format
454   if( unsigned int offset = currentAlignment % maxAlignmentRequired )
455   {
456     // Not compatible, realign
457     currentAlignment = currentAlignment + maxAlignmentRequired - offset;
458   }
459
460   // Set the format size
461   bufferFormat->size = currentAlignment;
462
463   mBufferFormat = bufferFormat;
464
465   SceneGraph::SetFormatMessage( GetEventThreadServices(),
466                                 *mSceneObject,
467                                 bufferFormat );
468
469   if( mSize )
470   {
471     SizeChanged();
472   }
473 }
474
475 void PropertyBuffer::SizeChanged()
476 {
477   // Check if format and size have been set yet
478   if( mBufferFormat != NULL )
479   {
480     unsigned int bufferSize = mBufferFormat->size * mSize;
481     mBuffer.Resize( bufferSize );
482   }
483 }
484
485 unsigned int GetPropertyImplementationSize( Property::Type& propertyType )
486 {
487   unsigned int size = 0u;
488
489   switch( propertyType )
490   {
491     case Property::NONE:
492     case Property::TYPE_COUNT:
493     case Property::STRING:
494     case Property::ARRAY:
495     case Property::MAP:
496     {
497       DALI_ASSERT_ALWAYS( "No size for properties with no type, or dynamic sizes" );
498       break;
499     }
500     case Property::BOOLEAN:
501     {
502       size = sizeof( PropertyImplementationType< Property::BOOLEAN >::Type );
503       break;
504     }
505     case Property::INTEGER:
506     {
507       size = sizeof( PropertyImplementationType< Property::INTEGER >::Type );
508       break;
509     }
510     case Property::UNSIGNED_INTEGER:
511     {
512       size = sizeof( PropertyImplementationType< Property::UNSIGNED_INTEGER >::Type );
513       break;
514     }
515     case Property::FLOAT:
516     {
517       size = sizeof( PropertyImplementationType< Property::FLOAT >::Type );
518       break;
519     }
520     case Property::VECTOR2:
521     {
522       size = sizeof( PropertyImplementationType< Property::VECTOR2 >::Type );
523       break;
524     }
525     case Property::VECTOR3:
526     {
527       size = sizeof( PropertyImplementationType< Property::VECTOR3 >::Type );
528       break;
529     }
530     case Property::VECTOR4:
531     {
532       size = sizeof( PropertyImplementationType< Property::VECTOR4 >::Type );
533       break;
534     }
535     case Property::MATRIX3:
536     {
537       size = sizeof( PropertyImplementationType< Property::MATRIX3 >::Type );
538       break;
539     }
540     case Property::MATRIX:
541     {
542       size = sizeof( PropertyImplementationType< Property::MATRIX >::Type );
543       break;
544     }
545     case Property::RECTANGLE:
546     {
547       size = sizeof( PropertyImplementationType< Property::RECTANGLE >::Type );
548       break;
549     }
550     case Property::ROTATION:
551     {
552       size = sizeof( PropertyImplementationType< Property::ROTATION >::Type );
553       break;
554     }
555   }
556
557   return size;
558 }
559
560
561 } // namespace Internal
562 } // namespace Dali