Merge "Updated patch coverage script." into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-scene-loader / internal / json-util.cpp
1 /*
2  * Copyright (c) 2020 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 #include "dali-scene-loader/internal/json-util.h"
18
19 // EXTERNAL INCLUDES
20 #include "dali/public-api/common/extents.h"
21 #include "dali/public-api/math/matrix3.h"
22 #include "dali/public-api/math/matrix.h"
23 #include "dali/public-api/math/quaternion.h"
24 #include "dali/public-api/math/radian.h"
25 #include "dali/public-api/math/vector2.h"
26 #include "dali/public-api/math/vector3.h"
27 #include "dali/public-api/object/property-value.h"
28 #include "dali/devel-api/common/map-wrapper.h"
29 #include <array>
30
31 namespace Dali
32 {
33 using namespace Toolkit;
34
35 namespace SceneLoader
36 {
37 namespace
38 {
39
40 template <typename T>
41 Property::Value ReadPrimitiveHelper(const TreeNode* tn, bool(*reader)(const TreeNode*, T&))
42 {
43   T value;
44   if (reader(tn, value))
45   {
46     return Property::Value(value);
47   }
48   return Property::Value();
49 }
50
51 template <typename T>
52 Property::Value ReadVectorHelper(const TreeNode* tn)
53 {
54   static_assert(sizeof(T) % sizeof(float) == 0, "");
55   T value;
56   if (ReadVector(tn, value.AsFloat(), sizeof(T) / sizeof(float)))
57   {
58     return Property::Value(value);
59   }
60   return Property::Value();
61 }
62
63 Property::Value ReadVectorSingleFloatHelper(const TreeNode* tn)
64 {
65   float value;
66   if (ReadVector(tn, &value, 1u))
67   {
68     return Property::Value(value);
69   }
70   return Property::Value();
71 }
72
73 Property::Value ReadRotationHelper(const TreeNode* tn)
74 {
75   switch (tn->Size())
76   {
77   case 3:
78   {
79     // degrees as per spec
80     Vector3 rotation;
81     ReadVector(tn, rotation.AsFloat(), 3u);
82     return Property::Value(Quaternion(Radian(Degree(rotation.x)),
83       Radian(Degree(rotation.y)),
84       Radian(Degree(rotation.z))));
85   }
86   case 4:
87   {
88     Vector4 v;
89     ReadVector(tn, v.AsFloat(), 4u);
90     //Quaternion
91     return Property::Value(Quaternion(v));
92   }
93   default:
94     return Property::Value();
95   }
96 }
97
98 template <typename T>
99 bool ReadQuadHelper(const TreeNode* tn, const std::array<T*, 4>& quad)
100 {
101   auto i = quad.begin();
102   auto iEnd = quad.end();
103   auto iJson = tn->CBegin();
104   while (iJson != tn->CEnd() && i != iEnd)
105   {
106     int value;
107     if (ReadInt(&(*iJson).second, value) && value <= std::numeric_limits<T>::max())
108     {
109       **i = value;
110       ++i;
111       ++iJson;
112     }
113     else
114     {
115       return false;
116     }
117   }
118   return true;
119 }
120
121 const std::map<std::string, Property::Value(*)(const TreeNode*)> kTypeIds {
122   // NONE
123   { "boolean", [](const TreeNode* tn) {
124     return ReadPrimitiveHelper<bool>(tn, ReadBool);
125   }},
126   { "float", [](const TreeNode* tn) {
127     return ReadPrimitiveHelper<float>(tn, ReadFloat);
128   }},
129   { "integer", [](const TreeNode* tn) {
130     return ReadPrimitiveHelper<int>(tn, ReadInt);
131   }},
132   { "vector2", ReadVectorHelper<Vector2> },
133   { "vector3", ReadVectorHelper<Vector3> },
134   { "vector4", ReadVectorHelper<Vector4> },
135   { "matrix3", ReadVectorHelper<Matrix3> },
136   { "matrix", ReadVectorHelper<Matrix> },
137   { "rectangle", [](const TreeNode* tn) {
138     Rect<int> value;
139     if (ReadQuadHelper<int>(tn, { &value.x, &value.y, &value.width, &value.height }))
140     {
141       return Property::Value(value);
142     }
143     return Property::Value();
144   }},
145   { "rotation", ReadRotationHelper },
146   // STRING - not particularly animatable
147   // ARRAY - not particularly animatable
148   // MAP - not particularly animatable
149   { "extents", [](const TreeNode* tn) {
150     Extents value;
151     if (ReadQuadHelper<uint16_t>(tn, { &value.start, &value.end, &value.top, &value.bottom }))
152     {
153       return Property::Value(value);
154     }
155     return Property::Value();
156   }},
157 };
158
159 Property::Value(* const kArrayPropertyProcessors[])(const TreeNode*) {
160   ReadVectorHelper<Matrix>,
161   ReadVectorHelper<Matrix3>,
162   ReadVectorHelper<Vector4>,
163   ReadVectorHelper<Vector3>,
164   ReadVectorHelper<Vector2>,
165   ReadVectorSingleFloatHelper
166 };
167
168 }  // nonamespace
169
170 bool ReadBool(const TreeNode* node, bool& num)
171 {
172   if (!node)
173   {
174     return false;
175   }
176
177   bool returnValue = false;
178   if (node->GetType() == TreeNode::BOOLEAN)
179   {
180     num = node->GetBoolean();
181     returnValue = true;
182   }
183
184   return returnValue;
185 }
186
187 bool ReadInt(const TreeNode* node, int& num)
188 {
189   if (!node)
190   {
191     return false;
192   }
193
194   bool returnValue = false;
195   if (node->GetType() == TreeNode::INTEGER)
196   {
197     num = node->GetInteger();
198     returnValue = true;
199   }
200   else if (node->GetType() == TreeNode::FLOAT)
201   {
202     num = static_cast<int>(node->GetFloat());
203     returnValue = true;
204   }
205
206   return returnValue;
207 }
208
209 bool ReadFloat(const TreeNode* node, float& num)
210 {
211   if (!node)
212   {
213     return false;
214   }
215
216   bool returnValue = false;
217   if (node->GetType() == TreeNode::FLOAT)
218   {
219     num = node->GetFloat();
220     returnValue = true;
221   }
222   else if (node->GetType() == TreeNode::INTEGER)
223   {
224     num = static_cast<float>(node->GetInteger());
225     returnValue = true;
226   }
227
228   return returnValue;
229 }
230
231 bool ReadIndex(const Toolkit::TreeNode* node, Index& num)
232 {
233   bool returnValue = node && node->GetType() == TreeNode::INTEGER;
234   if (returnValue)
235   {
236     num = static_cast<Index>(node->GetInteger());
237   }
238
239   return returnValue;
240 }
241
242 bool ReadBlob(const Toolkit::TreeNode* node, unsigned int& offset, unsigned int& length)
243 {
244   if (!node)
245   {
246     return false;
247   }
248
249   int iOffset, iLength;
250   bool success = ReadInt(node->GetChild("byteOffset"), iOffset) &&
251     ReadInt(node->GetChild("byteLength"), iLength) &&
252     iOffset >= 0 && iLength >= 0;  // 0 length might not be sensible, but is not an error at this stage.
253   if (success)
254   {
255     offset = static_cast<unsigned int>( iOffset );
256     length = static_cast<unsigned int>( iLength );
257   }
258   return success;
259 }
260
261 size_t GetNumericalArraySize(const TreeNode* node)
262 {
263   size_t size = 0;
264   if (node->GetType() == TreeNode::ARRAY)
265   {
266     for (auto i0 = node->CBegin(), i1 = node->CEnd(); i0 != i1 &&
267       ((*i0).second.GetType() == TreeNode::FLOAT || (*i0).second.GetType() == TreeNode::INTEGER);
268       ++i0)
269     {
270       ++size;
271     }
272   }
273   return size;
274 }
275
276 bool ReadVector(const TreeNode* node, float* num, unsigned int size)
277 {
278   if (!node)
279   {
280     return false;
281   }
282
283   bool returnValue = false;
284   if ((node->Size() >= size) && (node->GetType() == TreeNode::ARRAY))
285   {
286     unsigned int offset = 0u;
287     for (TreeNode::ConstIterator it = node->CBegin(); offset < size; ++it, ++offset)
288     {
289       const TreeNode& coord = (*it).second;
290       if (!ReadFloat(&coord, *(num + offset)))
291       {
292         return false;
293       }
294     }
295     returnValue = true;
296   }
297
298   return returnValue;
299 }
300
301 bool ReadVector(const Toolkit::TreeNode* node, int* num, unsigned int size)
302 {
303   if (!node)
304   {
305     return false;
306   }
307
308   bool returnValue = false;
309   if ((node->Size() >= size) && (node->GetType() == TreeNode::ARRAY))
310   {
311     unsigned int offset = 0u;
312     for (TreeNode::ConstIterator it = node->CBegin(); offset < size; ++it, ++offset)
313     {
314       const TreeNode& coord = (*it).second;
315       if (!ReadInt(&coord, *(num + offset)))
316       {
317         return false;
318       }
319     }
320     returnValue = true;
321   }
322
323   return returnValue;
324 }
325
326 bool ReadColor(const TreeNode* node, Vector4& color)
327 {
328   if (nullptr == node)
329   {
330     return false;
331   }
332
333   if (!ReadVector(node, color.AsFloat(), 4))
334   {
335     if (!ReadVector(node, color.AsFloat(), 3))
336     {
337       return false;
338     }
339     color.a = 1.f;
340   }
341
342   return true;
343 }
344
345 bool ReadTimePeriod(const TreeNode* node, TimePeriod& timePeriod)
346 {
347   if (!node)
348   {
349     return false;
350   }
351
352   if (!ReadFloat(node->GetChild("delay"), timePeriod.delaySeconds) || !ReadFloat(node->GetChild("duration"), timePeriod.durationSeconds))
353   {
354     return false;
355   }
356   return true;
357 }
358
359 bool ReadString(const TreeNode* node, std::string& strValue)
360 {
361   if (!node)
362   {
363     return false;
364   }
365
366   bool returnValue = false;
367   if (node->GetType() == TreeNode::STRING)
368   {
369     strValue = node->GetString();
370     returnValue = true;
371   }
372   return returnValue;
373 }
374
375 bool ReadStringVector(const TreeNode* node, std::vector<std::string>& strvector)
376 {
377   if (!node)
378   {
379     return false;
380   }
381
382   bool returnValue = false;
383   if (node->GetType() == TreeNode::ARRAY)
384   {
385     for (TreeNode::ConstIterator it = node->CBegin(); it != node->CEnd(); ++it)
386     {
387       const TreeNode& strNode = (*it).second;
388       if (strNode.GetType() == TreeNode::STRING)
389       {
390         strvector.push_back(strNode.GetString());
391       }
392       else
393       {
394         return false;
395       }
396     }
397     returnValue = true;
398   }
399   return returnValue;
400 }
401
402 Property::Value ReadPropertyValue(const Property::Type& propType, const TreeNode& tn)
403 {
404   switch (propType)
405   {
406   case Property::BOOLEAN:
407     return ReadPrimitiveHelper<bool>(&tn, ReadBool);
408
409   case Property::FLOAT:
410     return ReadPrimitiveHelper<float>(&tn, ReadFloat);
411
412   case Property::INTEGER:
413     return ReadPrimitiveHelper<int>(&tn, ReadInt);
414
415   case Property::VECTOR2:
416     return ReadVectorHelper<Vector2>(&tn);
417
418   case Property::VECTOR3:
419     return ReadVectorHelper<Vector3>(&tn);
420
421   case Property::VECTOR4:
422     return ReadVectorHelper<Vector4>(&tn);
423
424   case Property::MATRIX3:
425     return ReadVectorHelper<Matrix3>(&tn);
426
427   case Property::MATRIX:
428     return ReadVectorHelper<Matrix>(&tn);
429
430   case Property::RECTANGLE:
431   {
432     Rect<int> value;
433     if (ReadQuadHelper<int>(&tn, { &value.x, &value.y, &value.width, &value.height }))
434     {
435       return Property::Value(value);
436     }
437     break;
438   }
439
440   case Property::ROTATION:
441     return ReadRotationHelper(&tn);
442
443   case Property::EXTENTS:
444   {
445     Extents value;
446     if (ReadQuadHelper<uint16_t>(&tn, { &value.start, &value.end, &value.top, &value.bottom }))
447     {
448       return Property::Value(value);
449     }
450     break;
451   }
452
453   case Property::NONE: // fall
454   default:
455   {
456     DALI_ASSERT_ALWAYS(!"Property type incorrect");
457   }
458   }
459   return Property::Value();
460 }
461
462 Property::Value ReadPropertyValue(const Toolkit::TreeNode& tn)
463 {
464   Property::Value propValue;
465   if (tn.GetType() == TreeNode::OBJECT)  // attempt to disambiguate type.
466   {
467     auto jsonType = tn.GetChild("type");
468     if (jsonType && jsonType->GetType() == TreeNode::STRING)
469     {
470       auto iFind = kTypeIds.find(jsonType->GetString());
471       if (iFind != kTypeIds.end())
472       {
473         propValue = iFind->second(tn.GetChild("value"));
474       }
475     }
476   }
477
478   if (propValue.GetType() == Property::NONE)
479   {
480     if (tn.Size() == 0)
481     {
482       switch (tn.GetType())
483       {
484       case TreeNode::BOOLEAN:
485         propValue = ReadPrimitiveHelper<bool>(&tn, ReadBool);
486         break;
487
488       case TreeNode::INTEGER:
489         propValue = ReadPrimitiveHelper<int>(&tn, ReadInt);
490         break;
491
492       case TreeNode::FLOAT:
493         propValue = ReadPrimitiveHelper<float>(&tn, ReadFloat);
494         break;
495
496       default:
497         break;
498       }
499     }
500     else
501     {
502       bool allNumbers = true;
503       for (auto i0 = tn.CBegin(), i1 = tn.CEnd(); i0 != i1; ++i0)
504       {
505         auto type = (*i0).second.GetType();
506         if(!(type == TreeNode::FLOAT || type == TreeNode::INTEGER))
507         {
508           allNumbers = false;
509           break;
510         }
511       }
512
513       if (allNumbers)
514       {
515         // NOTE: rotations / rectangles / extents must be disambiguated in all circumstances.
516         for (auto& r : kArrayPropertyProcessors)
517         {
518           propValue = r(&tn);
519           if (propValue.GetType() != Property::NONE)
520           {
521             break;
522           }
523         }
524       }
525     }
526   }
527   return propValue;
528 }
529
530 }
531 }