Combine textvisual shader by TextShaderFactory
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / text / text-visual.cpp
index 19ecb5c..2106745 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
@@ -23,7 +23,7 @@
 #include <dali/devel-api/images/pixel-data-devel.h>
 #include <dali/devel-api/rendering/renderer-devel.h>
 #include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
-#include <dali/public-api/animation/constraints.h>
+#include <dali/integration-api/debug.h>
 #include <string.h>
 
 // INTERNAL HEADER
@@ -50,6 +50,8 @@ namespace Internal
 {
 namespace
 {
+const int CUSTOM_PROPERTY_COUNT(5); // anim,premul,size,offset,multicol
+
 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
 
 /**
@@ -146,9 +148,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;
@@ -224,6 +226,9 @@ void TextVisual::DoCreatePropertyMap(Property::Map& map) const
 
   GetBackgroundProperties(mController, value, Text::EffectStyle::DEFAULT);
   map.Insert(Toolkit::DevelTextVisual::Property::BACKGROUND, value);
+
+  GetStrikethroughProperties(mController, value, Text::EffectStyle::DEFAULT);
+  map.Insert(Toolkit::DevelTextVisual::Property::STRIKETHROUGH, value);
 }
 
 void TextVisual::DoCreateInstancePropertyMap(Property::Map& map) const
@@ -235,13 +240,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()
@@ -251,9 +270,10 @@ 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);
 }
 
 void TextVisual::DoSetProperties(const Property::Map& propertyMap)
@@ -288,33 +308,42 @@ 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();
-  Dali::Property::Index shaderTextColorIndex = mImpl->mRenderer.RegisterProperty("uTextColorAnimatable", defaultColor);
+  const Vector4& defaultColor = mController->GetTextModel()->GetDefaultColor();
+  if(mTextColorAnimatableIndex == Property::INVALID_INDEX)
+  {
+    mTextColorAnimatableIndex = mImpl->mRenderer.RegisterUniqueProperty("uTextColorAnimatable", defaultColor);
+  }
+  else
+  {
+    mImpl->mRenderer.SetProperty(mTextColorAnimatableIndex, defaultColor);
+  }
 
   if(mAnimatableTextColorPropertyIndex != Property::INVALID_INDEX)
   {
     // Create constraint for the animatable text's color Property with uTextColorAnimatable in the renderer.
-    if(shaderTextColorIndex != Property::INVALID_INDEX)
+    if(mTextColorAnimatableIndex != Property::INVALID_INDEX)
     {
-      Constraint colorConstraint = Constraint::New<Vector4>(mImpl->mRenderer, shaderTextColorIndex, TextColorConstraint);
-      colorConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex));
-      colorConstraint.Apply();
-
-      // Make zero if the alpha value of text color is zero to skip rendering text
-      Constraint opacityConstraint = Constraint::New<float>(mImpl->mRenderer, Dali::DevelRenderer::Property::OPACITY, OpacityConstraint);
-      opacityConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex));
-      opacityConstraint.Apply();
+      if(!mColorConstraint)
+      {
+        mColorConstraint = Constraint::New<Vector4>(mImpl->mRenderer, mTextColorAnimatableIndex, TextColorConstraint);
+        mColorConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex));
+      }
+      mColorConstraint.Apply();
     }
+
+    // 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));
+    }
+    mOpacityConstraint.Apply();
   }
 
   // Renderer needs textures and to be added to control
   mRendererUpdateNeeded = true;
 
-  mRendererList.push_back(mImpl->mRenderer);
-
   UpdateRenderer();
 }
 
@@ -335,6 +364,15 @@ void TextVisual::RemoveRenderer(Actor& actor)
 
 void TextVisual::DoSetOffScene(Actor& actor)
 {
+  if(mColorConstraint)
+  {
+    mColorConstraint.Remove();
+  }
+  if(mOpacityConstraint)
+  {
+    mOpacityConstraint.Remove();
+  }
+
   RemoveRenderer(actor);
 
   // Resets the control handle.
@@ -438,6 +476,11 @@ void TextVisual::DoSetProperty(Dali::Property::Index index, const Dali::Property
       SetBackgroundProperties(mController, propertyValue, Text::EffectStyle::DEFAULT);
       break;
     }
+    case Toolkit::DevelTextVisual::Property::STRIKETHROUGH:
+    {
+      SetStrikethroughProperties(mController, propertyValue, Text::EffectStyle::DEFAULT);
+      break;
+    }
   }
 }
 
@@ -523,10 +566,12 @@ void TextVisual::UpdateRenderer()
       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);
+      const bool styleEnabled   = (shadowEnabled || underlineEnabled || outlineEnabled || backgroundEnabled || markupProcessorEnabled || strikethroughEnabled);
+      const bool isOverlayStyle = underlineEnabled || strikethroughEnabled;
 
-      AddRenderer(control, relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled);
+      AddRenderer(control, relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled, isOverlayStyle);
 
       // Text rendered and ready to display
       ResourceReady(Toolkit::Visual::ResourceStatus::READY);
@@ -561,12 +606,13 @@ PixelData TextVisual::ConvertToPixelData(unsigned char* buffer, int width, int h
   return pixelData;
 }
 
-void TextVisual::CreateTextureSet(TilingInfo& info, Renderer& renderer, Sampler& sampler, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled)
+void TextVisual::CreateTextureSet(TilingInfo& info, VisualRenderer& renderer, Sampler& sampler)
 {
   TextureSet   textureSet      = TextureSet::New();
   unsigned int textureSetIndex = 0u;
 
   // Convert the buffer to pixel data to make it a texture.
+
   if(info.textBuffer)
   {
     PixelData data = ConvertToPixelData(info.textBuffer, info.width, info.height, info.offsetPosition, info.textPixelFormat);
@@ -574,14 +620,21 @@ void TextVisual::CreateTextureSet(TilingInfo& info, Renderer& renderer, Sampler&
     ++textureSetIndex;
   }
 
-  if(styleEnabled && info.styleBuffer)
+  if(mTextShaderFeatureCache.IsEnabledStyle() && info.styleBuffer)
   {
     PixelData styleData = ConvertToPixelData(info.styleBuffer, info.width, info.height, info.offsetPosition, Pixel::RGBA8888);
     AddTexture(textureSet, styleData, sampler, textureSetIndex);
     ++textureSetIndex;
   }
 
-  if(containsColorGlyph && !hasMultipleTextColors && info.maskBuffer)
+  if(mTextShaderFeatureCache.IsEnabledOverlay() && info.overlayStyleBuffer)
+  {
+    PixelData overlayStyleData = ConvertToPixelData(info.overlayStyleBuffer, info.width, info.height, info.offsetPosition, Pixel::RGBA8888);
+    AddTexture(textureSet, overlayStyleData, sampler, textureSetIndex);
+    ++textureSetIndex;
+  }
+
+  if(mTextShaderFeatureCache.IsEnabledEmoji() && !mTextShaderFeatureCache.IsEnabledMultiColor() && info.maskBuffer)
   {
     PixelData maskData = ConvertToPixelData(info.maskBuffer, info.width, info.height, info.offsetPosition, Pixel::L8);
     AddTexture(textureSet, maskData, sampler, textureSetIndex);
@@ -590,24 +643,24 @@ void TextVisual::CreateTextureSet(TilingInfo& info, Renderer& renderer, Sampler&
   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, Vector2(info.offSet.x, info.offSet.y));
   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)
+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.
@@ -616,11 +669,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);
+    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);
 
@@ -652,7 +705,7 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple
     Dali::DevelPixelData::PixelDataBuffer textPixelData = Dali::DevelPixelData::ReleasePixelDataBuffer(data);
     info.textBuffer                                     = textPixelData.buffer;
 
-    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);
@@ -660,7 +713,15 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple
       info.styleBuffer                                     = stylePixelData.buffer;
     }
 
-    if(containsColorGlyph && !hasMultipleTextColors)
+    if(mTextShaderFeatureCache.IsEnabledOverlay())
+    {
+      // Create RGBA texture for all the overlay styles
+      PixelData                             overlayStyleData      = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_OVERLAY_STYLE, false, Pixel::RGBA8888);
+      Dali::DevelPixelData::PixelDataBuffer overlayStylePixelData = Dali::DevelPixelData::ReleasePixelDataBuffer(overlayStyleData);
+      info.overlayStyleBuffer                                     = overlayStylePixelData.buffer;
+    }
+
+    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);
@@ -678,7 +739,7 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple
     }
 
     // Create a textureset in the default renderer.
-    CreateTextureSet(info, mImpl->mRenderer, sampler, hasMultipleTextColors, containsColorGlyph, styleEnabled);
+    CreateTextureSet(info, mImpl->mRenderer, sampler);
 
     verifiedHeight -= maxTextureSize;
 
@@ -688,7 +749,7 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple
     // 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;
@@ -697,7 +758,7 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple
       // New offset for tiling.
       info.offSet.y += maxTextureSize;
       // Create a textureset int the new tiling renderer.
-      CreateTextureSet(info, tilingRenderer, sampler, hasMultipleTextColors, containsColorGlyph, styleEnabled);
+      CreateTextureSet(info, tilingRenderer, sampler);
 
       verifiedHeight -= maxTextureSize;
     }
@@ -705,17 +766,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)
+TextureSet TextVisual::GetTextTexture(const Vector2& size)
 {
   // Filter mode needs to be set to linear to produce better quality while scaling.
   Sampler sampler = Sampler::New();
@@ -724,7 +811,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();
@@ -735,20 +822,26 @@ TextureSet TextVisual::GetTextTexture(const Vector2& size, bool hasMultipleTextC
   // 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;
-
   AddTexture(textureSet, data, sampler, textureSetIndex);
   ++textureSetIndex;
 
-  if(styleEnabled)
+  if(mTextShaderFeatureCache.IsEnabledStyle())
   {
-    // Create RGBA texture for all the text styles (without the text itself)
+    // 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(containsColorGlyph && !hasMultipleTextColors)
+  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(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);
@@ -759,73 +852,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;
 }