+/// Helper method to fetch the underline metrics for the specified font glyph
+void FetchFontUnderlineMetrics(
+ TextAbstraction::FontClient& fontClient,
+ const GlyphInfo* const glyphInfo,
+ float& currentUnderlinePosition,
+ const float underlineHeight,
+ float& currentUnderlineThickness,
+ float& maxUnderlineThickness,
+ FontId& lastUnderlinedFontId)
+{
+ FontMetrics fontMetrics;
+ fontClient.GetFontMetrics( glyphInfo->fontId, fontMetrics );
+ currentUnderlinePosition = ceil( fabsf( fontMetrics.underlinePosition ) );
+ const float descender = ceil( fabsf( fontMetrics.descender ) );
+
+ if( fabsf( underlineHeight ) < Math::MACHINE_EPSILON_1000 )
+ {
+ currentUnderlineThickness = fontMetrics.underlineThickness;
+
+ // Ensure underline will be at least a pixel high
+ if ( currentUnderlineThickness < 1.0f )
+ {
+ currentUnderlineThickness = 1.0f;
+ }
+ else
+ {
+ currentUnderlineThickness = ceil( currentUnderlineThickness );
+ }
+ }
+
+ // The underline thickness should be the max underline thickness of all glyphs of the line.
+ if ( currentUnderlineThickness > maxUnderlineThickness )
+ {
+ maxUnderlineThickness = currentUnderlineThickness;
+ }
+
+ // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font
+ if( currentUnderlinePosition > descender )
+ {
+ currentUnderlinePosition = descender;
+ }
+
+ if( fabsf( currentUnderlinePosition ) < Math::MACHINE_EPSILON_1000 )
+ {
+ // Move offset down by one ( EFL behavior )
+ currentUnderlinePosition = 1.0f;
+ }
+
+ lastUnderlinedFontId = glyphInfo->fontId;
+}
+
+/// Draws the specified color to the pixel buffer
+void WriteColorToPixelBuffer(
+ GlyphData& glyphData,
+ uint32_t* bitmapBuffer,
+ const Vector4& color,
+ const unsigned int x,
+ const unsigned int y)
+{
+ // Always RGBA image for text with styles
+ uint32_t pixel = *( bitmapBuffer + y * glyphData.width + x );
+ uint8_t* pixelBuffer = reinterpret_cast<uint8_t*>( &pixel );
+
+ // Write the color to the pixel buffer
+ uint8_t colorAlpha = static_cast< uint8_t >( color.a * 255.f );
+ *( pixelBuffer + 3u ) = colorAlpha;
+ *( pixelBuffer + 2u ) = static_cast< uint8_t >( color.b * colorAlpha );
+ *( pixelBuffer + 1u ) = static_cast< uint8_t >( color.g * colorAlpha );
+ *( pixelBuffer ) = static_cast< uint8_t >( color.r * colorAlpha );
+
+ *( bitmapBuffer + y * glyphData.width + x ) = pixel;
+}
+
+/// Draws the specified underline color to the buffer
+void DrawUnderline(
+ const Vector4& underlineColor,
+ const unsigned int bufferWidth,
+ const unsigned int bufferHeight,
+ GlyphData& glyphData,
+ const float baseline,
+ const float currentUnderlinePosition,
+ const float maxUnderlineThickness,
+ const float lineExtentLeft,
+ const float lineExtentRight)
+{
+ int underlineYOffset = glyphData.verticalOffset + baseline + currentUnderlinePosition;
+ uint32_t* bitmapBuffer = reinterpret_cast< uint32_t* >( glyphData.bitmapBuffer.GetBuffer() );
+
+ for( unsigned int y = underlineYOffset; y < underlineYOffset + maxUnderlineThickness; y++ )
+ {
+ if( y > bufferHeight - 1 )
+ {
+ // Do not write out of bounds.
+ break;
+ }
+
+ for( unsigned int x = glyphData.horizontalOffset + lineExtentLeft; x <= glyphData.horizontalOffset + lineExtentRight; x++ )
+ {
+ if( x > bufferWidth - 1 )
+ {
+ // Do not write out of bounds.
+ break;
+ }
+
+ WriteColorToPixelBuffer(glyphData, bitmapBuffer, underlineColor, x, y);
+ }
+ }
+}
+
+/// Draws the background color to the buffer
+void DrawBackgroundColor(
+ Vector4 backgroundColor,
+ const unsigned int bufferWidth,
+ const unsigned int bufferHeight,
+ GlyphData& glyphData,
+ const float baseline,
+ const LineRun& line,
+ const float lineExtentLeft,
+ const float lineExtentRight)
+{
+ uint32_t* bitmapBuffer = reinterpret_cast< uint32_t* >( glyphData.bitmapBuffer.GetBuffer() );
+
+ for( int y = glyphData.verticalOffset + baseline - line.ascender; y < glyphData.verticalOffset + baseline - line.descender; y++ )
+ {
+ if( ( y < 0 ) || ( y > static_cast<int>(bufferHeight - 1) ) )
+ {
+ // Do not write out of bounds.
+ continue;
+ }
+
+ for( int x = glyphData.horizontalOffset + lineExtentLeft; x <= glyphData.horizontalOffset + lineExtentRight; x++ )
+ {
+ if( ( x < 0 ) || ( x > static_cast<int>(bufferWidth - 1) ) )
+ {
+ // Do not write out of bounds.
+ continue;
+ }
+
+ WriteColorToPixelBuffer(glyphData, bitmapBuffer, backgroundColor, x, y);
+ }
+ }
+}
+