From 339acc57cf09fa99314625ec709ea74a1258be75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 20 Dec 2020 12:25:12 +0100 Subject: [PATCH] render: fix rounding error when calculating background color with alpha MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use pre-multiplied alpha color channels, but were having bad rounding errors due to the alpha divider being truncated to an integer. The algorithm for pre-multiplying a color channel is: alpha_divider = 0xffff / alpha pre_mult_color = color / alpha_divider In order to fix the rounding errors, we could turn ‘alpha_divider’ into a double. That however would introduce a performance penalty since now we’d need to do floating point math for each cell. The algorithm can be trivially converted to: pre_mult_color = color * alpha / 0xffff Since both color and alpa values are < 65536, the multiplication is “safe”; it will not overflow an uint32_t. Closes #249 --- CHANGELOG.md | 2 ++ render.c | 10 +++------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 795d395a..c25d5586 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ * Missing dependencies in meson, causing heavily parallelized builds to fail. +* Background color when alpha < 1.0 being wrong + (https://codeberg.org/dnkl/foot/issues/249). ### Security diff --git a/render.c b/render.c index df22dd6e..f66e277e 100644 --- a/render.c +++ b/render.c @@ -213,14 +213,10 @@ attrs_to_font(const struct terminal *term, const struct attributes *attrs) static inline pixman_color_t color_hex_to_pixman_with_alpha(uint32_t color, uint16_t alpha) { - if (alpha == 0) - return (pixman_color_t){0, 0, 0, 0}; - - int alpha_div = 0xffff / alpha; return (pixman_color_t){ - .red = ((color >> 16 & 0xff) | (color >> 8 & 0xff00)) / alpha_div, - .green = ((color >> 8 & 0xff) | (color >> 0 & 0xff00)) / alpha_div, - .blue = ((color >> 0 & 0xff) | (color << 8 & 0xff00)) / alpha_div, + .red = ((color >> 16 & 0xff) | (color >> 8 & 0xff00)) * alpha / 0xffff, + .green = ((color >> 8 & 0xff) | (color >> 0 & 0xff00)) * alpha / 0xffff, + .blue = ((color >> 0 & 0xff) | (color << 8 & 0xff00)) * alpha / 0xffff, .alpha = alpha, }; }