gdi32: Implement dithering of solid brushes when drawing to DDBs.

This commit is contained in:
Alexandre Julliard 2012-05-23 11:14:16 +02:00
parent 6afed7a52b
commit 139aeba3ef
3 changed files with 249 additions and 10 deletions

View File

@ -188,6 +188,7 @@ typedef struct primitive_funcs
void (* convert_to)(dib_info *dst, const dib_info *src, const RECT *src_rect, BOOL dither);
void (* create_rop_masks)(const dib_info *dib, const BYTE *hatch_ptr,
const rop_mask *fg, const rop_mask *bg, rop_mask_bits *bits);
void (* create_dither_masks)(const dib_info *dib, int rop2, COLORREF color, rop_mask_bits *bits);
void (* stretch_row)(const dib_info *dst_dib, const POINT *dst_start,
const dib_info *src_dib, const POINT *src_start,
const struct stretch_params *params, int mode, BOOL keep_dst);

View File

@ -1788,10 +1788,8 @@ static const BYTE hatches[6][8] =
{ 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 } /* HS_DIAGCROSS */
};
static BOOL create_hatch_brush_bits(dibdrv_physdev *pdev, dib_brush *brush, BOOL *needs_reselect)
static BOOL init_hatch_brush( dibdrv_physdev *pdev, dib_brush *brush )
{
rop_mask fg_mask, bg_mask;
/* Just initialise brush dib with the color / sizing info. We don't
need the bits as we'll calculate the rop masks straight from
the hatch patterns. */
@ -1804,8 +1802,14 @@ static BOOL create_hatch_brush_bits(dibdrv_physdev *pdev, dib_brush *brush, BOOL
brush->dib.rect.top = 0;
brush->dib.rect.right = 8;
brush->dib.rect.bottom = 8;
return alloc_brush_mask_bits( brush );
}
if (!alloc_brush_mask_bits( brush )) return FALSE;
static BOOL create_hatch_brush_bits(dibdrv_physdev *pdev, dib_brush *brush, BOOL *needs_reselect)
{
rop_mask fg_mask, bg_mask;
if (!init_hatch_brush( pdev, brush )) return FALSE;
get_color_masks( pdev, brush->rop, brush->colorref, GetBkMode(pdev->dev.hdc),
&fg_mask, &bg_mask );
@ -1820,6 +1824,23 @@ static BOOL create_hatch_brush_bits(dibdrv_physdev *pdev, dib_brush *brush, BOOL
return TRUE;
}
static BOOL create_dither_brush_bits(dibdrv_physdev *pdev, dib_brush *brush, BOOL *needs_reselect)
{
COLORREF rgb;
DWORD pixel;
BOOL got_pixel;
if (!init_hatch_brush( pdev, brush )) return FALSE;
if (brush->colorref & (1 << 24)) /* PALETTEINDEX */
*needs_reselect = TRUE;
rgb = make_rgb_colorref( pdev->dev.hdc, &pdev->dib, brush->colorref, &got_pixel, &pixel );
brush->dib.funcs->create_dither_masks( &brush->dib, brush->rop, rgb, &brush->masks );
return TRUE;
}
static BOOL matching_pattern_format( dib_info *dib, dib_info *pattern )
{
if (dib->bit_count != pattern->bit_count) return FALSE;
@ -1950,6 +1971,11 @@ static BOOL pattern_brush(dibdrv_physdev *pdev, dib_brush *brush, dib_info *dib,
return FALSE;
break;
case BS_SOLID:
if(!create_dither_brush_bits(pdev, brush, &needs_reselect))
return FALSE;
break;
case BS_HATCHED:
if(!create_hatch_brush_bits(pdev, brush, &needs_reselect))
return FALSE;
@ -1975,7 +2001,26 @@ static BOOL null_brush(dibdrv_physdev *pdev, dib_brush *brush, dib_info *dib,
return TRUE;
}
static void select_brush( dib_brush *brush, const LOGBRUSH *logbrush, const struct brush_pattern *pattern )
static BOOL brush_needs_dithering( dibdrv_physdev *pdev, COLORREF color )
{
int i;
RGBQUAD rgb;
const RGBQUAD *color_table = get_default_color_table( pdev->dib.bit_count );
if (!color_table) return FALSE;
if (pdev->dib.color_table) return FALSE;
if (color & (1 << 24)) return TRUE; /* PALETTEINDEX */
if (color >> 16 == 0x10ff) return FALSE; /* DIBINDEX */
rgb = rgbquad_from_colorref( color );
for (i = 0; i < (1 << pdev->dib.bit_count); i++)
if (rgbquad_equal( &color_table[i], &rgb )) return FALSE;
return TRUE;
}
static void select_brush( dibdrv_physdev *pdev, dib_brush *brush,
const LOGBRUSH *logbrush, const struct brush_pattern *pattern )
{
free_pattern_brush( brush );
@ -1993,9 +2038,11 @@ static void select_brush( dib_brush *brush, const LOGBRUSH *logbrush, const stru
switch (logbrush->lbStyle)
{
case BS_SOLID: brush->rects = solid_brush; break;
case BS_NULL: brush->rects = null_brush; break;
case BS_HATCHED: brush->rects = pattern_brush; break;
case BS_SOLID:
brush->rects = brush_needs_dithering( pdev, brush->colorref ) ? pattern_brush : solid_brush;
break;
}
}
}
@ -2015,7 +2062,7 @@ HBRUSH dibdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, const struct brush_patter
if (hbrush == GetStockObject( DC_BRUSH ))
logbrush.lbColor = GetDCBrushColor( dev->hdc );
select_brush( &pdev->brush, &logbrush, pattern );
select_brush( pdev, &pdev->brush, &logbrush, pattern );
return hbrush;
}
@ -2065,7 +2112,7 @@ HPEN dibdrv_SelectPen( PHYSDEV dev, HPEN hpen, const struct brush_pattern *patte
logbrush.lbColor = GetDCPenColor( dev->hdc );
set_dash_pattern( &pdev->pen_pattern, 0, NULL );
select_brush( &pdev->pen_brush, &logbrush, pattern );
select_brush( pdev, &pdev->pen_brush, &logbrush, pattern );
pdev->pen_style = logpen.lopnStyle & PS_STYLE_MASK;
@ -2129,8 +2176,10 @@ COLORREF dibdrv_SetDCBrushColor( PHYSDEV dev, COLORREF color )
dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
if (GetCurrentObject(dev->hdc, OBJ_BRUSH) == GetStockObject( DC_BRUSH ))
pdev->brush.colorref = color;
{
LOGBRUSH logbrush = { BS_SOLID, color, 0 };
select_brush( pdev, &pdev->brush, &logbrush, NULL );
}
return color;
}

View File

@ -37,6 +37,18 @@ static const BYTE bayer_4x4[4][4] =
{ 15, 7, 13, 5 }
};
static const BYTE bayer_8x8[8][8] =
{
{ 0, 32, 8, 40, 2, 34, 10, 42 },
{ 48, 16, 56, 24, 50, 18, 58, 26 },
{ 12, 44, 4, 36, 14, 46, 6, 38 },
{ 60, 28, 52, 20, 62, 30, 54, 22 },
{ 3, 35, 11, 43, 1, 33, 9, 41 },
{ 51, 19, 59, 27, 49, 17, 57, 25 },
{ 15, 47, 7, 39, 13, 45, 5, 37 },
{ 63, 31, 55, 23, 61, 29, 53, 21 }
};
static const BYTE bayer_16x16[16][16] =
{
{ 0, 128, 32, 160, 8, 136, 40, 168, 2, 130, 34, 162, 10, 138, 42, 170 },
@ -5041,6 +5053,174 @@ static void create_rop_masks_null(const dib_info *dib, const BYTE *hatch_ptr,
{
}
static void create_dither_masks_8(const dib_info *dib, int rop2, COLORREF color, rop_mask_bits *bits)
{
/* mapping between RGB triples and the default color table */
static const BYTE mapping[27] =
{
0, /* 000000 -> 000000 */
4, /* 00007f -> 000080 */
252, /* 0000ff -> 0000ff */
2, /* 007f00 -> 008000 */
6, /* 007f7f -> 008080 */
224, /* 007fff -> 0080c0 */
250, /* 00ff00 -> 00ff00 */
184, /* 00ff7f -> 00e080 */
254, /* 00ffff -> 00ffff */
1, /* 7f0000 -> 800000 */
5, /* 7f007f -> 800080 */
196, /* 7f00ff -> 8000c0 */
3, /* 7f7f00 -> 808000 */
248, /* 7f7f7f -> 808080 */
228, /* 7f7fff -> 8080c0 */
60, /* 7fff00 -> 80e000 */
188, /* 7fff7f -> 80e080 */
244, /* 7fffff -> 80c0c0 */
249, /* ff0000 -> ff0000 */
135, /* ff007f -> e00080 */
253, /* ff00ff -> ff00ff */
39, /* ff7f00 -> e08000 */
167, /* ff7f7f -> e08080 */
231, /* ff7fff -> e080c0 */
251, /* ffff00 -> ffff00 */
191, /* ffff7f -> e0e080 */
255 /* ffffff -> ffffff */
};
BYTE *and_bits = bits->and, *xor_bits = bits->xor;
struct rop_codes codes;
int x, y;
/* masks are always 8x8 */
assert( dib->width == 8 );
assert( dib->height == 8 );
get_rop_codes( rop2, &codes );
for (y = 0; y < 8; y++)
{
for (x = 0; x < 8; x++)
{
DWORD r = ((GetRValue(color) + 1) / 2 + bayer_8x8[y][x]) / 64;
DWORD g = ((GetGValue(color) + 1) / 2 + bayer_8x8[y][x]) / 64;
DWORD b = ((GetBValue(color) + 1) / 2 + bayer_8x8[y][x]) / 64;
DWORD pixel = mapping[r * 9 + g * 3 + b];
and_bits[x] = (pixel & codes.a1) ^ codes.a2;
xor_bits[x] = (pixel & codes.x1) ^ codes.x2;
}
and_bits += dib->stride;
xor_bits += dib->stride;
}
}
static void create_dither_masks_4(const dib_info *dib, int rop2, COLORREF color, rop_mask_bits *bits)
{
/* mapping between RGB triples and the default color table */
static const BYTE mapping[27] =
{
0, /* 000000 -> 000000 */
4, /* 00007f -> 000080 */
12, /* 0000ff -> 0000ff */
2, /* 007f00 -> 008000 */
6, /* 007f7f -> 008080 */
6, /* 007fff -> 008080 */
10, /* 00ff00 -> 00ff00 */
6, /* 00ff7f -> 008080 */
14, /* 00ffff -> 00ffff */
1, /* 7f0000 -> 800000 */
5, /* 7f007f -> 800080 */
5, /* 7f00ff -> 800080 */
3, /* 7f7f00 -> 808000 */
7, /* 7f7f7f -> 808080 */
8, /* 7f7fff -> c0c0c0 */
3, /* 7fff00 -> 808000 */
8, /* 7fff7f -> c0c0c0 */
8, /* 7fffff -> c0c0c0 */
9, /* ff0000 -> ff0000 */
5, /* ff007f -> 800080 */
13, /* ff00ff -> ff00ff */
3, /* ff7f00 -> 808000 */
8, /* ff7f7f -> c0c0c0 */
8, /* ff7fff -> c0c0c0 */
11, /* ffff00 -> ffff00 */
8, /* ffff7f -> c0c0c0 */
15 /* ffffff -> ffffff */
};
BYTE *and_bits = bits->and, *xor_bits = bits->xor;
struct rop_codes codes;
int x, y;
/* masks are always 8x8 */
assert( dib->width == 8 );
assert( dib->height == 8 );
get_rop_codes( rop2, &codes );
for (y = 0; y < 8; y++)
{
for (x = 0; x < 8; x++)
{
DWORD r = ((GetRValue(color) + 1) / 2 + bayer_8x8[y][x]) / 64;
DWORD g = ((GetGValue(color) + 1) / 2 + bayer_8x8[y][x]) / 64;
DWORD b = ((GetBValue(color) + 1) / 2 + bayer_8x8[y][x]) / 64;
DWORD pixel = mapping[r * 9 + g * 3 + b];
if (x & 1)
{
and_bits[x / 2] |= (pixel & codes.a1) ^ codes.a2;
xor_bits[x / 2] |= (pixel & codes.x1) ^ codes.x2;
}
else
{
and_bits[x / 2] = ((pixel & codes.a1) ^ codes.a2) << 4;
xor_bits[x / 2] = ((pixel & codes.x1) ^ codes.x2) << 4;
}
}
and_bits += dib->stride;
xor_bits += dib->stride;
}
}
static void create_dither_masks_1(const dib_info *dib, int rop2, COLORREF color, rop_mask_bits *bits)
{
BYTE *and_bits = bits->and, *xor_bits = bits->xor;
struct rop_codes codes;
rop_mask rop_mask;
int x, y, grey = (30 * GetRValue(color) + 59 * GetGValue(color) + 11 * GetBValue(color) + 200) / 400;
/* masks are always 8x8 */
assert( dib->width == 8 );
assert( dib->height == 8 );
get_rop_codes( rop2, &codes );
for (y = 0; y < 8; y++)
{
*and_bits = *xor_bits = 0;
for (x = 0; x < 8; x++)
{
if (grey + bayer_8x8[y][x] > 63)
{
rop_mask.and = (0xff & codes.a1) ^ codes.a2;
rop_mask.xor = (0xff & codes.x1) ^ codes.x2;
}
else
{
rop_mask.and = (0x00 & codes.a1) ^ codes.a2;
rop_mask.xor = (0x00 & codes.x1) ^ codes.x2;
}
*and_bits |= (rop_mask.and & pixel_masks_1[x]);
*xor_bits |= (rop_mask.xor & pixel_masks_1[x]);
}
and_bits += dib->stride;
xor_bits += dib->stride;
}
}
static void create_dither_masks_null(const dib_info *dib, int rop2, COLORREF color, rop_mask_bits *bits)
{
}
static inline void rop_codes_from_stretch_mode( int mode, struct rop_codes *codes )
{
switch (mode)
@ -5460,6 +5640,7 @@ const primitive_funcs funcs_8888 =
pixel_to_colorref_888,
convert_to_8888,
create_rop_masks_32,
create_dither_masks_null,
stretch_row_32,
shrink_row_32
};
@ -5478,6 +5659,7 @@ const primitive_funcs funcs_32 =
pixel_to_colorref_masks,
convert_to_32,
create_rop_masks_32,
create_dither_masks_null,
stretch_row_32,
shrink_row_32
};
@ -5496,6 +5678,7 @@ const primitive_funcs funcs_24 =
pixel_to_colorref_888,
convert_to_24,
create_rop_masks_24,
create_dither_masks_null,
stretch_row_24,
shrink_row_24
};
@ -5514,6 +5697,7 @@ const primitive_funcs funcs_555 =
pixel_to_colorref_555,
convert_to_555,
create_rop_masks_16,
create_dither_masks_null,
stretch_row_16,
shrink_row_16
};
@ -5532,6 +5716,7 @@ const primitive_funcs funcs_16 =
pixel_to_colorref_masks,
convert_to_16,
create_rop_masks_16,
create_dither_masks_null,
stretch_row_16,
shrink_row_16
};
@ -5550,6 +5735,7 @@ const primitive_funcs funcs_8 =
pixel_to_colorref_colortable,
convert_to_8,
create_rop_masks_8,
create_dither_masks_8,
stretch_row_8,
shrink_row_8
};
@ -5568,6 +5754,7 @@ const primitive_funcs funcs_4 =
pixel_to_colorref_colortable,
convert_to_4,
create_rop_masks_4,
create_dither_masks_4,
stretch_row_4,
shrink_row_4
};
@ -5586,6 +5773,7 @@ const primitive_funcs funcs_1 =
pixel_to_colorref_colortable,
convert_to_1,
create_rop_masks_1,
create_dither_masks_1,
stretch_row_1,
shrink_row_1
};
@ -5604,6 +5792,7 @@ const primitive_funcs funcs_null =
pixel_to_colorref_null,
convert_to_null,
create_rop_masks_null,
create_dither_masks_null,
stretch_row_null,
shrink_row_null
};