[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