Add null check for mTextureSet.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / builder / replacement.cpp
1 /*
2  * Copyright (c) 2017 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 // INTERNAL INCLUDES
19 #include <dali-toolkit/internal/builder/replacement.h>
20 #include <dali-toolkit/internal/builder/builder-impl.h>
21 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
22
23 namespace Dali
24 {
25
26 namespace Toolkit
27 {
28
29 namespace Internal
30 {
31
32 namespace  // anon
33 {
34
35 Property::Value* FindReplacement( const std::string &str, const Property::Map& overrideMap, const Property::Map& defaultMap )
36 {
37   Property::Value* ret  = overrideMap.Find( str );
38
39   if ( !ret )
40   {
41     ret = defaultMap.Find( str );
42
43     // @ todo
44     // try localized text ie dgettext. Look for colon  {DOMAIN:TEXT} {LC_MESSAGE:ID_XXXX}
45   }
46
47   return ret;
48 }
49
50 std::size_t FirstUnescapedChar(const std::string &initialValue, const std::size_t& startPos, const char c)
51 {
52   std::size_t pos = initialValue.find( c, startPos );
53
54   if(pos > 0)
55   {
56     while( pos != std::string::npos )
57     {
58       if( '\\' == initialValue.at( pos-1 ) )
59       {
60         pos = initialValue.find( c, pos );
61       }
62       else
63       {
64         break;
65       }
66     }
67   }
68
69   return pos;
70 }
71
72 bool GetSubstitutionPosition( const std::string &initialValue, std::size_t &startPos, std::size_t &size )
73 {
74   std::size_t pos = FirstUnescapedChar(initialValue, 0, '{');
75
76   if( std::string::npos == pos )
77   {
78     startPos = std::string::npos;
79     return false;
80   }
81   else
82   {
83     startPos = pos + 1;
84   }
85
86   pos = FirstUnescapedChar(initialValue, startPos, '}');
87
88   if( std::string::npos == pos )
89   {
90     size = std::string::npos;
91     return false;
92   }
93   else
94   {
95     size = pos - startPos;
96   }
97
98   return true;
99 }
100
101 bool ResolvePartialReplacement( const std::string &initialValue, Property::Value &out,
102                                 const Property::Map& overrideMap, const Property::Map& defaultMap )
103 {
104
105   if( initialValue.size() >= 2 )
106   {
107     // eg '{"constants": { "IMAGE_DIR": "/share/images" },
108     //      ...
109     //        "filename":"{IMAGE_DIR}/theme/header.png",
110     //
111     std::size_t startPos = 0;
112     std::size_t size     = std::string::npos;
113
114     if( !GetSubstitutionPosition( initialValue, startPos, size ) )
115     {
116       out = initialValue;
117       return true;
118     }
119     else
120     {
121       const std::string str( initialValue.substr( startPos, size ) );
122
123       Property::Value* value = FindReplacement( str, overrideMap, defaultMap );
124
125       if( !value )
126       {
127         DALI_SCRIPT_WARNING( "Cannot find replacement for '%s'\n", str.c_str() );
128       }
129       else
130       {
131         if( Property::STRING != value->GetType() )
132         {
133           DALI_SCRIPT_WARNING( "Cannot replace substring in non string property type='%s'. Initial value '%s'\n",
134                                PropertyTypes::GetName( out.GetType() ), initialValue.c_str() );
135         }
136         else
137         {
138           std::string newString = \
139             initialValue.substr(0, startPos - 1) +
140             value->Get< std::string >() +
141             initialValue.substr( startPos + size + 1 );
142
143           return ResolvePartialReplacement( newString, out, overrideMap,  defaultMap );
144         }
145       }
146     }
147   }
148
149   // if we get here we failed
150   return false;
151 }
152
153 } // namespace anon
154
155
156 Replacement::Replacement( const Property::Map& overrideMap, const Property::Map& defaultMap )
157   : mOverrideMap( &overrideMap ), mDefaultMap( &defaultMap )
158 {
159
160 }
161
162 namespace
163 {
164 Property::Map noMap;
165 }
166
167 Replacement::Replacement( const Property::Map& defaultMap )
168   : mOverrideMap( &noMap ), mDefaultMap( &defaultMap )
169 {
170
171 }
172
173 Replacement::Replacement(  )
174   : mOverrideMap( &noMap ), mDefaultMap( &noMap )
175 {
176
177 }
178
179 OptionalString Replacement::HasFullReplacement( const TreeNode & node ) const
180 {
181   OptionalString ret;
182
183   if( node.HasSubstitution() && ((*mOverrideMap).Count() || (*mDefaultMap).Count()) )
184   {
185     OptionalString v = ::IsString( node );
186     if( v )
187     {
188       const std::string& initialValue = *v;
189       if( (initialValue[ 0 ] == '{') && (initialValue[ initialValue.size() -1 ] == '}') )
190       {
191         ret = initialValue.substr( 1, initialValue.size() - 2 );
192       }
193     }
194   }
195   return ret;
196 }
197
198 Property::Value Replacement::GetFullReplacement( const std::string& replacementString ) const
199 {
200   Property::Value out;
201   DALI_ASSERT_DEBUG( mOverrideMap && "missing map");
202   DALI_ASSERT_DEBUG( mDefaultMap && "missing map");
203
204   Property::Value* value = FindReplacement( replacementString, *mOverrideMap, *mDefaultMap );
205
206   if( !value )
207   {
208     DALI_SCRIPT_WARNING("Cannot find replacement for '%s'\n", replacementString.c_str());
209   }
210   else
211   {
212     out = *value;
213 #if defined(DEBUG_ENABLED)
214     DALI_SCRIPT_VERBOSE("  Full replacement for '%s' => to Type '%s'\n",
215                         replacementString.c_str(),
216                         PropertyTypes::GetName( out.GetType()) );
217 #endif
218   }
219
220   return out;
221 }
222
223 OptionalBoolean Replacement::IsBoolean( const TreeNode & node ) const
224 {
225   OptionalBoolean ret;
226   if( OptionalString replace = HasFullReplacement( node ) )
227   {
228     Property::Value value = GetFullReplacement( *replace );
229     if( Property::BOOLEAN == value.GetType() )
230     {
231       ret = value.Get<bool>();
232     }
233   }
234   else
235   {
236     ret = ::IsBoolean( node );
237   }
238   return ret;
239 }
240
241 OptionalBoolean Replacement::IsBoolean( OptionalChild child ) const
242 {
243   if( child )
244   {
245     return IsBoolean( *child );
246   }
247   else
248   {
249     return OptionalBoolean();
250   }
251 }
252
253 OptionalFloat Replacement::IsFloat( const TreeNode & node ) const
254 {
255   OptionalFloat ret;
256   if( OptionalString replace = HasFullReplacement( node ) )
257   {
258     Property::Value value = GetFullReplacement( *replace );
259     if( Property::FLOAT == value.GetType() )
260     {
261       ret = value.Get<float>();
262     }
263   }
264   else
265   {
266     ret = ::IsFloat( node );
267   }
268   return ret;
269 }
270
271 OptionalString Replacement::IsString( const TreeNode& node ) const
272 {
273   OptionalString ret;
274
275   DALI_ASSERT_DEBUG( mOverrideMap && "missing map");
276   DALI_ASSERT_DEBUG( mDefaultMap && "missing map");
277
278   if( node.HasSubstitution() && ((*mOverrideMap).Count() || (*mDefaultMap).Count()) )
279   {
280     if( OptionalString v = ::IsString( node ) )
281     {
282       Property::Value value;
283       if( ResolvePartialReplacement( *v, value, *mOverrideMap, *mDefaultMap ) )
284       {
285         if( Property::STRING == value.GetType() )
286         {
287           ret = value.Get<std::string>();
288 #if defined(DEBUG_ENABLED)
289           DALI_SCRIPT_VERBOSE("  Resolved substring replacement for '%s' => '%s'\n", (*v).c_str(), (*ret).c_str());
290 #endif
291         }
292       }
293       else
294       {
295         ret = v; // sets the unexpanded. Expansion may occur later in processing with include files
296       }
297     }
298   }
299   else
300   {
301     ret = ::IsString( node );
302   }
303   return ret;
304 }
305
306 OptionalInteger Replacement::IsInteger( const TreeNode & node ) const
307 {
308   OptionalInteger ret;
309   if( OptionalString replace = HasFullReplacement( node ) )
310   {
311     Property::Value value = GetFullReplacement( *replace );
312     if( Property::INTEGER == value.GetType() )
313     {
314       ret = value.Get<int>();
315     }
316   }
317   else
318   {
319     ret = ::IsInteger( node );
320   }
321   return ret;
322 }
323
324 OptionalVector2 Replacement::IsVector2( const TreeNode & node ) const
325 {
326   OptionalVector2 ret;
327   if( OptionalString replace = HasFullReplacement( node ) )
328   {
329     Property::Value value = GetFullReplacement( *replace );
330     if( Property::VECTOR2 == value.GetType() )
331     {
332       ret = value.Get<Vector2>();
333     }
334   }
335   else
336   {
337     ret = ::IsVector2( node );
338   }
339   return ret;
340 }
341
342 OptionalVector3 Replacement::IsVector3( const TreeNode & node ) const
343 {
344   OptionalVector3 ret;
345   if( OptionalString replace = HasFullReplacement( node ) )
346   {
347     Property::Value value = GetFullReplacement( *replace );
348     if( Property::VECTOR3 == value.GetType() )
349     {
350       ret = value.Get<Vector3>();
351     }
352   }
353   else
354   {
355     ret = ::IsVector3( node );
356   }
357   return ret;
358 }
359
360 OptionalVector4 Replacement::IsVector4( const TreeNode & node ) const
361 {
362   OptionalVector4 ret;
363   if( OptionalString replace = HasFullReplacement( node ) )
364   {
365     Property::Value value = GetFullReplacement( *replace );
366     if( Property::VECTOR4 == value.GetType() )
367     {
368       ret = value.Get<Vector4>();
369     }
370   }
371   else
372   {
373     ret = ::IsVector4( node );
374   }
375   return ret;
376 }
377
378 OptionalMatrix Replacement::IsMatrix( const TreeNode & node ) const
379 {
380   OptionalMatrix ret;
381   if( OptionalString replace = HasFullReplacement( node ) )
382   {
383     Property::Value value = GetFullReplacement( *replace );
384     if( Property::MATRIX == value.GetType() )
385     {
386       ret = value.Get<Matrix>();
387     }
388   }
389   else
390   {
391     ret = ::IsMatrix( node );
392   }
393   return ret;
394 }
395
396 OptionalMatrix3 Replacement::IsMatrix3( const TreeNode & node ) const
397 {
398   OptionalMatrix3 ret;
399   if( OptionalString replace = HasFullReplacement( node ) )
400   {
401     Property::Value value = GetFullReplacement( *replace );
402     if( Property::MATRIX3 == value.GetType() )
403     {
404       ret = value.Get<Matrix3>();
405     }
406   }
407   else
408   {
409     ret = ::IsMatrix3( node );
410   }
411   return ret;
412 }
413
414 OptionalRect Replacement::IsRect( const TreeNode & node ) const
415 {
416   OptionalRect ret;
417   if( OptionalString replace = HasFullReplacement( node ) )
418   {
419     Property::Value value = GetFullReplacement( *replace );
420     if( Property::RECTANGLE == value.GetType() )
421     {
422       ret = value.Get<Rect<int> >();
423     }
424   }
425   else
426   {
427     ret = ::IsRect( node );
428   }
429   return ret;
430 }
431
432 OptionalExtents Replacement::IsExtents( const TreeNode & node ) const
433 {
434   OptionalExtents extents;
435   if( OptionalString replace = HasFullReplacement( node ) )
436   {
437     Property::Value value = GetFullReplacement( *replace );
438     if( Property::EXTENTS == value.GetType() )
439     {
440       extents = value.Get<Extents>();
441     }
442   }
443   else
444   {
445     extents = ::IsExtents( node );
446   }
447   return extents;
448 }
449
450 OptionalFloat Replacement::IsFloat( OptionalChild child ) const
451 {
452   if( child )
453   {
454     return IsFloat( *child );
455   }
456   else
457   {
458     return OptionalFloat();
459   }
460 }
461
462
463 OptionalString Replacement::IsString( OptionalChild child ) const
464 {
465   if( child )
466   {
467     return IsString( *child );
468   }
469   else
470   {
471     return OptionalString();
472   }
473 }
474
475 OptionalInteger Replacement::IsInteger( OptionalChild child ) const
476 {
477   if( child )
478   {
479     return IsInteger( *child );
480   }
481   else
482   {
483     return OptionalInteger();
484   }
485 }
486
487 OptionalVector2 Replacement::IsVector2( OptionalChild child ) const
488 {
489   if( child )
490   {
491     return IsVector2( *child );
492   }
493   else
494   {
495     return OptionalVector2();
496   }
497 }
498
499 OptionalVector3 Replacement::IsVector3( OptionalChild child ) const
500 {
501   if( child )
502   {
503     return IsVector3( *child );
504   }
505   else
506   {
507     return OptionalVector3();
508   }
509 }
510
511 OptionalVector4 Replacement::IsVector4( OptionalChild child ) const
512 {
513   if( child )
514   {
515     return IsVector4( *child );
516   }
517   else
518   {
519     return OptionalVector4();
520   }
521 }
522
523 OptionalMatrix Replacement::IsMatrix( OptionalChild child ) const
524 {
525   if( child )
526   {
527     return IsMatrix( *child );
528   }
529   else
530   {
531     return OptionalMatrix();
532   }
533 }
534
535 OptionalMatrix3 Replacement::IsMatrix3( OptionalChild child ) const
536 {
537   if( child )
538   {
539     return IsMatrix3( *child );
540   }
541   else
542   {
543     return OptionalMatrix3();
544   }
545 }
546
547 OptionalRect Replacement::IsRect( OptionalChild child ) const
548 {
549   if( child )
550   {
551     return IsRect( *child );
552   }
553   else
554   {
555     return OptionalRect();
556   }
557 }
558
559 bool Replacement::IsMap( OptionalChild child, Property::Value& out ) const
560 {
561   bool ret = false;
562
563   if( child )
564   {
565     if( OptionalString replace = HasFullReplacement( *child ) )
566     {
567       out = GetFullReplacement( *replace );
568       if( Property::MAP == out.GetType() )
569       {
570         ret = true;
571       }
572     }
573   }
574
575   return ret;
576 }
577
578 bool Replacement::IsArray( OptionalChild child, Property::Value& out ) const
579 {
580   bool ret = false;
581
582   if( child )
583   {
584     if( OptionalString replace = HasFullReplacement( *child ) )
585     {
586       out = GetFullReplacement( *replace );
587       if( Property::ARRAY == out.GetType() )
588       {
589         ret = true;
590       }
591     }
592   }
593
594   return ret;
595 }
596
597 OptionalExtents Replacement::IsExtents( OptionalChild child ) const
598 {
599   if( child )
600   {
601     return IsExtents( *child );
602   }
603   else
604   {
605     return OptionalExtents();
606   }
607 }
608
609 } // namespace Internal
610
611 } // namespace Toolkit
612
613 } // namespace Dali