Alexandre Julliard : gdi32: Implement dashed wide lines.
Alexandre Julliard
julliard at winehq.org
Wed Jan 4 13:53:00 CST 2012
Module: wine
Branch: master
Commit: c82d2a034f918a297915e39784ddfe949b37919c
URL: http://source.winehq.org/git/wine.git/?a=commit;h=c82d2a034f918a297915e39784ddfe949b37919c
Author: Alexandre Julliard <julliard at winehq.org>
Date: Wed Jan 4 15:05:00 2012 +0100
gdi32: Implement dashed wide lines.
---
dlls/gdi32/dibdrv/objects.c | 144 +++++++++++++++++++++++++++++++++++++++++--
1 files changed, 138 insertions(+), 6 deletions(-)
diff --git a/dlls/gdi32/dibdrv/objects.c b/dlls/gdi32/dibdrv/objects.c
index 6933346..51a49cc 100644
--- a/dlls/gdi32/dibdrv/objects.c
+++ b/dlls/gdi32/dibdrv/objects.c
@@ -1523,6 +1523,125 @@ static BOOL wide_pen_lines(dibdrv_physdev *pdev, int num, POINT *pts, BOOL close
return TRUE;
}
+static BOOL dashed_wide_pen_lines(dibdrv_physdev *pdev, int num, POINT *pts, BOOL close, HRGN total)
+{
+ int i, start, cur_len, initial_num = 0;
+ POINT initial_point, start_point, end_point;
+ HRGN round_cap = 0;
+
+ assert( total != 0 ); /* wide pens should always be drawn through a region */
+ assert( num >= 2 );
+
+ /* skip empty segments */
+ while (num > 2 && pts[0].x == pts[1].x && pts[0].y == pts[1].y) { pts++; num--; }
+ while (num > 2 && pts[num - 1].x == pts[num - 2].x && pts[num - 1].y == pts[num - 2].y) num--;
+
+ if (pdev->pen_join == PS_JOIN_ROUND || pdev->pen_endcap == PS_ENDCAP_ROUND)
+ round_cap = CreateEllipticRgn( -(pdev->pen_width / 2), -(pdev->pen_width / 2),
+ (pdev->pen_width + 1) / 2, (pdev->pen_width + 1) / 2 );
+
+ start = 0;
+ cur_len = 0;
+ start_point = pts[0];
+
+ for (i = 0; i < (close ? num : num - 1); i++)
+ {
+ const POINT *pt_1 = pts + i;
+ const POINT *pt_2 = pts + ((close && i == num - 1) ? 0 : i + 1);
+ int dx = pt_2->x - pt_1->x;
+ int dy = pt_2->y - pt_1->y;
+
+ if (dx == 0 && dy == 0) continue;
+
+ if (dy == 0)
+ {
+ if (abs( dx ) - cur_len < pdev->dash_pos.left_in_dash)
+ {
+ skip_dash( pdev, abs( dx ) - cur_len );
+ cur_len = 0;
+ continue;
+ }
+ cur_len += pdev->dash_pos.left_in_dash;
+ dx = (dx > 0) ? cur_len : -cur_len;
+ }
+ else if (dx == 0)
+ {
+ if (abs( dy ) - cur_len < pdev->dash_pos.left_in_dash)
+ {
+ skip_dash( pdev, abs( dy ) - cur_len );
+ cur_len = 0;
+ continue;
+ }
+ cur_len += pdev->dash_pos.left_in_dash;
+ dy = (dy > 0) ? cur_len : -cur_len;
+ }
+ else
+ {
+ double len = hypot( dx, dy );
+
+ if (len - cur_len < pdev->dash_pos.left_in_dash)
+ {
+ skip_dash( pdev, len - cur_len );
+ cur_len = 0;
+ continue;
+ }
+ cur_len += pdev->dash_pos.left_in_dash;
+ dx = dx * cur_len / len;
+ dy = dy * cur_len / len;
+ }
+ end_point.x = pt_1->x + dx;
+ end_point.y = pt_1->y + dy;
+
+ if (pdev->dash_pos.mark)
+ {
+ if (!initial_num && close) /* this is the first dash, save it for later */
+ {
+ initial_num = i - start + 1;
+ initial_point = end_point;
+ }
+ else wide_line_segments( pdev, num, pts, FALSE, start, i - start + 1,
+ &start_point, &end_point, round_cap, total );
+ }
+ if (!initial_num) initial_num = -1; /* no need to close it */
+
+ skip_dash( pdev, pdev->dash_pos.left_in_dash );
+ start_point = end_point;
+ start = i;
+ i--; /* go on with the same segment */
+ }
+
+ if (pdev->dash_pos.mark) /* we have a final dash */
+ {
+ int count;
+
+ if (initial_num > 0)
+ {
+ count = num - start + initial_num;
+ end_point = initial_point;
+ }
+ else if (close)
+ {
+ count = num - start;
+ end_point = pts[0];
+ }
+ else
+ {
+ count = num - start - 1;
+ end_point = pts[num - 1];
+ }
+ wide_line_segments( pdev, num, pts, FALSE, start, count,
+ &start_point, &end_point, round_cap, total );
+ }
+ else if (initial_num > 0) /* initial dash only */
+ {
+ wide_line_segments( pdev, num, pts, FALSE, 0, initial_num,
+ &pts[0], &initial_point, round_cap, total );
+ }
+
+ if (round_cap) DeleteObject( round_cap );
+ return TRUE;
+}
+
static const dash_pattern dash_patterns_cosmetic[4] =
{
{2, {18, 6}, 24}, /* PS_DASH */
@@ -1550,11 +1669,21 @@ static inline void set_dash_pattern( dash_pattern *pattern, DWORD count, DWORD *
if (pattern->count % 2) pattern->total_len *= 2;
}
-static inline void scale_dash_pattern( dash_pattern *pattern, DWORD scale )
+static inline void scale_dash_pattern( dash_pattern *pattern, DWORD scale, DWORD endcap )
{
DWORD i;
+
for (i = 0; i < pattern->count; i++) pattern->dashes[i] *= scale;
pattern->total_len *= scale;
+
+ if (endcap != PS_ENDCAP_FLAT) /* shrink the dashes to leave room for the caps */
+ {
+ for (i = 0; i < pattern->count; i += 2)
+ {
+ pattern->dashes[i] -= scale;
+ pattern->dashes[i + 1] += scale;
+ }
+ }
}
static inline int get_pen_device_width( dibdrv_physdev *pdev, int width )
@@ -1971,9 +2100,13 @@ HPEN dibdrv_SelectPen( PHYSDEV dev, HPEN hpen, const struct brush_pattern *patte
case PS_DASHDOTDOT:
if (logpen.lopnStyle & PS_GEOMETRIC)
{
- if (pdev->pen_width > 1) break; /* not supported yet */
- pdev->pen_lines = dashed_pen_lines;
pdev->pen_pattern = dash_patterns_geometric[pdev->pen_style - 1];
+ if (pdev->pen_width > 1)
+ {
+ scale_dash_pattern( &pdev->pen_pattern, pdev->pen_width, pdev->pen_endcap );
+ pdev->pen_lines = dashed_wide_pen_lines;
+ }
+ else pdev->pen_lines = dashed_pen_lines;
pdev->defer &= ~DEFER_PEN;
break;
}
@@ -2004,10 +2137,9 @@ HPEN dibdrv_SelectPen( PHYSDEV dev, HPEN hpen, const struct brush_pattern *patte
break;
case PS_USERSTYLE:
- if (pdev->pen_width > 1) break; /* not supported yet */
- pdev->pen_lines = dashed_pen_lines;
+ pdev->pen_lines = (pdev->pen_width == 1) ? dashed_pen_lines : dashed_wide_pen_lines;
set_dash_pattern( &pdev->pen_pattern, elp->elpNumEntries, elp->elpStyleEntry );
- if (!(logpen.lopnStyle & PS_GEOMETRIC)) scale_dash_pattern( &pdev->pen_pattern, 3 );
+ if (!(logpen.lopnStyle & PS_GEOMETRIC)) scale_dash_pattern( &pdev->pen_pattern, 3, PS_ENDCAP_FLAT );
pdev->defer &= ~DEFER_PEN;
break;
}
More information about the wine-cvs
mailing list