/*
- * 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.
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.
const double FROM_26_DOT_6_TO_PIXELS = dVerticalDpi / ( 64.0 * 72.0 );
+
GlyphRun currentGlyphRun;
currentGlyphRun.fontId = 0u;
currentGlyphRun.colorIndex = 0u;
{
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.
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 );
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);
}
}