gdi32: Use a local copy of the bitmap info structure to further simplify GetDIBits.

This commit is contained in:
Huw Davies 2011-07-12 16:10:50 +01:00 committed by Alexandre Julliard
parent 74707e956e
commit dd39da49e5
1 changed files with 114 additions and 76 deletions

View File

@ -63,6 +63,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include "windef.h" #include "windef.h"
#include "winbase.h" #include "winbase.h"
@ -443,6 +444,59 @@ static const DWORD bit_fields_888[3] = {0xff0000, 0x00ff00, 0x0000ff};
static const DWORD bit_fields_565[3] = {0xf800, 0x07e0, 0x001f}; static const DWORD bit_fields_565[3] = {0xf800, 0x07e0, 0x001f};
static const DWORD bit_fields_555[3] = {0x7c00, 0x03e0, 0x001f}; static const DWORD bit_fields_555[3] = {0x7c00, 0x03e0, 0x001f};
/************************************************************************
* copy_color_info
*
* Copy BITMAPINFO color information where dst may be a BITMAPCOREINFO.
*/
static void copy_color_info(BITMAPINFO *dst, const BITMAPINFO *src, UINT coloruse)
{
unsigned int colors = src->bmiHeader.biBitCount > 8 ? 0 : 1 << src->bmiHeader.biBitCount;
RGBQUAD *src_colors = (RGBQUAD *)((char *)src + src->bmiHeader.biSize);
assert( src->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER) );
if (src->bmiHeader.biClrUsed) colors = src->bmiHeader.biClrUsed;
if (dst->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
{
BITMAPCOREINFO *core = (BITMAPCOREINFO *)dst;
if (coloruse == DIB_PAL_COLORS)
memcpy( core->bmciColors, src_colors, colors * sizeof(WORD) );
else
{
unsigned int i;
for (i = 0; i < colors; i++)
{
core->bmciColors[i].rgbtRed = src_colors[i].rgbRed;
core->bmciColors[i].rgbtGreen = src_colors[i].rgbGreen;
core->bmciColors[i].rgbtBlue = src_colors[i].rgbBlue;
}
}
}
else
{
dst->bmiHeader.biClrUsed = src->bmiHeader.biClrUsed;
dst->bmiHeader.biSizeImage = src->bmiHeader.biSizeImage;
if (src->bmiHeader.biCompression == BI_BITFIELDS)
/* bitfields are always at bmiColors even in larger structures */
memcpy( dst->bmiColors, src->bmiColors, 3 * sizeof(DWORD) );
else if (colors)
{
void *colorptr = (char *)dst + dst->bmiHeader.biSize;
unsigned int size;
if (coloruse == DIB_PAL_COLORS)
size = colors * sizeof(WORD);
else
size = colors * sizeof(RGBQUAD);
memcpy( colorptr, src_colors, size );
}
}
}
/****************************************************************************** /******************************************************************************
* GetDIBits [GDI32.@] * GetDIBits [GDI32.@]
* *
@ -470,9 +524,8 @@ INT WINAPI GetDIBits(
LONG height; LONG height;
WORD planes, bpp; WORD planes, bpp;
DWORD compr, size; DWORD compr, size;
void* colorPtr; char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
RGBQUAD quad_buf[256]; BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
RGBQUAD* rgbQuads = quad_buf;
if (!info) return 0; if (!info) return 0;
@ -495,14 +548,9 @@ INT WINAPI GetDIBits(
return 0; return 0;
} }
colorPtr = (LPBYTE) info + (WORD) info->bmiHeader.biSize;
if(!core_header) rgbQuads = colorPtr;
/* Transfer color info */ if (bpp == 0) /* query bitmap info only */
switch (bpp)
{ {
case 0: /* query bitmap info only */
if (core_header) if (core_header)
{ {
BITMAPCOREHEADER* coreheader = (BITMAPCOREHEADER*) info; BITMAPCOREHEADER* coreheader = (BITMAPCOREHEADER*) info;
@ -549,34 +597,46 @@ INT WINAPI GetDIBits(
} }
lines = abs(bmp->bitmap.bmHeight); lines = abs(bmp->bitmap.bmHeight);
goto done; goto done;
}
/* 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 */
dst_info->bmiHeader.biSize = sizeof(dst_info->bmiHeader);
dst_info->bmiHeader.biWidth = width;
dst_info->bmiHeader.biHeight = height;
dst_info->bmiHeader.biPlanes = planes;
dst_info->bmiHeader.biBitCount = bpp;
dst_info->bmiHeader.biCompression = compr;
dst_info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes( width, height, bpp );
dst_info->bmiHeader.biXPelsPerMeter = 0;
dst_info->bmiHeader.biYPelsPerMeter = 0;
dst_info->bmiHeader.biClrUsed = 0;
dst_info->bmiHeader.biClrImportant = 0;
switch (bpp)
{
case 1: case 1:
case 4: case 4:
case 8: case 8:
{ {
unsigned int colors = 1 << bpp; unsigned int colors = 1 << bpp;
if (!core_header) info->bmiHeader.biClrUsed = 0;
if (coloruse == DIB_PAL_COLORS) if (coloruse == DIB_PAL_COLORS)
{ {
WORD *index = colorPtr; WORD *index = (WORD*)dst_info->bmiColors;
for (i = 0; i < colors; i++, index++) for (i = 0; i < colors; i++, index++)
*index = i; *index = i;
break;
} }
/* If the bitmap object already has a dib section at the /* If the bitmap object is a dib section at the
same color depth then get the color map from it */ same color depth then get the color map from it */
else if (bmp->dib && bpp == bmp->dib->dsBm.bmBitsPixel)
if (bmp->dib && bmp->dib->dsBm.bmBitsPixel == bpp)
{ {
colors = min( colors, bmp->nb_colors ); colors = min( colors, bmp->nb_colors );
if (colors != 1 << bpp) dst_info->bmiHeader.biClrUsed = colors;
if (!core_header && colors != 1 << bpp) info->bmiHeader.biClrUsed = colors; memcpy( dst_info->bmiColors, bmp->color_table, colors * sizeof(RGBQUAD) );
memcpy(rgbQuads, bmp->color_table, colors * sizeof(RGBQUAD));
} }
/* For color DDBs in native depth (mono DDBs always have a black/white palette): /* For color DDBs in native depth (mono DDBs always have a black/white palette):
@ -589,16 +649,16 @@ INT WINAPI GetDIBits(
memset( palEntry, 0, sizeof(palEntry) ); memset( palEntry, 0, sizeof(palEntry) );
if (!GetPaletteEntries( dc->hPalette, 0, colors, palEntry )) if (!GetPaletteEntries( dc->hPalette, 0, colors, palEntry ))
{ {
release_dc_ptr( dc ); lines = 0;
GDI_ReleaseObj( hbitmap ); goto done;
return 0;
} }
for (i = 0; i < colors; i++) for (i = 0; i < colors; i++)
{ {
rgbQuads[i].rgbRed = palEntry[i].peRed; dst_info->bmiColors[i].rgbRed = palEntry[i].peRed;
rgbQuads[i].rgbGreen = palEntry[i].peGreen; dst_info->bmiColors[i].rgbGreen = palEntry[i].peGreen;
rgbQuads[i].rgbBlue = palEntry[i].peBlue; dst_info->bmiColors[i].rgbBlue = palEntry[i].peBlue;
rgbQuads[i].rgbReserved = 0; dst_info->bmiColors[i].rgbReserved = 0;
} }
} }
else else
@ -606,76 +666,64 @@ INT WINAPI GetDIBits(
switch (bpp) switch (bpp)
{ {
case 1: case 1:
rgbQuads[0].rgbRed = rgbQuads[0].rgbGreen = rgbQuads[0].rgbBlue = 0; dst_info->bmiColors[0].rgbRed = dst_info->bmiColors[0].rgbGreen = dst_info->bmiColors[0].rgbBlue = 0;
rgbQuads[0].rgbReserved = 0; dst_info->bmiColors[0].rgbReserved = 0;
rgbQuads[1].rgbRed = rgbQuads[1].rgbGreen = rgbQuads[1].rgbBlue = 0xff; dst_info->bmiColors[1].rgbRed = dst_info->bmiColors[1].rgbGreen = dst_info->bmiColors[1].rgbBlue = 0xff;
rgbQuads[1].rgbReserved = 0; dst_info->bmiColors[1].rgbReserved = 0;
break; break;
case 4: case 4:
/* The EGA palette is the first and last 8 colours of the default palette /* The EGA palette is the first and last 8 colours of the default palette
with the innermost pair swapped */ with the innermost pair swapped */
memcpy(rgbQuads, DefLogPaletteQuads, 7 * sizeof(RGBQUAD)); memcpy(dst_info->bmiColors, DefLogPaletteQuads, 7 * sizeof(RGBQUAD));
memcpy(rgbQuads + 7, DefLogPaletteQuads + 12, 1 * sizeof(RGBQUAD)); memcpy(dst_info->bmiColors + 7, DefLogPaletteQuads + 12, 1 * sizeof(RGBQUAD));
memcpy(rgbQuads + 8, DefLogPaletteQuads + 7, 1 * sizeof(RGBQUAD)); memcpy(dst_info->bmiColors + 8, DefLogPaletteQuads + 7, 1 * sizeof(RGBQUAD));
memcpy(rgbQuads + 9, DefLogPaletteQuads + 13, 7 * sizeof(RGBQUAD)); memcpy(dst_info->bmiColors + 9, DefLogPaletteQuads + 13, 7 * sizeof(RGBQUAD));
break; break;
case 8: case 8:
memcpy(rgbQuads, DefLogPaletteQuads, 10 * sizeof(RGBQUAD)); memcpy(dst_info->bmiColors, DefLogPaletteQuads, 10 * sizeof(RGBQUAD));
memcpy(rgbQuads + 246, DefLogPaletteQuads + 10, 10 * sizeof(RGBQUAD)); memcpy(dst_info->bmiColors + 246, DefLogPaletteQuads + 10, 10 * sizeof(RGBQUAD));
for (i = 10; i < 246; i++) for (i = 10; i < 246; i++)
{ {
rgbQuads[i].rgbRed = (i & 0x07) << 5; dst_info->bmiColors[i].rgbRed = (i & 0x07) << 5;
rgbQuads[i].rgbGreen = (i & 0x38) << 2; dst_info->bmiColors[i].rgbGreen = (i & 0x38) << 2;
rgbQuads[i].rgbBlue = i & 0xc0; dst_info->bmiColors[i].rgbBlue = i & 0xc0;
rgbQuads[i].rgbReserved = 0; dst_info->bmiColors[i].rgbReserved = 0;
} }
} }
} }
if(core_header)
{
RGBTRIPLE *triple = (RGBTRIPLE *)colorPtr;
for (i = 0; i < colors; i++)
{
triple[i].rgbtRed = rgbQuads[i].rgbRed;
triple[i].rgbtGreen = rgbQuads[i].rgbGreen;
triple[i].rgbtBlue = rgbQuads[i].rgbBlue;
}
}
break; break;
} }
case 15: case 15:
if (info->bmiHeader.biCompression == BI_BITFIELDS) if (dst_info->bmiHeader.biCompression == BI_BITFIELDS)
memcpy( info->bmiColors, bit_fields_555, sizeof(bit_fields_555) ); memcpy( dst_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
break; break;
case 16: case 16:
if (info->bmiHeader.biCompression == BI_BITFIELDS) if (dst_info->bmiHeader.biCompression == BI_BITFIELDS)
{ {
if (bmp->dib) if (bmp->dib)
{ {
if (bmp->dib->dsBmih.biCompression == BI_BITFIELDS && bmp->dib->dsBmih.biBitCount == bpp) if (bmp->dib->dsBmih.biCompression == BI_BITFIELDS && bmp->dib->dsBmih.biBitCount == bpp)
memcpy( info->bmiColors, bmp->dib->dsBitfields, 3 * sizeof(DWORD) ); memcpy( dst_info->bmiColors, bmp->dib->dsBitfields, 3 * sizeof(DWORD) );
else else
memcpy( info->bmiColors, bit_fields_555, sizeof(bit_fields_555) ); memcpy( dst_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
} }
else else
memcpy( info->bmiColors, bit_fields_565, sizeof(bit_fields_565) ); memcpy( dst_info->bmiColors, bit_fields_565, sizeof(bit_fields_565) );
} }
break; break;
case 24: case 24:
case 32: case 32:
if (info->bmiHeader.biCompression == BI_BITFIELDS) if (dst_info->bmiHeader.biCompression == BI_BITFIELDS)
{ {
if (bmp->dib && bmp->dib->dsBmih.biCompression == BI_BITFIELDS && bmp->dib->dsBmih.biBitCount == bpp) if (bmp->dib && bmp->dib->dsBmih.biCompression == BI_BITFIELDS && bmp->dib->dsBmih.biBitCount == bpp)
memcpy( info->bmiColors, bmp->dib->dsBitfields, 3 * sizeof(DWORD) ); memcpy( dst_info->bmiColors, bmp->dib->dsBitfields, 3 * sizeof(DWORD) );
else else
memcpy( info->bmiColors, bit_fields_888, sizeof(bit_fields_888) ); memcpy( dst_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
} }
break; break;
} }
@ -894,7 +942,7 @@ INT WINAPI GetDIBits(
break; break;
default: /* ? bit DIB */ default: /* ? bit DIB */
FIXME("Unsupported DIB depth %d\n", info->bmiHeader.biBitCount); FIXME("Unsupported DIB depth %d\n", dst_info->bmiHeader.biBitCount);
break; break;
} }
} }
@ -904,22 +952,12 @@ INT WINAPI GetDIBits(
PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetDIBits ); PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetDIBits );
if (!BITMAP_SetOwnerDC( hbitmap, physdev )) lines = 0; if (!BITMAP_SetOwnerDC( hbitmap, physdev )) lines = 0;
else lines = physdev->funcs->pGetDIBits( physdev, hbitmap, startscan, else lines = physdev->funcs->pGetDIBits( physdev, hbitmap, startscan,
lines, bits, info, coloruse ); lines, bits, dst_info, coloruse );
} }
} }
else lines = abs(height); else lines = abs(height);
/* The knowledge base article Q81498 ("DIBs and Their Uses") states that copy_color_info( info, dst_info, coloruse );
if bits == NULL and bpp != 0, only biSizeImage and the color table are
filled in. */
if (!core_header)
{
/* FIXME: biSizeImage should be calculated according to the selected
compression algorithm if biCompression != BI_RGB */
info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes( width, height, bpp );
TRACE("biSizeImage = %d, ", info->bmiHeader.biSizeImage);
}
TRACE("biWidth = %d, biHeight = %d\n", width, height);
done: done:
release_dc_ptr( dc ); release_dc_ptr( dc );