gdiplus: Fix hatch brush patterns that require anti-aliasing.
Signed-off-by: Jeff Smith <whydoubt@gmail.com> Signed-off-by: Esme Povirk <vincent@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
a75584ec1b
commit
d0c70facbd
|
@ -197,13 +197,15 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
|
|||
return Ok;
|
||||
}
|
||||
|
||||
static const char HatchBrushes[][8] = {
|
||||
/* The first 8 items per entry are bitmaps for each row of the hatch style.
|
||||
* The 9th item of the entry is a flag indicating anti-aliasing. */
|
||||
static const unsigned char HatchBrushes[][9] = {
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff }, /* HatchStyleHorizontal */
|
||||
{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, /* HatchStyleVertical */
|
||||
{ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HatchStyleForwardDiagonal */
|
||||
{ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HatchStyleBackwardDiagonal */
|
||||
{ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, TRUE }, /* HatchStyleForwardDiagonal */
|
||||
{ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, TRUE }, /* HatchStyleBackwardDiagonal */
|
||||
{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xff }, /* HatchStyleCross */
|
||||
{ 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }, /* HatchStyleDiagonalCross */
|
||||
{ 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81, TRUE }, /* HatchStyleDiagonalCross */
|
||||
{ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80 }, /* HatchStyle05Percent */
|
||||
{ 0x00, 0x08, 0x00, 0x80, 0x00, 0x08, 0x00, 0x80 }, /* HatchStyle10Percent */
|
||||
{ 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00, 0x88 }, /* HatchStyle20Percent */
|
||||
|
@ -230,7 +232,7 @@ static const char HatchBrushes[][8] = {
|
|||
{ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff }, /* HatchStyleDarkHorizontal */
|
||||
};
|
||||
|
||||
GpStatus get_hatch_data(GpHatchStyle hatchstyle, const char **result)
|
||||
GpStatus get_hatch_data(GpHatchStyle hatchstyle, const unsigned char **result)
|
||||
{
|
||||
if (hatchstyle < ARRAY_SIZE(HatchBrushes))
|
||||
{
|
||||
|
|
|
@ -123,7 +123,7 @@ extern GpStatus trace_path(GpGraphics *graphics, GpPath *path) DECLSPEC_HIDDEN;
|
|||
typedef struct region_element region_element;
|
||||
extern void delete_element(region_element *element) DECLSPEC_HIDDEN;
|
||||
|
||||
extern GpStatus get_hatch_data(GpHatchStyle hatchstyle, const char **result) DECLSPEC_HIDDEN;
|
||||
extern GpStatus get_hatch_data(GpHatchStyle hatchstyle, const unsigned char **result) DECLSPEC_HIDDEN;
|
||||
|
||||
static inline INT gdip_round(REAL x)
|
||||
{
|
||||
|
|
|
@ -114,6 +114,19 @@ static COLORREF get_gdi_brush_color(const GpBrush *brush)
|
|||
return ARGB2COLORREF(argb);
|
||||
}
|
||||
|
||||
static ARGB blend_colors(ARGB start, ARGB end, REAL position);
|
||||
|
||||
static void init_hatch_palette(ARGB *hatch_palette, ARGB fore_color, ARGB back_color)
|
||||
{
|
||||
/* Pass the center of a 45-degree diagonal line with width of one unit through the
|
||||
* center of a unit square, and the portion of the square that will be covered will
|
||||
* equal sqrt(2) - 1/2. The covered portion for adjacent squares will be 1/4. */
|
||||
hatch_palette[0] = back_color;
|
||||
hatch_palette[1] = blend_colors(back_color, fore_color, 0.25);
|
||||
hatch_palette[2] = blend_colors(back_color, fore_color, sqrt(2.0) - 0.5);
|
||||
hatch_palette[3] = fore_color;
|
||||
}
|
||||
|
||||
static HBITMAP create_hatch_bitmap(const GpHatch *hatch)
|
||||
{
|
||||
HBITMAP hbmp;
|
||||
|
@ -132,18 +145,30 @@ static HBITMAP create_hatch_bitmap(const GpHatch *hatch)
|
|||
hbmp = CreateDIBSection(0, (BITMAPINFO *)&bmih, DIB_RGB_COLORS, (void **)&bits, NULL, 0);
|
||||
if (hbmp)
|
||||
{
|
||||
const char *hatch_data;
|
||||
const unsigned char *hatch_data;
|
||||
|
||||
if (get_hatch_data(hatch->hatchstyle, &hatch_data) == Ok)
|
||||
{
|
||||
ARGB hatch_palette[4];
|
||||
init_hatch_palette(hatch_palette, hatch->forecol, hatch->backcol);
|
||||
|
||||
/* Anti-aliasing is only specified for diagonal hatch patterns.
|
||||
* This implementation repeats the pattern, shifts as needed,
|
||||
* then uses bitmask 1 to check the pixel value, and the 0x82
|
||||
* bitmask to check the adjacent pixel values, to determine the
|
||||
* degree of shading needed. */
|
||||
for (y = 0; y < 8; y++)
|
||||
{
|
||||
for (x = 0; x < 8; x++)
|
||||
unsigned int row = 0x101 * hatch_data[y];
|
||||
|
||||
for (x = 0; x < 8; x++, row >>= 1)
|
||||
{
|
||||
if (hatch_data[y] & (0x80 >> x))
|
||||
bits[y * 8 + x] = hatch->forecol;
|
||||
int index;
|
||||
if (hatch_data[8])
|
||||
index = (row & 1) ? 2 : (row & 0x82) ? 1 : 0;
|
||||
else
|
||||
bits[y * 8 + x] = hatch->backcol;
|
||||
index = (row & 1) ? 3 : 0;
|
||||
bits[y * 8 + 7 - x] = hatch_palette[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1160,24 +1185,32 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
|
|||
{
|
||||
int x, y;
|
||||
GpHatch *fill = (GpHatch*)brush;
|
||||
const char *hatch_data;
|
||||
const unsigned char *hatch_data;
|
||||
ARGB hatch_palette[4];
|
||||
|
||||
if (get_hatch_data(fill->hatchstyle, &hatch_data) != Ok)
|
||||
return NotImplemented;
|
||||
|
||||
for (x=0; x<fill_area->Width; x++)
|
||||
for (y=0; y<fill_area->Height; y++)
|
||||
init_hatch_palette(hatch_palette, fill->forecol, fill->backcol);
|
||||
|
||||
/* See create_hatch_bitmap for an explanation of how index is derived. */
|
||||
for (y = 0; y < fill_area->Height; y++, argb_pixels += cdwStride)
|
||||
{
|
||||
int hx, hy;
|
||||
|
||||
/* FIXME: Account for the rendering origin */
|
||||
hx = (x + fill_area->X) % 8;
|
||||
hy = (y + fill_area->Y) % 8;
|
||||
const int hy = 7 - ((y + fill_area->Y) % 8);
|
||||
const unsigned int row = 0x101 * hatch_data[hy];
|
||||
|
||||
if ((hatch_data[7-hy] & (0x80 >> hx)) != 0)
|
||||
argb_pixels[x + y*cdwStride] = fill->forecol;
|
||||
for (x = 0; x < fill_area->Width; x++)
|
||||
{
|
||||
const unsigned int srow = row >> (7 - ((x + fill_area->X) % 8));
|
||||
int index;
|
||||
if (hatch_data[8])
|
||||
index = (srow & 1) ? 2 : (srow & 0x82) ? 1 : 0;
|
||||
else
|
||||
argb_pixels[x + y*cdwStride] = fill->backcol;
|
||||
index = (srow & 1) ? 3 : 0;
|
||||
|
||||
argb_pixels[x] = hatch_palette[index];
|
||||
}
|
||||
}
|
||||
|
||||
return Ok;
|
||||
|
|
|
@ -1650,16 +1650,15 @@ static void test_hatchBrushStyles(void)
|
|||
{
|
||||
short pattern[8];
|
||||
GpHatchStyle hs;
|
||||
BOOL todo;
|
||||
}
|
||||
styles[] =
|
||||
{
|
||||
{ {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff}, HatchStyleHorizontal },
|
||||
{ {0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000}, HatchStyleVertical },
|
||||
{ {0x4006, 0x0019, 0x0064, 0x0190, 0x0640, 0x1900, 0x6400, 0x9001}, HatchStyleForwardDiagonal, TRUE },
|
||||
{ {0x9001, 0x6400, 0x1900, 0x0640, 0x0190, 0x0064, 0x0019, 0x4006}, HatchStyleBackwardDiagonal, TRUE },
|
||||
{ {0x4006, 0x0019, 0x0064, 0x0190, 0x0640, 0x1900, 0x6400, 0x9001}, HatchStyleForwardDiagonal },
|
||||
{ {0x9001, 0x6400, 0x1900, 0x0640, 0x0190, 0x0064, 0x0019, 0x4006}, HatchStyleBackwardDiagonal },
|
||||
{ {0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xffff}, HatchStyleCross },
|
||||
{ {0x9006, 0x6419, 0x1964, 0x0690, 0x0690, 0x1964, 0x6419, 0x9006}, HatchStyleDiagonalCross, TRUE },
|
||||
{ {0x9006, 0x6419, 0x1964, 0x0690, 0x0690, 0x1964, 0x6419, 0x9006}, HatchStyleDiagonalCross },
|
||||
{ {0x0000, 0x0000, 0x0000, 0x00c0, 0x0000, 0x0000, 0x0000, 0xc000}, HatchStyle05Percent },
|
||||
{ {0x0000, 0x00c0, 0x0000, 0xc000, 0x0000, 0x00c0, 0x0000, 0xc000}, HatchStyle10Percent },
|
||||
{ {0x0000, 0x0c0c, 0x0000, 0xc0c0, 0x0000, 0x0c0c, 0x0000, 0xc0c0}, HatchStyle20Percent },
|
||||
|
@ -1742,12 +1741,9 @@ static void test_hatchBrushStyles(void)
|
|||
match_image = FALSE;
|
||||
}
|
||||
}
|
||||
todo_wine_if(styles[i].todo)
|
||||
{
|
||||
ok(match_hdc, "Unexpected pattern for hatch style %#x with hdc.\n", styles[i].hs);
|
||||
ok(match_image, "Unexpected pattern for hatch style %#x with image.\n", styles[i].hs);
|
||||
}
|
||||
}
|
||||
|
||||
status = GdipDeleteGraphics(graphics_image);
|
||||
expect(Ok, status);
|
||||
|
|
Loading…
Reference in New Issue