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