Skip to content

Commit

Permalink
CSS/colors: handle 'transparent' as a real color
Browse files Browse the repository at this point in the history
Use (css_val_color, CSS_COLOR_TRANSPARENT) for 'transparent'
instead of (css_val_unspecified, css_generic_transparent),
which avoids special cases when handling its inheritance.
This makes 'currentcolor' the only value with css_val_unspecified,
and make fixing the following issues simpler:
- when inheriting 'currentcolor', it must not be resolved to
  a color, but inherited as 'currentcolor'.
- other parsed transparent colors like rgba(12,34,56,0)
  or #88888800 are now handled as 'transparent'.
  • Loading branch information
poire-z committed Aug 31, 2023
1 parent f5cd3b2 commit 84d2ff0
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 91 deletions.
7 changes: 6 additions & 1 deletion crengine/include/cssdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,13 +378,18 @@ enum css_caption_side_t {
enum css_generic_value_t {
css_generic_auto = -1, // (css_val_unspecified, css_generic_auto), for "margin: auto"
css_generic_normal = -2, // (css_val_unspecified, css_generic_normal), for "line-height: normal"
css_generic_transparent = -3, // (css_val_unspecified, css_generic_transparent), for "color: transparent"
// css_generic_transparent = -3, // replaced by (css_val_color, CSS_COLOR_TRANSPARENT)
css_generic_currentcolor = -4, // (css_val_unspecified, css_generic_currentcolor), for "color: currentcolor"
css_generic_contain = -5, // (css_val_unspecified, css_generic_contain), for "background-size: contain"
css_generic_cover = -6, // (css_val_unspecified, css_generic_cover), for "background-size: cover"
css_generic_none = -7 // (css_val_unspecified, css_generic_none), for "max-width: none"
};

// color 'transparent' is transparent black rgba(0,0,0,0) per specs
#define CSS_COLOR_TRANSPARENT 0xFF000000
#define IS_COLOR_FULLY_TRANSPARENT(color_value) ( (bool)((color_value & 0xFF000000) == 0xFF000000) )
#define IS_COLOR_FULLY_OPAQUE(color_value) ( (bool)((color_value & 0xFF000000) == 0x00000000) )

// -cr-hint is a non standard property for providing hints to crengine via style tweaks
// Handled as a bitmap, with a flag for each hint, as we might set multiple on a same node (max 31 bits)
#define CSS_CR_HINT_NONE 0x00000000 // default value
Expand Down
3 changes: 3 additions & 0 deletions crengine/include/lvdrawbuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,9 @@ inline lUInt16 rgb888to565( lUInt32 cl ) {
return (lUInt16)(((cl>>8)& 0xF800) | ((cl>>5 )& 0x07E0) | ((cl>>3 )& 0x001F));
}

// Combine two colors
lUInt32 combineColors( lUInt32 foreColor, lUInt32 backColor );

#define DIV255(V) \
({ \
auto _v = (V) + 128; \
Expand Down
2 changes: 1 addition & 1 deletion crengine/include/lvstyles.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ struct css_style_rec_tag {
, max_width(css_val_unspecified, css_generic_none)
, max_height(css_val_unspecified, css_generic_none)
, color(css_val_inherited, 0)
, background_color(css_val_unspecified, 0)
, background_color(css_val_color, CSS_COLOR_TRANSPARENT)
, letter_spacing(css_val_inherited, 0)
, page_break_before(css_pb_auto)
, page_break_after(css_pb_auto)
Expand Down
34 changes: 34 additions & 0 deletions crengine/src/lvdrawbuf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,40 @@ static inline void ApplyAlphaGray8( lUInt8 &dst, lUInt8 src, lUInt8 alpha, lUInt
}
}

// Combine two colors
// (Shortcuts if foreColor or backColor are fully transparent or fully opaque could be taken,
// see lvrend.cpp's setNodeStyle() and background_color; but keeping this function pure so
// we can check it gives the same result as these shortcuts.)
lUInt32 combineColors( lUInt32 foreColor, lUInt32 backColor ) {
// Thanks to https://ciechanow.ski/alpha-compositing/ to make all that clearer,
// especially sections "Combining Alphas" and "Combining Colors", from which
// we take some wording for the following comments.
lUInt8 falpha = foreColor >> 24; // wrongly named "alpha" all around crengine, it's actually the transparency
lUInt8 fopacity = falpha ^ 0xFF;
lUInt8 balpha = backColor >> 24;
lUInt8 bopacity = balpha ^ 0xFF;
// The resulting transparency of two objects combined is equal to their product
lUInt8 ralpha = DIV255(falpha*balpha);
lUInt8 ropacity = ralpha ^ 0xFF;
lUInt32 rcolor;
if (ropacity == 0 ) {
rcolor = 0xFF000000; // fully transparent
}
else {
// foreColor's light contribution to the final color is its value * its opacity
// backColor's light contribution to the final color is its value * its opacity, but some
// of that light is blocked by the foremost object opacity (so the '* falpha')
// The total light contribution is the sum of these "pre-multiplied-alpha" values.
// But as these final values will be '* opacity' when later blended, we need
// to un-pre-multiply them to get straigth-alpha (so the '/ ropacity').
lUInt8 r = ( ((foreColor & 0xFF0000)>>16) * fopacity + DIV255( ((backColor & 0xFF0000)>>16) * bopacity * falpha ) ) / ropacity;
lUInt8 g = ( ((foreColor & 0x00FF00)>>8 ) * fopacity + DIV255( ((backColor & 0x00FF00)>>8 ) * bopacity * falpha ) ) / ropacity;
lUInt8 b = ( ((foreColor & 0x0000FF) ) * fopacity + DIV255( ((backColor & 0x0000FF) ) * bopacity * falpha ) ) / ropacity;
rcolor = (ralpha<<24) | (r<<16) | (g<<8) | b;
}
return rcolor;
}

//static const short dither_2bpp_4x4[] = {
// 5, 13, 8, 16,
// 9, 1, 12, 4,
Expand Down
Loading

0 comments on commit 84d2ff0

Please sign in to comment.