Huw Davies : gdi32: Add support for drawing horizontal patterned lines.
Alexandre Julliard
julliard at winehq.org
Fri May 6 13:44:07 CDT 2011
Module: wine
Branch: master
Commit: 6976cee4250ceee898669d4bf7c17750667f9c32
URL: http://source.winehq.org/git/wine.git/?a=commit;h=6976cee4250ceee898669d4bf7c17750667f9c32
Author: Huw Davies <huw at 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);
}
More information about the wine-cvs
mailing list