[PATCH 3/4] winemac.drv: Really fix our handling of DIBs on the clipboard.

Charles Davis cdavis5x at gmail.com
Tue May 3 14:03:25 CDT 2016


Additional testing has shown that I was (once again) wrong.

Signed-off-by: Charles Davis <cdavis5x at gmail.com>
---
 dlls/winemac.drv/clipboard.c | 413 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 386 insertions(+), 27 deletions(-)

diff --git a/dlls/winemac.drv/clipboard.c b/dlls/winemac.drv/clipboard.c
index 2082cad..af67c63 100644
--- a/dlls/winemac.drv/clipboard.c
+++ b/dlls/winemac.drv/clipboard.c
@@ -73,7 +73,10 @@ typedef struct _WINE_CLIPFORMAT
 static HANDLE import_clipboard_data(CFDataRef data);
 static HANDLE import_bmp_to_bitmap(CFDataRef data);
 static HANDLE import_bmp_to_dib(CFDataRef data);
+static HANDLE import_bmp_to_dibv5(CFDataRef data);
 static HANDLE import_dib_to_bitmap(CFDataRef data);
+static HANDLE import_dib_to_dibv5(CFDataRef data);
+static HANDLE import_dibv5_to_dib(CFDataRef data);
 static HANDLE import_enhmetafile(CFDataRef data);
 static HANDLE import_enhmetafile_to_metafilepict(CFDataRef data);
 static HANDLE import_metafilepict(CFDataRef data);
@@ -95,7 +98,10 @@ static HANDLE import_utf16_to_unicodetext(CFDataRef data);
 static CFDataRef export_clipboard_data(HANDLE data);
 static CFDataRef export_bitmap_to_bmp(HANDLE data);
 static CFDataRef export_bitmap_to_dib(HANDLE data);
+static CFDataRef export_bitmap_to_dibv5(HANDLE data);
 static CFDataRef export_dib_to_bmp(HANDLE data);
+static CFDataRef export_dib_to_dibv5(HANDLE data);
+static CFDataRef export_dibv5_to_dib(HANDLE data);
 static CFDataRef export_enhmetafile(HANDLE data);
 static CFDataRef export_hdrop_to_filenames(HANDLE data);
 static CFDataRef export_metafilepict(HANDLE data);
@@ -196,19 +202,19 @@ static const struct
 
     { CF_BITMAP,            CFSTR("org.winehq.builtin.bitmap"),             import_bmp_to_bitmap,           export_bitmap_to_bmp,       FALSE },
     { CF_DIB,               CFSTR("org.winehq.builtin.bitmap"),             import_bmp_to_dib,              export_dib_to_bmp,          TRUE },
-    { CF_DIBV5,             CFSTR("org.winehq.builtin.bitmap"),             import_bmp_to_dib,              export_dib_to_bmp,          TRUE },
+    { CF_DIBV5,             CFSTR("org.winehq.builtin.bitmap"),             import_bmp_to_dibv5,            export_dib_to_bmp,          TRUE },
 
     { CF_DIB,               CFSTR("org.winehq.builtin.dib"),                import_clipboard_data,          export_clipboard_data,      FALSE },
     { CF_BITMAP,            CFSTR("org.winehq.builtin.dib"),                import_dib_to_bitmap,           export_bitmap_to_dib,       TRUE },
-    { CF_DIBV5,             CFSTR("org.winehq.builtin.dib"),                import_clipboard_data,          export_clipboard_data,      TRUE },
+    { CF_DIBV5,             CFSTR("org.winehq.builtin.dib"),                import_dib_to_dibv5,            export_dibv5_to_dib,        TRUE },
 
     { CF_DIBV5,             CFSTR("org.winehq.builtin.dibv5"),              import_clipboard_data,          export_clipboard_data,      FALSE },
-    { CF_BITMAP,            CFSTR("org.winehq.builtin.dibv5"),              import_dib_to_bitmap,           export_bitmap_to_dib,       TRUE },
-    { CF_DIB,               CFSTR("org.winehq.builtin.dibv5"),              import_clipboard_data,          export_clipboard_data,      TRUE },
+    { CF_BITMAP,            CFSTR("org.winehq.builtin.dibv5"),              import_dib_to_bitmap,           export_bitmap_to_dibv5,     TRUE },
+    { CF_DIB,               CFSTR("org.winehq.builtin.dibv5"),              import_dibv5_to_dib,            export_dib_to_dibv5,        TRUE },
 
     { CF_BITMAP,            CFSTR("com.microsoft.bmp"),                     import_bmp_to_bitmap,           export_bitmap_to_bmp,       TRUE },
     { CF_DIB,               CFSTR("com.microsoft.bmp"),                     import_bmp_to_dib,              export_dib_to_bmp,          TRUE },
-    { CF_DIBV5,             CFSTR("com.microsoft.bmp"),                     import_bmp_to_dib,              export_dib_to_bmp,          TRUE },
+    { CF_DIBV5,             CFSTR("com.microsoft.bmp"),                     import_bmp_to_dibv5,            export_dib_to_bmp,          TRUE },
 
     { CF_HDROP,             CFSTR("org.winehq.builtin.hdrop"),              import_clipboard_data,          export_clipboard_data,      FALSE },
     { CF_HDROP,             CFSTR("NSFilenamesPboardType"),                 import_nsfilenames_to_hdrop,    export_hdrop_to_filenames,  TRUE },
@@ -615,6 +621,74 @@ static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp)
 }
 
 
+/***********************************************************************
+ *              create_dib_from_dibv5
+ *
+ * Given a packed version 5 DIB, allocates a packed version 3/4 DIB and
+ * copies the DIB data into it.  If the source DIB is already version 3
+ * or 4, the source handle will be directly returned.
+ */
+static HGLOBAL create_dib_from_dibv5(HGLOBAL src)
+{
+    HGLOBAL dest;
+    BYTE *psrc, *pdest;
+    BITMAPINFOHEADER *bmih;
+    const BITMAPV5HEADER *bv5;
+    unsigned int data_size, packed_size, offset_src, offset_dest;
+
+    psrc = GlobalLock(src);
+    bv5 = (BITMAPV5HEADER *)psrc;
+
+    /* Already not a V5 DIB? */
+    if (bv5->bV5Size < sizeof(BITMAPV5HEADER))
+    {
+        /* Nothing to do. */
+        GlobalUnlock(src);
+        return src;
+    }
+
+    /* Calculate the size of the new packed DIB */
+    data_size = bv5->bV5SizeImage;
+    packed_size = sizeof(BITMAPINFOHEADER)
+                  + ((bv5->bV5BitCount <= 8) ? (sizeof(RGBQUAD) * bv5->bV5ClrUsed) : 0)
+                  + ((bv5->bV5Compression == BI_BITFIELDS) ? (sizeof(DWORD) * 3) : 0)
+                  + data_size;
+    /* Get the offset to the bits */
+    offset_dest = packed_size - data_size;
+    offset_src = bv5->bV5Size
+                 + ((bv5->bV5BitCount <= 8) ? (sizeof(RGBQUAD) * bv5->bV5ClrUsed) : 0);
+
+    /* Allocate the packed DIB */
+    TRACE("\tAllocating packed DIB of size %d\n", packed_size);
+    dest = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, packed_size);
+    if (!dest)
+    {
+        WARN("Could not allocate packed DIB!\n");
+        GlobalUnlock(src);
+        return 0;
+    }
+
+    /* A packed DIB starts with a BITMAPINFOHEADER */
+    pdest = GlobalLock(dest);
+    bmih = (BITMAPINFOHEADER *)pdest;
+
+    /* Init the BITMAPINFOHEADER */
+    memcpy(bmih, bv5, sizeof(BITMAPINFOHEADER));
+    bmih->biSize = sizeof(BITMAPINFOHEADER);
+    if (bv5->bV5Compression == BI_BITFIELDS)
+        memcpy(bmih+1, &bv5->bV5RedMask, 3*sizeof(DWORD));
+    else if (bv5->bV5BitCount <= 8)
+        memcpy(bmih+1, bv5+1, bv5->bV5ClrUsed*sizeof(RGBQUAD));
+
+    /* Copy the bits. */
+    memcpy(pdest+offset_dest, psrc+offset_src, data_size);
+    GlobalUnlock(dest);
+    GlobalUnlock(src);
+
+    return dest;
+}
+
+
 /**************************************************************************
  *              create_bitmap_from_dib
  *
@@ -645,6 +719,157 @@ static HANDLE create_bitmap_from_dib(HANDLE dib)
 }
 
 
+/***********************************************************************
+ *              create_dibv5_from_dib
+ *
+ * Given a packed version 3 or 4 DIB, allocates a packed version 5 DIB
+ * and copies the DIB data into it.  If the source DIB is already
+ * version 5, the source handle will be directly returned.
+ */
+static HGLOBAL create_dibv5_from_dib(HGLOBAL src)
+{
+    HDC hdc;
+    HGLOBAL dest;
+    LOGCOLORSPACEW lcs;
+    BYTE *psrc, *pdest;
+    const BITMAPINFOHEADER *bmih;
+    BITMAPV5HEADER *bv5;
+    unsigned int data_size, packed_size, offset_src, offset_dest;
+
+    psrc = GlobalLock(src);
+    bmih = (BITMAPINFOHEADER *)psrc;
+
+    /* Already a V5 DIB? */
+    if (bmih->biSize >= sizeof(BITMAPV5HEADER))
+    {
+        /* Nothing to do. */
+        GlobalUnlock(src);
+        return src;
+    }
+
+    /* Calculate the size of the new packed DIB */
+    if (bmih->biSize < sizeof(BITMAPINFOHEADER))
+    {
+        /* Assume OS/2 bitmap */
+        const BITMAPCOREHEADER *bch = (BITMAPCOREHEADER *)bmih;
+        data_size = bch->bcHeight * (((bch->bcWidth * bch->bcBitCount + 31) / 8) & ~3);
+        packed_size = sizeof(BITMAPV5HEADER)
+                      + ((bch->bcBitCount <= 8) ? (sizeof(RGBQUAD) * (1 << bch->bcBitCount)) : 0)
+                      + data_size;
+        offset_src = bch->bcSize
+                     + ((bch->bcBitCount <= 8) ? (sizeof(RGBTRIPLE) * (1 << bch->bcBitCount)) :
+                         0);
+    }
+    else
+    {
+        data_size = bmih->biSizeImage;
+        packed_size = sizeof(BITMAPV5HEADER)
+                      + ((bmih->biBitCount <= 8) ? (sizeof(RGBQUAD) * bmih->biClrUsed) : 0)
+                      + data_size;
+        offset_src = bmih->biSize
+                     + ((bmih->biBitCount <= 8) ? (sizeof(RGBQUAD) * bmih->biClrUsed) : 0);
+    }
+    /* Get the offset to the bits */
+    offset_dest = packed_size - data_size;
+
+    /* Allocate the packed DIB */
+    TRACE("\tAllocating packed DIB of size %d\n", packed_size);
+    dest = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, packed_size);
+    if (!dest)
+    {
+        WARN("Could not allocate packed DIB!\n");
+        GlobalUnlock(src);
+        return 0;
+    }
+
+    pdest = GlobalLock(dest);
+    bv5 = (BITMAPV5HEADER *)pdest;
+
+    /* Init the BITMAPV5HEADER */
+    if (bmih->biSize < sizeof(BITMAPINFOHEADER))
+    {
+        const BITMAPCOREHEADER *bch = (BITMAPCOREHEADER *)bmih;
+
+        bv5->bV5Width = bch->bcWidth;
+        bv5->bV5Height = bch->bcHeight;
+        bv5->bV5Planes = bch->bcPlanes;
+        bv5->bV5BitCount = bch->bcBitCount;
+        bv5->bV5Compression = BI_RGB;
+        bv5->bV5SizeImage = data_size;
+        bv5->bV5XPelsPerMeter = 0;
+        bv5->bV5YPelsPerMeter = 0;
+        bv5->bV5ClrUsed = bch->bcBitCount <= 8 ? (1 << bch->bcBitCount) : 0;
+        bv5->bV5ClrImportant = 0;
+        if (bv5->bV5BitCount <= 8)
+        {
+            /* Unfortunately, this must be expanded manually. */
+            RGBQUAD *rgbq = (RGBQUAD *)(bv5+1);
+            const RGBTRIPLE *rgbt = (RGBTRIPLE *)(bch+1);
+            int i;
+
+            for (i = 0; i < bv5->bV5ClrUsed; ++i)
+            {
+                rgbq[i].rgbBlue = rgbt[i].rgbtBlue;
+                rgbq[i].rgbGreen = rgbt[i].rgbtGreen;
+                rgbq[i].rgbRed = rgbt[i].rgbtRed;
+                rgbq[i].rgbReserved = 0;
+            }
+        }
+    }
+    else
+    {
+        memcpy(bv5, bmih, bmih->biSize);
+        if (bv5->bV5BitCount <= 8)
+            memcpy(bv5+1, bmih+1, bv5->bV5ClrUsed*sizeof(RGBQUAD));
+    }
+    bv5->bV5Size = sizeof(BITMAPV5HEADER);
+    if (bv5->bV5Compression == BI_BITFIELDS && bmih->biSize < sizeof(BITMAPV4HEADER))
+    {
+        memcpy(&bv5->bV5RedMask, bmih+1, 3*sizeof(DWORD));
+        bv5->bV5AlphaMask = 0;
+    }
+
+    hdc = GetDC(0);
+    if (GetLogColorSpaceW(GetColorSpace(hdc), &lcs, sizeof(lcs)))
+    {
+        if (bmih->biSize < sizeof(BITMAPV4HEADER))
+        {
+            bv5->bV5CSType = lcs.lcsCSType;
+            bv5->bV5Endpoints = lcs.lcsEndpoints;
+            bv5->bV5GammaRed = lcs.lcsGammaRed;
+            bv5->bV5GammaGreen = lcs.lcsGammaGreen;
+            bv5->bV5GammaBlue = lcs.lcsGammaBlue;
+        }
+        bv5->bV5Intent = lcs.lcsIntent;
+    }
+    else
+    {
+        if (bmih->biSize < sizeof(BITMAPV4HEADER))
+        {
+            bv5->bV5CSType = LCS_DEVICE_RGB;
+            memset(&bv5->bV5Endpoints, 0, sizeof(bv5->bV5Endpoints));
+            bv5->bV5Endpoints.ciexyzRed.ciexyzX = 0xffffffff;
+            bv5->bV5Endpoints.ciexyzGreen.ciexyzY = 0xffffffff;
+            bv5->bV5Endpoints.ciexyzBlue.ciexyzZ = 0xffffffff;
+            bv5->bV5GammaRed = 0;
+            bv5->bV5GammaGreen = 0;
+            bv5->bV5GammaBlue = 0;
+        }
+        bv5->bV5Intent = LCS_GM_GRAPHICS;
+    }
+    bv5->bV5ProfileData = 0;
+    bv5->bV5ProfileSize = 0;
+    bv5->bV5Reserved = 0;
+
+    /* Copy the bits. */
+    memcpy(pdest+offset_dest, psrc+offset_src, data_size);
+    GlobalUnlock(dest);
+    GlobalUnlock(src);
+
+    return dest;
+}
+
+
 /**************************************************************************
  *              import_clipboard_data
  *
@@ -681,29 +906,12 @@ static HANDLE import_clipboard_data(CFDataRef data)
 
 
 /**************************************************************************
- *              import_bmp_to_bitmap
+ *              import_bmp_to_dib_any
  *
- *  Import BMP data, converting to CF_BITMAP format.
+ *  Import BMP data, converting to device-independent bitmap format.  This
+ *  just entails stripping the BMP file format header.
  */
-static HANDLE import_bmp_to_bitmap(CFDataRef data)
-{
-    HANDLE ret;
-    HANDLE dib = import_bmp_to_dib(data);
-
-    ret = create_bitmap_from_dib(dib);
-
-    GlobalFree(dib);
-    return ret;
-}
-
-
-/**************************************************************************
- *              import_bmp_to_dib
- *
- *  Import BMP data, converting to CF_DIB or CF_DIBV5 format.  This just
- *  entails stripping the BMP file format header.
- */
-static HANDLE import_bmp_to_dib(CFDataRef data)
+static HANDLE import_bmp_to_dib_any(CFDataRef data)
 {
     HANDLE ret = 0;
     BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)CFDataGetBytePtr(data);
@@ -724,6 +932,7 @@ static HANDLE import_bmp_to_dib(CFDataRef data)
         }
 
         memcpy(p, bmi, len);
+
         GlobalUnlock(ret);
     }
 
@@ -732,6 +941,57 @@ static HANDLE import_bmp_to_dib(CFDataRef data)
 
 
 /**************************************************************************
+ *              import_bmp_to_bitmap
+ *
+ *  Import BMP data, converting to CF_BITMAP format.
+ */
+static HANDLE import_bmp_to_bitmap(CFDataRef data)
+{
+    HANDLE ret;
+    HANDLE dib = import_bmp_to_dib_any(data);
+
+    ret = create_bitmap_from_dib(dib);
+
+    GlobalFree(dib);
+    return ret;
+}
+
+
+/**************************************************************************
+ *              import_bmp_to_dib
+ *
+ *  Import BMP data, converting to CF_DIB format.
+ */
+static HANDLE import_bmp_to_dib(CFDataRef data)
+{
+    HANDLE ret;
+    HANDLE dib = import_bmp_to_dib_any(data);
+
+    ret = create_dib_from_dibv5(dib);
+
+    if (dib != ret) GlobalFree(dib);
+    return ret;
+}
+
+
+/**************************************************************************
+ *              import_bmp_to_dibv5
+ *
+ *  Import BMP data, converting to CF_DIBV5 format.
+ */
+static HANDLE import_bmp_to_dibv5(CFDataRef data)
+{
+    HANDLE ret;
+    HANDLE dib = import_bmp_to_dib_any(data);
+
+    ret = create_dibv5_from_dib(dib);
+
+    if (dib != ret) GlobalFree(dib);
+    return ret;
+}
+
+
+/**************************************************************************
  *              import_dib_to_bitmap
  *
  *  Import device-independent bitmap data, converting to CF_BITMAP format.
@@ -750,6 +1010,44 @@ static HANDLE import_dib_to_bitmap(CFDataRef data)
 
 
 /**************************************************************************
+ *              import_dib_to_dibv5
+ *
+ *  Import version 3 device-independent bitmap data, converting to CF_DIBV5
+ *  format.
+ */
+static HANDLE import_dib_to_dibv5(CFDataRef data)
+{
+    HANDLE ret;
+    HANDLE dib = import_clipboard_data(data);
+
+    ret = create_dibv5_from_dib(dib);
+
+    if (dib != ret) GlobalFree(dib);
+
+    return ret;
+}
+
+
+/**************************************************************************
+ *              import_dibv5_to_dib
+ *
+ *  Import version 5 device-independent bitmap data, converting to CF_DIB
+ *  format.
+ */
+static HANDLE import_dibv5_to_dib(CFDataRef data)
+{
+    HANDLE ret;
+    HANDLE dib = import_clipboard_data(data);
+
+    ret = create_dib_from_dibv5(dib);
+
+    if (dib != ret) GlobalFree(dib);
+
+    return ret;
+}
+
+
+/**************************************************************************
  *              import_enhmetafile
  *
  *  Import enhanced metafile data, converting it to CF_ENHMETAFILE.
@@ -1254,8 +1552,35 @@ static CFDataRef export_bitmap_to_dib(HANDLE data)
     dib = create_dib_from_bitmap(data);
     if (dib)
     {
-        ret = export_clipboard_data(dib);
+        HGLOBAL dib3 = create_dib_from_dibv5(dib);
+
+        ret = export_clipboard_data(dib3);
+        GlobalFree(dib);
+        if (dib3 != dib) GlobalFree(dib3);
+    }
+
+    return ret;
+}
+
+
+/**************************************************************************
+ *              export_bitmap_to_dibv5
+ *
+ *  Export CF_BITMAP to a raw version 5 packed device-independent bitmap.
+ */
+static CFDataRef export_bitmap_to_dibv5(HANDLE data)
+{
+    CFDataRef ret = NULL;
+    HGLOBAL dib;
+
+    dib = create_dib_from_bitmap(data);
+    if (dib)
+    {
+        HGLOBAL dib5 = create_dibv5_from_dib(dib);
+
+        ret = export_clipboard_data(dib5);
         GlobalFree(dib);
+        if (dib5 != dib) GlobalFree(dib5);
     }
 
     return ret;
@@ -1349,6 +1674,40 @@ static CFDataRef export_dib_to_bmp(HANDLE data)
 
 
 /**************************************************************************
+ *              export_dib_to_dibv5
+ *
+ *  Export CF_DIB to CF_DIBV5 format.
+ */
+static CFDataRef export_dib_to_dibv5(HANDLE data)
+{
+    CFDataRef ret = NULL;
+    HANDLE dib5 = create_dibv5_from_dib(data);
+
+    ret = export_clipboard_data(dib5);
+    if (dib5 != data) GlobalFree(dib5);
+
+    return ret;
+}
+
+
+/**************************************************************************
+ *              export_dibv5_to_dib
+ *
+ *  Export CF_DIBV5 to CF_DIB format.
+ */
+static CFDataRef export_dibv5_to_dib(HANDLE data)
+{
+    CFDataRef ret = NULL;
+    HANDLE dib3 = create_dib_from_dibv5(data);
+
+    ret = export_clipboard_data(dib3);
+    if (dib3 != data) GlobalFree(dib3);
+
+    return ret;
+}
+
+
+/**************************************************************************
  *              export_enhmetafile
  *
  *  Export an enhanced metafile to data.
-- 
2.8.1




More information about the wine-patches mailing list