[dali_2.3.20] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / visual-factory-impl.cpp
1 /*
2  * Copyright (c) 2024 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 // CLASS HEADER
18 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
19
20 // EXTERNAL INCLUDES
21 #include <dali/devel-api/scripting/scripting.h>
22 #include <dali/integration-api/adaptor-framework/adaptor.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/public-api/object/property-array.h>
25 #include <dali/public-api/object/type-registry-helper.h>
26 #include <dali/public-api/object/type-registry.h>
27
28 // INTERNAL INCLUDES
29 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
30 #include <dali-toolkit/devel-api/styling/style-manager-devel.h>
31 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
32 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
33 #include <dali-toolkit/internal/visuals/animated-gradient/animated-gradient-visual.h>
34 #include <dali-toolkit/internal/visuals/animated-image/animated-image-visual.h>
35 #include <dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.h>
36 #include <dali-toolkit/internal/visuals/arc/arc-visual.h>
37 #include <dali-toolkit/internal/visuals/border/border-visual.h>
38 #include <dali-toolkit/internal/visuals/color/color-visual.h>
39 #include <dali-toolkit/internal/visuals/gradient/gradient-visual.h>
40 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
41 #include <dali-toolkit/internal/visuals/image/image-visual.h>
42 #include <dali-toolkit/internal/visuals/mesh/mesh-visual.h>
43 #include <dali-toolkit/internal/visuals/npatch/npatch-visual.h>
44 #include <dali-toolkit/internal/visuals/primitive/primitive-visual.h>
45 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
46 #include <dali-toolkit/internal/visuals/text-visual-shader-factory.h>
47 #include <dali-toolkit/internal/visuals/text/text-visual.h>
48 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
49 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
50 #include <dali-toolkit/internal/visuals/visual-url.h>
51 #include <dali-toolkit/internal/visuals/wireframe/wireframe-visual.h>
52 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
53 #include <dali-toolkit/public-api/visuals/text-visual-properties.h>
54 #include <dali-toolkit/public-api/visuals/visual-properties.h>
55
56 namespace Dali
57 {
58 namespace Toolkit
59 {
60 namespace Internal
61 {
62 namespace
63 {
64 #if defined(DEBUG_ENABLED)
65 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
66 #endif
67
68 BaseHandle Create()
69 {
70   BaseHandle handle = Toolkit::VisualFactory::Get();
71
72   return handle;
73 }
74
75 DALI_TYPE_REGISTRATION_BEGIN_CREATE(Toolkit::VisualFactory, Dali::BaseHandle, Create, true)
76 DALI_TYPE_REGISTRATION_END()
77 const char* const BROKEN_IMAGE_FILE_NAME = "broken.png"; ///< The file name of the broken image.
78
79 static constexpr auto SHADER_TYPE_COUNT = 2u;
80
81 constexpr std::string_view VertexPredefines[SHADER_TYPE_COUNT]{
82   "",                                     //VisualFactoryCache::COLOR_SHADER
83   "#define IS_REQUIRED_ROUNDED_CORNER\n", //VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER
84 };
85 constexpr std::string_view FragmentPredefines[SHADER_TYPE_COUNT]{
86   "",                                     //VisualFactoryCache::COLOR_SHADER
87   "#define IS_REQUIRED_ROUNDED_CORNER\n", //VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER
88 };
89 constexpr VisualFactoryCache::ShaderType ShaderTypePredefines[SHADER_TYPE_COUNT]{
90   VisualFactoryCache::ShaderType::COLOR_SHADER,
91   VisualFactoryCache::ShaderType::COLOR_SHADER_ROUNDED_CORNER,
92 };
93
94 } // namespace
95
96 VisualFactory::VisualFactory(bool debugEnabled)
97 : mFactoryCache(),
98   mImageVisualShaderFactory(),
99   mTextVisualShaderFactory(),
100   mSlotDelegate(this),
101   mIdleCallback(nullptr),
102   mDebugEnabled(debugEnabled),
103   mPreMultiplyOnLoad(true),
104   mPrecompiledShaderRequested(false)
105 {
106 }
107
108 VisualFactory::~VisualFactory()
109 {
110   if(mIdleCallback && Adaptor::IsAvailable())
111   {
112     // Removes the callback from the callback manager in case the control is destroyed before the callback is executed.
113     Adaptor::Get().RemoveIdle(mIdleCallback);
114     mIdleCallback = nullptr;
115   }
116 }
117
118 void VisualFactory::OnStyleChangedSignal(Toolkit::StyleManager styleManager, StyleChange::Type type)
119 {
120   if(type == StyleChange::THEME_CHANGE)
121   {
122     SetBrokenImageUrl(styleManager);
123   }
124 }
125
126 void VisualFactory::OnBrokenImageChangedSignal(Toolkit::StyleManager styleManager)
127 {
128   SetBrokenImageUrl(styleManager);
129 }
130
131 Toolkit::Visual::Base VisualFactory::CreateVisual(const Property::Map& propertyMap)
132 {
133   Visual::BasePtr visualPtr;
134
135   Property::Value*           typeValue  = propertyMap.Find(Toolkit::Visual::Property::TYPE, VISUAL_TYPE);
136   Toolkit::DevelVisual::Type visualType = Toolkit::DevelVisual::IMAGE; // Default to IMAGE type.
137   if(typeValue)
138   {
139     Scripting::GetEnumerationProperty(*typeValue, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT, visualType);
140   }
141
142   switch(visualType)
143   {
144     case Toolkit::Visual::BORDER:
145     {
146       visualPtr = BorderVisual::New(GetFactoryCache(), propertyMap);
147       break;
148     }
149
150     case Toolkit::Visual::COLOR:
151     {
152       visualPtr = ColorVisual::New(GetFactoryCache(), propertyMap);
153       break;
154     }
155
156     case Toolkit::Visual::GRADIENT:
157     {
158       visualPtr = GradientVisual::New(GetFactoryCache(), propertyMap);
159       break;
160     }
161
162     case Toolkit::Visual::IMAGE:
163     {
164       Property::Value* imageURLValue = propertyMap.Find(Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME);
165       std::string      imageUrl;
166       if(imageURLValue)
167       {
168         if(imageURLValue->Get(imageUrl))
169         {
170           if(!imageUrl.empty())
171           {
172             VisualUrl visualUrl(imageUrl);
173
174             switch(visualUrl.GetType())
175             {
176               case VisualUrl::N_PATCH:
177               {
178                 visualPtr = NPatchVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl, propertyMap);
179                 break;
180               }
181               case VisualUrl::TVG:
182               case VisualUrl::SVG:
183               {
184                 visualPtr = SvgVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl, propertyMap);
185                 break;
186               }
187               case VisualUrl::GIF:
188               case VisualUrl::WEBP:
189               {
190                 visualPtr = AnimatedImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl, propertyMap);
191                 break;
192               }
193               case VisualUrl::JSON:
194               {
195                 visualPtr = AnimatedVectorImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), imageUrl, propertyMap);
196                 break;
197               }
198               case VisualUrl::REGULAR_IMAGE:
199               {
200                 visualPtr = ImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl, propertyMap);
201                 break;
202               }
203             }
204           }
205         }
206         else
207         {
208           Property::Array* array = imageURLValue->GetArray();
209           if(array && array->Count() > 0)
210           {
211             visualPtr = AnimatedImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), *array, propertyMap);
212           }
213         }
214       }
215       break;
216     }
217
218     case Toolkit::Visual::MESH:
219     {
220       visualPtr = MeshVisual::New(GetFactoryCache(), propertyMap);
221       break;
222     }
223
224     case Toolkit::Visual::PRIMITIVE:
225     {
226       visualPtr = PrimitiveVisual::New(GetFactoryCache(), propertyMap);
227       break;
228     }
229
230     case Toolkit::Visual::WIREFRAME:
231     {
232       visualPtr = WireframeVisual::New(GetFactoryCache(), propertyMap);
233       break;
234     }
235
236     case Toolkit::Visual::TEXT:
237     {
238       visualPtr = TextVisual::New(GetFactoryCache(), GetTextVisualShaderFactory(), propertyMap);
239       break;
240     }
241
242     case Toolkit::Visual::N_PATCH:
243     {
244       Property::Value* imageURLValue = propertyMap.Find(Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME);
245       std::string      imageUrl;
246       if(imageURLValue && imageURLValue->Get(imageUrl))
247       {
248         if(!imageUrl.empty())
249         {
250           visualPtr = NPatchVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), imageUrl, propertyMap);
251         }
252       }
253       break;
254     }
255
256     case Toolkit::Visual::SVG:
257     {
258       Property::Value* imageURLValue = propertyMap.Find(Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME);
259       std::string      imageUrl;
260       if(imageURLValue && imageURLValue->Get(imageUrl))
261       {
262         if(!imageUrl.empty())
263         {
264           visualPtr = SvgVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), imageUrl, propertyMap);
265         }
266       }
267       break;
268     }
269
270     case Toolkit::Visual::ANIMATED_IMAGE:
271     {
272       Property::Value* imageURLValue = propertyMap.Find(Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME);
273       std::string      imageUrl;
274       if(imageURLValue)
275       {
276         if(imageURLValue->Get(imageUrl))
277         {
278           if(!imageUrl.empty())
279           {
280             visualPtr = AnimatedImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), imageUrl, propertyMap);
281           }
282         }
283         else
284         {
285           Property::Array* array = imageURLValue->GetArray();
286           if(array && array->Count() > 0)
287           {
288             visualPtr = AnimatedImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), *array, propertyMap);
289           }
290         }
291       }
292       break;
293     }
294
295     case Toolkit::DevelVisual::ANIMATED_GRADIENT:
296     {
297       visualPtr = AnimatedGradientVisual::New(GetFactoryCache(), propertyMap);
298       break;
299     }
300
301     case Toolkit::DevelVisual::ANIMATED_VECTOR_IMAGE:
302     {
303       Property::Value* imageURLValue = propertyMap.Find(Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME);
304       std::string      imageUrl;
305       if(imageURLValue && imageURLValue->Get(imageUrl))
306       {
307         if(!imageUrl.empty())
308         {
309           visualPtr = AnimatedVectorImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), imageUrl, propertyMap);
310         }
311       }
312       break;
313     }
314
315     case Toolkit::DevelVisual::ARC:
316     {
317       visualPtr = ArcVisual::New(GetFactoryCache(), propertyMap);
318       break;
319     }
320   }
321
322   DALI_LOG_INFO(gLogFilter, Debug::Concise, "VisualFactory::CreateVisual( VisualType:%s %s%s)\n", Scripting::GetEnumerationName<Toolkit::DevelVisual::Type>(visualType, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT), (visualType == Toolkit::DevelVisual::IMAGE) ? "url:" : "", (visualType == Toolkit::DevelVisual::IMAGE) ? (([&]() {
323                   // Return URL if present in PropertyMap else return "not found message"
324                   Property::Value* imageURLValue = propertyMap.Find(Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME);
325                   return (imageURLValue) ? imageURLValue->Get<std::string>().c_str() : "url not found in PropertyMap";
326                 })())
327                                                                                                                                                                                                                                                                                                                             : "");
328
329   if(!visualPtr)
330   {
331     DALI_LOG_ERROR("VisualType unknown\n");
332   }
333
334   if(mDebugEnabled && visualType != Toolkit::DevelVisual::WIREFRAME)
335   {
336     //Create a WireframeVisual if we have debug enabled
337     visualPtr = WireframeVisual::New(GetFactoryCache(), visualPtr, propertyMap);
338   }
339
340   return Toolkit::Visual::Base(visualPtr.Get());
341 }
342
343 Toolkit::Visual::Base VisualFactory::CreateVisual(const std::string& url, ImageDimensions size)
344 {
345   Visual::BasePtr visualPtr;
346
347   if(!url.empty())
348   {
349     // first resolve url type to know which visual to create
350     VisualUrl visualUrl(url);
351     switch(visualUrl.GetType())
352     {
353       case VisualUrl::N_PATCH:
354       {
355         visualPtr = NPatchVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl);
356         break;
357       }
358       case VisualUrl::TVG:
359       case VisualUrl::SVG:
360       {
361         visualPtr = SvgVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl, size);
362         break;
363       }
364       case VisualUrl::GIF:
365       case VisualUrl::WEBP:
366       {
367         visualPtr = AnimatedImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl, size);
368         break;
369       }
370       case VisualUrl::JSON:
371       {
372         visualPtr = AnimatedVectorImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl, size);
373         break;
374       }
375       case VisualUrl::REGULAR_IMAGE:
376       {
377         visualPtr = ImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl, size);
378         break;
379       }
380     }
381   }
382
383   if(mDebugEnabled)
384   {
385     //Create a WireframeVisual if we have debug enabled
386     visualPtr = WireframeVisual::New(GetFactoryCache(), visualPtr);
387   }
388
389   return Toolkit::Visual::Base(visualPtr.Get());
390 }
391
392 void VisualFactory::SetPreMultiplyOnLoad(bool preMultiply)
393 {
394   if(mPreMultiplyOnLoad != preMultiply)
395   {
396     GetFactoryCache().SetPreMultiplyOnLoad(preMultiply);
397   }
398   mPreMultiplyOnLoad = preMultiply;
399 }
400
401 bool VisualFactory::GetPreMultiplyOnLoad() const
402 {
403   return mPreMultiplyOnLoad;
404 }
405
406 void VisualFactory::DiscardVisual(Toolkit::Visual::Base visual)
407 {
408   mDiscardedVisuals.emplace_back(visual);
409
410   RegisterDiscardCallback();
411 }
412
413 void VisualFactory::UsePreCompiledShader()
414 {
415   if(mPrecompiledShaderRequested)
416   {
417     return;
418   }
419   mPrecompiledShaderRequested = true;
420
421   ShaderPreCompiler::Get().Enable();
422
423   // Get image shader
424   std::vector<RawShaderData> rawShaderList;
425   RawShaderData              imageShaderData;
426   GetImageVisualShaderFactory().GetPreCompiledShader(imageShaderData);
427   rawShaderList.push_back(imageShaderData);
428
429   // Get text shader
430   RawShaderData textShaderData;
431   GetTextVisualShaderFactory().GetPreCompiledShader(textShaderData);
432   rawShaderList.push_back(textShaderData);
433
434   // Get color shader
435   RawShaderData colorShaderData;
436   GetPreCompiledShader(colorShaderData);
437   rawShaderList.push_back(colorShaderData);
438
439   // Save all shader
440   ShaderPreCompiler::Get().SavePreCompileShaderList(rawShaderList);
441 }
442
443 Internal::TextureManager& VisualFactory::GetTextureManager()
444 {
445   return GetFactoryCache().GetTextureManager();
446 }
447
448 void VisualFactory::SetBrokenImageUrl(Toolkit::StyleManager& styleManager)
449 {
450   const std::string        imageDirPath   = AssetManager::GetDaliImagePath();
451   std::string              brokenImageUrl = imageDirPath + BROKEN_IMAGE_FILE_NAME;
452   std::vector<std::string> customBrokenImageUrlList;
453
454   if(styleManager)
455   {
456     customBrokenImageUrlList       = Toolkit::DevelStyleManager::GetBrokenImageUrlList(styleManager);
457     const auto brokenImageUrlValue = Toolkit::DevelStyleManager::GetConfigurations(styleManager).Find("brokenImageUrl", Property::Type::STRING);
458     if(brokenImageUrlValue)
459     {
460       brokenImageUrlValue->Get(brokenImageUrl);
461     }
462   }
463
464   // Add default image
465   mFactoryCache->SetBrokenImageUrl(brokenImageUrl, customBrokenImageUrlList);
466 }
467
468 void VisualFactory::GetPreCompiledShader(RawShaderData& shaders)
469 {
470   std::vector<std::string_view> vertexPrefix;
471   std::vector<std::string_view> fragmentPrefix;
472   std::vector<std::string_view> shaderName;
473   int                           shaderCount = 0;
474   shaders.shaderCount                       = 0;
475   for(uint32_t i = 0u; i < SHADER_TYPE_COUNT; ++i)
476   {
477     vertexPrefix.push_back(VertexPredefines[i]);
478     fragmentPrefix.push_back(FragmentPredefines[i]);
479     shaderName.push_back(Scripting::GetLinearEnumerationName<VisualFactoryCache::ShaderType>(ShaderTypePredefines[i], VISUAL_SHADER_TYPE_TABLE, VISUAL_SHADER_TYPE_TABLE_COUNT));
480     shaderCount++;
481   }
482
483   shaders.vertexPrefix   = vertexPrefix;
484   shaders.fragmentPrefix = fragmentPrefix;
485   shaders.shaderName     = shaderName;
486   shaders.vertexShader   = SHADER_COLOR_VISUAL_SHADER_VERT;
487   shaders.fragmentShader = SHADER_COLOR_VISUAL_SHADER_FRAG;
488   shaders.shaderCount    = shaderCount;
489 }
490
491 Internal::VisualFactoryCache& VisualFactory::GetFactoryCache()
492 {
493   if(!mFactoryCache)
494   {
495     mFactoryCache                      = std::unique_ptr<VisualFactoryCache>(new VisualFactoryCache(mPreMultiplyOnLoad));
496     Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
497     if(styleManager)
498     {
499       styleManager.StyleChangedSignal().Connect(mSlotDelegate, &VisualFactory::OnStyleChangedSignal);
500       Toolkit::DevelStyleManager::BrokenImageChangedSignal(styleManager).Connect(mSlotDelegate, &VisualFactory::OnBrokenImageChangedSignal);
501     }
502     SetBrokenImageUrl(styleManager);
503   }
504
505   return *mFactoryCache;
506 }
507
508 ImageVisualShaderFactory& VisualFactory::GetImageVisualShaderFactory()
509 {
510   if(!mImageVisualShaderFactory)
511   {
512     mImageVisualShaderFactory = std::unique_ptr<ImageVisualShaderFactory>(new ImageVisualShaderFactory());
513   }
514   return *mImageVisualShaderFactory;
515 }
516
517 TextVisualShaderFactory& VisualFactory::GetTextVisualShaderFactory()
518 {
519   if(!mTextVisualShaderFactory)
520   {
521     mTextVisualShaderFactory = std::unique_ptr<TextVisualShaderFactory>(new TextVisualShaderFactory());
522   }
523   return *mTextVisualShaderFactory;
524 }
525
526 void VisualFactory::OnDiscardCallback()
527 {
528   mIdleCallback = nullptr;
529
530   // Discard visual now.
531   mDiscardedVisuals.clear();
532 }
533
534 void VisualFactory::RegisterDiscardCallback()
535 {
536   if(!mIdleCallback && Adaptor::IsAvailable())
537   {
538     // The callback manager takes the ownership of the callback object.
539     mIdleCallback = MakeCallback(this, &VisualFactory::OnDiscardCallback);
540
541     Adaptor& adaptor = Adaptor::Get();
542
543     if(DALI_UNLIKELY(!adaptor.AddIdle(mIdleCallback, false)))
544     {
545       DALI_LOG_ERROR("Fail to add idle callback for visual factory. Call it synchronously.\n");
546       OnDiscardCallback();
547     }
548   }
549 }
550
551 } // namespace Internal
552
553 } // namespace Toolkit
554
555 } // namespace Dali