55bca88c4340a6b8211ae16a4a20165d23414a6f
[platform/core/uifw/dali-core.git] / dali / devel-api / scripting / scripting.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/devel-api/scripting/scripting.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/actors/actor.h>
23 #include <dali/public-api/images/resource-image.h>
24 #include <dali/public-api/object/type-registry.h>
25 #include <dali/public-api/object/property-array.h>
26 #include <dali/internal/common/image-attributes.h>
27 #include <dali/internal/event/common/property-helper.h>
28 #include <dali/internal/event/images/resource-image-impl.h>
29 #include <dali/internal/event/images/frame-buffer-image-impl.h>
30 #include <dali/internal/event/images/buffer-image-impl.h>
31
32 namespace Dali
33 {
34
35 namespace Scripting
36 {
37
38 namespace
39 {
40
41 // Tables used here for converting strings to the enumerations and vice versa
42 const StringEnum IMAGE_LOAD_POLICY_TABLE[] =
43 {
44   { "IMMEDIATE", ResourceImage::IMMEDIATE },
45   { "ON_DEMAND", ResourceImage::ON_DEMAND },
46 };
47 const unsigned int IMAGE_LOAD_POLICY_TABLE_COUNT = sizeof( IMAGE_LOAD_POLICY_TABLE ) / sizeof( IMAGE_LOAD_POLICY_TABLE[0] );
48
49 const StringEnum IMAGE_RELEASE_POLICY_TABLE[] =
50 {
51   { "UNUSED", Image::UNUSED },
52   { "NEVER",  Image::NEVER  },
53 };
54 const unsigned int IMAGE_RELEASE_POLICY_TABLE_COUNT = sizeof( IMAGE_RELEASE_POLICY_TABLE ) / sizeof( IMAGE_RELEASE_POLICY_TABLE[0] );
55
56 const StringEnum PIXEL_FORMAT_TABLE[] =
57 {
58   { "A8",                                           Pixel::A8                                           },
59   { "L8",                                           Pixel::L8                                           },
60   { "LA88",                                         Pixel::LA88                                         },
61   { "RGB565",                                       Pixel::RGB565                                       },
62   { "BGR565",                                       Pixel::BGR565                                       },
63   { "RGBA4444",                                     Pixel::RGBA4444                                     },
64   { "BGRA4444",                                     Pixel::BGRA4444                                     },
65   { "RGBA5551",                                     Pixel::RGBA5551                                     },
66   { "BGRA5551",                                     Pixel::BGRA5551                                     },
67   { "RGB888",                                       Pixel::RGB888                                       },
68   { "RGB8888",                                      Pixel::RGB8888                                      },
69   { "BGR8888",                                      Pixel::BGR8888                                      },
70   { "RGBA8888",                                     Pixel::RGBA8888                                     },
71   { "BGRA8888",                                     Pixel::BGRA8888                                     },
72   { "COMPRESSED_R11_EAC",                           Pixel::COMPRESSED_R11_EAC                           },
73   { "COMPRESSED_SIGNED_R11_EAC",                    Pixel::COMPRESSED_SIGNED_R11_EAC                    },
74   { "COMPRESSED_SIGNED_RG11_EAC",                   Pixel::COMPRESSED_SIGNED_RG11_EAC                   },
75   { "COMPRESSED_RG11_EAC",                          Pixel::COMPRESSED_RG11_EAC                          },
76   { "COMPRESSED_RGB8_ETC2",                         Pixel::COMPRESSED_RGB8_ETC2                         },
77   { "COMPRESSED_SRGB8_ETC2",                        Pixel::COMPRESSED_SRGB8_ETC2                        },
78   { "COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2",     Pixel::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2     },
79   { "COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2",    Pixel::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2    },
80   { "COMPRESSED_RGBA8_ETC2_EAC",                    Pixel::COMPRESSED_RGBA8_ETC2_EAC                    },
81   { "COMPRESSED_SRGB8_ALPHA8_ETC2_EAC",             Pixel::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC             },
82   { "COMPRESSED_RGB8_ETC1",                         Pixel::COMPRESSED_RGB8_ETC1                         },
83   { "COMPRESSED_RGB_PVRTC_4BPPV1",                  Pixel::COMPRESSED_RGB_PVRTC_4BPPV1                  },
84 };
85 const unsigned int PIXEL_FORMAT_TABLE_COUNT = sizeof( PIXEL_FORMAT_TABLE ) / sizeof( PIXEL_FORMAT_TABLE[0] );
86
87 const StringEnum IMAGE_FITTING_MODE_TABLE[] =
88 {
89   { "SHRINK_TO_FIT", FittingMode::SHRINK_TO_FIT },
90   { "SCALE_TO_FILL", FittingMode::SCALE_TO_FILL },
91   { "FIT_WIDTH",     FittingMode::FIT_WIDTH    },
92   { "FIT_HEIGHT",    FittingMode::FIT_HEIGHT   },
93 };
94 const unsigned int IMAGE_FITTING_MODE_TABLE_COUNT = sizeof( IMAGE_FITTING_MODE_TABLE ) / sizeof( IMAGE_FITTING_MODE_TABLE[0] );
95
96 const StringEnum IMAGE_SAMPLING_MODE_TABLE[] =
97 {
98   { "BOX",              SamplingMode::BOX            },
99   { "NEAREST",          SamplingMode::NEAREST        },
100   { "LINEAR",           SamplingMode::LINEAR         },
101   { "BOX_THEN_NEAREST", SamplingMode::BOX_THEN_NEAREST },
102   { "BOX_THEN_LINEAR",  SamplingMode::BOX_THEN_LINEAR  },
103   { "NO_FILTER",        SamplingMode::NO_FILTER       },
104   { "DONT_CARE",        SamplingMode::DONT_CARE       },
105 };
106 const unsigned int IMAGE_SAMPLING_MODE_TABLE_COUNT = sizeof( IMAGE_SAMPLING_MODE_TABLE ) / sizeof( IMAGE_SAMPLING_MODE_TABLE[0] );
107
108 const char* ImageTypeName[] = { "ResourceImage", "FrameBufferImage", "BufferImage" };
109 enum ImageType                { RESOURCE_IMAGE,  FRAME_BUFFER_IMAGE, BUFFER_IMAGE };
110 const unsigned int imageTypeCount = sizeof( ImageTypeName ) / sizeof( const char* );
111
112 } // unnamed namespace
113
114 bool EnumStringToInteger( const char * const value, const StringEnum* const enumTable, unsigned int tableCount, unsigned int& integerEnum )
115 {
116   unsigned int ret = 0;
117
118   bool found = false;
119   bool done = false;
120
121   if( value && enumTable && tableCount )
122   {
123     const char* pValue = value;
124
125     while(!done)
126     {
127       size_t size = 0;
128
129       const StringEnum* table = enumTable;
130
131       for ( unsigned int i = 0; i < tableCount; ++i )
132       {
133         if( Internal::CompareTokens( pValue, table->string, size ) )
134         {
135           found = true;
136           ret |= table->value;
137           break;
138         }
139         table++;
140       }
141
142       done = true;
143
144       if(found)
145       {
146         // allow comma separated or'd value
147         if( *(pValue+size) == ',' )
148         {
149           pValue += size + 1;
150           done = false;
151         }
152       }
153
154     }
155
156     integerEnum = ret;
157   }
158
159   if ( !found )
160   {
161     DALI_LOG_ERROR( "Unknown enumeration string %s\n", value );
162   }
163   return found;
164 }
165
166 unsigned int FindEnumIndex( const char* value, const StringEnum* table, unsigned int tableCount )
167 {
168   unsigned int index = 0;
169   bool found = false;
170   for ( unsigned int i = 0; i < tableCount; ++i, ++index )
171   {
172     size_t sizeIgnored = 0;
173     if( Internal::CompareTokens( value, table->string, sizeIgnored ) )
174     {
175       found = true;
176       break;
177     }
178     ++table;
179   }
180   if ( !found )
181   {
182     DALI_LOG_ERROR( "Unknown enumeration string %s\n", value );
183   }
184   return index;
185 }
186
187
188 Image NewImage( const Property::Value& property )
189 {
190   Image ret;
191
192   std::string filename;
193   ResourceImage::LoadPolicy loadPolicy = Dali::Internal::IMAGE_LOAD_POLICY_DEFAULT;
194   Image::ReleasePolicy releasePolicy   = Dali::Internal::IMAGE_RELEASE_POLICY_DEFAULT;
195   Internal::ImageAttributes attributes = Internal::ImageAttributes::New();
196
197   const Property::Map* map = property.GetMap();
198   ImageType imageType = RESOURCE_IMAGE; // default to resource image
199   if( map )
200   {
201     // first check the type as it determines, which other parameters are needed
202     const Property::Value* value = map->Find( "type" );
203     if( value )
204     {
205       std::string type;
206       value->Get( type );
207       for( unsigned int i = 0; i < imageTypeCount; ++i )
208       {
209         if( 0 == type.compare( ImageTypeName[ i ] ) )
210         {
211           imageType = static_cast<ImageType>( i );
212           break;
213         }
214       }
215     }
216
217     // filename is only needed for resource images
218     if( RESOURCE_IMAGE == imageType )
219     {
220       const Property::Value* value = map->Find( "filename" );
221       if( value )
222       {
223         value->Get( filename );
224       }
225       // if empty file, no need to go further
226       if( filename.size() == 0 )
227       {
228         DALI_LOG_ERROR( "No filename\n" );
229         return Image();
230       }
231     }
232
233     value = map->Find( "loadPolicy" );
234     if( value )
235     {
236       std::string policy;
237       value->Get( policy );
238       // keep default value on error
239       GetEnumeration< ResourceImage::LoadPolicy >( policy.c_str(), IMAGE_LOAD_POLICY_TABLE, IMAGE_LOAD_POLICY_TABLE_COUNT, loadPolicy );
240     }
241
242     value = map->Find( "releasePolicy" );
243     if( value )
244     {
245       std::string policy;
246       value->Get( policy );
247       // keep default value on error
248       GetEnumeration< Image::ReleasePolicy >( policy.c_str(), IMAGE_RELEASE_POLICY_TABLE, IMAGE_RELEASE_POLICY_TABLE_COUNT, releasePolicy );
249     }
250
251     // Width and height can be set individually. Dali derives the unspecified
252     // dimension from the aspect ratio of the raw image.
253     int width = 0, height = 0;
254
255     value = map->Find( "width" );
256     if( value )
257     {
258       // handle floats and integer the same for json script
259       if( value->GetType() == Property::FLOAT )
260       {
261         width = static_cast<unsigned int>( value->Get<float>() );
262       }
263       else
264       {
265         value->Get( width );
266       }
267     }
268     value = map->Find( "height" );
269     if( value )
270     {
271       if( value->GetType() == Property::FLOAT )
272       {
273         height = static_cast<int>( value->Get<float>() );
274       }
275       else
276       {
277         value->Get( height );
278       }
279     }
280     attributes.SetSize( width, height );
281
282     Pixel::Format pixelFormat = Pixel::RGBA8888;
283     value = map->Find( "pixelFormat" );
284     if( value )
285     {
286       std::string format;
287       value->Get( format );
288       GetEnumeration< Pixel::Format >( format.c_str(), PIXEL_FORMAT_TABLE, PIXEL_FORMAT_TABLE_COUNT, pixelFormat );
289     }
290
291     value = map->Find( "fittingMode" );
292     if( value )
293     {
294       std::string fitting;
295       value->Get( fitting );
296       FittingMode::Type mode;
297       if( GetEnumeration< FittingMode::Type >( fitting.c_str(), IMAGE_FITTING_MODE_TABLE, IMAGE_FITTING_MODE_TABLE_COUNT, mode ) )
298       {
299         attributes.SetScalingMode( mode );
300       }
301     }
302
303     value = map->Find( "samplingMode" );
304     if( value )
305     {
306       std::string sampling;
307       value->Get( sampling );
308       SamplingMode::Type mode;
309       if( GetEnumeration< SamplingMode::Type >( sampling.c_str(), IMAGE_SAMPLING_MODE_TABLE, IMAGE_SAMPLING_MODE_TABLE_COUNT, mode ) )
310       {
311         attributes.SetFilterMode( mode );
312       }
313     }
314
315     value = map->Find( "orientation" );
316     if( value )
317     {
318       bool b = value->Get<bool>();
319       attributes.SetOrientationCorrection( b );
320     }
321
322     switch( imageType )
323     {
324       case RESOURCE_IMAGE :
325       {
326         ret = ResourceImage::New( filename, loadPolicy, releasePolicy,
327                                   ImageDimensions( attributes.GetSize().x, attributes.GetSize().y ),
328                                   attributes.GetScalingMode(), attributes.GetFilterMode(), attributes.GetOrientationCorrection() );
329         break;
330       }
331       case BUFFER_IMAGE :
332       {
333         ret = BufferImage::New( attributes.GetWidth(),
334                                 attributes.GetHeight(),
335                                 pixelFormat,
336                                 releasePolicy );
337         break;
338       }
339       case FRAME_BUFFER_IMAGE :
340       {
341         ret = FrameBufferImage::New( attributes.GetWidth(),
342                                      attributes.GetHeight(),
343                                      pixelFormat,
344                                      releasePolicy );
345         break;
346       }
347     }
348   }
349
350   return ret;
351
352 } // Image NewImage( Property::Value map )
353
354
355 Actor NewActor( const Property::Map& map )
356 {
357   BaseHandle handle;
358
359   // First find type and create Actor
360   Property::Value* typeValue = map.Find( "type" );
361   if ( typeValue )
362   {
363     TypeInfo type = TypeRegistry::Get().GetTypeInfo( typeValue->Get< std::string >() );
364     if ( type )
365     {
366       handle = type.CreateInstance();
367     }
368   }
369
370   if ( !handle )
371   {
372     DALI_LOG_ERROR( "Actor type not provided\n" );
373     return Actor();
374   }
375
376   Actor actor( Actor::DownCast( handle ) );
377
378   if ( actor )
379   {
380     // Now set the properties, or create children
381     for ( unsigned int i = 0, mapCount = map.Count(); i < mapCount; ++i )
382     {
383       const StringValuePair& pair( map.GetPair( i ) );
384       const std::string& key( pair.first );
385       if ( key == "type" )
386       {
387         continue;
388       }
389
390       const Property::Value& value( pair.second );
391
392       if ( key == "actors" )
393       {
394         // Create children
395         Property::Array actorArray = value.Get< Property::Array >();
396         for ( Property::Array::SizeType i = 0; i < actorArray.Size(); ++i)
397         {
398           actor.Add( NewActor( actorArray[i].Get< Property::Map >() ) );
399         }
400       }
401       else
402       {
403         Property::Index index( actor.GetPropertyIndex( key ) );
404
405         if ( index != Property::INVALID_INDEX )
406         {
407           actor.SetProperty( index, value );
408         }
409       }
410     }
411   }
412
413   return actor;
414 }
415
416 void CreatePropertyMap( Actor actor, Property::Map& map )
417 {
418   map.Clear();
419
420   if ( actor )
421   {
422     map[ "type" ] = actor.GetTypeName();
423
424     // Default properties
425     Property::IndexContainer indices;
426     actor.GetPropertyIndices( indices );
427     const Property::IndexContainer::ConstIterator endIter = indices.End();
428
429     for ( Property::IndexContainer::Iterator iter = indices.Begin(); iter != endIter; ++iter )
430     {
431       map[ actor.GetPropertyName( *iter ) ] = actor.GetProperty( *iter );
432     }
433
434     // Children
435     unsigned int childCount( actor.GetChildCount() );
436     if ( childCount )
437     {
438       Property::Array childArray;
439       for ( unsigned int child = 0; child < childCount; ++child )
440       {
441         Property::Map childMap;
442         CreatePropertyMap( actor.GetChildAt( child ), childMap );
443         childArray.PushBack( childMap );
444       }
445       map[ "actors" ] = childArray;
446     }
447   }
448 }
449
450 void CreatePropertyMap( Image image, Property::Map& map )
451 {
452   map.Clear();
453
454   if ( image )
455   {
456     std::string imageType( "ResourceImage" );
457
458     // Get Type - cannot use TypeRegistry as Image is not an Object and thus, not registered
459     BufferImage bufferImage = BufferImage::DownCast( image );
460     if ( bufferImage )
461     {
462       imageType = "BufferImage";
463       map[ "pixelFormat" ] = GetEnumerationName< Pixel::Format >( bufferImage.GetPixelFormat(), PIXEL_FORMAT_TABLE, PIXEL_FORMAT_TABLE_COUNT );
464     }
465     else if ( FrameBufferImage::DownCast( image ) )
466     {
467       imageType = "FrameBufferImage";
468     }
469
470     map[ "type" ] = imageType;
471     map[ "releasePolicy" ] = GetEnumerationName< Image::ReleasePolicy >( image.GetReleasePolicy(), IMAGE_RELEASE_POLICY_TABLE, IMAGE_RELEASE_POLICY_TABLE_COUNT );
472
473     ResourceImage resourceImage = ResourceImage::DownCast( image );
474     if( resourceImage )
475     {
476       map[ "filename" ] = resourceImage.GetUrl();
477       map[ "loadPolicy" ] = GetEnumerationName< ResourceImage::LoadPolicy >( resourceImage.GetLoadPolicy(), IMAGE_LOAD_POLICY_TABLE, IMAGE_LOAD_POLICY_TABLE_COUNT );
478     }
479
480     int width( image.GetWidth() );
481     int height( image.GetHeight() );
482
483     if ( width && height )
484     {
485       map[ "width" ] = width;
486       map[ "height" ] = height;
487     }
488   }
489 }
490
491 void NewAnimation( const Property::Map& map, Dali::AnimationData& outputAnimationData )
492 {
493   // Note: Builder cannot currently pass generic Property::Maps "{" that are nested, so currently we can only have one AnimateTo per animation.
494   Dali::AnimationData::AnimationDataElement* element = new Dali::AnimationData::AnimationDataElement();
495   element->alphaFunction = AlphaFunction::LINEAR;
496   element->timePeriodDelay = 0.0f;
497   element->timePeriodDuration = 1.0f;
498
499   // Now set the properties, or create children
500   for( unsigned int i = 0, animationMapCount = map.Count(); i < animationMapCount; ++i )
501   {
502     const StringValuePair& pair( map.GetPair( i ) );
503     const std::string& key( pair.first );
504     const Property::Value& value( pair.second );
505
506     if( key == "actor" )
507     {
508       element->actor = value.Get< std::string >();
509     }
510     else if( key == "property" )
511     {
512       element->property = value.Get< std::string >();
513     }
514     else if( key == "value" )
515     {
516       element->value = value;
517     }
518     else if( key == "alphaFunction" )
519     {
520       std::string alphaFunctionValue = value.Get< std::string >();
521
522       if( alphaFunctionValue == "LINEAR" )
523       {
524         element->alphaFunction = AlphaFunction::LINEAR;
525       }
526       else if( alphaFunctionValue == "REVERSE" )
527       {
528         element->alphaFunction = AlphaFunction::REVERSE;
529       }
530       else if( alphaFunctionValue == "EASE_IN_SQUARE" )
531       {
532         element->alphaFunction = AlphaFunction::EASE_IN_SQUARE;
533       }
534       else if( alphaFunctionValue == "EASE_OUT_SQUARE" )
535       {
536         element->alphaFunction = AlphaFunction::EASE_OUT_SQUARE;
537       }
538       else if( alphaFunctionValue == "EASE_IN" )
539       {
540         element->alphaFunction = AlphaFunction::EASE_IN;
541       }
542       else if( alphaFunctionValue == "EASE_OUT" )
543       {
544         element->alphaFunction = AlphaFunction::EASE_OUT;
545       }
546       else if( alphaFunctionValue == "EASE_IN_OUT" )
547       {
548         element->alphaFunction = AlphaFunction::EASE_IN_OUT;
549       }
550       else if( alphaFunctionValue == "EASE_IN_SINE" )
551       {
552         element->alphaFunction = AlphaFunction::EASE_IN_SINE;
553       }
554       else if( alphaFunctionValue == "EASE_OUT_SINE" )
555       {
556         element->alphaFunction = AlphaFunction::EASE_OUT_SINE;
557       }
558       else if( alphaFunctionValue == "EASE_IN_OUT_SINE" )
559       {
560         element->alphaFunction = AlphaFunction::EASE_IN_OUT_SINE;
561       }
562       else if( alphaFunctionValue == "BOUNCE" )
563       {
564         element->alphaFunction = AlphaFunction::BOUNCE;
565       }
566       else if( alphaFunctionValue == "SIN" )
567       {
568         element->alphaFunction = AlphaFunction::SIN;
569       }
570       else if( alphaFunctionValue == "EASE_OUT_BACK" )
571       {
572         element->alphaFunction = AlphaFunction::EASE_OUT_BACK;
573       }
574     }
575     else if( key == "timePeriod" )
576     {
577       Property::Map timeMap = value.Get< Property::Map >();
578       for( unsigned int i = 0; i < timeMap.Count(); ++i )
579       {
580         const StringValuePair& pair( timeMap.GetPair( i ) );
581         if( pair.first == "delay" )
582         {
583           element->timePeriodDelay = pair.second.Get< float >();
584         }
585         else if( pair.first == "duration" )
586         {
587           element->timePeriodDuration = pair.second.Get< float >();
588         }
589       }
590     }
591   }
592
593   outputAnimationData.Add( element );
594 }
595
596 } // namespace scripting
597
598 } // namespace Dali
599
600
601
602