From e6c35bc8f671f1c85317d802c5c94abbad196bb0 Mon Sep 17 00:00:00 2001 From: Adeel Kazmi Date: Mon, 28 Sep 2020 16:51:35 +0100 Subject: [PATCH] (Cairo Renderer) Separate RenderTextCairo into several functions to reduce cyclomatic complexity Change-Id: I217eb4d38c7404f85354135822ff1d3aa8825a7e --- .../text/text-abstraction/cairo-renderer.cpp | 737 ++++++++++++--------- 1 file changed, 411 insertions(+), 326 deletions(-) diff --git a/dali/internal/text/text-abstraction/cairo-renderer.cpp b/dali/internal/text/text-abstraction/cairo-renderer.cpp index b6d75e6..eba8cbe 100755 --- a/dali/internal/text/text-abstraction/cairo-renderer.cpp +++ b/dali/internal/text/text-abstraction/cairo-renderer.cpp @@ -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( parameters.width ) ); - const int strideWidth = stride / bpp; - - // Convert from DALi glyphs to Cairo glyphs. - std::vector 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 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& 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( abs( glyphX ) ); + srcWidth -= xSrcIndex; + } + else + { + glyphUintX = static_cast( glyphX ); + } + + if( glyphUintX + srcWidth > static_cast( strideWidth ) ) + { + srcWidth -= ( ( glyphUintX + srcWidth ) - strideWidth ); + } + + if( glyphY - static_cast( srcHeight ) < 0.f ) + { + ySrcIndex = static_cast( abs( glyphY - static_cast( srcHeight ) ) ); + srcHeight -= ySrcIndex; + } + else + { + glyphUintY = static_cast( glyphY - static_cast( 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( alpha ); + + // Write the RGBA modulated with the given default color. + const float* const colorPtr = color.AsFloat(); + *( buffer + dstIndex + 0u ) = static_cast( TO_UCHAR * colorPtr[0u] * srcAlpha ); + *( buffer + dstIndex + 1u ) = static_cast( TO_UCHAR * colorPtr[1u] * srcAlpha ); + *( buffer + dstIndex + 2u ) = static_cast( TO_UCHAR * colorPtr[2u] * srcAlpha ); + *( buffer + dstIndex + 3u ) = static_cast( 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(alpha) * colorPtr[3u]; + + *(buffer + dstIndex + 0u) = static_cast( static_cast( *(data.buffer + srcIndex + 0u) ) * colorPtr[0u] ); + *(buffer + dstIndex + 1u) = static_cast( static_cast( *(data.buffer + srcIndex + 1u) ) * colorPtr[1u] ); + *(buffer + dstIndex + 2u) = static_cast( static_cast( *(data.buffer + srcIndex + 2u) ) * colorPtr[2u] ); + + // Write the alpha. + *(buffer + dstIndex + 3u) = static_cast( 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(alpha) * colorPtr[3u]; + + *(buffer + dstIndex + 0u) = static_cast( static_cast( *(data.buffer + srcIndex + 2u) ) * colorPtr[0u] ); + *(buffer + dstIndex + 1u) = static_cast( static_cast( *(data.buffer + srcIndex + 1u) ) * colorPtr[1u] ); + *(buffer + dstIndex + 2u) = static_cast( static_cast( *(data.buffer + srcIndex + 0u) ) * colorPtr[2u] ); + + // Write the alpha. + *(buffer + dstIndex + 3u) = static_cast( 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( color.b ), + static_cast( color.g ), + static_cast( color.r ), + static_cast( color.a ) ); + + // Create the Cairo's font from the FreeType font. + int options = 0; + options = CAIRO_HINT_STYLE_SLIGHT; + std::unique_ptr 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( 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( parameters.width ) ); + const int strideWidth = stride / bpp; + + // Convert from DALi glyphs to Cairo glyphs. + std::vector 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 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( abs( glyphX ) ); - srcWidth -= xSrcIndex; - } - else - { - glyphUintX = static_cast( glyphX ); - } - - if( glyphUintX + srcWidth > static_cast( strideWidth ) ) - { - srcWidth -= ( ( glyphUintX + srcWidth ) - strideWidth ); - } - - if( glyphY - static_cast( srcHeight ) < 0.f ) - { - ySrcIndex = static_cast( abs( glyphY - static_cast( srcHeight ) ) ); - srcHeight -= ySrcIndex; - } - else - { - glyphUintY = static_cast( glyphY - static_cast( 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( alpha ); - - // Write the RGBA modulated with the given default color. - const float* const colorPtr = color.AsFloat(); - *( buffer + dstIndex + 0u ) = static_cast( TO_UCHAR * colorPtr[0u] * srcAlpha ); - *( buffer + dstIndex + 1u ) = static_cast( TO_UCHAR * colorPtr[1u] * srcAlpha ); - *( buffer + dstIndex + 2u ) = static_cast( TO_UCHAR * colorPtr[2u] * srcAlpha ); - *( buffer + dstIndex + 3u ) = static_cast( 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(alpha) * colorPtr[3u]; - - *(buffer + dstIndex + 0u) = static_cast( static_cast( *(data.buffer + srcIndex + 0u) ) * colorPtr[0u] ); - *(buffer + dstIndex + 1u) = static_cast( static_cast( *(data.buffer + srcIndex + 1u) ) * colorPtr[1u] ); - *(buffer + dstIndex + 2u) = static_cast( static_cast( *(data.buffer + srcIndex + 2u) ) * colorPtr[2u] ); - - // Write the alpha. - *(buffer + dstIndex + 3u) = static_cast( 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(alpha) * colorPtr[3u]; - - *(buffer + dstIndex + 0u) = static_cast( static_cast( *(data.buffer + srcIndex + 2u) ) * colorPtr[0u] ); - *(buffer + dstIndex + 1u) = static_cast( static_cast( *(data.buffer + srcIndex + 1u) ) * colorPtr[1u] ); - *(buffer + dstIndex + 2u) = static_cast( static_cast( *(data.buffer + srcIndex + 0u) ) * colorPtr[2u] ); - - // Write the alpha. - *(buffer + dstIndex + 3u) = static_cast( 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( color.b ), - static_cast( color.g ), - static_cast( color.r ), - static_cast( color.a ) ); - - // Create the Cairo's font from the FreeType font. - int options = 0; - options = CAIRO_HINT_STYLE_SLIGHT; - std::unique_ptr 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( 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); } } -- 2.7.4