From 9c579023f0750539bdf7815f8545c4620540387a Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Tue, 24 Mar 2015 12:50:18 -0500 Subject: [PATCH] gdiplus: Fix blend_colors when alpha channel differs. When picking a color halfway between 100% white (0xffffffff) and fully transparent (0x00000000), the result was 50% opaque 50% grey (0x80808080) when it should really be 50% opaque white (0x80ffffff). This had a tendency to create grey fringes on things. The fix is to weight the non-alpha components based on how much they contribute to the final alpha value. --- dlls/gdiplus/graphics.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index ae530a9a8f6..580390fd704 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -521,20 +521,22 @@ static GpStatus alpha_blend_pixels(GpGraphics *graphics, INT dst_x, INT dst_y, static ARGB blend_colors(ARGB start, ARGB end, REAL position) { - ARGB result=0; - ARGB i; - INT a1, a2, a3; + INT start_a, end_a, final_a; + INT pos; - a1 = (start >> 24) & 0xff; - a2 = (end >> 24) & 0xff; + pos = gdip_round(position * 0xff); - a3 = (int)(a1*(1.0f - position)+a2*(position)); + start_a = ((start >> 24) & 0xff) * (pos ^ 0xff); + end_a = ((end >> 24) & 0xff) * pos; - result |= a3 << 24; + final_a = start_a + end_a; - for (i=0xff; i<=0xff0000; i = i << 8) - result |= (int)((start&i)*(1.0f - position)+(end&i)*(position))&i; - return result; + if (final_a < 0xff) return 0; + + return (final_a / 0xff) << 24 | + ((((start >> 16) & 0xff) * start_a + (((end >> 16) & 0xff) * end_a)) / final_a) << 16 | + ((((start >> 8) & 0xff) * start_a + (((end >> 8) & 0xff) * end_a)) / final_a) << 8 | + (((start & 0xff) * start_a + ((end & 0xff) * end_a)) / final_a); } static ARGB blend_line_gradient(GpLineGradient* brush, REAL position)