gdi32: Add support for 1 bpp dibs.

This commit is contained in:
Huw Davies 2011-06-15 13:43:49 +01:00 committed by Alexandre Julliard
parent 3582d3dfb4
commit b0f59c3b11
5 changed files with 379 additions and 8 deletions

View File

@ -126,6 +126,10 @@ static BOOL init_dib_info(dib_info *dib, const BITMAPINFOHEADER *bi, const DWORD
dib->funcs = &funcs_4;
break;
case 1:
dib->funcs = &funcs_1;
break;
default:
TRACE("bpp %d not supported, will forward to graphics driver.\n", dib->bit_count);
return FALSE;
@ -336,6 +340,8 @@ static COLORREF CDECL dibdrv_SetBkColor( PHYSDEV dev, COLORREF color )
pdev->bkgnd_xor = 0;
}
update_fg_colors( pdev ); /* Only needed in the 1 bpp case */
return next->funcs->pSetBkColor( next, color );
}

View File

@ -52,6 +52,7 @@ extern const primitive_funcs funcs_555 DECLSPEC_HIDDEN;
extern const primitive_funcs funcs_16 DECLSPEC_HIDDEN;
extern const primitive_funcs funcs_8 DECLSPEC_HIDDEN;
extern const primitive_funcs funcs_4 DECLSPEC_HIDDEN;
extern const primitive_funcs funcs_1 DECLSPEC_HIDDEN;
extern const primitive_funcs funcs_null DECLSPEC_HIDDEN;
extern void calc_and_xor_masks(INT rop, DWORD color, DWORD *and, DWORD *xor) DECLSPEC_HIDDEN;

View File

@ -92,20 +92,59 @@ void calc_and_xor_masks(INT rop, DWORD color, DWORD *and, DWORD *xor)
*xor = (color & rop2_xor_array[rop-1][0]) | ((~color) & rop2_xor_array[rop-1][1]);
}
static inline RGBQUAD rgbquad_from_colorref(COLORREF c)
{
RGBQUAD ret;
ret.rgbRed = GetRValue(c);
ret.rgbGreen = GetGValue(c);
ret.rgbBlue = GetBValue(c);
ret.rgbReserved = 0;
return ret;
}
static inline BOOL rgbquad_equal(const RGBQUAD *a, const RGBQUAD *b)
{
if(a->rgbRed == b->rgbRed &&
a->rgbGreen == b->rgbGreen &&
a->rgbBlue == b->rgbBlue)
return TRUE;
return FALSE;
}
/******************************************************************
* get_fg_color
*
* 1 bit bitmaps map the fg/bg colors as follows:
* If the fg colorref exactly matches one of the color table entries then
* that entry is the fg color and the other is the bg.
* Otherwise the bg color is mapped to the closest entry in the table and
* the fg takes the other one.
*/
DWORD get_fg_color( dibdrv_physdev *pdev, COLORREF fg )
{
RGBQUAD fg_quad;
if(pdev->dib.bit_count != 1)
return pdev->dib.funcs->colorref_to_pixel( &pdev->dib, fg );
FIXME("bit count == 1\n");
return 0;
fg_quad = rgbquad_from_colorref( fg );
if(rgbquad_equal(&fg_quad, pdev->dib.color_table))
return 0;
if(rgbquad_equal(&fg_quad, pdev->dib.color_table + 1))
return 1;
if(fg == GetBkColor(pdev->dev.hdc)) return pdev->bkgnd_color;
else return pdev->bkgnd_color ? 0 : 1;
}
/***************************************************************************
* get_pen_bkgnd_masks
*
* Returns the pre-calculated bkgnd color masks unless the dib is 1 bpp.
* In this case since there are several fg sources (pen, brush, text)
* this makes pdev->bkgnd_color unusable. So here we take the inverse
* of the relevant fg color (which is always set up correctly).
*/
static inline void get_pen_bkgnd_masks(const dibdrv_physdev *pdev, DWORD *and, DWORD *xor)
{
@ -116,9 +155,9 @@ static inline void get_pen_bkgnd_masks(const dibdrv_physdev *pdev, DWORD *and, D
}
else
{
FIXME("bit count == 1\n");
*and = ~0u;
*xor = 0u;
DWORD color = ~pdev->pen_color;
if(pdev->pen_colorref == GetBkColor(pdev->dev.hdc)) color = pdev->pen_color;
calc_and_xor_masks( GetROP2(pdev->dev.hdc), color, and, xor );
}
}

View File

@ -57,6 +57,13 @@ static inline BYTE *get_pixel_ptr_4(const dib_info *dib, int x, int y)
return (BYTE*)dib->bits + y * dib->stride + x / 2;
}
static inline BYTE *get_pixel_ptr_1(const dib_info *dib, int x, int y)
{
return (BYTE*)dib->bits + y * dib->stride + x / 8;
}
static const BYTE pixel_masks_1[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
static inline void do_rop_32(DWORD *ptr, DWORD and, DWORD xor)
{
*ptr = (*ptr & and) ^ xor;
@ -221,6 +228,60 @@ static void solid_rects_4(const dib_info *dib, int num, const RECT *rc, DWORD an
}
}
static void solid_rects_1(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor)
{
BYTE *ptr, *start;
int x, y, i;
BYTE byte_and = (and & 1) ? 0xff : 0;
BYTE byte_xor = (xor & 1) ? 0xff : 0;
BYTE start_and, start_xor, end_and, end_xor, mask;
static const BYTE masks[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
for(i = 0; i < num; i++, rc++)
{
if(rc->left >= rc->right) continue;
start = get_pixel_ptr_1(dib, rc->left, rc->top);
if((rc->left & ~7) == (rc->right & ~7)) /* Special case for lines that start and end in the same byte */
{
mask = masks[rc->left & 7] & ~masks[rc->right & 7];
start_and = byte_and | ~mask;
start_xor = byte_xor & mask;
for(y = rc->top; y < rc->bottom; y++, start += dib->stride)
{
do_rop_8(start, start_and, start_xor);
}
}
else
{
mask = masks[rc->left & 7];
start_and = byte_and | ~mask;
start_xor = byte_xor & mask;
mask = masks[rc->right & 7];
/* This is inverted wrt to start mask, so end_and/xor assignments reflect this */
end_and = byte_and | mask;
end_xor = byte_xor & ~mask;
for(y = rc->top; y < rc->bottom; y++, start += dib->stride)
{
ptr = start;
if(rc->left & 7)
do_rop_8(ptr++, start_and, start_xor);
for(x = (rc->left + 7) & ~7; x < (rc->right & ~7); x += 8)
do_rop_8(ptr++, byte_and, byte_xor);
if(rc->right & 7)
do_rop_8(ptr, end_and, end_xor);
}
}
}
}
static void solid_rects_null(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor)
{
return;
@ -516,6 +577,70 @@ static void pattern_rects_4(const dib_info *dib, int num, const RECT *rc, const
}
}
static void pattern_rects_1(const dib_info *dib, int num, const RECT *rc, const POINT *origin,
const dib_info *brush, void *and_bits, void *xor_bits)
{
BYTE *ptr, *start, *start_and, *and_ptr, *start_xor, *xor_ptr;
int x, y, i;
POINT offset;
for(i = 0; i < num; i++, rc++)
{
offset = calc_brush_offset(rc, brush, origin);
start = get_pixel_ptr_1(dib, rc->left, rc->top);
start_and = (BYTE*)and_bits + offset.y * brush->stride;
start_xor = (BYTE*)xor_bits + offset.y * brush->stride;
for(y = rc->top; y < rc->bottom; y++, start += dib->stride)
{
INT brush_x = offset.x;
BYTE byte_and, byte_xor;
and_ptr = start_and + brush_x / 8;
xor_ptr = start_xor + brush_x / 8;
for(x = rc->left, ptr = start; x < rc->right; x++)
{
byte_and = (*and_ptr & pixel_masks_1[brush_x % 8]) ? 0xff : 0;
byte_and |= ~pixel_masks_1[x % 8];
byte_xor = (*xor_ptr & pixel_masks_1[brush_x % 8]) ? 0xff : 0;
byte_xor &= pixel_masks_1[x % 8];
do_rop_8(ptr, byte_and, byte_xor);
if((x & 7) == 7) ptr++;
if((brush_x & 7) == 7)
{
and_ptr++;
xor_ptr++;
}
if(++brush_x == brush->width)
{
brush_x = 0;
and_ptr = start_and;
xor_ptr = start_xor;
}
}
offset.y++;
if(offset.y == brush->height)
{
start_and = and_bits;
start_xor = xor_bits;
offset.y = 0;
}
else
{
start_and += brush->stride;
start_xor += brush->stride;
}
}
}
}
static void pattern_rects_null(const dib_info *dib, int num, const RECT *rc, const POINT *origin,
const dib_info *brush, void *and_bits, void *xor_bits)
{
@ -1674,9 +1799,202 @@ static BOOL convert_to_4(dib_info *dst, const dib_info *src, const RECT *src_rec
return TRUE;
}
static BOOL convert_to_1(dib_info *dst, const dib_info *src, const RECT *src_rect)
{
BYTE *dst_start = dst->bits, *dst_pixel, dst_val;
INT x, y;
DWORD src_val;
int bit_pos;
/* FIXME: Brushes should be dithered. */
switch(src->bit_count)
{
case 32:
{
DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
if(src->funcs == &funcs_8888)
{
for(y = src_rect->top; y < src_rect->bottom; y++)
{
dst_pixel = dst_start;
src_pixel = src_start;
for(x = src_rect->left, bit_pos = 0; x < src_rect->right; x++)
{
src_val = *src_pixel++;
dst_val = colorref_to_pixel_colortable(dst, ((src_val >> 16) & 0x0000ff) |
( src_val & 0x00ff00) |
((src_val << 16) & 0xff0000) ) ? 0xff : 0;
if(bit_pos == 0) *dst_pixel = 0;
*dst_pixel = (*dst_pixel & ~pixel_masks_1[bit_pos]) | (dst_val & pixel_masks_1[bit_pos]);
if(++bit_pos == 8)
{
dst_pixel++;
bit_pos = 0;
}
}
dst_start += dst->stride;
src_start += src->stride / 4;
}
}
else
{
FIXME("Unsupported conversion: 32 -> 1\n");
return FALSE;
}
break;
}
case 24:
{
BYTE *src_start = get_pixel_ptr_24(src, src_rect->left, src_rect->top), *src_pixel;
for(y = src_rect->top; y < src_rect->bottom; y++)
{
dst_pixel = dst_start;
src_pixel = src_start;
for(x = src_rect->left, bit_pos = 0; x < src_rect->right; x++)
{
RGBQUAD rgb;
rgb.rgbBlue = *src_pixel++;
rgb.rgbGreen = *src_pixel++;
rgb.rgbRed = *src_pixel++;
dst_val = colorref_to_pixel_colortable(dst, ( rgb.rgbRed & 0x0000ff) |
((rgb.rgbGreen << 8) & 0x00ff00) |
((rgb.rgbBlue << 16) & 0xff0000)) ? 0xff : 0;
if(bit_pos == 0) *dst_pixel = 0;
*dst_pixel = (*dst_pixel & ~pixel_masks_1[bit_pos]) | (dst_val & pixel_masks_1[bit_pos]);
if(++bit_pos == 8)
{
dst_pixel++;
bit_pos = 0;
}
}
dst_start += dst->stride;
src_start += src->stride;
}
break;
}
case 16:
{
WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
if(src->funcs == &funcs_555)
{
for(y = src_rect->top; y < src_rect->bottom; y++)
{
dst_pixel = dst_start;
src_pixel = src_start;
for(x = src_rect->left, bit_pos = 0; x < src_rect->right; x++)
{
src_val = *src_pixel++;
dst_val = colorref_to_pixel_colortable(dst, ((src_val >> 7) & 0x0000f8) | ((src_val >> 12) & 0x000007) |
((src_val << 6) & 0x00f800) | ((src_val << 1) & 0x000700) |
((src_val << 19) & 0xf80000) | ((src_val << 14) & 0x070000) ) ? 0xff : 0;
if(bit_pos == 0) *dst_pixel = 0;
*dst_pixel = (*dst_pixel & ~pixel_masks_1[bit_pos]) | (dst_val & pixel_masks_1[bit_pos]);
if(++bit_pos == 8)
{
dst_pixel++;
bit_pos = 0;
}
}
dst_start += dst->stride;
src_start += src->stride / 2;
}
}
else
{
FIXME("Unsupported conversion: 16 -> 1\n");
return FALSE;
}
break;
}
case 8:
{
BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
for(y = src_rect->top; y < src_rect->bottom; y++)
{
dst_pixel = dst_start;
src_pixel = src_start;
for(x = src_rect->left, bit_pos = 0; x < src_rect->right; x++)
{
RGBQUAD rgb;
src_val = *src_pixel++;
if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
rgb = src->color_table[src_val];
dst_val = colorref_to_pixel_colortable(dst, RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue)) ? 0xff : 0;
if(bit_pos == 0) *dst_pixel = 0;
*dst_pixel = (*dst_pixel & ~pixel_masks_1[bit_pos]) | (dst_val & pixel_masks_1[bit_pos]);
if(++bit_pos == 8)
{
dst_pixel++;
bit_pos = 0;
}
}
dst_start += dst->stride;
src_start += src->stride;
}
break;
}
case 4:
{
BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
for(y = src_rect->top; y < src_rect->bottom; y++)
{
dst_pixel = dst_start;
src_pixel = src_start;
for(x = src_rect->left, bit_pos = 0; x < src_rect->right; x++)
{
RGBQUAD rgb;
if(x & 1)
src_val = *src_pixel++ & 0xf;
else
src_val = (*src_pixel >> 4) & 0xf;
if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
rgb = src->color_table[src_val];
dst_val = colorref_to_pixel_colortable(dst, RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue)) ? 0xff : 0;
if(bit_pos == 0) *dst_pixel = 0;
*dst_pixel = (*dst_pixel & ~pixel_masks_1[bit_pos]) | (dst_val & pixel_masks_1[bit_pos]);
if(++bit_pos == 8)
{
dst_pixel++;
bit_pos = 0;
}
}
dst_start += dst->stride;
src_start += src->stride;
}
break;
}
default:
FIXME("Unsupported conversion: %d -> 1\n", src->bit_count);
return FALSE;
}
return TRUE;
}
static BOOL convert_to_null(dib_info *dst, const dib_info *src, const RECT *src_rect)
{
return TRUE;
return FALSE;
}
const primitive_funcs funcs_8888 =
@ -1735,6 +2053,14 @@ const primitive_funcs funcs_4 =
convert_to_4
};
const primitive_funcs funcs_1 =
{
solid_rects_1,
pattern_rects_1,
colorref_to_pixel_colortable,
convert_to_1
};
const primitive_funcs funcs_null =
{
solid_rects_null,

View File

@ -976,10 +976,9 @@ static void test_mono_dibsection(void)
/* black border, white interior */
Rectangle(memdc, 0, 0, 10, 10);
todo_wine {
ok(ds_bits[0] == 0xff, "out_bits %02x\n", ds_bits[0]);
ok(ds_bits[4] == 0x80, "out_bits %02x\n", ds_bits[4]);
}
/* SetDIBitsToDevice with an inverted bmi -> inverted dib section */
memset(bits, 0, sizeof(bits));