Upload tiling text texture without copy
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / text / text-visual.cpp
index 5d523a4..14e1ce3 100644 (file)
@@ -22,7 +22,9 @@
 #include <dali/devel-api/adaptor-framework/image-loading.h>
 #include <dali/devel-api/images/pixel-data-devel.h>
 #include <dali/devel-api/rendering/renderer-devel.h>
+#include <dali/devel-api/rendering/texture-devel.h>
 #include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+#include <dali/integration-api/debug.h>
 #include <string.h>
 
 // INTERNAL HEADER
@@ -49,7 +51,7 @@ namespace Internal
 {
 namespace
 {
-const int CUSTOM_PROPERTY_COUNT(10); // 5 transform properties + anim,premul,size,offset,multicol
+const int CUSTOM_PROPERTY_COUNT(5); // anim,premul,size,offset,multicol
 
 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
 
@@ -147,9 +149,9 @@ void OpacityConstraint(float& current, const PropertyInputContainer& inputs)
 
 } // unnamed namespace
 
-TextVisualPtr TextVisual::New(VisualFactoryCache& factoryCache, const Property::Map& properties)
+TextVisualPtr TextVisual::New(VisualFactoryCache& factoryCache, TextVisualShaderFactory& shaderFactory, const Property::Map& properties)
 {
-  TextVisualPtr textVisualPtr(new TextVisual(factoryCache));
+  TextVisualPtr textVisualPtr(new TextVisual(factoryCache, shaderFactory));
   textVisualPtr->SetProperties(properties);
   textVisualPtr->Initialize();
   return textVisualPtr;
@@ -239,14 +241,27 @@ void TextVisual::DoCreateInstancePropertyMap(Property::Map& map) const
   map.Insert(Toolkit::TextVisual::Property::TEXT, text);
 }
 
-TextVisual::TextVisual(VisualFactoryCache& factoryCache)
+void TextVisual::EnablePreMultipliedAlpha(bool preMultiplied)
+{
+  // Make always enable pre multiplied alpha whether preMultiplied value is false.
+  if(!preMultiplied)
+  {
+    DALI_LOG_WARNING("Note : TextVisual cannot disable PreMultipliedAlpha\n");
+  }
+}
+
+TextVisual::TextVisual(VisualFactoryCache& factoryCache, TextVisualShaderFactory& shaderFactory)
 : Visual::Base(factoryCache, Visual::FittingMode::FIT_KEEP_ASPECT_RATIO, Toolkit::Visual::TEXT),
   mController(Text::Controller::New()),
   mTypesetter(Text::Typesetter::New(mController->GetTextModel())),
+  mTextVisualShaderFactory(shaderFactory),
+  mTextShaderFeatureCache(),
   mAnimatableTextColorPropertyIndex(Property::INVALID_INDEX),
   mTextColorAnimatableIndex(Property::INVALID_INDEX),
   mRendererUpdateNeeded(false)
 {
+  // Enable the pre-multiplied alpha to improve the text quality
+  mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
 }
 
 TextVisual::~TextVisual()
@@ -256,9 +271,9 @@ TextVisual::~TextVisual()
 void TextVisual::OnInitialize()
 {
   Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
-  Shader   shader   = GetTextShader(mFactoryCache, TextType::SINGLE_COLOR_TEXT, TextType::NO_EMOJI, TextType::NO_STYLES);
+  Shader   shader   = GetTextShader(mFactoryCache, TextVisualShaderFeature::FeatureBuilder());
 
-  mImpl->mRenderer = Renderer::New(geometry, shader);
+  mImpl->mRenderer = VisualRenderer::New(geometry, shader);
   mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
 }
 
@@ -294,13 +309,10 @@ void TextVisual::DoSetOnScene(Actor& actor)
 
   mImpl->mRenderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, Toolkit::DepthIndex::CONTENT);
 
-  // Enable the pre-multiplied alpha to improve the text quality
-  EnablePreMultipliedAlpha(true);
-
   const Vector4& defaultColor = mController->GetTextModel()->GetDefaultColor();
   if(mTextColorAnimatableIndex == Property::INVALID_INDEX)
   {
-    mTextColorAnimatableIndex = mImpl->mRenderer.RegisterProperty("uTextColorAnimatable", defaultColor);
+    mTextColorAnimatableIndex = mImpl->mRenderer.RegisterUniqueProperty("uTextColorAnimatable", defaultColor);
   }
   else
   {
@@ -323,6 +335,7 @@ void TextVisual::DoSetOnScene(Actor& actor)
     // Make zero if the alpha value of text color is zero to skip rendering text
     if(!mOpacityConstraint)
     {
+      // VisualRenderer::Property::OPACITY uses same animatable property internally.
       mOpacityConstraint = Constraint::New<float>(mImpl->mRenderer, Dali::DevelRenderer::Property::OPACITY, OpacityConstraint);
       mOpacityConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex));
     }
@@ -332,8 +345,6 @@ void TextVisual::DoSetOnScene(Actor& actor)
   // Renderer needs textures and to be added to control
   mRendererUpdateNeeded = true;
 
-  mRendererList.push_back(mImpl->mRenderer);
-
   UpdateRenderer();
 }
 
@@ -552,14 +563,15 @@ void TextVisual::UpdateRenderer()
         shadowEnabled = true;
       }
 
-      const bool underlineEnabled       = mController->GetTextModel()->IsUnderlineEnabled();
-      const bool outlineEnabled         = (mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1);
-      const bool backgroundEnabled      = mController->GetTextModel()->IsBackgroundEnabled();
-      const bool markupProcessorEnabled = mController->IsMarkupProcessorEnabled();
-      const bool strikethroughEnabled   = mController->GetTextModel()->IsStrikethroughEnabled();
-
-      const bool styleEnabled   = (shadowEnabled || underlineEnabled || outlineEnabled || backgroundEnabled || markupProcessorEnabled || strikethroughEnabled);
-      const bool isOverlayStyle = underlineEnabled || strikethroughEnabled;
+      const bool outlineEnabled             = (mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1);
+      const bool backgroundEnabled          = mController->GetTextModel()->IsBackgroundEnabled();
+      const bool markupProcessorEnabled     = mController->IsMarkupProcessorEnabled();
+      const bool markupUnderlineEnabled     = markupProcessorEnabled && mController->GetTextModel()->IsMarkupUnderlineSet();
+      const bool markupStrikethroughEnabled = markupProcessorEnabled && mController->GetTextModel()->IsMarkupStrikethroughSet();
+      const bool underlineEnabled           = mController->GetTextModel()->IsUnderlineEnabled() || markupUnderlineEnabled;
+      const bool strikethroughEnabled       = mController->GetTextModel()->IsStrikethroughEnabled() || markupStrikethroughEnabled;
+      const bool styleEnabled               = (shadowEnabled || outlineEnabled || backgroundEnabled || markupProcessorEnabled);
+      const bool isOverlayStyle             = underlineEnabled || strikethroughEnabled;
 
       AddRenderer(control, relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled, isOverlayStyle);
 
@@ -581,76 +593,70 @@ void TextVisual::AddTexture(TextureSet& textureSet, PixelData& data, Sampler& sa
   textureSet.SetSampler(textureSetIndex, sampler);
 }
 
-PixelData TextVisual::ConvertToPixelData(unsigned char* buffer, int width, int height, int offsetPosition, const Pixel::Format textPixelFormat)
+void TextVisual::AddTilingTexture(TextureSet& textureSet, TilingInfo& tilingInfo, PixelData& data, Sampler& sampler, unsigned int textureSetIndex)
 {
-  int            bpp        = Pixel::GetBytesPerPixel(textPixelFormat);
-  unsigned int   bufferSize = width * height * bpp;
-  unsigned char* dstBuffer  = static_cast<unsigned char*>(malloc(bufferSize));
-  memcpy(dstBuffer, buffer + offsetPosition * bpp, bufferSize);
-  PixelData pixelData = Dali::PixelData::New(dstBuffer,
-                                             bufferSize,
-                                             width,
-                                             height,
-                                             textPixelFormat,
-                                             Dali::PixelData::FREE);
-  return pixelData;
+  Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D,
+                                 tilingInfo.textPixelFormat,
+                                 tilingInfo.width,
+                                 tilingInfo.height);
+  DevelTexture::UploadSubPixelData(texture, data, 0u, tilingInfo.offsetHeight, tilingInfo.width, tilingInfo.height);
+
+  textureSet.SetTexture(textureSetIndex, texture);
+  textureSet.SetSampler(textureSetIndex, sampler);
 }
 
-void TextVisual::CreateTextureSet(TilingInfo& info, Renderer& renderer, Sampler& sampler, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled, bool isOverlayStyle)
+void TextVisual::CreateTextureSet(TilingInfo& info, VisualRenderer& renderer, Sampler& sampler)
 {
-  TextureSet   textureSet      = TextureSet::New();
-  unsigned int textureSetIndex = 0u;
+  TextureSet textureSet      = TextureSet::New();
+  uint32_t   textureSetIndex = 0u;
 
   // Convert the buffer to pixel data to make it a texture.
 
-  if(info.textBuffer)
+  if(info.textPixelData)
   {
-    PixelData data = ConvertToPixelData(info.textBuffer, info.width, info.height, info.offsetPosition, info.textPixelFormat);
-    AddTexture(textureSet, data, sampler, textureSetIndex);
+    AddTilingTexture(textureSet, info, info.textPixelData, sampler, textureSetIndex);
     ++textureSetIndex;
   }
 
-  if(styleEnabled && info.styleBuffer)
+  if(mTextShaderFeatureCache.IsEnabledStyle() && info.stylePixelData)
   {
-    PixelData styleData = ConvertToPixelData(info.styleBuffer, info.width, info.height, info.offsetPosition, Pixel::RGBA8888);
-    AddTexture(textureSet, styleData, sampler, textureSetIndex);
+    AddTilingTexture(textureSet, info, info.stylePixelData, sampler, textureSetIndex);
     ++textureSetIndex;
   }
 
-  if(styleEnabled && isOverlayStyle && info.styleBuffer)
+  if(mTextShaderFeatureCache.IsEnabledOverlay() && info.overlayStylePixelData)
   {
-    PixelData overlayStyleData = ConvertToPixelData(info.styleBuffer, info.width, info.height, info.offsetPosition, Pixel::RGBA8888);
-    AddTexture(textureSet, overlayStyleData, sampler, textureSetIndex);
+    AddTilingTexture(textureSet, info, info.overlayStylePixelData, sampler, textureSetIndex);
     ++textureSetIndex;
   }
 
-  if(containsColorGlyph && !hasMultipleTextColors && info.maskBuffer)
+  if(mTextShaderFeatureCache.IsEnabledEmoji() && !mTextShaderFeatureCache.IsEnabledMultiColor() && info.maskPixelData)
   {
-    PixelData maskData = ConvertToPixelData(info.maskBuffer, info.width, info.height, info.offsetPosition, Pixel::L8);
-    AddTexture(textureSet, maskData, sampler, textureSetIndex);
+    AddTilingTexture(textureSet, info, info.maskPixelData, sampler, textureSetIndex);
+    ++textureSetIndex;
   }
 
   renderer.SetTextures(textureSet);
 
   //Register transform properties
-  mImpl->mTransform.RegisterUniforms(renderer, Direction::LEFT_TO_RIGHT);
+  mImpl->mTransform.SetUniforms(renderer, Direction::LEFT_TO_RIGHT);
 
   // Enable the pre-multiplied alpha to improve the text quality
   renderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true);
   renderer.RegisterProperty(PREMULTIPLIED_ALPHA, 1.0f);
 
   // Set size and offset for the tiling.
-  renderer.RegisterProperty(SIZE, Vector2(info.width, info.height));
-  renderer.RegisterProperty(OFFSET, Vector2(info.offSet.x, info.offSet.y));
-  renderer.RegisterProperty("uHasMultipleTextColors", static_cast<float>(hasMultipleTextColors));
+  renderer.SetProperty(VisualRenderer::Property::TRANSFORM_SIZE, Vector2(info.width, info.height));
+  renderer.SetProperty(VisualRenderer::Property::TRANSFORM_OFFSET, info.transformOffset);
   renderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
+  renderer.RegisterProperty("uHasMultipleTextColors", static_cast<float>(mTextShaderFeatureCache.IsEnabledMultiColor()));
 
   mRendererList.push_back(renderer);
 }
 
 void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled, bool isOverlayStyle)
 {
-  Shader shader = GetTextShader(mFactoryCache, hasMultipleTextColors, containsColorGlyph, styleEnabled);
+  Shader shader = GetTextShader(mFactoryCache, TextVisualShaderFeature::FeatureBuilder().EnableMultiColor(hasMultipleTextColors).EnableEmoji(containsColorGlyph).EnableStyle(styleEnabled).EnableOverlay(isOverlayStyle));
   mImpl->mRenderer.SetShader(shader);
 
   // Get the maximum size.
@@ -659,11 +665,11 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple
   // No tiling required. Use the default renderer.
   if(size.height < maxTextureSize)
   {
-    TextureSet textureSet = GetTextTexture(size, hasMultipleTextColors, containsColorGlyph, styleEnabled, isOverlayStyle);
+    TextureSet textureSet = GetTextTexture(size);
 
     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);
     mImpl->mRenderer.RegisterProperty("uHasMultipleTextColors", static_cast<float>(hasMultipleTextColors));
     mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
 
@@ -691,24 +697,25 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple
     // Set information for creating textures.
     TilingInfo info(verifiedWidth, maxTextureSize, textPixelFormat);
 
-    // Get the buffer of text.
-    Dali::DevelPixelData::PixelDataBuffer textPixelData = Dali::DevelPixelData::ReleasePixelDataBuffer(data);
-    info.textBuffer                                     = textPixelData.buffer;
+    // Get the pixel data of text.
+    info.textPixelData = data;
 
-    if(styleEnabled)
+    if(mTextShaderFeatureCache.IsEnabledStyle())
     {
       // Create RGBA texture for all the text styles (without the text itself)
-      PixelData                             styleData      = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888);
-      Dali::DevelPixelData::PixelDataBuffer stylePixelData = Dali::DevelPixelData::ReleasePixelDataBuffer(styleData);
-      info.styleBuffer                                     = stylePixelData.buffer;
+      info.stylePixelData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888);
+    }
+
+    if(mTextShaderFeatureCache.IsEnabledOverlay())
+    {
+      // Create RGBA texture for all the overlay styles
+      info.overlayStylePixelData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_OVERLAY_STYLE, false, Pixel::RGBA8888);
     }
 
-    if(containsColorGlyph && !hasMultipleTextColors)
+    if(mTextShaderFeatureCache.IsEnabledEmoji() && !mTextShaderFeatureCache.IsEnabledMultiColor())
     {
       // Create a L8 texture as a mask to avoid color glyphs (e.g. emojis) to be affected by text color animation
-      PixelData                             maskData      = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8);
-      Dali::DevelPixelData::PixelDataBuffer maskPixelData = Dali::DevelPixelData::ReleasePixelDataBuffer(maskData);
-      info.maskBuffer                                     = maskPixelData.buffer;
+      info.maskPixelData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8);
     }
 
     // Get the current offset for recalculate the offset when tiling.
@@ -717,30 +724,29 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple
     Property::Value* offsetValue = retMap.Find(Dali::Toolkit::Visual::Transform::Property::OFFSET);
     if(offsetValue)
     {
-      offsetValue->Get(info.offSet);
+      offsetValue->Get(info.transformOffset);
     }
 
     // Create a textureset in the default renderer.
-    CreateTextureSet(info, mImpl->mRenderer, sampler, hasMultipleTextColors, containsColorGlyph, styleEnabled, isOverlayStyle);
+    CreateTextureSet(info, mImpl->mRenderer, sampler);
 
     verifiedHeight -= maxTextureSize;
 
     Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
 
-    int offsetPosition = verifiedWidth * maxTextureSize;
     // Create a renderer by cutting maxTextureSize.
     while(verifiedHeight > 0)
     {
-      Renderer tilingRenderer = Renderer::New(geometry, shader);
+      VisualRenderer tilingRenderer = VisualRenderer::New(geometry, shader);
       tilingRenderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, Toolkit::DepthIndex::CONTENT);
       // New offset position of buffer for tiling.
-      info.offsetPosition += offsetPosition;
+      info.offsetHeight += maxTextureSize;
       // New height for tiling.
       info.height = (verifiedHeight - maxTextureSize) > 0 ? maxTextureSize : verifiedHeight;
       // New offset for tiling.
-      info.offSet.y += maxTextureSize;
+      info.transformOffset.y += maxTextureSize;
       // Create a textureset int the new tiling renderer.
-      CreateTextureSet(info, tilingRenderer, sampler, hasMultipleTextColors, containsColorGlyph, styleEnabled, isOverlayStyle);
+      CreateTextureSet(info, tilingRenderer, sampler);
 
       verifiedHeight -= maxTextureSize;
     }
@@ -748,17 +754,43 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple
 
   mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
 
+  const Vector4& defaultColor = mController->GetTextModel()->GetDefaultColor();
+
   for(RendererContainer::iterator iter = mRendererList.begin(); iter != mRendererList.end(); ++iter)
   {
     Renderer renderer = (*iter);
     if(renderer)
     {
       actor.AddRenderer(renderer);
+
+      if(renderer != mImpl->mRenderer)
+      {
+        // Set constraint for text label's color for non-default renderers.
+        if(mAnimatableTextColorPropertyIndex != Property::INVALID_INDEX)
+        {
+          // Register unique property, or get property for default renderer.
+          Property::Index index = renderer.RegisterUniqueProperty("uTextColorAnimatable", defaultColor);
+
+          // Create constraint for the animatable text's color Property with uTextColorAnimatable in the renderer.
+          if(index != Property::INVALID_INDEX)
+          {
+            Constraint colorConstraint = Constraint::New<Vector4>(renderer, index, TextColorConstraint);
+            colorConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex));
+            colorConstraint.Apply();
+          }
+
+          // Make zero if the alpha value of text color is zero to skip rendering text
+          // VisualRenderer::Property::OPACITY uses same animatable property internally.
+          Constraint opacityConstraint = Constraint::New<float>(renderer, Dali::DevelRenderer::Property::OPACITY, OpacityConstraint);
+          opacityConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex));
+          opacityConstraint.Apply();
+        }
+      }
     }
   }
 }
 
-TextureSet TextVisual::GetTextTexture(const Vector2& size, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled, bool isOverlayStyle)
+TextureSet TextVisual::GetTextTexture(const Vector2& size)
 {
   // Filter mode needs to be set to linear to produce better quality while scaling.
   Sampler sampler = Sampler::New();
@@ -767,7 +799,7 @@ TextureSet TextVisual::GetTextTexture(const Vector2& size, bool hasMultipleTextC
   TextureSet textureSet = TextureSet::New();
 
   // Create RGBA texture if the text contains emojis or multiple text colors, otherwise L8 texture
-  Pixel::Format textPixelFormat = (containsColorGlyph || hasMultipleTextColors) ? Pixel::RGBA8888 : Pixel::L8;
+  Pixel::Format textPixelFormat = (mTextShaderFeatureCache.IsEnabledEmoji() || mTextShaderFeatureCache.IsEnabledMultiColor()) ? Pixel::RGBA8888 : Pixel::L8;
 
   // Check the text direction
   Toolkit::DevelText::TextDirection::Type textDirection = mController->GetTextDirection();
@@ -775,25 +807,27 @@ TextureSet TextVisual::GetTextTexture(const Vector2& size, bool hasMultipleTextC
   // Create a texture for the text without any styles
   PixelData data = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat);
 
-  // It may happen the image atlas can't handle a pixel data it exceeds the maximum size.
-  // In that case, create a texture. TODO: should tile the text.
-  unsigned int textureSetIndex = 0u;
+  uint32_t textureSetIndex = 0u;
   AddTexture(textureSet, data, sampler, textureSetIndex);
   ++textureSetIndex;
 
-  if(styleEnabled)
+  if(mTextShaderFeatureCache.IsEnabledStyle())
   {
     // Create RGBA texture for all the text styles that render in the background (without the text itself)
     PixelData styleData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888);
     AddTexture(textureSet, styleData, sampler, textureSetIndex);
     ++textureSetIndex;
+  }
+
+  if(mTextShaderFeatureCache.IsEnabledOverlay())
+  {
     // Create RGBA texture for overlay styles such as underline and strikethrough (without the text itself)
     PixelData overlayStyleData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_OVERLAY_STYLE, false, Pixel::RGBA8888);
     AddTexture(textureSet, overlayStyleData, sampler, textureSetIndex);
     ++textureSetIndex;
   }
 
-  if(containsColorGlyph && !hasMultipleTextColors)
+  if(mTextShaderFeatureCache.IsEnabledEmoji() && !mTextShaderFeatureCache.IsEnabledMultiColor())
   {
     // Create a L8 texture as a mask to avoid color glyphs (e.g. emojis) to be affected by text color animation
     PixelData maskData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8);
@@ -804,73 +838,13 @@ TextureSet TextVisual::GetTextTexture(const Vector2& size, bool hasMultipleTextC
   return textureSet;
 }
 
-Shader TextVisual::GetTextShader(VisualFactoryCache& factoryCache, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled)
+Shader TextVisual::GetTextShader(VisualFactoryCache& factoryCache, const TextVisualShaderFeature::FeatureBuilder& featureBuilder)
 {
-  Shader shader;
-
-  if(hasMultipleTextColors && !styleEnabled)
-  {
-    // We don't animate text color if the text contains multiple colors
-    shader = factoryCache.GetShader(VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT);
-    if(!shader)
-    {
-      shader = Shader::New(SHADER_TEXT_VISUAL_SHADER_VERT, SHADER_TEXT_VISUAL_MULTI_COLOR_TEXT_SHADER_FRAG);
-      shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
-      factoryCache.SaveShader(VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT, shader);
-    }
-  }
-  else if(hasMultipleTextColors && styleEnabled)
-  {
-    // We don't animate text color if the text contains multiple colors
-    shader = factoryCache.GetShader(VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE);
-    if(!shader)
-    {
-      shader = Shader::New(SHADER_TEXT_VISUAL_SHADER_VERT, SHADER_TEXT_VISUAL_MULTI_COLOR_TEXT_WITH_STYLE_SHADER_FRAG);
-      shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
-      factoryCache.SaveShader(VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE, shader);
-    }
-  }
-  else if(!hasMultipleTextColors && !containsColorGlyph && !styleEnabled)
-  {
-    shader = factoryCache.GetShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT);
-    if(!shader)
-    {
-      shader = Shader::New(SHADER_TEXT_VISUAL_SHADER_VERT, SHADER_TEXT_VISUAL_SINGLE_COLOR_TEXT_SHADER_FRAG);
-      shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
-      factoryCache.SaveShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT, shader);
-    }
-  }
-  else if(!hasMultipleTextColors && !containsColorGlyph && styleEnabled)
-  {
-    shader = factoryCache.GetShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE);
-    if(!shader)
-    {
-      shader = Shader::New(SHADER_TEXT_VISUAL_SHADER_VERT, SHADER_TEXT_VISUAL_SINGLE_COLOR_TEXT_WITH_STYLE_SHADER_FRAG);
-      shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
-      factoryCache.SaveShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE, shader);
-    }
-  }
-  else if(!hasMultipleTextColors && containsColorGlyph && !styleEnabled)
-  {
-    shader = factoryCache.GetShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI);
-    if(!shader)
-    {
-      shader = Shader::New(SHADER_TEXT_VISUAL_SHADER_VERT, SHADER_TEXT_VISUAL_SINGLE_COLOR_TEXT_WITH_EMOJI_SHADER_FRAG);
-      shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
-      factoryCache.SaveShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI, shader);
-    }
-  }
-  else // if( !hasMultipleTextColors && containsColorGlyph && styleEnabled )
-  {
-    shader = factoryCache.GetShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI);
-    if(!shader)
-    {
-      shader = Shader::New(SHADER_TEXT_VISUAL_SHADER_VERT, SHADER_TEXT_VISUAL_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI_SHADER_FRAG);
-      shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
-      factoryCache.SaveShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI, shader);
-    }
-  }
+  // Cache feature builder informations.
+  mTextShaderFeatureCache = featureBuilder;
 
+  Shader shader = mTextVisualShaderFactory.GetShader(factoryCache, mTextShaderFeatureCache);
+  shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
   return shader;
 }