Reset AsyncTask what we don't need anymore
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / svg / svg-visual.cpp
index b6f9520..8fcbf52 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/visuals/image-atlas-manager.h>
 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
-#include <dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h>
+#include <dali-toolkit/internal/visuals/svg/svg-task.h>
 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
 
 // EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/file-loader.h>
 #include <dali/devel-api/common/stage.h>
 #include <dali/integration-api/debug.h>
+#include <dali/public-api/rendering/decorated-visual-renderer.h>
 
 namespace Dali
 {
@@ -39,6 +39,8 @@ namespace Internal
 {
 namespace
 {
+const int CUSTOM_PROPERTY_COUNT(1); // atlas
+
 // property name
 const Dali::Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
 
@@ -46,22 +48,20 @@ const Dali::Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
 
 SvgVisualPtr SvgVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties)
 {
-  SvgVisualPtr svgVisual(new SvgVisual(factoryCache, shaderFactory, imageUrl));
-  svgVisual->Load();
+  SvgVisualPtr svgVisual(new SvgVisual(factoryCache, shaderFactory, imageUrl, ImageDimensions{}));
   svgVisual->SetProperties(properties);
   svgVisual->Initialize();
   return svgVisual;
 }
 
-SvgVisualPtr SvgVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl)
+SvgVisualPtr SvgVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, ImageDimensions size)
 {
-  SvgVisualPtr svgVisual(new SvgVisual(factoryCache, shaderFactory, imageUrl));
-  svgVisual->Load();
+  SvgVisualPtr svgVisual(new SvgVisual(factoryCache, shaderFactory, imageUrl, size));
   svgVisual->Initialize();
   return svgVisual;
 }
 
-SvgVisual::SvgVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl)
+SvgVisual::SvgVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, ImageDimensions size)
 : Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::SVG),
   mImageVisualShaderFactory(shaderFactory),
   mAtlasRect(FULL_TEXTURE_RECT),
@@ -70,7 +70,8 @@ SvgVisual::SvgVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory&
   mDefaultWidth(0),
   mDefaultHeight(0),
   mPlacementActor(),
-  mVisualSize(Vector2::ZERO),
+  mRasterizedSize(Vector2::ZERO),
+  mDesiredSize(size),
   mLoadFailed(false),
   mAttemptAtlasing(false)
 {
@@ -80,32 +81,44 @@ SvgVisual::SvgVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory&
 
 SvgVisual::~SvgVisual()
 {
+  if(Stage::IsInstalled())
+  {
+    if(mLoadingTask)
+    {
+      Dali::AsyncTaskManager::Get().RemoveTask(mLoadingTask);
+    }
+    if(mRasterizingTask)
+    {
+      Dali::AsyncTaskManager::Get().RemoveTask(mRasterizingTask);
+    }
+  }
 }
 
 void SvgVisual::OnInitialize()
 {
-  Shader shader;
-  if(!mImpl->mCustomShader)
+  Shader   shader   = GenerateShader();
+  Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
+  mImpl->mRenderer  = DecoratedVisualRenderer::New(geometry, shader);
+  mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
+
+  Vector2 dpi     = Stage::GetCurrent().GetDpi();
+  float   meanDpi = (dpi.height + dpi.width) * 0.5f;
+
+  mLoadingTask = new SvgLoadingTask(mVectorRenderer, mImageUrl, meanDpi, MakeCallback(this, &SvgVisual::ApplyRasterizedImage));
+
+  if(IsSynchronousLoadingRequired() && mImageUrl.IsLocalResource())
   {
-    shader = mImageVisualShaderFactory.GetShader(
-      mFactoryCache,
-      mAttemptAtlasing ? TextureAtlas::ENABLED : TextureAtlas::DISABLED,
-      DefaultTextureWrapMode::APPLY,
-      IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
-      IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED
-    );
+    mLoadingTask->Process();
+    if(!mLoadingTask->HasSucceeded())
+    {
+      mLoadFailed = true;
+    }
+    mLoadingTask.Reset(); // We don't need it anymore.
   }
   else
   {
-    shader = Shader::New(mImpl->mCustomShader->mVertexShader.empty() ? mImageVisualShaderFactory.GetVertexShaderSource().data() : mImpl->mCustomShader->mVertexShader,
-                         mImpl->mCustomShader->mFragmentShader.empty() ? mImageVisualShaderFactory.GetFragmentShaderSource().data() : mImpl->mCustomShader->mFragmentShader,
-                         mImpl->mCustomShader->mHints);
-
-    shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
+    Dali::AsyncTaskManager::Get().AddTask(mLoadingTask);
   }
-
-  Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
-  mImpl->mRenderer  = Renderer::New(geometry, shader);
 }
 
 void SvgVisual::DoSetProperties(const Property::Map& propertyMap)
@@ -126,6 +139,14 @@ void SvgVisual::DoSetProperties(const Property::Map& propertyMap)
     {
       DoSetProperty(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second);
     }
+    else if(keyValue.first == IMAGE_DESIRED_WIDTH)
+    {
+      DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_WIDTH, keyValue.second);
+    }
+    else if(keyValue.first == IMAGE_DESIRED_HEIGHT)
+    {
+      DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, keyValue.second);
+    }
   }
 }
 
@@ -158,6 +179,24 @@ void SvgVisual::DoSetProperty(Property::Index index, const Property::Value& valu
       }
       break;
     }
+    case Toolkit::ImageVisual::Property::DESIRED_WIDTH:
+    {
+      int32_t desiredWidth = 0;
+      if(value.Get(desiredWidth))
+      {
+        mDesiredSize.SetWidth(desiredWidth);
+      }
+      break;
+    }
+    case Toolkit::ImageVisual::Property::DESIRED_HEIGHT:
+    {
+      int32_t desiredHeight = 0;
+      if(value.Get(desiredHeight))
+      {
+        mDesiredSize.SetHeight(desiredHeight);
+      }
+      break;
+    }
   }
 }
 
@@ -167,7 +206,7 @@ void SvgVisual::DoSetOnScene(Actor& actor)
   mImpl->mRenderer.SetTextures(textureSet);
 
   // Register transform properties
-  mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
+  mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
 
   // Defer the rasterisation task until we get given a size (by Size Negotiation algorithm)
 
@@ -176,35 +215,71 @@ void SvgVisual::DoSetOnScene(Actor& actor)
 
   if(mLoadFailed)
   {
-    Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
-    textureSet.SetTexture(0u, brokenImage);
-
+    Vector2 imageSize = Vector2::ZERO;
+    imageSize         = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+    mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
     actor.AddRenderer(mImpl->mRenderer);
 
     ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
   }
   else
   {
-    // SVG visual needs it's size set before it can be rasterized hence set ResourceReady once on stage
-    ResourceReady(Toolkit::Visual::ResourceStatus::READY);
+    if(mImpl->mEventObserver)
+    {
+      // SVG visual needs it's size set before it can be rasterized hence request relayout once on stage
+      mImpl->mEventObserver->RelayoutRequest(*this);
+    }
   }
 }
 
 void SvgVisual::DoSetOffScene(Actor& actor)
 {
-  mFactoryCache.GetSVGRasterizationThread()->RemoveTask(this);
+  // Remove loading & rasterizing task
+  if(mLoadingTask)
+  {
+    Dali::AsyncTaskManager::Get().RemoveTask(mLoadingTask);
+    mLoadingTask.Reset();
+  }
+  if(mRasterizingTask)
+  {
+    Dali::AsyncTaskManager::Get().RemoveTask(mRasterizingTask);
+    mRasterizingTask.Reset();
+  }
 
   actor.RemoveRenderer(mImpl->mRenderer);
   mPlacementActor.Reset();
 
   // Reset the visual size to zero so that when adding the actor back to stage the SVG rasterization is forced
-  mVisualSize = Vector2::ZERO;
+  mRasterizedSize = Vector2::ZERO;
 }
 
 void SvgVisual::GetNaturalSize(Vector2& naturalSize)
 {
-  naturalSize.x = mDefaultWidth;
-  naturalSize.y = mDefaultHeight;
+  if(mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0)
+  {
+    naturalSize.x = mDesiredSize.GetWidth();
+    naturalSize.y = mDesiredSize.GetHeight();
+  }
+  else if(mLoadFailed && mImpl->mRenderer)
+  {
+    // Load failed, use broken image size
+    auto textureSet = mImpl->mRenderer.GetTextures();
+    if(textureSet && textureSet.GetTextureCount())
+    {
+      auto texture = textureSet.GetTexture(0);
+      if(texture)
+      {
+        naturalSize.x = texture.GetWidth();
+        naturalSize.y = texture.GetHeight();
+        return;
+      }
+    }
+  }
+  else
+  {
+    naturalSize.x = mDefaultWidth;
+    naturalSize.y = mDefaultHeight;
+  }
 }
 
 void SvgVisual::DoCreatePropertyMap(Property::Map& map) const
@@ -217,6 +292,8 @@ void SvgVisual::DoCreatePropertyMap(Property::Map& map) const
     map.Insert(Toolkit::ImageVisual::Property::ATLASING, mAttemptAtlasing);
   }
   map.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, IsSynchronousLoadingRequired());
+  map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
+  map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
 }
 
 void SvgVisual::DoCreateInstancePropertyMap(Property::Map& map) const
@@ -224,31 +301,12 @@ void SvgVisual::DoCreateInstancePropertyMap(Property::Map& map) const
   // Do nothing
 }
 
-void SvgVisual::Load()
+void SvgVisual::EnablePreMultipliedAlpha(bool preMultiplied)
 {
-  // load remote resource on svg rasterize thread.
-  if(mImageUrl.IsLocalResource())
+  // Make always enable pre multiplied alpha whether preMultiplied value is false.
+  if(!preMultiplied)
   {
-    Dali::Vector<uint8_t> buffer;
-    if(Dali::FileLoader::ReadFile(mImageUrl.GetUrl(), buffer))
-    {
-      buffer.PushBack('\0');
-
-      Vector2 dpi     = Stage::GetCurrent().GetDpi();
-      float   meanDpi = (dpi.height + dpi.width) * 0.5f;
-      if(!mVectorRenderer.Load(buffer, meanDpi))
-      {
-        mLoadFailed = true;
-        DALI_LOG_ERROR("SvgVisual::Load: Failed to load file! [%s]\n", mImageUrl.GetUrl().c_str());
-        return;
-      }
-      mVectorRenderer.GetDefaultSize(mDefaultWidth, mDefaultHeight);
-    }
-    else
-    {
-      mLoadFailed = true;
-      DALI_LOG_ERROR("SvgVisual::Load: Failed to read file! [%s]\n", mImageUrl.GetUrl().c_str());
-    }
+    DALI_LOG_WARNING("Note : SvgVisual cannot disable PreMultipliedAlpha\n");
   }
 }
 
@@ -259,128 +317,185 @@ void SvgVisual::AddRasterizationTask(const Vector2& size)
     unsigned int width  = static_cast<unsigned int>(size.width);
     unsigned int height = static_cast<unsigned int>(size.height);
 
-    Vector2 dpi     = Stage::GetCurrent().GetDpi();
-    float   meanDpi = (dpi.height + dpi.width) * 0.5f;
+    mRasterizingTask = new SvgRasterizingTask(mVectorRenderer, width, height, MakeCallback(this, &SvgVisual::ApplyRasterizedImage));
 
-    RasterizingTaskPtr newTask = new RasterizingTask(this, mVectorRenderer, mImageUrl, meanDpi, width, height);
     if(IsSynchronousLoadingRequired() && mImageUrl.IsLocalResource())
     {
-      newTask->Load();
-      newTask->Rasterize();
-      ApplyRasterizedImage(newTask->GetVectorRenderer(), newTask->GetPixelData(), newTask->IsLoaded());
+      mRasterizingTask->Process();
+      ApplyRasterizedImage(mRasterizingTask);
+      mRasterizingTask.Reset(); // We don't need it anymore.
     }
     else
     {
-      mFactoryCache.GetSVGRasterizationThread()->AddTask(newTask);
+      Dali::AsyncTaskManager::Get().AddTask(mRasterizingTask);
     }
   }
 }
 
-void SvgVisual::ApplyRasterizedImage(VectorImageRenderer vectorRenderer, PixelData rasterizedPixelData, bool isLoaded)
+void SvgVisual::ApplyRasterizedImage(SvgTaskPtr task)
 {
-  if(isLoaded && rasterizedPixelData && IsOnScene())
+  if(task->HasSucceeded())
   {
-    TextureSet currentTextureSet = mImpl->mRenderer.GetTextures();
-    if(mImpl->mFlags & Impl::IS_ATLASING_APPLIED)
+    PixelData rasterizedPixelData = task->GetPixelData();
+    if(mDefaultWidth == 0 || mDefaultHeight == 0)
     {
-      mFactoryCache.GetAtlasManager()->Remove(currentTextureSet, mAtlasRect);
+      task->GetRenderer().GetDefaultSize(mDefaultWidth, mDefaultHeight);
     }
 
-    TextureSet textureSet;
-
-    if(mAttemptAtlasing && !mImpl->mCustomShader)
+    // Rasterization success
+    if(rasterizedPixelData && IsOnScene())
     {
-      Vector4 atlasRect;
-      textureSet = mFactoryCache.GetAtlasManager()->Add(atlasRect, rasterizedPixelData);
-      if(textureSet) // atlasing
+      mRasterizedSize.x = static_cast<float>(rasterizedPixelData.GetWidth());
+      mRasterizedSize.y = static_cast<float>(rasterizedPixelData.GetHeight());
+
+      TextureSet currentTextureSet = mImpl->mRenderer.GetTextures();
+      if(mImpl->mFlags & Impl::IS_ATLASING_APPLIED)
       {
-        if(textureSet != currentTextureSet)
-        {
-          mImpl->mRenderer.SetTextures(textureSet);
-        }
-        mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, atlasRect);
-        mAtlasRect = atlasRect;
-        mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
+        mFactoryCache.GetAtlasManager()->Remove(currentTextureSet, mAtlasRect);
       }
-    }
 
-    if(!textureSet) // no atlasing - mAttemptAtlasing is false or adding to atlas is failed
-    {
-      Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, Pixel::RGBA8888, rasterizedPixelData.GetWidth(), rasterizedPixelData.GetHeight());
-      texture.Upload(rasterizedPixelData);
-      mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
+      TextureSet textureSet;
 
-      if(mAtlasRect == FULL_TEXTURE_RECT)
+      if(mAttemptAtlasing && !mImpl->mCustomShader)
       {
-        textureSet = currentTextureSet;
+        Vector4 atlasRect;
+        textureSet = mFactoryCache.GetAtlasManager()->Add(atlasRect, rasterizedPixelData);
+        if(textureSet) // atlasing
+        {
+          if(textureSet != currentTextureSet)
+          {
+            mImpl->mRenderer.SetTextures(textureSet);
+          }
+          mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, atlasRect);
+          mAtlasRect = atlasRect;
+          mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
+        }
       }
-      else
+
+      if(!textureSet) // no atlasing - mAttemptAtlasing is false or adding to atlas is failed
       {
-        textureSet = TextureSet::New();
-        mImpl->mRenderer.SetTextures(textureSet);
+        Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, Pixel::RGBA8888, rasterizedPixelData.GetWidth(), rasterizedPixelData.GetHeight());
+        texture.Upload(rasterizedPixelData);
+        mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
 
-        mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT);
-        mAtlasRect = FULL_TEXTURE_RECT;
+        if(mAtlasRect == FULL_TEXTURE_RECT)
+        {
+          textureSet = currentTextureSet;
+        }
+        else
+        {
+          textureSet = TextureSet::New();
+          mImpl->mRenderer.SetTextures(textureSet);
+
+          mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT);
+          mAtlasRect = FULL_TEXTURE_RECT;
+        }
+
+        if(textureSet)
+        {
+          textureSet.SetTexture(0, texture);
+        }
       }
 
-      if(textureSet)
+      // Rasterized pixels are uploaded to texture. If weak handle is holding a placement actor, it is the time to add the renderer to actor.
+      Actor actor = mPlacementActor.GetHandle();
+      if(actor)
       {
-        textureSet.SetTexture(0, texture);
+        actor.AddRenderer(mImpl->mRenderer);
+        // reset the weak handle so that the renderer only get added to actor once
+        mPlacementActor.Reset();
       }
-    }
 
-    // Rasterized pixels are uploaded to texture. If weak handle is holding a placement actor, it is the time to add the renderer to actor.
-    Actor actor = mPlacementActor.GetHandle();
-    if(actor)
-    {
-      actor.AddRenderer(mImpl->mRenderer);
-      // reset the weak handle so that the renderer only get added to actor once
-      mPlacementActor.Reset();
+      // Svg loaded and ready to display
+      ResourceReady(Toolkit::Visual::ResourceStatus::READY);
     }
-
-    // Svg loaded and ready to display
-    ResourceReady(Toolkit::Visual::ResourceStatus::READY);
   }
-  else if(!isLoaded || !rasterizedPixelData)
+  else if(!mLoadFailed)
   {
+    mLoadFailed = true;
+
     Actor actor = mPlacementActor.GetHandle();
     if(actor)
     {
-      TextureSet textureSet = mImpl->mRenderer.GetTextures();
-
-      Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
-      textureSet.SetTexture(0u, brokenImage);
-
+      Vector2 imageSize = Vector2::ZERO;
+      imageSize         = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+      mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
       actor.AddRenderer(mImpl->mRenderer);
     }
 
     ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
   }
+
+  // We don't need to keep tasks anymore. reset now.
+  if(task == mLoadingTask)
+  {
+    mLoadingTask.Reset();
+  }
+  if(task == mRasterizingTask)
+  {
+    mRasterizingTask.Reset();
+  }
 }
 
 void SvgVisual::OnSetTransform()
 {
-  Vector2 visualSize = mImpl->mTransform.GetVisualSize(mImpl->mControlSize);
-
   if(IsOnScene() && !mLoadFailed)
   {
-    if(visualSize != mVisualSize)
+    Vector2 size;
+    if(mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0)
+    {
+      // Use desired size
+      size = Vector2(mDesiredSize.GetWidth(), mDesiredSize.GetHeight());
+    }
+    else
+    {
+      // Use visual size
+      size = mImpl->mTransform.GetVisualSize(mImpl->mControlSize);
+    }
+
+    if(size != mRasterizedSize || mDefaultWidth == 0 || mDefaultHeight == 0)
     {
-      AddRasterizationTask(visualSize);
-      mVisualSize = visualSize;
+      mRasterizedSize = size;
+      AddRasterizationTask(size);
     }
   }
 
   if(mImpl->mRenderer)
   {
-    mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
+    mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
+  }
+}
+
+void SvgVisual::UpdateShader()
+{
+  if(mImpl->mRenderer)
+  {
+    Shader shader = GenerateShader();
+    mImpl->mRenderer.SetShader(shader);
   }
 }
 
-bool SvgVisual::IsResourceReady() const
+Shader SvgVisual::GenerateShader() const
 {
-  return (mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY ||
-          mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::FAILED);
+  Shader shader;
+  if(!mImpl->mCustomShader)
+  {
+    shader = mImageVisualShaderFactory.GetShader(
+      mFactoryCache,
+      ImageVisualShaderFeature::FeatureBuilder()
+        .EnableTextureAtlas(mAttemptAtlasing)
+        .EnableRoundedCorner(IsRoundedCornerRequired())
+        .EnableBorderline(IsBorderlineRequired()));
+  }
+  else
+  {
+    shader = Shader::New(mImpl->mCustomShader->mVertexShader.empty() ? mImageVisualShaderFactory.GetVertexShaderSource().data() : mImpl->mCustomShader->mVertexShader,
+                         mImpl->mCustomShader->mFragmentShader.empty() ? mImageVisualShaderFactory.GetFragmentShaderSource().data() : mImpl->mCustomShader->mFragmentShader,
+                         mImpl->mCustomShader->mHints);
+
+    shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
+  }
+  return shader;
 }
 
 } // namespace Internal