diff --git a/dlls/gdi32/dibdrv/dc.c b/dlls/gdi32/dibdrv/dc.c index abb3fbc5ad3..8bdb60dd968 100644 --- a/dlls/gdi32/dibdrv/dc.c +++ b/dlls/gdi32/dibdrv/dc.c @@ -102,6 +102,10 @@ static BOOL init_dib_info(dib_info *dib, const BITMAPINFOHEADER *bi, const DWORD dib->funcs = &funcs_32; break; + case 24: + dib->funcs = &funcs_24; + break; + case 16: if(bi->biCompression == BI_RGB) bit_fields = bit_fields_555; diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h index 95d8b756c89..c23574beac2 100644 --- a/dlls/gdi32/dibdrv/dibdrv.h +++ b/dlls/gdi32/dibdrv/dibdrv.h @@ -47,6 +47,7 @@ typedef struct primitive_funcs extern const primitive_funcs funcs_8888 DECLSPEC_HIDDEN; extern const primitive_funcs funcs_32 DECLSPEC_HIDDEN; +extern const primitive_funcs funcs_24 DECLSPEC_HIDDEN; extern const primitive_funcs funcs_555 DECLSPEC_HIDDEN; extern const primitive_funcs funcs_16 DECLSPEC_HIDDEN; extern const primitive_funcs funcs_8 DECLSPEC_HIDDEN; diff --git a/dlls/gdi32/dibdrv/primitives.c b/dlls/gdi32/dibdrv/primitives.c index 018ef9aff41..b7270e916c1 100644 --- a/dlls/gdi32/dibdrv/primitives.c +++ b/dlls/gdi32/dibdrv/primitives.c @@ -32,6 +32,16 @@ static inline DWORD *get_pixel_ptr_32(const dib_info *dib, int x, int y) return (DWORD *)((BYTE*)dib->bits + y * dib->stride + x * 4); } +static inline DWORD *get_pixel_ptr_24_dword(const dib_info *dib, int x, int y) +{ + return (DWORD *)((BYTE*)dib->bits + y * dib->stride) + x * 3 / 4; +} + +static inline BYTE *get_pixel_ptr_24(const dib_info *dib, int x, int y) +{ + return (BYTE*)dib->bits + y * dib->stride + x * 3; +} + static inline WORD *get_pixel_ptr_16(const dib_info *dib, int x, int y) { return (WORD *)((BYTE*)dib->bits + y * dib->stride + x * 2); @@ -76,6 +86,87 @@ static void solid_rects_32(const dib_info *dib, int num, const RECT *rc, DWORD a } } +static void solid_rects_24(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor) +{ + DWORD *ptr, *start; + BYTE *byte_ptr, *byte_start; + int x, y, i; + DWORD and_masks[3], xor_masks[3]; + + and_masks[0] = ( and & 0x00ffffff) | ((and << 24) & 0xff000000); + and_masks[1] = ((and >> 8) & 0x0000ffff) | ((and << 16) & 0xffff0000); + and_masks[2] = ((and >> 16) & 0x000000ff) | ((and << 8) & 0xffffff00); + xor_masks[0] = ( xor & 0x00ffffff) | ((xor << 24) & 0xff000000); + xor_masks[1] = ((xor >> 8) & 0x0000ffff) | ((xor << 16) & 0xffff0000); + xor_masks[2] = ((xor >> 16) & 0x000000ff) | ((xor << 8) & 0xffffff00); + + for(i = 0; i < num; i++, rc++) + { + if(rc->left >= rc->right) continue; + + if((rc->left & ~3) == (rc->right & ~3)) /* Special case for lines that start and end in the same DWORD triplet */ + { + byte_start = get_pixel_ptr_24(dib, rc->left, rc->top); + for(y = rc->top; y < rc->bottom; y++, byte_start += dib->stride) + { + for(x = rc->left, byte_ptr = byte_start; x < rc->right; x++) + { + do_rop_8(byte_ptr++, and_masks[0] & 0xff, xor_masks[0] & 0xff); + do_rop_8(byte_ptr++, and_masks[1] & 0xff, xor_masks[1] & 0xff); + do_rop_8(byte_ptr++, and_masks[2] & 0xff, xor_masks[2] & 0xff); + } + } + } + else + { + start = get_pixel_ptr_24_dword(dib, rc->left, rc->top); + for(y = rc->top; y < rc->bottom; y++, start += dib->stride / 4) + { + ptr = start; + + switch(rc->left & 3) + { + case 1: + do_rop_32(ptr++, and_masks[0] | 0x00ffffff, xor_masks[0] & 0xff000000); + do_rop_32(ptr++, and_masks[1], xor_masks[1]); + do_rop_32(ptr++, and_masks[2], xor_masks[2]); + break; + case 2: + do_rop_32(ptr++, and_masks[1] | 0x0000ffff, xor_masks[1] & 0xffff0000); + do_rop_32(ptr++, and_masks[2], xor_masks[2]); + break; + case 3: + do_rop_32(ptr++, and_masks[2] | 0x000000ff, xor_masks[2] & 0xffffff00); + break; + } + + for(x = (rc->left + 3) & ~3; x < (rc->right & ~3); x += 4) + { + do_rop_32(ptr++, and_masks[0], xor_masks[0]); + do_rop_32(ptr++, and_masks[1], xor_masks[1]); + do_rop_32(ptr++, and_masks[2], xor_masks[2]); + } + + switch(rc->right & 3) + { + case 1: + do_rop_32(ptr, and_masks[0] | 0xff000000, xor_masks[0] & 0x00ffffff); + break; + case 2: + do_rop_32(ptr++, and_masks[0], xor_masks[0]); + do_rop_32(ptr, and_masks[1] | 0xffff0000, xor_masks[1] & 0x0000ffff); + break; + case 3: + do_rop_32(ptr++, and_masks[0], xor_masks[0]); + do_rop_32(ptr++, and_masks[1], xor_masks[1]); + do_rop_32(ptr, and_masks[2] | 0xffffff00, xor_masks[2] & 0x000000ff); + break; + } + } + } + } +} + static void solid_rects_16(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor) { WORD *ptr, *start; @@ -205,6 +296,54 @@ static void pattern_rects_32(const dib_info *dib, int num, const RECT *rc, const } } +static void pattern_rects_24(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_24(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) + { + and_ptr = start_and + offset.x * 3; + xor_ptr = start_xor + offset.x * 3; + + for(x = rc->left, ptr = start; x < rc->right; x++) + { + do_rop_8(ptr++, *and_ptr++, *xor_ptr++); + do_rop_8(ptr++, *and_ptr++, *xor_ptr++); + do_rop_8(ptr++, *and_ptr++, *xor_ptr++); + if(and_ptr == start_and + brush->width * 3) + { + 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_16(const dib_info *dib, int num, const RECT *rc, const POINT *origin, const dib_info *brush, void *and_bits, void *xor_bits) { @@ -689,6 +828,127 @@ static BOOL convert_to_32(dib_info *dst, const dib_info *src, const RECT *src_re return TRUE; } +static BOOL convert_to_24(dib_info *dst, const dib_info *src, const RECT *src_rect) +{ + BYTE *dst_start = dst->bits, *dst_pixel; + DWORD src_val; + int x, y; + + 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; x < src_rect->right; x++) + { + src_val = *src_pixel++; + *dst_pixel++ = src_val & 0xff; + *dst_pixel++ = (src_val >> 8) & 0xff; + *dst_pixel++ = (src_val >> 16) & 0xff; + } + dst_start += dst->stride; + src_start += src->stride / 4; + } + } + else + { + FIXME("Unsupported conversion: 32 -> 24\n"); + return FALSE; + } + 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; x < src_rect->right; x++) + { + src_val = *src_pixel++; + *dst_pixel++ = ((src_val << 3) & 0xf8) | ((src_val >> 2) & 0x07); + *dst_pixel++ = ((src_val >> 2) & 0xf8) | ((src_val >> 7) & 0x07); + *dst_pixel++ = ((src_val >> 7) & 0xf8) | ((src_val >> 12) & 0x07); + } + dst_start += dst->stride; + src_start += src->stride / 2; + } + } + else + { + FIXME("Unsupported conversion: 16 -> 24\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; 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_pixel++ = rgb.rgbBlue; + *dst_pixel++ = rgb.rgbGreen; + *dst_pixel++ = rgb.rgbRed; + } + 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; 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_pixel++ = rgb.rgbBlue; + *dst_pixel++ = rgb.rgbGreen; + *dst_pixel++ = rgb.rgbRed; + } + dst_start += dst->stride; + src_start += src->stride; + } + break; + } + + default: + FIXME("Unsupported conversion: %d -> 24\n", src->bit_count); + return FALSE; + } + + return TRUE; +} + static BOOL convert_to_555(dib_info *dst, const dib_info *src, const RECT *src_rect) { WORD *dst_start = dst->bits, *dst_pixel; @@ -1261,6 +1521,14 @@ const primitive_funcs funcs_32 = convert_to_32 }; +const primitive_funcs funcs_24 = +{ + solid_rects_24, + pattern_rects_24, + colorref_to_pixel_888, + convert_to_24 +}; + const primitive_funcs funcs_555 = { solid_rects_16,