Merge "Fix ZWJ, ZWNJ issues" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / visual-factory-cache.cpp
1 /*
2  * Copyright (c) 2021 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 "visual-factory-cache.h"
19
20 // EXTERNAL INCLUDES
21 #include <dali/devel-api/adaptor-framework/image-loading.h>
22 #include <dali/devel-api/common/hash.h>
23
24 // INTERNAL INCLUDES
25 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-manager.h>
26 #include <dali-toolkit/internal/visuals/color/color-visual.h>
27 #include <dali-toolkit/internal/visuals/image-atlas-manager.h>
28 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
29 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
30 #include <dali/integration-api/debug.h>
31
32 namespace Dali
33 {
34 namespace Toolkit
35 {
36 namespace Internal
37 {
38 namespace
39 {
40
41 /**
42  * @brief Creates the geometry formed from the vertices and indices
43  *
44  * @param[in]  vertices             The vertices to generate the geometry from
45  * @param[in]  indices              The indices to generate the geometry from
46  * @return The geometry formed from the vertices and indices
47  */
48 Geometry GenerateGeometry(const Vector<Vector2>& vertices, const Vector<unsigned short>& indices)
49 {
50   Property::Map vertexFormat;
51   vertexFormat["aPosition"] = Property::VECTOR2;
52   VertexBuffer vertexBuffer = VertexBuffer::New(vertexFormat);
53   if(vertices.Size() > 0)
54   {
55     vertexBuffer.SetData(&vertices[0], vertices.Size());
56   }
57
58   // Create the geometry object
59   Geometry geometry = Geometry::New();
60   geometry.AddVertexBuffer(vertexBuffer);
61   if(indices.Size() > 0)
62   {
63     geometry.SetIndexBuffer(&indices[0], indices.Size());
64   }
65
66   return geometry;
67 }
68
69 /**
70  * @brief Adds the indices to form a quad composed off two triangles where the indices are organised in a grid
71  *
72  * @param[out] indices     The indices to add to
73  * @param[in]  rowIdx      The row index to start the quad
74  * @param[in]  nextRowIdx  The index to the next row
75  */
76 void AddQuadIndices(Vector<unsigned short>& indices, unsigned int rowIdx, unsigned int nextRowIdx)
77 {
78   indices.PushBack(rowIdx);
79   indices.PushBack(nextRowIdx + 1);
80   indices.PushBack(rowIdx + 1);
81
82   indices.PushBack(rowIdx);
83   indices.PushBack(nextRowIdx);
84   indices.PushBack(nextRowIdx + 1);
85 }
86
87 /**
88  * @brief Adds the vertices to create for npatch
89  * @param[out] vertices The vertices to add to
90  * @param[in]  x        The x value of vector
91  * @param[in]  y        The y value of vector
92  */
93 void AddVertex(Vector<Vector2>& vertices, unsigned int x, unsigned int y)
94 {
95   vertices.PushBack(Vector2(x, y));
96 }
97
98 } //unnamed namespace
99
100 VisualFactoryCache::VisualFactoryCache(bool preMultiplyOnLoad)
101 : mSvgRasterizeThread(NULL),
102   mVectorAnimationManager(),
103   mPreMultiplyOnLoad(preMultiplyOnLoad),
104   mBrokenImageInfoContainer()
105 {
106 }
107
108 VisualFactoryCache::~VisualFactoryCache()
109 {
110   SvgRasterizeThread::TerminateThread(mSvgRasterizeThread);
111 }
112
113 Geometry VisualFactoryCache::GetGeometry(GeometryType type)
114 {
115   if(!mGeometry[type] && type == QUAD_GEOMETRY)
116   {
117     mGeometry[type] = CreateQuadGeometry();
118   }
119
120   return mGeometry[type];
121 }
122
123 void VisualFactoryCache::SaveGeometry(GeometryType type, Geometry geometry)
124 {
125   mGeometry[type] = geometry;
126 }
127
128 Shader VisualFactoryCache::GetShader(ShaderType type)
129 {
130   return mShader[type];
131 }
132
133 void VisualFactoryCache::SaveShader(ShaderType type, Shader shader)
134 {
135   mShader[type] = shader;
136 }
137
138 Geometry VisualFactoryCache::CreateQuadGeometry()
139 {
140   const float halfWidth  = 0.5f;
141   const float halfHeight = 0.5f;
142   struct QuadVertex
143   {
144     Vector2 position;
145   };
146   QuadVertex quadVertexData[4] =
147     {
148       {Vector2(-halfWidth, -halfHeight)},
149       {Vector2(-halfWidth, halfHeight)},
150       {Vector2(halfWidth, -halfHeight)},
151       {Vector2(halfWidth, halfHeight)}};
152
153   Property::Map quadVertexFormat;
154   quadVertexFormat["aPosition"] = Property::VECTOR2;
155   VertexBuffer quadVertices     = VertexBuffer::New(quadVertexFormat);
156   quadVertices.SetData(quadVertexData, 4);
157
158   // Create the geometry object
159   Geometry geometry = Geometry::New();
160   geometry.AddVertexBuffer(quadVertices);
161   geometry.SetType(Geometry::TRIANGLE_STRIP);
162
163   return geometry;
164 }
165
166 ImageAtlasManagerPtr VisualFactoryCache::GetAtlasManager()
167 {
168   if(!mAtlasManager)
169   {
170     mAtlasManager = new ImageAtlasManager();
171     if(!mBrokenImageInfoContainer.empty())
172     {
173       mAtlasManager->SetBrokenImage(mBrokenImageInfoContainer[0].url);
174     }
175   }
176
177   return mAtlasManager;
178 }
179
180 TextureManager& VisualFactoryCache::GetTextureManager()
181 {
182   return mTextureManager;
183 }
184
185 NPatchLoader& VisualFactoryCache::GetNPatchLoader()
186 {
187   return mNPatchLoader;
188 }
189
190 SvgRasterizeThread* VisualFactoryCache::GetSVGRasterizationThread()
191 {
192   if(!mSvgRasterizeThread)
193   {
194     mSvgRasterizeThread = new SvgRasterizeThread();
195     mSvgRasterizeThread->Start();
196   }
197   return mSvgRasterizeThread;
198 }
199
200 VectorAnimationManager& VisualFactoryCache::GetVectorAnimationManager()
201 {
202   if(!mVectorAnimationManager)
203   {
204     mVectorAnimationManager = std::unique_ptr<VectorAnimationManager>(new VectorAnimationManager());
205   }
206   return *mVectorAnimationManager;
207 }
208
209 Geometry VisualFactoryCache::CreateGridGeometry(Uint16Pair gridSize)
210 {
211   uint16_t gridWidth  = gridSize.GetWidth();
212   uint16_t gridHeight = gridSize.GetHeight();
213
214   // Create vertices
215   Vector<Vector2> vertices;
216   vertices.Reserve((gridWidth + 1) * (gridHeight + 1));
217
218   for(int y = 0; y < gridHeight + 1; ++y)
219   {
220     for(int x = 0; x < gridWidth + 1; ++x)
221     {
222       vertices.PushBack(Vector2((float)x / gridWidth - 0.5f, (float)y / gridHeight - 0.5f));
223     }
224   }
225
226   // Create indices
227   Vector<unsigned short> indices;
228   indices.Reserve((gridWidth + 2) * gridHeight * 2 - 2);
229
230   for(unsigned int row = 0u; row < gridHeight; ++row)
231   {
232     unsigned int rowStartIndex     = row * (gridWidth + 1u);
233     unsigned int nextRowStartIndex = rowStartIndex + gridWidth + 1u;
234
235     if(row != 0u) // degenerate index on non-first row
236     {
237       indices.PushBack(rowStartIndex);
238     }
239
240     for(unsigned int column = 0u; column < gridWidth + 1u; column++) // main strip
241     {
242       indices.PushBack(rowStartIndex + column);
243       indices.PushBack(nextRowStartIndex + column);
244     }
245
246     if(row != gridHeight - 1u) // degenerate index on non-last row
247     {
248       indices.PushBack(nextRowStartIndex + gridWidth);
249     }
250   }
251
252   Property::Map vertexFormat;
253   vertexFormat["aPosition"] = Property::VECTOR2;
254   VertexBuffer vertexBuffer = VertexBuffer::New(vertexFormat);
255   if(vertices.Size() > 0)
256   {
257     vertexBuffer.SetData(&vertices[0], vertices.Size());
258   }
259
260   Property::Map indexFormat;
261   indexFormat["indices"]         = Property::INTEGER;
262   VertexBuffer indexVertexBuffer = VertexBuffer::New(indexFormat);
263
264   // Create the geometry object
265   Geometry geometry = Geometry::New();
266   geometry.AddVertexBuffer(vertexBuffer);
267   if(indices.Size() > 0)
268   {
269     geometry.SetIndexBuffer(&indices[0], indices.Size());
270   }
271
272   geometry.SetType(Geometry::TRIANGLE_STRIP);
273
274   return geometry;
275 }
276
277 Texture VisualFactoryCache::GetBrokenVisualImage(uint32_t brokenIndex)
278 {
279   if(!(mBrokenImageInfoContainer[brokenIndex].texture))
280   {
281     PixelData          pixelData;
282     Devel::PixelBuffer pixelBuffer = LoadImageFromFile(mBrokenImageInfoContainer[brokenIndex].url);
283     if(pixelBuffer)
284     {
285       pixelData                = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
286       mBrokenImageInfoContainer[brokenIndex].texture  = Texture::New(Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
287       mBrokenImageInfoContainer[brokenIndex].texture.Upload(pixelData);
288       mBrokenImageInfoContainer[brokenIndex].width = pixelData.GetWidth();
289       mBrokenImageInfoContainer[brokenIndex].height = pixelData.GetHeight();
290     }
291   }
292   return mBrokenImageInfoContainer[brokenIndex].texture;
293 }
294
295 void VisualFactoryCache::SetPreMultiplyOnLoad(bool preMultiply)
296 {
297   mPreMultiplyOnLoad = preMultiply;
298 }
299
300 bool VisualFactoryCache::GetPreMultiplyOnLoad()
301 {
302   return mPreMultiplyOnLoad;
303 }
304
305 void VisualFactoryCache::SetBrokenImageUrl(const std::vector<std::string>& brokenImageUrlList)
306 {
307   mBrokenImageInfoContainer.clear();
308   mBrokenImageInfoContainer.assign(brokenImageUrlList.size(), BrokenImageInfo());
309   for(unsigned int i = 0; i < brokenImageUrlList.size(); i++)
310   {
311     mBrokenImageInfoContainer[i].url = brokenImageUrlList[i];
312   }
313 }
314
315 VisualUrl::Type VisualFactoryCache::GetBrokenImageVisualType(int index)
316 {
317   return mBrokenImageInfoContainer[index].visualType;
318 }
319
320 Geometry VisualFactoryCache::CreateNPatchGeometry(Uint16Pair gridSize)
321 {
322   uint16_t gridWidth  = gridSize.GetWidth();
323   uint16_t gridHeight = gridSize.GetHeight();
324
325   // Create vertices
326   Vector<Vector2> vertices;
327   vertices.Reserve((gridWidth + 1) * (gridHeight + 1));
328
329   for(int y = 0; y < gridHeight + 1; ++y)
330   {
331     for(int x = 0; x < gridWidth + 1; ++x)
332     {
333       AddVertex(vertices, x, y);
334     }
335   }
336
337   // Create indices
338   Vector<unsigned short> indices;
339   indices.Reserve(gridWidth * gridHeight * 6);
340
341   unsigned int rowIdx     = 0;
342   unsigned int nextRowIdx = gridWidth + 1;
343   for(int y = 0; y < gridHeight; ++y, ++nextRowIdx, ++rowIdx)
344   {
345     for(int x = 0; x < gridWidth; ++x, ++nextRowIdx, ++rowIdx)
346     {
347       AddQuadIndices(indices, rowIdx, nextRowIdx);
348     }
349   }
350
351   return GenerateGeometry(vertices, indices);
352 }
353
354 Geometry VisualFactoryCache::GetNPatchGeometry(int index)
355 {
356   Geometry          geometry;
357   const NPatchData* data;
358   if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[index].npatchId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
359   {
360     if(data->GetStretchPixelsX().Size() == 1 && data->GetStretchPixelsY().Size() == 1)
361     {
362       geometry = GetGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY);
363       if(!geometry)
364       {
365         geometry = CreateNPatchGeometry(Uint16Pair(3,3));
366         SaveGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY, geometry);
367       }
368     }
369     else if(data->GetStretchPixelsX().Size() > 0 || data->GetStretchPixelsY().Size() > 0)
370     {
371       Uint16Pair gridSize(2 * data->GetStretchPixelsX().Size() + 1, 2 * data->GetStretchPixelsY().Size() + 1);
372       geometry = CreateNPatchGeometry(gridSize);
373     }
374   }
375   else
376   {
377     // no N patch data so use default geometry
378     geometry = GetGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY);
379     if(!geometry)
380     {
381       geometry = CreateNPatchGeometry(Uint16Pair(3,3));
382       SaveGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY, geometry);
383     }
384   }
385   return geometry;
386 }
387
388 Shader VisualFactoryCache::GetNPatchShader(int index)
389 {
390   Shader            shader;
391   const NPatchData* data;
392   // 0 is either no data (load failed?) or no stretch regions on image
393   // for both cases we use the default shader
394   NPatchUtility::StretchRanges::SizeType xStretchCount = 0;
395   NPatchUtility::StretchRanges::SizeType yStretchCount = 0;
396
397   // ask loader for the regions
398   if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[index].npatchId, data))
399   {
400     xStretchCount = data->GetStretchPixelsX().Count();
401     yStretchCount = data->GetStretchPixelsY().Count();
402   }
403
404   if(DALI_LIKELY((xStretchCount == 0 && yStretchCount == 0)))
405   {
406     shader = GetShader(VisualFactoryCache::NINE_PATCH_SHADER);
407     if(DALI_UNLIKELY(!shader))
408     {
409       shader = Shader::New(SHADER_NPATCH_VISUAL_3X3_SHADER_VERT, SHADER_NPATCH_VISUAL_SHADER_FRAG);
410
411       // Only cache vanilla 9 patch shaders
412       SaveShader(VisualFactoryCache::NINE_PATCH_SHADER, shader);
413     }
414   }
415   else if(xStretchCount > 0 || yStretchCount > 0)
416   {
417     std::stringstream vertexShader;
418     vertexShader << "#define FACTOR_SIZE_X " << xStretchCount + 2 << "\n"
419                  << "#define FACTOR_SIZE_Y " << yStretchCount + 2 << "\n"
420                  << SHADER_NPATCH_VISUAL_SHADER_VERT;
421     shader = Shader::New(vertexShader.str(), SHADER_NPATCH_VISUAL_SHADER_FRAG);
422   }
423   return shader;
424 }
425
426 void VisualFactoryCache::RegisterStretchProperties(Renderer& renderer, const char* uniformName, const NPatchUtility::StretchRanges& stretchPixels, uint16_t imageExtent)
427 {
428   uint16_t     prevEnd     = 0;
429   uint16_t     prevFix     = 0;
430   uint16_t     prevStretch = 0;
431   unsigned int i           = 1;
432   for(NPatchUtility::StretchRanges::ConstIterator it = stretchPixels.Begin(); it != stretchPixels.End(); ++it, ++i)
433   {
434     uint16_t start = it->GetX();
435     uint16_t end   = it->GetY();
436
437     uint16_t fix     = prevFix + start - prevEnd;
438     uint16_t stretch = prevStretch + end - start;
439
440     std::stringstream uniform;
441     uniform << uniformName << "[" << i << "]";
442     renderer.RegisterProperty(uniform.str(), Vector2(fix, stretch));
443
444     prevEnd     = end;
445     prevFix     = fix;
446     prevStretch = stretch;
447   }
448
449   {
450     prevFix += imageExtent - prevEnd;
451     std::stringstream uniform;
452     uniform << uniformName << "[" << i << "]";
453     renderer.RegisterProperty(uniform.str(), Vector2(prevFix, prevStretch));
454   }
455 }
456
457 void VisualFactoryCache::ApplyTextureAndUniforms(Renderer& renderer, int index)
458 {
459   const NPatchData* data;
460   TextureSet        textureSet;
461   if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[index].npatchId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
462   {
463     textureSet = data->GetTextures();
464     mBrokenImageInfoContainer[index].texture = data->GetTextures().GetTexture(0);
465
466     if(data->GetStretchPixelsX().Size() == 1 && data->GetStretchPixelsY().Size() == 1)
467     {
468       //special case for 9 patch
469       Uint16Pair stretchX = data->GetStretchPixelsX()[0];
470       Uint16Pair stretchY = data->GetStretchPixelsY()[0];
471
472       uint16_t stretchWidth  = (stretchX.GetY() >= stretchX.GetX()) ? stretchX.GetY() - stretchX.GetX() : 0;
473       uint16_t stretchHeight = (stretchY.GetY() >= stretchY.GetX()) ? stretchY.GetY() - stretchY.GetX() : 0;
474
475       renderer.RegisterProperty("uFixed[0]", Vector2::ZERO);
476       renderer.RegisterProperty("uFixed[1]", Vector2(stretchX.GetX(), stretchY.GetX()));
477       renderer.RegisterProperty("uFixed[2]", Vector2(data->GetCroppedWidth() - stretchWidth, data->GetCroppedHeight() - stretchHeight));
478       renderer.RegisterProperty("uStretchTotal", Vector2(stretchWidth, stretchHeight));
479     }
480     else
481     {
482       renderer.RegisterProperty("uNinePatchFactorsX[0]", Vector2::ZERO);
483       renderer.RegisterProperty("uNinePatchFactorsY[0]", Vector2::ZERO);
484
485       RegisterStretchProperties(renderer, "uNinePatchFactorsX", data->GetStretchPixelsX(), data->GetCroppedWidth());
486       RegisterStretchProperties(renderer, "uNinePatchFactorsY", data->GetStretchPixelsY(), data->GetCroppedHeight());
487     }
488     renderer.SetTextures(textureSet);
489   }
490 }
491
492 void VisualFactoryCache::UpdateBrokenImageRenderer(Renderer& renderer, const Vector2& size)
493 {
494   // Load Information for broken image
495   for(uint32_t index = 0; index < mBrokenImageInfoContainer.size(); index++)
496   {
497     if(mBrokenImageInfoContainer[index].width == 0 && mBrokenImageInfoContainer[index].height == 0)
498     {
499       if(!mBrokenImageInfoContainer[index].url.empty())
500       {
501         VisualUrl visualUrl(mBrokenImageInfoContainer[index].url);
502         mBrokenImageInfoContainer[index].visualType = visualUrl.GetType();
503         if(mBrokenImageInfoContainer[index].visualType == VisualUrl::Type::N_PATCH)
504         {
505           const NPatchData* data;
506           Rect<int> border;
507           mBrokenImageInfoContainer[index].npatchId = mNPatchLoader.Load( mTextureManager, NULL, mBrokenImageInfoContainer[index].url, border, mPreMultiplyOnLoad, true);
508           if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[index].npatchId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
509           {
510             mBrokenImageInfoContainer[index].width = data->GetCroppedWidth();
511             mBrokenImageInfoContainer[index].height = data->GetCroppedHeight();
512           }
513           else
514           {
515             DALI_LOG_ERROR("Can't update renderer for broken image. maybe image loading is failed [path:%s] \n",mBrokenImageInfoContainer[index].url.c_str());
516           }
517         }
518         else
519         {
520           GetBrokenVisualImage(index);
521         }
522       }
523     }
524   }
525
526   // Set Texutre to renderer
527   int brokenIndex = GetProperBrokenImageIndex(size);
528   if(GetBrokenImageVisualType(brokenIndex) == VisualUrl::N_PATCH)
529   {
530     // Set geometry and shader for npatch
531     Geometry geometry = GetNPatchGeometry(brokenIndex);
532     Shader shader = GetNPatchShader(brokenIndex);
533     renderer.SetGeometry(geometry);
534     renderer.SetShader(shader);
535     ApplyTextureAndUniforms(renderer, brokenIndex);
536   }
537   else
538   {
539     Texture brokenImage = GetBrokenVisualImage(brokenIndex);
540     TextureSet textureSet = TextureSet::New();
541     textureSet.SetTexture(0u, brokenImage);
542     renderer.SetTextures(textureSet);
543   }
544 }
545
546 int32_t VisualFactoryCache::GetProperBrokenImageIndex(const Vector2& size)
547 {
548   // Sets the default broken type
549   int32_t returnIndex = 0;
550   if((size.width == 0 || size.height == 0))
551   {
552     // To do : Need to add observer about size
553     return returnIndex;
554   }
555
556   // Find the proper value if we know the size of the image
557   for(int32_t index = static_cast<int32_t>(mBrokenImageInfoContainer.size()) - 1; index >= 0; index--)
558   {
559     // Skip if the value is not set
560     if(mBrokenImageInfoContainer[index].width == 0 || mBrokenImageInfoContainer[index].height == 0)
561     {
562       continue;
563     }
564
565     if(mBrokenImageInfoContainer[index].width < size.width && mBrokenImageInfoContainer[index].height < size.height)
566     {
567       returnIndex = index;
568       break;
569     }
570   }
571
572   return returnIndex;
573 }
574
575 } // namespace Internal
576
577 } // namespace Toolkit
578
579 } // namespace Dali