gdi32: Implement dithering of solid brushes when drawing to DDBs.
This commit is contained in:
parent
6afed7a52b
commit
139aeba3ef
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue