Alexandre Julliard : gdi32: Copy DIB rectangles in the correct order when source and destination overlap .

Alexandre Julliard julliard at winehq.org
Thu Sep 22 13:39:47 CDT 2011


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

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Thu Sep 22 10:11:27 2011 +0200

gdi32: Copy DIB rectangles in the correct order when source and destination overlap.

---

 dlls/gdi32/dibdrv/bitblt.c |  102 +++++++++++++++++++++++++++++++++++++++++---
 dlls/gdi32/dibdrv/dibdrv.h |    5 ++
 2 files changed, 101 insertions(+), 6 deletions(-)

diff --git a/dlls/gdi32/dibdrv/bitblt.c b/dlls/gdi32/dibdrv/bitblt.c
index 1d41e11..94ae266 100644
--- a/dlls/gdi32/dibdrv/bitblt.c
+++ b/dlls/gdi32/dibdrv/bitblt.c
@@ -431,28 +431,118 @@ static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
     { OP(PAT,DST,R2_WHITE) }                                        /* 0xff  1              */
 };
 
+static int get_overlap( const dib_info *dst, const RECT *dst_rect,
+                        const dib_info *src, const RECT *src_rect )
+{
+    const char *src_top, *dst_top;
+    int height, ret = 0;
+
+    if (dst->stride != src->stride) return 0;  /* can't be the same dib */
+    if (dst_rect->right <= src_rect->left) return 0;
+    if (dst_rect->left >= src_rect->right) return 0;
+
+    src_top = (const char *)src->bits.ptr + src_rect->top * src->stride;
+    dst_top = (const char *)dst->bits.ptr + dst_rect->top * dst->stride;
+    height = (dst_rect->bottom - dst_rect->top) * dst->stride;
+
+    if (dst->stride > 0)
+    {
+        if (src_top >= dst_top + height) return 0;
+        if (src_top + height <= dst_top) return 0;
+        if (dst_top < src_top) ret |= OVERLAP_ABOVE;
+        else if (dst_top > src_top) ret |= OVERLAP_BELOW;
+    }
+    else
+    {
+        if (src_top <= dst_top + height) return 0;
+        if (src_top + height >= dst_top) return 0;
+        if (dst_top > src_top) ret |= OVERLAP_ABOVE;
+        else if (dst_top < src_top) ret |= OVERLAP_BELOW;
+    }
+
+    if (dst_rect->left < src_rect->left) ret |= OVERLAP_LEFT;
+    else if (dst_rect->left > src_rect->left) ret |= OVERLAP_RIGHT;
+
+    return ret;
+}
+
 static DWORD copy_rect( dib_info *dst, const RECT *dst_rect, const dib_info *src, const RECT *src_rect,
                         HRGN clip, INT rop2 )
 {
     POINT origin;
     RECT clipped_rect;
     const WINEREGION *clip_data;
-    int i;
+    int i, start, end, overlap;
 
     origin.x = src_rect->left;
     origin.y = src_rect->top;
+    overlap = get_overlap( dst, dst_rect, src, src_rect );
 
     if (clip == NULL) dst->funcs->copy_rect( dst, dst_rect, src, &origin, rop2 );
     else
     {
         clip_data = get_wine_region( clip );
-        for (i = 0; i < clip_data->numRects; i++)
+        if (overlap & OVERLAP_BELOW)
+        {
+            if (overlap & OVERLAP_RIGHT)  /* right to left, bottom to top */
+            {
+                for (i = clip_data->numRects - 1; i >= 0; i--)
+                {
+                    if (intersect_rect( &clipped_rect, dst_rect, clip_data->rects + i ))
+                    {
+                        origin.x = src_rect->left + clipped_rect.left - dst_rect->left;
+                        origin.y = src_rect->top  + clipped_rect.top  - dst_rect->top;
+                        dst->funcs->copy_rect( dst, &clipped_rect, src, &origin, rop2 );
+                    }
+                }
+            }
+            else  /* left to right, bottom to top */
+            {
+                for (start = clip_data->numRects - 1; start >= 0; start = end)
+                {
+                    for (end = start - 1; end >= 0; end--)
+                        if (clip_data->rects[start].top != clip_data->rects[end].top) break;
+
+                    for (i = end + 1; i <= start; i++)
+                    {
+                        if (intersect_rect( &clipped_rect, dst_rect, clip_data->rects + i ))
+                        {
+                            origin.x = src_rect->left + clipped_rect.left - dst_rect->left;
+                            origin.y = src_rect->top  + clipped_rect.top  - dst_rect->top;
+                            dst->funcs->copy_rect( dst, &clipped_rect, src, &origin, rop2 );
+                        }
+                    }
+                }
+            }
+        }
+        else if (overlap & OVERLAP_RIGHT)  /* right to left, top to bottom */
+        {
+            for (start = 0; start < clip_data->numRects; start = end)
+            {
+                for (end = start + 1; end < clip_data->numRects; end++)
+                    if (clip_data->rects[start].top != clip_data->rects[end].top) break;
+
+                for (i = end - 1; i >= start; i--)
+                {
+                    if (intersect_rect( &clipped_rect, dst_rect, clip_data->rects + i ))
+                    {
+                        origin.x = src_rect->left + clipped_rect.left - dst_rect->left;
+                        origin.y = src_rect->top  + clipped_rect.top  - dst_rect->top;
+                        dst->funcs->copy_rect( dst, &clipped_rect, src, &origin, rop2 );
+                    }
+                }
+            }
+        }
+        else  /* left to right, top to bottom */
         {
-            if (intersect_rect( &clipped_rect, dst_rect, clip_data->rects + i ))
+            for (i = 0; i < clip_data->numRects; i++)
             {
-                origin.x = src_rect->left + clipped_rect.left - dst_rect->left;
-                origin.y = src_rect->top  + clipped_rect.top  - dst_rect->top;
-                dst->funcs->copy_rect( dst, &clipped_rect, src, &origin, rop2 );
+                if (intersect_rect( &clipped_rect, dst_rect, clip_data->rects + i ))
+                {
+                    origin.x = src_rect->left + clipped_rect.left - dst_rect->left;
+                    origin.y = src_rect->top  + clipped_rect.top  - dst_rect->top;
+                    dst->funcs->copy_rect( dst, &clipped_rect, src, &origin, rop2 );
+                }
             }
         }
         release_wine_region( clip );
diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h
index 7f0d697..8130900 100644
--- a/dlls/gdi32/dibdrv/dibdrv.h
+++ b/dlls/gdi32/dibdrv/dibdrv.h
@@ -147,6 +147,11 @@ struct rop_codes
     DWORD a1, a2, x1, x2;
 };
 
+#define OVERLAP_LEFT  0x01  /* dest starts left of source */
+#define OVERLAP_RIGHT 0x02  /* dest starts right of source */
+#define OVERLAP_ABOVE 0x04  /* dest starts above source */
+#define OVERLAP_BELOW 0x08  /* dest starts below source */
+
 extern void get_rop_codes(INT rop, struct rop_codes *codes);
 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;




More information about the wine-cvs mailing list