Module: wine Branch: master Commit: 1805f123b08cac862667d1543e198ece57a6ef77 URL: http://source.winehq.org/git/wine.git/?a=commit;h=1805f123b08cac862667d1543e...
Author: Alexandre Julliard julliard@winehq.org Date: Mon Jul 11 13:44:26 2011 +0200
gdi32: Compute StretchBlt rectangles in gdi32.
---
dlls/gdi32/bitblt.c | 144 +++++++++++++++++++++++++++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 11 ---- include/wine/gdi_driver.h | 14 +++++ 3 files changed, 158 insertions(+), 11 deletions(-)
diff --git a/dlls/gdi32/bitblt.c b/dlls/gdi32/bitblt.c index 6c556d7..733e2cf 100644 --- a/dlls/gdi32/bitblt.c +++ b/dlls/gdi32/bitblt.c @@ -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 ); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 617504f..149b5ce 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -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 */ diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 882d5c5..2804d5c 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -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 */