Corrected camel case for BgraShader
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / rendering / basic / text-basic-renderer.cpp
index 4521d94..dc6ec3e 100644 (file)
 
 // INTERNAL INCLUDES
 #include <dali/public-api/text-abstraction/font-client.h>
+#include <dali/public-api/actors/image-actor.h>
 #include <dali/public-api/actors/mesh-actor.h>
 #include <dali/public-api/images/atlas.h>
 #include <dali/public-api/geometry/mesh.h>
 #include <dali-toolkit/internal/text/rendering/shaders/text-basic-shader.h>
+#include <dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h>
+
 
 using namespace Dali;
 using namespace Dali::Toolkit;
@@ -50,9 +53,9 @@ struct TextureCoordinates
   Vector2 bottomRight;
 };
 
-struct AtlasHelperGlyph
+struct AtlasGlyph
 {
-  AtlasHelperGlyph()
+  AtlasGlyph()
   : fontId( 0 ),
     index( 0 ),
     xOffset( 0 ),
@@ -61,16 +64,18 @@ struct AtlasHelperGlyph
   {
   }
 
-  AtlasHelperGlyph( FontId id,
-                    GlyphIndex glyphIndex,
-                    std::size_t offset,
-                    std::size_t widthPixels,
-                    std::size_t heightPixels )
+  AtlasGlyph( FontId id,
+              GlyphIndex glyphIndex,
+              std::size_t offset,
+              std::size_t widthPixels,
+              std::size_t heightPixels,
+              BufferImage bitmap )
   : fontId( id ),
     index( glyphIndex ),
     xOffset( offset ),
     width( widthPixels ),
-    height( heightPixels )
+    height( heightPixels ),
+    mBitmap( bitmap )
   {
   }
 
@@ -79,140 +84,179 @@ struct AtlasHelperGlyph
   std::size_t xOffset;
   std::size_t width;
   std::size_t height;
+  BufferImage mBitmap;
   TextureCoordinates coords;
 };
 
-struct AtlasHelper
+} // unnamed namespace
+
+struct BasicRenderer::Impl
 {
-  AtlasHelper()
-  : mWidth( 0.0f ),
-    mHeight( 0.0f )
+  /**
+   * @brief Create the renderer implementation.
+   */
+  Impl()
+  : mWidthL8( 0.0f ),
+    mHeightL8( 0.0f ),
+    mWidthBGRA8888( 0.0f ),
+    mHeightBGRA8888( 0.0f )
   {
     mFontClient = TextAbstraction::FontClient::Get();
   }
 
-  void Reset()
+  /**
+   * @brief Reset the previous glyph calculations.
+   *
+   * @param[in] size The glyph space to reserve.
+   */
+  void Reset( std::size_t size )
   {
-    mWidth = 0.0f;
-    mHeight = 0.0f;
+    mWidthL8 = 0.0f;
+    mHeightL8 = 0.0f;
+    mWidthBGRA8888 = 0.0f;
+    mHeightBGRA8888 = 0.0f;
     mGlyphs.clear();
-  }
-
-  void Reserve( std::size_t size )
-  {
     mGlyphs.reserve( size );
+    mAtlasL8.Reset();
+    mAtlasBGRA8888.Reset();
   }
 
-  bool GlyphFound( FontId fontId, GlyphIndex index ) const
+  /**
+   * @brief Ccreate an Atlas, uploading the necessary glyph bitmaps
+   *
+   * @param[in] glyphs The glyphs to upload.
+   */
+  void CreateAtlases( const Vector<GlyphInfo>& glyphs )
   {
-    for( unsigned int i=0; i<mGlyphs.size(); ++i )
+    // Clear previous atlas
+    Reset( glyphs.Count() );
+
+    for( unsigned int i=0; i<glyphs.Count(); ++i )
     {
-      const AtlasHelperGlyph& glyph = mGlyphs[i];
+      float width  = glyphs[i].width;
+      float height = glyphs[i].height;
 
-      if( fontId == glyph.fontId &&
-          index  == glyph.index )
+      if( width > 0 &&
+          height > 0 ) // skip whitespace
       {
-        return true;
+        if( !GlyphFound( glyphs[i].fontId, glyphs[i].index ) )
+        {
+          AddGlyph( glyphs[i] );
+        }
       }
     }
 
-    return false;
+    mAtlasL8 = CreateAtlas( mWidthL8, mHeightL8, Pixel::L8 );
+    mAtlasBGRA8888 = CreateAtlas( mWidthBGRA8888, mHeightBGRA8888, Pixel::BGRA8888 );
   }
 
-  void AddGlyph( const GlyphInfo& glyphInfo )
+  Atlas CreateAtlas( unsigned int width, unsigned int height, Pixel::Format format )
   {
-    mGlyphs.push_back( AtlasHelperGlyph( glyphInfo.fontId, glyphInfo.index, mWidth, glyphInfo.width, glyphInfo.height ) );
+    Atlas atlas;
 
-    mWidth += glyphInfo.width + PADDING;
-    if( mHeight < glyphInfo.height + PADDING )
+    if( width > 0 && height > 0 )
     {
-      mHeight = glyphInfo.height + PADDING;
-    }
-  }
+      atlas = Atlas::New( width, height, format );
 
-  Atlas CreateAtlas()
-  {
-    Atlas atlas = Atlas::New( mWidth, mHeight, Pixel::L8 );
+      for( unsigned int i=0; i<mGlyphs.size(); ++i )
+      {
+        AtlasGlyph& glyph = mGlyphs[i];
 
-    for( unsigned int i=0; i<mGlyphs.size(); ++i )
-    {
-      AtlasHelperGlyph& glyph = mGlyphs[i];
-      BufferImage bitmap = mFontClient.CreateBitmap( glyph.fontId, glyph.index );
-      atlas.Upload( bitmap, glyph.xOffset, 0 );
-
-      TextureCoordinates& coords = glyph.coords;
-      coords.topLeft.x     = static_cast<float>(glyph.xOffset) / static_cast<float>(mWidth);
-      coords.topLeft.y     = 0.0f;
-      coords.topRight.x    = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(mWidth);
-      coords.topRight.y    = 0.0f;
-      coords.bottomLeft.x  = static_cast<float>(glyph.xOffset) / static_cast<float>(mWidth);
-      coords.bottomLeft.y  = static_cast<float>(glyph.height) / static_cast<float>(mHeight);
-      coords.bottomRight.x = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(mWidth);
-      coords.bottomRight.y = static_cast<float>(glyph.height) / static_cast<float>(mHeight);
+        const Pixel::Format glyphFormat = glyph.mBitmap.GetPixelFormat();
+
+        if( format == glyphFormat )
+        {
+          atlas.Upload( glyph.mBitmap, glyph.xOffset, 0 );
+
+          TextureCoordinates& coords = glyph.coords;
+          coords.topLeft.x     = static_cast<float>(glyph.xOffset) / static_cast<float>(width);
+          coords.topLeft.y     = 0.0f;
+          coords.topRight.x    = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(width);
+          coords.topRight.y    = 0.0f;
+          coords.bottomLeft.x  = static_cast<float>(glyph.xOffset) / static_cast<float>(width);
+          coords.bottomLeft.y  = static_cast<float>(glyph.height) / static_cast<float>(height);
+          coords.bottomRight.x = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(width);
+          coords.bottomRight.y = static_cast<float>(glyph.height) / static_cast<float>(height);
+        }
+      }
     }
 
     return atlas;
   }
 
-  void GetTextureCoordinates( FontId fontId, GlyphIndex index, TextureCoordinates& coords )
+  /**
+   * @brief Check whether we already have the glyph.
+   */
+  bool GlyphFound( FontId fontId, GlyphIndex index ) const
   {
     for( unsigned int i=0; i<mGlyphs.size(); ++i )
     {
-      const AtlasHelperGlyph& glyph = mGlyphs[i];
+      const AtlasGlyph& glyph = mGlyphs[i];
 
       if( fontId == glyph.fontId &&
           index  == glyph.index )
       {
-        coords = glyph.coords;
-        return;
+        return true;
       }
     }
+
+    return false;
   }
 
-private: // Data
+  /**
+   * @brief Add the glyph.
+   */
+  void AddGlyph( const GlyphInfo& glyphInfo )
+  {
+    BufferImage bitmap = mFontClient.CreateBitmap( glyphInfo.fontId, glyphInfo.index );
 
-  std::size_t mWidth;
-  std::size_t mHeight;
+    const Pixel::Format format = bitmap.GetPixelFormat();
 
-  std::vector<AtlasHelperGlyph> mGlyphs;
+    if( Pixel::L8 == format )
+    {
+      mGlyphs.push_back( AtlasGlyph( glyphInfo.fontId, glyphInfo.index, mWidthL8, glyphInfo.width, glyphInfo.height, bitmap ) );
 
-  TextAbstraction::FontClient mFontClient;
-};
+      // Increase the Atlas width/height
+      mWidthL8 += glyphInfo.width + PADDING;
+      if( mHeightL8 < glyphInfo.height + PADDING )
+      {
+        mHeightL8 = glyphInfo.height + PADDING;
+      }
+    }
+    else if ( Pixel::BGRA8888 == format )
+    {
+       mGlyphs.push_back( AtlasGlyph( glyphInfo.fontId, glyphInfo.index, mWidthBGRA8888, glyphInfo.width, glyphInfo.height, bitmap ) );
 
-} // unnamed namespace
+      // A separate Atlas is used for color Emojis
+      mWidthBGRA8888 += glyphInfo.width + PADDING;
+      if( mHeightBGRA8888 < glyphInfo.height + PADDING )
+      {
+        mHeightBGRA8888 = glyphInfo.height + PADDING;
+      }
+    }
+  }
 
-struct BasicRenderer::Impl
-{
   /**
-   * @brief Ccreate an Atlas, uploading the necessary glyph bitmaps
-   *
-   * @param[in] glyphs The glyphs to upload.
+   * @brief Get the texture coordinates for a glyph.
    */
-  Atlas CreateAtlas( const Vector<GlyphInfo>& glyphs )
+  bool GetTextureCoordinates( Pixel::Format format, FontId fontId, GlyphIndex index, TextureCoordinates& coords )
   {
-    AtlasHelper& helper = mAtlasHelper;
-
-    // Clear previous atlas
-    helper.Reset();
-    helper.Reserve( glyphs.Count() );
-
-    for( unsigned int i=0; i<glyphs.Count(); ++i )
+    for( unsigned int i=0; i<mGlyphs.size(); ++i )
     {
-      float width  = glyphs[i].width;
-      float height = glyphs[i].height;
+      const AtlasGlyph& glyph = mGlyphs[i];
 
-      if( width > 0 &&
-          height > 0 ) // skip whitespace
+      const Pixel::Format glyphFormat = glyph.mBitmap.GetPixelFormat();
+
+      if( format == glyphFormat &&
+          fontId == glyph.fontId &&
+          index  == glyph.index )
       {
-        if( !helper.GlyphFound( glyphs[i].fontId, glyphs[i].index ) )
-        {
-          helper.AddGlyph( glyphs[i] );
-        }
+        coords = glyph.coords;
+        return true;
       }
     }
 
-    // Uploads the bitmaps to Dali
-    return helper.CreateAtlas();
+    return false;
   }
 
   /**
@@ -222,7 +266,7 @@ struct BasicRenderer::Impl
    * @param[in] positions The 2D positions of the glyphs.
    * @param[in] image The material uses this as a diffuse texture.
    */
-  Mesh CreateMesh( const Vector<GlyphInfo>& glyphs, const std::vector<Vector2>& positions, Image image )
+  Mesh CreateMesh( const Vector<GlyphInfo>& glyphs, const std::vector<Vector2>& positions, Pixel::Format format, Image image )
   {
     MeshData::VertexContainer vertices( 4 * glyphs.Count() ); // 1 quad per glyph
 
@@ -240,15 +284,16 @@ struct BasicRenderer::Impl
         const Vector2& position = positions[i];
 
         TextureCoordinates coords;
-        mAtlasHelper.GetTextureCoordinates( glyphs[i].fontId, glyphs[i].index, coords );
-
-        vertices[ i*4 + 0 ] = MeshData::Vertex( Vector3( position.x + 0.0f*width, position.y + 0.0f*height, 0.0f ), coords.topLeft,     Vector3( 1.0f, 0.0f, 0.0f ) );
-        vertices[ i*4 + 1 ] = MeshData::Vertex( Vector3( position.x + 1.0f*width, position.y + 0.0f*height, 0.0f ), coords.topRight,    Vector3( 1.0f, 1.0f, 0.0f ) );
-        vertices[ i*4 + 2 ] = MeshData::Vertex( Vector3( position.x + 0.0f*width, position.y + 1.0f*height, 0.0f ), coords.bottomLeft,  Vector3( 0.0f, 1.0f, 0.0f ) );
-        vertices[ i*4 + 3 ] = MeshData::Vertex( Vector3( position.x + 1.0f*width, position.y + 1.0f*height, 0.0f ), coords.bottomRight, Vector3( 0.0f, 0.0f, 1.0f ) );
+        if( GetTextureCoordinates( format, glyphs[i].fontId, glyphs[i].index, coords ) )
+        {
+          vertices[ i*4 + 0 ] = MeshData::Vertex( Vector3( position.x + 0.0f*width, position.y + 0.0f*height, 0.0f ), coords.topLeft,     Vector3( 1.0f, 0.0f, 0.0f ) );
+          vertices[ i*4 + 1 ] = MeshData::Vertex( Vector3( position.x + 1.0f*width, position.y + 0.0f*height, 0.0f ), coords.topRight,    Vector3( 1.0f, 1.0f, 0.0f ) );
+          vertices[ i*4 + 2 ] = MeshData::Vertex( Vector3( position.x + 0.0f*width, position.y + 1.0f*height, 0.0f ), coords.bottomLeft,  Vector3( 0.0f, 1.0f, 0.0f ) );
+          vertices[ i*4 + 3 ] = MeshData::Vertex( Vector3( position.x + 1.0f*width, position.y + 1.0f*height, 0.0f ), coords.bottomRight, Vector3( 0.0f, 0.0f, 1.0f ) );
 
-        faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 3 ); faces.push_back( i*4 + 1 );
-        faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 2 ); faces.push_back( i*4 + 3 );
+          faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 3 ); faces.push_back( i*4 + 1 );
+          faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 2 ); faces.push_back( i*4 + 3 );
+        }
       }
     }
 
@@ -269,7 +314,18 @@ struct BasicRenderer::Impl
 
   RenderableActor mActor; ///< The actor which renders the text
 
-  AtlasHelper mAtlasHelper; ///< A helper class for storing atlas positions etc.
+  Atlas mAtlasL8;
+  unsigned int mWidthL8;
+  unsigned int mHeightL8;
+
+  // A separate Atlas is used for color Emojis
+  Atlas mAtlasBGRA8888;
+  unsigned int mWidthBGRA8888;
+  unsigned int mHeightBGRA8888;
+
+  std::vector<AtlasGlyph> mGlyphs;
+
+  TextAbstraction::FontClient mFontClient;
 };
 
 Text::RendererPtr BasicRenderer::New()
@@ -279,6 +335,7 @@ Text::RendererPtr BasicRenderer::New()
 
 RenderableActor BasicRenderer::Render( Text::ViewInterface& view )
 {
+  // Remove the previous text
   UnparentAndReset( mImpl->mActor );
 
   Text::Length numberOfGlyphs = view.GetNumberOfGlyphs();
@@ -294,16 +351,46 @@ RenderableActor BasicRenderer::Render( Text::ViewInterface& view )
     positions.resize( numberOfGlyphs );
     view.GetGlyphPositions( &positions[0], 0, numberOfGlyphs );
 
-    Atlas atlas = mImpl->CreateAtlas( glyphs );
+    mImpl->CreateAtlases( glyphs );
 
-    MeshActor actor = MeshActor::New( mImpl->CreateMesh( glyphs, positions, atlas ) );
-    actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
-    actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
+    MeshActor actorL8;
+    if( mImpl->mAtlasL8 )
+    {
+      actorL8 = MeshActor::New( mImpl->CreateMesh( glyphs, positions, Pixel::L8, mImpl->mAtlasL8 ) );
+      actorL8.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
 
-    ShaderEffect shader = BasicShader::New();
-    actor.SetShaderEffect( shader );
+      ShaderEffect shader = BasicShader::New();
+      actorL8.SetShaderEffect( shader );
+    }
+
+    MeshActor actorBGRA8888;
+    if( mImpl->mAtlasBGRA8888 )
+    {
+      actorBGRA8888 = MeshActor::New( mImpl->CreateMesh( glyphs, positions, Pixel::BGRA8888, mImpl->mAtlasBGRA8888 ) );
+      actorBGRA8888.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
 
-    mImpl->mActor = actor;
+      ShaderEffect shader = BgraShader::New();
+      actorBGRA8888.SetShaderEffect( shader );
+    }
+
+    // If we have both monochrome & color glyphs, two mesh actors are returned in a container
+    if( actorL8 && actorBGRA8888 )
+    {
+      mImpl->mActor = ImageActor::New();
+      mImpl->mActor.Add( actorL8 );
+      mImpl->mActor.Add( actorBGRA8888 );
+    }
+    else
+    {
+      if( actorL8 )
+      {
+        mImpl->mActor = actorL8;
+      }
+      else if( actorBGRA8888 )
+      {
+        mImpl->mActor = actorBGRA8888;
+      }
+    }
   }
 
   return mImpl->mActor;