diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index f3393d4325b..b78e459a3ce 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -152,6 +152,12 @@ struct GpGraphics{ UINT textcontrast; /* not used yet. get/set only */ struct list containers; GraphicsContainer contid; /* last-issued container ID */ + /* For giving the caller an HDC when we technically can't: */ + HBITMAP temp_hbitmap; + int temp_hbitmap_width; + int temp_hbitmap_height; + BYTE *temp_bits; + HDC temp_hdc; }; struct GpBrush{ diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 885011085ad..8e203f35b7b 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -4663,6 +4663,9 @@ GpStatus WINGDIPAPI GdipMultiplyWorldTransform(GpGraphics *graphics, GDIPCONST G return ret; } +/* Color used to fill bitmaps so we can tell which parts have been drawn over by gdi32. */ +static const COLORREF DC_BACKGROUND_KEY = 0x0c0b0d; + GpStatus WINGDIPAPI GdipGetDC(GpGraphics *graphics, HDC *hdc) { TRACE("(%p, %p)\n", graphics, hdc); @@ -4673,14 +4676,61 @@ GpStatus WINGDIPAPI GdipGetDC(GpGraphics *graphics, HDC *hdc) if(graphics->busy) return ObjectBusy; - if (!graphics->hdc) + if (!graphics->hdc || + (graphics->image && graphics->image->type == ImageTypeBitmap && ((GpBitmap*)graphics->image)->format & PixelFormatAlpha)) { - WARN("no HDC for this graphics\n"); - *hdc = NULL; - return GenericError; + /* Create a fake HDC and fill it with a constant color. */ + HDC temp_hdc; + HBITMAP hbitmap; + GpStatus stat; + GpRectF bounds; + BITMAPINFOHEADER bmih; + int i; + + stat = get_graphics_bounds(graphics, &bounds); + if (stat != Ok) + return stat; + + graphics->temp_hbitmap_width = bounds.Width; + graphics->temp_hbitmap_height = bounds.Height; + + bmih.biSize = sizeof(bmih); + bmih.biWidth = graphics->temp_hbitmap_width; + bmih.biHeight = -graphics->temp_hbitmap_height; + bmih.biPlanes = 1; + bmih.biBitCount = 32; + bmih.biCompression = BI_RGB; + bmih.biSizeImage = 0; + bmih.biXPelsPerMeter = 0; + bmih.biYPelsPerMeter = 0; + bmih.biClrUsed = 0; + bmih.biClrImportant = 0; + + hbitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, + (void**)&graphics->temp_bits, NULL, 0); + if (!hbitmap) + return GenericError; + + temp_hdc = CreateCompatibleDC(0); + if (!temp_hdc) + { + DeleteObject(hbitmap); + return GenericError; + } + + for (i=0; i<(graphics->temp_hbitmap_width * graphics->temp_hbitmap_height); i++) + ((DWORD*)graphics->temp_bits)[i] = DC_BACKGROUND_KEY; + + SelectObject(temp_hdc, hbitmap); + + graphics->temp_hbitmap = hbitmap; + *hdc = graphics->temp_hdc = temp_hdc; + } + else + { + *hdc = graphics->hdc; } - *hdc = graphics->hdc; graphics->busy = TRUE; return Ok; @@ -4690,12 +4740,40 @@ GpStatus WINGDIPAPI GdipReleaseDC(GpGraphics *graphics, HDC hdc) { TRACE("(%p, %p)\n", graphics, hdc); - if(!graphics) + if(!graphics || !hdc) return InvalidParameter; - if(graphics->hdc != hdc || !(graphics->busy)) + if((graphics->hdc != hdc && graphics->temp_hdc != hdc) || !(graphics->busy)) return InvalidParameter; + if (graphics->temp_hdc == hdc) + { + DWORD* pos; + int i; + + /* Find the pixels that have changed, and mark them as opaque. */ + pos = (DWORD*)graphics->temp_bits; + for (i=0; i<(graphics->temp_hbitmap_width * graphics->temp_hbitmap_height); i++) + { + if (*pos != DC_BACKGROUND_KEY) + { + *pos |= 0xff000000; + } + pos++; + } + + /* Write the changed pixels to the real target. */ + alpha_blend_pixels(graphics, 0, 0, graphics->temp_bits, + graphics->temp_hbitmap_width, graphics->temp_hbitmap_height, + graphics->temp_hbitmap_width * 4); + + /* Clean up. */ + DeleteDC(graphics->temp_hdc); + DeleteObject(graphics->temp_hbitmap); + graphics->temp_hdc = NULL; + graphics->temp_hbitmap = NULL; + } + graphics->busy = FALSE; return Ok;