(Cairo Renderer) Separate RenderTextCairo into several functions to reduce cyclomatic... 81/244981/1
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Mon, 28 Sep 2020 15:51:35 +0000 (16:51 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Mon, 28 Sep 2020 15:51:35 +0000 (16:51 +0100)
Change-Id: I217eb4d38c7404f85354135822ff1d3aa8825a7e

dali/internal/text/text-abstraction/cairo-renderer.cpp

index b6d75e6..eba8cbe 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 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.
@@ -226,77 +226,26 @@ namespace TextAbstraction
 namespace Internal
 {
 
-Devel::PixelBuffer RenderTextCairo( const TextAbstraction::TextRenderer::Parameters& parameters )
+namespace
 {
-  const unsigned int numberOfGlyphs = parameters.glyphs.Count();
-
-  if( 0u == numberOfGlyphs )
-  {
-    // return a pixel buffer with all pixels set to transparent.
-    return CreateVoidPixelBuffer( parameters );
-  }
-
-  // Choose the pixel format to be used.
-  //
-  // @note Behdad wrote "Upper 8 bits maps to the fourth byte in a little-endian machine like the intels."
-  //       https://lists.cairographics.org/archives/cairo/2006-March/006563.html
-  //
-  //       Here in practice Cairo's ARGB32 is like DALi's RGBA8888.
-  //
-  const bool isDstRgba = TextAbstraction::TextRenderer::Parameters::RGBA8888 == parameters.pixelFormat;
-  const Pixel::Format pixelFormat = isDstRgba ? Pixel::Format::RGBA8888 : Pixel::Format::A8;
-  const cairo_format_t cairoFormat = isDstRgba ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_A8;
-
-  const int bpp = Pixel::GetBytesPerPixel( pixelFormat );
-  if( 0u == bpp )
-  {
-    // return a pixel buffer with all pixels set to transparent.
-    return CreateVoidPixelBuffer( parameters );
-  }
-
-  // This function provides a stride value that will respect all alignment requirements of the
-  // accelerated image-rendering code within cairo.
-  const int stride = cairo_format_stride_for_width( cairoFormat,
-                                                    static_cast<int>( parameters.width ) );
-  const int strideWidth = stride / bpp;
-
-  // Convert from DALi glyphs to Cairo glyphs.
-  std::vector<cairo_glyph_t> cairoGlyphs;
-  cairoGlyphs.resize( numberOfGlyphs );
-  cairo_glyph_t* cairoGlyphsBuffer = &cairoGlyphs[0u];
-
-  const GlyphInfo* const daliGlyphsBuffer = parameters.glyphs.Begin();
-  const Vector2* const positionsBuffer = parameters.positions.Begin();
-  const ColorIndex* const colorIndicesBuffer = ( 0u == parameters.colorIndices.Count() ) ? nullptr : parameters.colorIndices.Begin();
-
-  for( unsigned index = 0u; index < numberOfGlyphs; ++index )
-  {
-    const GlyphInfo& daliGlyph = *( daliGlyphsBuffer + index );
-    const Vector2& position = *( positionsBuffer + index );
-    cairo_glyph_t& cairoGlyph = *( cairoGlyphsBuffer + index );
-
-    cairoGlyph.index = daliGlyph.index;
-    cairoGlyph.x = round( position.x );
-    cairoGlyph.y = round( position.y );
-  }
-
-  // Retrieve the FreeType fonts needed by Cairo from the font-client.
-  Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
-
-  FT_Library ftLibrary;
-  auto error = FT_Init_FreeType( &ftLibrary );
-  if( error )
-  {
-    DALI_LOG_ERROR( "Error initializing FT library\n" );
-
-    // return a pixel buffer with all pixels set to transparent.
-    return CreateVoidPixelBuffer( parameters );
-  }
-
-  // Vector used to store the FreeType font faces, its size and the run of glyphs that use the font.
-  std::vector<GlyphRun> glyphRuns;
-  glyphRuns.reserve( 8u );
 
+/**
+ * @brief Converts the size so that it can be used by Cairo
+ * @param[in] fontClient A reference to the font client
+ * @param[in] ftLibrary A reference to the Freetype library instance
+ * @param[in] numberOfGlyphs The total number of glyphs
+ * @param[in] daliGlyphsBuffer A pointer to the glyphs buffer
+ * @param[in] colorIndicesBuffer A pointer to the color indices buffer
+ * @param[in/out] glyphRuns A vector of glyph-runs
+ */
+bool ConvertSizeForCairo(
+    TextAbstraction::FontClient& fontClient,
+    FT_Library& ftLibrary,
+    const unsigned int numberOfGlyphs,
+    const GlyphInfo* const daliGlyphsBuffer,
+    const ColorIndex* const colorIndicesBuffer,
+    std::vector<GlyphRun>& glyphRuns)
+{
   // The size set in Cairo and FreeType has different units.
   // Before the size is set in Cairo it needs to be converted according the formula
   // 'pixel_size = point_size * resolution / 72' got from the FreeType doc.
@@ -309,6 +258,7 @@ Devel::PixelBuffer RenderTextCairo( const TextAbstraction::TextRenderer::Paramet
 
   const double FROM_26_DOT_6_TO_PIXELS = dVerticalDpi / ( 64.0 * 72.0 );
 
+
   GlyphRun currentGlyphRun;
   currentGlyphRun.fontId = 0u;
   currentGlyphRun.colorIndex = 0u;
@@ -360,8 +310,8 @@ Devel::PixelBuffer RenderTextCairo( const TextAbstraction::TextRenderer::Paramet
             {
               DALI_LOG_ERROR( "Error in FT while creating a new face\n" );
 
-              // return a pixel buffer with all pixels set to transparent.
-              return CreateVoidPixelBuffer( parameters );
+              // Error so just return false
+              return false;
             }
 
             // Set the font's size. It needs to be set in the Freetype font and in the Cairo's context.
@@ -397,6 +347,393 @@ Devel::PixelBuffer RenderTextCairo( const TextAbstraction::TextRenderer::Paramet
     glyphRuns.push_back( currentGlyphRun );
   }
 
+  return true; // Successfully converted
+}
+
+/**
+ * @brief Copies the image to the cairo surface
+ * @param[in] parameters The text renderer parameters
+ * @param[in] pixelFormat The pixel format
+ * @param[in] data The glyph buffer data
+ * @param[in] buffer The output buffer
+ * @param[in] rgbaCase 0 -> image and cairo buffer are A8
+ *                     1 -> image is A8, cairo buffer is ARGB
+ *                     2 -> image is RGBA and cairo buffer is ARGB
+ *                     3 -> image is BGRA and cairo buffer is ARGB
+ * @param[in] glyphX The x-position of the glyph
+ * @param[in] glyphY The y-position of the glyph
+ * @param[in] strideWidth The stride width
+ * @param[in] color The color of the text
+ * @param[in] doBlendWithTextColor Whether to blend with the text color or not)
+ */
+void CopyImageToSurface(
+    const TextAbstraction::TextRenderer::Parameters& parameters,
+    const Pixel::Format pixelFormat,
+    TextAbstraction::FontClient::GlyphBufferData& data,
+    unsigned char * buffer,
+    const int rgbaCase,
+    const double glyphX,
+    const double glyphY,
+    const int strideWidth,
+    const Vector4& color,
+    const bool doBlendWithTextColor)
+{
+  // Select the cropped source image area to copy into the surface buffer
+  unsigned int glyphUintX = 0u;
+  unsigned int glyphUintY = 0u;
+  unsigned int srcWidth = data.width;
+  unsigned int srcHeight = data.height;
+  unsigned int xSrcIndex = 0u;
+  unsigned int ySrcIndex = 0u;
+  if( glyphX < 0.f )
+  {
+    xSrcIndex = static_cast<unsigned int>( abs( glyphX ) );
+    srcWidth -= xSrcIndex;
+  }
+  else
+  {
+    glyphUintX = static_cast<unsigned int>( glyphX );
+  }
+
+  if( glyphUintX + srcWidth > static_cast<unsigned int>( strideWidth ) )
+  {
+    srcWidth -= ( ( glyphUintX + srcWidth ) - strideWidth );
+  }
+
+  if( glyphY - static_cast<float>( srcHeight ) < 0.f )
+  {
+    ySrcIndex = static_cast<unsigned int>( abs( glyphY - static_cast<float>( srcHeight ) ) );
+    srcHeight -= ySrcIndex;
+  }
+  else
+  {
+    glyphUintY = static_cast<unsigned int>( glyphY - static_cast<float>( srcHeight ) );
+  }
+
+  if( glyphUintY + srcHeight > parameters.height )
+  {
+    srcHeight -= ( ( glyphUintY + srcHeight ) - parameters.height );
+  }
+
+  // Calculate the source and destination indices.
+  const unsigned int srcPixelSize = Pixel::GetBytesPerPixel( data.format );
+  const unsigned int dstPixelSize = Pixel::GetBytesPerPixel( pixelFormat );
+
+  unsigned int srcIndex = srcPixelSize * ( ySrcIndex * srcWidth + xSrcIndex );
+  unsigned int dstIndex = dstPixelSize * ( glyphUintY * strideWidth + glyphUintX );
+
+  const unsigned int srcWidthOffset = srcPixelSize * ( data.width - srcWidth );
+  const unsigned int dstWidthOffset = dstPixelSize * ( strideWidth - srcWidth );
+
+  // Copy the image to the surface
+  for( unsigned int j = 0; j < srcHeight; ++j )
+  {
+    for( unsigned int i = 0; i < srcWidth; ++i )
+    {
+      switch( rgbaCase )
+      {
+        case 0: // Both the image's buffer and cairo's buffer are A8
+        {
+          const unsigned char alpha = *( data.buffer + srcIndex );
+          if( alpha != 0u )
+          {
+            // @todo needs a proper blending!
+            *( buffer + dstIndex ) = alpha;
+          }
+          break;
+        }
+        case 1: // The image's buffer is A8 and the cairo's buffer is ARGB
+        {
+          const unsigned char alpha = *( data.buffer + srcIndex );
+          if( alpha != 0u )
+          {
+            // @todo needs a proper blending!
+            const float srcAlpha = TO_FLOAT * static_cast<float>( alpha );
+
+            // Write the RGBA modulated with the given default color.
+            const float* const colorPtr = color.AsFloat();
+            *( buffer + dstIndex + 0u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[0u] * srcAlpha );
+            *( buffer + dstIndex + 1u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[1u] * srcAlpha );
+            *( buffer + dstIndex + 2u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[2u] * srcAlpha );
+            *( buffer + dstIndex + 3u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[3u] * srcAlpha );
+          }
+          break;
+        }
+        case 2: // The image's buffer is RGBA and the cairo's buffer is ARGB
+        {
+          const unsigned char alpha = *(data.buffer + srcIndex + 3u);
+          if( alpha != 0u )
+          {
+            if( doBlendWithTextColor )
+            {
+              const float* const colorPtr = color.AsFloat();
+
+              const float srcAlpha = TO_FLOAT * static_cast<float>(alpha) * colorPtr[3u];
+
+              *(buffer + dstIndex + 0u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 0u) ) * colorPtr[0u] );
+              *(buffer + dstIndex + 1u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 1u) ) * colorPtr[1u] );
+              *(buffer + dstIndex + 2u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 2u) ) * colorPtr[2u] );
+
+              // Write the alpha.
+              *(buffer + dstIndex + 3u) = static_cast<unsigned char>( TO_UCHAR * srcAlpha );
+            }
+            else
+            {
+              // @todo needs a proper blending!
+              // Write the RGB
+              *(buffer + dstIndex + 0u) = *(data.buffer + srcIndex + 0u);
+              *(buffer + dstIndex + 1u) = *(data.buffer + srcIndex + 1u);
+              *(buffer + dstIndex + 2u) = *(data.buffer + srcIndex + 2u);
+
+              // Write the alpha.
+              *(buffer + dstIndex + 3u) = *(data.buffer + srcIndex + 3u);
+            }
+          }
+          break;
+        }
+        case 3: // The image's buffer is BGRA and the cairo's buffer is ARGB
+        {
+          const unsigned char alpha = *(data.buffer + srcIndex + 3u);
+          if( alpha != 0u )
+          {
+            if( doBlendWithTextColor )
+            {
+              const float* const colorPtr = color.AsFloat();
+
+              const float srcAlpha = TO_FLOAT * static_cast<float>(alpha) * colorPtr[3u];
+
+              *(buffer + dstIndex + 0u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 2u) ) * colorPtr[0u] );
+              *(buffer + dstIndex + 1u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 1u) ) * colorPtr[1u] );
+              *(buffer + dstIndex + 2u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 0u) ) * colorPtr[2u] );
+
+              // Write the alpha.
+              *(buffer + dstIndex + 3u) = static_cast<unsigned char>( TO_UCHAR * srcAlpha );
+            }
+            else
+            {
+              // @todo needs a proper blending!
+              // Write the RGBA
+              *(buffer + dstIndex + 0u) = *(data.buffer + srcIndex + 2u);
+              *(buffer + dstIndex + 1u) = *(data.buffer + srcIndex + 1u);
+              *(buffer + dstIndex + 2u) = *(data.buffer + srcIndex + 0u);
+              *(buffer + dstIndex + 3u) = *(data.buffer + srcIndex + 3u);
+            }
+          }
+          break;
+        }
+        default:
+        {
+          DALI_ASSERT_ALWAYS( !"Cairo Renderer: The accepted values for this switch case are: 0, 1, 2!" );
+        }
+      } // switch
+      srcIndex += srcPixelSize;
+      dstIndex += dstPixelSize;
+    } // for width
+    srcIndex += srcWidthOffset;
+    dstIndex += dstWidthOffset;
+  } // for height
+}
+
+/**
+ * @brief Renders the glyph
+ * @param[in] parameters The text renderer parameters
+ * @param[in] run The current glyph-run
+ * @param[in] cairoGlyphsBuffer The cairo glyphs buffer
+ * @param[in/out] cr The cairo surface
+ * @param[in/out] circularCr The cairo surface if using circular text
+ * @param[in] isCircularText Whether we're using circular text or not
+ * @param[in/out] circularTextParameters The circular text parameters
+ */
+void RenderGlyphs(
+    const TextAbstraction::TextRenderer::Parameters& parameters,
+    const GlyphRun& run,
+    cairo_glyph_t*& cairoGlyphsBuffer,
+    cairo_t*& cr,
+    cairo_t*& circularCr,
+    const bool isCircularText,
+    CircularTextParameters& circularTextParameters)
+{
+  // Sets the color. The color is actually BGRA
+  const Vector4& color = parameters.colors[run.colorIndex];
+
+  cairo_set_source_rgba( cr,
+                         static_cast<double>( color.b ),
+                         static_cast<double>( color.g ),
+                         static_cast<double>( color.r ),
+                         static_cast<double>( color.a ) );
+
+  // Create the Cairo's font from the FreeType font.
+  int options = 0;
+  options = CAIRO_HINT_STYLE_SLIGHT;
+  std::unique_ptr<cairo_font_face_t, void(*)(cairo_font_face_t*)> fontFacePtr( cairo_ft_font_face_create_for_ft_face( run.fontFace, options ), cairo_font_face_destroy );
+  cairo_font_face_t* fontFace = fontFacePtr.get();
+
+  static const cairo_user_data_key_t key = { 0 };
+  cairo_status_t status = cairo_font_face_set_user_data( fontFace, &key, run.fontFace, reinterpret_cast<cairo_destroy_func_t>( FT_Done_Face ) );
+  if( status )
+  {
+    cairo_font_face_destroy( fontFace );
+  }
+
+  unsigned int ftSynthesizeFlag = 0u;
+  if( run.isBoldRequired && !( run.fontFace->style_flags & FT_STYLE_FLAG_BOLD ) )
+  {
+    ftSynthesizeFlag |= CAIRO_FT_SYNTHESIZE_BOLD;
+  }
+
+  cairo_ft_font_face_set_synthesize( fontFace, ftSynthesizeFlag );
+
+  cairo_font_face_reference( fontFace );
+
+  const bool synthesizeItalic = ( run.isItalicRequired && !( run.fontFace->style_flags & FT_STYLE_FLAG_ITALIC ) );
+
+  if( CAIRO_STATUS_SUCCESS != cairo_font_face_status( fontFace ) )
+  {
+    DALI_LOG_ERROR( "Failed to load the Freetype Font\n" );
+  }
+
+  // Sets the font.
+  cairo_set_font_face( isCircularText ? circularCr : cr, fontFace );
+
+  // Sets the size
+  cairo_set_font_size( isCircularText ? circularCr : cr, run.fontSize );
+
+  // Render the glyphs.
+  if( isCircularText )
+  {
+    circularTextParameters.synthesizeItalic = synthesizeItalic;
+
+    const unsigned int glyphJump = circularTextParameters.synthesizeItalic ? 1u : run.numberOfGlyphs;
+
+    for( unsigned int index = 0u; index < run.numberOfGlyphs; index += glyphJump )
+    {
+      // Clears the current path where the text is laid out on a horizontal straight line.
+      cairo_new_path( circularCr );
+      cairo_move_to( circularCr, 0.0, 0.0 );
+
+      cairo_glyph_path( circularCr, ( cairoGlyphsBuffer + run.glyphIndex + index ), glyphJump );
+
+      WrapToCircularPath( cr, circularCr, circularTextParameters );
+      cairo_fill( cr );
+    }
+  }
+  else
+  {
+    if( synthesizeItalic )
+    {
+      // Apply a shear transform to synthesize the italics.
+      // For a reason Cairo may trim some glyphs if the CAIRO_FT_SYNTHESIZE_OBLIQUE flag is used.
+
+      // This is to calculate an offset used to compensate the 'translation' done by the shear transform
+      // as it's done for the whole render buffer.
+      double maxY = 0.0;
+      for( unsigned int index = run.glyphIndex, endIndex = run.glyphIndex + run.numberOfGlyphs; index < endIndex; ++index )
+      {
+        maxY = std::max( maxY, (*( cairoGlyphsBuffer + index )).y );
+      }
+
+      cairo_matrix_t matrix;
+      cairo_matrix_init( &matrix,
+                                                                              1.0, 0.0,
+                               -TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE, 1.0,
+                         maxY * TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE, 0.0 );
+
+      cairo_transform( cr, &matrix );
+    }
+
+    cairo_show_glyphs( cr, ( cairoGlyphsBuffer + run.glyphIndex ), run.numberOfGlyphs );
+
+    if( synthesizeItalic )
+    {
+      // Restore the transform matrix to the identity.
+      cairo_matrix_t matrix;
+      cairo_matrix_init_identity( &matrix );
+      cairo_set_matrix( cr, &matrix );
+    }
+
+    cairo_fill( cr );
+  }
+}
+
+} // unnamed namespace
+
+Devel::PixelBuffer RenderTextCairo( const TextAbstraction::TextRenderer::Parameters& parameters )
+{
+  const unsigned int numberOfGlyphs = parameters.glyphs.Count();
+
+  if( 0u == numberOfGlyphs )
+  {
+    // return a pixel buffer with all pixels set to transparent.
+    return CreateVoidPixelBuffer( parameters );
+  }
+
+  // Choose the pixel format to be used.
+  //
+  // @note Behdad wrote "Upper 8 bits maps to the fourth byte in a little-endian machine like the intels."
+  //       https://lists.cairographics.org/archives/cairo/2006-March/006563.html
+  //
+  //       Here in practice Cairo's ARGB32 is like DALi's RGBA8888.
+  //
+  const bool isDstRgba = TextAbstraction::TextRenderer::Parameters::RGBA8888 == parameters.pixelFormat;
+  const Pixel::Format pixelFormat = isDstRgba ? Pixel::Format::RGBA8888 : Pixel::Format::A8;
+  const cairo_format_t cairoFormat = isDstRgba ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_A8;
+
+  const int bpp = Pixel::GetBytesPerPixel( pixelFormat );
+  if( 0u == bpp )
+  {
+    // return a pixel buffer with all pixels set to transparent.
+    return CreateVoidPixelBuffer( parameters );
+  }
+
+  // This function provides a stride value that will respect all alignment requirements of the
+  // accelerated image-rendering code within cairo.
+  const int stride = cairo_format_stride_for_width( cairoFormat,
+                                                    static_cast<int>( parameters.width ) );
+  const int strideWidth = stride / bpp;
+
+  // Convert from DALi glyphs to Cairo glyphs.
+  std::vector<cairo_glyph_t> cairoGlyphs;
+  cairoGlyphs.resize( numberOfGlyphs );
+  cairo_glyph_t* cairoGlyphsBuffer = &cairoGlyphs[0u];
+
+  const GlyphInfo* const daliGlyphsBuffer = parameters.glyphs.Begin();
+  const Vector2* const positionsBuffer = parameters.positions.Begin();
+  const ColorIndex* const colorIndicesBuffer = ( 0u == parameters.colorIndices.Count() ) ? nullptr : parameters.colorIndices.Begin();
+
+  for( unsigned index = 0u; index < numberOfGlyphs; ++index )
+  {
+    const GlyphInfo& daliGlyph = *( daliGlyphsBuffer + index );
+    const Vector2& position = *( positionsBuffer + index );
+    cairo_glyph_t& cairoGlyph = *( cairoGlyphsBuffer + index );
+
+    cairoGlyph.index = daliGlyph.index;
+    cairoGlyph.x = round( position.x );
+    cairoGlyph.y = round( position.y );
+  }
+
+  // Retrieve the FreeType fonts needed by Cairo from the font-client.
+  Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
+
+  FT_Library ftLibrary;
+  auto error = FT_Init_FreeType( &ftLibrary );
+  if( error )
+  {
+    DALI_LOG_ERROR( "Error initializing FT library\n" );
+
+    // return a pixel buffer with all pixels set to transparent.
+    return CreateVoidPixelBuffer( parameters );
+  }
+
+  // Vector used to store the FreeType font faces, its size and the run of glyphs that use the font.
+  std::vector<GlyphRun> glyphRuns;
+  glyphRuns.reserve( 8u );
+
+  if( ! ConvertSizeForCairo(fontClient, ftLibrary, numberOfGlyphs, daliGlyphsBuffer, colorIndicesBuffer, glyphRuns) )
+  {
+    // return a pixel buffer with all pixels set to transparent.
+    return CreateVoidPixelBuffer( parameters );
+  }
+
   // Creates the pixel buffer and retrieves the buffer pointer used to create the Cairo's surface.
   Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New( strideWidth, parameters.height, pixelFormat );
 
@@ -626,265 +963,13 @@ Devel::PixelBuffer RenderTextCairo( const TextAbstraction::TextRenderer::Paramet
             continue;
           }
 
-          // Select the cropped source image area to copy into the surface buffer
-          unsigned int glyphUintX = 0u;
-          unsigned int glyphUintY = 0u;
-          unsigned int srcWidth = data.width;
-          unsigned int srcHeight = data.height;
-          unsigned int xSrcIndex = 0u;
-          unsigned int ySrcIndex = 0u;
-          if( glyphX < 0.f )
-          {
-            xSrcIndex = static_cast<unsigned int>( abs( glyphX ) );
-            srcWidth -= xSrcIndex;
-          }
-          else
-          {
-            glyphUintX = static_cast<unsigned int>( glyphX );
-          }
-
-          if( glyphUintX + srcWidth > static_cast<unsigned int>( strideWidth ) )
-          {
-            srcWidth -= ( ( glyphUintX + srcWidth ) - strideWidth );
-          }
-
-          if( glyphY - static_cast<float>( srcHeight ) < 0.f )
-          {
-            ySrcIndex = static_cast<unsigned int>( abs( glyphY - static_cast<float>( srcHeight ) ) );
-            srcHeight -= ySrcIndex;
-          }
-          else
-          {
-            glyphUintY = static_cast<unsigned int>( glyphY - static_cast<float>( srcHeight ) );
-          }
-
-          if( glyphUintY + srcHeight > parameters.height )
-          {
-            srcHeight -= ( ( glyphUintY + srcHeight ) - parameters.height );
-          }
-
-          // Calculate the source and destination indices.
-          const unsigned int srcPixelSize = Pixel::GetBytesPerPixel( data.format );
-          const unsigned int dstPixelSize = Pixel::GetBytesPerPixel( pixelFormat );
-
-          unsigned int srcIndex = srcPixelSize * ( ySrcIndex * srcWidth + xSrcIndex );
-          unsigned int dstIndex = dstPixelSize * ( glyphUintY * strideWidth + glyphUintX );
-
-          const unsigned int srcWidthOffset = srcPixelSize * ( data.width - srcWidth );
-          const unsigned int dstWidthOffset = dstPixelSize * ( strideWidth - srcWidth );
-
-          // Copy the image to the surface
-          for( unsigned int j = 0; j < srcHeight; ++j )
-          {
-            for( unsigned int i = 0; i < srcWidth; ++i )
-            {
-              switch( rgbaCase )
-              {
-                case 0: // Both the image's buffer and cairo's buffer are A8
-                {
-                  const unsigned char alpha = *( data.buffer + srcIndex );
-                  if( alpha != 0u )
-                  {
-                    // @todo needs a proper blending!
-                    *( buffer + dstIndex ) = alpha;
-                  }
-                  break;
-                }
-                case 1: // The image's buffer is A8 and the cairo's buffer is ARGB
-                {
-                  const unsigned char alpha = *( data.buffer + srcIndex );
-                  if( alpha != 0u )
-                  {
-                    // @todo needs a proper blending!
-                    const float srcAlpha = TO_FLOAT * static_cast<float>( alpha );
-
-                    // Write the RGBA modulated with the given default color.
-                    const float* const colorPtr = color.AsFloat();
-                    *( buffer + dstIndex + 0u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[0u] * srcAlpha );
-                    *( buffer + dstIndex + 1u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[1u] * srcAlpha );
-                    *( buffer + dstIndex + 2u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[2u] * srcAlpha );
-                    *( buffer + dstIndex + 3u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[3u] * srcAlpha );
-                  }
-                  break;
-                }
-                case 2: // The image's buffer is RGBA and the cairo's buffer is ARGB
-                {
-                  const unsigned char alpha = *(data.buffer + srcIndex + 3u);
-                  if( alpha != 0u )
-                  {
-                    if( doBlendWithTextColor )
-                    {
-                      const float* const colorPtr = color.AsFloat();
-
-                      const float srcAlpha = TO_FLOAT * static_cast<float>(alpha) * colorPtr[3u];
-
-                      *(buffer + dstIndex + 0u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 0u) ) * colorPtr[0u] );
-                      *(buffer + dstIndex + 1u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 1u) ) * colorPtr[1u] );
-                      *(buffer + dstIndex + 2u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 2u) ) * colorPtr[2u] );
-
-                      // Write the alpha.
-                      *(buffer + dstIndex + 3u) = static_cast<unsigned char>( TO_UCHAR * srcAlpha );
-                    }
-                    else
-                    {
-                      // @todo needs a proper blending!
-                      // Write the RGB
-                      *(buffer + dstIndex + 0u) = *(data.buffer + srcIndex + 0u);
-                      *(buffer + dstIndex + 1u) = *(data.buffer + srcIndex + 1u);
-                      *(buffer + dstIndex + 2u) = *(data.buffer + srcIndex + 2u);
-
-                      // Write the alpha.
-                      *(buffer + dstIndex + 3u) = *(data.buffer + srcIndex + 3u);
-                    }
-                  }
-                  break;
-                }
-                case 3: // The image's buffer is BGRA and the cairo's buffer is ARGB
-                {
-                  const unsigned char alpha = *(data.buffer + srcIndex + 3u);
-                  if( alpha != 0u )
-                  {
-                    if( doBlendWithTextColor )
-                    {
-                      const float* const colorPtr = color.AsFloat();
-
-                      const float srcAlpha = TO_FLOAT * static_cast<float>(alpha) * colorPtr[3u];
-
-                      *(buffer + dstIndex + 0u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 2u) ) * colorPtr[0u] );
-                      *(buffer + dstIndex + 1u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 1u) ) * colorPtr[1u] );
-                      *(buffer + dstIndex + 2u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 0u) ) * colorPtr[2u] );
-
-                      // Write the alpha.
-                      *(buffer + dstIndex + 3u) = static_cast<unsigned char>( TO_UCHAR * srcAlpha );
-                    }
-                    else
-                    {
-                      // @todo needs a proper blending!
-                      // Write the RGBA
-                      *(buffer + dstIndex + 0u) = *(data.buffer + srcIndex + 2u);
-                      *(buffer + dstIndex + 1u) = *(data.buffer + srcIndex + 1u);
-                      *(buffer + dstIndex + 2u) = *(data.buffer + srcIndex + 0u);
-                      *(buffer + dstIndex + 3u) = *(data.buffer + srcIndex + 3u);
-                    }
-                  }
-                  break;
-                }
-                default:
-                {
-                  DALI_ASSERT_ALWAYS( !"Cairo Renderer: The accepted values for this switch case are: 0, 1, 2!" );
-                }
-              } // switch
-              srcIndex += srcPixelSize;
-              dstIndex += dstPixelSize;
-            } // for width
-            srcIndex += srcWidthOffset;
-            dstIndex += dstWidthOffset;
-          } // for height
+          CopyImageToSurface(parameters, pixelFormat, data, buffer, rgbaCase, glyphX, glyphY, strideWidth, color, doBlendWithTextColor);
         }
       }
     }
     else
     {
-      // Sets the color. The color is actually BGRA
-      const Vector4& color = parameters.colors[run.colorIndex];
-
-      cairo_set_source_rgba( cr,
-                             static_cast<double>( color.b ),
-                             static_cast<double>( color.g ),
-                             static_cast<double>( color.r ),
-                             static_cast<double>( color.a ) );
-
-      // Create the Cairo's font from the FreeType font.
-      int options = 0;
-      options = CAIRO_HINT_STYLE_SLIGHT;
-      std::unique_ptr<cairo_font_face_t, void(*)(cairo_font_face_t*)> fontFacePtr( cairo_ft_font_face_create_for_ft_face( run.fontFace, options ), cairo_font_face_destroy );
-      cairo_font_face_t* fontFace = fontFacePtr.get();
-
-      static const cairo_user_data_key_t key = { 0 };
-      cairo_status_t status = cairo_font_face_set_user_data( fontFace, &key, run.fontFace, reinterpret_cast<cairo_destroy_func_t>( FT_Done_Face ) );
-      if( status )
-      {
-        cairo_font_face_destroy( fontFace );
-      }
-
-      unsigned int ftSynthesizeFlag = 0u;
-      if( run.isBoldRequired && !( run.fontFace->style_flags & FT_STYLE_FLAG_BOLD ) )
-      {
-        ftSynthesizeFlag |= CAIRO_FT_SYNTHESIZE_BOLD;
-      }
-
-      cairo_ft_font_face_set_synthesize( fontFace, ftSynthesizeFlag );
-
-      cairo_font_face_reference( fontFace );
-
-      const bool synthesizeItalic = ( run.isItalicRequired && !( run.fontFace->style_flags & FT_STYLE_FLAG_ITALIC ) );
-
-      if( CAIRO_STATUS_SUCCESS != cairo_font_face_status( fontFace ) )
-      {
-        DALI_LOG_ERROR( "Failed to load the Freetype Font\n" );
-      }
-
-      // Sets the font.
-      cairo_set_font_face( isCircularText ? circularCr : cr, fontFace );
-
-      // Sets the size
-      cairo_set_font_size( isCircularText ? circularCr : cr, run.fontSize );
-
-      // Render the glyphs.
-      if( isCircularText )
-      {
-        circularTextParameters.synthesizeItalic = synthesizeItalic;
-
-        const unsigned int glyphJump = circularTextParameters.synthesizeItalic ? 1u : run.numberOfGlyphs;
-
-        for( unsigned int index = 0u; index < run.numberOfGlyphs; index += glyphJump )
-        {
-          // Clears the current path where the text is laid out on a horizontal straight line.
-          cairo_new_path( circularCr );
-          cairo_move_to( circularCr, 0.0, 0.0 );
-
-          cairo_glyph_path( circularCr, ( cairoGlyphsBuffer + run.glyphIndex + index ), glyphJump );
-
-          WrapToCircularPath( cr, circularCr, circularTextParameters );
-          cairo_fill( cr );
-        }
-      }
-      else
-      {
-        if( synthesizeItalic )
-        {
-          // Apply a shear transform to synthesize the italics.
-          // For a reason Cairo may trim some glyphs if the CAIRO_FT_SYNTHESIZE_OBLIQUE flag is used.
-
-          // This is to calculate an offset used to compensate the 'translation' done by the shear transform
-          // as it's done for the whole render buffer.
-          double maxY = 0.0;
-          for( unsigned int index = run.glyphIndex, endIndex = run.glyphIndex + run.numberOfGlyphs; index < endIndex; ++index )
-          {
-            maxY = std::max( maxY, (*( cairoGlyphsBuffer + index )).y );
-          }
-
-          cairo_matrix_t matrix;
-          cairo_matrix_init( &matrix,
-                                                                                  1.0, 0.0,
-                                   -TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE, 1.0,
-                             maxY * TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE, 0.0 );
-
-          cairo_transform( cr, &matrix );
-        }
-
-        cairo_show_glyphs( cr, ( cairoGlyphsBuffer + run.glyphIndex ), run.numberOfGlyphs );
-
-        if( synthesizeItalic )
-        {
-          // Restore the transform matrix to the identity.
-          cairo_matrix_t matrix;
-          cairo_matrix_init_identity( &matrix );
-          cairo_set_matrix( cr, &matrix );
-        }
-
-        cairo_fill( cr );
-      }
+      RenderGlyphs(parameters, run, cairoGlyphsBuffer, cr, circularCr, isCircularText, circularTextParameters);
     }
   }