gdi32: If possible use the GetImage driver entry to fill the colour table for GetDIBits.

This commit is contained in:
Huw Davies 2011-08-04 12:38:33 +01:00 committed by Alexandre Julliard
parent d947f6ef08
commit b94616864d
2 changed files with 75 additions and 116 deletions

View File

@ -881,14 +881,16 @@ INT WINAPI GetDIBits(
{ {
DC * dc; DC * dc;
BITMAPOBJ * bmp; BITMAPOBJ * bmp;
int i, ret = 0; int i, dst_to_src_offset, ret = 0;
LONG width; DWORD err;
LONG height;
WORD bpp;
char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf; BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
unsigned int colors = 0; char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
const struct gdi_dc_funcs *funcs; const struct gdi_dc_funcs *funcs;
struct gdi_image_bits src_bits;
struct bitblt_coords src, dst;
BOOL empty_rect = FALSE;
/* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our
own copy and transfer the colour info back at the end */ own copy and transfer the colour info back at the end */
@ -911,90 +913,12 @@ INT WINAPI GetDIBits(
funcs = bmp->funcs; funcs = bmp->funcs;
if (bmp->dib) funcs = dc->dibdrv.dev.funcs; if (bmp->dib) funcs = dc->dibdrv.dev.funcs;
width = dst_info->bmiHeader.biWidth; if (dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */
height = dst_info->bmiHeader.biHeight;
bpp = dst_info->bmiHeader.biBitCount;
if (bpp == 0) /* query bitmap info only */
{ {
ret = fill_query_info( info, bmp ); ret = fill_query_info( info, bmp );
goto done; goto done;
} }
switch (bpp)
{
case 1:
case 4:
case 8:
{
colors = 1 << bpp;
/* If the bitmap object is a dib section at the
same color depth then get the color map from it */
if (bmp->dib && bpp == bmp->dib->dsBm.bmBitsPixel && coloruse == DIB_RGB_COLORS)
{
colors = min( colors, bmp->nb_colors );
if (colors != 1 << bpp) dst_info->bmiHeader.biClrUsed = colors;
memcpy( dst_info->bmiColors, bmp->color_table, colors * sizeof(RGBQUAD) );
}
/* For color DDBs in native depth (mono DDBs always have a black/white palette):
Generate the color map from the selected palette. In the DIB_PAL_COLORS
case we'll fix up the indices after the format conversion. */
else if ( (bpp > 1 && bpp == bmp->bitmap.bmBitsPixel) || coloruse == DIB_PAL_COLORS )
{
if (!fill_color_table_from_palette( dst_info, dc ))
{
lines = 0;
goto done;
}
}
else
fill_default_color_table( dst_info );
break;
}
case 15:
if (dst_info->bmiHeader.biCompression == BI_BITFIELDS)
memcpy( dst_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
break;
case 16:
if (dst_info->bmiHeader.biCompression == BI_BITFIELDS)
{
if (bmp->dib)
{
if (bmp->dib->dsBmih.biCompression == BI_BITFIELDS && bmp->dib->dsBmih.biBitCount == bpp)
memcpy( dst_info->bmiColors, bmp->dib->dsBitfields, 3 * sizeof(DWORD) );
else
memcpy( dst_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
}
else
memcpy( dst_info->bmiColors, bit_fields_565, sizeof(bit_fields_565) );
}
break;
case 24:
case 32:
if (dst_info->bmiHeader.biCompression == BI_BITFIELDS)
{
if (bmp->dib && bmp->dib->dsBmih.biCompression == BI_BITFIELDS && bmp->dib->dsBmih.biBitCount == bpp)
memcpy( dst_info->bmiColors, bmp->dib->dsBitfields, 3 * sizeof(DWORD) );
else
memcpy( dst_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
}
break;
}
if (bits && lines)
{
char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
struct gdi_image_bits src_bits;
struct bitblt_coords src, dst;
DWORD err;
int dst_to_src_offset;
BOOL empty_rect;
src.visrect.left = 0; src.visrect.left = 0;
src.visrect.top = 0; src.visrect.top = 0;
src.visrect.right = bmp->bitmap.bmWidth; src.visrect.right = bmp->bitmap.bmWidth;
@ -1005,12 +929,11 @@ INT WINAPI GetDIBits(
dst.visrect.right = dst_info->bmiHeader.biWidth; dst.visrect.right = dst_info->bmiHeader.biWidth;
dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight ); dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight );
if (startscan >= dst.visrect.bottom) if (lines == 0 || startscan >= dst.visrect.bottom)
{ bits = NULL;
ret = 1; /* yes, this is strange */
goto empty_image;
}
if (bits)
{
if (dst_info->bmiHeader.biHeight > 0) if (dst_info->bmiHeader.biHeight > 0)
{ {
dst_to_src_offset = -startscan; dst_to_src_offset = -startscan;
@ -1038,7 +961,7 @@ INT WINAPI GetDIBits(
if (dst.visrect.bottom < dst_info->bmiHeader.biHeight) if (dst.visrect.bottom < dst_info->bmiHeader.biHeight)
{ {
int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines ); int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines );
int pad_bytes = pad_lines * get_dib_stride( width, bpp ); int pad_bytes = pad_lines * get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
memset( bits, 0, pad_bytes ); memset( bits, 0, pad_bytes );
bits = (char *)bits + pad_bytes; bits = (char *)bits + pad_bytes;
} }
@ -1047,33 +970,71 @@ INT WINAPI GetDIBits(
{ {
if (dst.visrect.bottom < lines) if (dst.visrect.bottom < lines)
{ {
int pad_lines = lines - dst.visrect.bottom, stride = get_dib_stride( width, bpp ); int pad_lines = lines - dst.visrect.bottom;
int stride = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
int pad_bytes = pad_lines * stride; int pad_bytes = pad_lines * stride;
memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes ); memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes );
} }
} }
if (empty_rect) goto empty_image; if (empty_rect) bits = NULL;
src.x = src.visrect.left; src.x = src.visrect.left;
src.y = src.visrect.top; src.y = src.visrect.top;
src.width = src.visrect.right - src.visrect.left; src.width = src.visrect.right - src.visrect.left;
src.height = src.visrect.bottom - src.visrect.top; src.height = src.visrect.bottom - src.visrect.top;
err = funcs->pGetImage( NULL, hbitmap, src_info, &src_bits, &src ); lines = src.height;
}
err = funcs->pGetImage( NULL, hbitmap, src_info, bits ? &src_bits : NULL, bits ? &src : NULL );
if (err) goto done; if (err) goto done;
ret = src.height; /* fill out the src colour table, if it needs one */
if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0) if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0)
{ {
if (bmp->dib)
memcpy( src_info->bmiColors, bmp->color_table, bmp->nb_colors * sizeof(RGBQUAD) );
else
fill_default_color_table( src_info ); fill_default_color_table( src_info );
src_info->bmiHeader.biClrUsed = 1 << src_info->bmiHeader.biBitCount;
} }
/* if the src and dst are the same depth, copy the colour info across */
if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS )
{
switch (src_info->bmiHeader.biBitCount)
{
case 16:
if (src_info->bmiHeader.biCompression == BI_RGB)
{
src_info->bmiHeader.biCompression = BI_BITFIELDS;
memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
}
break;
case 32:
if (src_info->bmiHeader.biCompression == BI_RGB)
{
src_info->bmiHeader.biCompression = BI_BITFIELDS;
memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
}
break;
}
src_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
copy_color_info( dst_info, src_info, coloruse );
}
else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
{
if( coloruse == DIB_PAL_COLORS )
{
if (!fill_color_table_from_palette( dst_info, dc )) goto done;
}
else
{
fill_default_color_table( dst_info );
}
}
if (bits)
{
if(dst_info->bmiHeader.biHeight > 0) if(dst_info->bmiHeader.biHeight > 0)
dst_info->bmiHeader.biHeight = src.height; dst_info->bmiHeader.biHeight = src.height;
else else
@ -1081,13 +1042,15 @@ INT WINAPI GetDIBits(
convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits ); convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits );
if (src_bits.free) src_bits.free( &src_bits ); if (src_bits.free) src_bits.free( &src_bits );
ret = lines;
} }
else ret = abs( height ); else
ret = empty_rect ? FALSE : TRUE;
empty_image:
if (coloruse == DIB_PAL_COLORS) if (coloruse == DIB_PAL_COLORS)
{ {
WORD *index = (WORD *)dst_info->bmiColors; WORD *index = (WORD *)dst_info->bmiColors;
int colors = get_dib_num_of_colors( dst_info );
for (i = 0; i < colors; i++, index++) for (i = 0; i < colors; i++, index++)
*index = i; *index = i;
} }

View File

@ -1255,21 +1255,18 @@ static void test_GetDIBits_selected_DIB(UINT bpp)
/* Test various combinations of lines = 0 and bits2 = NULL */ /* Test various combinations of lines = 0 and bits2 = NULL */
memset( info2->bmiColors, 0xcc, 256 * sizeof(RGBQUAD) ); memset( info2->bmiColors, 0xcc, 256 * sizeof(RGBQUAD) );
res = GetDIBits( dc, dib, 0, 0, bits2, info2, DIB_RGB_COLORS ); res = GetDIBits( dc, dib, 0, 0, bits2, info2, DIB_RGB_COLORS );
todo_wine
ok( res == 1, "got %d (bpp %d)\n", res, bpp ); ok( res == 1, "got %d (bpp %d)\n", res, bpp );
ok( !memcmp( info->bmiColors, info2->bmiColors, (1 << bpp) * sizeof(RGBQUAD) ), ok( !memcmp( info->bmiColors, info2->bmiColors, (1 << bpp) * sizeof(RGBQUAD) ),
"color table mismatch (bpp %d)\n", bpp ); "color table mismatch (bpp %d)\n", bpp );
memset( info2->bmiColors, 0xcc, 256 * sizeof(RGBQUAD) ); memset( info2->bmiColors, 0xcc, 256 * sizeof(RGBQUAD) );
res = GetDIBits( dc, dib, 0, 0, NULL, info2, DIB_RGB_COLORS ); res = GetDIBits( dc, dib, 0, 0, NULL, info2, DIB_RGB_COLORS );
todo_wine
ok( res == 1, "got %d (bpp %d)\n", res, bpp ); ok( res == 1, "got %d (bpp %d)\n", res, bpp );
ok( !memcmp( info->bmiColors, info2->bmiColors, (1 << bpp) * sizeof(RGBQUAD) ), ok( !memcmp( info->bmiColors, info2->bmiColors, (1 << bpp) * sizeof(RGBQUAD) ),
"color table mismatch (bpp %d)\n", bpp ); "color table mismatch (bpp %d)\n", bpp );
memset( info2->bmiColors, 0xcc, 256 * sizeof(RGBQUAD) ); memset( info2->bmiColors, 0xcc, 256 * sizeof(RGBQUAD) );
res = GetDIBits( dc, dib, 0, info->bmiHeader.biHeight, NULL, info2, DIB_RGB_COLORS ); res = GetDIBits( dc, dib, 0, info->bmiHeader.biHeight, NULL, info2, DIB_RGB_COLORS );
todo_wine
ok( res == 1, "got %d (bpp %d)\n", res, bpp ); ok( res == 1, "got %d (bpp %d)\n", res, bpp );
ok( !memcmp( info->bmiColors, info2->bmiColors, (1 << bpp) * sizeof(RGBQUAD) ), ok( !memcmp( info->bmiColors, info2->bmiColors, (1 << bpp) * sizeof(RGBQUAD) ),
"color table mismatch (bpp %d)\n", bpp ); "color table mismatch (bpp %d)\n", bpp );
@ -1386,7 +1383,6 @@ static void test_GetDIBits_selected_DDB(BOOL monochrome)
/* Get the palette indices */ /* Get the palette indices */
res = GetDIBits(dc, ddb, 0, 0, NULL, info2, DIB_PAL_COLORS); res = GetDIBits(dc, ddb, 0, 0, NULL, info2, DIB_PAL_COLORS);
todo_wine
ok( res == 1, "got %d (bpp %d)\n", res, bpp ); ok( res == 1, "got %d (bpp %d)\n", res, bpp );
for (i = 0; i < (1 << info->bmiHeader.biBitCount); i++) for (i = 0; i < (1 << info->bmiHeader.biBitCount); i++)