gdi32: Add a helper function for drawing a wide line segment.

This commit is contained in:
Alexandre Julliard 2012-01-04 15:50:31 +01:00
parent 8b1bab524b
commit a59c53b312
1 changed files with 127 additions and 119 deletions

View File

@ -1326,42 +1326,20 @@ static void add_join( dibdrv_physdev *pdev, HRGN region, HRGN round_cap, const P
return; return;
} }
static BOOL wide_pen_lines(dibdrv_physdev *pdev, int num, POINT *pts, BOOL close, HRGN total) static void wide_line_segment( dibdrv_physdev *pdev, HRGN total,
const POINT *pt_1, const POINT *pt_2, int dx, int dy,
BOOL need_cap_1, BOOL need_cap_2, struct face *face_1, struct face *face_2 )
{ {
int i;
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 );
if (!close) num--;
for (i = 0; i < num; 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;
RECT rect; RECT rect;
struct face face_1, face_2, prev_face, first_face;
BOOL need_cap_1 = !close && (i == 0);
BOOL need_cap_2 = !close && (i == num - 1);
BOOL sq_cap_1 = need_cap_1 && (pdev->pen_endcap == PS_ENDCAP_SQUARE); BOOL sq_cap_1 = need_cap_1 && (pdev->pen_endcap == PS_ENDCAP_SQUARE);
BOOL sq_cap_2 = need_cap_2 && (pdev->pen_endcap == PS_ENDCAP_SQUARE); BOOL sq_cap_2 = need_cap_2 && (pdev->pen_endcap == PS_ENDCAP_SQUARE);
if (dx == 0 && dy == 0) continue; if (dx == 0 && dy == 0) return;
if (dy == 0) if (dy == 0)
{ {
rect.left = min( pt_1->x, pt_2->x ); rect.left = min( pt_1->x, pt_2->x );
rect.right = rect.left + abs( dx ); rect.right = max( pt_1->x, pt_2->x );
rect.top = pt_1->y - pdev->pen_width / 2; rect.top = pt_1->y - pdev->pen_width / 2;
rect.bottom = rect.top + pdev->pen_width; rect.bottom = rect.top + pdev->pen_width;
if ((sq_cap_1 && dx > 0) || (sq_cap_2 && dx < 0)) rect.left -= pdev->pen_width / 2; if ((sq_cap_1 && dx > 0) || (sq_cap_2 && dx < 0)) rect.left -= pdev->pen_width / 2;
@ -1369,23 +1347,23 @@ static BOOL wide_pen_lines(dibdrv_physdev *pdev, int num, POINT *pts, BOOL close
add_rect_to_region( total, &rect ); add_rect_to_region( total, &rect );
if (dx > 0) if (dx > 0)
{ {
face_1.start.x = face_1.end.x = rect.left; face_1->start.x = face_1->end.x = rect.left;
face_1.start.y = face_2.end.y = rect.bottom; face_1->start.y = face_2->end.y = rect.bottom;
face_1.end.y = face_2.start.y = rect.top; face_1->end.y = face_2->start.y = rect.top;
face_2.start.x = face_2.end.x = rect.right - 1; face_2->start.x = face_2->end.x = rect.right - 1;
} }
else else
{ {
face_1.start.x = face_1.end.x = rect.right; face_1->start.x = face_1->end.x = rect.right;
face_1.start.y = face_2.end.y = rect.top; face_1->start.y = face_2->end.y = rect.top;
face_1.end.y = face_2.start.y = rect.bottom; face_1->end.y = face_2->start.y = rect.bottom;
face_2.start.x = face_2.end.x = rect.left + 1; face_2->start.x = face_2->end.x = rect.left + 1;
} }
} }
else if (dx == 0) else if (dx == 0)
{ {
rect.top = min( pt_1->y, pt_2->y ); rect.top = min( pt_1->y, pt_2->y );
rect.bottom = rect.top + abs( dy ); rect.bottom = max( pt_1->y, pt_2->y );
rect.left = pt_1->x - pdev->pen_width / 2; rect.left = pt_1->x - pdev->pen_width / 2;
rect.right = rect.left + pdev->pen_width; rect.right = rect.left + pdev->pen_width;
if ((sq_cap_1 && dy > 0) || (sq_cap_2 && dy < 0)) rect.top -= pdev->pen_width / 2; if ((sq_cap_1 && dy > 0) || (sq_cap_2 && dy < 0)) rect.top -= pdev->pen_width / 2;
@ -1393,17 +1371,17 @@ static BOOL wide_pen_lines(dibdrv_physdev *pdev, int num, POINT *pts, BOOL close
add_rect_to_region( total, &rect ); add_rect_to_region( total, &rect );
if (dy > 0) if (dy > 0)
{ {
face_1.start.x = face_2.end.x = rect.left; face_1->start.x = face_2->end.x = rect.left;
face_1.start.y = face_1.end.y = rect.top; face_1->start.y = face_1->end.y = rect.top;
face_1.end.x = face_2.start.x = rect.right; face_1->end.x = face_2->start.x = rect.right;
face_2.start.y = face_2.end.y = rect.bottom - 1; face_2->start.y = face_2->end.y = rect.bottom - 1;
} }
else else
{ {
face_1.start.x = face_2.end.x = rect.right; face_1->start.x = face_2->end.x = rect.right;
face_1.start.y = face_1.end.y = rect.bottom; face_1->start.y = face_1->end.y = rect.bottom;
face_1.end.x = face_2.start.x = rect.left; face_1->end.x = face_2->start.x = rect.left;
face_2.start.y = face_2.end.y = rect.top + 1; face_2->start.y = face_2->end.y = rect.top + 1;
} }
} }
else else
@ -1464,18 +1442,48 @@ static BOOL wide_pen_lines(dibdrv_physdev *pdev, int num, POINT *pts, BOOL close
CombineRgn( total, total, segment, RGN_OR ); CombineRgn( total, total, segment, RGN_OR );
DeleteObject( segment ); DeleteObject( segment );
face_1.start = seg_pts[0]; face_1->start = seg_pts[0];
face_1.end = seg_pts[1]; face_1->end = seg_pts[1];
face_2.start = seg_pts[2]; face_2->start = seg_pts[2];
face_2.end = seg_pts[3]; face_2->end = seg_pts[3];
} }
face_1->dx = face_2->dx = dx;
face_1->dy = face_2->dy = dy;
}
static BOOL wide_pen_lines(dibdrv_physdev *pdev, int num, POINT *pts, BOOL close, HRGN total)
{
int i;
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 );
if (!close) num--;
for (i = 0; i < num; 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;
struct face face_1, face_2, prev_face, first_face;
BOOL need_cap_1 = !close && (i == 0);
BOOL need_cap_2 = !close && (i == num - 1);
wide_line_segment( pdev, total, pt_1, pt_2, dx, dy, need_cap_1, need_cap_2, &face_1, &face_2 );
if (need_cap_1) add_cap( pdev, total, round_cap, pt_1 ); if (need_cap_1) add_cap( pdev, total, round_cap, pt_1 );
if (need_cap_2) add_cap( pdev, total, round_cap, pt_2 ); if (need_cap_2) add_cap( pdev, total, round_cap, pt_2 );
face_1.dx = face_2.dx = dx;
face_1.dy = face_2.dy = dy;
if (i == 0) first_face = face_1; if (i == 0) first_face = face_1;
else add_join( pdev, total, round_cap, pt_1, &prev_face, &face_1 ); else add_join( pdev, total, round_cap, pt_1, &prev_face, &face_1 );