From 9a652e211c06d1a139f6105173a523450dbf9e05 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 7 Sep 2016 11:35:02 +0900 Subject: [PATCH] user32: Synthesize bitmap clipboard formats on the user32 side. Signed-off-by: Alexandre Julliard --- dlls/user32/clipboard.c | 122 ++++++++++++++++++++++++++++++++++++++---- dlls/user32/cursoricon.c | 2 +- dlls/user32/tests/clipboard.c | 18 ++----- dlls/user32/user_private.h | 1 + 4 files changed, 119 insertions(+), 24 deletions(-) diff --git a/dlls/user32/clipboard.c b/dlls/user32/clipboard.c index 0fe5631e031..72f73345dc3 100644 --- a/dlls/user32/clipboard.c +++ b/dlls/user32/clipboard.c @@ -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(); } diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c index 2b923073ec0..a1fd0735073 100644 --- a/dlls/user32/cursoricon.c +++ b/dlls/user32/cursoricon.c @@ -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; diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c index 4c003616878..da2163bbb9d 100644 --- a/dlls/user32/tests/clipboard.c +++ b/dlls/user32/tests/clipboard.c @@ -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; diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 68aa6999eb2..c8b283a0d07 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -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 */ -- 2.11.4.GIT