Huw Davies : gdi32: Add support for wide cosmetic pens.
Alexandre Julliard
julliard at winehq.org
Fri Dec 9 14:41:37 CST 2011
Module: wine
Branch: master
Commit: e155a8054bff9e139116ceaeec272b5cbf0a3d3b
URL: http://source.winehq.org/git/wine.git/?a=commit;h=e155a8054bff9e139116ceaeec272b5cbf0a3d3b
Author: Huw Davies <huw at codeweavers.com>
Date: Fri Dec 9 13:47:27 2011 +0000
gdi32: Add support for wide cosmetic pens.
---
dlls/gdi32/dibdrv/dibdrv.h | 3 +-
dlls/gdi32/dibdrv/objects.c | 185 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 185 insertions(+), 3 deletions(-)
diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h
index 1bf0696..6f01a5e 100644
--- a/dlls/gdi32/dibdrv/dibdrv.h
+++ b/dlls/gdi32/dibdrv/dibdrv.h
@@ -85,7 +85,8 @@ typedef struct dibdrv_physdev
/* pen */
COLORREF pen_colorref;
- DWORD pen_color, pen_and, pen_xor;
+ DWORD pen_color, pen_and, pen_xor, pen_endcap, pen_join;
+ int pen_width;
dash_pattern pen_pattern;
dash_pos dash_pos;
BOOL (* pen_lines)(struct dibdrv_physdev *pdev, int num, POINT *pts, BOOL close);
diff --git a/dlls/gdi32/dibdrv/objects.c b/dlls/gdi32/dibdrv/objects.c
index 9c85094..14f1260 100644
--- a/dlls/gdi32/dibdrv/objects.c
+++ b/dlls/gdi32/dibdrv/objects.c
@@ -1017,6 +1017,166 @@ static BOOL null_pen_lines(dibdrv_physdev *pdev, int num, POINT *pts, BOOL close
return TRUE;
}
+static void add_cap( dibdrv_physdev *pdev, HRGN region, const POINT *pt )
+{
+ HRGN cap;
+
+ switch (pdev->pen_endcap)
+ {
+ case PS_ENDCAP_ROUND:
+ cap = CreateEllipticRgn( pt->x - pdev->pen_width / 2, pt->y - pdev->pen_width / 2,
+ pt->x + (pdev->pen_width + 1) / 2, pt->y + (pdev->pen_width + 1) / 2 );
+ break;
+
+ default: /* only supporting cosmetic pens so far, so always PS_ENDCAP_ROUND */
+ return;
+ }
+
+ CombineRgn( region, region, cap, RGN_OR );
+ DeleteObject( cap );
+ return;
+}
+
+static void add_join( dibdrv_physdev *pdev, HRGN region, const POINT *pt )
+{
+ HRGN join;
+
+ switch (pdev->pen_join)
+ {
+ case PS_JOIN_ROUND:
+ join = CreateEllipticRgn( pt->x - pdev->pen_width / 2, pt->y - pdev->pen_width / 2,
+ pt->x + (pdev->pen_width + 1) / 2, pt->y + (pdev->pen_width + 1) / 2 );
+ break;
+
+ default: /* only supporting cosmetic pens so far, so always PS_JOIN_ROUND */
+ return;
+ }
+
+ CombineRgn( region, region, join, RGN_OR );
+ DeleteObject( join );
+ return;
+}
+
+#define round( f ) (((f) > 0) ? (f) + 0.5 : (f) - 0.5)
+
+static HRGN get_wide_lines_region( dibdrv_physdev *pdev, int num, POINT *pts, BOOL close )
+{
+ int i;
+ HRGN total, segment;
+
+ assert( num >= 2 );
+
+ total = CreateRectRgn( 0, 0, 0, 0 );
+
+ 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;
+
+ if (dx == 0 && dy == 0) continue;
+
+ if (dy == 0)
+ {
+ rect.left = min( pt_1->x, pt_2->x );
+ rect.right = rect.left + abs( dx );
+ rect.top = pt_1->y - pdev->pen_width / 2;
+ rect.bottom = rect.top + pdev->pen_width;
+ segment = CreateRectRgnIndirect( &rect );
+ }
+ else if (dx == 0)
+ {
+ rect.top = min( pt_1->y, pt_2->y );
+ rect.bottom = rect.top + abs( dy );
+ rect.left = pt_1->x - pdev->pen_width / 2;
+ rect.right = rect.left + pdev->pen_width;
+ segment = CreateRectRgnIndirect( &rect );
+ }
+ else
+ {
+ double len = hypot( dx, dy );
+ double width_x, width_y;
+ POINT seg_pts[4];
+ POINT wide_half, narrow_half;
+
+ width_x = pdev->pen_width * abs( dy ) / len;
+ width_y = pdev->pen_width * abs( dx ) / len;
+
+ narrow_half.x = round( width_x / 2 );
+ narrow_half.y = round( width_y / 2 );
+ wide_half.x = round( (width_x + 1) / 2 );
+ wide_half.y = round( (width_y + 1) / 2 );
+
+ if (dx < 0)
+ {
+ wide_half.y = -wide_half.y;
+ narrow_half.y = -narrow_half.y;
+ }
+
+ if (dy < 0)
+ {
+ POINT tmp = narrow_half; narrow_half = wide_half; wide_half = tmp;
+ wide_half.x = -wide_half.x;
+ narrow_half.x = -narrow_half.x;
+ }
+
+ seg_pts[0].x = pt_1->x - narrow_half.x;
+ seg_pts[0].y = pt_1->y + narrow_half.y;
+ seg_pts[1].x = pt_1->x + wide_half.x;
+ seg_pts[1].y = pt_1->y - wide_half.y;
+ seg_pts[2].x = pt_2->x + wide_half.x;
+ seg_pts[2].y = pt_2->y - wide_half.y;
+ seg_pts[3].x = pt_2->x - narrow_half.x;
+ seg_pts[3].y = pt_2->y + narrow_half.y;
+
+ segment = CreatePolygonRgn( seg_pts, 4, ALTERNATE );
+ }
+
+ CombineRgn( total, total, segment, RGN_OR );
+ DeleteObject( segment );
+
+ if (i == 0)
+ {
+ if (!close) add_cap( pdev, total, pt_1 );
+ }
+ else
+ add_join( pdev, total, pt_1 );
+
+ if (i == num - 1)
+ {
+ if (close) add_join( pdev, total, pt_2 );
+ else add_cap( pdev, total, pt_2 );
+ }
+
+ }
+ return total;
+}
+
+static BOOL wide_pen_lines(dibdrv_physdev *pdev, int num, POINT *pts, BOOL close)
+{
+ const WINEREGION *data;
+ rop_mask color;
+ HRGN region;
+
+ color.and = pdev->pen_and;
+ color.xor = pdev->pen_xor;
+
+ region = get_wide_lines_region( pdev, num, pts, close );
+
+ if (CombineRgn( region, region, pdev->clip, RGN_AND ) != ERROR)
+ {
+ data = get_wine_region( region );
+ solid_rects( &pdev->dib, data->numRects, data->rects, &color, NULL );
+ release_wine_region( region );
+ }
+
+ DeleteObject( region );
+ return TRUE;
+}
+
static const dash_pattern dash_patterns[5] =
{
{0, {0}, 0}, /* PS_SOLID - a pseudo-pattern used to initialise unpatterned pens. */
@@ -1026,6 +1186,21 @@ static const dash_pattern dash_patterns[5] =
{6, {9, 3, 3, 3, 3, 3}, 24} /* PS_DASHDOTDOT */
};
+static inline int get_pen_device_width( dibdrv_physdev *pdev, LOGPEN *pen )
+{
+ int width = pen->lopnWidth.x;
+
+ if (pen->lopnStyle & PS_GEOMETRIC && width > 1)
+ {
+ POINT pts[2];
+ pts[0].x = pts[0].y = pts[1].y = 0;
+ pts[1].x = width;
+ LPtoDP( pdev->dev.hdc, pts, 2 );
+ width = max( abs( pts[1].x - pts[0].x ), 1 );
+ }
+ return width;
+}
+
/***********************************************************************
* dibdrv_SelectPen
*/
@@ -1058,6 +1233,10 @@ HPEN dibdrv_SelectPen( PHYSDEV dev, HPEN hpen )
HeapFree( GetProcessHeap(), 0, elp );
}
+ pdev->pen_join = logpen.lopnStyle & PS_JOIN_MASK;
+ pdev->pen_endcap = logpen.lopnStyle & PS_ENDCAP_MASK;
+ pdev->pen_width = get_pen_device_width( pdev, &logpen );
+
if (hpen == GetStockObject( DC_PEN ))
logpen.lopnColor = GetDCPenColor( dev->hdc );
@@ -1075,8 +1254,10 @@ HPEN dibdrv_SelectPen( PHYSDEV dev, HPEN hpen )
{
case PS_SOLID:
if(logpen.lopnStyle & PS_GEOMETRIC) break;
- if(logpen.lopnWidth.x > 1) break;
- pdev->pen_lines = solid_pen_lines;
+ if(pdev->pen_width <= 1)
+ pdev->pen_lines = solid_pen_lines;
+ else
+ pdev->pen_lines = wide_pen_lines;
pdev->defer &= ~DEFER_PEN;
break;
More information about the wine-cvs
mailing list