Signed-off-by: Jeff Smith whydoubt@gmail.com --- dlls/gdiplus/brush.c | 12 +++--- dlls/gdiplus/gdiplus_private.h | 2 +- dlls/gdiplus/graphics.c | 73 ++++++++++++++++++++++++++-------- dlls/gdiplus/tests/brush.c | 13 ++---- 4 files changed, 68 insertions(+), 32 deletions(-)
diff --git a/dlls/gdiplus/brush.c b/dlls/gdiplus/brush.c index aa1cda1990..4b6ccca12a 100644 --- a/dlls/gdiplus/brush.c +++ b/dlls/gdiplus/brush.c @@ -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)) { diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 9e90a5d28c..d62860360a 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -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) { diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 72075e02fb..c2421339e5 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -114,6 +114,27 @@ static COLORREF get_gdi_brush_color(const GpBrush *brush) return ARGB2COLORREF(argb); }
+static ARGB blend_colors_pre(ARGB start, ARGB end, REAL position) +{ + const BYTE a = ((start >> 24) & 0xff) * (1 - position) + ((end >> 24) & 0xff) * position; + const BYTE r = ((start >> 16) & 0xff) * (1 - position) + ((end >> 16) & 0xff) * position; + const BYTE g = ((start >> 8) & 0xff) * (1 - position) + ((end >> 8) & 0xff) * position; + const BYTE b = (start & 0xff) * (1 - position) + (end & 0xff) * position; + + return (a << 24) | (r << 16) | (g << 8) | b; +} + +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_pre(back_color, fore_color, 0.25); + hatch_palette[2] = blend_colors_pre(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 +153,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,25 +1193,33 @@ 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++) - { - int hx, hy; + init_hatch_palette(hatch_palette, fill->forecol, fill->backcol);
- /* FIXME: Account for the rendering origin */ - hx = (x + fill_area->X) % 8; - hy = (y + fill_area->Y) % 8; + /* See create_hatch_bitmap for an explanation of how index is derived. */ + for (y = 0; y < fill_area->Height; y++, argb_pixels += cdwStride) + { + /* FIXME: Account for the rendering origin */ + 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; } diff --git a/dlls/gdiplus/tests/brush.c b/dlls/gdiplus/tests/brush.c index 8e50318268..4afc6fcb76 100644 --- a/dlls/gdiplus/tests/brush.c +++ b/dlls/gdiplus/tests/brush.c @@ -1649,16 +1649,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 }, @@ -1741,11 +1740,8 @@ 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); @@ -1825,8 +1821,6 @@ static void test_hatchBrushColors(void) const int x = pixel_coord[j][0]; const int y = pixel_coord[j][1];
- todo_wine_if(j == 1 || j == 2) - { color = get_pixel_as_argb(hdc, x, y); ok(color == exp_color, "For hwnd (%d, %d) colorset %d expected %08x, got %08x.\n", x, y, i, exp_color, color); @@ -1838,7 +1832,6 @@ static void test_hatchBrushColors(void) GdipBitmapGetPixel(bitmap_a, x, y, &color); ok(color == exp_color, "For argb image (%d, %d) colorset %d expected %08x, got %08x.\n", x, y, i, exp_color, color); - } } }