user32: Synthesize bitmap clipboard formats on the user32 side.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2016-09-07 11:35:02 +09:00
parent 1993898459
commit 9a652e211c
4 changed files with 119 additions and 24 deletions

View File

@ -2,9 +2,10 @@
* WIN32 clipboard implementation
*
* Copyright 1994 Martin Ayotte
* 1996 Alex Korobka
* 1999 Noel Borthwick
* 2003 Ulrich Czekalla for CodeWeavers
* Copyright 1996 Alex Korobka
* Copyright 1999 Noel Borthwick
* Copyright 2003 Ulrich Czekalla for CodeWeavers
* Copyright 2016 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -20,13 +21,6 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* NOTES:
* This file contains the implementation for the WIN32 Clipboard API
* and Wine's internal clipboard cache.
* The actual contents of the clipboard are held in the clipboard cache.
* The internal implementation talks to a "clipboard driver" to fill or
* expose the cache to the native device. (Currently only the X11 and
* TTY clipboard driver are available)
*/
#include "config.h"
@ -140,6 +134,33 @@ static void add_synthesized_text(void)
}
}
/* add synthesized bitmap formats based on what is already in the clipboard */
static void add_synthesized_bitmap(void)
{
BOOL has_dib = IsClipboardFormatAvailable( CF_DIB );
BOOL has_dibv5 = IsClipboardFormatAvailable( CF_DIBV5 );
BOOL has_bitmap = IsClipboardFormatAvailable( CF_BITMAP );
if (!has_bitmap && !has_dib && !has_dibv5) return; /* nothing to do */
if (has_bitmap && has_dib && has_dibv5) return; /* nothing to synthesize */
if (has_bitmap)
{
if (!has_dib) add_synthesized_format( CF_DIB, CF_BITMAP );
if (!has_dibv5) add_synthesized_format( CF_DIBV5, CF_BITMAP );
}
else if (has_dib)
{
if (!has_bitmap) add_synthesized_format( CF_BITMAP, CF_DIB );
if (!has_dibv5) add_synthesized_format( CF_DIBV5, CF_DIB );
}
else
{
if (!has_bitmap) add_synthesized_format( CF_BITMAP, CF_DIBV5 );
if (!has_dib) add_synthesized_format( CF_DIB, CF_DIBV5 );
}
}
/* add synthesized metafile formats based on what is already in the clipboard */
static void add_synthesized_metafile(void)
{
@ -200,6 +221,79 @@ static HANDLE render_synthesized_textW( HANDLE data, UINT from )
return ret;
}
/* render a synthesized bitmap based on the DIB clipboard data */
static HANDLE render_synthesized_bitmap( HANDLE data, UINT from )
{
BITMAPINFO *bmi;
HANDLE ret = 0;
HDC hdc = GetDC( 0 );
if ((bmi = GlobalLock( data )))
{
/* FIXME: validate data size */
ret = CreateDIBitmap( hdc, &bmi->bmiHeader, CBM_INIT,
(char *)bmi + bitmap_info_size( bmi, DIB_RGB_COLORS ),
bmi, DIB_RGB_COLORS );
GlobalUnlock( data );
}
ReleaseDC( 0, hdc );
return ret;
}
/* render a synthesized DIB based on the clipboard data */
static HANDLE render_synthesized_dib( HANDLE data, UINT format, UINT from )
{
BITMAPINFO *bmi, *src;
DWORD src_size, header_size, bits_size;
HANDLE ret = 0;
HDC hdc = GetDC( 0 );
if (from == CF_BITMAP)
{
BITMAP bmp;
if (!GetObjectW( data, sizeof(bmp), &bmp )) goto done;
bits_size = abs( bmp.bmHeight ) * (((bmp.bmWidth * bmp.bmBitsPixel + 31) / 8) & ~3);
if (bmp.bmBitsPixel <= 8)
header_size = offsetof( BITMAPINFO, bmiColors[1 << bmp.bmBitsPixel] );
else
header_size = (format == CF_DIBV5) ? sizeof(BITMAPV5HEADER) : sizeof(BITMAPINFOHEADER);
if (!(ret = GlobalAlloc( GMEM_FIXED, header_size + bits_size ))) goto done;
bmi = (BITMAPINFO *)ret;
memset( bmi, 0, header_size );
bmi->bmiHeader.biSize = header_size;
bmi->bmiHeader.biWidth = bmp.bmWidth;
bmi->bmiHeader.biHeight = bmp.bmHeight;
bmi->bmiHeader.biPlanes = 1;
bmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
bmi->bmiHeader.biCompression = BI_RGB;
GetDIBits( hdc, data, 0, bmp.bmHeight, (char *)bmi + header_size, bmi, DIB_RGB_COLORS );
}
else
{
if (!(src = GlobalLock( data ))) goto done;
src_size = bitmap_info_size( src, DIB_RGB_COLORS );
bits_size = GlobalSize( data ) - src_size;
header_size = (format == CF_DIBV5) ? sizeof(BITMAPV5HEADER) :
offsetof( BITMAPINFO, bmiColors[src->bmiHeader.biCompression == BI_BITFIELDS ? 3 : 0] );
if (!(ret = GlobalAlloc( GMEM_FIXED, header_size + bits_size ))) goto done;
bmi = (BITMAPINFO *)ret;
memset( bmi, 0, header_size );
memcpy( bmi, src, min( header_size, src_size ));
bmi->bmiHeader.biSize = header_size;
/* FIXME: convert colors according to DIBv5 color profile */
memcpy( (char *)bmi + header_size, (char *)src + src_size, bits_size );
}
done:
ReleaseDC( 0, hdc );
return ret;
}
/* render a synthesized metafile based on the enhmetafile clipboard data */
static HANDLE render_synthesized_metafile( HANDLE data )
{
@ -268,6 +362,13 @@ static HANDLE render_synthesized_format( UINT format, UINT from )
case CF_UNICODETEXT:
data = render_synthesized_textW( data, from );
break;
case CF_BITMAP:
data = render_synthesized_bitmap( data, from );
break;
case CF_DIB:
case CF_DIBV5:
data = render_synthesized_dib( data, format, from );
break;
case CF_METAFILEPICT:
data = render_synthesized_metafile( data );
break;
@ -405,6 +506,7 @@ BOOL WINAPI CloseClipboard(void)
{
memset( synthesized_formats, 0, sizeof(synthesized_formats) );
add_synthesized_text();
add_synthesized_bitmap();
add_synthesized_metafile();
}

View File

@ -306,7 +306,7 @@ static int get_dib_image_size( int width, int height, int depth )
*
* Return the size of the bitmap info structure including color table.
*/
static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
{
unsigned int colors, size, masks = 0;

View File

@ -585,7 +585,6 @@ static void test_synthesized(void)
{
UINT format;
UINT expected[8];
UINT todo;
} tests[] =
{
/* 0 */ { CF_TEXT, { CF_TEXT, CF_LOCALE, CF_OEMTEXT, CF_UNICODETEXT }},
@ -593,9 +592,9 @@ static void test_synthesized(void)
{ CF_UNICODETEXT, { CF_UNICODETEXT, CF_LOCALE, CF_TEXT, CF_OEMTEXT }},
{ CF_ENHMETAFILE, { CF_ENHMETAFILE, CF_METAFILEPICT }},
{ CF_METAFILEPICT, { CF_METAFILEPICT, CF_ENHMETAFILE }},
/* 5 */ { CF_BITMAP, { CF_BITMAP, CF_DIB, CF_DIBV5 }, 1 << 2 },
{ CF_DIB, { CF_DIB, CF_BITMAP, CF_DIBV5 }, 1 << 2 },
{ CF_DIBV5, { CF_DIBV5, CF_BITMAP, CF_DIB }, (1 << 1) | (1 << 2) },
/* 5 */ { CF_BITMAP, { CF_BITMAP, CF_DIB, CF_DIBV5 }},
{ CF_DIB, { CF_DIB, CF_BITMAP, CF_DIBV5 }},
{ CF_DIBV5, { CF_DIBV5, CF_BITMAP, CF_DIB }},
};
HGLOBAL h, htext;
@ -739,10 +738,8 @@ static void test_synthesized(void)
for (j = 0; tests[i].expected[j]; j++)
{
r = IsClipboardFormatAvailable( tests[i].expected[j] );
todo_wine_if (tests[i].todo & (1 << j))
ok( r, "%u: %04x not available\n", i, tests[i].expected[j] );
}
todo_wine_if (tests[i].todo)
ok( count == j, "%u: count %u instead of %u\n", i, count, j );
r = OpenClipboard( hwnd );
@ -751,7 +748,6 @@ static void test_synthesized(void)
for (j = 0; tests[i].expected[j]; j++)
{
cf = EnumClipboardFormats( cf );
todo_wine_if (tests[i].todo & (1 << j))
ok(cf == tests[i].expected[j], "%u.%u: got %04x instead of %04x\n",
i, j, cf, tests[i].expected[j] );
if (cf != tests[i].expected[j]) break;
@ -799,10 +795,8 @@ static void test_synthesized(void)
for (j = 0; tests[i].expected[j]; j++)
{
r = IsClipboardFormatAvailable( tests[i].expected[j] );
todo_wine_if (tests[i].todo & (1 << j))
ok( r, "%u: %04x not available\n", i, tests[i].expected[j] );
}
todo_wine_if (tests[i].todo)
ok( count == j, "%u: count %u instead of %u\n", i, count, j );
rendered = SendMessageA( hwnd, WM_USER, 0, 0 );
ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered );
@ -813,7 +807,6 @@ static void test_synthesized(void)
for (j = 0; tests[i].expected[j]; j++)
{
cf = EnumClipboardFormats( cf );
todo_wine_if (tests[i].todo & (1 << j))
ok(cf == tests[i].expected[j], "%u.%u: got %04x instead of %04x\n",
i, j, cf, tests[i].expected[j] );
if (cf != tests[i].expected[j]) break;
@ -834,7 +827,6 @@ static void test_synthesized(void)
/* try to render a second time */
data = GetClipboardData( cf );
rendered = SendMessageA( hwnd, WM_USER, 0, 0 );
todo_wine_if( i > 4 && j == 1 )
ok( rendered == (1 << tests[i].format),
"%u.%u: formats %08x have been rendered\n", i, j, rendered );
}
@ -1707,7 +1699,7 @@ static void test_handles( HWND hwnd )
data = GetClipboardData( CF_DIB );
ok( is_fixed( data ), "expected fixed mem %p\n", data );
data = GetClipboardData( CF_DIBV5 );
todo_wine ok( is_fixed( data ), "expected fixed mem %p\n", data );
ok( is_fixed( data ), "expected fixed mem %p\n", data );
ok( GetObjectType( bitmap ) == OBJ_BITMAP, "expected bitmap %p\n", bitmap );
ok( GetObjectType( bitmap2 ) == OBJ_BITMAP, "expected bitmap %p\n", bitmap2 );
@ -1776,7 +1768,7 @@ static DWORD WINAPI test_handles_thread2( void *arg )
h = GetClipboardData( CF_DIB );
ok( is_fixed( h ), "expected fixed mem %p\n", h );
h = GetClipboardData( CF_DIBV5 );
todo_wine ok( is_fixed( h ), "expected fixed mem %p\n", h );
ok( is_fixed( h ), "expected fixed mem %p\n", h );
r = CloseClipboard();
ok( r, "gle %d\n", GetLastError() );
return 0;

View File

@ -343,6 +343,7 @@ typedef struct
#include "poppack.h"
extern int bitmap_info_size( const BITMAPINFO * info, WORD coloruse ) DECLSPEC_HIDDEN;
extern BOOL get_icon_size( HICON handle, SIZE *size ) DECLSPEC_HIDDEN;
/* Mingw's assert() imports MessageBoxA and gets confused by user32 exporting it */