gdi32: Compute StretchBlt rectangles in gdi32.

This commit is contained in:
Alexandre Julliard 2011-07-11 13:44:26 +02:00
parent 2ff31091ed
commit 1805f123b0
3 changed files with 158 additions and 11 deletions

View file

@ -40,6 +40,130 @@ static inline BOOL rop_uses_src( DWORD rop )
return ((rop >> 2) & 0x330000) != (rop & 0x330000);
}
static inline void swap_ints( int *i, int *j )
{
int tmp = *i;
*i = *j;
*j = tmp;
}
static inline BOOL intersect_rect( RECT *dst, const RECT *src1, const RECT *src2 )
{
dst->left = max( src1->left, src2->left );
dst->top = max( src1->top, src2->top );
dst->right = min( src1->right, src2->right );
dst->bottom = min( src1->bottom, src2->bottom );
return (dst->left < dst->right && dst->top < dst->bottom);
}
static inline void offset_rect( RECT *rect, int offset_x, int offset_y )
{
rect->left += offset_x;
rect->top += offset_y;
rect->right += offset_x;
rect->bottom += offset_y;
}
static void get_vis_rectangles( DC *dc_dst, struct bitblt_coords *dst,
DC *dc_src, struct bitblt_coords *src )
{
RECT rect, clip;
/* get the destination visible rectangle */
rect.left = dst->log_x;
rect.top = dst->log_y;
rect.right = dst->log_x + dst->log_width;
rect.bottom = dst->log_y + dst->log_height;
LPtoDP( dc_dst->hSelf, (POINT *)&rect, 2 );
dst->x = rect.left;
dst->y = rect.top;
dst->width = rect.right - rect.left;
dst->height = rect.bottom - rect.top;
if (dst->layout & LAYOUT_RTL && dst->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
{
swap_ints( &rect.left, &rect.right );
dst->x = rect.left;
dst->width = rect.right - rect.left;
}
if (rect.left > rect.right) { swap_ints( &rect.left, &rect.right ); rect.left++; rect.right++; }
if (rect.top > rect.bottom) { swap_ints( &rect.top, &rect.bottom ); rect.top++; rect.bottom++; }
get_clip_box( dc_dst, &clip );
intersect_rect( &dst->visrect, &rect, &clip );
/* get the source visible rectangle */
if (!src) return;
rect.left = src->log_x;
rect.top = src->log_y;
rect.right = src->log_x + src->log_width;
rect.bottom = src->log_y + src->log_height;
LPtoDP( dc_src->hSelf, (POINT *)&rect, 2 );
src->x = rect.left;
src->y = rect.top;
src->width = rect.right - rect.left;
src->height = rect.bottom - rect.top;
if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
{
swap_ints( &rect.left, &rect.right );
src->x = rect.left;
src->width = rect.right - rect.left;
}
if (rect.left > rect.right) { swap_ints( &rect.left, &rect.right ); rect.left++; rect.right++; }
if (rect.top > rect.bottom) { swap_ints( &rect.top, &rect.bottom ); rect.top++; rect.bottom++; }
/* source is not clipped */
if (dc_src->header.type == OBJ_MEMDC)
intersect_rect( &src->visrect, &rect, &dc_src->vis_rect );
else
src->visrect = rect; /* FIXME: clip to device size */
/* intersect the rectangles */
if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
{
offset_rect( &src->visrect, dst->x - src->x, dst->y - src->y );
intersect_rect( &rect, &src->visrect, &dst->visrect );
src->visrect = dst->visrect = rect;
offset_rect( &src->visrect, src->x - dst->x, src->y - dst->y );
}
else /* stretching */
{
/* map source rectangle into destination coordinates */
rect.left = dst->x + (src->visrect.left - src->x)*dst->width/src->width;
rect.top = dst->y + (src->visrect.top - src->y)*dst->height/src->height;
rect.right = dst->x + (src->visrect.right - src->x)*dst->width/src->width;
rect.bottom = dst->y + (src->visrect.bottom - src->y)*dst->height/src->height;
if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
/* avoid rounding errors */
rect.left--;
rect.top--;
rect.right++;
rect.bottom++;
if (!intersect_rect( &dst->visrect, &rect, &dst->visrect )) return;
/* map destination rectangle back to source coordinates */
rect = dst->visrect;
rect.left = src->x + (dst->visrect.left - dst->x)*src->width/dst->width;
rect.top = src->y + (dst->visrect.top - dst->y)*src->height/dst->height;
rect.right = src->x + (dst->visrect.right - dst->x)*src->width/dst->width;
rect.bottom = src->y + (dst->visrect.bottom - dst->y)*src->height/dst->height;
if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
/* avoid rounding errors */
rect.left--;
rect.top--;
rect.right++;
rect.bottom++;
intersect_rect( &src->visrect, &rect, &src->visrect );
}
}
/* nulldrv fallback implementation using StretchDIBits */
BOOL CDECL nulldrv_StretchBlt( PHYSDEV dst_dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
PHYSDEV src_dev, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
@ -149,10 +273,30 @@ BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT height
if ((dcSrc = get_dc_ptr( hdcSrc )))
{
struct bitblt_coords src, dst;
PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
update_dc( dcSrc );
update_dc( dcDst );
src.log_x = xSrc;
src.log_y = ySrc;
src.log_width = widthSrc;
src.log_height = heightSrc;
src.layout = dcSrc->layout;
dst.log_x = xDst;
dst.log_y = yDst;
dst.log_width = widthDst;
dst.log_height = heightDst;
dst.layout = dcDst->layout;
if (rop & NOMIRRORBITMAP)
{
src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
rop &= ~NOMIRRORBITMAP;
}
get_vis_rectangles( dcDst, &dst, dcSrc, &src );
ret = dst_dev->funcs->pStretchBlt( dst_dev, xDst, yDst, widthDst, heightDst,
src_dev, xSrc, ySrc, widthSrc, heightSrc, rop );
release_dc_ptr( dcSrc );

View file

@ -173,17 +173,6 @@ static inline X11DRV_PDEVICE *get_x11drv_dev( PHYSDEV dev )
return (X11DRV_PDEVICE *)dev;
}
struct bitblt_coords
{
int x; /* original position and width */
int y;
int width;
int height;
RECT visrect; /* rectangle clipped to the visible part */
DWORD layout; /* DC layout */
};
extern X_PHYSBITMAP BITMAP_stock_phys_bitmap DECLSPEC_HIDDEN; /* phys bitmap for the default stock bitmap */
/* Retrieve the GC used for bitmap operations */

View file

@ -30,4 +30,18 @@ typedef struct gdi_physdev
HDC hdc;
} *PHYSDEV;
struct bitblt_coords
{
int log_x; /* original position and size, in logical coords */
int log_y;
int log_width;
int log_height;
int x; /* mapped position and size, in device coords */
int y;
int width;
int height;
RECT visrect; /* rectangle clipped to the visible part, in device coords */
DWORD layout; /* DC layout */
};
#endif /* __WINE_WINE_GDI_DRIVER_H */