+ const int widthMinusOne = static_cast<int>(data.width - 1u);
+ const int heightMinusOne = static_cast<int>(data.height - 1u);
+
+ if(Pixel::RGBA8888 == pixelFormat)
+ {
+ // Whether the given glyph is a color one.
+ const bool isColorGlyph = data.glyphBitmap.isColorEmoji || data.glyphBitmap.isColorBitmap;
+ const uint32_t glyphPixelSize = Pixel::GetBytesPerPixel(data.glyphBitmap.format);
+ const uint32_t alphaIndex = glyphPixelSize - 1u;
+ const bool swapChannelsBR = Pixel::BGRA8888 == data.glyphBitmap.format;
+
+ // Pointer to the color glyph if there is one.
+ const uint32_t* const colorGlyphBuffer = isColorGlyph ? reinterpret_cast<uint32_t*>(data.glyphBitmap.buffer) : NULL;
+
+ // Initial vertical offset.
+ const int yOffset = data.verticalOffset + position->y;
+
+ uint32_t* bitmapBuffer = reinterpret_cast<uint32_t*>(data.bitmapBuffer.GetBuffer());
+
+ // Traverse the pixels of the glyph line per line.
+ for(int lineIndex = 0, glyphHeight = static_cast<int>(data.glyphBitmap.height); lineIndex < glyphHeight; ++lineIndex)
+ {
+ const int yOffsetIndex = yOffset + lineIndex;
+ if((0 > yOffsetIndex) || (yOffsetIndex > heightMinusOne))
+ {
+ // Do not write out of bounds.
+ continue;
+ }
+
+ const int verticalOffset = yOffsetIndex * data.width;
+ const int xOffset = data.horizontalOffset + position->x;
+ const int glyphBufferOffset = lineIndex * static_cast<int>(data.glyphBitmap.width);
+ for(int index = 0, glyphWidth = static_cast<int>(data.glyphBitmap.width); index < glyphWidth; ++index)
+ {
+ const int xOffsetIndex = xOffset + index;
+ if((0 > xOffsetIndex) || (xOffsetIndex > widthMinusOne))
+ {
+ // Don't write out of bounds.
+ continue;
+ }
+
+ if(isColorGlyph)
+ {
+ // Retrieves the color from the color glyph.
+ uint32_t packedColorGlyph = *(colorGlyphBuffer + glyphBufferOffset + index);
+ uint8_t* packedColorGlyphBuffer = reinterpret_cast<uint8_t*>(&packedColorGlyph);
+
+ // 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
+ {
+ const 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
+ {
+ if(swapChannelsBR)
+ {
+ 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);
+
+ if(data.glyphBitmap.isColorBitmap)
+ {
+ *(packedColorGlyphBuffer + 2u) = static_cast<uint8_t>(*(packedColorGlyphBuffer + 2u) * color->b);
+ *(packedColorGlyphBuffer + 1u) = static_cast<uint8_t>(*(packedColorGlyphBuffer + 1u) * color->g);
+ *packedColorGlyphBuffer = static_cast<uint8_t>(*packedColorGlyphBuffer * color->r);
+ }
+ }
+ }
+
+ // Set the color into the final pixel buffer.
+ *(bitmapBuffer + verticalOffset + xOffsetIndex) = packedColorGlyph;
+ }
+ 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 + glyphPixelSize * (glyphBufferOffset + index) + alphaIndex);
+
+ // Copy non-transparent pixels only
+ if(alpha > 0u)
+ {
+ // Check alpha of overlapped pixels
+ uint32_t& currentColor = *(bitmapBuffer + verticalOffset + xOffsetIndex);
+ uint8_t* packedCurrentColorBuffer = reinterpret_cast<uint8_t*>(¤tColor);
+
+ // 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).
+ 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;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Whether the given glyph is a color one.
+ const bool isColorGlyph = data.glyphBitmap.isColorEmoji || data.glyphBitmap.isColorBitmap;
+ const uint32_t glyphPixelSize = Pixel::GetBytesPerPixel(data.glyphBitmap.format);
+ const uint32_t alphaIndex = glyphPixelSize - 1u;
+
+ // Initial vertical offset.
+ const int yOffset = data.verticalOffset + position->y;
+
+ uint8_t* bitmapBuffer = reinterpret_cast<uint8_t*>(data.bitmapBuffer.GetBuffer());
+
+ // Traverse the pixels of the glyph line per line.
+ for(int lineIndex = 0, glyphHeight = static_cast<int>(data.glyphBitmap.height); lineIndex < glyphHeight; ++lineIndex)
+ {
+ const int yOffsetIndex = yOffset + lineIndex;
+ if((0 > yOffsetIndex) || (yOffsetIndex > heightMinusOne))
+ {
+ // Do not write out of bounds.
+ continue;
+ }
+
+ const int verticalOffset = yOffsetIndex * data.width;
+ const int xOffset = data.horizontalOffset + position->x;
+ const int glyphBufferOffset = lineIndex * static_cast<int>(data.glyphBitmap.width);
+ for(int index = 0, glyphWidth = static_cast<int>(data.glyphBitmap.width); index < glyphWidth; ++index)
+ {
+ const int xOffsetIndex = xOffset + index;
+ if((0 > xOffsetIndex) || (xOffsetIndex > widthMinusOne))
+ {
+ // Don't write out of bounds.
+ continue;
+ }
+
+ if(!isColorGlyph)
+ {
+ // Update the alpha channel.
+ const uint8_t alpha = *(data.glyphBitmap.buffer + glyphPixelSize * (glyphBufferOffset + index) + alphaIndex);
+
+ // Copy non-transparent pixels only
+ if(alpha > 0u)
+ {
+ // Check alpha of overlapped pixels
+ uint8_t& currentAlpha = *(bitmapBuffer + verticalOffset + xOffsetIndex);
+
+ // 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).
+ currentAlpha = std::max(currentAlpha, alpha);
+ }
+ }
+ }
+ }
+ }
+}