Module: wine Branch: master Commit: 6976cee4250ceee898669d4bf7c17750667f9c32 URL: http://source.winehq.org/git/wine.git/?a=commit;h=6976cee4250ceee898669d4bf7...
Author: Huw Davies huw@codeweavers.com Date: Fri May 6 11:48:34 2011 +0100
gdi32: Add support for drawing horizontal patterned lines.
---
dlls/gdi32/dibdrv/dibdrv.h | 1 + dlls/gdi32/dibdrv/graphics.c | 2 + dlls/gdi32/dibdrv/objects.c | 132 +++++++++++++++++++++++++++++++++++++++++- dlls/gdi32/gdi_private.h | 10 +++- dlls/gdi32/tests/dib.c | 29 +++++++++- 5 files changed, 170 insertions(+), 4 deletions(-)
diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h index c6cdd62..c2b3294 100644 --- a/dlls/gdi32/dibdrv/dibdrv.h +++ b/dlls/gdi32/dibdrv/dibdrv.h @@ -47,6 +47,7 @@ extern const primitive_funcs funcs_null DECLSPEC_HIDDEN;
extern void calc_and_xor_masks(INT rop, DWORD color, DWORD *and, DWORD *xor) DECLSPEC_HIDDEN; extern void update_brush_rop( dibdrv_physdev *pdev, INT rop ) DECLSPEC_HIDDEN; +extern void reset_dash_origin(dibdrv_physdev *pdev) DECLSPEC_HIDDEN;
static inline BOOL defer_pen(dibdrv_physdev *pdev) { diff --git a/dlls/gdi32/dibdrv/graphics.c b/dlls/gdi32/dibdrv/graphics.c index 7d0f2e9..c231434 100644 --- a/dlls/gdi32/dibdrv/graphics.c +++ b/dlls/gdi32/dibdrv/graphics.c @@ -71,6 +71,8 @@ BOOL CDECL dibdrv_LineTo( PHYSDEV dev, INT x, INT y )
LPtoDP(dev->hdc, pts, 2);
+ reset_dash_origin(pdev); + if(defer_pen(pdev) || !pdev->pen_line(pdev, pts, pts + 1)) return next->funcs->pLineTo( next, x, y );
diff --git a/dlls/gdi32/dibdrv/objects.c b/dlls/gdi32/dibdrv/objects.c index 25aad8e..cb58f4b 100644 --- a/dlls/gdi32/dibdrv/objects.c +++ b/dlls/gdi32/dibdrv/objects.c @@ -544,9 +544,139 @@ static BOOL solid_pen_line(dibdrv_physdev *pdev, POINT *start, POINT *end) return TRUE; }
+void reset_dash_origin(dibdrv_physdev *pdev) +{ + pdev->dash_pos.cur_dash = 0; + pdev->dash_pos.left_in_dash = pdev->pen_pattern.dashes[0]; + pdev->dash_pos.mark = TRUE; +} + +static inline void skip_dash(dibdrv_physdev *pdev, unsigned int skip) +{ + skip %= pdev->pen_pattern.total_len; + while(skip) + { + if(pdev->dash_pos.left_in_dash > skip) + { + pdev->dash_pos.left_in_dash -= skip; + return; + } + skip -= pdev->dash_pos.left_in_dash; + pdev->dash_pos.cur_dash++; + if(pdev->dash_pos.cur_dash == pdev->pen_pattern.count) pdev->dash_pos.cur_dash = 0; + pdev->dash_pos.left_in_dash = pdev->pen_pattern.dashes[pdev->dash_pos.cur_dash]; + pdev->dash_pos.mark = !pdev->dash_pos.mark; + } +} + +static inline void get_dash_colors(const dibdrv_physdev *pdev, DWORD *and, DWORD *xor) +{ + if(pdev->dash_pos.mark) + { + *and = pdev->pen_and; + *xor = pdev->pen_xor; + } + else /* space */ + { + *and = pdev->bkgnd_and; + *xor = pdev->bkgnd_xor; + } +} + static BOOL dashed_pen_line(dibdrv_physdev *pdev, POINT *start, POINT *end) { - return FALSE; + const WINEREGION *clip = get_wine_region(pdev->clip); + DWORD and, xor; + int i, dash_len; + RECT rect; + const dash_pos start_pos = pdev->dash_pos; + BOOL ret = TRUE; + + if(start->y == end->y) /* hline */ + { + BOOL l_to_r; + INT left, right, cur_x; + + rect.top = start->y; + rect.bottom = start->y + 1; + + if(start->x <= end->x) + { + left = start->x; + right = end->x - 1; + l_to_r = TRUE; + } + else + { + left = end->x + 1; + right = start->x; + l_to_r = FALSE; + } + + for(i = 0; i < clip->numRects; i++) + { + if(clip->rects[i].top > start->y) break; + if(clip->rects[i].bottom <= start->y) continue; + + if(clip->rects[i].right > left && clip->rects[i].left <= right) + { + int clipped_left = max(clip->rects[i].left, left); + int clipped_right = min(clip->rects[i].right - 1, right); + + pdev->dash_pos = start_pos; + + if(l_to_r) + { + cur_x = clipped_left; + if(cur_x != left) + skip_dash(pdev, clipped_left - left); + + while(cur_x <= clipped_right) + { + get_dash_colors(pdev, &and, &xor); + dash_len = pdev->dash_pos.left_in_dash; + if(cur_x + dash_len > clipped_right + 1) + dash_len = clipped_right - cur_x + 1; + rect.left = cur_x; + rect.right = cur_x + dash_len; + + pdev->dib.funcs->solid_rects(&pdev->dib, 1, &rect, and, xor); + cur_x += dash_len; + skip_dash(pdev, dash_len); + } + } + else + { + cur_x = clipped_right; + if(cur_x != right) + skip_dash(pdev, right - clipped_right); + + while(cur_x >= clipped_left) + { + get_dash_colors(pdev, &and, &xor); + dash_len = pdev->dash_pos.left_in_dash; + if(cur_x - dash_len < clipped_left - 1) + dash_len = cur_x - clipped_left + 1; + rect.left = cur_x - dash_len + 1; + rect.right = cur_x + 1; + + pdev->dib.funcs->solid_rects(&pdev->dib, 1, &rect, and, xor); + cur_x -= dash_len; + skip_dash(pdev, dash_len); + } + } + } + } + pdev->dash_pos = start_pos; + skip_dash(pdev, right - left + 1); + } + else + { + ret = FALSE; + } + + release_wine_region(pdev->clip); + return ret; }
static const dash_pattern dash_patterns[4] = diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index 0a90fb1..7b4c585 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -99,6 +99,13 @@ typedef struct DWORD total_len; /* total length of the dashes, should be multiplied by 2 if there are an odd number of dash lengths */ } dash_pattern;
+typedef struct +{ + int left_in_dash; + int cur_dash; + BOOL mark; +} dash_pos; + typedef struct dibdrv_physdev { struct gdi_physdev dev; @@ -109,8 +116,9 @@ typedef struct dibdrv_physdev
/* pen */ DWORD pen_color, pen_and, pen_xor; - BOOL (* pen_line)(struct dibdrv_physdev *pdev, POINT *start, POINT *end); dash_pattern pen_pattern; + dash_pos dash_pos; + BOOL (* pen_line)(struct dibdrv_physdev *pdev, POINT *start, POINT *end);
/* brush */ UINT brush_style; diff --git a/dlls/gdi32/tests/dib.c b/dlls/gdi32/tests/dib.c index 57a2969..6b7a0bf 100644 --- a/dlls/gdi32/tests/dib.c +++ b/dlls/gdi32/tests/dib.c @@ -84,6 +84,8 @@ static const char *sha1_graphics_a8r8g8b8[] = "d51bd330cec510cdccf5394328bd8e5411901e9e", "df4aebf98d91f11be560dd232123b3ae327303d7", "f2af53dd073a09b1031d0032d28da35c82adc566", + "eb5a963a6f7b25533ddfb8915e70865d037bd156", + "c387917268455017aa0b28bed73aa6554044bbb3", NULL };
@@ -237,7 +239,7 @@ static const RECT patblt_clips[] = static void draw_graphics(HDC hdc, BITMAPINFO *bmi, BYTE *bits, const char ***sha1) { DWORD dib_size = get_dib_size(bmi); - HPEN solid_pen, orig_pen; + HPEN solid_pen, dashed_pen, orig_pen; HBRUSH solid_brush, orig_brush; INT i, y; HRGN hrgn, hrgn2; @@ -349,12 +351,35 @@ static void draw_graphics(HDC hdc, BITMAPINFO *bmi, BYTE *bits, const char ***sh patblt_clips[i].bottom - patblt_clips[i].top, PATCOPY); } compare_hash(bmi, bits, sha1, "clipped patblt"); + memset(bits, 0xcc, dib_size);
- ExtSelectClipRgn(hdc, NULL, RGN_COPY); + /* clipped dashed lines */ + dashed_pen = CreatePen(PS_DASH, 1, RGB(0xff, 0, 0)); + SelectObject(hdc, dashed_pen); + SetBkMode(hdc, TRANSPARENT); + SetBkColor(hdc, RGB(0, 0xff, 0));
+ for(i = 0; i < sizeof(hline_clips)/sizeof(hline_clips[0]); i++) + { + MoveToEx(hdc, hline_clips[i].left, hline_clips[i].top, NULL); + LineTo(hdc, hline_clips[i].right, hline_clips[i].bottom); + } + compare_hash(bmi, bits, sha1, "clipped dashed hlines"); + memset(bits, 0xcc, dib_size); + + for(i = 0; i < sizeof(hline_clips)/sizeof(hline_clips[0]); i++) + { + MoveToEx(hdc, hline_clips[i].right - 1, hline_clips[i].bottom, NULL); + LineTo(hdc, hline_clips[i].left - 1, hline_clips[i].top); + } + compare_hash(bmi, bits, sha1, "clipped dashed hlines r -> l"); + memset(bits, 0xcc, dib_size); + + ExtSelectClipRgn(hdc, NULL, RGN_COPY);
SelectObject(hdc, orig_brush); SelectObject(hdc, orig_pen); + DeleteObject(dashed_pen); DeleteObject(solid_brush); DeleteObject(solid_pen); }