Merge "(AutomatedTests) Synchronise TestSingletonService with Adaptor" into devel...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / rendering / atlas / text-atlas-renderer.cpp
index e3b4827..789dfaf 100644 (file)
 
 // EXTERNAL INCLUDES
 #include <dali/dali.h>
+#include <dali/devel-api/object/property-buffer.h>
+#include <dali/devel-api/rendering/geometry.h>
+#include <dali/devel-api/rendering/renderer.h>
+#include <dali/devel-api/rendering/sampler.h>
+#include <dali/devel-api/rendering/shader.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
 #include <dali/integration-api/debug.h>
-//#include <dali/public-api/actors/renderer.h>
-#include <dali/public-api/text-abstraction/text-abstraction.h>
-
 // INTERNAL INCLUDES
-#include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
+#include <dali-toolkit/public-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
-#include <dali-toolkit/internal/text/rendering/shaders/text-basic-shader.h>
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_ATLAS_RENDERER");
-#endif
 
 using namespace Dali;
 using namespace Dali::Toolkit;
@@ -38,70 +37,17 @@ using namespace Dali::Toolkit::Text;
 
 namespace
 {
-  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;
+#if defined(DEBUG_ENABLED)
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
+#endif
 
-  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 float TWO( 2.0f );
+const uint32_t DEFAULT_ATLAS_WIDTH = 512u;
+const uint32_t DEFAULT_ATLAS_HEIGHT = 512u;
 }
-
 struct AtlasRenderer::Impl : public ConnectionTracker
 {
 
@@ -130,17 +76,24 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     uint32_t mMeshRecordIndex;
   };
 
-  struct AtlasRecord
+  struct MaxBlockSize
   {
-    uint32_t mImageId;
+    FontId mFontId;
+    uint32_t mNeededBlockWidth;
+    uint32_t mNeededBlockHeight;
+  };
+
+  struct CheckEntry
+  {
+    FontId mFontId;
     Text::GlyphIndex mIndex;
   };
 
-  struct MaxBlockSize
+  struct TextCacheEntry
   {
     FontId mFontId;
-    uint32_t mNeededBlockWidth;
-    uint32_t mNeededBlockHeight;
+    Text::GlyphIndex mIndex;
+    uint32_t mImageId;
   };
 
   Impl()
@@ -151,9 +104,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
     mQuadVertexFormat[ "aTexCoord" ] = Property::VECTOR2;
     mQuadIndexFormat[ "indices" ] = Property::UNSIGNED_INTEGER;
-
-    mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
-    mShadowShader = Shader::New( VERTEX_SHADER_SHADOW, FRAGMENT_SHADER_SHADOW );
   }
 
   void AddGlyphs( const std::vector<Vector2>& positions,
@@ -163,11 +113,14 @@ struct AtlasRenderer::Impl : public ConnectionTracker
                   const Vector4& shadowColor,
                   bool underlineEnabled,
                   const Vector4& underlineColor,
-                  float underlineHeight )
+                  float underlineHeight,
+                  int depth )
   {
     AtlasManager::AtlasSlot slot;
     std::vector< MeshRecord > meshContainer;
     Vector< Extent > extents;
+    TextCacheEntry textCacheEntry;
+    mDepth = depth;
 
     float currentUnderlinePosition = ZERO;
     float currentUnderlineThickness = underlineHeight;
@@ -180,17 +133,17 @@ struct AtlasRenderer::Impl : public ConnectionTracker
       style = STYLE_DROP_SHADOW;
     }
 
-    if ( mImageIds.Size() )
+    if ( mTextCache.Size() )
     {
-      // Unreference any currently used glyphs
-      RemoveText();
+      // Update the glyph cache with any changes to current text
+      RemoveText( glyphs );
     }
 
     CalculateBlocksSize( glyphs );
 
-    for ( uint32_t i = 0; i < glyphs.Size(); ++i )
+    for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
     {
-      GlyphInfo glyph = glyphs[ i ];
+      const GlyphInfo& glyph = glyphs[ i ];
 
       // No operation for white space
       if ( glyph.width && glyph.height )
@@ -231,19 +184,11 @@ struct AtlasRenderer::Impl : public ConnectionTracker
           }
         }
 
-        Vector2 position = positions[ i ];
+        const Vector2& position = positions[ i ];
         AtlasManager::Mesh2D newMesh;
-        mGlyphManager.Cached( glyph.fontId, glyph.index, slot );
 
-        if ( slot.mImageId )
-        {
-          // This glyph already exists so generate mesh data plugging in our supplied position
-          mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh );
-          mImageIds.PushBack( slot.mImageId );
-        }
-        else
+        if ( !mGlyphManager.Cached( glyph.fontId, glyph.index, slot ) )
         {
-
           // Select correct size for new atlas if needed....?
           if ( lastFontId != glyph.fontId )
           {
@@ -262,38 +207,41 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
           // Create a new image for the glyph
           BufferImage bitmap = mFontClient.CreateBitmap( glyph.fontId, glyph.index );
-
-          // Ensure that the next image will fit into the current block size
-          bool setSize = false;
-          if ( bitmap.GetWidth() > mBlockSizes[ currentBlockSize ].mNeededBlockWidth )
-          {
-            setSize = true;
-            mBlockSizes[ currentBlockSize ].mNeededBlockWidth = bitmap.GetWidth();
-          }
-          if ( bitmap.GetHeight() > mBlockSizes[ currentBlockSize ].mNeededBlockHeight )
+          if ( bitmap )
           {
-            setSize = true;
-            mBlockSizes[ currentBlockSize ].mNeededBlockHeight = bitmap.GetHeight();
-          }
-
-          if ( setSize )
-          {
-            mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH,
-                                           DEFAULT_ATLAS_HEIGHT,
-                                           mBlockSizes[ currentBlockSize ].mNeededBlockWidth,
-                                           mBlockSizes[ currentBlockSize ].mNeededBlockHeight );
-          }
+            // Ensure that the next image will fit into the current block size
+            bool setSize = false;
+            if ( bitmap.GetWidth() > mBlockSizes[ currentBlockSize ].mNeededBlockWidth )
+            {
+              setSize = true;
+              mBlockSizes[ currentBlockSize ].mNeededBlockWidth = bitmap.GetWidth();
+            }
+            if ( bitmap.GetHeight() > mBlockSizes[ currentBlockSize ].mNeededBlockHeight )
+            {
+              setSize = true;
+              mBlockSizes[ currentBlockSize ].mNeededBlockHeight = bitmap.GetHeight();
+            }
 
-          // Locate a new slot for our glyph
-          mGlyphManager.Add( glyph, bitmap, slot );
+            if ( setSize )
+            {
+              mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH,
+                                             DEFAULT_ATLAS_HEIGHT,
+                                             mBlockSizes[ currentBlockSize ].mNeededBlockWidth,
+                                             mBlockSizes[ currentBlockSize ].mNeededBlockHeight );
+            }
 
-          // Generate mesh data for this quad, plugging in our supplied position
-          if ( slot.mImageId )
-          {
-            mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh );
-            mImageIds.PushBack( slot.mImageId );
+            // Locate a new slot for our glyph
+            mGlyphManager.Add( glyph, bitmap, slot );
           }
         }
+
+        // Generate mesh data for this quad, plugging in our supplied position
+        mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh );
+        textCacheEntry.mFontId = glyph.fontId;
+        textCacheEntry.mImageId = slot.mImageId;
+        textCacheEntry.mIndex = glyph.index;
+        mTextCache.PushBack( textCacheEntry );
+
         // 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,
@@ -303,7 +251,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
                         currentUnderlinePosition,
                         currentUnderlineThickness,
                         slot );
-       lastFontId = glyph.fontId;
+        lastFontId = glyph.fontId;
       }
     }
 
@@ -326,8 +274,9 @@ struct AtlasRenderer::Impl : public ConnectionTracker
           actor.Add( GenerateShadow( *mIt, shadowOffset, shadowColor ) );
         }
 
-        if ( mActor )
+        if( mActor )
         {
+          actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned
           mActor.Add( actor );
         }
         else
@@ -335,11 +284,10 @@ struct AtlasRenderer::Impl : public ConnectionTracker
           mActor = actor;
         }
       }
-      mActor.OffStageSignal().Connect( this, &AtlasRenderer::Impl::OffStageDisconnect );
     }
 #if defined(DEBUG_ENABLED)
     Toolkit::AtlasGlyphManager::Metrics metrics = mGlyphManager.GetMetrics();
-    DALI_LOG_INFO( gLogFilter, Debug::Concise, "TextAtlasRenderer::GlyphManager::GlyphCount: %i, AtlasCount: %i, TextureMemoryUse: %iK\n",
+    DALI_LOG_INFO( gLogFilter, Debug::General, "TextAtlasRenderer::GlyphManager::GlyphCount: %i, AtlasCount: %i, TextureMemoryUse: %iK\n",
                                                 metrics.mGlyphCount,
                                                 metrics.mAtlasMetrics.mAtlasCount,
                                                 metrics.mAtlasMetrics.mTextureMemoryUsed / 1024 );
@@ -360,8 +308,8 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
   Actor CreateMeshActor( const MeshRecord& meshRecord )
   {
-    PropertyBuffer quadVertices = PropertyBuffer::New( PropertyBuffer::STATIC, mQuadVertexFormat, meshRecord.mMesh.mVertices.Size() );
-    PropertyBuffer quadIndices = PropertyBuffer::New( PropertyBuffer::STATIC, mQuadIndexFormat, meshRecord.mMesh.mIndices.Size() );
+    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 ] ) );
 
@@ -371,8 +319,11 @@ 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.SetColor( meshRecord.mColor );
@@ -490,19 +441,56 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     }
   }
 
-  // Unreference any glyphs that were used with this actor
-  void OffStageDisconnect( Dali::Actor actor )
+  void RemoveText( const Vector<GlyphInfo>& glyphs )
   {
-    RemoveText();
-  }
+    Vector< CheckEntry > checked;
+    CheckEntry checkEntry;
 
-  void RemoveText()
-  {
-    for ( uint32_t i = 0; i < mImageIds.Size(); ++i )
+    for ( Vector< TextCacheEntry >::Iterator tCit = mTextCache.Begin(); tCit != mTextCache.End(); ++tCit )
     {
-      mGlyphManager.Remove( mImageIds[ i ] );
+      uint32_t index = tCit->mIndex;
+      uint32_t fontId = tCit->mFontId;
+
+      // Check that this character has not already been checked...
+      bool wasChecked = false;
+      for ( Vector< CheckEntry >::Iterator cEit = checked.Begin(); cEit != checked.End(); ++cEit )
+      {
+        if ( fontId == cEit->mFontId && index == cEit->mIndex )
+        {
+          wasChecked = true;
+        }
+      }
+
+      if ( !wasChecked )
+      {
+
+        int32_t newCount = 0;
+        int32_t oldCount = 0;
+
+        // How many times does this character occur in the old text ?
+        for ( Vector< TextCacheEntry >::Iterator oTcit = mTextCache.Begin(); oTcit != mTextCache.End(); ++oTcit )
+        {
+          if ( fontId == oTcit->mFontId && index == oTcit->mIndex )
+          {
+            oldCount++;
+          }
+        }
+
+        // And how many times in the new ?
+        for ( Vector< GlyphInfo >::Iterator cGit = glyphs.Begin(); cGit != glyphs.End(); ++cGit )
+        {
+          if ( fontId == cGit->fontId && index == cGit->index )
+          {
+            newCount++;
+          }
+        }
+        mGlyphManager.AdjustReferenceCount( fontId, tCit->mImageId, newCount - oldCount );
+        checkEntry.mIndex = index;
+        checkEntry.mFontId = fontId;
+        checked.PushBack( checkEntry );
+      }
     }
-    mImageIds.Resize( 0 );
+    mTextCache.Resize( 0 );
   }
 
   void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
@@ -640,8 +628,8 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
     // We will render a quad into this buffer
     unsigned int indices[ 6 ] = { 1, 0, 2, 2, 3, 1 };
-    PropertyBuffer quadVertices = PropertyBuffer::New( PropertyBuffer::STATIC, mQuadVertexFormat, 4u );
-    PropertyBuffer quadIndices = PropertyBuffer::New( PropertyBuffer::STATIC, mQuadIndexFormat, sizeof(indices)/sizeof(indices[0]) );
+    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 ) },
@@ -657,11 +645,13 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     quadGeometry.SetIndexBuffer( quadIndices );
 
     Sampler sampler = Sampler::New( meshRecord.mBuffer, "sTexture" );
-    Material material = Material::New( mShader );
+    Material material = Material::New( mGlyphManager.GetEffectBufferShader() );
     material.AddSampler( sampler );
 
     Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, material );
-    renderer.SetDepthIndex( 1.0f );
+
+    // Ensure shadow is behind the text...
+    renderer.SetDepthIndex( CONTENT_DEPTH_INDEX + mDepth - 1 );
     Actor actor = Actor::New();
     actor.AddRenderer( renderer );
     actor.SetSize( 1.0f, 1.0f );
@@ -676,8 +666,8 @@ struct AtlasRenderer::Impl : public ConnectionTracker
       normVertexList.PushBack( vertex );
     }
 
-    PropertyBuffer normVertices = PropertyBuffer::New( PropertyBuffer::STATIC, mQuadVertexFormat, normVertexList.Size() );
-    PropertyBuffer normIndices = PropertyBuffer::New( PropertyBuffer::STATIC, mQuadIndexFormat, meshRecord.mMesh.mIndices.Size() );
+    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 ] ) );
 
@@ -685,7 +675,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     normGeometry.AddVertexBuffer( normVertices );
     normGeometry.SetIndexBuffer( normIndices );
 
-    Material normMaterial = Material::New( mShadowShader );
+    Material normMaterial = Material::New( mGlyphManager.GetGlyphShadowShader() );
     Sampler normSampler =  mGlyphManager.GetSampler( meshRecord.mAtlasId );
     normMaterial.AddSampler( normSampler );
     Dali::Renderer normRenderer = Dali::Renderer::New( normGeometry, normMaterial );
@@ -729,38 +719,43 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
   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
+  Vector< TextCacheEntry > mTextCache;
   Property::Map mQuadVertexFormat;
   Property::Map mQuadIndexFormat;
+  int mDepth;
 };
 
 Text::RendererPtr AtlasRenderer::New()
 {
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::AtlasRenderer::New()\n" );
+
   return Text::RendererPtr( new AtlasRenderer() );
 }
 
-Actor AtlasRenderer::Render( Text::ViewInterface& view )
+Actor AtlasRenderer::Render( Text::ViewInterface& view, int depth )
 {
-
   UnparentAndReset( mImpl->mActor );
 
-  Text::Length numberOfGlyphs = view.GetNumberOfGlyphs();
+  Length numberOfGlyphs = view.GetNumberOfGlyphs();
 
-  if( numberOfGlyphs > 0 )
+  if( numberOfGlyphs > 0u )
   {
     Vector<GlyphInfo> glyphs;
     glyphs.Resize( numberOfGlyphs );
 
-    view.GetGlyphs( &glyphs[0], 0, numberOfGlyphs );
-
     std::vector<Vector2> positions;
     positions.resize( numberOfGlyphs );
-    view.GetGlyphPositions( &positions[0], 0, numberOfGlyphs );
+
+    numberOfGlyphs = view.GetGlyphs( glyphs.Begin(),
+                                     &positions[0],
+                                     0u,
+                                     numberOfGlyphs );
+    glyphs.Resize( numberOfGlyphs );
+    positions.resize( numberOfGlyphs );
+
     mImpl->AddGlyphs( positions,
                       glyphs,
                       view.GetTextColor(),
@@ -768,8 +763,10 @@ Actor AtlasRenderer::Render( Text::ViewInterface& view )
                       view.GetShadowColor(),
                       view.IsUnderlineEnabled(),
                       view.GetUnderlineColor(),
-                      view.GetUnderlineHeight() );
+                      view.GetUnderlineHeight(),
+                      depth );
   }
+
   return mImpl->mActor;
 }
 
@@ -781,5 +778,7 @@ AtlasRenderer::AtlasRenderer()
 
 AtlasRenderer::~AtlasRenderer()
 {
+  Vector< GlyphInfo > emptyGlyphs;
+  mImpl->RemoveText( emptyGlyphs );
   delete mImpl;
 }