Alexandre Julliard : gdi32: Clip solid pen regions to the DIB rectangle to avoid overflows.

Alexandre Julliard julliard at winehq.org
Mon Jul 30 14:18:51 CDT 2012


Module: wine
Branch: master
Commit: 6714f16c74180c450edb8b9f9bdba43c14c0b8e0
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=6714f16c74180c450edb8b9f9bdba43c14c0b8e0

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Mon Jul 30 13:59:04 2012 +0200

gdi32: Clip solid pen regions to the DIB rectangle to avoid overflows.

---

 dlls/gdi32/dibdrv/dc.c      |   12 +++
 dlls/gdi32/dibdrv/dibdrv.h  |    1 +
 dlls/gdi32/dibdrv/objects.c |  177 +++++++++++++++++++++++++------------------
 3 files changed, 116 insertions(+), 74 deletions(-)

diff --git a/dlls/gdi32/dibdrv/dc.c b/dlls/gdi32/dibdrv/dc.c
index de64d18..73895c9 100644
--- a/dlls/gdi32/dibdrv/dc.c
+++ b/dlls/gdi32/dibdrv/dc.c
@@ -255,6 +255,18 @@ DWORD convert_bitmapinfo( const BITMAPINFO *src_info, void *src_bits, struct bit
     return ERROR_SUCCESS;
 }
 
+int clip_rect_to_dib( const dib_info *dib, RECT *rc )
+{
+    RECT rect;
+
+    rect.left   = max( 0, -dib->rect.left );
+    rect.top    = max( 0, -dib->rect.top );
+    rect.right  = min( dib->rect.right, dib->width ) - dib->rect.left;
+    rect.bottom = min( dib->rect.bottom, dib->height ) - dib->rect.top;
+    if (is_rect_empty( &rect )) return 0;
+    return intersect_rect( rc, &rect, rc );
+}
+
 int get_clipped_rects( const dib_info *dib, const RECT *rc, HRGN clip, struct clipped_rects *clip_rects )
 {
     const WINEREGION *region;
diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h
index 7802d17..0a99fba 100644
--- a/dlls/gdi32/dibdrv/dibdrv.h
+++ b/dlls/gdi32/dibdrv/dibdrv.h
@@ -244,6 +244,7 @@ extern void copy_dib_color_info(dib_info *dst, const dib_info *src) DECLSPEC_HID
 extern BOOL convert_dib(dib_info *dst, const dib_info *src) DECLSPEC_HIDDEN;
 extern COLORREF make_rgb_colorref( HDC hdc, dib_info *dib, COLORREF color, BOOL *got_pixel, DWORD *pixel ) DECLSPEC_HIDDEN;
 extern DWORD get_pixel_color(dibdrv_physdev *pdev, COLORREF color, BOOL mono_fixup) DECLSPEC_HIDDEN;
+extern int clip_rect_to_dib( const dib_info *dib, RECT *rc ) DECLSPEC_HIDDEN;
 extern int get_clipped_rects( const dib_info *dib, const RECT *rc, HRGN clip, struct clipped_rects *clip_rects ) DECLSPEC_HIDDEN;
 extern void add_clipped_bounds( dibdrv_physdev *dev, const RECT *rect, HRGN clip ) DECLSPEC_HIDDEN;
 extern int clip_line(const POINT *start, const POINT *end, const RECT *clip,
diff --git a/dlls/gdi32/dibdrv/objects.c b/dlls/gdi32/dibdrv/objects.c
index 0292537..f9736f6 100644
--- a/dlls/gdi32/dibdrv/objects.c
+++ b/dlls/gdi32/dibdrv/objects.c
@@ -654,6 +654,87 @@ static BOOL solid_pen_line(dibdrv_physdev *pdev, POINT *start, POINT *end, DWORD
     return TRUE;
 }
 
+static void solid_line_region( const dib_info *dib, const POINT *start, const struct line_params *params,
+                               HRGN region )
+{
+    int len, err = params->err_start;
+    RECT rect;
+
+    rect.left   = start->x;
+    rect.top    = start->y;
+    rect.right  = start->x + 1;
+    rect.bottom = start->y + 1;
+
+    if (params->x_major)
+    {
+        if (params->x_inc > 0)
+        {
+            for (len = params->length; len; len--, rect.right++)
+            {
+                if (err + params->bias > 0)
+                {
+                    add_rect_to_region( region, &rect );
+                    rect.left = rect.right;
+                    rect.top += params->y_inc;
+                    rect.bottom += params->y_inc;
+                    err += params->err_add_1;
+                }
+                else err += params->err_add_2;
+            }
+        }
+        else
+        {
+            for (len = params->length; len; len--, rect.left--)
+            {
+                if (err + params->bias > 0)
+                {
+                    add_rect_to_region( region, &rect );
+                    rect.right = rect.left;
+                    rect.top += params->y_inc;
+                    rect.bottom += params->y_inc;
+                    err += params->err_add_1;
+                }
+                else err += params->err_add_2;
+            }
+        }
+    }
+    else
+    {
+        if (params->y_inc > 0)
+        {
+            for (len = params->length; len; len--, rect.bottom++)
+            {
+                if (err + params->bias > 0)
+                {
+                    add_rect_to_region( region, &rect );
+                    rect.top = rect.bottom;
+                    rect.left += params->x_inc;
+                    rect.right += params->x_inc;
+                    err += params->err_add_1;
+                }
+                else err += params->err_add_2;
+            }
+        }
+        else
+        {
+            for (len = params->length; len; len--, rect.top--)
+            {
+                if (err + params->bias > 0)
+                {
+                    add_rect_to_region( region, &rect );
+                    rect.bottom = rect.top;
+                    rect.left += params->x_inc;
+                    rect.right += params->x_inc;
+                    err += params->err_add_1;
+                }
+                else err += params->err_add_2;
+            }
+        }
+    }
+    /* add final rect */
+    add_rect_to_region( region, &rect );
+}
+
 static BOOL solid_pen_line_region( dibdrv_physdev *pdev, POINT *start, POINT *end, HRGN region )
 {
     RECT rect;
@@ -667,99 +748,47 @@ static BOOL solid_pen_line_region( dibdrv_physdev *pdev, POINT *start, POINT *en
     {
         rect.right = end->x;
         order_end_points(&rect.left, &rect.right);
-        add_rect_to_region( region, &rect );
+        if (clip_rect_to_dib( &pdev->dib, &rect )) add_rect_to_region( region, &rect );
     }
     else if(start->x == end->x)
     {
         rect.bottom = end->y;
         order_end_points(&rect.top, &rect.bottom);
-        add_rect_to_region( region, &rect );
+        if (clip_rect_to_dib( &pdev->dib, &rect )) add_rect_to_region( region, &rect );
     }
     else
     {
-        INT dx = end->x - start->x, dy = end->y - start->y;
-        INT abs_dx = abs(dx), abs_dy = abs(dy);
-        DWORD octant = get_octant_mask(dx, dy);
-        INT bias = get_bias( octant );
+        bres_params clip_params;
+        struct line_params line_params;
+        POINT p1 = crop_coords( *start ), p2 = crop_coords( *end );
 
-        if (is_xmajor( octant ))
+        init_bres_params( start, end, &clip_params, &line_params, &rect );
+        if (clip_rect_to_dib( &pdev->dib, &rect ))
         {
-            int y_inc = is_y_increasing( octant ) ? 1 : -1;
-            int err_add_1 = 2 * abs_dy - 2 * abs_dx;
-            int err_add_2 = 2 * abs_dy;
-            int err = 2 * abs_dy - abs_dx;
+            POINT clipped_start, clipped_end;
 
-            if (is_x_increasing( octant ))
-            {
-                for (rect.right = start->x + 1; rect.right <= end->x; rect.right++)
-                {
-                    if (err + bias > 0)
-                    {
-                        add_rect_to_region( region, &rect );
-                        rect.left = rect.right;
-                        rect.top += y_inc;
-                        rect.bottom += y_inc;
-                        err += err_add_1;
-                    }
-                    else err += err_add_2;
-                }
-            }
-            else
+            if (clip_line( &p1, &p2, &rect, &clip_params, &clipped_start, &clipped_end ))
             {
-                for (rect.left = start->x; rect.left > end->x; rect.left--)
-                {
-                    if (err + bias > 0)
-                    {
-                        add_rect_to_region( region, &rect );
-                        rect.right = rect.left;
-                        rect.top += y_inc;
-                        rect.bottom += y_inc;
-                        err += err_add_1;
-                    }
-                    else err += err_add_2;
-                }
-            }
-        }
-        else
-        {
-            int x_inc = is_x_increasing( octant ) ? 1 : -1;
-            int err_add_1 = 2 * abs_dx - 2 * abs_dy;
-            int err_add_2 = 2 * abs_dx;
-            int err = 2 * abs_dx - abs_dy;
+                int m = abs(clipped_start.x - p1.x);
+                int n = abs(clipped_start.y - p1.y);
 
-            if (is_y_increasing( octant ))
-            {
-                for (rect.bottom = start->y + 1; rect.bottom <= end->y; rect.bottom++)
+                if (line_params.x_major)
                 {
-                    if (err + bias > 0)
-                    {
-                        add_rect_to_region( region, &rect );
-                        rect.top = rect.bottom;
-                        rect.left += x_inc;
-                        rect.right += x_inc;
-                        err += err_add_1;
-                    }
-                    else err += err_add_2;
+                    line_params.err_start = 2 * clip_params.dy - clip_params.dx
+                                          + m * 2 * clip_params.dy - n * 2 * clip_params.dx;
+                    line_params.length = abs( clipped_end.x - clipped_start.x ) + 1;
                 }
-            }
-            else
-            {
-                for (rect.top = start->y; rect.top > end->y; rect.top--)
+                else
                 {
-                    if (err + bias > 0)
-                    {
-                        add_rect_to_region( region, &rect );
-                        rect.bottom = rect.top;
-                        rect.left += x_inc;
-                        rect.right += x_inc;
-                        err += err_add_1;
-                    }
-                    else err += err_add_2;
+                    line_params.err_start = 2 * clip_params.dx - clip_params.dy
+                                          + n * 2 * clip_params.dx - m * 2 * clip_params.dy;
+                    line_params.length = abs( clipped_end.y - clipped_start.y ) + 1;
                 }
+
+                if (clipped_end.x == p2.x && clipped_end.y == p2.y) line_params.length--;
+                solid_line_region( &pdev->dib, &clipped_start, &line_params, region );
             }
         }
-        /* add final rect */
-        add_rect_to_region( region, &rect );
     }
     return TRUE;
 }




More information about the wine-cvs mailing list