Vincent Povirk : gdiplus: Create HBITMAP-less bitmap objects for exotic pixel formats.

Alexandre Julliard julliard at winehq.org
Tue Aug 17 11:31:11 CDT 2010


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

Author: Vincent Povirk <vincent at codeweavers.com>
Date:   Sun Aug  8 16:18:40 2010 -0500

gdiplus: Create HBITMAP-less bitmap objects for exotic pixel formats.

---

 dlls/gdiplus/gdiplus_private.h |    3 +
 dlls/gdiplus/graphics.c        |   39 +++++++++++++++
 dlls/gdiplus/image.c           |  103 ++++++++++++++++++++++++++--------------
 dlls/gdiplus/tests/graphics.c  |    6 +-
 4 files changed, 113 insertions(+), 38 deletions(-)

diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index 908a1b7..f3393d4 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -49,6 +49,8 @@ extern REAL gdiplus_atan2(REAL dy, REAL dx);
 extern GpStatus hresult_to_status(HRESULT res);
 extern REAL convert_unit(REAL logpixels, GpUnit unit);
 
+extern GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics);
+
 extern void calc_curve_bezier(CONST GpPointF *pts, REAL tension, REAL *x1,
     REAL *y1, REAL *x2, REAL *y2);
 extern void calc_curve_bezier_endp(REAL xend, REAL yend, REAL xadj, REAL yadj,
@@ -269,6 +271,7 @@ struct GpBitmap{
     HDC hdc;
     BYTE *bits; /* actual image bits if this is a DIB */
     INT stride; /* stride of bits if this is a DIB */
+    BYTE *own_bits; /* image bits that need to be freed with this object */
 };
 
 struct GpCachedBitmap{
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 79290b5..e748477 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -1254,6 +1254,45 @@ GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **gra
     return Ok;
 }
 
+GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics)
+{
+    GpStatus retval;
+
+    *graphics = GdipAlloc(sizeof(GpGraphics));
+    if(!*graphics)  return OutOfMemory;
+
+    if((retval = GdipCreateMatrix(&(*graphics)->worldtrans)) != Ok){
+        GdipFree(*graphics);
+        return retval;
+    }
+
+    if((retval = GdipCreateRegion(&(*graphics)->clip)) != Ok){
+        GdipFree((*graphics)->worldtrans);
+        GdipFree(*graphics);
+        return retval;
+    }
+
+    (*graphics)->hdc = NULL;
+    (*graphics)->hwnd = NULL;
+    (*graphics)->owndc = FALSE;
+    (*graphics)->image = image;
+    (*graphics)->smoothing = SmoothingModeDefault;
+    (*graphics)->compqual = CompositingQualityDefault;
+    (*graphics)->interpolation = InterpolationModeDefault;
+    (*graphics)->pixeloffset = PixelOffsetModeDefault;
+    (*graphics)->compmode = CompositingModeSourceOver;
+    (*graphics)->unit = UnitDisplay;
+    (*graphics)->scale = 1.0;
+    (*graphics)->busy = FALSE;
+    (*graphics)->textcontrast = 4;
+    list_init(&(*graphics)->containers);
+    (*graphics)->contid = 0;
+
+    TRACE("<-- %p\n", *graphics);
+
+    return Ok;
+}
+
 GpStatus WINGDIPAPI GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics)
 {
     GpStatus ret;
diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c
index 57c9f83..536eebb 100644
--- a/dlls/gdiplus/image.c
+++ b/dlls/gdiplus/image.c
@@ -1626,10 +1626,10 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
 {
     BITMAPINFO* pbmi;
-    HBITMAP hbitmap;
+    HBITMAP hbitmap=NULL;
     INT row_size, dib_stride;
     HDC hdc;
-    BYTE *bits;
+    BYTE *bits=NULL, *own_bits=NULL;
     int i;
     REAL xres, yres;
     GpStatus stat;
@@ -1655,39 +1655,63 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     if(stride == 0)
         stride = dib_stride;
 
-    pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
-    if (!pbmi)
-        return OutOfMemory;
+    if (format & PixelFormatGDI)
+    {
+        pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+        if (!pbmi)
+            return OutOfMemory;
 
-    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
-    pbmi->bmiHeader.biWidth = width;
-    pbmi->bmiHeader.biHeight = -height;
-    pbmi->bmiHeader.biPlanes = 1;
-    /* FIXME: use the rest of the data from format */
-    pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(format);
-    pbmi->bmiHeader.biCompression = BI_RGB;
-    pbmi->bmiHeader.biSizeImage = 0;
-    pbmi->bmiHeader.biXPelsPerMeter = 0;
-    pbmi->bmiHeader.biYPelsPerMeter = 0;
-    pbmi->bmiHeader.biClrUsed = 0;
-    pbmi->bmiHeader.biClrImportant = 0;
+        pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+        pbmi->bmiHeader.biWidth = width;
+        pbmi->bmiHeader.biHeight = -height;
+        pbmi->bmiHeader.biPlanes = 1;
+        /* FIXME: use the rest of the data from format */
+        pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(format);
+        pbmi->bmiHeader.biCompression = BI_RGB;
+        pbmi->bmiHeader.biSizeImage = 0;
+        pbmi->bmiHeader.biXPelsPerMeter = 0;
+        pbmi->bmiHeader.biYPelsPerMeter = 0;
+        pbmi->bmiHeader.biClrUsed = 0;
+        pbmi->bmiHeader.biClrImportant = 0;
+
+        hdc = CreateCompatibleDC(NULL);
+        if (!hdc) {
+            GdipFree(pbmi);
+            return GenericError;
+        }
 
-    hdc = CreateCompatibleDC(NULL);
-    if (!hdc) {
+        hbitmap = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+
+        DeleteDC(hdc);
         GdipFree(pbmi);
-        return GenericError;
-    }
 
-    hbitmap = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+        if (!hbitmap) return GenericError;
+    }
+    else
+    {
+        /* Not a GDI format; don't try to make an HBITMAP. */
+        if (scan0)
+        {
+            /* FIXME: We should do this with GDI formats too when scan0 is
+             * provided, but for now we need the HDC for most drawing
+             * operations. */
+            bits = scan0;
+        }
+        else
+        {
+            INT size = abs(stride) * height;
 
-    DeleteDC(hdc);
-    GdipFree(pbmi);
+            own_bits = bits = GdipAlloc(size);
+            if (!own_bits) return OutOfMemory;
 
-    if (!hbitmap) return GenericError;
+            if (stride < 0)
+                bits += stride * (1 - height);
+        }
+    }
 
     /* copy bits to the dib if necessary */
     /* FIXME: should reference the bits instead of copying them */
-    if (scan0)
+    if (scan0 && bits != scan0)
         for (i=0; i<height; i++)
             memcpy(bits+i*dib_stride, scan0+i*stride, row_size);
 
@@ -1695,6 +1719,7 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     if(!*bitmap)
     {
         DeleteObject(hbitmap);
+        GdipFree(own_bits);
         return OutOfMemory;
     }
 
@@ -1715,6 +1740,7 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     (*bitmap)->hdc = NULL;
     (*bitmap)->bits = bits;
     (*bitmap)->stride = dib_stride;
+    (*bitmap)->own_bits = own_bits;
 
     if (format == PixelFormat1bppIndexed ||
         format == PixelFormat4bppIndexed ||
@@ -1916,6 +1942,7 @@ static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette)
     dst->hdc = src->hdc;
     dst->bits = src->bits;
     dst->stride = src->stride;
+    dst->own_bits = src->own_bits;
 
     GdipFree(src);
 }
@@ -1932,6 +1959,7 @@ GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
     if (image->type == ImageTypeBitmap)
     {
         GdipFree(((GpBitmap*)image)->bitmapbits);
+        GdipFree(((GpBitmap*)image)->own_bits);
         DeleteDC(((GpBitmap*)image)->hdc);
         DeleteObject(((GpBitmap*)image)->hbitmap);
     }
@@ -2048,18 +2076,23 @@ GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image,
         return NotImplemented;
     }
 
-    hdc = ((GpBitmap*)image)->hdc;
+    if (((GpBitmap*)image)->hbitmap)
+    {
+        hdc = ((GpBitmap*)image)->hdc;
 
-    if(!hdc){
-        hdc = CreateCompatibleDC(0);
-        SelectObject(hdc, ((GpBitmap*)image)->hbitmap);
-        ((GpBitmap*)image)->hdc = hdc;
-    }
+        if(!hdc){
+            hdc = CreateCompatibleDC(0);
+            SelectObject(hdc, ((GpBitmap*)image)->hbitmap);
+            ((GpBitmap*)image)->hdc = hdc;
+        }
 
-    stat = GdipCreateFromHDC(hdc, graphics);
+        stat = GdipCreateFromHDC(hdc, graphics);
 
-    if (stat == Ok)
-        (*graphics)->image = image;
+        if (stat == Ok)
+            (*graphics)->image = image;
+    }
+    else
+        stat = graphics_from_image(image, graphics);
 
     return stat;
 }
diff --git a/dlls/gdiplus/tests/graphics.c b/dlls/gdiplus/tests/graphics.c
index 441367e..609f426 100644
--- a/dlls/gdiplus/tests/graphics.c
+++ b/dlls/gdiplus/tests/graphics.c
@@ -2616,7 +2616,7 @@ static void test_GdipGetNearestColor(void)
     GdipDisposeImage((GpImage*)bitmap);
 
     status = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat48bppRGB, NULL, &bitmap);
-    todo_wine expect(Ok, status);
+    expect(Ok, status);
     if (status == Ok)
     {
         status = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics);
@@ -2629,7 +2629,7 @@ static void test_GdipGetNearestColor(void)
     }
 
     status = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat64bppARGB, NULL, &bitmap);
-    todo_wine expect(Ok, status);
+    expect(Ok, status);
     if (status == Ok)
     {
         status = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics);
@@ -2642,7 +2642,7 @@ static void test_GdipGetNearestColor(void)
     }
 
     status = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat64bppPARGB, NULL, &bitmap);
-    todo_wine expect(Ok, status);
+    expect(Ok, status);
     if (status == Ok)
     {
         status = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics);




More information about the wine-cvs mailing list