From 5433969ec8f46d3587658723a30aaa884430666c Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Sun, 28 Mar 2010 22:25:20 -0500 Subject: [PATCH] gdiplus: Don't use gdi32 to draw to bitmaps with formats it can't handle. --- dlls/gdiplus/gdiplus_private.h | 23 ++++ dlls/gdiplus/graphics.c | 233 ++++++++++++++++++++++----------- 2 files changed, 182 insertions(+), 74 deletions(-) diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index fb2c1f562b3..5ff71255b9d 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -78,6 +78,29 @@ static inline REAL deg2rad(REAL degrees) return M_PI * degrees / 180.0; } +static inline ARGB color_over(ARGB bg, ARGB fg) +{ + BYTE b, g, r, a; + BYTE bg_alpha, fg_alpha; + + fg_alpha = (fg>>24)&0xff; + + if (fg_alpha == 0xff) return fg; + + if (fg_alpha == 0) return bg; + + bg_alpha = (((bg>>24)&0xff) * (0xff-fg_alpha)) / 0xff; + + if (bg_alpha == 0) return fg; + + a = bg_alpha + fg_alpha; + b = ((bg&0xff)*bg_alpha + (fg&0xff)*fg_alpha)*0xff/a; + g = (((bg>>8)&0xff)*bg_alpha + ((fg>>8)&0xff)*fg_alpha)*0xff/a; + r = (((bg>>16)&0xff)*bg_alpha + ((fg>>16)&0xff)*fg_alpha)*0xff/a; + + return (a<<24)|(r<<16)|(g<<8)|b; +} + extern const char *debugstr_rectf(CONST RectF* rc); extern const char *debugstr_pointf(CONST PointF* pt); diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 1fd870e3d42..c5242e41ea1 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -1872,9 +1872,10 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image REAL srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes, DrawImageAbort callback, VOID * callbackData) { - GpPointF ptf[3]; - POINT pti[3]; + GpPointF ptf[4]; + POINT pti[4]; REAL dx, dy; + GpStatus stat; TRACE("(%p, %p, %p, %d, %f, %f, %f, %f, %d, %p, %p, %p)\n", graphics, image, points, count, srcx, srcy, srcwidth, srcheight, srcUnit, imageAttributes, callback, @@ -1887,7 +1888,9 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image debugstr_pointf(&points[2])); memcpy(ptf, points, 3 * sizeof(GpPointF)); - transform_and_round_points(graphics, pti, ptf, 3); + ptf[3].X = ptf[2].X + ptf[1].X - ptf[0].X; + ptf[3].Y = ptf[2].Y + ptf[1].Y - ptf[0].Y; + transform_and_round_points(graphics, pti, ptf, 4); if (image->picture) { @@ -1914,10 +1917,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image } else if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->hbitmap) { - HDC hdc; GpBitmap* bitmap = (GpBitmap*)image; - int temp_hdc=0, temp_bitmap=0; - HBITMAP hbitmap, old_hbm=NULL; + int use_software=0; if (srcUnit == UnitInch) dx = dy = 96.0; /* FIXME: use the image resolution */ @@ -1926,83 +1927,167 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image else return NotImplemented; - if (!(bitmap->format == PixelFormat16bppRGB555 || - bitmap->format == PixelFormat24bppRGB || - bitmap->format == PixelFormat32bppRGB || - bitmap->format == PixelFormat32bppPARGB)) + if (graphics->image && graphics->image->type == ImageTypeBitmap) { - BITMAPINFOHEADER bih; - BYTE *temp_bits; - PixelFormat dst_format; + GpBitmap *dst_bitmap = (GpBitmap*)graphics->image; + if (!(dst_bitmap->format == PixelFormat16bppRGB555 || + dst_bitmap->format == PixelFormat24bppRGB || + dst_bitmap->format == PixelFormat32bppRGB)) + use_software = 1; + } - /* we can't draw a bitmap of this format directly */ - hdc = CreateCompatibleDC(0); - temp_hdc = 1; - temp_bitmap = 1; + if (use_software) + { + RECT src_area, dst_area; + int i, x, y; + GpMatrix *dst_to_src; + REAL m11, m12, m21, m22, mdx, mdy; - bih.biSize = sizeof(BITMAPINFOHEADER); - bih.biWidth = bitmap->width; - bih.biHeight = -bitmap->height; - bih.biPlanes = 1; - bih.biBitCount = 32; - bih.biCompression = BI_RGB; - bih.biSizeImage = 0; - bih.biXPelsPerMeter = 0; - bih.biYPelsPerMeter = 0; - bih.biClrUsed = 0; - bih.biClrImportant = 0; + src_area.left = srcx*dx; + src_area.top = srcy*dy; + src_area.right = (srcx+srcwidth)*dx; + src_area.bottom = (srcy+srcheight)*dy; - hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS, - (void**)&temp_bits, NULL, 0); + dst_area.left = dst_area.right = pti[0].x; + dst_area.top = dst_area.bottom = pti[0].y; + for (i=1; i<4; i++) + { + if (dst_area.left > pti[i].x) dst_area.left = pti[i].x; + if (dst_area.right < pti[i].x) dst_area.right = pti[i].x; + if (dst_area.top > pti[i].y) dst_area.top = pti[i].y; + if (dst_area.bottom < pti[i].y) dst_area.bottom = pti[i].y; + } + + m11 = (ptf[1].X - ptf[0].X) / srcwidth; + m12 = (ptf[2].X - ptf[0].X) / srcheight; + mdx = ptf[0].X - m11 * srcx - m12 * srcy; + m21 = (ptf[1].Y - ptf[0].Y) / srcwidth; + m22 = (ptf[2].Y - ptf[0].Y) / srcheight; + mdy = ptf[0].Y - m21 * srcx - m22 * srcy; + + stat = GdipCreateMatrix2(m11, m12, m21, m22, mdx, mdy, &dst_to_src); + if (stat != Ok) return stat; + + stat = GdipInvertMatrix(dst_to_src); + if (stat != Ok) + { + GdipDeleteMatrix(dst_to_src); + return stat; + } + + for (x=dst_area.left; x= src_area.right || + src_y < src_area.top || src_y >= src_area.bottom) + /* FIXME: Use wrapmode */ + continue; + + GdipBitmapGetPixel(bitmap, src_x, src_y, &src_color); + GdipBitmapGetPixel((GpBitmap*)graphics->image, x, y, &dst_color); + GdipBitmapSetPixel((GpBitmap*)graphics->image, x, y, color_over(dst_color, src_color)); + } + } + + GdipDeleteMatrix(dst_to_src); + } + else + { + HDC hdc; + int temp_hdc=0, temp_bitmap=0; + HBITMAP hbitmap, old_hbm=NULL; + + if (!(bitmap->format == PixelFormat16bppRGB555 || + bitmap->format == PixelFormat24bppRGB || + bitmap->format == PixelFormat32bppRGB || + bitmap->format == PixelFormat32bppPARGB)) + { + BITMAPINFOHEADER bih; + BYTE *temp_bits; + PixelFormat dst_format; + + /* we can't draw a bitmap of this format directly */ + hdc = CreateCompatibleDC(0); + temp_hdc = 1; + temp_bitmap = 1; + + bih.biSize = sizeof(BITMAPINFOHEADER); + bih.biWidth = bitmap->width; + bih.biHeight = -bitmap->height; + bih.biPlanes = 1; + bih.biBitCount = 32; + bih.biCompression = BI_RGB; + bih.biSizeImage = 0; + bih.biXPelsPerMeter = 0; + bih.biYPelsPerMeter = 0; + bih.biClrUsed = 0; + bih.biClrImportant = 0; + + hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS, + (void**)&temp_bits, NULL, 0); + + if (bitmap->format & (PixelFormatAlpha|PixelFormatPAlpha)) + dst_format = PixelFormat32bppPARGB; + else + dst_format = PixelFormat32bppRGB; + + convert_pixels(bitmap->width, bitmap->height, + bitmap->width*4, temp_bits, dst_format, + bitmap->stride, bitmap->bits, bitmap->format, bitmap->image.palette_entries); + } + else + { + hbitmap = bitmap->hbitmap; + hdc = bitmap->hdc; + temp_hdc = (hdc == 0); + } + + if (temp_hdc) + { + if (!hdc) hdc = CreateCompatibleDC(0); + old_hbm = SelectObject(hdc, hbitmap); + } if (bitmap->format & (PixelFormatAlpha|PixelFormatPAlpha)) - dst_format = PixelFormat32bppPARGB; + { + BLENDFUNCTION bf; + + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 255; + bf.AlphaFormat = AC_SRC_ALPHA; + + GdiAlphaBlend(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y, + hdc, srcx*dx, srcy*dy, srcwidth*dx, srcheight*dy, bf); + } else - dst_format = PixelFormat32bppRGB; + { + StretchBlt(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y, + hdc, srcx*dx, srcy*dy, srcwidth*dx, srcheight*dy, SRCCOPY); + } - convert_pixels(bitmap->width, bitmap->height, - bitmap->width*4, temp_bits, dst_format, - bitmap->stride, bitmap->bits, bitmap->format, bitmap->image.palette_entries); + if (temp_hdc) + { + SelectObject(hdc, old_hbm); + DeleteDC(hdc); + } + + if (temp_bitmap) + DeleteObject(hbitmap); } - else - { - hbitmap = bitmap->hbitmap; - hdc = bitmap->hdc; - temp_hdc = (hdc == 0); - } - - if (temp_hdc) - { - if (!hdc) hdc = CreateCompatibleDC(0); - old_hbm = SelectObject(hdc, hbitmap); - } - - if (bitmap->format & (PixelFormatAlpha|PixelFormatPAlpha)) - { - BLENDFUNCTION bf; - - bf.BlendOp = AC_SRC_OVER; - bf.BlendFlags = 0; - bf.SourceConstantAlpha = 255; - bf.AlphaFormat = AC_SRC_ALPHA; - - GdiAlphaBlend(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y, - hdc, srcx*dx, srcy*dy, srcwidth*dx, srcheight*dy, bf); - } - else - { - StretchBlt(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y, - hdc, srcx*dx, srcy*dy, srcwidth*dx, srcheight*dy, SRCCOPY); - } - - if (temp_hdc) - { - SelectObject(hdc, old_hbm); - DeleteDC(hdc); - } - - if (temp_bitmap) - DeleteObject(hbitmap); } else {