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

This commit is contained in:
Alexandre Julliard 2011-09-22 10:11:27 +02:00
parent 6176fa469a
commit 3ace501190
2 changed files with 101 additions and 6 deletions

View File

@ -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 (intersect_rect( &clipped_rect, dst_rect, clip_data->rects + i ))
if (overlap & OVERLAP_RIGHT) /* right to left, bottom to top */
{
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 );
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 */
{
for (i = 0; i < clip_data->numRects; 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 );
}
}
}
release_wine_region( clip );

View File

@ -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;