Sync bytesPerPixel when pixelFormat contain float at text-utils-devel
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / devel-api / text / text-utils-devel.cpp
old mode 100755 (executable)
new mode 100644 (file)
index 3a286ad..e4733c1
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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/devel-api/text/text-utils-devel.h>
 
 // EXTERNAL INCLUDES
+#include <dali/devel-api/scripting/enum-helper.h>
 #include <dali/devel-api/text-abstraction/font-client.h>
-#include <dali/devel-api/text-abstraction/text-renderer.h>
 #include <dali/devel-api/text-abstraction/text-renderer-layout-helper.h>
+#include <dali/devel-api/text-abstraction/text-renderer.h>
 #include <dali/integration-api/debug.h>
-#include <dali/devel-api/scripting/enum-helper.h>
 #include <cstring>
+#include <limits>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/bidirectional-support.h>
 #include <dali-toolkit/internal/text/color-segmentation.h>
 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
-#include <dali-toolkit/internal/text/logical-model-impl.h>
 #include <dali-toolkit/internal/text/markup-processor.h>
 #include <dali-toolkit/internal/text/multi-language-support.h>
 #include <dali-toolkit/internal/text/segmentation.h>
 #include <dali-toolkit/internal/text/shaper.h>
 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
 #include <dali-toolkit/internal/text/text-font-style.h>
-#include <dali-toolkit/internal/text/visual-model-impl.h>
+#include <dali-toolkit/internal/text/text-model.h>
 
 namespace Dali
 {
-
 using namespace TextAbstraction;
 
 namespace Toolkit
@@ -52,10 +51,8 @@ using namespace Text;
 
 namespace DevelText
 {
-
 namespace Layout
 {
-
 /**
  * @brief The text's layout.
  */
@@ -70,7 +67,6 @@ enum Type
 
 namespace CircularAlignment
 {
-
 /**
  * @brief The enumerations for the circular alignment.
  */
@@ -84,26 +80,58 @@ enum Type
 } // namespace CircularAlignment
 
 const float TO_POINT_26_DOT_6 = 64.f;
-const float TO_FLOAT = 1.f / 255.f;
-const float TO_UCHAR = 255.f;
-const bool RTL = true;
-const float TWO_PI = 2.f * Dali::Math::PI; ///< 360 degrees in radians
-const float RAD_135 = Math::PI_2 + Math::PI_4; ///< 135 degrees in radians;
-const float RAD_225 = RAD_135    + Math::PI_2; ///< 225 degrees in radians;
-const float RAD_270 = 3.f * Math::PI_2;        ///< 270 degrees in radians;
-const float RAD_315 = RAD_225    + Math::PI_2; ///< 315 degrees in radians;
-
-DALI_ENUM_TO_STRING_TABLE_BEGIN( LAYOUT_TYPE )
-DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::Layout, SINGLELINE )
-DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::Layout, MULTILINE )
-DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::Layout, CIRCULAR )
-DALI_ENUM_TO_STRING_TABLE_END( LAYOUT_TYPE )
-
-DALI_ENUM_TO_STRING_TABLE_BEGIN( CIRCULAR_ALIGNMENT_TYPE )
-DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::CircularAlignment, BEGIN )
-DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::CircularAlignment, CENTER )
-DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::CircularAlignment, END )
-DALI_ENUM_TO_STRING_TABLE_END( CIRCULAR_ALIGNMENT_TYPE )
+const float TO_FLOAT          = 1.f / 255.f;
+const float TO_UCHAR          = 255.f;
+const bool  RTL               = true;
+const float TWO_PI            = 2.f * Dali::Math::PI;    ///< 360 degrees in radians
+const float RAD_135           = Math::PI_2 + Math::PI_4; ///< 135 degrees in radians;
+const float RAD_225           = RAD_135 + Math::PI_2;    ///< 225 degrees in radians;
+const float RAD_270           = 3.f * Math::PI_2;        ///< 270 degrees in radians;
+const float RAD_315           = RAD_225 + Math::PI_2;    ///< 315 degrees in radians;
+const float MAX_INT           = std::numeric_limits<int>::max();
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN(LAYOUT_TYPE)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(DevelText::Layout, SINGLELINE)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(DevelText::Layout, MULTILINE)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(DevelText::Layout, CIRCULAR)
+DALI_ENUM_TO_STRING_TABLE_END(LAYOUT_TYPE)
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN(CIRCULAR_ALIGNMENT_TYPE)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(DevelText::CircularAlignment, BEGIN)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(DevelText::CircularAlignment, CENTER)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(DevelText::CircularAlignment, END)
+DALI_ENUM_TO_STRING_TABLE_END(CIRCULAR_ALIGNMENT_TYPE)
+
+struct InternalDataModel
+{
+  InternalDataModel(FontClient&    fontClient,
+                    MetricsPtr     metrics,
+                    Text::ModelPtr textModel)
+  : fontClient(fontClient),
+    metrics(metrics),
+    textModel(textModel),
+    numberOfCharacters{0u},
+    isTextMirrored{false},
+    numberOfGlyphs{0u}
+  {
+    layoutEngine.SetMetrics(metrics);
+  }
+
+  FontClient&               fontClient;
+  MetricsPtr                metrics;
+  Text::Layout::Engine      layoutEngine; ///< The layout engine.
+  Text::ModelPtr            textModel;    ///< Pointer to the text's model.
+  Vector<ColorBlendingMode> blendingMode; ///< How embedded items and bitmap font glyphs are blended with color text.
+  Vector<bool>              isEmoji;      ///< Whether the glyph is an emoji.
+
+  Vector<Character> mirroredUtf32Characters; // The utf32Characters Characters but mirrored if there are RTL text.
+
+  Length numberOfCharacters; // The number of characters (not glyphs!).
+  bool   isTextMirrored;     // Whether the text has been mirrored.
+
+  Length numberOfGlyphs;
+  Size   textLayoutArea;
+};
 
 bool GetLayoutEnumeration(const Property::Value& propertyValue, DevelText::Layout::Type& layout)
 {
@@ -115,83 +143,41 @@ bool GetCircularAlignmentEnumeration(const Property::Value& propertyValue, Devel
   return Scripting::GetEnumerationProperty(propertyValue, CIRCULAR_ALIGNMENT_TYPE_TABLE, CIRCULAR_ALIGNMENT_TYPE_TABLE_COUNT, circularAlignment);
 }
 
-Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<EmbeddedItemInfo>& embeddedItemLayout )
+void ShapeTextPreprocess(const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters, InternalDataModel& internalDataModel)
 {
-  if( textParameters.text.empty() )
-  {
-    Dali::Devel::PixelBuffer pixelBuffer = Dali::Devel::PixelBuffer::New( textParameters.textWidth,
-                                                                          textParameters.textHeight,
-                                                                          Dali::Pixel::RGBA8888 );
-
-    const unsigned int bufferSize = textParameters.textWidth * textParameters.textHeight * Dali::Pixel::GetBytesPerPixel(Dali::Pixel::RGBA8888);
-    unsigned char* buffer = pixelBuffer.GetBuffer();
-    memset(buffer, 0, bufferSize);
-
-    return pixelBuffer;
-  }
-
   MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
-  FontClient fontClient = FontClient::Get();
-  MetricsPtr metrics;
-  Text::Layout::Engine layoutEngine;                  ///< The layout engine.
-  LogicalModelPtr logicalModel = LogicalModel::New(); ///< Pointer to the logical model.
-  VisualModelPtr visualModel = VisualModel::New();    ///< Pointer to the visual model.
-  Vector<ColorBlendingMode> blendingMode;             ///< How embedded items and bitmap font glyphs are blended with color text.
-  Vector<bool> isEmoji;                               ///< Whether the glyph is an emoji.
-
-  // Use this to access FontClient i.e. to get down-scaled Emoji metrics.
-  metrics = Metrics::New( fontClient );
-  layoutEngine.SetMetrics( metrics );
-
-  TextAbstraction::TextRenderer::Parameters rendererParameters( visualModel->mGlyphs,
-                                                                visualModel->mGlyphPositions,
-                                                                visualModel->mColors,
-                                                                visualModel->mColorIndices,
-                                                                blendingMode,
-                                                                isEmoji );
-
-  rendererParameters.width = textParameters.textWidth;
-  rendererParameters.height = textParameters.textHeight;
-  rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888; // @note: At the moment all textures are generated RGBA8888
-
-  Vector<Character>& utf32Characters = logicalModel->mText;                                             // Characters encoded in utf32.
-  Vector<Character> mirroredUtf32Characters;                                                             // The utf32Characters Characters but mirrored if there are RTL text.
-  Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;                                  // The line break info.
-  Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;                                               // Charactes's script.
-  Vector<FontDescriptionRun>& fontDescriptionRuns = logicalModel->mFontDescriptionRuns;                 // Desired font descriptions.
-  Vector<FontRun>& validFonts = logicalModel->mFontRuns;                                                // Validated fonts.
-  Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo; // The bidirectional info per paragraph.
-  Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = logicalModel->mBidirectionalLineInfo;       // The bidirectional info per line.
-  Vector<CharacterDirection>& directions = logicalModel->mCharacterDirections;                          // Character's directions.
-  Vector<ColorRun>& colorRuns = logicalModel->mColorRuns;                                               // colors of the text.
-
-  Vector<CharacterIndex>& glyphsToCharacters = visualModel->mGlyphsToCharacters;                        // Glyphs to character map.
-  Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;                              // Characters to glyphs map.
-  Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;                                // Number of characters per glyph.
-  Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;                                // The number of glyphs that are shaped.
-  Vector<LineRun>& lines = visualModel->mLines;                                                         // The laid out lines.
-
-  Vector<GlyphIndex> newParagraphGlyphs;                   // Glyphs for the new paragraph characters.
+  const uint8_t*       utf8                 = NULL; // pointer to the first character of the text (encoded in utf8)
+  Length               textSize             = 0u;   // The length of the utf8 string.
+
+  Length&            numberOfCharacters      = internalDataModel.numberOfCharacters;
+  Vector<Character>& mirroredUtf32Characters = internalDataModel.mirroredUtf32Characters;
+  Text::ModelPtr&    textModel               = internalDataModel.textModel;
+
+  Vector<Character>&                     utf32Characters     = textModel->mLogicalModel->mText;                       // Characters encoded in utf32.
+  Vector<LineBreakInfo>&                 lineBreakInfo       = textModel->mLogicalModel->mLineBreakInfo;              // The line break info.
+  Vector<ScriptRun>&                     scripts             = textModel->mLogicalModel->mScriptRuns;                 // Charactes's script.
+  Vector<FontDescriptionRun>&            fontDescriptionRuns = textModel->mLogicalModel->mFontDescriptionRuns;        // Desired font descriptions.
+  Vector<FontRun>&                       validFonts          = textModel->mLogicalModel->mFontRuns;                   // Validated fonts.
+  Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo   = textModel->mLogicalModel->mBidirectionalParagraphInfo; // The bidirectional info per paragraph.
+  Vector<CharacterDirection>&            directions          = textModel->mLogicalModel->mCharacterDirections;        // Character's directions.
+  Vector<ColorRun>&                      colorRuns           = textModel->mLogicalModel->mColorRuns;                  // colors of the text.
 
   // the default font's description.
   FontDescription defaultFontDescription;
   PointSize26Dot6 defaultPointSize = FontClient::DEFAULT_POINT_SIZE;
 
-  Length numberOfCharacters = 0u;                          // The number of characters (not glyphs!).
-  bool isTextMirrored = false;                             // Whether the text has been mirrored.
-
-  const uint8_t* utf8 = NULL;                              // pointer to the first character of the text (encoded in utf8)
-  Length textSize = 0u;                                    // The length of the utf8 string.
-
   ////////////////////////////////////////////////////////////////////////////////
   // Process the markup string if the mark-up processor is enabled.
   ////////////////////////////////////////////////////////////////////////////////
 
-  MarkupProcessData markupProcessData( colorRuns,
-                                       fontDescriptionRuns,
-                                       logicalModel->mEmbeddedItems );
+  MarkupProcessData markupProcessData(colorRuns,
+                                      fontDescriptionRuns,
+                                      textModel->mLogicalModel->mEmbeddedItems,
+                                      textModel->mLogicalModel->mAnchors,
+                                      textModel->mLogicalModel->mUnderlinedCharacterRuns,
+                                      textModel->mLogicalModel->mBackgroundColorRuns);
 
-  if (textParameters.markupEnabled)
+  if(textParameters.markupEnabled)
   {
     ProcessMarkupString(textParameters.text, markupProcessData);
     textSize = markupProcessData.markupProcessedText.size();
@@ -215,34 +201,34 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
 
   // Transform a text array encoded in utf8 into an array encoded in utf32.
   // It returns the actual number of characters.
-  numberOfCharacters = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
-  utf32Characters.Resize( numberOfCharacters );
+  numberOfCharacters = Utf8ToUtf32(utf8, textSize, utf32Characters.Begin());
+  utf32Characters.Resize(numberOfCharacters);
 
   ////////////////////////////////////////////////////////////////////////////////
   // Retrieve the Line and Word Break Info.
   ////////////////////////////////////////////////////////////////////////////////
 
-  lineBreakInfo.Resize( numberOfCharacters, LINE_NO_BREAK );
+  lineBreakInfo.Resize(numberOfCharacters, LINE_NO_BREAK);
 
-  SetLineBreakInfo( utf32Characters,
-                    0u,
-                    numberOfCharacters,
-                    lineBreakInfo );
+  SetLineBreakInfo(utf32Characters,
+                   0u,
+                   numberOfCharacters,
+                   lineBreakInfo);
 
   ////////////////////////////////////////////////////////////////////////////////
   // Retrieve the script runs.
   ////////////////////////////////////////////////////////////////////////////////
 
-  multilanguageSupport.SetScripts( utf32Characters,
-                                   0u,
-                                   numberOfCharacters,
-                                   scripts );
+  multilanguageSupport.SetScripts(utf32Characters,
+                                  0u,
+                                  numberOfCharacters,
+                                  scripts);
 
   // Check if there are emojis.
   // If there are an RGBA8888 pixel format is needed.
-  for( const auto& run : scripts )
+  for(const auto& run : scripts)
   {
-    if( run.script == TextAbstraction::Script::EMOJI )
+    if(run.script == TextAbstraction::Script::EMOJI)
     {
       rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888;
       break;
@@ -255,90 +241,107 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
 
   // Set the description font run with the given text parameters.
   FontDescriptionRun fontDescriptionRun;
-  fontDescriptionRun.characterRun.characterIndex = 0u;
+  fontDescriptionRun.characterRun.characterIndex     = 0u;
   fontDescriptionRun.characterRun.numberOfCharacters = numberOfCharacters;
 
-  fontDescriptionRun.familyLength = 0u;
-  fontDescriptionRun.familyName = nullptr;
+  fontDescriptionRun.familyLength  = 0u;
+  fontDescriptionRun.familyName    = nullptr;
   fontDescriptionRun.familyDefined = !textParameters.fontFamily.empty();
-  if( fontDescriptionRun.familyDefined )
+  if(fontDescriptionRun.familyDefined)
   {
     // The allocated memory will be freed when the logical model is destroyed.
     fontDescriptionRun.familyLength = textParameters.fontFamily.size();
-    fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
-    memcpy( fontDescriptionRun.familyName, textParameters.fontFamily.c_str(), fontDescriptionRun.familyLength );
+    fontDescriptionRun.familyName   = new char[fontDescriptionRun.familyLength];
+    memcpy(fontDescriptionRun.familyName, textParameters.fontFamily.c_str(), fontDescriptionRun.familyLength);
   }
 
   fontDescriptionRun.weightDefined = !textParameters.fontWeight.empty();
-  if( fontDescriptionRun.weightDefined )
+  if(fontDescriptionRun.weightDefined)
   {
-    fontDescriptionRun.weight = StringToWeight( textParameters.fontWeight.c_str() );
+    fontDescriptionRun.weight = StringToWeight(textParameters.fontWeight.c_str());
   }
 
   fontDescriptionRun.widthDefined = !textParameters.fontWidth.empty();
-  if( fontDescriptionRun.widthDefined )
+  if(fontDescriptionRun.widthDefined)
   {
-    fontDescriptionRun.width = StringToWidth( textParameters.fontWidth.c_str() );
+    fontDescriptionRun.width = StringToWidth(textParameters.fontWidth.c_str());
   }
 
   fontDescriptionRun.slantDefined = !textParameters.fontSlant.empty();
-  if( fontDescriptionRun.slantDefined )
+  if(fontDescriptionRun.slantDefined)
   {
-    fontDescriptionRun.slant = StringToSlant( textParameters.fontSlant.c_str() );
+    fontDescriptionRun.slant = StringToSlant(textParameters.fontSlant.c_str());
   }
 
-  fontDescriptionRun.sizeDefined = !EqualsZero( textParameters.fontSize );
-  if( fontDescriptionRun.sizeDefined )
+  fontDescriptionRun.sizeDefined = !EqualsZero(textParameters.fontSize);
+  if(fontDescriptionRun.sizeDefined)
   {
-    fontDescriptionRun.size = static_cast<unsigned int>( textParameters.fontSize * TO_POINT_26_DOT_6 );
+    fontDescriptionRun.size = static_cast<unsigned int>(textParameters.fontSize * TO_POINT_26_DOT_6);
   }
 
-  fontDescriptionRuns.PushBack( fontDescriptionRun );
+  fontDescriptionRuns.PushBack(fontDescriptionRun);
 
   // Validates the fonts. If there is a character with no assigned font it sets a default one.
   // After this call, fonts are validated.
-  multilanguageSupport.ValidateFonts( utf32Characters,
-                                      scripts,
-                                      fontDescriptionRuns,
-                                      defaultFontDescription,
-                                      defaultPointSize,
-                                      0u,
-                                      numberOfCharacters,
-                                      validFonts );
+  multilanguageSupport.ValidateFonts(utf32Characters,
+                                     scripts,
+                                     fontDescriptionRuns,
+                                     defaultFontDescription,
+                                     defaultPointSize,
+                                     0u,
+                                     numberOfCharacters,
+                                     validFonts);
 
   ////////////////////////////////////////////////////////////////////////////////
   // Retrieve the Bidirectional info.
   ////////////////////////////////////////////////////////////////////////////////
 
-  bidirectionalInfo.Reserve( 1u );
+  bidirectionalInfo.Reserve(1u);
 
-  SetBidirectionalInfo( utf32Characters,
-                        scripts,
-                        lineBreakInfo,
-                        0u,
-                        numberOfCharacters,
-                        bidirectionalInfo );
+  SetBidirectionalInfo(utf32Characters,
+                       scripts,
+                       lineBreakInfo,
+                       0u,
+                       numberOfCharacters,
+                       bidirectionalInfo);
 
   const bool hasBidirectionalText = 0u != bidirectionalInfo.Count();
-  if( hasBidirectionalText )
+  if(hasBidirectionalText)
   {
     // Only set the character directions if there is right to left characters.
-    GetCharactersDirection( bidirectionalInfo,
-                            numberOfCharacters,
-                            0u,
-                            numberOfCharacters,
-                            directions );
+    GetCharactersDirection(bidirectionalInfo,
+                           numberOfCharacters,
+                           0u,
+                           numberOfCharacters,
+                           directions);
 
     // This paragraph has right to left text. Some characters may need to be mirrored.
     // TODO: consider if the mirrored string can be stored as well.
 
-    isTextMirrored = GetMirroredText( utf32Characters,
-                                      directions,
-                                      bidirectionalInfo,
-                                      0u,
-                                      numberOfCharacters,
-                                      mirroredUtf32Characters );
+    internalDataModel.isTextMirrored = GetMirroredText(utf32Characters,
+                                                       directions,
+                                                       bidirectionalInfo,
+                                                       0u,
+                                                       numberOfCharacters,
+                                                       mirroredUtf32Characters);
   }
+}
+
+void ShapeText(TextAbstraction::TextRenderer::Parameters& rendererParameters, Vector<EmbeddedItemInfo>& embeddedItemLayout, InternalDataModel& internalDataModel)
+{
+  Vector<GlyphIndex>           newParagraphGlyphs; // Glyphs for the new paragraph characters.
+  const Length                 numberOfCharacters      = internalDataModel.numberOfCharacters;
+  const bool                   isTextMirrored          = internalDataModel.isTextMirrored;
+  Text::ModelPtr&              textModel               = internalDataModel.textModel;
+  const Vector<Character>&     mirroredUtf32Characters = internalDataModel.mirroredUtf32Characters;
+  FontClient&                  fontClient              = internalDataModel.fontClient;
+  const Vector<Character>&     utf32Characters         = textModel->mLogicalModel->mText;          // Characters encoded in utf32.
+  const Vector<LineBreakInfo>& lineBreakInfo           = textModel->mLogicalModel->mLineBreakInfo; // The line break info.
+  const Vector<ScriptRun>&     scripts                 = textModel->mLogicalModel->mScriptRuns;    // Charactes's script.
+  const Vector<FontRun>&       validFonts              = textModel->mLogicalModel->mFontRuns;      // Validated fonts.
+
+  Vector<CharacterIndex>& glyphsToCharacters = textModel->mVisualModel->mGlyphsToCharacters; // Glyphs to character map.
+  Vector<Length>&         charactersPerGlyph = textModel->mVisualModel->mCharactersPerGlyph; // Number of characters per glyph.
 
   ////////////////////////////////////////////////////////////////////////////////
   // Retrieve the glyphs. Text shaping
@@ -346,100 +349,104 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
 
   const Vector<Character>& textToShape = isTextMirrored ? mirroredUtf32Characters : utf32Characters;
 
-  newParagraphGlyphs.Reserve( 1u );
+  newParagraphGlyphs.Reserve(1u);
 
   // Shapes the text.
-  ShapeText( textToShape,
-             lineBreakInfo,
-             scripts,
-             validFonts,
-             0u,
-             0u,
-             numberOfCharacters,
-             rendererParameters.glyphs,
-             glyphsToCharacters,
-             charactersPerGlyph,
-             newParagraphGlyphs );
+  ShapeText(textToShape,
+            lineBreakInfo,
+            scripts,
+            validFonts,
+            0u,
+            0u,
+            numberOfCharacters,
+            rendererParameters.glyphs,
+            glyphsToCharacters,
+            charactersPerGlyph,
+            newParagraphGlyphs);
 
   // Create the 'number of glyphs' per character and the glyph to character conversion tables.
-  visualModel->CreateGlyphsPerCharacterTable( 0u, 0u, numberOfCharacters );
-  visualModel->CreateCharacterToGlyphTable( 0u, 0u, numberOfCharacters );
+  textModel->mVisualModel->CreateGlyphsPerCharacterTable(0u, 0u, numberOfCharacters);
+  textModel->mVisualModel->CreateCharacterToGlyphTable(0u, 0u, numberOfCharacters);
 
-  const Length numberOfGlyphs = rendererParameters.glyphs.Count();
+  internalDataModel.numberOfGlyphs = rendererParameters.glyphs.Count();
 
   // Once the text has been shaped and the glyphs created it's possible to replace the font id of those glyphs
   // that represent an image or an item and create the embedded item layout info.
   // Note: the position of the embedded item can't be set until the text is laid-out.
-  embeddedItemLayout.Reserve( logicalModel->mEmbeddedItems.Count() );
-  for( const auto& item : logicalModel->mEmbeddedItems )
+  embeddedItemLayout.Reserve(textModel->mLogicalModel->mEmbeddedItems.Count());
+  for(const auto& item : textModel->mLogicalModel->mEmbeddedItems)
   {
     // Get the glyph that matches with the character index.
-    const GlyphIndex glyphIndex = visualModel->mCharactersToGlyph[item.characterIndex];
-    GlyphInfo& glyph = rendererParameters.glyphs[glyphIndex];
+    const GlyphIndex glyphIndex = textModel->mVisualModel->mCharactersToGlyph[item.characterIndex];
+    GlyphInfo&       glyph      = rendererParameters.glyphs[glyphIndex];
 
-    glyph.fontId = 0u;
-    Pixel::Format pixelFormat = Pixel::A8;
-    TextAbstraction::FontClient::EmbeddedItemDescription description = { std::string( item.url, item.urlLength ), item.width, item.height, item.colorBlendingMode };
-    glyph.index = fontClient.CreateEmbeddedItem( description, pixelFormat ); // Set here an index to an item.
+    glyph.fontId                                                     = 0u;
+    Pixel::Format                                        pixelFormat = Pixel::A8;
+    TextAbstraction::FontClient::EmbeddedItemDescription description = {std::string(item.url, item.urlLength), item.width, item.height, item.colorBlendingMode};
+    glyph.index                                                      = fontClient.CreateEmbeddedItem(description, pixelFormat); // Set here an index to an item.
 
-    if( ( Pixel::RGBA8888 == pixelFormat ) || ( Pixel::BGRA8888 == pixelFormat ) )
+    if((Pixel::RGBA8888 == pixelFormat) || (Pixel::BGRA8888 == pixelFormat))
     {
       rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888;
     }
 
     // If the url is empty the item is going to be added after the text is rendered. It's needed to store the layout here.
-    if( description.url.empty() )
+    if(description.url.empty())
     {
       EmbeddedItemInfo embeddedInfo =
-      {
-        item.characterIndex,
-        glyphIndex,
-        Vector2::ZERO,
-        Size( static_cast<float>( item.width ), static_cast<float>( item.height ) ),
-        Size( static_cast<float>( item.width ), static_cast<float>( item.height ) ),
-        Degree( 0.f ),
-        item.colorBlendingMode
-      };
-
-      embeddedItemLayout.PushBack( embeddedInfo );
+        {
+          item.characterIndex,
+          glyphIndex,
+          Vector2::ZERO,
+          Size(static_cast<float>(item.width), static_cast<float>(item.height)),
+          Size(static_cast<float>(item.width), static_cast<float>(item.height)),
+          Degree(0.f),
+          item.colorBlendingMode};
+
+      embeddedItemLayout.PushBack(embeddedInfo);
     }
   }
+}
 
-  ////////////////////////////////////////////////////////////////////////////////
-  // Retrieve the glyph's metrics.
-  ////////////////////////////////////////////////////////////////////////////////
+void SetColorSegmentation(const RendererParameters& textParameters, InternalDataModel& internalDataModel)
+{
+  Text::ModelPtr&            textModel    = internalDataModel.textModel;
+  Vector<ColorBlendingMode>& blendingMode = internalDataModel.blendingMode;
+
+  Vector<ColorRun>& colorRuns = textModel->mLogicalModel->mColorRuns; // colors of the text.
 
-  metrics->GetGlyphMetrics( rendererParameters.glyphs.Begin(), numberOfGlyphs );
+  Vector<GlyphIndex>& charactersToGlyph  = textModel->mVisualModel->mCharactersToGlyph;  // Characters to glyphs map.
+  Vector<Length>&     glyphsPerCharacter = textModel->mVisualModel->mGlyphsPerCharacter; // The number of glyphs that are shaped.
 
   ////////////////////////////////////////////////////////////////////////////////
   // Set the color runs in glyphs.
   ////////////////////////////////////////////////////////////////////////////////
 
-  SetColorSegmentationInfo( colorRuns,
-                            charactersToGlyph,
-                            glyphsPerCharacter,
-                            0u,
-                            0u,
-                            numberOfCharacters,
-                            visualModel->mColors,
-                            visualModel->mColorIndices );
+  SetColorSegmentationInfo(colorRuns,
+                           charactersToGlyph,
+                           glyphsPerCharacter,
+                           0u,
+                           0u,
+                           internalDataModel.numberOfCharacters,
+                           textModel->mVisualModel->mColors,
+                           textModel->mVisualModel->mColorIndices);
 
   // Insert the default color at the beginning of the vector.
-  visualModel->mColors.Insert( visualModel->mColors.Begin(),textParameters.textColor );
+  textModel->mVisualModel->mColors.Insert(textModel->mVisualModel->mColors.Begin(), textParameters.textColor);
 
   // Set how the embedded items are blended with text color.
-  blendingMode.Resize( numberOfGlyphs, textParameters.isTextColorSet ? ColorBlendingMode::MULTIPLY : ColorBlendingMode::NONE );
+  blendingMode.Resize(internalDataModel.numberOfGlyphs, textParameters.isTextColorSet ? ColorBlendingMode::MULTIPLY : ColorBlendingMode::NONE);
 
-  if( !textParameters.isTextColorSet )
+  if(!textParameters.isTextColorSet)
   {
     // Traverse the color runs.
-    for( const auto& run : colorRuns )
+    for(const auto& run : colorRuns)
     {
-      const GlyphIndex firstGlyph = visualModel->mCharactersToGlyph[run.characterRun.characterIndex];
-      const CharacterIndex lastCharacter = run.characterRun.characterIndex + run.characterRun.numberOfCharacters - 1u;
-      const GlyphIndex lastGlyphPlusOne = visualModel->mCharactersToGlyph[lastCharacter] + visualModel->mGlyphsPerCharacter[lastCharacter];
+      const GlyphIndex     firstGlyph       = textModel->mVisualModel->mCharactersToGlyph[run.characterRun.characterIndex];
+      const CharacterIndex lastCharacter    = run.characterRun.characterIndex + run.characterRun.numberOfCharacters - 1u;
+      const GlyphIndex     lastGlyphPlusOne = textModel->mVisualModel->mCharactersToGlyph[lastCharacter] + textModel->mVisualModel->mGlyphsPerCharacter[lastCharacter];
 
-      for( GlyphIndex index = firstGlyph; index < lastGlyphPlusOne; ++index )
+      for(GlyphIndex index = firstGlyph; index < lastGlyphPlusOne; ++index)
       {
         blendingMode[index] = ColorBlendingMode::MULTIPLY;
       }
@@ -447,89 +454,84 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
   }
 
   // Traverse the embedded items and update the blending mode vector.
-  for( const auto& item : logicalModel->mEmbeddedItems )
+  for(const auto& item : textModel->mLogicalModel->mEmbeddedItems)
   {
-    const GlyphIndex glyphIndex = visualModel->mCharactersToGlyph[item.characterIndex];
-    blendingMode[glyphIndex] = item.colorBlendingMode;
+    const GlyphIndex glyphIndex = textModel->mVisualModel->mCharactersToGlyph[item.characterIndex];
+    blendingMode[glyphIndex]    = item.colorBlendingMode;
   }
+}
 
+void SetEmojiVector(InternalDataModel& internalDataModel)
+{
+  Vector<bool>&   isEmoji        = internalDataModel.isEmoji;
+  Text::ModelPtr& textModel      = internalDataModel.textModel;
+  const Length    numberOfGlyphs = internalDataModel.numberOfGlyphs;
+
+  const Vector<ScriptRun>& scripts = textModel->mLogicalModel->mScriptRuns; // Charactes's script.
   ////////////////////////////////////////////////////////////////////////////////
   // Set the isEmoji Vector
   ////////////////////////////////////////////////////////////////////////////////
 
-  isEmoji.Resize( numberOfGlyphs, false );
+  isEmoji.Resize(numberOfGlyphs, false);
 
-  for( const auto& run : scripts )
+  for(const auto& run : scripts)
   {
-    if( run.script == TextAbstraction::Script::EMOJI )
+    if(run.script == TextAbstraction::Script::EMOJI)
     {
-      const GlyphIndex firstGlyph = visualModel->mCharactersToGlyph[run.characterRun.characterIndex];
-      const CharacterIndex lastCharacter = run.characterRun.characterIndex + run.characterRun.numberOfCharacters - 1u;
-      const GlyphIndex lastGlyphPlusOne = visualModel->mCharactersToGlyph[lastCharacter] + visualModel->mGlyphsPerCharacter[lastCharacter];
+      const GlyphIndex     firstGlyph       = textModel->mVisualModel->mCharactersToGlyph[run.characterRun.characterIndex];
+      const CharacterIndex lastCharacter    = run.characterRun.characterIndex + run.characterRun.numberOfCharacters - 1u;
+      const GlyphIndex     lastGlyphPlusOne = textModel->mVisualModel->mCharactersToGlyph[lastCharacter] + textModel->mVisualModel->mGlyphsPerCharacter[lastCharacter];
 
-      for( GlyphIndex index = firstGlyph; index < lastGlyphPlusOne; ++index )
+      for(GlyphIndex index = firstGlyph; index < lastGlyphPlusOne; ++index)
       {
         isEmoji[index] = true;
       }
     }
   }
+}
+
+void Align(const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters, Vector<EmbeddedItemInfo>& embeddedItemLayout, InternalDataModel& internalDataModel, const Size& newLayoutSize)
+{
+  Text::Layout::Engine& layoutEngine       = internalDataModel.layoutEngine;
+  Text::ModelPtr&       textModel          = internalDataModel.textModel;
+  const Length          numberOfCharacters = internalDataModel.numberOfCharacters;
+  Size&                 textLayoutArea     = internalDataModel.textLayoutArea;
+
+  Vector<LineRun>& lines = textModel->mVisualModel->mLines; // The laid out lines.
 
   ////////////////////////////////////////////////////////////////////////////////
-  // Layout the text.
+  // Align the text.
   ////////////////////////////////////////////////////////////////////////////////
 
-  // Sets the alignment
-  HorizontalAlignment::Type horizontalAlignment = Toolkit::HorizontalAlignment::CENTER;
+  HorizontalAlignment::Type horizontalAlignment         = Toolkit::HorizontalAlignment::CENTER;
   HorizontalAlignment::Type horizontalCircularAlignment = Toolkit::HorizontalAlignment::CENTER;
-  VerticalAlignment::Type verticalAlignment = VerticalAlignment::CENTER;
+  VerticalAlignment::Type   verticalAlignment           = VerticalAlignment::CENTER;
+  CircularAlignment::Type   circularAlignment           = CircularAlignment::BEGIN;
+
   Layout::Type layout = Layout::SINGLELINE;
-  CircularAlignment::Type circularAlignment = CircularAlignment::BEGIN;
 
-  Property::Value horizontalAlignmentStr( textParameters.horizontalAlignment );
-  GetHorizontalAlignmentEnumeration( horizontalAlignmentStr, horizontalAlignment );
+  // Sets the alignment
+  Property::Value horizontalAlignmentStr(textParameters.horizontalAlignment);
+  GetHorizontalAlignmentEnumeration(horizontalAlignmentStr, horizontalAlignment);
   horizontalCircularAlignment = horizontalAlignment;
 
-  Property::Value verticalAlignmentStr( textParameters.verticalAlignment );
-  GetVerticalAlignmentEnumeration( verticalAlignmentStr, verticalAlignment );
-
-  Property::Value layoutStr( textParameters.layout );
-  GetLayoutEnumeration( layoutStr, layout );
-
-  Property::Value circularAlignmentStr( textParameters.circularAlignment );
-  GetCircularAlignmentEnumeration( circularAlignmentStr, circularAlignment );
+  Property::Value verticalAlignmentStr(textParameters.verticalAlignment);
+  GetVerticalAlignmentEnumeration(verticalAlignmentStr, verticalAlignment);
 
-  // Whether the layout is multi-line.
-  const Text::Layout::Engine::Type horizontalLayout = ( Layout::MULTILINE == layout ) ? Text::Layout::Engine::MULTI_LINE_BOX : Text::Layout::Engine::SINGLE_LINE_BOX;
-  layoutEngine.SetLayout( horizontalLayout ); // TODO: multi-line.
+  Property::Value circularAlignmentStr(textParameters.circularAlignment);
+  GetCircularAlignmentEnumeration(circularAlignmentStr, circularAlignment);
 
+  Property::Value layoutStr(textParameters.layout);
+  GetLayoutEnumeration(layoutStr, layout);
 
   // Whether the layout is circular.
   const bool isCircularTextLayout = (Layout::CIRCULAR == layout);
-  const bool isClockwise = isCircularTextLayout && ( 0.f < textParameters.incrementAngle );
-
-  // Calculates the max ascender or the max descender.
-  // Is used to calculate the radius of the base line of the text.
-  float maxAscenderDescender = 0.f;
-  if( isCircularTextLayout )
-  {
-    FontId currentFontId = 0u;
-    for( const auto& glyph : rendererParameters.glyphs )
-    {
-      if( currentFontId != glyph.fontId )
-      {
-        currentFontId = glyph.fontId;
-        FontMetrics metrics;
-        fontClient.GetFontMetrics(currentFontId, metrics);
-        maxAscenderDescender = std::max( maxAscenderDescender, isClockwise ? metrics.ascender : metrics.descender );
-      }
-    }
-  }
-  const unsigned int radius = textParameters.radius - static_cast<unsigned int>( maxAscenderDescender );
+  const bool isClockwise          = isCircularTextLayout && (0.f < textParameters.incrementAngle);
 
   // Convert CircularAlignment to HorizontalAlignment.
-  if( isCircularTextLayout )
+  if(isCircularTextLayout)
   {
-    switch( circularAlignment )
+    switch(circularAlignment)
     {
       case CircularAlignment::BEGIN:
       {
@@ -548,91 +550,12 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       }
     }
   }
-
-  // Set the layout parameters.
-  Size textLayoutArea( static_cast<float>( textParameters.textWidth ),
-                     static_cast<float>( textParameters.textHeight ) );
-
-  if( isCircularTextLayout )
-  {
-    // In a circular layout, the length of the text area depends on the radius.
-    rendererParameters.radius = radius;
-    textLayoutArea.width = fabs( Radian( Degree( textParameters.incrementAngle ) ) * static_cast<float>( rendererParameters.radius ) );
-  }
-
-  Text::Layout::Parameters layoutParameters( textLayoutArea,
-                                       textToShape.Begin(),
-                                       lineBreakInfo.Begin(),
-                                       nullptr,
-                                       ( 0u != directions.Count() ) ? directions.Begin() : nullptr,
-                                       rendererParameters.glyphs.Begin(),
-                                       glyphsToCharacters.Begin(),
-                                       charactersPerGlyph.Begin(),
-                                       charactersToGlyph.Begin(),
-                                       glyphsPerCharacter.Begin(),
-                                       numberOfGlyphs,
-                                       isCircularTextLayout ? horizontalCircularAlignment : horizontalAlignment,
-                                       LineWrap::WORD,
-                                       0.f,
-                                       false,
-                                       false ); // Outline's width
-
-  // Resize the vector of positions to have the same size than the vector of glyphs.
-  rendererParameters.positions.Resize( numberOfGlyphs );
-
-  // Whether the last character is a new paragraph character.
-  layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( textToShape[numberOfCharacters - 1u] );
-
-  // The initial glyph and the number of glyphs to layout.
-  layoutParameters.startGlyphIndex = 0u;
-  layoutParameters.numberOfGlyphs = numberOfGlyphs;
-  layoutParameters.startLineIndex = 0u;
-  layoutParameters.estimatedNumberOfLines = 1u;
-
-  // Update the visual model.
-  Size newLayoutSize;
-  bool isAutoScrollEnabled = false;
-  layoutEngine.LayoutText( layoutParameters,
-                           rendererParameters.positions,
-                           lines,
-                           newLayoutSize,
-                           textParameters.ellipsisEnabled,
-                           isAutoScrollEnabled );
-
-  ////////////////////////////////////////////////////////////////////////////////
-  // Reorder BiDirectional lines.
-  ////////////////////////////////////////////////////////////////////////////////
-
-  if( hasBidirectionalText )
-  {
-    // Reorder the line.
-    bidirectionalLineInfo.Reserve( 1u );
-
-    ReorderLines( bidirectionalInfo,
-                  0u,
-                  numberOfCharacters,
-                  lines,
-                  bidirectionalLineInfo );
-
-    // Set the bidirectional info per line into the layout parameters.
-    layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
-    layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
-
-    // Re-layout the text. Reorder those lines with right to left characters.
-    layoutEngine.ReLayoutRightToLeftLines( layoutParameters,
-                                           0u,
-                                           numberOfCharacters,
-                                           rendererParameters.positions );
-  }
-
-  ////////////////////////////////////////////////////////////////////////////////
-  // Align the text.
-  ////////////////////////////////////////////////////////////////////////////////
+  textModel->mHorizontalAlignment = isCircularTextLayout ? horizontalCircularAlignment : horizontalAlignment;
 
   // Retrieve the line of text to know the direction and the width. @todo multi-line
   const LineRun& line = lines[0u];
 
-  if( isCircularTextLayout )
+  if(isCircularTextLayout)
   {
     // Set the circular alignment.
     rendererParameters.circularLayout = isClockwise ? TextRenderer::Parameters::CLOCKWISE : TextRenderer::Parameters::COUNTER_CLOCKWISE;
@@ -641,11 +564,11 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
     textLayoutArea.height = newLayoutSize.height;
 
     // Set the size of the text laid out on a straight horizontal line.
-    rendererParameters.circularWidth = static_cast<unsigned int>( newLayoutSize.width );
-    rendererParameters.circularHeight = static_cast<unsigned int>( newLayoutSize.height );
+    rendererParameters.circularWidth  = static_cast<unsigned int>(newLayoutSize.width);
+    rendererParameters.circularHeight = static_cast<unsigned int>(newLayoutSize.height);
 
     // Calculate the center of the circular text according the horizontal and vertical alingments and the radius.
-    switch( horizontalAlignment )
+    switch(horizontalAlignment)
     {
       case HorizontalAlignment::BEGIN:
       {
@@ -654,17 +577,17 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       }
       case HorizontalAlignment::CENTER:
       {
-        rendererParameters.centerX = static_cast<int>( textParameters.textWidth / 2u );
+        rendererParameters.centerX = static_cast<int>(textParameters.textWidth / 2u);
         break;
       }
       case HorizontalAlignment::END:
       {
-        rendererParameters.centerX = static_cast<int>( textParameters.textWidth ) - static_cast<int>(textParameters.radius);
+        rendererParameters.centerX = static_cast<int>(textParameters.textWidth) - static_cast<int>(textParameters.radius);
         break;
       }
     }
 
-    switch( verticalAlignment )
+    switch(verticalAlignment)
     {
       case VerticalAlignment::TOP:
       {
@@ -673,12 +596,12 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       }
       case VerticalAlignment::CENTER:
       {
-        rendererParameters.centerY = static_cast<int>( textParameters.textHeight / 2u );
+        rendererParameters.centerY = static_cast<int>(textParameters.textHeight / 2u);
         break;
       }
       case VerticalAlignment::BOTTOM:
       {
-        rendererParameters.centerY = static_cast<int>( textParameters.textHeight ) - static_cast<int>(textParameters.radius);
+        rendererParameters.centerY = static_cast<int>(textParameters.textHeight) - static_cast<int>(textParameters.radius);
         break;
       }
     }
@@ -687,10 +610,10 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
     const bool isRTL = RTL == line.direction;
 
     CircularAlignment::Type alignment = circularAlignment;
-    if( isRTL )
+    if(isRTL)
     {
       // Swap the alignment type if the line is right to left.
-      switch( alignment )
+      switch(alignment)
       {
         case CircularAlignment::BEGIN:
         {
@@ -712,7 +635,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
 
     float angleOffset = 0.f;
 
-    switch( alignment )
+    switch(alignment)
     {
       case CircularAlignment::BEGIN:
       {
@@ -721,25 +644,25 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       }
       case CircularAlignment::CENTER:
       {
-        const bool isNeg = textParameters.incrementAngle < 0.f;
-        const float textWidth = static_cast<float>( rendererParameters.circularWidth );
-        angleOffset = ( isNeg ? -0.5f : 0.5f ) * ( textLayoutArea.width - textWidth ) / static_cast<float>( radius );
+        const bool  isNeg     = textParameters.incrementAngle < 0.f;
+        const float textWidth = static_cast<float>(rendererParameters.circularWidth);
+        angleOffset           = (isNeg ? -0.5f : 0.5f) * (textLayoutArea.width - textWidth) / static_cast<float>(rendererParameters.radius);
         break;
       }
       case CircularAlignment::END:
       {
-        const bool isNeg = textParameters.incrementAngle < 0.f;
-        const float textWidth = static_cast<float>( rendererParameters.circularWidth );
-        angleOffset = ( isNeg ? -1.f : 1.f ) * ( textLayoutArea.width - textWidth ) / static_cast<float>( radius );
+        const bool  isNeg     = textParameters.incrementAngle < 0.f;
+        const float textWidth = static_cast<float>(rendererParameters.circularWidth);
+        angleOffset           = (isNeg ? -1.f : 1.f) * (textLayoutArea.width - textWidth) / static_cast<float>(rendererParameters.radius);
         break;
       }
     }
 
     // Update the beginning angle with the calculated offset.
-    rendererParameters.beginAngle = Radian( Degree( textParameters.beginAngle ) ) + angleOffset;
+    rendererParameters.beginAngle = Radian(Degree(textParameters.beginAngle)) + angleOffset;
 
     // Set the vertical position of the glyphs.
-    for( auto& position : rendererParameters.positions )
+    for(auto& position : rendererParameters.positions)
     {
       position.y = 0.f;
     }
@@ -749,7 +672,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
     // Calculate the vertical offset according with the given alignment.
     float penY = 0.f;
 
-    switch( verticalAlignment )
+    switch(verticalAlignment)
     {
       case VerticalAlignment::TOP:
       {
@@ -758,7 +681,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       }
       case VerticalAlignment::CENTER:
       {
-        penY = line.ascender + 0.5f * ( textLayoutArea.height - ( line.ascender - line.descender ) );
+        penY = line.ascender + 0.5f * (textLayoutArea.height - (line.ascender - line.descender));
         break;
       }
       case VerticalAlignment::BOTTOM:
@@ -769,31 +692,31 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
     }
 
     // Calculate the horizontal offset according with the given alignment.
-  float alignmentOffset = 0.f;
-    layoutEngine.Align( textLayoutArea,
-                      0u,
-                      numberOfCharacters,
-                      horizontalAlignment,
-                      lines,
-                      alignmentOffset,
-                      Dali::LayoutDirection::LEFT_TO_RIGHT,
-                      false );
+    float alignmentOffset = 0.f;
+    layoutEngine.Align(textLayoutArea,
+                       0u,
+                       numberOfCharacters,
+                       horizontalAlignment,
+                       lines,
+                       alignmentOffset,
+                       Dali::LayoutDirection::LEFT_TO_RIGHT,
+                       false);
 
     // Update the position of the glyphs with the calculated offsets.
-    for( auto& position : rendererParameters.positions )
-  {
-    position.x += line.alignmentOffset;
-    position.y = penY;
-  }
+    for(auto& position : rendererParameters.positions)
+    {
+      position.x += line.alignmentOffset;
+      position.y = penY;
+    }
   }
 
   // Cairo adds the bearing to the position of the glyph
   // that has already been added by the DALi's layout engine,
   // so it's needed to be removed here.
-  for( unsigned int index = 0u; index < rendererParameters.glyphs.Count(); ++index )
+  for(unsigned int index = 0u; index < rendererParameters.glyphs.Count(); ++index)
   {
-    const GlyphInfo& glyph = rendererParameters.glyphs[index];
-    Vector2& position = rendererParameters.positions[index];
+    const GlyphInfo& glyph    = rendererParameters.glyphs[index];
+    Vector2&         position = rendererParameters.positions[index];
 
     position.x -= glyph.xBearing;
   }
@@ -801,104 +724,111 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
   // Set the position of the embedded items (if there is any).
   EmbeddedItemInfo* embeddedItemLayoutBuffer = embeddedItemLayout.Begin();
 
-  auto transformToArc = isClockwise ? &Dali::TextAbstraction::TransformToArcClockwise : &Dali::TextAbstraction::TransformToArcAntiClockwise;
-
-  for( Length index = 0u, endIndex = embeddedItemLayout.Count(); index < endIndex; ++index )
+  for(Length index = 0u, endIndex = embeddedItemLayout.Count(); index < endIndex; ++index)
   {
-    EmbeddedItemInfo& embeddedItem = *( embeddedItemLayoutBuffer + index );
+    EmbeddedItemInfo& embeddedItem = *(embeddedItemLayoutBuffer + index);
 
     embeddedItem.position = rendererParameters.positions[embeddedItem.glyphIndex];
 
-    if( isCircularTextLayout )
+    if(isCircularTextLayout)
     {
       // Calculate the new position of the embedded item in the circular path.
 
       // Center of the bitmap.
-      const float halfWidth = 0.5f * embeddedItem.size.width;
+      const float halfWidth  = 0.5f * embeddedItem.size.width;
       const float halfHeight = 0.5f * embeddedItem.size.height;
-      double centerX = static_cast<double>( embeddedItem.position.x + halfWidth );
-      double centerY = static_cast<double>(embeddedItem.position.y - halfHeight);
+      double      centerX    = static_cast<double>(embeddedItem.position.x + halfWidth);
+      double      centerY    = static_cast<double>(embeddedItem.position.y - halfHeight);
 
       Dali::TextAbstraction::CircularTextParameters circularTextParameters;
 
-      circularTextParameters.radius = static_cast<double>( radius );
-      circularTextParameters.invRadius = 1.0 / circularTextParameters.radius;
-      circularTextParameters.beginAngle = static_cast<double>( -rendererParameters.beginAngle + Dali::Math::PI_2 );
-      circularTextParameters.centerX = 0.5f * static_cast<double>( textParameters.textWidth );
-      circularTextParameters.centerY = 0.5f * static_cast<double>( textParameters.textHeight );
+      circularTextParameters.radius     = static_cast<double>(rendererParameters.radius);
+      circularTextParameters.invRadius  = 1.0 / circularTextParameters.radius;
+      circularTextParameters.beginAngle = static_cast<double>(-rendererParameters.beginAngle + Dali::Math::PI_2);
+      circularTextParameters.centerX    = 0.5f * static_cast<double>(textParameters.textWidth);
+      circularTextParameters.centerY    = 0.5f * static_cast<double>(textParameters.textHeight);
 
       // Calculate the rotation angle.
       float radians = rendererParameters.beginAngle;
-      if( isClockwise )
+      if(isClockwise)
       {
-        radians += static_cast<float>( circularTextParameters.invRadius * centerX );
+        radians += static_cast<float>(circularTextParameters.invRadius * centerX);
         radians = -radians;
       }
       else
       {
-        radians -= static_cast<float>( circularTextParameters.invRadius * centerX );
+        radians -= static_cast<float>(circularTextParameters.invRadius * centerX);
         radians = -radians + Dali::Math::PI;
       }
-      embeddedItem.angle = Degree( Radian( radians ) );
+      embeddedItem.angle = Degree(Radian(radians));
 
-      transformToArc( circularTextParameters, centerX, centerY );
+      Dali::TextAbstraction::TransformToArc(circularTextParameters, centerX, centerY);
 
       // Recalculate the size of the embedded item after the rotation to position it correctly.
-      float width = embeddedItem.size.width;
+      float width  = embeddedItem.size.width;
       float height = embeddedItem.size.height;
 
       // Transform the input angle into the range [0..2PI]
-      radians = fmod( radians, TWO_PI );
-      radians += ( radians < 0.f ) ? TWO_PI : 0.f;
+      radians = fmod(radians, TWO_PI);
+      radians += (radians < 0.f) ? TWO_PI : 0.f;
 
       // Does the same operations than rotate by shear.
-      if( ( radians > Math::PI_4 ) && ( radians <= RAD_135 ) )
+      if((radians > Math::PI_4) && (radians <= RAD_135))
       {
-        std::swap( width, height );
+        std::swap(width, height);
         radians -= Math::PI_2;
       }
-      else if( ( radians > RAD_135 ) && ( radians <= RAD_225 ) )
+      else if((radians > RAD_135) && (radians <= RAD_225))
       {
         radians -= Math::PI;
       }
-      else if( ( radians > RAD_225 ) && ( radians <= RAD_315 ) )
+      else if((radians > RAD_225) && (radians <= RAD_315))
       {
-        std::swap( width, height );
+        std::swap(width, height);
         radians -= RAD_270;
       }
 
-      if( fabs( radians ) > Dali::Math::MACHINE_EPSILON_10 )
+      if(fabs(radians) > Dali::Math::MACHINE_EPSILON_10)
       {
-        const float angleSinus = fabs( sin( radians ) );
-        const float angleCosinus = cos( radians );
+        const float angleSinus   = fabs(sin(radians));
+        const float angleCosinus = cos(radians);
 
         // Calculate the rotated image dimensions.
         embeddedItem.rotatedSize.height = width * angleSinus + height * angleCosinus;
-        embeddedItem.rotatedSize.width = height * angleSinus + width * angleCosinus + 1.f;
+        embeddedItem.rotatedSize.width  = height * angleSinus + width * angleCosinus + 1.f;
       }
 
-      embeddedItem.position.x = floor( static_cast<float>( centerX ) - 0.5f * embeddedItem.rotatedSize.width );
-      embeddedItem.position.y = floor( static_cast<float>( centerY ) - 0.5f * embeddedItem.rotatedSize.height );
+      embeddedItem.position.x = floor(static_cast<float>(centerX) - 0.5f * embeddedItem.rotatedSize.width);
+      embeddedItem.position.y = floor(static_cast<float>(centerY) - 0.5f * embeddedItem.rotatedSize.height);
     }
     else
     {
       embeddedItem.position.y -= embeddedItem.size.height;
     }
   }
+}
 
+void Ellipsis(const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters, Vector<EmbeddedItemInfo>& embeddedItemLayout, InternalDataModel& internalDataModel)
+{
+  Text::ModelPtr& textModel  = internalDataModel.textModel;
+  FontClient&     fontClient = internalDataModel.fontClient;
+
+  Vector<LineRun>& lines          = textModel->mVisualModel->mLines; // The laid out lines.
+  Vector<bool>&    isEmoji        = internalDataModel.isEmoji;
+  const Size       textLayoutArea = internalDataModel.textLayoutArea;
   ////////////////////////////////////////////////////////////////////////////////
   // Ellipsis the text.
   ////////////////////////////////////////////////////////////////////////////////
 
-  if( textParameters.ellipsisEnabled )
+  if(textParameters.ellipsisEnabled)
   {
     const LineRun& line = lines[0u]; // TODO: multi-line
 
-    if( line.ellipsis )
+    if(line.ellipsis)
     {
       Length finalNumberOfGlyphs = 0u;
 
-      if( ( line.ascender - line.descender ) > textLayoutArea.height )
+      if((GetLineHeight(line)) > textLayoutArea.height)
       {
         // The height of the line is bigger than the height of the text area.
         // Show the ellipsis glyph even if it doesn't fit in the text area.
@@ -906,13 +836,13 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
         // until is find out that the text area is too small.
 
         // Get the first glyph which is going to be replaced and the ellipsis glyph.
-        GlyphInfo& glyphInfo = rendererParameters.glyphs[0u];
-        const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph( fontClient.GetPointSize( glyphInfo.fontId ) );
+        GlyphInfo&       glyphInfo     = rendererParameters.glyphs[0u];
+        const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph(fontClient.GetPointSize(glyphInfo.fontId));
 
         // Change the 'x' and 'y' position of the ellipsis glyph.
         Vector2& position = rendererParameters.positions[0u];
-        position.x = ellipsisGlyph.xBearing;
-        position.y = textLayoutArea.height - ellipsisGlyph.yBearing;
+        position.x        = ellipsisGlyph.xBearing;
+        position.y        = textLayoutArea.height - ellipsisGlyph.yBearing;
 
         // Replace the glyph by the ellipsis glyph.
         glyphInfo = ellipsisGlyph;
@@ -922,46 +852,45 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       }
       else
       {
-
         // firstPenX, penY and firstPenSet are used to position the ellipsis glyph if needed.
-        float firstPenX = 0.f; // Used if rtl text is elided.
-        bool firstPenSet = false;
+        float firstPenX   = 0.f; // Used if rtl text is elided.
+        bool  firstPenSet = false;
 
         // Add the ellipsis glyph.
-        bool inserted = false;
-        float removedGlypsWidth = 0.f;
+        bool   inserted              = false;
+        float  removedGlypsWidth     = 0.f;
         Length numberOfRemovedGlyphs = 0u;
-        if (line.glyphRun.numberOfGlyphs > 0u)
+        if(line.glyphRun.numberOfGlyphs > 0u)
         {
           GlyphIndex index = line.glyphRun.numberOfGlyphs - 1u;
 
-          GlyphInfo* glyphs = rendererParameters.glyphs.Begin();
-          Vector2* glyphPositions = rendererParameters.positions.Begin();
+          GlyphInfo* glyphs         = rendererParameters.glyphs.Begin();
+          Vector2*   glyphPositions = rendererParameters.positions.Begin();
 
           float penY = 0.f;
 
           // The ellipsis glyph has to fit in the place where the last glyph(s) is(are) removed.
-          while( !inserted )
+          while(!inserted)
           {
-            const GlyphInfo& glyphToRemove = *( glyphs + index );
+            const GlyphInfo& glyphToRemove = *(glyphs + index);
 
-            if( 0u != glyphToRemove.fontId )
+            if(0u != glyphToRemove.fontId)
             {
               // i.e. The font id of the glyph shaped from the '\n' character is zero.
 
               // Need to reshape the glyph as the font may be different in size.
-              const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph( fontClient.GetPointSize( glyphToRemove.fontId ) );
+              const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph(fontClient.GetPointSize(glyphToRemove.fontId));
 
-              if( !firstPenSet )
+              if(!firstPenSet)
               {
-                const Vector2& position = *( glyphPositions + index );
+                const Vector2& position = *(glyphPositions + index);
 
                 // Calculates the penY of the current line. It will be used to position the ellipsis glyph.
                 penY = position.y;
 
                 // Calculates the first penX which will be used if rtl text is elided.
                 firstPenX = position.x - glyphToRemove.xBearing;
-                if( firstPenX < -ellipsisGlyph.xBearing )
+                if(firstPenX < -ellipsisGlyph.xBearing)
                 {
                   // Avoids to exceed the bounding box when rtl text is elided.
                   firstPenX = -ellipsisGlyph.xBearing;
@@ -972,15 +901,15 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
                 firstPenSet = true;
               }
 
-              removedGlypsWidth += std::min( glyphToRemove.advance, ( glyphToRemove.xBearing + glyphToRemove.width ) );
+              removedGlypsWidth += std::min(glyphToRemove.advance, (glyphToRemove.xBearing + glyphToRemove.width));
 
               // Calculate the width of the ellipsis glyph and check if it fits.
               const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing;
-              if( ellipsisGlyphWidth < removedGlypsWidth )
+              if(ellipsisGlyphWidth < removedGlypsWidth)
               {
-                GlyphInfo& glyphInfo = *( glyphs + index );
-                Vector2& position = *( glyphPositions + index );
-                position.x -= ( 0.f > glyphInfo.xBearing ) ? glyphInfo.xBearing : 0.f;
+                GlyphInfo& glyphInfo = *(glyphs + index);
+                Vector2&   position  = *(glyphPositions + index);
+                position.x -= (0.f > glyphInfo.xBearing) ? glyphInfo.xBearing : 0.f;
 
                 // Replace the glyph by the ellipsis glyph.
                 glyphInfo = ellipsisGlyph;
@@ -990,7 +919,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
 
                 // Change the 'x' and 'y' position of the ellipsis glyph.
 
-                if( position.x > firstPenX )
+                if(position.x > firstPenX)
                 {
                   position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth;
                 }
@@ -1002,9 +931,9 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
               }
             }
 
-            if( !inserted )
+            if(!inserted)
             {
-              if( index > 0u )
+              if(index > 0u)
               {
                 --index;
               }
@@ -1022,46 +951,223 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
         }
 
         // Resize the number of glyphs/positions
-        rendererParameters.glyphs.Resize( finalNumberOfGlyphs );
-        rendererParameters.positions.Resize( finalNumberOfGlyphs );
+        rendererParameters.glyphs.Resize(finalNumberOfGlyphs);
+        rendererParameters.positions.Resize(finalNumberOfGlyphs);
 
         // Remove from the embedded items those exceding the last laid out glyph.
-        embeddedItemLayout.Erase( std::remove_if( embeddedItemLayout.Begin(),
-                                                  embeddedItemLayout.End(),
-                                                  [finalNumberOfGlyphs]( const EmbeddedItemInfo& item )
-                                                  {
-                                                     return item.glyphIndex >= finalNumberOfGlyphs;
-                                                  } ),
-                                 embeddedItemLayout.End() );
+        embeddedItemLayout.Erase(std::remove_if(embeddedItemLayout.Begin(),
+                                                embeddedItemLayout.End(),
+                                                [finalNumberOfGlyphs](const EmbeddedItemInfo& item) {
+                                                  return item.glyphIndex >= finalNumberOfGlyphs;
+                                                }),
+                                 embeddedItemLayout.End());
       }
     }
   }
+}
 
+Size LayoutText(const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters, Vector<EmbeddedItemInfo>& embeddedItemLayout, InternalDataModel& internalDataModel)
+{
+  ////////////////////////////////////////////////////////////////////////////////
+  // Layout the text.
+  ////////////////////////////////////////////////////////////////////////////////
+  Text::ModelPtr&          textModel               = internalDataModel.textModel;
+  Text::Layout::Engine&    layoutEngine            = internalDataModel.layoutEngine;
+  FontClient&              fontClient              = internalDataModel.fontClient;
+  const Length             numberOfGlyphs          = internalDataModel.numberOfGlyphs;
+  const bool               isTextMirrored          = internalDataModel.isTextMirrored;
+  const Vector<Character>& mirroredUtf32Characters = internalDataModel.mirroredUtf32Characters;
+  const Length             numberOfCharacters      = internalDataModel.numberOfCharacters;
+  const auto               ellipsisPosition        = textModel->mEllipsisPosition;
+
+  Layout::Type layout = Layout::SINGLELINE;
+
+  Property::Value layoutStr(textParameters.layout);
+  GetLayoutEnumeration(layoutStr, layout);
+
+  // Whether the layout is multi-line.
+  const Text::Layout::Engine::Type horizontalLayout = (Layout::MULTILINE == layout) ? Text::Layout::Engine::MULTI_LINE_BOX : Text::Layout::Engine::SINGLE_LINE_BOX;
+  layoutEngine.SetLayout(horizontalLayout); // TODO: multi-line.
+
+  // Set minimun line size
+  layoutEngine.SetDefaultLineSize(textParameters.minLineSize);
+
+  // Whether the layout is circular.
+  const bool isCircularTextLayout = (Layout::CIRCULAR == layout);
+  const bool isClockwise          = isCircularTextLayout && (0.f < textParameters.incrementAngle);
+
+  // Calculates the max ascender or the max descender.
+  // Is used to calculate the radius of the base line of the text.
+  float maxAscenderDescender = 0.f;
+  if(isCircularTextLayout)
+  {
+    FontId currentFontId = 0u;
+    for(const auto& glyph : rendererParameters.glyphs)
+    {
+      if(currentFontId != glyph.fontId)
+      {
+        currentFontId = glyph.fontId;
+        FontMetrics metrics;
+        fontClient.GetFontMetrics(currentFontId, metrics);
+        maxAscenderDescender = std::max(maxAscenderDescender, isClockwise ? metrics.ascender : metrics.descender);
+      }
+    }
+  }
+  const unsigned int radius = textParameters.radius - static_cast<unsigned int>(maxAscenderDescender);
+
+  // Set the layout parameters.
+  Size textLayoutArea = Size(static_cast<float>(textParameters.textWidth),
+                             static_cast<float>(textParameters.textHeight));
+
+  // padding
+  Extents padding                  = textParameters.padding;
+  internalDataModel.textLayoutArea = Size(textLayoutArea.x - (padding.start + padding.end), textLayoutArea.y - (padding.top + padding.bottom));
+
+  if(isCircularTextLayout)
+  {
+    // In a circular layout, the length of the text area depends on the radius.
+    rendererParameters.radius              = radius;
+    internalDataModel.textLayoutArea.width = fabs(Radian(Degree(textParameters.incrementAngle)) * static_cast<float>(rendererParameters.radius));
+  }
+  // Resize the vector of positions to have the same size than the vector of glyphs.
+  rendererParameters.positions.Resize(numberOfGlyphs);
+
+  textModel->mLineWrapMode          = Text::LineWrap::WORD;
+  textModel->mIgnoreSpacesAfterText = false;
+  Text::Layout::Parameters layoutParameters(internalDataModel.textLayoutArea,
+                                            textModel);
+
+  // Whether the last character is a new paragraph character.
+  const Vector<Character>& textToShape = isTextMirrored ? mirroredUtf32Characters : textModel->mLogicalModel->mText;
+  layoutParameters.isLastNewParagraph  = TextAbstraction::IsNewParagraph(textToShape[numberOfCharacters - 1u]);
+
+  // The initial glyph and the number of glyphs to layout.
+  layoutParameters.startGlyphIndex        = 0u;
+  layoutParameters.numberOfGlyphs         = numberOfGlyphs;
+  layoutParameters.startLineIndex         = 0u;
+  layoutParameters.estimatedNumberOfLines = 1u;
+  layoutParameters.interGlyphExtraAdvance = 0.f;
+
+  // Update the visual model.
+  Size newLayoutSize;
+  bool isAutoScrollEnabled = false;
+  layoutEngine.LayoutText(layoutParameters,
+                          newLayoutSize,
+                          textParameters.ellipsisEnabled,
+                          isAutoScrollEnabled,
+                          ellipsisPosition);
+
+  return newLayoutSize;
+}
+
+Devel::PixelBuffer RenderText(const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters)
+{
   ////////////////////////////////////////////////////////////////////////////////
   // Render the text.
   ////////////////////////////////////////////////////////////////////////////////
 
-  rendererParameters.width = textParameters.textWidth;
+  rendererParameters.width  = textParameters.textWidth;
   rendererParameters.height = textParameters.textHeight;
 
   TextAbstraction::TextRenderer renderer = TextAbstraction::TextRenderer::Get();
-  return renderer.Render( rendererParameters );
+  return renderer.Render(rendererParameters);
+}
+
+Devel::PixelBuffer Render(const RendererParameters& textParameters, Vector<EmbeddedItemInfo>& embeddedItemLayout)
+{
+  if(textParameters.text.empty())
+  {
+    Dali::Devel::PixelBuffer pixelBuffer = Dali::Devel::PixelBuffer::New(textParameters.textWidth,
+                                                                         textParameters.textHeight,
+                                                                         Dali::Pixel::RGBA8888);
+
+    const unsigned int bufferSize = textParameters.textWidth * textParameters.textHeight * Dali::Pixel::GetBytesPerPixel(Dali::Pixel::RGBA8888);
+    unsigned char*     buffer     = pixelBuffer.GetBuffer();
+    memset(buffer, 0, bufferSize);
+
+    return pixelBuffer;
+  }
+
+  FontClient fontClient = FontClient::Get();
+  MetricsPtr metrics;
+  // Use this to access FontClient i.e. to get down-scaled Emoji metrics.
+  metrics = Metrics::New(fontClient);
+
+  Text::ModelPtr    textModel = Text::Model::New();
+  InternalDataModel internalData(fontClient, metrics, textModel);
+
+  TextAbstraction::TextRenderer::Parameters rendererParameters(internalData.textModel->mVisualModel->mGlyphs,
+                                                               internalData.textModel->mVisualModel->mGlyphPositions,
+                                                               internalData.textModel->mVisualModel->mColors,
+                                                               internalData.textModel->mVisualModel->mColorIndices,
+                                                               internalData.blendingMode,
+                                                               internalData.isEmoji);
+
+  rendererParameters.width       = textParameters.textWidth;
+  rendererParameters.height      = textParameters.textHeight;
+  rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888; // @note: At the moment all textures are generated RGBA8888
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Process the markup string if the mark-up processor is enabled.
+  ////////////////////////////////////////////////////////////////////////////////
+  ShapeTextPreprocess(textParameters, rendererParameters, internalData);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Retrieve the glyphs. Text shaping
+  ////////////////////////////////////////////////////////////////////////////////
+  ShapeText(rendererParameters, embeddedItemLayout, internalData);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Retrieve the glyph's metrics.
+  ////////////////////////////////////////////////////////////////////////////////
+
+  metrics->GetGlyphMetrics(rendererParameters.glyphs.Begin(), internalData.numberOfGlyphs);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Set the color runs in glyphs.
+  ////////////////////////////////////////////////////////////////////////////////
+  SetColorSegmentation(textParameters, internalData);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Set the isEmoji Vector
+  ////////////////////////////////////////////////////////////////////////////////
+  SetEmojiVector(internalData);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Layout the text
+  ////////////////////////////////////////////////////////////////////////////////
+  Size newLayoutSize = LayoutText(textParameters, rendererParameters, embeddedItemLayout, internalData);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Align the text.
+  ////////////////////////////////////////////////////////////////////////////////
+  Align(textParameters, rendererParameters, embeddedItemLayout, internalData, newLayoutSize);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Ellipsis the text.
+  ////////////////////////////////////////////////////////////////////////////////
+  Ellipsis(textParameters, rendererParameters, embeddedItemLayout, internalData);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Render the text.
+  ////////////////////////////////////////////////////////////////////////////////
+  return RenderText(textParameters, rendererParameters);
 }
 
-Devel::PixelBuffer CreateShadow( const ShadowParameters& shadowParameters )
+Devel::PixelBuffer CreateShadow(const ShadowParameters& shadowParameters)
 {
   // The size of the pixel data.
-  const int width = static_cast<int>(shadowParameters.input.GetWidth());
+  const int width  = static_cast<int>(shadowParameters.input.GetWidth());
   const int height = static_cast<int>(shadowParameters.input.GetHeight());
 
   // The shadow's offset.
-  const int xOffset = static_cast<int>( shadowParameters.offset.x );
-  const int yOffset = static_cast<int>( shadowParameters.offset.y );
+  const int xOffset = static_cast<int>(shadowParameters.offset.x);
+  const int yOffset = static_cast<int>(shadowParameters.offset.y);
 
   // The size in bytes of the pixel of the input's buffer.
-  const Pixel::Format inputFormat = shadowParameters.input.GetPixelFormat();
-  const unsigned int inputPixelSize = Pixel::GetBytesPerPixel( inputFormat );
-  const bool isA8 = Pixel::A8 == inputFormat;
+  const Pixel::Format inputFormat    = shadowParameters.input.GetPixelFormat();
+  const unsigned int  inputPixelSize = Pixel::GetBytesPerPixel(inputFormat);
+  const bool          isA8           = Pixel::A8 == inputFormat;
 
   // Creates the output pixel buffer.
   Devel::PixelBuffer outputPixelBuffer = Devel::PixelBuffer::New(width, height, Pixel::RGBA8888);
@@ -1074,35 +1180,35 @@ Devel::PixelBuffer CreateShadow( const ShadowParameters& shadowParameters )
   const unsigned char* const inputPixelBuffer = shadowParameters.input.GetBuffer();
 
   float textColor[4u];
-  if (isA8)
+  if(isA8)
   {
     memcpy(textColor, shadowParameters.textColor.AsFloat(), 4u * sizeof(float));
   }
   const float* const shadowColor = shadowParameters.color.AsFloat();
 
   // Traverse the input pixel buffer and write the text on the foreground and the shadow on the background.
-  for (int rowIndex = 0; rowIndex < height; ++rowIndex)
+  for(int rowIndex = 0; rowIndex < height; ++rowIndex)
   {
     // Calculates the rowIndex to the input pixel buffer for the shadow and whether it's within the boundaries.
-    const int yOffsetIndex = rowIndex - yOffset;
+    const int  yOffsetIndex    = rowIndex - yOffset;
     const bool isValidRowIndex = ((yOffsetIndex >= 0) && (yOffsetIndex < height));
 
-    const int rows = rowIndex * width;
+    const int rows       = rowIndex * width;
     const int offsetRows = yOffsetIndex * width;
-    for (int columnIndex = 0; columnIndex < width; ++columnIndex)
+    for(int columnIndex = 0; columnIndex < width; ++columnIndex)
     {
       // Index to the input buffer to retrieve the alpha value of the foreground text.
       const unsigned int index = inputPixelSize * static_cast<unsigned int>(rows + columnIndex);
 
       // Build the index to the input buffer to retrieve the alpha value of the background shadow.
-      unsigned int shadowIndex = 0u;
-      bool isValidShadowIndex = false;
-      if (isValidRowIndex)
+      unsigned int shadowIndex        = 0u;
+      bool         isValidShadowIndex = false;
+      if(isValidRowIndex)
       {
         const int xOffsetIndex = columnIndex - xOffset;
-        isValidShadowIndex = ((xOffsetIndex >= 0) && (xOffsetIndex < width));
+        isValidShadowIndex     = ((xOffsetIndex >= 0) && (xOffsetIndex < width));
 
-        if (isValidShadowIndex)
+        if(isValidShadowIndex)
         {
           shadowIndex = inputPixelSize * static_cast<unsigned int>(offsetRows + xOffsetIndex);
         }
@@ -1111,8 +1217,8 @@ Devel::PixelBuffer CreateShadow( const ShadowParameters& shadowParameters )
       // If the input buffer is an alpha mask, retrieve the values for the foreground text and the background shadow.
       // If not retrieve the color.
       float inputShadowOffsetAlphaValue = 1.f;
-      float inputAlphaValue = 1.f;
-      if (isA8)
+      float inputAlphaValue             = 1.f;
+      if(isA8)
       {
         // Retrieve the alpha value for the shadow.
         inputShadowOffsetAlphaValue = isValidShadowIndex ? (static_cast<float>(*(inputPixelBuffer + shadowIndex)) / 255.f) : 0.f;
@@ -1123,59 +1229,59 @@ Devel::PixelBuffer CreateShadow( const ShadowParameters& shadowParameters )
       else
       {
         // The input buffer is not an alpha mask. Retrieve the color.
-        textColor[0u] = TO_FLOAT * static_cast<float>( *(inputPixelBuffer + index + 0u) );
-        textColor[1u] = TO_FLOAT * static_cast<float>( *(inputPixelBuffer + index + 1u) );
-        textColor[2u] = TO_FLOAT * static_cast<float>( *(inputPixelBuffer + index + 2u) );
-        textColor[3u] = TO_FLOAT * static_cast<float>( *(inputPixelBuffer + index + 3u) );
-        inputAlphaValue = textColor[3u];
-        inputShadowOffsetAlphaValue = isValidShadowIndex ? TO_FLOAT * static_cast<float>( *(inputPixelBuffer + shadowIndex + 3u) ) : 0.f;
+        textColor[0u]               = TO_FLOAT * static_cast<float>(*(inputPixelBuffer + index + 0u));
+        textColor[1u]               = TO_FLOAT * static_cast<float>(*(inputPixelBuffer + index + 1u));
+        textColor[2u]               = TO_FLOAT * static_cast<float>(*(inputPixelBuffer + index + 2u));
+        textColor[3u]               = TO_FLOAT * static_cast<float>(*(inputPixelBuffer + index + 3u));
+        inputAlphaValue             = textColor[3u];
+        inputShadowOffsetAlphaValue = isValidShadowIndex ? TO_FLOAT * static_cast<float>(*(inputPixelBuffer + shadowIndex + 3u)) : 0.f;
       }
 
       // Build the output color.
       float outputColor[4u];
 
-      if( shadowParameters.blendShadow )
+      if(shadowParameters.blendShadow)
       {
         // Blend the shadow's color with the text's color on top
-        const float textAlpha = textColor[3u] * inputAlphaValue;
+        const float textAlpha   = textColor[3u] * inputAlphaValue;
         const float shadowAlpha = shadowColor[3u] * inputShadowOffsetAlphaValue;
 
         // Blends the alpha.
-        outputColor[3u] = 1.f - ((1.f - textAlpha) * (1.f - shadowAlpha));
+        outputColor[3u]              = 1.f - ((1.f - textAlpha) * (1.f - shadowAlpha));
         const bool isOutputAlphaZero = outputColor[3u] < Dali::Math::MACHINE_EPSILON_1000;
-        if( isOutputAlphaZero )
+        if(isOutputAlphaZero)
         {
-          std::fill( outputColor, outputColor + 4u, 0.f );
+          std::fill(outputColor, outputColor + 4u, 0.f);
         }
         else
         {
           // Blends the RGB components.
           float shadowComponent = 0.f;
-          float textComponent = 0.f;
+          float textComponent   = 0.f;
 
           shadowComponent = shadowColor[0u] * inputShadowOffsetAlphaValue;
-          textComponent = textColor[0u] * inputAlphaValue;
-          outputColor[0u] =  (textComponent * textAlpha / outputColor[3u]) + (shadowComponent * shadowAlpha * (1.f - textAlpha) / outputColor[3u]);
+          textComponent   = textColor[0u] * inputAlphaValue;
+          outputColor[0u] = (textComponent * textAlpha / outputColor[3u]) + (shadowComponent * shadowAlpha * (1.f - textAlpha) / outputColor[3u]);
 
           shadowComponent = shadowColor[1u] * inputShadowOffsetAlphaValue;
-          textComponent = textColor[1u] * inputAlphaValue;
-          outputColor[1u] =  (textComponent * textAlpha / outputColor[3u]) + (shadowComponent * shadowAlpha * (1.f - textAlpha) / outputColor[3u]);
+          textComponent   = textColor[1u] * inputAlphaValue;
+          outputColor[1u] = (textComponent * textAlpha / outputColor[3u]) + (shadowComponent * shadowAlpha * (1.f - textAlpha) / outputColor[3u]);
 
           shadowComponent = shadowColor[2u] * inputShadowOffsetAlphaValue;
-          textComponent = textColor[2u] * inputAlphaValue;
-          outputColor[2u] =  (textComponent * textAlpha / outputColor[3u]) + (shadowComponent * shadowAlpha * (1.f - textAlpha) / outputColor[3u]);
+          textComponent   = textColor[2u] * inputAlphaValue;
+          outputColor[2u] = (textComponent * textAlpha / outputColor[3u]) + (shadowComponent * shadowAlpha * (1.f - textAlpha) / outputColor[3u]);
         }
       }
       else
       {
         // No blending!!!
-        std::fill( outputColor, outputColor + 4u, 0.f );
+        std::fill(outputColor, outputColor + 4u, 0.f);
 
-        const float textAlpha = textColor[3u];
+        const float textAlpha   = textColor[3u];
         const float shadowAlpha = shadowColor[3u] * inputShadowOffsetAlphaValue;
 
         // Write shadow first.
-        if( shadowAlpha > Dali::Math::MACHINE_EPSILON_1000 )
+        if(shadowAlpha > Dali::Math::MACHINE_EPSILON_1000)
         {
           outputColor[0u] = shadowColor[0u] * inputShadowOffsetAlphaValue;
           outputColor[1u] = shadowColor[1u] * inputShadowOffsetAlphaValue;
@@ -1184,7 +1290,7 @@ Devel::PixelBuffer CreateShadow( const ShadowParameters& shadowParameters )
         }
 
         // Write character on top.
-        if( textAlpha > Dali::Math::MACHINE_EPSILON_1000 )
+        if(textAlpha > Dali::Math::MACHINE_EPSILON_1000)
         {
           outputColor[0u] = textColor[0u];
           outputColor[1u] = textColor[1u];
@@ -1194,11 +1300,11 @@ Devel::PixelBuffer CreateShadow( const ShadowParameters& shadowParameters )
       }
 
       // Write the color into the output pixel buffer.
-      const unsigned int outputIndex = 4u * (rows + columnIndex);
-      *(outputPixelBufferPtr + outputIndex + 0u) = static_cast<unsigned char>( TO_UCHAR * outputColor[0u] );
-      *(outputPixelBufferPtr + outputIndex + 1u) = static_cast<unsigned char>( TO_UCHAR * outputColor[1u] );
-      *(outputPixelBufferPtr + outputIndex + 2u) = static_cast<unsigned char>( TO_UCHAR * outputColor[2u] );
-      *(outputPixelBufferPtr + outputIndex + 3u) = static_cast<unsigned char>( TO_UCHAR * outputColor[3u] );
+      const unsigned int outputIndex             = 4u * (rows + columnIndex);
+      *(outputPixelBufferPtr + outputIndex + 0u) = static_cast<unsigned char>(TO_UCHAR * outputColor[0u]);
+      *(outputPixelBufferPtr + outputIndex + 1u) = static_cast<unsigned char>(TO_UCHAR * outputColor[1u]);
+      *(outputPixelBufferPtr + outputIndex + 2u) = static_cast<unsigned char>(TO_UCHAR * outputColor[2u]);
+      *(outputPixelBufferPtr + outputIndex + 3u) = static_cast<unsigned char>(TO_UCHAR * outputColor[3u]);
     }
   }
 
@@ -1208,50 +1314,50 @@ Devel::PixelBuffer CreateShadow( const ShadowParameters& shadowParameters )
 
 Devel::PixelBuffer ConvertToRgba8888(Devel::PixelBuffer pixelBuffer, const Vector4& color, bool multiplyByAlpha)
 {
-  if (Dali::Pixel::A8 != pixelBuffer.GetPixelFormat())
+  if(Dali::Pixel::A8 != pixelBuffer.GetPixelFormat())
   {
     // Does nothing.
     return pixelBuffer;
   }
 
-  const unsigned int width = pixelBuffer.GetWidth();
-  const unsigned int height = pixelBuffer.GetHeight();
-  Devel::PixelBuffer newPixelBuffer = Devel::PixelBuffer::New( width, height, Dali::Pixel::RGBA8888 );
+  const unsigned int width          = pixelBuffer.GetWidth();
+  const unsigned int height         = pixelBuffer.GetHeight();
+  Devel::PixelBuffer newPixelBuffer = Devel::PixelBuffer::New(width, height, Dali::Pixel::RGBA8888);
 
-  unsigned char* dstBuffer = newPixelBuffer.GetBuffer();
+  unsigned char*             dstBuffer = newPixelBuffer.GetBuffer();
   const unsigned char* const srcBuffer = pixelBuffer.GetBuffer();
 
-  const unsigned char r = static_cast<unsigned char>( TO_UCHAR * color.r );
-  const unsigned char g = static_cast<unsigned char>( TO_UCHAR * color.g );
-  const unsigned char b = static_cast<unsigned char>( TO_UCHAR * color.b );
+  const unsigned char r = static_cast<unsigned char>(TO_UCHAR * color.r);
+  const unsigned char g = static_cast<unsigned char>(TO_UCHAR * color.g);
+  const unsigned char b = static_cast<unsigned char>(TO_UCHAR * color.b);
 
   unsigned char dstColor[4];
-  for( unsigned int j = 0u; j < height; ++j )
+  for(unsigned int j = 0u; j < height; ++j)
   {
     const unsigned int lineIndex = j * width;
-    for( unsigned int i=0u; i < width; ++i )
+    for(unsigned int i = 0u; i < width; ++i)
     {
       const unsigned int srcIndex = lineIndex + i;
 
-      const float srcAlpha = static_cast<float>( *( srcBuffer + srcIndex ) );
+      const float srcAlpha = static_cast<float>(*(srcBuffer + srcIndex));
 
-      if( multiplyByAlpha )
+      if(multiplyByAlpha)
       {
-        dstColor[0u] = static_cast<unsigned char>( srcAlpha * color.r );
-        dstColor[1u] = static_cast<unsigned char>( srcAlpha * color.g );
-        dstColor[2u] = static_cast<unsigned char>( srcAlpha * color.b );
-        dstColor[3u] = static_cast<unsigned char>( srcAlpha * color.a );
+        dstColor[0u] = static_cast<unsigned char>(srcAlpha * color.r);
+        dstColor[1u] = static_cast<unsigned char>(srcAlpha * color.g);
+        dstColor[2u] = static_cast<unsigned char>(srcAlpha * color.b);
+        dstColor[3u] = static_cast<unsigned char>(srcAlpha * color.a);
       }
       else
       {
         dstColor[0u] = r;
         dstColor[1u] = g;
         dstColor[2u] = b;
-        dstColor[3u] = static_cast<unsigned char>( srcAlpha );
+        dstColor[3u] = static_cast<unsigned char>(srcAlpha);
       }
 
       const unsigned int dstIndex = srcIndex * 4u;
-      memcpy( dstBuffer + dstIndex, dstColor, 4u );
+      memcpy(dstBuffer + dstIndex, dstColor, 4u);
     }
   }
 
@@ -1261,38 +1367,43 @@ Devel::PixelBuffer ConvertToRgba8888(Devel::PixelBuffer pixelBuffer, const Vecto
 void UpdateBuffer(Devel::PixelBuffer src, Devel::PixelBuffer dst, unsigned int x, unsigned int y, bool blend)
 {
   const Dali::Pixel::Format pixelFormat = dst.GetPixelFormat();
-  if( src.GetPixelFormat() != pixelFormat )
+  if(src.GetPixelFormat() != pixelFormat)
   {
     DALI_LOG_ERROR("PixelBuffer::SetBuffer. The pixel format of the new data must be the same of the current pixel buffer.");
     return;
   }
 
-  const unsigned int srcWidth = src.GetWidth();
+  const unsigned int srcWidth  = src.GetWidth();
   const unsigned int srcHeight = src.GetHeight();
-  const unsigned int dstWidth = dst.GetWidth();
+  const unsigned int dstWidth  = dst.GetWidth();
   const unsigned int dstHeight = dst.GetHeight();
 
-  if( ( x > dstWidth ) ||
-      ( y > dstHeight ) ||
-      ( x + srcWidth > dstWidth ) ||
-      ( y + srcHeight > dstHeight ) )
+  if((x > dstWidth) ||
+     (y > dstHeight) ||
+     (x + srcWidth > dstWidth) ||
+     (y + srcHeight > dstHeight))
   {
     DALI_LOG_ERROR("PixelBuffer::SetBuffer. The source pixel buffer is out of the boundaries of the destination pixel buffer.");
     return;
   }
 
   const unsigned int bytesPerPixel = Dali::Pixel::GetBytesPerPixel(pixelFormat);
+  // Ignore when pixelFormat is invalid or contain float
+  if(bytesPerPixel == 0u || bytesPerPixel == 6u || bytesPerPixel == 12u)
+  {
+    return;
+  }
   const unsigned int alphaIndex = bytesPerPixel - 1u;
 
   const unsigned char* const srcBuffer = src.GetBuffer();
-  unsigned char* dstBuffer = dst.GetBuffer();
+  unsigned char*             dstBuffer = dst.GetBuffer();
 
-  if( !blend )
+  if(!blend)
   {
     const unsigned int currentLineSize = dstWidth * bytesPerPixel;
-    const unsigned int newLineSize = srcWidth * bytesPerPixel;
-    unsigned char* currentBuffer = dstBuffer + (y * dstWidth + x) * bytesPerPixel;
-    for (unsigned int j = 0u; j < srcHeight; ++j)
+    const unsigned int newLineSize     = srcWidth * bytesPerPixel;
+    unsigned char*     currentBuffer   = dstBuffer + (y * dstWidth + x) * bytesPerPixel;
+    for(unsigned int j = 0u; j < srcHeight; ++j)
     {
       memcpy(currentBuffer + j * currentLineSize, srcBuffer + j * newLineSize, newLineSize);
     }
@@ -1310,41 +1421,41 @@ void UpdateBuffer(Devel::PixelBuffer src, Devel::PixelBuffer dst, unsigned int x
 
     // Jump till the 'x,y' position
     const unsigned int dstWidthBytes = dstWidth * bytesPerPixel;
-    dstBuffer += ( y * dstWidthBytes + x * bytesPerPixel );
+    dstBuffer += (y * dstWidthBytes + x * bytesPerPixel);
 
-    for (unsigned int j = 0u; j < srcHeight; ++j)
+    for(unsigned int j = 0u; j < srcHeight; ++j)
     {
       const unsigned int srcLineIndex = j * srcWidth;
-      for (unsigned int i = 0u; i < srcWidth; ++i)
+      for(unsigned int i = 0u; i < srcWidth; ++i)
       {
-        const float srcAlpha = TO_FLOAT * static_cast<float>( *( srcBuffer + bytesPerPixel * ( srcLineIndex + i ) + alphaIndex ) );
-        const float dstAlpha = TO_FLOAT * static_cast<float>( *(dstBuffer + i*bytesPerPixel + alphaIndex) );
+        const float srcAlpha = TO_FLOAT * static_cast<float>(*(srcBuffer + bytesPerPixel * (srcLineIndex + i) + alphaIndex));
+        const float dstAlpha = TO_FLOAT * static_cast<float>(*(dstBuffer + i * bytesPerPixel + alphaIndex));
 
         // Blends the alpha channel.
         const float oneMinusSrcAlpha = 1.f - srcAlpha;
-        outputColor[alphaIndex] = 1.f - (oneMinusSrcAlpha * (1.f - dstAlpha));
+        outputColor[alphaIndex]      = 1.f - (oneMinusSrcAlpha * (1.f - dstAlpha));
 
         // Blends the RGB channels.
         const bool isOutputAlphaZero = outputColor[alphaIndex] < Dali::Math::MACHINE_EPSILON_1000;
-        if( isOutputAlphaZero )
+        if(isOutputAlphaZero)
         {
-          std::fill( outputColor, outputColor + bytesPerPixel, 0.f );
+          std::fill(outputColor, outputColor + bytesPerPixel, 0.f);
         }
         else
         {
-          const float srcAlphaOverOutputAlpha = srcAlpha / outputColor[alphaIndex];                                    // fgAlpha / alpha
+          const float srcAlphaOverOutputAlpha                 = srcAlpha / outputColor[alphaIndex];                    // fgAlpha / alpha
           const float dstAlphaOneMinusSrcAlphaOverOutputAlpha = dstAlpha * oneMinusSrcAlpha / outputColor[alphaIndex]; // bgAlpha * ( 1 - fgAlpha ) / alpha
-          for (unsigned int index = 0u; index < alphaIndex; ++index)
+          for(unsigned int index = 0u; index < alphaIndex; ++index)
           {
-            const float dstComponent = TO_FLOAT * static_cast<float>( *( dstBuffer + i * bytesPerPixel + index ) ) * dstAlpha;
-            const float srcComponent = TO_FLOAT * static_cast<float>(*(srcBuffer + bytesPerPixel * (srcLineIndex + i) + index) ) * srcAlpha;
-            outputColor[index] = ( srcComponent * srcAlphaOverOutputAlpha ) + ( dstComponent * dstAlphaOneMinusSrcAlphaOverOutputAlpha );
+            const float dstComponent = TO_FLOAT * static_cast<float>(*(dstBuffer + i * bytesPerPixel + index)) * dstAlpha;
+            const float srcComponent = TO_FLOAT * static_cast<float>(*(srcBuffer + bytesPerPixel * (srcLineIndex + i) + index)) * srcAlpha;
+            outputColor[index]       = (srcComponent * srcAlphaOverOutputAlpha) + (dstComponent * dstAlphaOneMinusSrcAlphaOverOutputAlpha);
           }
         }
 
-        for (unsigned int index = 0u; index < bytesPerPixel; ++index)
+        for(unsigned int index = 0u; index < bytesPerPixel; ++index)
         {
-          *(dstBuffer + i * bytesPerPixel + index) = static_cast<unsigned char>( TO_UCHAR * outputColor[index] );
+          *(dstBuffer + i * bytesPerPixel + index) = static_cast<unsigned char>(TO_UCHAR * outputColor[index]);
         }
       }
 
@@ -1353,6 +1464,90 @@ void UpdateBuffer(Devel::PixelBuffer src, Devel::PixelBuffer dst, unsigned int x
   }
 }
 
+Dali::Property::Array RenderForLastIndex(RendererParameters& textParameters)
+{
+  Property::Array offsetValues;
+  if(textParameters.text.empty())
+  {
+    return offsetValues;
+  }
+  FontClient fontClient = FontClient::Get();
+  MetricsPtr metrics;
+  metrics = Metrics::New(fontClient);
+
+  Text::ModelPtr    textModel = Text::Model::New();
+  InternalDataModel internalData(fontClient, metrics, textModel);
+
+  TextAbstraction::TextRenderer::Parameters rendererParameters(textModel->mVisualModel->mGlyphs,
+                                                               textModel->mVisualModel->mGlyphPositions,
+                                                               textModel->mVisualModel->mColors,
+                                                               textModel->mVisualModel->mColorIndices,
+                                                               internalData.blendingMode,
+                                                               internalData.isEmoji);
+
+  rendererParameters.width  = textParameters.textWidth;
+  rendererParameters.height = textParameters.textHeight;
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Process the markup string if the mark-up processor is enabled.
+  ////////////////////////////////////////////////////////////////////////////////
+  ShapeTextPreprocess(textParameters, rendererParameters, internalData);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Retrieve the glyphs. Text shaping
+  ////////////////////////////////////////////////////////////////////////////////
+  Dali::Vector<Dali::Toolkit::DevelText::EmbeddedItemInfo> embeddedItemLayout;
+  ShapeText(rendererParameters, embeddedItemLayout, internalData);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Retrieve the glyph's metrics.
+  ////////////////////////////////////////////////////////////////////////////////
+  metrics->GetGlyphMetrics(rendererParameters.glyphs.Begin(), internalData.numberOfGlyphs);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Layout the text
+  ////////////////////////////////////////////////////////////////////////////////
+  int boundingBox           = textParameters.textHeight - (textParameters.padding.top + textParameters.padding.bottom);
+  textParameters.textHeight = MAX_INT; // layout for the entire area.
+  LayoutText(textParameters, rendererParameters, embeddedItemLayout, internalData);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Calculation last character index
+  ////////////////////////////////////////////////////////////////////////////////
+  Vector<LineRun>& lines              = internalData.textModel->mVisualModel->mLines;
+  unsigned int     numberOfLines      = lines.Count();
+  int              numberOfCharacters = 0;
+  float            penY               = 0.f;
+  float            lineSize           = internalData.layoutEngine.GetDefaultLineSize();
+  float            lineOffset         = 0.f;
+  for(unsigned int index = 0u; index < numberOfLines; ++index)
+  {
+    const LineRun& line = *(lines.Begin() + index);
+    numberOfCharacters += line.characterRun.numberOfCharacters;
+
+    lineOffset = lineSize > 0.f ? lineSize : GetLineHeight(line);
+    penY += lineOffset;
+    if((penY + lineOffset) > boundingBox)
+    {
+      offsetValues.PushBack(numberOfCharacters);
+      penY = 0.f;
+    }
+  }
+  if(penY > 0.f)
+  {
+    // add remain character index
+    offsetValues.PushBack(numberOfCharacters);
+  }
+
+  return offsetValues;
+}
+
+Dali::Property::Array GetLastCharacterIndex(RendererParameters& textParameters)
+{
+  Dali::Property::Array offsetValues = Toolkit::DevelText::RenderForLastIndex(textParameters);
+  return offsetValues;
+}
+
 } // namespace DevelText
 
 } // namespace Toolkit