gdi32: Add support for 1 bpp dibs.
This commit is contained in:
parent
3582d3dfb4
commit
b0f59c3b11
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue