Skip to content

Commit

Permalink
lvdrawbuf: handle text and background colors with alpha
Browse files Browse the repository at this point in the history
In Draw(glyph bitmap) and FillRect(), so for text and
background colors (only implemented for bpp=8/16/32).
Enable alpha values when parsing CSS colors.
  • Loading branch information
poire-z committed Apr 6, 2022
1 parent c7b6737 commit ada7342
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 37 deletions.
92 changes: 62 additions & 30 deletions crengine/src/lvdrawbuf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,9 @@ void LVGrayDrawBuf::FillRect( int x0, int y0, int x1, int y1, lUInt32 color32 )
if (x0>=x1 || y0>=y1)
return;
lUInt8 color = rgbToGrayMask( color32, _bpp );
const lUInt8 opacity = ~color32 >> 24;
if (opacity == 0) // Fully transparent color
return;
#if (GRAY_INVERSE==1)
color ^= 0xFF;
#endif
Expand All @@ -926,8 +929,15 @@ void LVGrayDrawBuf::FillRect( int x0, int y0, int x1, int y1, lUInt32 color32 )
line[index] = (lUInt8)((line[index] & ~mask) | (color & mask));
}
} else { // 3, 4, 8
for (int x=x0; x<x1; x++)
line[x] = color;
if ( opacity == 0xFF ) {
for (int x=x0; x<x1; x++)
line[x] = color;
}
else {
const lUInt8 alpha = opacity ^ 0xFF;
for (int x=x0; x<x1; x++)
ApplyAlphaGray8( line[x], color, alpha, opacity );
}
}
line += _rowsize;
}
Expand Down Expand Up @@ -1249,24 +1259,31 @@ void LVGrayDrawBuf::Draw( int x, int y, const lUInt8 * bitmap, int width, int he
// true : false;
//#endif

// Note: support for TextColor opacity/alpha was added only in the _bpp==8 branch
if ( _bpp==8 ) {
lUInt8 * dstline = _data + _rowsize*y + x;
const lUInt8 color = rgbToGrayMask(GetTextColor(), 8);
const lUInt8 bopacity = ~GetTextColor() >> 24;
if (bopacity == 0) // Fully transparent color
return;
while (height--)
{
const lUInt8 * __restrict src = bitmap;
lUInt8 * __restrict dst = dstline;
size_t px_count = width;
while (px_count--)
{
const lUInt8 opaque = (*src++);
if ( opaque == 0 ) {
lUInt8 opacity = *(src++); // glyph opacity
if ( opacity == 0 ) {
// Background pixel, NOP
} else if ( opaque == 0xFF ) {
}
else if (opacity == 0xFF && bopacity == 0xFF) { // fully opaque pixel and color
*dst = color;
} else {
const lUInt8 alpha = opaque ^ 0xFF;
ApplyAlphaGray8( *dst, color, alpha, opaque );
}
else {
opacity = (opacity*bopacity)>>8;
const lUInt8 alpha = opacity ^ 0xFF;
ApplyAlphaGray8( *dst, color, alpha, opacity );
}
dst++;
}
Expand Down Expand Up @@ -1660,6 +1677,8 @@ void LVColorDrawBuf::FillRect( int x0, int y0, int x1, int y1, lUInt32 color )
if (x0>=x1 || y0>=y1)
return;
const lUInt8 alpha = (color >> 24) & 0xFF;
if (alpha == 0xFF) // Fully transparent color
return;
if ( _bpp==16 ) {
const lUInt16 cl16 = rgb888to565(color);
for (int y=y0; y<y1; y++)
Expand Down Expand Up @@ -1910,6 +1929,9 @@ void LVColorDrawBuf::Draw( int x, int y, const lUInt8 * bitmap, int width, int h

if ( _bpp==16 ) {
const lUInt16 bmpcl16 = rgb888to565(bmpcl);
const lUInt8 bopacity = ~bmpcl >> 24; // alpha=0x00 => opacity=0xFF
if (bopacity == 0) // Fully transparent color
return;

while (height--)
{
Expand All @@ -1919,24 +1941,33 @@ void LVColorDrawBuf::Draw( int x, int y, const lUInt8 * bitmap, int width, int h
size_t px_count = width;
while (px_count--)
{
const lUInt8 opaque = ((*(src++))>>4)&0x0F;
if ( opaque==0 ) {
// Note: former code was considering pixel opacity >= 0xF0 as fully opaque (0xFF),
// not sure why (it would save on the blending computation by 5% to 15%).
lUInt8 opacity = *(src++); // glyph pixel opacity
if ( opacity == 0 ) {
// Background pixel, NOP
} else if ( opaque>=0xF ) {
}
else if (opacity == 0xFF && bopacity == 0xFF) { // fully opaque pixel and color
*dst = bmpcl16;
} else {
const lUInt8 alpha = 0xF-opaque;
const lUInt16 cl1 = (lUInt16)(((alpha*((*dst)&0xF81F) + opaque*(bmpcl16&0xF81F))>>4) & 0xF81F);
const lUInt16 cl2 = (lUInt16)(((alpha*((*dst)&0x07E0) + opaque*(bmpcl16&0x07E0))>>4) & 0x07E0);
*dst = cl1 | cl2;
}
else {
opacity = (opacity*bopacity)>>8;
const lUInt8 alpha = opacity ^ 0xFF;
const lUInt32 r = ((((*dst) & 0xF800) * alpha + (bmpcl16 & 0xF800) * opacity) >> 8) & 0xF800;
const lUInt32 g = ((((*dst) & 0x07E0) * alpha + (bmpcl16 & 0x07E0) * opacity) >> 8) & 0x07E0;
const lUInt32 b = ((((*dst) & 0x001F) * alpha + (bmpcl16 & 0x001F) * opacity) >> 8) & 0x001F;
*dst = (lUInt16)(r | g | b);
}
dst++;
}
/* new src line, to account for clipping */
bitmap += bmp_width;
}
} else {
const lUInt32 bmpcl32 = bmpcl;
const lUInt32 bmpcl32 = bmpcl & 0x00FFFFFF;
const lUInt8 bopacity = ~bmpcl >> 24; // alpha=0x00 => opacity=0xFF
if (bopacity == 0) // Fully transparent color
return;

while (height--)
{
Expand All @@ -1946,24 +1977,25 @@ void LVColorDrawBuf::Draw( int x, int y, const lUInt8 * bitmap, int width, int h
size_t px_count = width;
while (px_count--)
{
// NOTE: Not quite sure what's the rationale for the funky semi half-precision alpha-blending there...
const lUInt8 opaque = ((*(src++))>>1)&0x7F;
if ( opaque==0 ) {
// Note: former code was considering pixel opacity >= 0xF0 as fully opaque (0xFF),
// not sure why (it would save on the blending computation by 5% to 15%).
lUInt8 opacity = *(src++); // glyph pixel opacity
if ( opacity == 0 ) {
// Background pixel, NOP
} else if ( opaque>=0x78 ) {
}
else if (opacity == 0xFF && bopacity == 0xFF) { // fully opaque pixel and color
*dst = bmpcl32;
} else {
const lUInt8 alpha = 0x7F-opaque;
const lUInt32 cl1 = ((alpha*((*dst)&0xFF00FF) + opaque*(bmpcl32&0xFF00FF))>>7) & 0xFF00FF;
const lUInt32 cl2 = ((alpha*((*dst)&0x00FF00) + opaque*(bmpcl32&0x00FF00))>>7) & 0x00FF00;
// NOTE: We're skipping the alpha byte here, because CRe uses inverted alpha :(
// Which means that the masking shenanigans above ensure it's 0x00, fully opaque...
// (c.f., ApplyAlphaRGB, which does the same thing without the weird half-precision hack).
*dst = cl1 | cl2;
}
else {
opacity = (opacity*bopacity)>>8;
const lUInt8 alpha = opacity ^ 0xFF;
const lUInt32 n1 = ((((*dst) & 0xFF00FF) * alpha + (bmpcl32 & 0xFF00FF) * opacity) >> 8) & 0xFF00FF;
const lUInt32 n2 = ((((*dst) & 0x00FF00) * alpha + (bmpcl32 & 0x00FF00) * opacity) >> 8) & 0x00FF00;
*dst = n1 | n2;
}

dst++;
}
/* next src line, accounting for clipping */
bitmap += bmp_width;
}
}
Expand Down
9 changes: 3 additions & 6 deletions crengine/src/lvstsheet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1167,8 +1167,7 @@ bool parse_color_value( const char * & str, css_length_t & value )
if ( nDigits==4 ) {
int a = hexDigit( *str++ );
// cre color upper byte is inverted alpha (0x00=opaque, 0xFF=transparency)
// value.value |= ((a + a*16)^0xFF)<<24;
// Disabled for now, as support for alpha needs work
value.value |= ((a + a*16)^0xFF)<<24;
}
return true;
} else if ( nDigits==6 || nDigits==8 ) {
Expand All @@ -1184,8 +1183,7 @@ bool parse_color_value( const char * & str, css_length_t & value )
int a = hexDigit( *str++ ) * 16;
a += hexDigit( *str++ );
// cre color upper byte is inverted alpha
// value.value |= ((a + a*16)^0xFF)<<24;
// Disabled for now, as support for alpha needs work
value.value |= ((a + a*16)^0xFF)<<24;
}
return true;
} else {
Expand Down Expand Up @@ -1297,8 +1295,7 @@ bool parse_color_value( const char * & str, css_length_t & value )
break;
}
// cre color upper byte is inverted alpha (0x00=opaque, 0xFF=transparency)
// color = ((n^0xFF)<<24) | color;
// Disabled for now, as support for alpha needs work
color = ((n^0xFF)<<24) | color;
}
else {
valid = false;
Expand Down
2 changes: 1 addition & 1 deletion crengine/src/lvtinydom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ extern const int gDOMVersionCurrent = DOM_VERSION_CURRENT;
// increment to force complete reload/reparsing of old file
#define CACHE_FILE_FORMAT_VERSION "3.05.67k"
/// increment following value to force re-formatting of old book after load
#define FORMATTING_VERSION_ID 0x002B
#define FORMATTING_VERSION_ID 0x002C

#ifndef DOC_DATA_COMPRESSION_LEVEL
/// data compression level (0=no compression, 1=fast compressions, 3=normal compression)
Expand Down

0 comments on commit ada7342

Please sign in to comment.