michael@0: changeset: 106848:28db6dbdd9ea michael@0: tag: gdi-patch michael@0: tag: qbase michael@0: tag: qtip michael@0: tag: tip michael@0: user: Jeff Muizelaar michael@0: date: Wed Sep 12 22:52:06 2012 -0400 michael@0: summary: Bug 788794. Use BitBlt to do SOURCE and OVER from RGB24 to ARGB32. r=nical michael@0: michael@0: diff --git a/gfx/cairo/cairo/src/cairo-win32-surface.c b/gfx/cairo/cairo/src/cairo-win32-surface.c michael@0: --- a/gfx/cairo/cairo/src/cairo-win32-surface.c michael@0: +++ b/gfx/cairo/cairo/src/cairo-win32-surface.c michael@0: @@ -884,16 +884,28 @@ static cairo_int_status_t michael@0: src_x, src_y, michael@0: src_w, src_h, michael@0: blend_function)) michael@0: return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(AlphaBlend)"); michael@0: michael@0: return CAIRO_STATUS_SUCCESS; michael@0: } michael@0: michael@0: +/* makes the alpha channel in a RGB24 surface 0xff */ michael@0: +static void michael@0: +make_opaque (cairo_image_surface_t *image, cairo_rectangle_int_t src_r) michael@0: +{ michael@0: + int x; int y; michael@0: + for (y = src_r.y; y < src_r.height; y++) { michael@0: + for (x = src_r.x; x < src_r.width; x++) { michael@0: + image->data[y * image->stride + x*4 + 3] = 0xff; michael@0: + } michael@0: + } michael@0: +} michael@0: + michael@0: static cairo_int_status_t michael@0: _cairo_win32_surface_composite_inner (cairo_win32_surface_t *src, michael@0: cairo_image_surface_t *src_image, michael@0: cairo_win32_surface_t *dst, michael@0: cairo_rectangle_int_t src_extents, michael@0: cairo_rectangle_int_t src_r, michael@0: cairo_rectangle_int_t dst_r, michael@0: int alpha, michael@0: @@ -935,16 +947,24 @@ static cairo_int_status_t michael@0: src_r.width, - (int) src_r.height, michael@0: src_image->data, michael@0: &bi, michael@0: DIB_RGB_COLORS, michael@0: SRCCOPY)) michael@0: return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(StretchDIBits)"); michael@0: } michael@0: } else if (!needs_alpha) { michael@0: + if (src->format == CAIRO_FORMAT_RGB24 && dst->format == CAIRO_FORMAT_ARGB32) { michael@0: + /* Because we store RGB24 & ARGB32 in the same way GDI has no way michael@0: + * to ignore the alpha channel from a RGB24 source. Therefore, we set michael@0: + * the alpha channel in our RGB24 source to opaque so that we can treat michael@0: + * it like ARGB32. */ michael@0: + GdiFlush(); michael@0: + make_opaque(src->image, src_r); michael@0: + } michael@0: /* BitBlt or StretchBlt? */ michael@0: if (!needs_scale && (dst->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT)) { michael@0: if (!BitBlt (dst->dc, michael@0: dst_r.x, dst_r.y, michael@0: dst_r.width, dst_r.height, michael@0: src->dc, michael@0: src_r.x, src_r.y, michael@0: SRCCOPY)) michael@0: @@ -1184,28 +1204,36 @@ static cairo_int_status_t michael@0: } michael@0: } else { michael@0: needs_repeat = TRUE; michael@0: } michael@0: michael@0: /* michael@0: * Operations that we can do: michael@0: * michael@0: + * AlphaBlend uses the following formula for alpha when not use the per-pixel alpha (AlphaFormat = 0) michael@0: + * Dst.Alpha = Src.Alpha * (SCA/255.0) + Dst.Alpha * (1.0 - (SCA/255.0)) michael@0: + * This turns into Dst.Alpha = Src.Alpha when SCA = 255. michael@0: + * (http://msdn.microsoft.com/en-us/library/aa921335.aspx) michael@0: + * michael@0: * RGB OVER RGB -> BitBlt (same as SOURCE) michael@0: - * RGB OVER ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA) michael@0: + * RGB OVER ARGB -> Partially supported, We convert this operation into a ARGB SOURCE ARGB michael@0: + * by setting the alpha values of the source to 255. michael@0: * ARGB OVER ARGB -> AlphaBlend, with AC_SRC_ALPHA michael@0: * ARGB OVER RGB -> AlphaBlend, with AC_SRC_ALPHA; we'll have junk in the dst A byte michael@0: * michael@0: * RGB OVER RGB + mask -> AlphaBlend, no AC_SRC_ALPHA michael@0: - * RGB OVER ARGB + mask -> UNSUPPORTED michael@0: + * RGB OVER ARGB + mask -> Partially supported, We convert this operation into a ARGB OVER ARGB + mask michael@0: + * by setting the alpha values of the source to 255. michael@0: * ARGB OVER ARGB + mask -> AlphaBlend, with AC_SRC_ALPHA michael@0: * ARGB OVER RGB + mask -> AlphaBlend, with AC_SRC_ALPHA; junk in the dst A byte michael@0: * michael@0: * RGB SOURCE RGB -> BitBlt michael@0: - * RGB SOURCE ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA) michael@0: + * RGB SOURCE ARGB -> Partially supported, We convert this operation into a ARGB SOURCE ARGB michael@0: + * by setting the alpha values of the source to 255. michael@0: * ARGB SOURCE ARGB -> BitBlt michael@0: * ARGB SOURCE RGB -> BitBlt michael@0: * michael@0: * RGB SOURCE RGB + mask -> unsupported michael@0: * RGB SOURCE ARGB + mask -> unsupported michael@0: * ARGB SOURCE ARGB + mask -> unsupported michael@0: * ARGB SOURCE RGB + mask -> unsupported michael@0: */ michael@0: @@ -1222,22 +1250,32 @@ static cairo_int_status_t michael@0: needs_alpha = FALSE; michael@0: } else { michael@0: needs_alpha = TRUE; michael@0: } michael@0: } else if (src_format == CAIRO_FORMAT_ARGB32 && michael@0: dst->format == CAIRO_FORMAT_RGB24) michael@0: { michael@0: needs_alpha = TRUE; michael@0: + } else if (src_format == CAIRO_FORMAT_RGB24 && michael@0: + dst->format == CAIRO_FORMAT_ARGB32 && michael@0: + src->image) michael@0: + { michael@0: + if (alpha == 255) { michael@0: + needs_alpha = FALSE; michael@0: + } else { michael@0: + needs_alpha = TRUE; michael@0: + } michael@0: } else { michael@0: goto UNSUPPORTED; michael@0: } michael@0: } else if (alpha == 255 && op == CAIRO_OPERATOR_SOURCE) { michael@0: if ((src_format == dst->format) || michael@0: - (src_format == CAIRO_FORMAT_ARGB32 && dst->format == CAIRO_FORMAT_RGB24)) michael@0: + (src_format == CAIRO_FORMAT_ARGB32 && dst->format == CAIRO_FORMAT_RGB24) || michael@0: + (src_format == CAIRO_FORMAT_RGB24 && dst->format == CAIRO_FORMAT_ARGB32 && src->image)) michael@0: { michael@0: needs_alpha = FALSE; michael@0: } else { michael@0: goto UNSUPPORTED; michael@0: } michael@0: } else { michael@0: goto UNSUPPORTED; michael@0: } michael@0: