831d4b47ab2ee938df6d14d834daab70dcceec7c
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / npatch / npatch-visual.cpp
1 /*
2  * Copyright (c) 2022 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 "npatch-visual.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/image-loading.h>
23 #include <dali/devel-api/common/stage.h>
24 #include <dali/devel-api/rendering/renderer-devel.h>
25 #include <dali/integration-api/debug.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/devel-api/utility/npatch-helper.h>
29 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
30 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
31 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
32 #include <dali-toolkit/internal/visuals/npatch-loader.h>
33 #include <dali-toolkit/internal/visuals/rendering-addon.h>
34 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
35 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
36 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
37 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
38 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
39 #include <dali-toolkit/public-api/visuals/visual-properties.h>
40
41 namespace Dali
42 {
43 namespace Toolkit
44 {
45 namespace Internal
46 {
47 namespace
48 {
49 const int CUSTOM_PROPERTY_COUNT(5); // fixed(3),stretch,aux
50 }
51
52 /////////////////NPatchVisual////////////////
53
54 NPatchVisualPtr NPatchVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties)
55 {
56   NPatchVisualPtr nPatchVisual(new NPatchVisual(factoryCache, shaderFactory));
57   nPatchVisual->mImageUrl = imageUrl;
58   nPatchVisual->SetProperties(properties);
59   nPatchVisual->Initialize();
60   return nPatchVisual;
61 }
62
63 NPatchVisualPtr NPatchVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl)
64 {
65   NPatchVisualPtr nPatchVisual(new NPatchVisual(factoryCache, shaderFactory));
66   nPatchVisual->mImageUrl = imageUrl;
67   nPatchVisual->Initialize();
68   return nPatchVisual;
69 }
70
71 void NPatchVisual::LoadImages()
72 {
73   TextureManager& textureManager     = mFactoryCache.GetTextureManager();
74   bool            synchronousLoading = mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
75
76   if(mId == NPatchData::INVALID_NPATCH_DATA_ID && (mImageUrl.IsLocalResource() || mImageUrl.IsBufferResource()))
77   {
78     bool preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader ? true : false;
79     mId                    = mLoader.Load(textureManager, this, mImageUrl, mBorder, preMultiplyOnLoad, synchronousLoading);
80
81     const NPatchData* data;
82     if(mLoader.GetNPatchData(mId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
83     {
84       EnablePreMultipliedAlpha(data->IsPreMultiplied());
85     }
86   }
87
88   if(!mAuxiliaryPixelBuffer && mAuxiliaryUrl.IsValid() && (mAuxiliaryUrl.IsLocalResource() || mAuxiliaryUrl.IsBufferResource()))
89   {
90     // Load the auxiliary image
91     auto preMultiplyOnLoading = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
92     mAuxiliaryPixelBuffer     = textureManager.LoadPixelBuffer(mAuxiliaryUrl, Dali::ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, this, true, preMultiplyOnLoading);
93
94     // If synchronousLoading is true, we can check the auxiliaryResource's statue now.
95     if(synchronousLoading)
96     {
97       mAuxiliaryResourceStatus = mAuxiliaryPixelBuffer ? Toolkit::Visual::ResourceStatus::READY : Toolkit::Visual::ResourceStatus::FAILED;
98     }
99   }
100 }
101
102 void NPatchVisual::GetNaturalSize(Vector2& naturalSize)
103 {
104   naturalSize.x = 0u;
105   naturalSize.y = 0u;
106
107   // load now if not already loaded
108   const NPatchData* data;
109   if(mLoader.GetNPatchData(mId, data) && data->GetLoadingState() != NPatchData::LoadingState::LOADING)
110   {
111     naturalSize.x = data->GetCroppedWidth();
112     naturalSize.y = data->GetCroppedHeight();
113   }
114   else
115   {
116     if(mImageUrl.IsValid())
117     {
118       ImageDimensions dimensions = Dali::GetOriginalImageSize(mImageUrl.GetUrl());
119       if(dimensions != ImageDimensions(0, 0))
120       {
121         naturalSize.x = dimensions.GetWidth();
122         naturalSize.y = dimensions.GetHeight();
123       }
124     }
125   }
126
127   if(mAuxiliaryPixelBuffer)
128   {
129     naturalSize.x = std::max(naturalSize.x, float(mAuxiliaryPixelBuffer.GetWidth()));
130     naturalSize.y = std::max(naturalSize.y, float(mAuxiliaryPixelBuffer.GetHeight()));
131   }
132 }
133
134 void NPatchVisual::DoSetProperties(const Property::Map& propertyMap)
135 {
136   // URL is already passed in via constructor
137
138   Property::Value* borderOnlyValue = propertyMap.Find(Toolkit::ImageVisual::Property::BORDER_ONLY, BORDER_ONLY);
139   if(borderOnlyValue)
140   {
141     borderOnlyValue->Get(mBorderOnly);
142   }
143
144   Property::Value* borderValue = propertyMap.Find(Toolkit::ImageVisual::Property::BORDER, BORDER);
145   if(borderValue && !borderValue->Get(mBorder)) // If value exists and is rect, just set mBorder
146   {
147     // Not a rect so try vector4
148     Vector4 border;
149     if(borderValue->Get(border))
150     {
151       mBorder.left   = static_cast<int>(border.x);
152       mBorder.right  = static_cast<int>(border.y);
153       mBorder.bottom = static_cast<int>(border.z);
154       mBorder.top    = static_cast<int>(border.w);
155     }
156   }
157
158   Property::Value* auxImage = propertyMap.Find(Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE, AUXILIARY_IMAGE_NAME);
159   if(auxImage)
160   {
161     std::string url;
162     if(auxImage->Get(url))
163     {
164       mAuxiliaryUrl = url;
165     }
166   }
167
168   Property::Value* auxImageAlpha = propertyMap.Find(Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA, AUXILIARY_IMAGE_ALPHA_NAME);
169   if(auxImageAlpha)
170   {
171     auxImageAlpha->Get(mAuxiliaryImageAlpha);
172   }
173
174   Property::Value* synchronousLoading = propertyMap.Find(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, SYNCHRONOUS_LOADING);
175   if(synchronousLoading)
176   {
177     bool sync = false;
178     synchronousLoading->Get(sync);
179     if(sync)
180     {
181       mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
182     }
183     else
184     {
185       mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
186     }
187   }
188
189   Property::Value* releasePolicy = propertyMap.Find(Toolkit::ImageVisual::Property::RELEASE_POLICY, RELEASE_POLICY_NAME);
190   if(releasePolicy)
191   {
192     releasePolicy->Get(mReleasePolicy);
193   }
194 }
195
196 void NPatchVisual::DoSetOnScene(Actor& actor)
197 {
198   // load when first go on stage
199   LoadImages();
200
201   const NPatchData* data;
202   if(mLoader.GetNPatchData(mId, data))
203   {
204     Geometry geometry = CreateGeometry();
205     Shader   shader   = CreateShader();
206
207     mImpl->mRenderer.SetGeometry(geometry);
208     mImpl->mRenderer.SetShader(shader);
209
210     mPlacementActor = actor;
211     // If all reasources are already loaded, apply textures and uniforms now
212     // else, will be completed uploaded at LoadComplete function asynchronously.
213     if(data->GetLoadingState() != NPatchData::LoadingState::LOADING &&
214        (!mAuxiliaryUrl.IsValid() || mAuxiliaryResourceStatus != Toolkit::Visual::ResourceStatus::PREPARING))
215     {
216       if(RenderingAddOn::Get().IsValid())
217       {
218         RenderingAddOn::Get().SubmitRenderTask(mImpl->mRenderer, data->GetRenderingMap());
219       }
220
221       ApplyTextureAndUniforms();
222       actor.AddRenderer(mImpl->mRenderer);
223       mPlacementActor.Reset();
224
225       // npatch loaded and ready to display
226       if(data->GetLoadingState() != NPatchData::LoadingState::LOAD_COMPLETE ||
227          (mAuxiliaryUrl.IsValid() && mAuxiliaryResourceStatus != Toolkit::Visual::ResourceStatus::READY))
228       {
229         ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
230       }
231       else
232       {
233         ResourceReady(Toolkit::Visual::ResourceStatus::READY);
234       }
235     }
236   }
237 }
238
239 void NPatchVisual::DoSetOffScene(Actor& actor)
240 {
241   if((mId != NPatchData::INVALID_NPATCH_DATA_ID) && mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED)
242   {
243     mLoader.Remove(mId, this);
244     mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
245     mId                    = NPatchData::INVALID_NPATCH_DATA_ID;
246   }
247
248   actor.RemoveRenderer(mImpl->mRenderer);
249   mPlacementActor.Reset();
250 }
251
252 void NPatchVisual::OnSetTransform()
253 {
254   if(mImpl->mRenderer)
255   {
256     mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
257   }
258 }
259
260 bool NPatchVisual::IsResourceReady() const
261 {
262   return (mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY ||
263           mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::FAILED);
264 }
265
266 void NPatchVisual::DoCreatePropertyMap(Property::Map& map) const
267 {
268   map.Clear();
269   bool sync = IsSynchronousLoadingRequired();
270   map.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, sync);
271   map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::N_PATCH);
272   map.Insert(Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl());
273   map.Insert(Toolkit::ImageVisual::Property::BORDER_ONLY, mBorderOnly);
274   map.Insert(Toolkit::ImageVisual::Property::BORDER, mBorder);
275   map.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy);
276
277   if(mAuxiliaryUrl.IsValid())
278   {
279     map.Insert(Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE, mAuxiliaryUrl.GetUrl());
280     map.Insert(Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA, mAuxiliaryImageAlpha);
281   }
282 }
283
284 void NPatchVisual::DoCreateInstancePropertyMap(Property::Map& map) const
285 {
286   if(mAuxiliaryUrl.IsValid())
287   {
288     map.Insert(Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE, mAuxiliaryUrl.GetUrl());
289     map.Insert(Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA, mAuxiliaryImageAlpha);
290   }
291 }
292
293 NPatchVisual::NPatchVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory)
294 : Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::N_PATCH),
295   mPlacementActor(),
296   mLoader(factoryCache.GetNPatchLoader()),
297   mImageVisualShaderFactory(shaderFactory),
298   mImageUrl(),
299   mAuxiliaryUrl(),
300   mId(NPatchData::INVALID_NPATCH_DATA_ID),
301   mAuxiliaryResourceStatus(Toolkit::Visual::ResourceStatus::PREPARING),
302   mBorderOnly(false),
303   mBorder(),
304   mAuxiliaryImageAlpha(0.0f),
305   mReleasePolicy(Toolkit::ImageVisual::ReleasePolicy::DETACHED)
306 {
307   EnablePreMultipliedAlpha(mFactoryCache.GetPreMultiplyOnLoad());
308 }
309
310 NPatchVisual::~NPatchVisual()
311 {
312   if(Stage::IsInstalled() && (mId != NPatchData::INVALID_NPATCH_DATA_ID) && (mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER))
313   {
314     mLoader.Remove(mId, this);
315     mId = NPatchData::INVALID_NPATCH_DATA_ID;
316   }
317 }
318
319 void NPatchVisual::OnInitialize()
320 {
321   // Get basic geometry and shader
322   Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
323   Shader   shader   = mImageVisualShaderFactory.GetShader(
324     mFactoryCache,
325     ImageVisualShaderFeature::FeatureBuilder());
326
327   mImpl->mRenderer = VisualRenderer::New(geometry, shader);
328   mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
329
330   //Register transform properties
331   mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
332 }
333
334 Geometry NPatchVisual::CreateGeometry()
335 {
336   Geometry          geometry;
337   const NPatchData* data;
338   if(mLoader.GetNPatchData(mId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
339   {
340     if(data->GetStretchPixelsX().Size() == 1 && data->GetStretchPixelsY().Size() == 1)
341     {
342       if(DALI_UNLIKELY(mBorderOnly))
343       {
344         geometry = GetNinePatchGeometry(VisualFactoryCache::NINE_PATCH_BORDER_GEOMETRY);
345       }
346       else
347       {
348         if(data->GetRenderingMap())
349         {
350           uint32_t elementCount[2];
351           geometry = RenderingAddOn::Get().CreateGeometryGrid(data->GetRenderingMap(), Uint16Pair(3, 3), elementCount);
352           if(mImpl->mRenderer)
353           {
354             RenderingAddOn::Get().SubmitRenderTask(mImpl->mRenderer, data->GetRenderingMap());
355           }
356         }
357         else
358         {
359           geometry = GetNinePatchGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY);
360         }
361       }
362     }
363     else if(data->GetStretchPixelsX().Size() > 0 || data->GetStretchPixelsY().Size() > 0)
364     {
365       Uint16Pair gridSize(2 * data->GetStretchPixelsX().Size() + 1, 2 * data->GetStretchPixelsY().Size() + 1);
366       if(!data->GetRenderingMap())
367       {
368         geometry = !mBorderOnly ? NPatchHelper::CreateGridGeometry(gridSize) : NPatchHelper::CreateBorderGeometry(gridSize);
369       }
370       else
371       {
372         uint32_t elementCount[2];
373         geometry = !mBorderOnly ? RenderingAddOn::Get().CreateGeometryGrid(data->GetRenderingMap(), gridSize, elementCount) : NPatchHelper::CreateBorderGeometry(gridSize);
374         if(mImpl->mRenderer)
375         {
376           RenderingAddOn::Get().SubmitRenderTask(mImpl->mRenderer, data->GetRenderingMap());
377         }
378       }
379     }
380   }
381   else
382   {
383     // no N patch data so use default geometry
384     geometry = GetNinePatchGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY);
385   }
386   return geometry;
387 }
388
389 Shader NPatchVisual::CreateShader()
390 {
391   Shader            shader;
392   const NPatchData* data;
393   // 0 is either no data (load failed?) or no stretch regions on image
394   // for both cases we use the default shader
395   NPatchUtility::StretchRanges::SizeType xStretchCount = 0;
396   NPatchUtility::StretchRanges::SizeType yStretchCount = 0;
397
398   auto fragmentShader = mAuxiliaryPixelBuffer ? SHADER_NPATCH_VISUAL_MASK_SHADER_FRAG
399                                               : SHADER_NPATCH_VISUAL_SHADER_FRAG;
400   auto shaderType = mAuxiliaryPixelBuffer ? VisualFactoryCache::NINE_PATCH_MASK_SHADER
401                                           : VisualFactoryCache::NINE_PATCH_SHADER;
402
403   // ask loader for the regions
404   if(mLoader.GetNPatchData(mId, data))
405   {
406     xStretchCount = data->GetStretchPixelsX().Count();
407     yStretchCount = data->GetStretchPixelsY().Count();
408   }
409
410   if(DALI_LIKELY(!mImpl->mCustomShader))
411   {
412     if(DALI_LIKELY((xStretchCount == 1 && yStretchCount == 1) ||
413                    (xStretchCount == 0 && yStretchCount == 0)))
414     {
415       shader = mFactoryCache.GetShader(shaderType);
416       if(DALI_UNLIKELY(!shader))
417       {
418         shader = Shader::New(SHADER_NPATCH_VISUAL_3X3_SHADER_VERT, fragmentShader);
419         // Only cache vanilla 9 patch shaders
420         mFactoryCache.SaveShader(shaderType, shader);
421       }
422     }
423     else if(xStretchCount > 0 || yStretchCount > 0)
424     {
425       std::stringstream vertexShader;
426       vertexShader << "#define FACTOR_SIZE_X " << xStretchCount + 2 << "\n"
427                    << "#define FACTOR_SIZE_Y " << yStretchCount + 2 << "\n"
428                    << SHADER_NPATCH_VISUAL_SHADER_VERT;
429
430       shader = Shader::New(vertexShader.str(), fragmentShader);
431     }
432   }
433   else
434   {
435     Dali::Shader::Hint::Value hints = Dali::Shader::Hint::NONE;
436
437     if(!mImpl->mCustomShader->mFragmentShader.empty())
438     {
439       fragmentShader = mImpl->mCustomShader->mFragmentShader.c_str();
440     }
441     hints = mImpl->mCustomShader->mHints;
442
443     /* Apply Custom Vertex Shader only if image is 9-patch */
444     if((xStretchCount == 1 && yStretchCount == 1) ||
445        (xStretchCount == 0 && yStretchCount == 0))
446     {
447       const char* vertexShader = SHADER_NPATCH_VISUAL_3X3_SHADER_VERT.data();
448
449       if(!mImpl->mCustomShader->mVertexShader.empty())
450       {
451         vertexShader = mImpl->mCustomShader->mVertexShader.c_str();
452       }
453       shader = Shader::New(vertexShader, fragmentShader, hints);
454     }
455     else if(xStretchCount > 0 || yStretchCount > 0)
456     {
457       std::stringstream vertexShader;
458       vertexShader << "#define FACTOR_SIZE_X " << xStretchCount + 2 << "\n"
459                    << "#define FACTOR_SIZE_Y " << yStretchCount + 2 << "\n"
460                    << SHADER_NPATCH_VISUAL_SHADER_VERT;
461
462       shader = Shader::New(vertexShader.str(), fragmentShader, hints);
463     }
464   }
465
466   return shader;
467 }
468
469 void NPatchVisual::ApplyTextureAndUniforms()
470 {
471   const NPatchData* data;
472   TextureSet        textureSet;
473
474   if(mLoader.GetNPatchData(mId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
475   {
476     textureSet = data->GetTextures();
477     NPatchHelper::ApplyTextureAndUniforms(mImpl->mRenderer, data);
478
479     if(mAuxiliaryPixelBuffer)
480     {
481       // If the auxiliary image is smaller than the un-stretched NPatch, use CPU resizing to enlarge it to the
482       // same size as the unstretched NPatch. This will give slightly higher quality results than just relying
483       // on GL interpolation alone.
484       if(mAuxiliaryPixelBuffer.GetWidth() < data->GetCroppedWidth() &&
485          mAuxiliaryPixelBuffer.GetHeight() < data->GetCroppedHeight())
486       {
487         mAuxiliaryPixelBuffer.Resize(data->GetCroppedWidth(), data->GetCroppedHeight());
488       }
489
490       // Note, this resets mAuxiliaryPixelBuffer handle
491       auto auxiliaryPixelData = Devel::PixelBuffer::Convert(mAuxiliaryPixelBuffer);
492
493       auto texture = Texture::New(TextureType::TEXTURE_2D,
494                                   auxiliaryPixelData.GetPixelFormat(),
495                                   auxiliaryPixelData.GetWidth(),
496                                   auxiliaryPixelData.GetHeight());
497       texture.Upload(auxiliaryPixelData);
498
499       // TODO : This code exist due to the texture cache manager hold TextureSet, not Texture.
500       // If we call textureSet.SetTexture(1, texture) directly, the cached TextureSet also be changed.
501       // We should make pass utc-Dali-VisualFactory.cpp UtcDaliNPatchVisualAuxiliaryImage02().
502       TextureSet tempTextureSet = TextureSet::New();
503       tempTextureSet.SetTexture(0, textureSet.GetTexture(0));
504       tempTextureSet.SetTexture(1, texture);
505       textureSet = tempTextureSet;
506
507       mImpl->mRenderer.RegisterProperty(DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA,
508                                         AUXILIARY_IMAGE_ALPHA_NAME,
509                                         mAuxiliaryImageAlpha);
510     }
511     mImpl->mRenderer.SetTextures(textureSet);
512   }
513   else
514   {
515     DALI_LOG_ERROR("The N patch image '%s' is not a valid N patch image\n", mImageUrl.GetUrl().c_str());
516     textureSet = TextureSet::New();
517
518     Actor   actor     = mPlacementActor.GetHandle();
519     Vector2 imageSize = Vector2::ZERO;
520     if(actor)
521     {
522       imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
523     }
524     mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize, false);
525   }
526
527   // Register transform properties
528   mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
529 }
530
531 Geometry NPatchVisual::GetNinePatchGeometry(VisualFactoryCache::GeometryType subType)
532 {
533   Geometry geometry = mFactoryCache.GetGeometry(subType);
534   if(!geometry)
535   {
536     if(DALI_LIKELY(VisualFactoryCache::NINE_PATCH_GEOMETRY == subType))
537     {
538       geometry = NPatchHelper::CreateGridGeometry(Uint16Pair(3, 3));
539     }
540     else if(VisualFactoryCache::NINE_PATCH_BORDER_GEOMETRY == subType)
541     {
542       geometry = NPatchHelper::CreateBorderGeometry(Uint16Pair(3, 3));
543     }
544     mFactoryCache.SaveGeometry(subType, geometry);
545   }
546   return geometry;
547 }
548
549 void NPatchVisual::SetResource()
550 {
551   Geometry geometry = CreateGeometry();
552   Shader   shader   = CreateShader();
553
554   mImpl->mRenderer.SetGeometry(geometry);
555   mImpl->mRenderer.SetShader(shader);
556
557   Actor actor = mPlacementActor.GetHandle();
558   if(actor)
559   {
560     ApplyTextureAndUniforms();
561     actor.AddRenderer(mImpl->mRenderer);
562     mPlacementActor.Reset();
563   }
564 }
565
566 void NPatchVisual::LoadComplete(bool loadSuccess, TextureInformation textureInformation)
567 {
568   if(textureInformation.returnType == TextureUploadObserver::ReturnType::TEXTURE) // For the Url.
569   {
570     if(loadSuccess)
571     {
572       EnablePreMultipliedAlpha(textureInformation.preMultiplied);
573     }
574   }
575   else // For the AuxiliaryUrl : ReturnType::PIXEL_BUFFER
576   {
577     if(loadSuccess && textureInformation.url == mAuxiliaryUrl.GetUrl())
578     {
579       mAuxiliaryPixelBuffer    = textureInformation.pixelBuffer;
580       mAuxiliaryResourceStatus = Toolkit::Visual::ResourceStatus::READY;
581     }
582     else
583     {
584       mAuxiliaryResourceStatus = Toolkit::Visual::ResourceStatus::FAILED;
585     }
586   }
587   // If auxiliaryUrl didn't set || auxiliaryUrl load done.
588   if(!mAuxiliaryUrl.IsValid() || mAuxiliaryResourceStatus != Toolkit::Visual::ResourceStatus::PREPARING)
589   {
590     const NPatchData* data;
591     // and.. If Url loading done.
592     if(mImpl->mRenderer && mLoader.GetNPatchData(mId, data) && data->GetLoadingState() != NPatchData::LoadingState::LOADING)
593     {
594       SetResource();
595       // npatch loaded and ready to display
596       if(data->GetLoadingState() != NPatchData::LoadingState::LOAD_COMPLETE ||
597          (mAuxiliaryUrl.IsValid() && mAuxiliaryResourceStatus != Toolkit::Visual::ResourceStatus::READY))
598       {
599         ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
600       }
601       else
602       {
603         ResourceReady(Toolkit::Visual::ResourceStatus::READY);
604       }
605     }
606   }
607 }
608
609 } // namespace Internal
610
611 } // namespace Toolkit
612
613 } // namespace Dali