Fix to allow Actor::COLOR property to change text color
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / rendering / atlas / text-atlas-renderer.cpp
index 5af46ef..6fe86a4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 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.
 #include <dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h>
 
 // EXTERNAL INCLUDES
-#include <dali/integration-api/debug.h>
-#include <dali/public-api/common/stage.h>
+#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/rendering/renderer.h>
 #include <dali/public-api/images/frame-buffer-image.h>
-#include <dali/public-api/render-tasks/render-task.h>
-#include <dali/public-api/render-tasks/render-task-list.h>
-#include <dali/devel-api/rendering/renderer.h>
-#include <dali/devel-api/rendering/geometry.h>
 #include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/integration-api/debug.h>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/public-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/internal/text/glyph-run.h>
 #include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h>
 #include <dali-toolkit/internal/text/text-view.h>
 
 using namespace Dali;
@@ -41,17 +39,61 @@ using namespace Dali::Toolkit::Text;
 namespace
 {
 #if defined(DEBUG_ENABLED)
-  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_RENDERING");
 #endif
 
+#define MAKE_SHADER(A)#A
+
+const char* VERTEX_SHADER = MAKE_SHADER(
+attribute mediump vec2    aPosition;
+attribute mediump vec2    aTexCoord;
+attribute mediump vec4    aColor;
+uniform   mediump vec2    uOffset;
+uniform   mediump mat4    uMvpMatrix;
+varying   mediump vec2    vTexCoord;
+varying   mediump vec4    vColor;
+
+void main()
+{
+  mediump vec4 position = vec4( aPosition.xy + uOffset, 0.0, 1.0 );
+  gl_Position = uMvpMatrix * position;
+  vTexCoord = aTexCoord;
+  vColor = aColor;
+}
+);
+
+const char* FRAGMENT_SHADER_L8 = MAKE_SHADER(
+uniform lowp    vec4      uColor;
+uniform         sampler2D sTexture;
+varying mediump vec2      vTexCoord;
+varying mediump vec4      vColor;
+
+void main()
+{
+  mediump vec4 color = texture2D( sTexture, vTexCoord );
+  gl_FragColor = vec4( vColor.rgb * uColor.rgb, vColor.a * uColor.a * color.r );
+}
+);
+
+const char* FRAGMENT_SHADER_RGBA = MAKE_SHADER(
+uniform lowp    vec4      uColor;
+uniform         sampler2D sTexture;
+varying mediump vec2      vTexCoord;
+
+void main()
+{
+  gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;
+}
+);
+
 const float ZERO( 0.0f );
 const float HALF( 0.5f );
 const float ONE( 1.0f );
-const float TWO( 2.0f );
 const uint32_t DEFAULT_ATLAS_WIDTH = 512u;
 const uint32_t DEFAULT_ATLAS_HEIGHT = 512u;
 }
-struct AtlasRenderer::Impl : public ConnectionTracker
+
+struct AtlasRenderer::Impl
 {
   enum Style
   {
@@ -62,12 +104,10 @@ struct AtlasRenderer::Impl : public ConnectionTracker
   struct MeshRecord
   {
     MeshRecord()
-    : mColor( Color::BLACK ),
-      mAtlasId( 0 )
+    : mAtlasId( 0u )
     {
     }
 
-    Vector4 mColor;
     uint32_t mAtlasId;
     AtlasManager::Mesh2D mMesh;
     FrameBufferImage mBuffer;
@@ -85,7 +125,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
       mRight( 0.0f ),
       mUnderlinePosition( 0.0f ),
       mUnderlineThickness( 0.0f ),
-      mMeshRecordIndex( 0 )
+      mMeshRecordIndex( 0u )
     {
     }
 
@@ -145,15 +185,12 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
     mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
     mQuadVertexFormat[ "aTexCoord" ] = Property::VECTOR2;
-    mQuadIndexFormat[ "indices" ] = Property::INTEGER;
+    mQuadVertexFormat[ "aColor" ] = Property::VECTOR4;
   }
 
   bool IsGlyphUnderlined( GlyphIndex index,
                           const Vector<GlyphRun>& underlineRuns )
   {
-    // TODO: At the moment it works because we always traverse the glyphs starting from the beginning
-    //       and there is only one glyph run! If there are more they should be ordered.
-
     for( Vector<GlyphRun>::ConstIterator it = underlineRuns.Begin(),
            endIt = underlineRuns.End();
            it != endIt;
@@ -173,7 +210,11 @@ struct AtlasRenderer::Impl : public ConnectionTracker
   void AddGlyphs( Text::ViewInterface& view,
                   const Vector<Vector2>& positions,
                   const Vector<GlyphInfo>& glyphs,
-                  int depth )
+                  const Vector4& defaultColor,
+                  const Vector4* const colorsBuffer,
+                  const ColorIndex* const colorIndicesBuffer,
+                  int depth,
+                  float minLineOffset )
   {
     AtlasManager::AtlasSlot slot;
     std::vector< MeshRecord > meshContainer;
@@ -181,15 +222,16 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     TextCacheEntry textCacheEntry;
     mDepth = depth;
 
-    const Vector2& actorSize( view.GetControlSize() );
-    const Vector2 halfActorSize( actorSize * 0.5f );
-    const Vector4& textColor( view.GetTextColor() );
+    const Vector2& textSize( view.GetLayoutSize() );
+    const Vector2 halfTextSize( textSize * 0.5f );
     const Vector2& shadowOffset( view.GetShadowOffset() );
     const Vector4& shadowColor( view.GetShadowColor() );
     const bool underlineEnabled( view.IsUnderlineEnabled() );
     const Vector4& underlineColor( view.GetUnderlineColor() );
     const float underlineHeight( view.GetUnderlineHeight() );
 
+    const bool useDefaultColor = ( NULL == colorsBuffer );
+
     // Get the underline runs.
     const Length numberOfUnderlineRuns = view.GetNumberOfUnderlineRuns();
     Vector<GlyphRun> underlineRuns;
@@ -218,19 +260,19 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     Vector< TextCacheEntry > newTextCache;
     const GlyphInfo* const glyphsBuffer = glyphs.Begin();
     const Vector2* const positionsBuffer = positions.Begin();
+    const Vector2 lineOffsetPosition( minLineOffset, 0.f );
 
     for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
     {
       const GlyphInfo& glyph = *( glyphsBuffer + i );
-
       const bool underlineGlyph = underlineEnabled || IsGlyphUnderlined( i, underlineRuns );
       thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || underlineGlyph;
 
       // No operation for white space
-      if ( glyph.width && glyph.height )
+      if( glyph.width && glyph.height )
       {
         // Are we still using the same fontId as previous
-        if ( underlineGlyph && ( glyph.fontId != lastUnderlinedFontId ) )
+        if( underlineGlyph && ( glyph.fontId != lastUnderlinedFontId ) )
         {
           // We need to fetch fresh font underline metrics
           FontMetrics fontMetrics;
@@ -238,7 +280,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
           currentUnderlinePosition = ceil( fabsf( fontMetrics.underlinePosition ) );
           const float descender = ceil( fabsf( fontMetrics.descender ) );
 
-          if ( underlineHeight == ZERO )
+          if( fabsf( underlineHeight ) < Math::MACHINE_EPSILON_1000 )
           {
             currentUnderlineThickness = fontMetrics.underlineThickness;
 
@@ -254,11 +296,12 @@ struct AtlasRenderer::Impl : public ConnectionTracker
           }
 
           // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font
-          if ( currentUnderlinePosition > descender )
+          if( currentUnderlinePosition > descender )
           {
             currentUnderlinePosition = descender;
           }
-          if ( ZERO == currentUnderlinePosition )
+
+          if( fabsf( currentUnderlinePosition ) < Math::MACHINE_EPSILON_1000 )
           {
             // Move offset down by one ( EFL behavior )
             currentUnderlinePosition = ONE;
@@ -267,47 +310,75 @@ struct AtlasRenderer::Impl : public ConnectionTracker
           lastUnderlinedFontId = glyph.fontId;
         } // underline
 
-        if ( !mGlyphManager.Cached( glyph.fontId, glyph.index, slot ) )
+        if( !mGlyphManager.IsCached( glyph.fontId, glyph.index, slot ) )
         {
           // Select correct size for new atlas if needed....?
-          if ( lastFontId != glyph.fontId )
+          if( lastFontId != glyph.fontId )
           {
-            for ( uint32_t j = 0; j < mBlockSizes.size(); ++j )
+            uint32_t index = 0u;
+            for( std::vector<MaxBlockSize>::const_iterator it = mBlockSizes.begin(),
+                   endIt = mBlockSizes.end();
+                 it != endIt;
+                 ++it, ++index )
             {
-              if ( mBlockSizes[ j ].mFontId == glyph.fontId )
+              const MaxBlockSize& blockSize = *it;
+              if( blockSize.mFontId == glyph.fontId )
               {
-                currentBlockSize = j;
+                currentBlockSize = index;
                 mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH,
                                                DEFAULT_ATLAS_HEIGHT,
-                                               mBlockSizes[ j ].mNeededBlockWidth,
-                                               mBlockSizes[ j ].mNeededBlockHeight );
+                                               blockSize.mNeededBlockWidth,
+                                               blockSize.mNeededBlockHeight );
               }
             }
           }
 
           // Create a new image for the glyph
-          BufferImage bitmap = mFontClient.CreateBitmap( glyph.fontId, glyph.index );
-          if ( bitmap )
+          PixelData bitmap;
+
+          // Whether the current glyph is a color one.
+          const bool isColorGlyph = mFontClient.IsColorGlyph( glyph.fontId, glyph.index );
+
+          // Retrieve the emoji's bitmap.
+          TextAbstraction::FontClient::GlyphBufferData glyphBufferData;
+          glyphBufferData.width = isColorGlyph ? glyph.width : 0;   // Desired width and height.
+          glyphBufferData.height = isColorGlyph ? glyph.height : 0;
+
+          mFontClient.CreateBitmap( glyph.fontId,
+                                    glyph.index,
+                                    glyphBufferData );
+
+          // Create the pixel data.
+          bitmap = PixelData::New( glyphBufferData.buffer,
+                                   glyph.width * glyph.height * GetBytesPerPixel( glyphBufferData.format ),
+                                   glyph.width,
+                                   glyph.height,
+                                   glyphBufferData.format,
+                                   PixelData::DELETE_ARRAY );
+
+          if( bitmap )
           {
+            MaxBlockSize& blockSize = mBlockSizes[currentBlockSize];
+
             // Ensure that the next image will fit into the current block size
             bool setSize = false;
-            if ( bitmap.GetWidth() > mBlockSizes[ currentBlockSize ].mNeededBlockWidth )
+            if( bitmap.GetWidth() > blockSize.mNeededBlockWidth )
             {
               setSize = true;
-              mBlockSizes[ currentBlockSize ].mNeededBlockWidth = bitmap.GetWidth();
+              blockSize.mNeededBlockWidth = bitmap.GetWidth();
             }
-            if ( bitmap.GetHeight() > mBlockSizes[ currentBlockSize ].mNeededBlockHeight )
+            if( bitmap.GetHeight() > blockSize.mNeededBlockHeight )
             {
               setSize = true;
-              mBlockSizes[ currentBlockSize ].mNeededBlockHeight = bitmap.GetHeight();
+              blockSize.mNeededBlockHeight = bitmap.GetHeight();
             }
 
-            if ( setSize )
+            if( setSize )
             {
               mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH,
                                              DEFAULT_ATLAS_HEIGHT,
-                                             mBlockSizes[ currentBlockSize ].mNeededBlockWidth,
-                                             mBlockSizes[ currentBlockSize ].mNeededBlockHeight );
+                                             blockSize.mNeededBlockWidth,
+                                             blockSize.mNeededBlockHeight );
             }
 
             // Locate a new slot for our glyph
@@ -321,7 +392,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
         }
 
         // Move the origin (0,0) of the mesh to the center of the actor
-        Vector2 position = *( positionsBuffer + i ) - halfActorSize;
+        const Vector2 position = *( positionsBuffer + i ) - halfTextSize - lineOffsetPosition;
 
         // Generate mesh data for this quad, plugging in our supplied position
         AtlasManager::Mesh2D newMesh;
@@ -331,21 +402,26 @@ struct AtlasRenderer::Impl : public ConnectionTracker
         textCacheEntry.mIndex = glyph.index;
         newTextCache.PushBack( textCacheEntry );
 
-        // Adjust the vertices if the fixed-size font should be down-scaled
-        if( glyph.scaleFactor > 0 )
+        AtlasManager::Vertex2D* verticesBuffer = newMesh.mVertices.Begin();
+
+        // Get the color of the character.
+        const ColorIndex colorIndex = useDefaultColor ? 0u : *( colorIndicesBuffer + i );
+        const Vector4& color = ( useDefaultColor || ( 0u == colorIndex ) ) ? defaultColor : *( colorsBuffer + colorIndex - 1u );
+
+        for( unsigned int index = 0u, size = newMesh.mVertices.Count();
+             index < size;
+             ++index )
         {
-          for( unsigned int i=0; i<newMesh.mVertices.Count(); ++i )
-          {
-            newMesh.mVertices[i].mPosition.x = position.x + ( ( newMesh.mVertices[i].mPosition.x - position.x ) * glyph.scaleFactor );
-            newMesh.mVertices[i].mPosition.y = position.y + ( ( newMesh.mVertices[i].mPosition.y - position.y ) * glyph.scaleFactor );
-          }
+          AtlasManager::Vertex2D& vertex = *( verticesBuffer + index );
+
+          // Set the color of the vertex.
+          vertex.mColor = color;
         }
 
         // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
         StitchTextMesh( meshContainer,
                         newMesh,
                         extents,
-                        textColor,
                         position.y + glyph.yBearing,
                         underlineGlyph,
                         currentUnderlinePosition,
@@ -362,32 +438,64 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     if( thereAreUnderlinedGlyphs )
     {
       // Check to see if any of the text needs an underline
-      GenerateUnderlines( meshContainer, extents, underlineColor, textColor );
+      GenerateUnderlines( meshContainer, extents, underlineColor );
     }
 
     // For each MeshData object, create a mesh actor and add to the renderable actor
-    if ( meshContainer.size() )
+    if( !meshContainer.empty() )
     {
-      for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt )
+      if( !mActor )
       {
-        Actor actor = CreateMeshActor( *mIt, actorSize );
+        // Create a container actor to act as a common parent for text and shadow, to avoid color inheritence issues.
+        mActor = Actor::New();
+        mActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+        mActor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+        mActor.SetSize( textSize );
+        mActor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
+      }
+
+      for( std::vector< MeshRecord >::iterator it = meshContainer.begin(),
+              endIt = meshContainer.end();
+            it != endIt; ++it )
+      {
+        MeshRecord& meshRecord = *it;
+
+        Actor actor = CreateMeshActor( meshRecord, textSize, STYLE_NORMAL );
+
+        // Whether the actor has renderers.
+        const bool hasRenderer = actor.GetRendererCount() > 0u;
 
         // Create an effect if necessary
-        if ( style == STYLE_DROP_SHADOW )
+        if( hasRenderer &&
+            ( style == STYLE_DROP_SHADOW ) )
         {
-          Actor shadowActor = GenerateShadow( *mIt, actorSize, shadowOffset, shadowColor );
-          shadowActor.Add( actor );
-          actor = shadowActor;
+          // Change the color of the vertices.
+          for( Vector<AtlasManager::Vertex2D>::Iterator vIt =  meshRecord.mMesh.mVertices.Begin(),
+                 vEndIt = meshRecord.mMesh.mVertices.End();
+               vIt != vEndIt;
+               ++vIt )
+          {
+            AtlasManager::Vertex2D& vertex = *vIt;
+
+            vertex.mColor = shadowColor;
+          }
+
+          Actor shadowActor = CreateMeshActor( meshRecord, textSize, STYLE_DROP_SHADOW );
+#if defined(DEBUG_ENABLED)
+          shadowActor.SetName( "Text Shadow renderable actor" );
+#endif
+          // Offset shadow in x and y
+          shadowActor.RegisterProperty("uOffset", shadowOffset );
+          Dali::Renderer renderer( shadowActor.GetRendererAt( 0 ) );
+          int depthIndex = renderer.GetProperty<int>(Dali::Renderer::Property::DEPTH_INDEX);
+          renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, depthIndex - 1 );
+          mActor.Add( shadowActor );
         }
 
-        if( mActor )
+        if( hasRenderer )
         {
           mActor.Add( actor );
         }
-        else
-        {
-          mActor = actor;
-        }
       }
     }
 #if defined(DEBUG_ENABLED)
@@ -399,7 +507,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%s\n", metrics.mVerboseGlyphCounts.c_str() );
 
-    for ( uint32_t i = 0; i < metrics.mAtlasMetrics.mAtlasCount; ++i )
+    for( uint32_t i = 0; i < metrics.mAtlasMetrics.mAtlasCount; ++i )
     {
       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "   Atlas [%i] %sPixels: %s Size: %ix%i, BlockSize: %ix%i, BlocksUsed: %i/%i\n",
                                                  i + 1, i > 8 ? "" : " ",
@@ -416,42 +524,68 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
   void RemoveText()
   {
-    for ( Vector< TextCacheEntry >::Iterator oldTextIter = mTextCache.Begin(); oldTextIter != mTextCache.End(); ++oldTextIter )
+    for( Vector< TextCacheEntry >::Iterator oldTextIter = mTextCache.Begin(); oldTextIter != mTextCache.End(); ++oldTextIter )
     {
       mGlyphManager.AdjustReferenceCount( oldTextIter->mFontId, oldTextIter->mIndex, -1/*decrement*/ );
     }
     mTextCache.Resize( 0 );
   }
 
-  Actor CreateMeshActor( const MeshRecord& meshRecord, const Vector2& actorSize )
+  Actor CreateMeshActor( const MeshRecord& meshRecord, const Vector2& actorSize, Style style )
   {
-    PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat, meshRecord.mMesh.mVertices.Size() );
-    PropertyBuffer quadIndices = PropertyBuffer::New( mQuadIndexFormat, meshRecord.mMesh.mIndices.Size() );
-    quadVertices.SetData( const_cast< AtlasManager::Vertex2D* >( &meshRecord.mMesh.mVertices[ 0 ] ) );
-    quadIndices.SetData( const_cast< unsigned int* >( &meshRecord.mMesh.mIndices[ 0 ] ) );
+    PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat );
+    quadVertices.SetData( const_cast< AtlasManager::Vertex2D* >( &meshRecord.mMesh.mVertices[ 0 ] ), meshRecord.mMesh.mVertices.Size() );
 
     Geometry quadGeometry = Geometry::New();
     quadGeometry.AddVertexBuffer( quadVertices );
-    quadGeometry.SetIndexBuffer( quadIndices );
+    quadGeometry.SetIndexBuffer( &meshRecord.mMesh.mIndices[0],  meshRecord.mMesh.mIndices.Size() );
+
+    TextureSet textureSet( mGlyphManager.GetTextures( meshRecord.mAtlasId ) );
+
+    // Choose the shader to use.
+    const bool isColorShader = ( STYLE_DROP_SHADOW != style ) && ( Pixel::BGRA8888 == mGlyphManager.GetPixelFormat( meshRecord.mAtlasId ) );
+    Shader shader;
+    if( isColorShader )
+    {
+      // The glyph is an emoji and is not a shadow.
+      if( !mShaderRgba )
+      {
+        mShaderRgba = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RGBA );
+      }
+      shader = mShaderRgba;
+    }
+    else
+    {
+      // The glyph is text or a shadow.
+      if( !mShaderL8 )
+      {
+        mShaderL8 = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_L8 );
+      }
+      shader = mShaderL8;
+    }
+
+    Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, shader );
+    renderer.SetTextures( textureSet );
+    renderer.SetProperty( Dali::Renderer::Property::BLEND_MODE, BlendMode::ON );
+    renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT + mDepth );
 
-    Material material = mGlyphManager.GetMaterial( meshRecord.mAtlasId );
-    Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, material );
-    renderer.SetDepthIndex( CONTENT_DEPTH_INDEX + mDepth );
     Actor actor = Actor::New();
 #if defined(DEBUG_ENABLED)
     actor.SetName( "Text renderable actor" );
 #endif
     actor.AddRenderer( renderer );
-    actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned
+    // Keep all of the origins aligned
+    actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+    actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
     actor.SetSize( actorSize );
-    actor.SetColor( meshRecord.mColor );
+    actor.RegisterProperty("uOffset", Vector2::ZERO );
+    actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
     return actor;
   }
 
   void StitchTextMesh( std::vector< MeshRecord >& meshContainer,
                        AtlasManager::Mesh2D& newMesh,
                        Vector< Extent >& extents,
-                       const Vector4& color,
                        float baseLine,
                        bool underlineGlyph,
                        float underlinePosition,
@@ -470,10 +604,10 @@ struct AtlasRenderer::Impl : public ConnectionTracker
             mIt != mEndIt;
             ++mIt, ++index )
       {
-        if ( slot.mAtlasId == mIt->mAtlasId && color == mIt->mColor )
+        if( slot.mAtlasId == mIt->mAtlasId )
         {
-          // Stitch the mesh to the existing mesh and adjust any extents
-          mGlyphManager.StitchMesh( mIt->mMesh, newMesh );
+          // Append the mesh to the existing mesh and adjust any extents
+          Toolkit::Internal::AtlasMeshFactory::AppendMesh( mIt->mMesh, newMesh );
 
           if( underlineGlyph )
           {
@@ -495,7 +629,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker
       MeshRecord meshRecord;
       meshRecord.mAtlasId = slot.mAtlasId;
       meshRecord.mMesh = newMesh;
-      meshRecord.mColor = color;
       meshContainer.push_back( meshRecord );
 
       if( underlineGlyph )
@@ -565,25 +698,36 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
   void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
   {
-    MaxBlockSize maxBlockSize;
-    for ( uint32_t i = 0; i < glyphs.Size(); ++i )
+    for( Vector<GlyphInfo>::ConstIterator glyphIt = glyphs.Begin(),
+           glyphEndIt = glyphs.End();
+         glyphIt != glyphEndIt;
+         ++glyphIt )
     {
-      FontId fontId = glyphs[ i ].fontId;
+      const FontId fontId = (*glyphIt).fontId;
       bool foundFont = false;
-      for ( uint32_t j = 0; j < mBlockSizes.size(); ++j )
+
+      for( std::vector< MaxBlockSize >::const_iterator blockIt = mBlockSizes.begin(),
+             blockEndIt = mBlockSizes.end();
+           blockIt != blockEndIt;
+           ++blockIt )
       {
-        if ( mBlockSizes[ j ].mFontId == fontId )
+        if( (*blockIt).mFontId == fontId )
         {
           foundFont = true;
+          break;
         }
       }
+
       if ( !foundFont )
       {
         FontMetrics fontMetrics;
         mFontClient.GetFontMetrics( fontId, fontMetrics );
+
+        MaxBlockSize maxBlockSize;
         maxBlockSize.mNeededBlockWidth = static_cast< uint32_t >( fontMetrics.height );
-        maxBlockSize.mNeededBlockHeight = static_cast< uint32_t >( fontMetrics.height );
+        maxBlockSize.mNeededBlockHeight = maxBlockSize.mNeededBlockWidth;
         maxBlockSize.mFontId = fontId;
+
         mBlockSizes.push_back( maxBlockSize );
       }
     }
@@ -591,8 +735,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
   void GenerateUnderlines( std::vector< MeshRecord >& meshRecords,
                            Vector< Extent >& extents,
-                           const Vector4& underlineColor,
-                           const Vector4& textColor )
+                           const Vector4& underlineColor )
   {
     AtlasManager::Mesh2D newMesh;
     unsigned short faceIndex = 0;
@@ -617,22 +760,26 @@ struct AtlasRenderer::Impl : public ConnectionTracker
       vert.mPosition.y = baseLine;
       vert.mTexCoords.x = ZERO;
       vert.mTexCoords.y = ZERO;
+      vert.mColor = underlineColor;
       newMesh.mVertices.PushBack( vert );
 
       vert.mPosition.x = brx;
       vert.mPosition.y = baseLine;
       vert.mTexCoords.x = u;
+      vert.mColor = underlineColor;
       newMesh.mVertices.PushBack( vert );
 
       vert.mPosition.x = tlx;
       vert.mPosition.y = baseLine + thickness;
       vert.mTexCoords.x = ZERO;
       vert.mTexCoords.y = v;
+      vert.mColor = underlineColor;
       newMesh.mVertices.PushBack( vert );
 
       vert.mPosition.x = brx;
       vert.mPosition.y = baseLine + thickness;
       vert.mTexCoords.x = u;
+      vert.mColor = underlineColor;
       newMesh.mVertices.PushBack( vert );
 
       // Six indices in counter clockwise winding
@@ -644,162 +791,19 @@ struct AtlasRenderer::Impl : public ConnectionTracker
       newMesh.mIndices.PushBack( faceIndex + 1u );
       faceIndex += 4;
 
-      if ( underlineColor == textColor )
-      {
-        mGlyphManager.StitchMesh( meshRecords[ index ].mMesh, newMesh );
-      }
-      else
-      {
-        MeshRecord record;
-        record.mMesh = newMesh;
-        record.mAtlasId = meshRecords[ index ].mAtlasId;
-        record.mColor = underlineColor;
-        meshRecords.push_back( record );
-      }
-    }
-  }
-
-  Actor GenerateShadow( MeshRecord& meshRecord,
-                        const Vector2& actorSize,
-                        const Vector2& shadowOffset,
-                        const Vector4& shadowColor )
-  {
-    // Scan vertex buffer to determine width and height of effect buffer needed
-    const Vector< AtlasManager::Vertex2D >& verts = meshRecord.mMesh.mVertices;
-    float tlx = verts[ 0 ].mPosition.x;
-    float tly = verts[ 0 ].mPosition.y;
-    float brx = ZERO;
-    float bry = ZERO;
-
-    for ( uint32_t i = 0; i < verts.Size(); ++i )
-    {
-      if ( verts[ i ].mPosition.x < tlx )
-      {
-        tlx = verts[ i ].mPosition.x;
-      }
-      if ( verts[ i ].mPosition.y < tly )
-      {
-        tly = verts[ i ].mPosition.y;
-      }
-      if ( verts[ i ].mPosition.x > brx )
-      {
-        brx = verts[ i ].mPosition.x;
-      }
-      if ( verts[ i ].mPosition.y > bry )
-      {
-        bry = verts[ i ].mPosition.y;
-      }
-    }
-
-    float width = brx - tlx;
-    float height = bry - tly;
-    float divWidth = TWO / width;
-    float divHeight = TWO / height;
-
-    // Create a buffer to render to
-    meshRecord.mBuffer = FrameBufferImage::New( width, height );
-
-    // We will render a quad into this buffer
-    unsigned int indices[ 6 ] = { 1, 0, 2, 2, 3, 1 };
-    PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat, 4u );
-    PropertyBuffer quadIndices = PropertyBuffer::New( mQuadIndexFormat, sizeof(indices)/sizeof(indices[0]) );
-
-    AtlasManager::Vertex2D vertices[ 4 ] = {
-    { Vector2( tlx + shadowOffset.x, tly + shadowOffset.y ), Vector2( ZERO, ZERO ) },
-    { Vector2( brx + shadowOffset.x, tly + shadowOffset.y ), Vector2( ONE, ZERO ) },
-    { Vector2( tlx + shadowOffset.x, bry + shadowOffset.y ), Vector2( ZERO, ONE ) },
-    { Vector2( brx + shadowOffset.x, bry + shadowOffset.y ), Vector2( ONE, ONE ) } };
-
-    quadVertices.SetData( vertices );
-    quadIndices.SetData( indices );
-
-    Geometry quadGeometry = Geometry::New();
-    quadGeometry.AddVertexBuffer( quadVertices );
-    quadGeometry.SetIndexBuffer( quadIndices );
-
-    Sampler sampler = Sampler::New( meshRecord.mBuffer, "sTexture" );
-    Material material = Material::New( mGlyphManager.GetEffectBufferShader() );
-    material.AddSampler( sampler );
-
-    Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, material );
-
-    // Set depth index to -1.0 to make sure shadow is rendered first in 3D layers
-    renderer.SetDepthIndex( -1.0f );
-    Actor actor = Actor::New();
-    actor.AddRenderer( renderer );
-    actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned
-    actor.SetSize( actorSize );
-
-    // Create a sub actor to render the source with normalized vertex positions
-    Vector< AtlasManager::Vertex2D > normVertexList;
-    for ( uint32_t i = 0; i < verts.Size(); ++i )
-    {
-      AtlasManager::Vertex2D vertex = verts[ i ];
-      vertex.mPosition.x = ( ( vertex.mPosition.x - tlx ) * divWidth ) - ONE;
-      vertex.mPosition.y = ( ( vertex.mPosition.y - tly ) * divHeight ) - ONE;
-      normVertexList.PushBack( vertex );
-    }
-
-    PropertyBuffer normVertices = PropertyBuffer::New( mQuadVertexFormat, normVertexList.Size() );
-    PropertyBuffer normIndices = PropertyBuffer::New( mQuadIndexFormat, meshRecord.mMesh.mIndices.Size() );
-    normVertices.SetData( const_cast< AtlasManager::Vertex2D* >( &normVertexList[ 0 ] ) );
-    normIndices.SetData( const_cast< unsigned int* >( &meshRecord.mMesh.mIndices[ 0 ] ) );
-
-    Geometry normGeometry = Geometry::New();
-    normGeometry.AddVertexBuffer( normVertices );
-    normGeometry.SetIndexBuffer( normIndices );
-
-    Material normMaterial = Material::New( mGlyphManager.GetGlyphShadowShader() );
-    Sampler normSampler =  mGlyphManager.GetSampler( meshRecord.mAtlasId );
-    normMaterial.AddSampler( normSampler );
-    Dali::Renderer normRenderer = Dali::Renderer::New( normGeometry, normMaterial );
-    Actor subActor = Actor::New();
-    subActor.AddRenderer( normRenderer );
-    subActor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned
-    subActor.SetSize( actorSize );
-    subActor.SetColor( shadowColor );
-
-    // Create a render task to render the effect
-    RenderTask task = Stage::GetCurrent().GetRenderTaskList().CreateTask();
-    task.SetTargetFrameBuffer( meshRecord.mBuffer );
-    task.SetSourceActor( subActor );
-    task.SetClearEnabled( true );
-    task.SetClearColor( Vector4::ZERO );
-    task.SetExclusive( true );
-    task.SetRefreshRate( RenderTask::REFRESH_ONCE );
-    task.FinishedSignal().Connect( this, &AtlasRenderer::Impl::RenderComplete );
-    actor.Add( subActor );
-
-    return actor;
-  }
-
-  void RenderComplete( RenderTask& renderTask )
-  {
-    // Disconnect and remove this single shot render task
-    renderTask.FinishedSignal().Disconnect( this, &AtlasRenderer::Impl::RenderComplete );
-    Stage::GetCurrent().GetRenderTaskList().RemoveTask( renderTask );
-
-    // Get the actor used for render to buffer and remove it from the parent
-    Actor renderActor = renderTask.GetSourceActor();
-    if ( renderActor )
-    {
-      Actor parent = renderActor.GetParent();
-      if ( parent )
-      {
-        parent.Remove( renderActor );
-      }
+      Toolkit::Internal::AtlasMeshFactory::AppendMesh( meshRecords[ index ].mMesh, newMesh );
     }
   }
 
   Actor mActor;                                       ///< The actor parent which renders the text
   AtlasGlyphManager mGlyphManager;                    ///< Glyph Manager to handle upload and caching
-  TextAbstraction::FontClient mFontClient;            ///> The font client used to supply glyph information
-  std::vector< MaxBlockSize > mBlockSizes;            ///> Maximum size needed to contain a glyph in a block within a new atlas
-  std::vector< uint32_t > mFace;                      ///> Face indices for a quad
-  Vector< TextCacheEntry > mTextCache;
-  Property::Map mQuadVertexFormat;
-  Property::Map mQuadIndexFormat;
-  int mDepth;
+  TextAbstraction::FontClient mFontClient;            ///< The font client used to supply glyph information
+  Shader mShaderL8;                                   ///< The shader for glyphs and emoji's shadows.
+  Shader mShaderRgba;                                 ///< The shader for emojis.
+  std::vector< MaxBlockSize > mBlockSizes;            ///< Maximum size needed to contain a glyph in a block within a new atlas
+  Vector< TextCacheEntry > mTextCache;                ///< Caches data from previous render
+  Property::Map mQuadVertexFormat;                    ///< Describes the vertex format for text
+  int mDepth;                                         ///< DepthIndex passed by control when connect to stage
 };
 
 Text::RendererPtr AtlasRenderer::New()
@@ -809,8 +813,12 @@ Text::RendererPtr AtlasRenderer::New()
   return Text::RendererPtr( new AtlasRenderer() );
 }
 
-Actor AtlasRenderer::Render( Text::ViewInterface& view, int depth )
+Actor AtlasRenderer::Render( Text::ViewInterface& view,
+                             float& alignmentOffset,
+                             int depth )
 {
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Text::AtlasRenderer::Render()\n" );
+
   UnparentAndReset( mImpl->mActor );
 
   Length numberOfGlyphs = view.GetNumberOfGlyphs();
@@ -825,15 +833,32 @@ Actor AtlasRenderer::Render( Text::ViewInterface& view, int depth )
 
     numberOfGlyphs = view.GetGlyphs( glyphs.Begin(),
                                      positions.Begin(),
+                                     alignmentOffset,
                                      0u,
                                      numberOfGlyphs );
+
     glyphs.Resize( numberOfGlyphs );
     positions.Resize( numberOfGlyphs );
 
+    const Vector4* const colorsBuffer = view.GetColors();
+    const ColorIndex* const colorIndicesBuffer = view.GetColorIndices();
+    const Vector4& defaultColor = view.GetTextColor();
+
     mImpl->AddGlyphs( view,
                       positions,
                       glyphs,
-                      depth );
+                      defaultColor,
+                      colorsBuffer,
+                      colorIndicesBuffer,
+                      depth,
+                      alignmentOffset );
+
+    /* In the case where AddGlyphs does not create a renderable Actor for example when glyphs are all whitespace create a new Actor. */
+    /* This renderable actor is used to position the text, other "decorations" can rely on there always being an Actor regardless of it is whitespace or regular text. */
+    if ( !mImpl->mActor )
+    {
+      mImpl->mActor = Actor::New();
+    }
   }
 
   return mImpl->mActor;