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