From b0f59c3b11d928243dc54fb076b2a1ba27c1562e Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Wed, 15 Jun 2011 13:43:49 +0100 Subject: [PATCH] gdi32: Add support for 1 bpp dibs. --- dlls/gdi32/dibdrv/dc.c | 6 + dlls/gdi32/dibdrv/dibdrv.h | 1 + dlls/gdi32/dibdrv/objects.c | 49 ++++- dlls/gdi32/dibdrv/primitives.c | 328 ++++++++++++++++++++++++++++++++- dlls/gdi32/tests/bitmap.c | 3 +- 5 files changed, 379 insertions(+), 8 deletions(-) diff --git a/dlls/gdi32/dibdrv/dc.c b/dlls/gdi32/dibdrv/dc.c index 53e63bda121..1f8b3216c32 100644 --- a/dlls/gdi32/dibdrv/dc.c +++ b/dlls/gdi32/dibdrv/dc.c @@ -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 ); } diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h index 3ebe4fefc88..eb8f2045e8d 100644 --- a/dlls/gdi32/dibdrv/dibdrv.h +++ b/dlls/gdi32/dibdrv/dibdrv.h @@ -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; diff --git a/dlls/gdi32/dibdrv/objects.c b/dlls/gdi32/dibdrv/objects.c index 2b59d0a70f4..2e9ece1a59b 100644 --- a/dlls/gdi32/dibdrv/objects.c +++ b/dlls/gdi32/dibdrv/objects.c @@ -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 ); } } diff --git a/dlls/gdi32/dibdrv/primitives.c b/dlls/gdi32/dibdrv/primitives.c index 411cddd1d16..f3d2130caeb 100644 --- a/dlls/gdi32/dibdrv/primitives.c +++ b/dlls/gdi32/dibdrv/primitives.c @@ -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, diff --git a/dlls/gdi32/tests/bitmap.c b/dlls/gdi32/tests/bitmap.c index 6dd612c7987..a67d7815060 100644 --- a/dlls/gdi32/tests/bitmap.c +++ b/dlls/gdi32/tests/bitmap.c @@ -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));