[dali_2.3.41] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / rendering / text-typesetter.cpp
index da397ac..503b394 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <dali-toolkit/internal/text/rendering/text-typesetter.h>
 
 // EXTERNAL INCLUDES
+#include <cmath>
 #include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
 #include <dali/public-api/common/constants.h>
+#include <dali/public-api/math/math-utils.h>
 #include <memory.h>
 
 // INTERNAL INCLUDES
@@ -40,6 +44,8 @@ namespace Text
 {
 namespace
 {
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_TEXT_PERFORMANCE_MARKER, false);
+
 const float HALF(0.5f);
 const float ONE_AND_A_HALF(1.5f);
 
@@ -50,24 +56,102 @@ const float ONE_AND_A_HALF(1.5f);
  * @param y The value between [0..255]
  * @return (x*y)/255
  */
-inline uint8_t MultiplyAndNormalizeColor(const uint8_t& x, const uint8_t& y) noexcept
+inline uint8_t MultiplyAndNormalizeColor(const uint8_t x, const uint8_t y) noexcept
 {
   const uint32_t xy = static_cast<const uint32_t>(x) * y;
   return ((xy << 15) + (xy << 7) + xy) >> 23;
 }
 
 /**
+ * @brief Fast multiply & Summation & divide by 255.
+ *
+ * @param x1 The value between [0..255]
+ * @param y1 The value between [0..255]
+ * @param x2 The value between [0..255]
+ * @param y2 The value between [0..255]
+ * @return min(255, (x1*y1)/255 + (x2*y2)/255)
+ */
+inline uint8_t MultiplyAndSummationAndNormalizeColor(const uint8_t x1, const uint8_t y1, const uint8_t x2, const uint8_t y2) noexcept
+{
+  const uint32_t xy1 = static_cast<const uint32_t>(x1) * y1;
+  const uint32_t xy2 = static_cast<const uint32_t>(x2) * y2;
+  const uint32_t res = std::min(65025u, xy1 + xy2); // 65025 is 255 * 255.
+  return ((res + ((res + 257) >> 8)) >> 8); // fast divide by 255.
+}
+
+/// Helper macro define for glyph typesetter. It will reduce some duplicated code line.
+// clang-format off
+/**
+ * @brief Prepare decode glyph bitmap data. It must be call END_GLYPH_BITMAP end of same scope.
+ */
+#define BEGIN_GLYPH_BITMAP(data)                                                                                                                \
+{                                                                                                                                               \
+  uint32_t   glyphOffet               = 0u;                                                                                                     \
+  const bool useLocalScanline         = data.glyphBitmap.compressionType != TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;  \
+  uint8_t* __restrict__ glyphScanline = useLocalScanline ? (uint8_t*)malloc(data.glyphBitmap.width * glyphPixelSize) : data.glyphBitmap.buffer; \
+  DALI_ASSERT_ALWAYS(glyphScanline && "Glyph scanline for buffer is null!");
+
+/**
+ * @brief Macro to skip useless line fast.
+ */
+#define SKIP_GLYPH_SCANLINE(skipLine)                                                                  \
+if(useLocalScanline)                                                                                   \
+{                                                                                                      \
+  for(int32_t lineIndex = 0; lineIndex < skipLine; ++lineIndex)                                        \
+  {                                                                                                    \
+    TextAbstraction::GlyphBufferData::DecompressScanline(data.glyphBitmap, glyphScanline, glyphOffet); \
+  }                                                                                                    \
+}                                                                                                      \
+else                                                                                                   \
+{                                                                                                      \
+  glyphScanline += skipLine * static_cast<int32_t>(data.glyphBitmap.width * glyphPixelSize);           \
+}
+
+/**
+ * @brief Prepare scanline of glyph bitmap data per each lines. It must be call END_GLYPH_SCANLINE_DECODE end of same scope.
+ */
+#define BEGIN_GLYPH_SCANLINE_DECODE(data)                                                              \
+{                                                                                                      \
+  if(useLocalScanline)                                                                                 \
+  {                                                                                                    \
+    TextAbstraction::GlyphBufferData::DecompressScanline(data.glyphBitmap, glyphScanline, glyphOffet); \
+  }
+
+/**
+ * @brief Finalize scanline of glyph bitmap data per each lines.
+ */
+#define END_GLYPH_SCANLINE_DECODE(data)                       \
+  if(!useLocalScanline)                                       \
+  {                                                           \
+    glyphScanline += data.glyphBitmap.width * glyphPixelSize; \
+  }                                                           \
+} // For ensure that we call BEGIN_GLYPH_SCANLINE_DECODE before
+
+/**
+ * @brief Finalize decode glyph bitmap data.
+ */
+#define END_GLYPH_BITMAP() \
+  if(useLocalScanline)     \
+  {                        \
+    free(glyphScanline);   \
+  }                        \
+} // For ensure that we call BEGIN_GLYPH_BITMAP before
+
+// clang-format on
+/// Helper macro define end.
+
+/**
  * @brief Data struct used to set the buffer of the glyph's bitmap into the final bitmap's buffer.
  */
 struct GlyphData
 {
-  Devel::PixelBuffer                           bitmapBuffer;     ///< The buffer of the whole bitmap. The format is RGBA8888.
-  Vector2*                                     position;         ///< The position of the glyph.
-  TextAbstraction::FontClient::GlyphBufferData glyphBitmap;      ///< The glyph's bitmap.
-  uint32_t                                     width;            ///< The bitmap's width.
-  uint32_t                                     height;           ///< The bitmap's height.
-  int32_t                                      horizontalOffset; ///< The horizontal offset to be added to the 'x' glyph's position.
-  int32_t                                      verticalOffset;   ///< The vertical offset to be added to the 'y' glyph's position.
+  Devel::PixelBuffer               bitmapBuffer;     ///< The buffer of the whole bitmap. The format is RGBA8888.
+  Vector2*                         position;         ///< The position of the glyph.
+  TextAbstraction::GlyphBufferData glyphBitmap;      ///< The glyph's bitmap.
+  uint32_t                         width;            ///< The bitmap's width.
+  uint32_t                         height;           ///< The bitmap's height.
+  int32_t                          horizontalOffset; ///< The horizontal offset to be added to the 'x' glyph's position.
+  int32_t                          verticalOffset;   ///< The vertical offset to be added to the 'y' glyph's position.
 };
 
 /**
@@ -79,11 +163,11 @@ struct GlyphData
  * @param[in] style The style of the text.
  * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
  */
-void TypesetGlyph(GlyphData&           data,
-                  const Vector2* const position,
-                  const Vector4* const color,
-                  Typesetter::Style    style,
-                  Pixel::Format        pixelFormat)
+void TypesetGlyph(GlyphData& __restrict__ data,
+                  const Vector2* const __restrict__ position,
+                  const Vector4* const __restrict__ color,
+                  const Typesetter::Style style,
+                  const Pixel::Format     pixelFormat)
 {
   if((0u == data.glyphBitmap.width) || (0u == data.glyphBitmap.height))
   {
@@ -98,7 +182,7 @@ void TypesetGlyph(GlyphData&           data,
   // Whether the given glyph is a color one.
   const bool     isColorGlyph    = data.glyphBitmap.isColorEmoji || data.glyphBitmap.isColorBitmap;
   const uint32_t glyphPixelSize  = Pixel::GetBytesPerPixel(data.glyphBitmap.format);
-  const uint32_t glyphAlphaIndex = glyphPixelSize - 1u;
+  const uint32_t glyphAlphaIndex = (glyphPixelSize > 0u) ? glyphPixelSize - 1u : 0u;
 
   // Determinate iterator range.
   const int32_t lineIndexRangeMin = std::max(0, -yOffset);
@@ -114,7 +198,7 @@ void TypesetGlyph(GlyphData&           data,
 
   if(Pixel::RGBA8888 == pixelFormat)
   {
-    uint32_t* bitmapBuffer = reinterpret_cast<uint32_t*>(data.bitmapBuffer.GetBuffer());
+    uint32_t* __restrict__ bitmapBuffer = reinterpret_cast<uint32_t*>(data.bitmapBuffer.GetBuffer());
     // Skip basic line.
     bitmapBuffer += (lineIndexRangeMin + yOffset) * static_cast<int32_t>(data.width);
 
@@ -133,33 +217,35 @@ void TypesetGlyph(GlyphData&           data,
 
     const bool swapChannelsBR = Pixel::BGRA8888 == data.glyphBitmap.format;
 
-    // Pointer to the color glyph if there is one.
-    const uint8_t* glyphBuffer = data.glyphBitmap.buffer;
-
     // Precalculate input color's packed result.
-    uint32_t packedInputColor       = 0u;
-    uint8_t* packedInputColorBuffer = reinterpret_cast<uint8_t*>(&packedInputColor);
+    uint32_t packedInputColor                    = 0u;
+    uint8_t* __restrict__ packedInputColorBuffer = reinterpret_cast<uint8_t*>(&packedInputColor);
 
     *(packedInputColorBuffer + 3u) = static_cast<uint8_t>(color->a * 255);
     *(packedInputColorBuffer + 2u) = static_cast<uint8_t>(color->b * 255);
     *(packedInputColorBuffer + 1u) = static_cast<uint8_t>(color->g * 255);
     *(packedInputColorBuffer)      = static_cast<uint8_t>(color->r * 255);
 
+    // Prepare glyph bitmap
+    BEGIN_GLYPH_BITMAP(data);
+
     // Skip basic line of glyph.
-    glyphBuffer += (lineIndexRangeMin) * static_cast<int32_t>(data.glyphBitmap.width) * glyphPixelSize;
+    SKIP_GLYPH_SCANLINE(lineIndexRangeMin);
 
     // Traverse the pixels of the glyph line per line.
     if(isColorGlyph)
     {
       for(int32_t lineIndex = lineIndexRangeMin; lineIndex < lineIndexRangeMax; ++lineIndex)
       {
+        BEGIN_GLYPH_SCANLINE_DECODE(data);
+
         for(int32_t index = indexRangeMin; index < indexRangeMax; ++index)
         {
           const int32_t xOffsetIndex = xOffset + index;
 
           // Retrieves the color from the color glyph.
-          uint32_t packedColorGlyph       = *(reinterpret_cast<const uint32_t*>(glyphBuffer + (index << 2)));
-          uint8_t* packedColorGlyphBuffer = reinterpret_cast<uint8_t*>(&packedColorGlyph);
+          uint32_t packedColorGlyph                    = *(reinterpret_cast<const uint32_t*>(glyphScanline + (index << 2)));
+          uint8_t* __restrict__ packedColorGlyphBuffer = reinterpret_cast<uint8_t*>(&packedColorGlyph);
 
           // Update the alpha channel.
           const uint8_t colorAlpha       = MultiplyAndNormalizeColor(*(packedInputColorBuffer + 3u), *(packedColorGlyphBuffer + 3u));
@@ -194,18 +280,22 @@ void TypesetGlyph(GlyphData&           data,
           // Set the color into the final pixel buffer.
           *(bitmapBuffer + xOffsetIndex) = packedColorGlyph;
         }
+
         bitmapBuffer += data.width;
-        glyphBuffer += data.glyphBitmap.width * glyphPixelSize;
+
+        END_GLYPH_SCANLINE_DECODE(data);
       }
     }
     else
     {
       for(int32_t lineIndex = lineIndexRangeMin; lineIndex < lineIndexRangeMax; ++lineIndex)
       {
+        BEGIN_GLYPH_SCANLINE_DECODE(data);
+
         for(int32_t index = indexRangeMin; index < indexRangeMax; ++index)
         {
           // Update the alpha channel.
-          const uint8_t alpha = *(glyphBuffer + index * glyphPixelSize + glyphAlphaIndex);
+          const uint8_t alpha = *(glyphScanline + index * glyphPixelSize + glyphAlphaIndex);
 
           // Copy non-transparent pixels only
           if(alpha > 0u)
@@ -231,8 +321,8 @@ void TypesetGlyph(GlyphData&           data,
             {
               // Pack the given color into a 32bit buffer. The alpha channel will be updated later for each pixel.
               // The format is RGBA8888.
-              uint32_t packedColor       = 0u;
-              uint8_t* packedColorBuffer = reinterpret_cast<uint8_t*>(&packedColor);
+              uint32_t packedColor                    = 0u;
+              uint8_t* __restrict__ packedColorBuffer = reinterpret_cast<uint8_t*>(&packedColor);
 
               // Color is pre-muliplied with its alpha.
               *(packedColorBuffer + 3u) = MultiplyAndNormalizeColor(*(packedInputColorBuffer + 3u), currentAlpha);
@@ -245,32 +335,41 @@ void TypesetGlyph(GlyphData&           data,
             }
           }
         }
+
         bitmapBuffer += data.width;
-        glyphBuffer += data.glyphBitmap.width * glyphPixelSize;
+
+        END_GLYPH_SCANLINE_DECODE(data);
       }
     }
+
+    END_GLYPH_BITMAP();
   }
   else // Pixel::L8
   {
     // Below codes required only if not color glyph.
     if(!isColorGlyph)
     {
-      uint8_t*       bitmapBuffer = data.bitmapBuffer.GetBuffer();
-      const uint8_t* glyphBuffer  = data.glyphBitmap.buffer;
-
+      uint8_t* __restrict__ bitmapBuffer = data.bitmapBuffer.GetBuffer();
       // Skip basic line.
       bitmapBuffer += (lineIndexRangeMin + yOffset) * static_cast<int32_t>(data.width);
-      glyphBuffer += (lineIndexRangeMin) * static_cast<int32_t>(data.glyphBitmap.width) * glyphPixelSize;
+
+      // Prepare glyph bitmap
+      BEGIN_GLYPH_BITMAP(data);
+
+      // Skip basic line of glyph.
+      SKIP_GLYPH_SCANLINE(lineIndexRangeMin);
 
       // Traverse the pixels of the glyph line per line.
       for(int32_t lineIndex = lineIndexRangeMin; lineIndex < lineIndexRangeMax; ++lineIndex)
       {
+        BEGIN_GLYPH_SCANLINE_DECODE(data);
+
         for(int32_t index = indexRangeMin; index < indexRangeMax; ++index)
         {
           const int32_t xOffsetIndex = xOffset + index;
 
           // Update the alpha channel.
-          const uint8_t alpha = *(glyphBuffer + index * glyphPixelSize + glyphAlphaIndex);
+          const uint8_t alpha = *(glyphScanline + index * glyphPixelSize + glyphAlphaIndex);
 
           // Copy non-transparent pixels only
           if(alpha > 0u)
@@ -287,22 +386,25 @@ void TypesetGlyph(GlyphData&           data,
         }
 
         bitmapBuffer += data.width;
-        glyphBuffer += data.glyphBitmap.width * glyphPixelSize;
+
+        END_GLYPH_SCANLINE_DECODE(data);
       }
+
+      END_GLYPH_BITMAP();
     }
   }
 }
 
 /// Draws the specified underline color to the buffer
 void DrawUnderline(
-  const uint32_t&                 bufferWidth,
-  const uint32_t&                 bufferHeight,
+  const uint32_t                  bufferWidth,
+  const uint32_t                  bufferHeight,
   GlyphData&                      glyphData,
-  const float&                    baseline,
-  const float&                    currentUnderlinePosition,
-  const float&                    maxUnderlineHeight,
-  const float&                    lineExtentLeft,
-  const float&                    lineExtentRight,
+  const float                     baseline,
+  const float                     currentUnderlinePosition,
+  const float                     maxUnderlineHeight,
+  const float                     lineExtentLeft,
+  const float                     lineExtentRight,
   const UnderlineStyleProperties& commonUnderlineProperties,
   const UnderlineStyleProperties& currentUnderlineProperties,
   const LineRun&                  line)
@@ -379,7 +481,7 @@ void DrawUnderline(
 
         for(uint32_t x = xRangeMin; x < xRangeMax; x++)
         {
-          if(dashGap == 0 && dashWidth > 0)
+          if(Dali::EqualsZero(dashGap) && dashWidth > 0)
           {
             // Note : this is same logic as bitmap[y][x] = underlineColor;
             *(bitmapBuffer + x) = packedUnderlineColor;
@@ -431,14 +533,14 @@ void DrawUnderline(
 
 /// Draws the background color to the buffer
 void DrawBackgroundColor(
-  Vector4         backgroundColor,
-  const uint32_t& bufferWidth,
-  const uint32_t& bufferHeight,
-  GlyphData&      glyphData,
-  const float&    baseline,
-  const LineRun&  line,
-  const float&    lineExtentLeft,
-  const float&    lineExtentRight)
+  Vector4        backgroundColor,
+  const uint32_t bufferWidth,
+  const uint32_t bufferHeight,
+  GlyphData&     glyphData,
+  const float    baseline,
+  const LineRun& line,
+  const float    lineExtentLeft,
+  const float    lineExtentRight)
 {
   const int32_t yRangeMin = std::max(0, static_cast<int32_t>(glyphData.verticalOffset + baseline - line.ascender));
   const int32_t yRangeMax = std::min(static_cast<int32_t>(bufferHeight), static_cast<int32_t>(glyphData.verticalOffset + baseline - line.descender));
@@ -491,7 +593,7 @@ void DrawBackgroundColor(
   }
 }
 
-Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuffer& buffer, const uint32_t& bufferWidth, const uint32_t& bufferHeight, bool ignoreHorizontalAlignment, int32_t horizontalOffset, int32_t verticalOffset)
+Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuffer& buffer, const uint32_t bufferWidth, const uint32_t bufferHeight, const bool ignoreHorizontalAlignment, const int32_t horizontalOffset, const int32_t verticalOffset)
 {
   // Retrieve lines, glyphs, positions and colors from the view model.
   const Length            modelNumberOfLines           = model->GetNumberOfLines();
@@ -501,6 +603,8 @@ Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuff
   const Vector2* const    positionBuffer               = model->GetLayout();
   const Vector4* const    backgroundColorsBuffer       = model->GetBackgroundColors();
   const ColorIndex* const backgroundColorIndicesBuffer = model->GetBackgroundColorIndices();
+  const bool              removeFrontInset             = model->IsRemoveFrontInset();
+  const bool              removeBackInset              = model->IsRemoveBackInset();
 
   const DevelText::VerticalLineAlignment::Type verLineAlign = model->GetVerticalLineAlignment();
 
@@ -570,14 +674,36 @@ Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuff
       }
 
       // Calculate the positions of leftmost and rightmost glyphs in the current line
-      if((position->x < left) || (backgroundColorIndex != prevBackgroundColorIndex))
+      if(removeFrontInset)
       {
-        left = position->x - glyphInfo->xBearing;
+        if((position->x < left) || (backgroundColorIndex != prevBackgroundColorIndex))
+        {
+          left = position->x;
+        }
+      }
+      else
+      {
+        const float originPositionLeft = position->x - glyphInfo->xBearing;
+        if((originPositionLeft < left) || (backgroundColorIndex != prevBackgroundColorIndex))
+        {
+          left = originPositionLeft;
+        }
       }
 
-      if(position->x + glyphInfo->width > right)
+      if(removeBackInset)
+      {
+        if(position->x + glyphInfo->width > right)
+        {
+          right = position->x + glyphInfo->width;
+        }
+      }
+      else
       {
-        right = position->x - glyphInfo->xBearing + glyphInfo->advance;
+        const float originPositionRight = position->x - glyphInfo->xBearing + glyphInfo->advance;
+        if(originPositionRight > right)
+        {
+          right = originPositionRight;
+        }
       }
 
       prevBackgroundColorIndex = backgroundColorIndex;
@@ -598,14 +724,14 @@ Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuff
 }
 
 /// Draws the specified strikethrough color to the buffer
-void DrawStrikethrough(const uint32_t&                     bufferWidth,
-                       const uint32_t&                     bufferHeight,
+void DrawStrikethrough(const uint32_t                      bufferWidth,
+                       const uint32_t                      bufferHeight,
                        GlyphData&                          glyphData,
-                       const float&                        baseline,
-                       const float&                        strikethroughStartingYPosition,
-                       const float&                        maxStrikethroughHeight,
-                       const float&                        lineExtentLeft,
-                       const float&                        lineExtentRight,
+                       const float                         baseline,
+                       const float                         strikethroughStartingYPosition,
+                       const float                         maxStrikethroughHeight,
+                       const float                         lineExtentLeft,
+                       const float                         lineExtentRight,
                        const StrikethroughStyleProperties& commonStrikethroughProperties,
                        const StrikethroughStyleProperties& currentStrikethroughProperties,
                        const LineRun&                      line)
@@ -674,19 +800,19 @@ void DrawStrikethrough(const uint32_t&                     bufferWidth,
  *
  * @return An image buffer.
  */
-inline Devel::PixelBuffer CreateTransparentImageBuffer(const uint32_t& bufferWidth, const uint32_t& bufferHeight, const Pixel::Format& pixelFormat)
+inline Devel::PixelBuffer CreateTransparentImageBuffer(const uint32_t bufferWidth, const uint32_t bufferHeight, const Pixel::Format pixelFormat)
 {
   Devel::PixelBuffer imageBuffer = Devel::PixelBuffer::New(bufferWidth, bufferHeight, pixelFormat);
 
   if(Pixel::RGBA8888 == pixelFormat)
   {
     const uint32_t bufferSizeInt  = bufferWidth * bufferHeight;
-    const uint32_t bufferSizeChar = sizeof(uint32_t) * bufferSizeInt;
+    const size_t   bufferSizeChar = sizeof(uint32_t) * static_cast<std::size_t>(bufferSizeInt);
     memset(imageBuffer.GetBuffer(), 0, bufferSizeChar);
   }
   else
   {
-    memset(imageBuffer.GetBuffer(), 0, bufferWidth * bufferHeight);
+    memset(imageBuffer.GetBuffer(), 0, static_cast<std::size_t>(bufferWidth * bufferHeight));
   }
 
   return imageBuffer;
@@ -712,7 +838,7 @@ inline Devel::PixelBuffer CreateTransparentImageBuffer(const uint32_t& bufferWid
  * False if we store the combined image buffer result into bottomPixelBuffer.
  *
  */
-void CombineImageBuffer(Devel::PixelBuffer& topPixelBuffer, Devel::PixelBuffer& bottomPixelBuffer, const uint32_t& bufferWidth, const uint32_t& bufferHeight, bool storeResultIntoTop)
+void CombineImageBuffer(Devel::PixelBuffer& __restrict__ topPixelBuffer, Devel::PixelBuffer& __restrict__ bottomPixelBuffer, const uint32_t bufferWidth, const uint32_t bufferHeight, bool storeResultIntoTop)
 {
   // Assume that we always combine two RGBA images
   // Jump with 4bytes for optimize runtime.
@@ -749,8 +875,8 @@ void CombineImageBuffer(Devel::PixelBuffer& topPixelBuffer, Devel::PixelBuffer&
 
   const uint32_t bufferSizeInt = bufferWidth * bufferHeight;
 
-  uint32_t* combinedBuffer        = storeResultIntoTop ? topBuffer : bottomBuffer;
-  uint8_t*  topAlphaBufferPointer = reinterpret_cast<uint8_t*>(topBuffer) + 3;
+  uint32_t* __restrict__ combinedBuffer       = storeResultIntoTop ? topBuffer : bottomBuffer;
+  uint8_t* __restrict__ topAlphaBufferPointer = reinterpret_cast<uint8_t*>(topBuffer) + 3;
 
   for(uint32_t pixelIndex = 0; pixelIndex < bufferSizeInt; ++pixelIndex)
   {
@@ -780,8 +906,8 @@ void CombineImageBuffer(Devel::PixelBuffer& topPixelBuffer, Devel::PixelBuffer&
     {
       // At least one pixel is not fully opaque
       // "Over" blend the the pixel from topBuffer with the pixel in bottomBuffer
-      uint32_t blendedBottomBufferColor       = *(bottomBuffer);
-      uint8_t* blendedBottomBufferColorBuffer = reinterpret_cast<uint8_t*>(&blendedBottomBufferColor);
+      uint32_t blendedBottomBufferColor                    = *(bottomBuffer);
+      uint8_t* __restrict__ blendedBottomBufferColorBuffer = reinterpret_cast<uint8_t*>(&blendedBottomBufferColor);
 
       blendedBottomBufferColorBuffer[0] = MultiplyAndNormalizeColor(blendedBottomBufferColorBuffer[0], 255 - topAlpha);
       blendedBottomBufferColorBuffer[1] = MultiplyAndNormalizeColor(blendedBottomBufferColorBuffer[1], 255 - topAlpha);
@@ -811,21 +937,43 @@ ViewModel* Typesetter::GetViewModel()
   return mModel;
 }
 
+void Typesetter::SetFontClient(TextAbstraction::FontClient& fontClient)
+{
+  mFontClient = fontClient;
+}
+
 PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat)
 {
+  Devel::PixelBuffer result = RenderWithPixelBuffer(size, textDirection, behaviour, ignoreHorizontalAlignment, pixelFormat);
+  PixelData pixelData = Devel::PixelBuffer::Convert(result);
+
+  return pixelData;
+}
+
+PixelData Typesetter::RenderWithCutout(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, Devel::PixelBuffer mask, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, float originAlpha)
+{
+  Devel::PixelBuffer result = RenderWithPixelBuffer(size, textDirection, behaviour, ignoreHorizontalAlignment, pixelFormat);
+  SetMaskForImageBuffer(mask, result, size.width, size.height, originAlpha);
+
+  PixelData pixelData = Devel::PixelBuffer::Convert(result);
+
+  return pixelData;
+}
+
+Devel::PixelBuffer Typesetter::RenderWithPixelBuffer(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat)
+{
+  DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_RENDERING_TYPESETTER");
   // @todo. This initial implementation for a TextLabel has only one visible page.
 
   // Elides the text if needed.
-  mModel->ElideGlyphs();
+  mModel->ElideGlyphs(mFontClient);
 
   // Retrieves the layout size.
   const Size& layoutSize = mModel->GetLayoutSize();
-
   const int32_t outlineWidth = static_cast<int32_t>(mModel->GetOutlineWidth());
 
   // Set the offset for the horizontal alignment according to the text direction and outline width.
   int32_t penX = 0;
-
   switch(mModel->GetHorizontalAlignment())
   {
     case HorizontalAlignment::BEGIN:
@@ -847,7 +995,6 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
 
   // Set the offset for the vertical alignment.
   int32_t penY = 0u;
-
   switch(mModel->GetVerticalAlignment())
   {
     case VerticalAlignment::TOP:
@@ -857,8 +1004,9 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
     }
     case VerticalAlignment::CENTER:
     {
-      penY = static_cast<int32_t>(0.5f * (size.height - layoutSize.height));
+      penY = static_cast<int32_t>(std::round(0.5f * (size.height - layoutSize.height)));
       penY = penY < 0.f ? 0.f : penY;
+
       break;
     }
     case VerticalAlignment::BOTTOM:
@@ -868,6 +1016,14 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
     }
   }
 
+  const bool isCutoutEnabled = mModel->IsCutoutEnabled();
+  if(isCutoutEnabled)
+  {
+    Vector2 offset = mModel->GetOffsetWithCutout();
+    penX = offset.x;
+    penY = offset.y;
+  }
+
   // Generate the image buffers of the text for each different style first,
   // then combine all of them together as one final image buffer. We try to
   // do all of these in CPU only, so that once the final texture is generated,
@@ -877,7 +1033,7 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
   const uint32_t bufferHeight = static_cast<uint32_t>(size.height);
 
   const uint32_t bufferSizeInt  = bufferWidth * bufferHeight;
-  const uint32_t bufferSizeChar = sizeof(uint32_t) * bufferSizeInt;
+  const size_t   bufferSizeChar = sizeof(uint32_t) * static_cast<std::size_t>(bufferSizeInt);
 
   //Elided text in ellipsis at START could start on index greater than 0
   auto startIndexOfGlyphs = mModel->GetStartIndexOfElidedGlyphs();
@@ -906,20 +1062,29 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
   {
     // Generate the outline if enabled
     const uint16_t outlineWidth = mModel->GetOutlineWidth();
-    if(outlineWidth != 0u && RENDER_OVERLAY_STYLE != behaviour)
+    const float    outlineAlpha = mModel->GetOutlineColor().a;
+    if(outlineWidth != 0u && fabsf(outlineAlpha) > Math::MACHINE_EPSILON_1 && RENDER_OVERLAY_STYLE != behaviour)
     {
       // Create the image buffer for outline
       Devel::PixelBuffer outlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_OUTLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
 
+      const float& blurRadius = mModel->GetOutlineBlurRadius();
+
+      if(blurRadius > Math::MACHINE_EPSILON_1)
+      {
+        outlineImageBuffer.ApplyGaussianBlur(blurRadius);
+      }
+
       // Combine the two buffers
       CombineImageBuffer(imageBuffer, outlineImageBuffer, bufferWidth, bufferHeight, true);
     }
 
-    // @todo. Support shadow and underline for partial text later on.
+    // @todo. Support shadow for partial text later on.
 
     // Generate the shadow if enabled
     const Vector2& shadowOffset = mModel->GetShadowOffset();
-    if(RENDER_OVERLAY_STYLE != behaviour && (fabsf(shadowOffset.x) > Math::MACHINE_EPSILON_1 || fabsf(shadowOffset.y) > Math::MACHINE_EPSILON_1))
+    const float    shadowAlpha  = mModel->GetShadowColor().a;
+    if(RENDER_OVERLAY_STYLE != behaviour && fabsf(shadowAlpha) > Math::MACHINE_EPSILON_1 && (fabsf(shadowOffset.x) > Math::MACHINE_EPSILON_1 || fabsf(shadowOffset.y) > Math::MACHINE_EPSILON_1))
     {
       // Create the image buffer for shadow
       Devel::PixelBuffer shadowImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_SHADOW, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
@@ -936,17 +1101,6 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
       CombineImageBuffer(imageBuffer, shadowImageBuffer, bufferWidth, bufferHeight, true);
     }
 
-    // Generate the underline if enabled
-    const bool underlineEnabled = mModel->IsUnderlineEnabled();
-    if(underlineEnabled && RENDER_OVERLAY_STYLE == behaviour)
-    {
-      // Create the image buffer for underline
-      Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
-
-      // Combine the two buffers
-      CombineImageBuffer(imageBuffer, underlineImageBuffer, bufferWidth, bufferHeight, true);
-    }
-
     // Generate the background if enabled
     const bool backgroundEnabled   = mModel->IsBackgroundEnabled();
     const bool backgroundMarkupSet = mModel->IsMarkupBackgroundColorSet();
@@ -972,40 +1126,95 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
       CombineImageBuffer(imageBuffer, backgroundImageBuffer, bufferWidth, bufferHeight, true);
     }
 
-    // Generate the strikethrough if enabled
-    const bool strikethroughEnabled = mModel->IsStrikethroughEnabled();
-    if(strikethroughEnabled && RENDER_OVERLAY_STYLE == behaviour)
+    // Generate the background_with_mask if enabled
+    const bool backgroundWithCutoutEnabled   = mModel->IsBackgroundWithCutoutEnabled();
+    if((backgroundWithCutoutEnabled) && RENDER_OVERLAY_STYLE != behaviour)
     {
-      // Create the image buffer for strikethrough
-      Devel::PixelBuffer strikethroughImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_STRIKETHROUGH, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, endIndexOfGlyphs);
+      Devel::PixelBuffer backgroundImageBuffer;
+
+      backgroundImageBuffer = CreateFullBackgroundBuffer(bufferWidth, bufferHeight, mModel->GetBackgroundColorWithCutout());
 
       // Combine the two buffers
-      CombineImageBuffer(imageBuffer, strikethroughImageBuffer, bufferWidth, bufferHeight, true);
+      CombineImageBuffer(imageBuffer, backgroundImageBuffer, bufferWidth, bufferHeight, true);
     }
 
-    // Markup-Processor
+    if(RENDER_OVERLAY_STYLE == behaviour)
+    {
+      if(mModel->IsUnderlineEnabled())
+      {
+        // Create the image buffer for underline
+        Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
+
+        // Combine the two buffers
+        CombineImageBuffer(imageBuffer, underlineImageBuffer, bufferWidth, bufferHeight, true);
+      }
+
+      if(mModel->IsStrikethroughEnabled())
+      {
+        // Create the image buffer for strikethrough
+        Devel::PixelBuffer strikethroughImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_STRIKETHROUGH, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, endIndexOfGlyphs);
+
+        // Combine the two buffers
+        CombineImageBuffer(imageBuffer, strikethroughImageBuffer, bufferWidth, bufferHeight, true);
+      }
 
-    imageBuffer = ApplyMarkupProcessorOnPixelBuffer(imageBuffer, bufferWidth, bufferHeight, ignoreHorizontalAlignment, pixelFormat, penX, penY);
+      // Markup-Processor for overlay styles
+      if(mModel->IsMarkupProcessorEnabled() || mModel->IsSpannedTextPlaced())
+      {
+        if(mModel->IsMarkupUnderlineSet())
+        {
+          imageBuffer = ApplyUnderlineMarkupImageBuffer(imageBuffer, bufferWidth, bufferHeight, ignoreHorizontalAlignment, pixelFormat, penX, penY);
+        }
+
+        if(mModel->IsMarkupStrikethroughSet())
+        {
+          imageBuffer = ApplyStrikethroughMarkupImageBuffer(imageBuffer, bufferWidth, bufferHeight, ignoreHorizontalAlignment, pixelFormat, penX, penY);
+        }
+      }
+    }
   }
 
-  // Create the final PixelData for the combined image buffer
-  PixelData pixelData = Devel::PixelBuffer::Convert(imageBuffer);
+  return imageBuffer;
+}
 
-  return pixelData;
+Devel::PixelBuffer Typesetter::CreateFullBackgroundBuffer(const uint32_t bufferWidth, const uint32_t bufferHeight, const Vector4& backgroundColor)
+{
+  const uint32_t bufferSizeInt = bufferWidth * bufferHeight;
+  uint8_t backgroundColorAlpha = static_cast<uint8_t>(backgroundColor.a * 255.f);
+
+  Devel::PixelBuffer buffer = Devel::PixelBuffer::New(bufferWidth, bufferHeight, Pixel::RGBA8888);
+
+  uint32_t* bitmapBuffer = reinterpret_cast<uint32_t*>(buffer.GetBuffer());
+
+  uint32_t packedBackgroundColor       = 0u;
+  uint8_t* packedBackgroundColorBuffer = reinterpret_cast<uint8_t*>(&packedBackgroundColor);
+
+  // Write the color to the pixel buffer
+  *(packedBackgroundColorBuffer + 3u) = backgroundColorAlpha;
+  *(packedBackgroundColorBuffer + 2u) = static_cast<uint8_t>(backgroundColor.b * backgroundColorAlpha);
+  *(packedBackgroundColorBuffer + 1u) = static_cast<uint8_t>(backgroundColor.g * backgroundColorAlpha);
+  *(packedBackgroundColorBuffer)      = static_cast<uint8_t>(backgroundColor.r * backgroundColorAlpha);
+
+  std::fill(bitmapBuffer, bitmapBuffer + bufferSizeInt, packedBackgroundColor);
+
+  return buffer;
 }
 
-Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t& bufferWidth, const uint32_t& bufferHeight, Typesetter::Style style, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, const int32_t& horizontalOffset, const int32_t& verticalOffset, GlyphIndex fromGlyphIndex, GlyphIndex toGlyphIndex)
+Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t bufferWidth, const uint32_t bufferHeight, const Typesetter::Style style, const bool ignoreHorizontalAlignment, const Pixel::Format pixelFormat, const int32_t horizontalOffset, const int32_t verticalOffset, const GlyphIndex fromGlyphIndex, const GlyphIndex toGlyphIndex)
 {
   // Retrieve lines, glyphs, positions and colors from the view model.
-  const Length            modelNumberOfLines = mModel->GetNumberOfLines();
-  const LineRun* const    modelLinesBuffer   = mModel->GetLines();
-  const GlyphInfo* const  glyphsBuffer       = mModel->GetGlyphs();
-  const Vector2* const    positionBuffer     = mModel->GetLayout();
-  const Vector4* const    colorsBuffer       = mModel->GetColors();
-  const ColorIndex* const colorIndexBuffer   = mModel->GetColorIndices();
-  const GlyphInfo*        hyphens            = mModel->GetHyphens();
-  const Length*           hyphenIndices      = mModel->GetHyphenIndices();
-  const Length            hyphensCount       = mModel->GetHyphensCount();
+  const Length modelNumberOfLines                       = mModel->GetNumberOfLines();
+  const LineRun* const __restrict__ modelLinesBuffer    = mModel->GetLines();
+  const GlyphInfo* const __restrict__ glyphsBuffer      = mModel->GetGlyphs();
+  const Vector2* const __restrict__ positionBuffer      = mModel->GetLayout();
+  const Vector4* const __restrict__ colorsBuffer        = mModel->GetColors();
+  const ColorIndex* const __restrict__ colorIndexBuffer = mModel->GetColorIndices();
+  const GlyphInfo* __restrict__ hyphens                 = mModel->GetHyphens();
+  const Length* __restrict__ hyphenIndices              = mModel->GetHyphenIndices();
+  const Length hyphensCount                             = mModel->GetHyphensCount();
+  const bool removeFrontInset                           = mModel->IsRemoveFrontInset();
+  const bool removeBackInset                            = mModel->IsRemoveBackInset();
+  const bool cutoutEnabled                              = mModel->IsCutoutEnabled();
 
   // Elided text info. Indices according to elided text and Ellipsis position.
   const auto startIndexOfGlyphs              = mModel->GetStartIndexOfElidedGlyphs();
@@ -1027,13 +1236,12 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t& bufferWidth, co
   glyphData.horizontalOffset = 0;
 
   // Get a handle of the font client. Used to retrieve the bitmaps of the glyphs.
-  TextAbstraction::FontClient fontClient  = TextAbstraction::FontClient::Get();
   Length                      hyphenIndex = 0;
 
-  const Character*              textBuffer                = mModel->GetTextBuffer();
-  float                         calculatedAdvance         = 0.f;
-  const Vector<CharacterIndex>& glyphToCharacterMap       = mModel->GetGlyphsToCharacters();
-  const CharacterIndex*         glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
+  const Character* __restrict__ textBuffer                       = mModel->GetTextBuffer();
+  float calculatedAdvance                                        = 0.f;
+  const Vector<CharacterIndex>& __restrict__ glyphToCharacterMap = mModel->GetGlyphsToCharacters();
+  const CharacterIndex* __restrict__ glyphToCharacterMapBuffer   = glyphToCharacterMap.Begin();
 
   const DevelText::VerticalLineAlignment::Type verLineAlign = mModel->GetVerticalLineAlignment();
 
@@ -1054,11 +1262,15 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t& bufferWidth, co
 
     if(style == Typesetter::STYLE_OUTLINE)
     {
+      const Vector2& outlineOffset = mModel->GetOutlineOffset();
+
       glyphData.horizontalOffset -= outlineWidth;
+      glyphData.horizontalOffset += outlineOffset.x;
       if(lineIndex == 0u)
       {
         // Only need to add the vertical outline offset for the first line
         glyphData.verticalOffset -= outlineWidth;
+        glyphData.verticalOffset += outlineOffset.y;
       }
     }
     else if(style == Typesetter::STYLE_SHADOW)
@@ -1078,7 +1290,7 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t& bufferWidth, co
     const float modelCharacterSpacing = mModel->GetCharacterSpacing();
 
     // Get the character-spacing runs.
-    const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = mModel->GetCharacterSpacingGlyphRuns();
+    const Vector<CharacterSpacingGlyphRun>& __restrict__ characterSpacingGlyphRuns = mModel->GetCharacterSpacingGlyphRuns();
 
     // Aggregate underline-style-properties from mModel
     const UnderlineStyleProperties modelUnderlineProperties{mModel->GetUnderlineType(),
@@ -1193,7 +1405,7 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t& bufferWidth, co
       {
         // We need to fetch fresh font underline metrics
         FontMetrics fontMetrics;
-        fontClient.GetFontMetrics(glyphInfo->fontId, fontMetrics);
+        mFontClient.GetFontMetrics(glyphInfo->fontId, fontMetrics);
 
         //The currentUnderlinePosition will be used for both Underline and/or Strikethrough
         currentUnderlinePosition = FetchUnderlinePositionFromFontMetrics(fontMetrics);
@@ -1230,14 +1442,36 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t& bufferWidth, co
       }
 
       // Calculate the positions of leftmost and rightmost glyphs in the current line
-      if(position.x < lineExtentLeft)
+      if(removeFrontInset)
+      {
+        if(position.x < lineExtentLeft)
+        {
+          lineExtentLeft = position.x;
+        }
+      }
+      else
       {
-        lineExtentLeft = position.x;
+        const float originPositionLeft = position.x - glyphInfo->xBearing;
+        if(originPositionLeft < lineExtentLeft)
+        {
+          lineExtentLeft = originPositionLeft;
+        }
       }
 
-      if(position.x + glyphInfo->width > lineExtentRight)
+      if(removeBackInset)
+      {
+        if(position.x + glyphInfo->width > lineExtentRight)
+        {
+          lineExtentRight = position.x + glyphInfo->width;
+        }
+      }
+      else
       {
-        lineExtentRight = position.x + glyphInfo->width;
+        const float originPositionRight = position.x - glyphInfo->xBearing + glyphInfo->advance;
+        if(originPositionRight > lineExtentRight)
+        {
+          lineExtentRight = originPositionRight;
+        }
       }
 
       // Retrieves the glyph's color.
@@ -1257,6 +1491,12 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t& bufferWidth, co
         color = (useDefaultColor || (0u == colorIndex)) ? defaultColor : *(colorsBuffer + (colorIndex - 1u));
       }
 
+      if(style == Typesetter::STYLE_NONE && cutoutEnabled)
+      {
+        // Temporarily adjust the transparency to 1.f
+        color.a = 1.f;
+      }
+
       // Premultiply alpha
       color.r *= color.a;
       color.g *= color.a;
@@ -1275,12 +1515,12 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t& bufferWidth, co
 
       if(style != Typesetter::STYLE_UNDERLINE && style != Typesetter::STYLE_STRIKETHROUGH)
       {
-        fontClient.CreateBitmap(glyphInfo->fontId,
-                                glyphInfo->index,
-                                glyphInfo->isItalicRequired,
-                                glyphInfo->isBoldRequired,
-                                glyphData.glyphBitmap,
-                                static_cast<int32_t>(outlineWidth));
+        mFontClient.CreateBitmap(glyphInfo->fontId,
+                                 glyphInfo->index,
+                                 glyphInfo->isItalicRequired,
+                                 glyphInfo->isBoldRequired,
+                                 glyphData.glyphBitmap,
+                                 static_cast<int32_t>(outlineWidth));
       }
 
       // Sets the glyph's bitmap into the bitmap of the whole text.
@@ -1307,8 +1547,12 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t& bufferWidth, co
           glyphData.verticalOffset += glyphData.glyphBitmap.outlineOffsetY;
         }
 
-        // free the glyphBitmap.buffer as it is now copied into glyphData.bitmapBuffer
-        free(glyphData.glyphBitmap.buffer);
+        // free the glyphBitmap.buffer if it is owner of buffer
+        if(glyphData.glyphBitmap.isBufferOwned)
+        {
+          free(glyphData.glyphBitmap.buffer);
+          glyphData.glyphBitmap.isBufferOwned = false;
+        }
         glyphData.glyphBitmap.buffer = NULL;
       }
 
@@ -1354,7 +1598,7 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t& bufferWidth, co
   return glyphData.bitmapBuffer;
 }
 
-Devel::PixelBuffer Typesetter::ApplyUnderlineMarkupImageBuffer(Devel::PixelBuffer topPixelBuffer, const uint32_t& bufferWidth, const uint32_t& bufferHeight, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, const int32_t& horizontalOffset, const int32_t& verticalOffset)
+Devel::PixelBuffer Typesetter::ApplyUnderlineMarkupImageBuffer(Devel::PixelBuffer topPixelBuffer, const uint32_t bufferWidth, const uint32_t bufferHeight, const bool ignoreHorizontalAlignment, const Pixel::Format pixelFormat, const int32_t horizontalOffset, const int32_t verticalOffset)
 {
   // Underline-tags (this is for Markup case)
   // Get the underline runs.
@@ -1386,7 +1630,7 @@ Devel::PixelBuffer Typesetter::ApplyUnderlineMarkupImageBuffer(Devel::PixelBuffe
   return topPixelBuffer;
 }
 
-Devel::PixelBuffer Typesetter::ApplyStrikethroughMarkupImageBuffer(Devel::PixelBuffer topPixelBuffer, const uint32_t& bufferWidth, const uint32_t& bufferHeight, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, const int32_t& horizontalOffset, const int32_t& verticalOffset)
+Devel::PixelBuffer Typesetter::ApplyStrikethroughMarkupImageBuffer(Devel::PixelBuffer topPixelBuffer, const uint32_t bufferWidth, const uint32_t bufferHeight, const bool ignoreHorizontalAlignment, const Pixel::Format pixelFormat, const int32_t horizontalOffset, const int32_t verticalOffset)
 {
   // strikethrough-tags (this is for Markup case)
   // Get the strikethrough runs.
@@ -1418,23 +1662,54 @@ Devel::PixelBuffer Typesetter::ApplyStrikethroughMarkupImageBuffer(Devel::PixelB
   return topPixelBuffer;
 }
 
-Devel::PixelBuffer Typesetter::ApplyMarkupProcessorOnPixelBuffer(Devel::PixelBuffer topPixelBuffer, const uint32_t& bufferWidth, const uint32_t& bufferHeight, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, const int32_t& horizontalOffset, const int32_t& verticalOffset)
+void Typesetter::SetMaskForImageBuffer(Devel::PixelBuffer& __restrict__ topPixelBuffer, Devel::PixelBuffer& __restrict__ bottomPixelBuffer, const uint32_t bufferWidth, const uint32_t bufferHeight, float originAlpha)
 {
-  // Apply the markup-Processor if enabled
-  const bool markupProcessorEnabled = mModel->IsMarkupProcessorEnabled();
-  if(markupProcessorEnabled)
-  {
-    topPixelBuffer = ApplyUnderlineMarkupImageBuffer(topPixelBuffer, bufferWidth, bufferHeight, ignoreHorizontalAlignment, pixelFormat, horizontalOffset, verticalOffset);
+  // Assume that we always combine two RGBA images
+  // Jump with 4bytes for optimize runtime.
+  uint32_t* topBuffer    = reinterpret_cast<uint32_t*>(topPixelBuffer.GetBuffer());
+  uint32_t* bottomBuffer = reinterpret_cast<uint32_t*>(bottomPixelBuffer.GetBuffer());
 
-    topPixelBuffer = ApplyStrikethroughMarkupImageBuffer(topPixelBuffer, bufferWidth, bufferHeight, ignoreHorizontalAlignment, pixelFormat, horizontalOffset, verticalOffset);
+  if(topBuffer == NULL || bottomBuffer == NULL)
+  {
+    // Nothing to do if one of both buffers are empty.
+    return;
   }
 
-  return topPixelBuffer;
+  const uint32_t bufferSizeInt = bufferWidth * bufferHeight;
+
+  for(uint32_t pixelIndex = 0; pixelIndex < bufferSizeInt; ++pixelIndex)
+  {
+    uint32_t topBufferColor = *(topBuffer);
+    uint32_t bottomBufferColor = *(bottomBuffer);
+    uint8_t* __restrict__ topBufferColorBuffer = reinterpret_cast<uint8_t*>(&topBufferColor);
+    uint8_t* __restrict__ bottomBufferColorBuffer = reinterpret_cast<uint8_t*>(&bottomBufferColor);
+
+    // Return the transparency of the text to original.
+    uint8_t originAlphaInt = originAlpha * 255;
+
+    uint8_t topAlpha = topBufferColorBuffer[3];
+    uint8_t bottomAlpha = 255 - topAlpha;
+
+    // Manual blending.
+    bottomBufferColorBuffer[0] = MultiplyAndSummationAndNormalizeColor(topBufferColorBuffer[0], originAlphaInt, bottomBufferColorBuffer[0], bottomAlpha);
+    bottomBufferColorBuffer[1] = MultiplyAndSummationAndNormalizeColor(topBufferColorBuffer[1], originAlphaInt, bottomBufferColorBuffer[1], bottomAlpha);
+    bottomBufferColorBuffer[2] = MultiplyAndSummationAndNormalizeColor(topBufferColorBuffer[2], originAlphaInt, bottomBufferColorBuffer[2], bottomAlpha);
+    bottomBufferColorBuffer[3] = MultiplyAndSummationAndNormalizeColor(topBufferColorBuffer[3], originAlphaInt, bottomBufferColorBuffer[3], bottomAlpha);
+
+    *(bottomBuffer) = bottomBufferColor;
+
+    // Increase each buffer's pointer.
+    ++topBuffer;
+    ++bottomBuffer;
+  }
 }
 
 Typesetter::Typesetter(const ModelInterface* const model)
-: mModel(new ViewModel(model))
+: mModel(new ViewModel(model)),
+  mFontClient()
 {
+  // Default font client set.
+  mFontClient = TextAbstraction::FontClient::Get();
 }
 
 Typesetter::~Typesetter()