[PATCH v2 1/4] winex11.drv: Fix handling of DIBs on the clipboard.

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


Signed-off-by: Charles Davis <cdavis5x at gmail.com>
---
Try 2:
* Stop assuming biSize is the size of the whole DIB, not just the header size.
* Handle OS/2 bitmaps. (Yes, Windows really does support this!)
---

 dlls/winex11.drv/bitblt.c    |  97 +++++++++--
 dlls/winex11.drv/clipboard.c | 379 +++++++++++++++++++++++++++++++++++++++----
 2 files changed, 431 insertions(+), 45 deletions(-)

diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c
index 8d61a4b..d7405e6 100644
--- a/dlls/winex11.drv/bitblt.c
+++ b/dlls/winex11.drv/bitblt.c
@@ -928,10 +928,10 @@ static void free_ximage_bits( struct gdi_image_bits *bits )
 static inline int get_dib_info_size( const BITMAPINFO *info, UINT coloruse )
 {
     if (info->bmiHeader.biCompression == BI_BITFIELDS)
-        return sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD);
+        return max( sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD), info->bmiHeader.biSize );
     if (coloruse == DIB_PAL_COLORS)
-        return sizeof(BITMAPINFOHEADER) + info->bmiHeader.biClrUsed * sizeof(WORD);
-    return FIELD_OFFSET( BITMAPINFO, bmiColors[info->bmiHeader.biClrUsed] );
+        return info->bmiHeader.biSize + info->bmiHeader.biClrUsed * sizeof(WORD);
+    return info->bmiHeader.biSize + info->bmiHeader.biClrUsed * sizeof(RGBQUAD);
 }
 
 static inline int get_dib_stride( int width, int bpp )
@@ -975,15 +975,38 @@ static void set_color_info( const XVisualInfo *vis, BITMAPINFO *info, BOOL has_a
         break;
     }
     case 16:
-        colors[0] = vis->red_mask;
-        colors[1] = vis->green_mask;
-        colors[2] = vis->blue_mask;
+        if (info->bmiHeader.biSize >= sizeof(BITMAPV4HEADER))
+        {
+            /* In V4/V5 DIBs, the BI_BITFIELDS masks are part of the header. */
+            BITMAPV4HEADER *v4info = (BITMAPV4HEADER *)&info->bmiHeader;
+            v4info->bV4RedMask = vis->red_mask;
+            v4info->bV4GreenMask = vis->green_mask;
+            v4info->bV4BlueMask = vis->blue_mask;
+            v4info->bV4AlphaMask = has_alpha ? ~(vis->red_mask|vis->green_mask|vis->blue_mask) & 0xffff : 0;
+        }
+        else
+        {
+            colors[0] = vis->red_mask;
+            colors[1] = vis->green_mask;
+            colors[2] = vis->blue_mask;
+        }
         info->bmiHeader.biCompression = BI_BITFIELDS;
         break;
     case 32:
-        colors[0] = vis->red_mask;
-        colors[1] = vis->green_mask;
-        colors[2] = vis->blue_mask;
+        if (info->bmiHeader.biSize >= sizeof(BITMAPV4HEADER))
+        {
+            BITMAPV4HEADER *v4info = (BITMAPV4HEADER *)&info->bmiHeader;
+            v4info->bV4RedMask = vis->red_mask;
+            v4info->bV4GreenMask = vis->green_mask;
+            v4info->bV4BlueMask = vis->blue_mask;
+            v4info->bV4AlphaMask = has_alpha ? ~(vis->red_mask|vis->green_mask|vis->blue_mask) : 0;
+        }
+        else
+        {
+            colors[0] = vis->red_mask;
+            colors[1] = vis->green_mask;
+            colors[2] = vis->blue_mask;
+        }
         if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff || !has_alpha)
             info->bmiHeader.biCompression = BI_BITFIELDS;
         break;
@@ -993,7 +1016,11 @@ static void set_color_info( const XVisualInfo *vis, BITMAPINFO *info, BOOL has_a
 /* check if the specified color info is suitable for PutImage */
 static BOOL matching_color_info( const XVisualInfo *vis, const BITMAPINFO *info )
 {
-    DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
+    DWORD *colors;
+    if (info->bmiHeader.biCompression == BI_BITFIELDS)
+        colors = (DWORD *)((char *)info + sizeof(BITMAPINFOHEADER));
+    else
+        colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
 
     switch (info->bmiHeader.biBitCount)
     {
@@ -1458,8 +1485,8 @@ Pixmap create_pixmap_from_image( HDC hdc, const XVisualInfo *vis, const BITMAPIN
                                  const struct gdi_image_bits *bits, UINT coloruse )
 {
     static const RGBQUAD default_colortable[2] = { { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff } };
-    char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
-    char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
+    char dst_buffer[sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD)];
+    char src_buffer[sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD)];
     BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
     BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
     struct gdi_image_bits dst_bits;
@@ -1478,12 +1505,13 @@ Pixmap create_pixmap_from_image( HDC hdc, const XVisualInfo *vis, const BITMAPIN
         (err = put_pixmap_image( pixmap, vis, dst_info, bits )) == ERROR_BAD_FORMAT)
     {
         if (dst_info->bmiHeader.biBitCount == 1)  /* set a default color table for 1-bpp */
-            memcpy( dst_info->bmiColors, default_colortable, sizeof(default_colortable) );
+            memcpy( dst_buffer + dst_info->bmiHeader.biSize, default_colortable, sizeof(default_colortable) );
         dib = CreateDIBSection( hdc, dst_info, coloruse, &dst_bits.ptr, 0, 0 );
         if (dib)
         {
             if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
-                memcpy( src_info->bmiColors, default_colortable, sizeof(default_colortable) );
+                memcpy( src_buffer + src_info->bmiHeader.biSize, default_colortable,
+                    sizeof(default_colortable) );
             SetDIBits( hdc, dib, 0, abs(info->bmiHeader.biHeight), bits->ptr, src_info, coloruse );
             dst_bits.free = NULL;
             dst_bits.is_copy = TRUE;
@@ -1518,7 +1546,6 @@ DWORD get_pixmap_image( Pixmap pixmap, int width, int height, const XVisualInfo
 
     if (!format) return ERROR_INVALID_PARAMETER;
 
-    info->bmiHeader.biSize          = sizeof(info->bmiHeader);
     info->bmiHeader.biWidth         = width;
     info->bmiHeader.biHeight        = -height;
     info->bmiHeader.biPlanes        = 1;
@@ -1527,6 +1554,46 @@ DWORD get_pixmap_image( Pixmap pixmap, int width, int height, const XVisualInfo
     info->bmiHeader.biYPelsPerMeter = 0;
     info->bmiHeader.biClrImportant  = 0;
     set_color_info( vis, info, FALSE );
+    if (info->bmiHeader.biSize >= sizeof(BITMAPV4HEADER))
+    {
+        HDC hdc = GetDC( 0 );
+        LOGCOLORSPACEW lcs;
+        BITMAPV4HEADER *v4info = (BITMAPV4HEADER *)&info->bmiHeader;
+
+        if (GetLogColorSpaceW( GetColorSpace( hdc ), &lcs, sizeof(lcs) ))
+        {
+            v4info->bV4CSType = lcs.lcsCSType;
+            v4info->bV4Endpoints = lcs.lcsEndpoints;
+            v4info->bV4GammaRed = lcs.lcsGammaRed;
+            v4info->bV4GammaGreen = lcs.lcsGammaGreen;
+            v4info->bV4GammaBlue = lcs.lcsGammaBlue;
+            if (info->bmiHeader.biSize >= sizeof(BITMAPV5HEADER))
+            {
+                BITMAPV5HEADER *v5info = (BITMAPV5HEADER *)&info->bmiHeader;
+                v5info->bV5Intent = lcs.lcsIntent;
+                v5info->bV5ProfileData = 0;
+                v5info->bV5ProfileSize = 0;
+                v5info->bV5Reserved = 0;
+            }
+        }
+        else
+        {
+            v4info->bV4CSType = LCS_DEVICE_RGB;
+            memset( &v4info->bV4Endpoints, 0, sizeof(v4info->bV4Endpoints) );
+            v4info->bV4GammaRed = 0;
+            v4info->bV4GammaGreen = 0;
+            v4info->bV4GammaBlue = 0;
+            if (info->bmiHeader.biSize >= sizeof(BITMAPV5HEADER))
+            {
+                BITMAPV5HEADER *v5info = (BITMAPV5HEADER *)&info->bmiHeader;
+                v5info->bV5Intent = LCS_GM_GRAPHICS;
+                v5info->bV5ProfileData = 0;
+                v5info->bV5ProfileSize = 0;
+                v5info->bV5Reserved = 0;
+            }
+        }
+        ReleaseDC( 0, hdc );
+    }
 
     if (!bits) return ERROR_SUCCESS;  /* just querying the color information */
 
diff --git a/dlls/winex11.drv/clipboard.c b/dlls/winex11.drv/clipboard.c
index 5dc5e3c..c514a7f 100644
--- a/dlls/winex11.drv/clipboard.c
+++ b/dlls/winex11.drv/clipboard.c
@@ -134,7 +134,9 @@ static HANDLE X11DRV_CLIPBOARD_ImportClipboardData(Display *d, Window w, Atom pr
 static HANDLE X11DRV_CLIPBOARD_ImportEnhMetaFile(Display *d, Window w, Atom prop);
 static HANDLE X11DRV_CLIPBOARD_ImportMetaFilePict(Display *d, Window w, Atom prop);
 static HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(Display *d, Window w, Atom prop);
+static HANDLE X11DRV_CLIPBOARD_ImportV5XAPIXMAP(Display *d, Window w, Atom prop);
 static HANDLE X11DRV_CLIPBOARD_ImportImageBmp(Display *d, Window w, Atom prop);
+static HANDLE X11DRV_CLIPBOARD_ImportImageV5Bmp(Display *d, Window w, Atom prop);
 static HANDLE X11DRV_CLIPBOARD_ImportXAString(Display *d, Window w, Atom prop);
 static HANDLE X11DRV_CLIPBOARD_ImportUTF8(Display *d, Window w, Atom prop);
 static HANDLE X11DRV_CLIPBOARD_ImportCompoundText(Display *d, Window w, Atom prop);
@@ -166,7 +168,7 @@ static BOOL X11DRV_CLIPBOARD_RenderFormat(Display *display, LPWINE_CLIPDATA lpDa
 static HANDLE X11DRV_CLIPBOARD_SerializeMetafile(INT wformat, HANDLE hdata, LPDWORD lpcbytes, BOOL out);
 static BOOL X11DRV_CLIPBOARD_SynthesizeData(UINT wFormatID);
 static BOOL X11DRV_CLIPBOARD_RenderSynthesizedFormat(Display *display, LPWINE_CLIPDATA lpData);
-static BOOL X11DRV_CLIPBOARD_RenderSynthesizedDIB(Display *display);
+static BOOL X11DRV_CLIPBOARD_RenderSynthesizedDIB(Display *display, BOOL isV5);
 static BOOL X11DRV_CLIPBOARD_RenderSynthesizedBitmap(Display *display);
 static BOOL X11DRV_CLIPBOARD_RenderSynthesizedEnhMetaFile(Display *display);
 static void X11DRV_HandleSelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
@@ -191,6 +193,7 @@ static const struct
     { CF_TIFF, XATOM_WCF_TIFF, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
     { CF_OEMTEXT, XATOM_WCF_OEMTEXT, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
     { CF_DIB, XA_PIXMAP, X11DRV_CLIPBOARD_ImportXAPIXMAP, X11DRV_CLIPBOARD_ExportXAPIXMAP },
+    { CF_DIBV5, XA_PIXMAP, X11DRV_CLIPBOARD_ImportV5XAPIXMAP, X11DRV_CLIPBOARD_ExportXAPIXMAP },
     { CF_PALETTE, XATOM_WCF_PALETTE, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
     { CF_PENDATA, XATOM_WCF_PENDATA, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
     { CF_RIFF, XATOM_WCF_RIFF, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
@@ -201,13 +204,13 @@ static const struct
     { CF_ENHMETAFILE, XATOM_WCF_ENHMETAFILE, X11DRV_CLIPBOARD_ImportEnhMetaFile, X11DRV_CLIPBOARD_ExportEnhMetaFile },
     { CF_HDROP, XATOM_text_uri_list, X11DRV_CLIPBOARD_ImportTextUriList, X11DRV_CLIPBOARD_ExportHDROP },
     { CF_LOCALE, XATOM_WCF_LOCALE, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
-    { CF_DIBV5, XATOM_WCF_DIBV5, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
     { CF_OWNERDISPLAY, XATOM_WCF_OWNERDISPLAY, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
     { CF_DSPTEXT, XATOM_WCF_DSPTEXT, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
     { CF_DSPBITMAP, XATOM_WCF_DSPBITMAP, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
     { CF_DSPMETAFILEPICT, XATOM_WCF_DSPMETAFILEPICT, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
     { CF_DSPENHMETAFILE, XATOM_WCF_DSPENHMETAFILE, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
     { CF_DIB, XATOM_image_bmp, X11DRV_CLIPBOARD_ImportImageBmp, X11DRV_CLIPBOARD_ExportImageBmp },
+    { CF_DIBV5, XATOM_image_bmp, X11DRV_CLIPBOARD_ImportImageV5Bmp, X11DRV_CLIPBOARD_ExportImageBmp },
 };
 
 static struct list format_list = LIST_INIT( format_list );
@@ -581,12 +584,14 @@ static void X11DRV_CLIPBOARD_FreeData(LPWINE_CLIPDATA lpData)
         lpData->wFormatID <= CF_GDIOBJLAST) || 
         lpData->wFormatID == CF_BITMAP || 
         lpData->wFormatID == CF_DIB || 
+        lpData->wFormatID == CF_DIBV5 ||
         lpData->wFormatID == CF_PALETTE)
     {
       if (lpData->hData)
 	DeleteObject(lpData->hData);
 
-      if ((lpData->wFormatID == CF_DIB) && lpData->drvData)
+      if ((lpData->wFormatID == CF_DIB || lpData->wFormatID == CF_DIBV5) &&
+          lpData->drvData)
           XFreePixmap(gdi_display, lpData->drvData);
     }
     else if (lpData->wFormatID == CF_METAFILEPICT)
@@ -773,7 +778,8 @@ static BOOL X11DRV_CLIPBOARD_RenderSynthesizedFormat(Display *display, LPWINE_CL
             switch (wFormatID)
 	    {
                 case CF_DIB:
-                    bret = X11DRV_CLIPBOARD_RenderSynthesizedDIB( display );
+                case CF_DIBV5:
+                    bret = X11DRV_CLIPBOARD_RenderSynthesizedDIB( display, wFormatID == CF_DIBV5 );
                     break;
 
                 case CF_BITMAP:
@@ -917,12 +923,38 @@ static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
 }
 
 
+static inline int bitmap_image_stride( int width, int bpp )
+{
+    return ((width * bpp + 31) >> 3) & ~3;
+}
+
+
+/***********************************************************************
+ *           bitmap_image_size
+ *
+ * Return the size of the bitmap's image data.
+ */
+static int bitmap_image_size( const BITMAPINFOHEADER * info )
+{
+    if (info->biSize == sizeof(BITMAPCOREHEADER))
+    {
+        const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
+        return bitmap_image_stride( core->bcWidth, core->bcBitCount ) * core->bcHeight;
+    }
+    else  /* assume BITMAPINFOHEADER */
+    {
+        return info->biSizeImage ? info->biSizeImage :
+            bitmap_image_stride( info->biWidth, info->biBitCount ) * abs( info->biHeight );
+    }
+}
+
+
 /***********************************************************************
  *           create_dib_from_bitmap
  *
  *  Allocates a packed DIB and copies the bitmap data into it.
  */
-static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp)
+static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp, BOOL isV5)
 {
     BITMAP bmp;
     HDC hdc;
@@ -941,7 +973,7 @@ static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp)
 
     /* Calculate the size of the packed DIB */
     cDataSize = abs( bmp.bmHeight ) * (((bmp.bmWidth * bmp.bmBitsPixel + 31) / 8) & ~3);
-    cPackedSize = sizeof(BITMAPINFOHEADER)
+    cPackedSize = isV5 ? sizeof(BITMAPV5HEADER) : sizeof(BITMAPINFOHEADER)
                   + ( (bmp.bmBitsPixel <= 8) ? (sizeof(RGBQUAD) * (1 << bmp.bmBitsPixel)) : 0 )
                   + cDataSize;
     /* Get the offset to the bits */
@@ -961,8 +993,10 @@ static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp)
     pPackedDIB = GlobalLock(hPackedDIB);
     pbmiHeader = (LPBITMAPINFOHEADER)pPackedDIB;
 
+    hdc = GetDC( 0 );
+
     /* Init the BITMAPINFOHEADER */
-    pbmiHeader->biSize = sizeof(BITMAPINFOHEADER);
+    pbmiHeader->biSize = isV5 ? sizeof(BITMAPV5HEADER) : sizeof(BITMAPINFOHEADER);
     pbmiHeader->biWidth = bmp.bmWidth;
     pbmiHeader->biHeight = bmp.bmHeight;
     pbmiHeader->biPlanes = 1;
@@ -972,10 +1006,37 @@ static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp)
     pbmiHeader->biXPelsPerMeter = pbmiHeader->biYPelsPerMeter = 0;
     pbmiHeader->biClrUsed = 0;
     pbmiHeader->biClrImportant = 0;
+    if (isV5)
+    {
+        LOGCOLORSPACEW lcs;
+        BITMAPV5HEADER *pbV5Header = (BITMAPV5HEADER *)pbmiHeader;
+
+        pbV5Header->bV5AlphaMask = 0;
+        if (GetLogColorSpaceW( GetColorSpace( hdc ), &lcs, sizeof(lcs) ))
+        {
+            pbV5Header->bV5CSType = lcs.lcsCSType;
+            pbV5Header->bV5Endpoints = lcs.lcsEndpoints;
+            pbV5Header->bV5GammaRed = lcs.lcsGammaRed;
+            pbV5Header->bV5GammaGreen = lcs.lcsGammaGreen;
+            pbV5Header->bV5GammaBlue = lcs.lcsGammaBlue;
+            pbV5Header->bV5Intent = lcs.lcsIntent;
+        }
+        else
+        {
+            pbV5Header->bV5CSType = LCS_DEVICE_RGB;
+            memset( &pbV5Header->bV5Endpoints, 0, sizeof(pbV5Header->bV5Endpoints) );
+            pbV5Header->bV5GammaRed = 0;
+            pbV5Header->bV5GammaGreen = 0;
+            pbV5Header->bV5GammaBlue = 0;
+            pbV5Header->bV5Intent = LCS_GM_GRAPHICS;
+        }
+        pbV5Header->bV5ProfileData = 0;
+        pbV5Header->bV5ProfileSize = 0;
+        pbV5Header->bV5Reserved = 0;
+    }
 
     /* Retrieve the DIB bits from the bitmap and fill in the
      * DIB color table if present */
-    hdc = GetDC( 0 );
     nLinesCopied = GetDIBits(hdc,                       /* Handle to device context */
                              hBmp,                      /* Handle to bitmap */
                              0,                         /* First scan line to set in dest bitmap */
@@ -1086,17 +1147,209 @@ static WCHAR* uri_to_dos(char *encodedURI)
  *
  * Renders synthesized DIB
  */
-static BOOL X11DRV_CLIPBOARD_RenderSynthesizedDIB(Display *display)
+static BOOL X11DRV_CLIPBOARD_RenderSynthesizedDIB(Display *display, BOOL isV5)
 {
     BOOL bret = FALSE;
     LPWINE_CLIPDATA lpSource = NULL;
+    UINT cf = isV5 ? CF_DIBV5 : CF_DIB;
 
     TRACE("\n");
 
-    if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIB)) && lpSource->hData)
+    if ((lpSource = X11DRV_CLIPBOARD_LookupData(cf)) && lpSource->hData)
     {
         bret = TRUE;
     }
+    /* If we have a V3/V4 DIB and it's not synthesized or it has been rendered */
+    else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIB)) && isV5 &&
+        (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData))
+    {
+        /* Render source if required */
+        if (lpSource->hData || X11DRV_CLIPBOARD_RenderFormat(display, lpSource))
+        {
+            BITMAPINFOHEADER *bmih = GlobalLock(lpSource->hData);
+            if (bmih)
+            {
+                size_t imgsize = bitmap_image_size( bmih );
+                unsigned int colors, bpp;
+                if (bmih->biSize == sizeof(BITMAPCOREHEADER))
+                {
+                    bpp = ((BITMAPCOREHEADER *)bmih)->bcBitCount;
+                    colors = 1 << bpp;
+                }
+                else
+                {
+                    bpp = bmih->biBitCount;
+                    colors = bmih->biClrUsed;
+                }
+                HGLOBAL data = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, sizeof(BITMAPV5HEADER) +
+                    (bpp <= 8 ? sizeof(RGBQUAD) * colors : 0) +
+                    imgsize);
+
+                if (data)
+                {
+                    /* Convert to a V5 DIB */
+                    BITMAPV5HEADER *bV5 = GlobalLock(data);
+                    if (bV5)
+                    {
+                        BYTE *srcbits = (BYTE *)bmih + bmih->biSize;
+                        BYTE *destbits = (BYTE *)(bV5 + 1);
+
+                        if (bmih->biSize == sizeof(BITMAPCOREHEADER))
+                        {
+                            /* Due to an impedance mismatch between BITMAPCOREHEADER and
+                             * BITMAPV5HEADER, the fields need to be copied manually. And yes,
+                             * Windows really does support this.
+                             */
+                            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 = imgsize;
+                            bV5->bV5XPelsPerMeter = 0;
+                            bV5->bV5YPelsPerMeter = 0;
+                            bV5->bV5ClrUsed = bch->bcBitCount <= 8 ? colors : 0;
+                            bV5->bV5ClrImportant = 0;
+                        }
+                        else
+                            memcpy(bV5, bmih, min(bmih->biSize, sizeof(BITMAPV5HEADER)));
+                        if (bmih->biSize < sizeof(BITMAPV5HEADER))
+                        {
+                            HDC hdc = GetDC(0);
+                            LOGCOLORSPACEW lcs;
+
+                            if (GetLogColorSpaceW(GetColorSpace(hdc), &lcs, sizeof(lcs)))
+                            {
+                                if (sizeof(BITMAPV4HEADER) > bmih->biSize)
+                                {
+                                    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))
+                                {
+                                    memset(&bV5->bV5RedMask, 0,
+                                           sizeof(BITMAPV5HEADER) - sizeof(BITMAPINFOHEADER));
+                                    bV5->bV5CSType = LCS_DEVICE_RGB;
+                                }
+                                bV5->bV5Intent = LCS_GM_GRAPHICS;
+                            }
+                            ReleaseDC(0, hdc);
+                        }
+                        bV5->bV5Size = sizeof(BITMAPV5HEADER);
+                        if (bmih->biSize < sizeof(BITMAPV4HEADER) &&
+                            bV5->bV5Compression == BI_BITFIELDS)
+                        {
+                            /* These aren't part of the V3 BITMAPINFOHEADER. */
+                            DWORD *masks = (DWORD *)(bmih+1);
+
+                            bV5->bV5RedMask = masks[0];
+                            bV5->bV5GreenMask = masks[1];
+                            bV5->bV5BlueMask = masks[2];
+                            if (bmih->biSize == sizeof(BITMAPINFOHEADER))
+                                srcbits += 3 * sizeof(DWORD);
+                        }
+                        if (bV5->bV5BitCount <= 8)
+                        {
+                            if (bmih->biSize == sizeof(BITMAPCOREHEADER))
+                            {
+                                /* Another impedance mismatch. The DIB format really changed a lot
+                                 * between OS/2 and Windows 3.0.
+                                 */
+                                RGBTRIPLE *srcpal = (RGBTRIPLE *)srcbits;
+                                RGBQUAD *destpal = (RGBQUAD *)destbits;
+                                int i;
+
+                                for (i = 0; i < bV5->bV5ClrUsed; ++i)
+                                {
+                                    destpal[i].rgbRed = srcpal[i].rgbtRed;
+                                    destpal[i].rgbGreen = srcpal[i].rgbtGreen;
+                                    destpal[i].rgbBlue = srcpal[i].rgbtBlue;
+                                    destpal[i].rgbReserved = 0;
+                                }
+                                srcbits += sizeof(RGBTRIPLE) * bV5->bV5ClrUsed;
+                            }
+                            else
+                            {
+                                memcpy(destbits, srcbits, sizeof(RGBQUAD) * bV5->bV5ClrUsed);
+                                srcbits += sizeof(RGBQUAD) * bV5->bV5ClrUsed;
+                            }
+                            destbits += sizeof(RGBQUAD) * bV5->bV5ClrUsed;
+                        }
+                        memcpy(destbits, srcbits, imgsize);
+                        GlobalUnlock(data);
+                        X11DRV_CLIPBOARD_InsertClipboardData(cf, data, 0, NULL, TRUE);
+                        bret = TRUE;
+                    }
+                    else
+                        GlobalFree(data);
+                }
+                GlobalUnlock(lpSource->hData);
+            }
+        }
+    }
+    /* If we have a V5 DIB and it's not synthesized or it has been rendered */
+    else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIBV5)) && !isV5 &&
+        (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData))
+    {
+        /* Render source if required */
+        if (lpSource->hData || X11DRV_CLIPBOARD_RenderFormat(display, lpSource))
+        {
+            BITMAPV5HEADER *bV5 = (BITMAPV5HEADER *)GlobalLock(lpSource->hData);
+            if (bV5)
+            {
+                size_t imgsize = bitmap_image_size( (BITMAPINFOHEADER *)bV5 );
+                HGLOBAL data = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, sizeof(BITMAPINFOHEADER) +
+                    (bV5->bV5Compression == BI_BITFIELDS ? 3 * sizeof(DWORD) : 0) +
+                    (bV5->bV5BitCount <= 8 ? sizeof(RGBQUAD) * bV5->bV5ClrUsed : 0) +
+                    imgsize);
+
+                if (data)
+                {
+                    /* Convert to a V3 DIB */
+                    BITMAPINFOHEADER *bmih = (BITMAPINFOHEADER *)GlobalLock(data);
+                    if (bmih)
+                    {
+                        BYTE *srcbits = (BYTE *)bV5 + bV5->bV5Size;
+                        BYTE *destbits = (BYTE *)bmih + sizeof(BITMAPINFOHEADER);
+
+                        memcpy(bmih, bV5, sizeof(BITMAPINFOHEADER));
+                        bmih->biSize = sizeof(BITMAPINFOHEADER);
+                        if (bmih->biCompression == BI_BITFIELDS)
+                        {
+                            /* These aren't part of the V3 BITMAPINFOHEADER. */
+                            DWORD *masks = (DWORD *)destbits;
+                            masks[0] = bV5->bV5RedMask;
+                            masks[1] = bV5->bV5GreenMask;
+                            masks[2] = bV5->bV5BlueMask;
+                            destbits += 3 * sizeof(DWORD);
+                        }
+                        if (bmih->biBitCount <= 8)
+                        {
+                            memcpy(destbits, srcbits, sizeof(RGBQUAD) * bmih->biClrUsed);
+                            srcbits += sizeof(RGBQUAD) * bmih->biClrUsed;
+                            destbits += sizeof(RGBQUAD) * bmih->biClrUsed;
+                        }
+                        memcpy(destbits, srcbits, imgsize);
+                        GlobalUnlock(data);
+                        X11DRV_CLIPBOARD_InsertClipboardData(cf, data, 0, NULL, TRUE);
+                        bret = TRUE;
+                    }
+                    else
+                        GlobalFree(data);
+                }
+                GlobalUnlock(lpSource->hData);
+            }
+        }
+    }
     /* If we have a bitmap and it's not synthesized or it has been rendered */
     else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_BITMAP)) &&
         (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData))
@@ -1104,10 +1357,10 @@ static BOOL X11DRV_CLIPBOARD_RenderSynthesizedDIB(Display *display)
         /* Render source if required */
         if (lpSource->hData || X11DRV_CLIPBOARD_RenderFormat(display, lpSource))
         {
-            HGLOBAL hData = create_dib_from_bitmap( lpSource->hData );
+            HGLOBAL hData = create_dib_from_bitmap( lpSource->hData, isV5 );
             if (hData)
             {
-                X11DRV_CLIPBOARD_InsertClipboardData(CF_DIB, hData, 0, NULL, TRUE);
+                X11DRV_CLIPBOARD_InsertClipboardData(cf, hData, 0, NULL, TRUE);
                 bret = TRUE;
             }
         }
@@ -1149,7 +1402,7 @@ static BOOL X11DRV_CLIPBOARD_RenderSynthesizedBitmap(Display *display)
             lpbmih = GlobalLock(lpSource->hData);
             if (lpbmih)
             {
-                offset = sizeof(BITMAPINFOHEADER)
+                offset = lpbmih->biSize
                       + ((lpbmih->biBitCount <= 8) ? (sizeof(RGBQUAD) *
                         (1 << lpbmih->biBitCount)) : 0);
 
@@ -1167,6 +1420,39 @@ static BOOL X11DRV_CLIPBOARD_RenderSynthesizedBitmap(Display *display)
             }
         }
     }
+    else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIBV5)) &&
+        (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData))
+    {
+        /* Render source if required */
+        if (lpSource->hData || X11DRV_CLIPBOARD_RenderFormat(display, lpSource))
+        {
+            HDC hdc;
+            HBITMAP hData = NULL;
+            unsigned int offset;
+            LPBITMAPV5HEADER lpbmih;
+
+            hdc = GetDC(NULL);
+            lpbmih = GlobalLock(lpSource->hData);
+            if (lpbmih)
+            {
+                offset = lpbmih->bV5Size
+                      + ((lpbmih->bV5BitCount <= 8) ? (sizeof(RGBQUAD) *
+                        lpbmih->bV5ClrUsed) : 0);
+
+                hData = CreateDIBitmap(hdc, (BITMAPINFOHEADER *) lpbmih, CBM_INIT, (LPBYTE)lpbmih +
+                    offset, (LPBITMAPINFO) lpbmih, DIB_RGB_COLORS);
+
+                GlobalUnlock(lpSource->hData);
+            }
+            ReleaseDC(NULL, hdc);
+
+            if (hData)
+            {
+                X11DRV_CLIPBOARD_InsertClipboardData(CF_BITMAP, hData, 0, NULL, TRUE);
+                bret = TRUE;
+            }
+        }
+    }
 
     return bret;
 }
@@ -1382,11 +1668,11 @@ static HANDLE X11DRV_CLIPBOARD_ImportCompoundText(Display *display, Window w, At
 
 
 /**************************************************************************
- *		X11DRV_CLIPBOARD_ImportXAPIXMAP
+ *		import_pixmap_to_dib
  *
- *  Import XA_PIXMAP, converting the image to CF_DIB.
+ *  Import XA_PIXMAP, converting the image to either CF_DIB or CF_DIBV5.
  */
-static HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(Display *display, Window w, Atom prop)
+static HANDLE import_pixmap_to_dib(Display *display, Window w, Atom prop, BOOL isV5)
 {
     LPBYTE lpdata;
     unsigned long cbytes;
@@ -1396,7 +1682,7 @@ static HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(Display *display, Window w, Atom p
     if (X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
     {
         XVisualInfo vis = default_visual;
-        char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
+        char buffer[sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD)];
         BITMAPINFO *info = (BITMAPINFO *)buffer;
         struct gdi_image_bits bits;
         Window root;
@@ -1434,6 +1720,7 @@ static HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(Display *display, Window w, Atom p
         default:
             return 0;
         }
+        info->bmiHeader.biSize = isV5 ? sizeof(BITMAPV5HEADER) : sizeof(BITMAPINFOHEADER);
 
         if (!get_pixmap_image( *pPixmap, width, height, &vis, info, &bits ))
         {
@@ -1460,11 +1747,33 @@ static HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(Display *display, Window w, Atom p
 
 
 /**************************************************************************
- *		X11DRV_CLIPBOARD_ImportImageBmp
+ *		X11DRV_CLIPBOARD_ImportXAPIXMAP
  *
- *  Import image/bmp, converting the image to CF_DIB.
+ *  Import XA_PIXMAP, converting the image to CF_DIB.
  */
-static HANDLE X11DRV_CLIPBOARD_ImportImageBmp(Display *display, Window w, Atom prop)
+static HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(Display *display, Window w, Atom prop)
+{
+    return import_pixmap_to_dib( display, w, prop, FALSE );
+}
+
+
+/**************************************************************************
+ *		X11DRV_CLIPBOARD_ImportV5XAPIXMAP
+ *
+ *  Import XA_PIXMAP, converting the image to CF_DIBV5.
+ */
+static HANDLE X11DRV_CLIPBOARD_ImportV5XAPIXMAP(Display *display, Window w, Atom prop)
+{
+    return import_pixmap_to_dib( display, w, prop, TRUE );
+}
+
+
+/**************************************************************************
+ *		import_bmp_to_dib
+ *
+ *  Import image/bmp, converting the image to either CF_DIB or CF_DIBV5.
+ */
+static HANDLE import_bmp_to_dib(Display *display, Window w, Atom prop, BOOL isV5)
 {
     LPBYTE lpdata;
     unsigned long cbytes;
@@ -1491,7 +1800,7 @@ static HANDLE X11DRV_CLIPBOARD_ImportImageBmp(Display *display, Window w, Atom p
                 DIB_RGB_COLORS
                 );
 
-            hClipData = create_dib_from_bitmap( hbmp );
+            hClipData = create_dib_from_bitmap( hbmp, isV5 );
 
             DeleteObject(hbmp);
             ReleaseDC(0, hdc);
@@ -1505,6 +1814,16 @@ static HANDLE X11DRV_CLIPBOARD_ImportImageBmp(Display *display, Window w, Atom p
 }
 
 
+static HANDLE X11DRV_CLIPBOARD_ImportImageBmp(Display *display, Window w, Atom prop)
+{
+    return import_bmp_to_dib(display, w, prop, FALSE);
+}
+
+static HANDLE X11DRV_CLIPBOARD_ImportImageV5Bmp(Display *display, Window w, Atom prop)
+{
+    return import_bmp_to_dib(display, w, prop, TRUE);
+}
+
 /**************************************************************************
  *		X11DRV_CLIPBOARD_ImportMetaFilePict
  *
@@ -3201,15 +3520,14 @@ static BOOL X11DRV_CLIPBOARD_SynthesizeData(UINT wFormatID)
         bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_ENHMETAFILE)) &&
             ~lpSource->wFlags & CF_FLAG_SYNTHESIZED;
     }
-    else if (wFormatID == CF_DIB)
+    else if (wFormatID == CF_BITMAP || wFormatID == CF_DIB || wFormatID == CF_DIBV5)
     {
-        bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_BITMAP)) &&
-            ~lpSource->wFlags & CF_FLAG_SYNTHESIZED;
-    }
-    else if (wFormatID == CF_BITMAP)
-    {
-        bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIB)) &&
-            ~lpSource->wFlags & CF_FLAG_SYNTHESIZED;
+        bsyn = ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_BITMAP)) &&
+            ~lpSource->wFlags & CF_FLAG_SYNTHESIZED) ||
+            ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIB)) &&
+            ~lpSource->wFlags & CF_FLAG_SYNTHESIZED) ||
+            ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIBV5)) &&
+            ~lpSource->wFlags & CF_FLAG_SYNTHESIZED);
     }
 
     if (bsyn)
@@ -3239,8 +3557,9 @@ void CDECL X11DRV_EndClipboardUpdate(void)
     X11DRV_CLIPBOARD_SynthesizeData(CF_METAFILEPICT);
 
     /* DIB <-> Bitmap mapping */
-    X11DRV_CLIPBOARD_SynthesizeData(CF_DIB);
     X11DRV_CLIPBOARD_SynthesizeData(CF_BITMAP);
+    X11DRV_CLIPBOARD_SynthesizeData(CF_DIB);
+    X11DRV_CLIPBOARD_SynthesizeData(CF_DIBV5);
 
     TRACE("%d formats added to cached data\n", ClipDataCount - count);
 }
-- 
2.8.1




More information about the wine-patches mailing list