Vincent Povirk : gdiplus: Add a fallback method for getting HDC' s from Graphics objects.

Alexandre Julliard julliard at winehq.org
Wed Aug 18 12:09:54 CDT 2010


Module: wine
Branch: master
Commit: 9d0cd0959793eba4da32ebf5ce4dbbcb3c67270d
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=9d0cd0959793eba4da32ebf5ce4dbbcb3c67270d

Author: Vincent Povirk <vincent at codeweavers.com>
Date:   Mon Aug 16 16:31:18 2010 -0500

gdiplus: Add a fallback method for getting HDC's from Graphics objects.

Native does this in more cases (at least for all bitmap graphics
objects), but using gdi32 objects when we can should perform better.

---

 dlls/gdiplus/gdiplus_private.h |    6 +++
 dlls/gdiplus/graphics.c        |   92 +++++++++++++++++++++++++++++++++++++---
 2 files changed, 91 insertions(+), 7 deletions(-)

diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index f3393d4..b78e459 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 8850110..8e203f3 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;




More information about the wine-cvs mailing list