TextSelection Popup to be aware of requirement to Paste and whitespace selectable
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / rendering / atlas / text-atlas-renderer.cpp
index 5af8695..4cb19ed 100644 (file)
 #include <dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h>
 
 // EXTERNAL INCLUDES
-#include <dali/dali.h>
 #include <dali/integration-api/debug.h>
+#include <dali/devel-api/rendering/renderer.h>
+#include <dali/devel-api/rendering/geometry.h>
 #include <dali/devel-api/text-abstraction/font-client.h>
 
-
 // INTERNAL INCLUDES
-#include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
-#include <dali-toolkit/internal/text/line-run.h>
+#include <dali-toolkit/public-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/shaders/text-basic-shader.h>
-#include <dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h>
-//#include <dali-toolkit/internal/text/rendering/shaders/text-basic-shadow-shader.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h>
+#include <dali-toolkit/internal/text/text-view.h>
 
 using namespace Dali;
 using namespace Dali::Toolkit;
@@ -42,73 +41,15 @@ namespace
   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
 #endif
 
-  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;
-
-  #define MAKE_SHADER(A)#A
-
-  const char* VERTEX_SHADER = MAKE_SHADER(
-  attribute mediump vec2    aPosition;
-  attribute mediump vec2    aTexCoord;
-  uniform   mediump mat4    uMvpMatrix;
-  uniform   mediump vec3    uSize;
-  varying   mediump vec2    vTexCoord;
-
-  void main()
-  {
-    mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
-    position.xyz *= uSize;
-    gl_Position = uMvpMatrix * position;
-    vTexCoord = aTexCoord;
-  }
-  );
-
-  const char* FRAGMENT_SHADER = MAKE_SHADER(
-  uniform         sampler2D sTexture;
-  varying mediump vec2      vTexCoord;
-
-  void main()
-  {
-    //gl_FragColor = vec4( 1.0 );
-    gl_FragColor = texture2D( sTexture, vTexCoord );
-  }
-  );
-
-  const char* VERTEX_SHADER_SHADOW = MAKE_SHADER(
-  attribute mediump vec2    aPosition;
-  attribute mediump vec2    aTexCoord;
-  uniform   mediump vec3    uSize;
-  varying   mediump vec2    vTexCoord;
-
-  void main()
-  {
-    mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
-    position.xyz *= uSize;
-    gl_Position = position;
-    vTexCoord = aTexCoord;
-  }
-  );
-
-  const char* FRAGMENT_SHADER_SHADOW = MAKE_SHADER(
-  uniform         sampler2D sTexture;
-  uniform lowp    vec4      uColor;
-  varying mediump vec2      vTexCoord;
-
-  void main()
-  {
-    mediump vec4 color = texture2D( sTexture, vTexCoord );
-    gl_FragColor = vec4(uColor.rgb, uColor.a*color.r);
-  }
-  );
+const float ZERO( 0.0f );
+const float HALF( 0.5f );
+const float ONE( 1.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
   {
     STYLE_NORMAL,
@@ -117,15 +58,34 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
   struct MeshRecord
   {
+    MeshRecord()
+    : mColor( Color::BLACK ),
+      mAtlasId( 0 )
+    {
+    }
+
     Vector4 mColor;
     uint32_t mAtlasId;
     AtlasManager::Mesh2D mMesh;
     FrameBufferImage mBuffer;
-    bool mIsUnderline;
   };
 
+  /**
+   * brief Struct used to generate the underline mesh.
+   * There is one Extent per line of text.
+   */
   struct Extent
   {
+    Extent()
+    : mBaseLine( 0.0f ),
+      mLeft( 0.0f ),
+      mRight( 0.0f ),
+      mUnderlinePosition( 0.0f ),
+      mUnderlineThickness( 0.0f ),
+      mMeshRecordIndex( 0 )
+    {
+    }
+
     float mBaseLine;
     float mLeft;
     float mRight;
@@ -134,49 +94,111 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     uint32_t mMeshRecordIndex;
   };
 
-  struct AtlasRecord
+  struct MaxBlockSize
   {
-    uint32_t mImageId;
+    MaxBlockSize()
+    : mFontId( 0 ),
+      mNeededBlockWidth( 0 ),
+      mNeededBlockHeight( 0 )
+    {
+    }
+
+    FontId mFontId;
+    uint32_t mNeededBlockWidth;
+    uint32_t mNeededBlockHeight;
+  };
+
+  struct CheckEntry
+  {
+    CheckEntry()
+    : mFontId( 0 ),
+      mIndex( 0 )
+    {
+    }
+
+    FontId mFontId;
     Text::GlyphIndex mIndex;
   };
 
-  struct MaxBlockSize
+  struct TextCacheEntry
   {
+    TextCacheEntry()
+    : mFontId( 0 ),
+      mIndex( 0 ),
+      mImageId( 0 )
+    {
+    }
+
     FontId mFontId;
-    uint32_t mNeededBlockWidth;
-    uint32_t mNeededBlockHeight;
+    Text::GlyphIndex mIndex;
+    uint32_t mImageId;
   };
 
   Impl()
+  : mDepth( 0 )
   {
     mGlyphManager = AtlasGlyphManager::Get();
     mFontClient = TextAbstraction::FontClient::Get();
 
     mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
     mQuadVertexFormat[ "aTexCoord" ] = Property::VECTOR2;
-    mQuadIndexFormat[ "indices" ] = Property::UNSIGNED_INTEGER;
+    mQuadIndexFormat[ "indices" ] = Property::INTEGER;
+  }
+
+  bool IsGlyphUnderlined( GlyphIndex index,
+                          const Vector<GlyphRun>& underlineRuns )
+  {
+    for( Vector<GlyphRun>::ConstIterator it = underlineRuns.Begin(),
+           endIt = underlineRuns.End();
+           it != endIt;
+         ++it )
+    {
+      const GlyphRun& run = *it;
 
-    mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
-    mShadowShader = Shader::New( VERTEX_SHADER_SHADOW, FRAGMENT_SHADER_SHADOW );
+      if( ( run.glyphIndex <= index ) && ( index < run.glyphIndex + run.numberOfGlyphs ) )
+      {
+        return true;
+      }
+    }
+
+    return false;
   }
 
-  void AddGlyphs( const std::vector<Vector2>& positions,
+  void AddGlyphs( Text::ViewInterface& view,
+                  const Vector<Vector2>& positions,
                   const Vector<GlyphInfo>& glyphs,
-                  const Vector4& textColor,
-                  const Vector2& shadowOffset,
-                  const Vector4& shadowColor,
-                  bool underlineEnabled,
-                  const Vector4& underlineColor,
-                  float underlineHeight )
+                  int depth )
   {
     AtlasManager::AtlasSlot slot;
     std::vector< MeshRecord > meshContainer;
     Vector< Extent > extents;
+    TextCacheEntry textCacheEntry;
+    mDepth = depth;
+
+    const Vector2& actorSize( view.GetControlSize() );
+    const Vector2 halfActorSize( actorSize * 0.5f );
+    const Vector4& textColor( view.GetTextColor() );
+    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() );
+
+    // Get the underline runs.
+    const Length numberOfUnderlineRuns = view.GetNumberOfUnderlineRuns();
+    Vector<GlyphRun> underlineRuns;
+    underlineRuns.Resize( numberOfUnderlineRuns );
+    view.GetUnderlineRuns( underlineRuns.Begin(),
+                           0u,
+                           numberOfUnderlineRuns );
+
+    bool thereAreUnderlinedGlyphs = false;
 
     float currentUnderlinePosition = ZERO;
     float currentUnderlineThickness = underlineHeight;
     uint32_t currentBlockSize = 0;
     FontId lastFontId = 0;
+    FontId lastUnderlinedFontId = 0;
     Style style = STYLE_NORMAL;
 
     if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
@@ -184,31 +206,33 @@ struct AtlasRenderer::Impl : public ConnectionTracker
       style = STYLE_DROP_SHADOW;
     }
 
-    if ( mImageIds.Size() )
-    {
-      // Unreference any currently used glyphs
-      RemoveText();
-    }
-
     CalculateBlocksSize( glyphs );
 
+    // Avoid emptying mTextCache (& removing references) until after incremented references for the new text
+    Vector< TextCacheEntry > newTextCache;
+    const GlyphInfo* const glyphsBuffer = glyphs.Begin();
+    const Vector2* const positionsBuffer = positions.Begin();
+
     for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
     {
-      const GlyphInfo& glyph = glyphs[ 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 )
       {
         // Are we still using the same fontId as previous
-        if ( glyph.fontId != lastFontId )
+        if ( underlineGlyph && ( glyph.fontId != lastUnderlinedFontId ) )
         {
           // We need to fetch fresh font underline metrics
           FontMetrics fontMetrics;
           mFontClient.GetFontMetrics( glyph.fontId, fontMetrics );
           currentUnderlinePosition = ceil( fabsf( fontMetrics.underlinePosition ) );
-          float descender = ceil( fabsf( fontMetrics.descender ) );
+          const float descender = ceil( fabsf( fontMetrics.descender ) );
 
-          if ( underlineHeight == ZERO )
+          if( fabsf( underlineHeight ) < Math::MACHINE_EPSILON_1000 )
           {
             currentUnderlineThickness = fontMetrics.underlineThickness;
 
@@ -228,26 +252,17 @@ struct AtlasRenderer::Impl : public ConnectionTracker
           {
             currentUnderlinePosition = descender;
           }
-          if ( ZERO == currentUnderlinePosition )
+          if( fabsf( currentUnderlinePosition ) < Math::MACHINE_EPSILON_1000 )
           {
             // Move offset down by one ( EFL behavior )
             currentUnderlinePosition = ONE;
           }
-        }
 
-        const Vector2& position = positions[ i ];
-        AtlasManager::Mesh2D newMesh;
-        mGlyphManager.Cached( glyph.fontId, glyph.index, slot );
+          lastUnderlinedFontId = glyph.fontId;
+        } // underline
 
-        if ( slot.mImageId )
+        if ( !mGlyphManager.IsCached( glyph.fontId, glyph.index, slot ) )
         {
-          // This glyph already exists so generate mesh data plugging in our supplied position
-          mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh );
-          mImageIds.PushBack( slot.mImageId );
-        }
-        else
-        {
-
           // Select correct size for new atlas if needed....?
           if ( lastFontId != glyph.fontId )
           {
@@ -291,29 +306,54 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
             // Locate a new slot for our glyph
             mGlyphManager.Add( glyph, bitmap, slot );
+          }
+        }
+        else
+        {
+          // We have 2+ copies of the same glyph
+          mGlyphManager.AdjustReferenceCount( glyph.fontId, glyph.index, 1/*increment*/ );
+        }
 
-            // Generate mesh data for this quad, plugging in our supplied position
-            if ( slot.mImageId )
-            {
-              mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh );
-              mImageIds.PushBack( slot.mImageId );
-            }
+        // Move the origin (0,0) of the mesh to the center of the actor
+        Vector2 position = *( positionsBuffer + i ) - halfActorSize;
+
+        // Generate mesh data for this quad, plugging in our supplied position
+        AtlasManager::Mesh2D newMesh;
+        mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh );
+        textCacheEntry.mFontId = glyph.fontId;
+        textCacheEntry.mImageId = slot.mImageId;
+        textCacheEntry.mIndex = glyph.index;
+        newTextCache.PushBack( textCacheEntry );
+
+        // Adjust the vertices if the fixed-size font should be down-scaled
+        if( glyph.scaleFactor > 0 )
+        {
+          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 );
           }
         }
+
         // 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,
                         currentUnderlineThickness,
                         slot );
-       lastFontId = glyph.fontId;
+        lastFontId = glyph.fontId;
       }
-    }
+    } // glyphs
+
+    // Now remove references for the old text
+    RemoveText();
+    mTextCache.Swap( newTextCache );
 
-    if ( underlineEnabled )
+    if( thereAreUnderlinedGlyphs )
     {
       // Check to see if any of the text needs an underline
       GenerateUnderlines( meshContainer, extents, underlineColor, textColor );
@@ -324,15 +364,41 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     {
       for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt )
       {
-        Actor actor = CreateMeshActor( *mIt );
+        Actor actor = CreateMeshActor( *mIt, actorSize );
 
         // Create an effect if necessary
         if ( style == STYLE_DROP_SHADOW )
         {
-          actor.Add( GenerateShadow( *mIt, shadowOffset, shadowColor ) );
+          // Create a container actor to act as a common parent for text and shadow, to avoid color inheritence issues.
+          Actor containerActor = Actor::New();
+          containerActor.SetParentOrigin( ParentOrigin::CENTER );
+          containerActor.SetSize( actorSize );
+
+          Actor shadowActor = Actor::New();
+#if defined(DEBUG_ENABLED)
+          shadowActor.SetName( "Text Shadow renderable actor" );
+#endif
+          // Offset shadow in x and y
+          shadowActor.RegisterProperty("uOffset", shadowOffset );
+          if ( actor.GetRendererCount() )
+          {
+            Dali::Renderer renderer( actor.GetRendererAt( 0 ) );
+            Geometry geometry = renderer.GetGeometry();
+            Material material = renderer.GetMaterial();
+
+            Dali::Renderer shadowRenderer = Dali::Renderer::New( geometry, material );
+            shadowRenderer.SetDepthIndex( renderer.GetDepthIndex() - 1 );
+            shadowActor.AddRenderer( shadowRenderer );
+            shadowActor.SetParentOrigin( ParentOrigin::CENTER );
+            shadowActor.SetSize( actorSize );
+            shadowActor.SetColor( shadowColor );
+            containerActor.Add( shadowActor );
+            containerActor.Add( actor );
+            actor = containerActor;
+          }
         }
 
-        if ( mActor )
+        if( mActor )
         {
           mActor.Add( actor );
         }
@@ -341,7 +407,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker
           mActor = actor;
         }
       }
-      mActor.OffStageSignal().Connect( this, &AtlasRenderer::Impl::OffStageDisconnect );
     }
 #if defined(DEBUG_ENABLED)
     Toolkit::AtlasGlyphManager::Metrics metrics = mGlyphManager.GetMetrics();
@@ -349,9 +414,12 @@ struct AtlasRenderer::Impl : public ConnectionTracker
                                                 metrics.mGlyphCount,
                                                 metrics.mAtlasMetrics.mAtlasCount,
                                                 metrics.mAtlasMetrics.mTextureMemoryUsed / 1024 );
+
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%s\n", metrics.mVerboseGlyphCounts.c_str() );
+
     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",
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "   Atlas [%i] %sPixels: %s Size: %ix%i, BlockSize: %ix%i, BlocksUsed: %i/%i\n",
                                                  i + 1, i > 8 ? "" : " ",
                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mPixelFormat == Pixel::L8 ? "L8  " : "BGRA",
                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mWidth,
@@ -364,7 +432,16 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 #endif
   }
 
-  Actor CreateMeshActor( const MeshRecord& meshRecord )
+  void RemoveText()
+  {
+    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 )
   {
     PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat, meshRecord.mMesh.mVertices.Size() );
     PropertyBuffer quadIndices = PropertyBuffer::New( mQuadIndexFormat, meshRecord.mMesh.mIndices.Size() );
@@ -377,20 +454,16 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
     Material material = mGlyphManager.GetMaterial( meshRecord.mAtlasId );
     Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, material );
-    renderer.SetDepthIndex( 0 );
+    renderer.SetDepthIndex( CONTENT_DEPTH_INDEX + mDepth );
     Actor actor = Actor::New();
+#if defined(DEBUG_ENABLED)
+    actor.SetName( "Text renderable actor" );
+#endif
     actor.AddRenderer( renderer );
-    actor.SetSize( 1.0f, 1.0f );
+    actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned
+    actor.SetSize( actorSize );
     actor.SetColor( meshRecord.mColor );
-
-    if ( meshRecord.mIsUnderline )
-    {
-      actor.SetColorMode( USE_OWN_COLOR );
-    }
-    else
-    {
-      actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
-    }
+    actor.RegisterProperty("uOffset", Vector2::ZERO );
     return actor;
   }
 
@@ -399,6 +472,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
                        Vector< Extent >& extents,
                        const Vector4& color,
                        float baseLine,
+                       bool underlineGlyph,
                        float underlinePosition,
                        float underlineThickness,
                        AtlasManager::AtlasSlot& slot )
@@ -410,20 +484,28 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
       // Check to see if there's a mesh data object that references the same atlas ?
       uint32_t index = 0;
-      for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt, ++index )
+      for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(),
+              mEndIt = meshContainer.end();
+            mIt != mEndIt;
+            ++mIt, ++index )
       {
         if ( slot.mAtlasId == mIt->mAtlasId && color == mIt->mColor )
         {
-          // Stitch the mesh to the existing mesh and adjust any extents
-          mGlyphManager.StitchMesh( mIt->mMesh, newMesh );
-          AdjustExtents( extents,
-                         meshContainer,
-                         index,
-                         left,
-                         right,
-                         baseLine,
-                         underlinePosition,
-                         underlineThickness );
+          // Append the mesh to the existing mesh and adjust any extents
+          Toolkit::Internal::AtlasMeshFactory::AppendMesh( mIt->mMesh, newMesh );
+
+          if( underlineGlyph )
+          {
+            AdjustExtents( extents,
+                           meshContainer,
+                           index,
+                           left,
+                           right,
+                           baseLine,
+                           underlinePosition,
+                           underlineThickness );
+          }
+
           return;
         }
       }
@@ -433,19 +515,20 @@ struct AtlasRenderer::Impl : public ConnectionTracker
       meshRecord.mAtlasId = slot.mAtlasId;
       meshRecord.mMesh = newMesh;
       meshRecord.mColor = color;
-      meshRecord.mIsUnderline = false;
       meshContainer.push_back( meshRecord );
 
-      // Adjust extents for this new meshrecord
-      AdjustExtents( extents,
-                     meshContainer,
-                     meshContainer.size() - 1u,
-                     left,
-                     right,
-                     baseLine,
-                     underlinePosition,
-                     underlineThickness );
-
+      if( underlineGlyph )
+      {
+        // Adjust extents for this new meshrecord
+        AdjustExtents( extents,
+                       meshContainer,
+                       meshContainer.size() - 1u,
+                       left,
+                       right,
+                       baseLine,
+                       underlinePosition,
+                       underlineThickness );
+      }
     }
   }
 
@@ -459,7 +542,10 @@ struct AtlasRenderer::Impl : public ConnectionTracker
                       float underlineThickness )
   {
     bool foundExtent = false;
-    for ( Vector< Extent >::Iterator eIt = extents.Begin(); eIt != extents.End(); ++eIt )
+    for ( Vector< Extent >::Iterator eIt = extents.Begin(),
+            eEndIt = extents.End();
+          eIt != eEndIt;
+          ++eIt )
     {
       if ( Equals( baseLine, eIt->mBaseLine ) )
       {
@@ -496,21 +582,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     }
   }
 
-  // Unreference any glyphs that were used with this actor
-  void OffStageDisconnect( Dali::Actor actor )
-  {
-    RemoveText();
-  }
-
-  void RemoveText()
-  {
-    for ( uint32_t i = 0; i < mImageIds.Size(); ++i )
-    {
-      mGlyphManager.Remove( mImageIds[ i ] );
-    }
-    mImageIds.Resize( 0 );
-  }
-
   void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
   {
     MaxBlockSize maxBlockSize;
@@ -537,14 +608,17 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     }
   }
 
-  void GenerateUnderlines( std::vector< MeshRecord>& meshRecords,
+  void GenerateUnderlines( std::vector< MeshRecord >& meshRecords,
                            Vector< Extent >& extents,
                            const Vector4& underlineColor,
                            const Vector4& textColor )
   {
     AtlasManager::Mesh2D newMesh;
     unsigned short faceIndex = 0;
-    for ( Vector< Extent >::ConstIterator eIt = extents.Begin(); eIt != extents.End(); ++eIt )
+    for ( Vector< Extent >::ConstIterator eIt = extents.Begin(),
+            eEndIt = extents.End();
+          eIt != eEndIt;
+          ++eIt )
     {
       AtlasManager::Vertex2D vert;
       uint32_t index = eIt->mMeshRecordIndex;
@@ -591,7 +665,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
       if ( underlineColor == textColor )
       {
-        mGlyphManager.StitchMesh( meshRecords[ index ].mMesh, newMesh );
+        Toolkit::Internal::AtlasMeshFactory::AppendMesh( meshRecords[ index ].mMesh, newMesh );
       }
       else
       {
@@ -599,150 +673,19 @@ struct AtlasRenderer::Impl : public ConnectionTracker
         record.mMesh = newMesh;
         record.mAtlasId = meshRecords[ index ].mAtlasId;
         record.mColor = underlineColor;
-        record.mIsUnderline = true;
         meshRecords.push_back( record );
       }
     }
   }
 
-  Actor GenerateShadow( MeshRecord& meshRecord,
-                        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( mShader );
-    material.AddSampler( sampler );
-
-    Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, material );
-    renderer.SetDepthIndex( 1.0f );
-    Actor actor = Actor::New();
-    actor.AddRenderer( renderer );
-    actor.SetSize( 1.0f, 1.0f );
-
-    // 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( mShadowShader );
-    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.SetSize( 1.0f, 1.0f );
-    subActor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
-    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 );
-      }
-    }
-  }
-
   Actor mActor;                                       ///< The actor parent which renders the text
   AtlasGlyphManager mGlyphManager;                    ///< Glyph Manager to handle upload and caching
-  Vector< uint32_t > mImageIds;                       ///< A list of imageIDs used by the renderer
   TextAbstraction::FontClient mFontClient;            ///> The font client used to supply glyph information
-  Shader mShader;                                     ///> Shader used to render drop shadow buffer textures
-  Shader mShadowShader;                               ///> Shader used to render drop shadow into buffer
   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
-  Property::Map mQuadVertexFormat;
-  Property::Map mQuadIndexFormat;
+  Vector< TextCacheEntry > mTextCache;                ///> Caches data from previous render
+  Property::Map mQuadVertexFormat;                    ///> Describes the vertex format for text
+  Property::Map mQuadIndexFormat;                     ///> Describes the index format for text
+  int mDepth;                                         ///> DepthIndex passed by control when connect to stage
 };
 
 Text::RendererPtr AtlasRenderer::New()
@@ -752,7 +695,7 @@ Text::RendererPtr AtlasRenderer::New()
   return Text::RendererPtr( new AtlasRenderer() );
 }
 
-Actor AtlasRenderer::Render( Text::ViewInterface& view )
+Actor AtlasRenderer::Render( Text::ViewInterface& view, int depth )
 {
   UnparentAndReset( mImpl->mActor );
 
@@ -763,24 +706,27 @@ Actor AtlasRenderer::Render( Text::ViewInterface& view )
     Vector<GlyphInfo> glyphs;
     glyphs.Resize( numberOfGlyphs );
 
-    std::vector<Vector2> positions;
-    positions.resize( numberOfGlyphs );
+    Vector<Vector2> positions;
+    positions.Resize( numberOfGlyphs );
 
     numberOfGlyphs = view.GetGlyphs( glyphs.Begin(),
-                                     &positions[0],
+                                     positions.Begin(),
                                      0u,
                                      numberOfGlyphs );
     glyphs.Resize( numberOfGlyphs );
-    positions.resize( numberOfGlyphs );
+    positions.Resize( numberOfGlyphs );
 
-    mImpl->AddGlyphs( positions,
+    mImpl->AddGlyphs( view,
+                      positions,
                       glyphs,
-                      view.GetTextColor(),
-                      view.GetShadowOffset(),
-                      view.GetShadowColor(),
-                      view.IsUnderlineEnabled(),
-                      view.GetUnderlineColor(),
-                      view.GetUnderlineHeight() );
+                      depth );
+
+    /* 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;
@@ -794,5 +740,6 @@ AtlasRenderer::AtlasRenderer()
 
 AtlasRenderer::~AtlasRenderer()
 {
+  mImpl->RemoveText();
   delete mImpl;
 }