// Pointer to the color glyph if there is one.
const uint32_t* const colorGlyphBuffer = isColorGlyph ? reinterpret_cast<uint32_t*>( data.glyphBitmap.buffer ) : NULL;
- // Pack the given color into a 32bit buffer. The alpha channel will be updated later for each pixel.
- // The format is RGBA8888.
- uint32_t packedColor = 0u;
- uint8_t* packedColorBuffer = reinterpret_cast<uint8_t*>( &packedColor );
- *( packedColorBuffer + 2 ) = static_cast<uint8_t>( color->b * 255.f );
- *( packedColorBuffer + 1 ) = static_cast<uint8_t>( color->g * 255.f );
- *packedColorBuffer = static_cast<uint8_t>( color->r * 255.f );
-
// Initial vertical offset.
const int yOffset = data.verticalOffset + position->y;
uint32_t packedColorGlyph = *( colorGlyphBuffer + glyphBufferOffset + index );
uint8_t* packedColorGlyphBuffer = reinterpret_cast<uint8_t*>( &packedColorGlyph );
- if( Typesetter::STYLE_SHADOW == style )
- {
- // The shadow of color glyph needs to have the shadow color.
- *( packedColorGlyphBuffer + 2 ) = static_cast<uint8_t>( color->b * 255.f );
- *( packedColorGlyphBuffer + 1 ) = static_cast<uint8_t>( color->g * 255.f );
- *packedColorGlyphBuffer = static_cast<uint8_t>( color->r * 255.f );
- }
- else
- {
- std::swap( *packedColorGlyphBuffer, *( packedColorGlyphBuffer + 2u ) ); // Swap B and R.
- }
-
// Update the alpha channel.
if( Typesetter::STYLE_MASK == style || Typesetter::STYLE_OUTLINE == style ) // Outline not shown for color glyph
{
// Create an alpha mask for color glyph.
*( packedColorGlyphBuffer + 3u ) = 0u;
+ *( packedColorGlyphBuffer + 2u ) = 0u;
+ *( packedColorGlyphBuffer + 1u ) = 0u;
+ *packedColorGlyphBuffer = 0u;
}
else
{
- *( packedColorGlyphBuffer + 3u ) = static_cast<uint8_t>( color->a * static_cast<float>( *( packedColorGlyphBuffer + 3u ) ) );
+ uint8_t colorAlpha = static_cast<uint8_t>( color->a * static_cast<float>( *( packedColorGlyphBuffer + 3u ) ) );
+ *( packedColorGlyphBuffer + 3u ) = colorAlpha;
+
+ if( Typesetter::STYLE_SHADOW == style )
+ {
+ // The shadow of color glyph needs to have the shadow color.
+ *( packedColorGlyphBuffer + 2u ) = static_cast<uint8_t>( color->b * colorAlpha );
+ *( packedColorGlyphBuffer + 1u ) = static_cast<uint8_t>( color->g * colorAlpha );
+ *packedColorGlyphBuffer = static_cast<uint8_t>( color->r * colorAlpha );
+ }
+ else
+ {
+ std::swap( *packedColorGlyphBuffer, *( packedColorGlyphBuffer + 2u ) ); // Swap B and R.
+
+ *( packedColorGlyphBuffer + 2u ) = ( *( packedColorGlyphBuffer + 2u ) * colorAlpha / 255 );
+ *( packedColorGlyphBuffer + 1u ) = ( *( packedColorGlyphBuffer + 1u ) * colorAlpha / 255 );
+ *packedColorGlyphBuffer = ( *( packedColorGlyphBuffer ) * colorAlpha / 255 );
+ }
}
// Set the color into the final pixel buffer.
}
else
{
+ // Pack the given color into a 32bit buffer. The alpha channel will be updated later for each pixel.
+ // The format is RGBA8888.
+ uint32_t packedColor = 0u;
+ uint8_t* packedColorBuffer = reinterpret_cast<uint8_t*>( &packedColor );
+
// Update the alpha channel.
const uint8_t alpha = *( data.glyphBitmap.buffer + glyphBufferOffset + index );
uint32_t& currentColor = *( bitmapBuffer + verticalOffset + xOffsetIndex );
uint8_t* packedCurrentColorBuffer = reinterpret_cast<uint8_t*>( ¤tColor );
- uint8_t currentAlpha = *( packedCurrentColorBuffer + 3u );
- uint8_t newAlpha = static_cast<uint8_t>( color->a * static_cast<float>( alpha ) );
-
// For any pixel overlapped with the pixel in previous glyphs, make sure we don't
// overwrite a previous bigger alpha with a smaller alpha (in order to avoid
// semi-transparent gaps between joint glyphs with overlapped pixels, which could
// happen, for example, in the RTL text when we copy glyphs from right to left).
- *( packedColorBuffer + 3u ) = std::max( currentAlpha, newAlpha );
+ uint8_t currentAlpha = *( packedCurrentColorBuffer + 3u );
+ currentAlpha = std::max( currentAlpha, alpha );
+
+ // Color is pre-muliplied with its alpha.
+ *( packedColorBuffer + 3u ) = static_cast<uint8_t>( color->a * currentAlpha );
+ *( packedColorBuffer + 2u ) = static_cast<uint8_t>( color->b * currentAlpha );
+ *( packedColorBuffer + 1u ) = static_cast<uint8_t>( color->g * currentAlpha );
+ *( packedColorBuffer ) = static_cast<uint8_t>( color->r * currentAlpha );
// Set the color into the final pixel buffer.
currentColor = packedColor;
{
// Check alpha of overlapped pixels
uint8_t& currentAlpha = *( bitmapBuffer + verticalOffset + xOffsetIndex );
- uint8_t newAlpha = static_cast<uint8_t>( color->a * static_cast<float>( alpha ) );
// For any pixel overlapped with the pixel in previous glyphs, make sure we don't
// overwrite a previous bigger alpha with a smaller alpha (in order to avoid
// semi-transparent gaps between joint glyphs with overlapped pixels, which could
// happen, for example, in the RTL text when we copy glyphs from right to left).
- *( bitmapBuffer + verticalOffset + xOffsetIndex ) = std::max( currentAlpha, newAlpha );
+ *( bitmapBuffer + verticalOffset + xOffsetIndex ) = std::max( currentAlpha, alpha );
}
}
}
// Retrieves the glyph's color.
const ColorIndex colorIndex = *( colorIndexBuffer + glyphIndex );
- const Vector4* color;
+ Vector4 color;
if ( style == Typesetter::STYLE_SHADOW )
{
- color = &( mModel->GetShadowColor() );
+ color = mModel->GetShadowColor();
}
else if ( style == Typesetter::STYLE_OUTLINE )
{
- color = &( mModel->GetOutlineColor() );
+ color = mModel->GetOutlineColor();
}
else
{
- color = ( useDefaultColor || ( 0u == colorIndex ) ) ? &defaultColor : colorsBuffer + ( colorIndex - 1u );
+ color = ( useDefaultColor || ( 0u == colorIndex ) ) ? defaultColor : *( colorsBuffer + ( colorIndex - 1u ) );
}
+ // Premultiply alpha
+ color.r *= color.a;
+ color.g *= color.a;
+ color.b *= color.a;
+
// Retrieves the glyph's bitmap.
glyphData.glyphBitmap.buffer = NULL;
glyphData.glyphBitmap.width = glyphInfo->width; // Desired width and height.
{
TypesetGlyph( glyphData,
position,
- color,
+ &color,
style,
pixelFormat);
// delete the glyphBitmap.buffer as it is now copied into glyphData.bitmapBuffer
uint8_t* underlinePixelBuffer = reinterpret_cast<uint8_t*>( &underlinePixel );
// Write the underline color to the pixel buffer
- *( underlinePixelBuffer ) = static_cast<uint8_t>( underlineColor.r * 255.f );
- *( underlinePixelBuffer + 1u ) = static_cast<uint8_t>( underlineColor.g * 255.f );
- *( underlinePixelBuffer + 2u ) = static_cast<uint8_t>( underlineColor.b * 255.f );
- *( underlinePixelBuffer + 3u ) = static_cast<uint8_t>( underlineColor.a * 255.f );
+ uint8_t colorAlpha = static_cast< uint8_t >( underlineColor.a * 255.f );
+ *( underlinePixelBuffer + 3u ) = colorAlpha;
+ *( underlinePixelBuffer + 2u ) = static_cast< uint8_t >( underlineColor.b * colorAlpha );
+ *( underlinePixelBuffer + 1u ) = static_cast< uint8_t >( underlineColor.g * colorAlpha );
+ *( underlinePixelBuffer ) = static_cast< uint8_t >( underlineColor.r * colorAlpha );
*( bitmapBuffer + y * glyphData.width + x ) = underlinePixel;
}
uint8_t* backgroundPixelBuffer = reinterpret_cast<uint8_t*>( &backgroundPixel );
// Write the background color to the pixel buffer
- *( backgroundPixelBuffer ) = static_cast<uint8_t>( backgroundColor.r * 255.f );
- *( backgroundPixelBuffer + 1u ) = static_cast<uint8_t>( backgroundColor.g * 255.f );
- *( backgroundPixelBuffer + 2u ) = static_cast<uint8_t>( backgroundColor.b * 255.f );
- *( backgroundPixelBuffer + 3u ) = static_cast<uint8_t>( backgroundColor.a * 255.f );
+ uint8_t colorAlpha = static_cast< uint8_t >( backgroundColor.a * 255.f );
+ *( backgroundPixelBuffer + 3u ) = colorAlpha;
+ *( backgroundPixelBuffer + 2u ) = static_cast< uint8_t >( backgroundColor.b * colorAlpha );
+ *( backgroundPixelBuffer + 1u ) = static_cast< uint8_t >( backgroundColor.g * colorAlpha );
+ *( backgroundPixelBuffer ) = static_cast< uint8_t >( backgroundColor.r * colorAlpha );
*( bitmapBuffer + y * glyphData.width + x ) = backgroundPixel;
}
// Otherwise, copy pixel from topBuffer to combinedBuffer.
unsigned int alphaBuffer1 = topBuffer[pixelIndex*4+3];
- unsigned int alphaBuffer2 = bottomBuffer[pixelIndex*4+3];
- if ( alphaBuffer1 != 255 || alphaBuffer2 != 255 )
+ if ( alphaBuffer1 != 255 )
{
// At least one pixel is not fully opaque
// "Over" blend the the pixel from topBuffer with the pixel in bottomBuffer
- combinedBuffer[pixelIndex*4] = ( topBuffer[pixelIndex*4] * topBuffer[pixelIndex*4+3] / 255 ) + ( bottomBuffer[pixelIndex*4] * bottomBuffer[pixelIndex*4+3] * ( 255 - topBuffer[pixelIndex*4+3] ) / ( 255*255 ) );
- combinedBuffer[pixelIndex*4+1] = ( topBuffer[pixelIndex*4+1] * topBuffer[pixelIndex*4+3] / 255 ) + ( bottomBuffer[pixelIndex*4+1] * bottomBuffer[pixelIndex*4+3] * ( 255 - topBuffer[pixelIndex*4+3] ) / ( 255*255 ) );
- combinedBuffer[pixelIndex*4+2] = ( topBuffer[pixelIndex*4+2] * topBuffer[pixelIndex*4+3] / 255 ) + ( bottomBuffer[pixelIndex*4+2] * bottomBuffer[pixelIndex*4+3] * ( 255 - topBuffer[pixelIndex*4+3] ) / ( 255*255 ) );
+ combinedBuffer[pixelIndex*4] = topBuffer[pixelIndex*4] + ( bottomBuffer[pixelIndex*4] * ( 255 - topBuffer[pixelIndex*4+3] ) / 255 );
+ combinedBuffer[pixelIndex*4+1] = topBuffer[pixelIndex*4+1] + ( bottomBuffer[pixelIndex*4+1] * ( 255 - topBuffer[pixelIndex*4+3] ) / 255 );
+ combinedBuffer[pixelIndex*4+2] = topBuffer[pixelIndex*4+2] + ( bottomBuffer[pixelIndex*4+2] * ( 255 - topBuffer[pixelIndex*4+3] ) / 255 );
combinedBuffer[pixelIndex*4+3] = topBuffer[pixelIndex*4+3] + ( bottomBuffer[pixelIndex*4+3] * ( 255 - topBuffer[pixelIndex*4+3] ) / 255 );
}
else