From 4a87722144c0f1114e8c03da449b9b89a30b40a9 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 16 Apr 2012 17:49:05 +0200 Subject: [PATCH] winex11: Add bounds rectangle tracking to all graphics entry points. --- dlls/gdi32/tests/dc.c | 12 +--- dlls/winex11.drv/bitblt.c | 5 ++ dlls/winex11.drv/graphics.c | 122 +++++++++++++++++++++++++++++------- dlls/winex11.drv/init.c | 28 ++++++++- dlls/winex11.drv/opengl.c | 3 + dlls/winex11.drv/x11drv.h | 18 ++++++ dlls/winex11.drv/xrender.c | 34 ++++++++-- 7 files changed, 183 insertions(+), 39 deletions(-) diff --git a/dlls/gdi32/tests/dc.c b/dlls/gdi32/tests/dc.c index 91e06c4569c..b7ace86f0f9 100644 --- a/dlls/gdi32/tests/dc.c +++ b/dlls/gdi32/tests/dc.c @@ -391,7 +391,7 @@ static void test_device_caps( HDC hdc, HDC ref_dc, const char *descr ) SetMapMode( hdc, MM_TEXT ); Rectangle( hdc, 2, 2, 4, 4 ); type = GetBoundsRect( hdc, &rect, DCB_RESET ); - if (GetObjectType( hdc ) != OBJ_MEMDC || GetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASDISPLAY) + if (GetObjectType( hdc ) == OBJ_ENHMETADC) todo_wine ok( rect.left == 2 && rect.top == 2 && rect.right == 4 && rect.bottom == 4 && type == DCB_SET, "GetBoundsRect returned %d,%d,%d,%d type %x for %s\n", @@ -890,10 +890,8 @@ static void test_boundsrect(void) MoveToEx( hdc, 10, 10, NULL ); LineTo( hdc, 20, 20 ); ret = GetBoundsRect( hdc, &rect, 0 ); - todo_wine ok( ret == DCB_SET, "GetBoundsRect returned %x\n", ret ); SetRect( &expect, 10, 10, 21, 21 ); - todo_wine ok( EqualRect(&rect, &expect), "Got (%d,%d)-(%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom ); SetRect( &rect, 8, 8, 23, 23 ); expect = rect; @@ -907,32 +905,27 @@ static void test_boundsrect(void) ret = GetBoundsRect( hdc, &rect, 0 ); ok( ret == DCB_SET, "GetBoundsRect returned %x\n", ret ); SetRect( &expect, 8, 8, 31, 26 ); - todo_wine ok( EqualRect(&rect, &expect), "Got (%d,%d)-(%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom ); SetBoundsRect( hdc, NULL, DCB_DISABLE ); LineTo( hdc, 40, 40 ); ret = GetBoundsRect( hdc, &rect, 0 ); ok( ret == DCB_SET, "GetBoundsRect returned %x\n", ret ); SetRect( &expect, 8, 8, 31, 26 ); - todo_wine ok( EqualRect(&rect, &expect), "Got (%d,%d)-(%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom ); SetRect( &rect, 6, 6, 30, 30 ); SetBoundsRect( hdc, &rect, DCB_ACCUMULATE ); ret = GetBoundsRect( hdc, &rect, 0 ); ok( ret == DCB_SET, "GetBoundsRect returned %x\n", ret ); SetRect( &expect, 6, 6, 31, 30 ); - todo_wine ok( EqualRect(&rect, &expect), "Got (%d,%d)-(%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom ); RestoreDC( hdc, level ); ret = GetBoundsRect( hdc, &rect, 0 ); ok( ret == DCB_SET, "GetBoundsRect returned %x\n", ret ); - todo_wine ok( EqualRect(&rect, &expect), "Got (%d,%d)-(%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom ); LineTo( hdc, 40, 40 ); ret = GetBoundsRect( hdc, &rect, 0 ); ok( ret == DCB_SET, "GetBoundsRect returned %x\n", ret ); - todo_wine ok( EqualRect(&rect, &expect), "Got (%d,%d)-(%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom ); SelectObject( hdc, old ); @@ -947,14 +940,12 @@ static void test_boundsrect(void) ret = GetBoundsRect( hdc, &rect, 0 ); ok( ret == DCB_SET, "GetBoundsRect returned %x\n", ret ); SetRect( &expect, 6, 6, 51, 41 ); - todo_wine ok( EqualRect(&rect, &expect), "Got (%d,%d)-(%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom ); SelectObject( hdc, GetStockObject( NULL_PEN )); LineTo( hdc, 50, 50 ); ret = GetBoundsRect( hdc, &rect, 0 ); ok( ret == DCB_SET, "GetBoundsRect returned %x\n", ret ); SetRect( &expect, 6, 6, 51, 51 ); - todo_wine ok( EqualRect(&rect, &expect), "Got (%d,%d)-(%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom ); memset( buffer, 0, sizeof(buffer) ); @@ -970,7 +961,6 @@ static void test_boundsrect(void) ret = GetBoundsRect( hdc, &rect, 0 ); ok( ret == DCB_SET, "GetBoundsRect returned %x\n", ret ); SetRect( &expect, 6, 6, 51, 51 ); - todo_wine ok( EqualRect(&rect, &expect), "Got (%d,%d)-(%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom ); LineTo( hdc, 55, 30 ); ret = GetBoundsRect( hdc, &rect, 0 ); diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c index 801ea08c712..056e4c4108d 100644 --- a/dlls/winex11.drv/bitblt.c +++ b/dlls/winex11.drv/bitblt.c @@ -749,6 +749,7 @@ void execute_rop( X11DRV_PDEVICE *physdev, Pixmap src_pixmap, GC gc, const RECT XFreePixmap( gdi_display, pixmaps[DST] ); if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] ); wine_tsx11_unlock(); + add_device_bounds( physdev, visrect ); } /*********************************************************************** @@ -800,6 +801,7 @@ BOOL X11DRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop ) dst->visrect.right - dst->visrect.left, dst->visrect.bottom - dst->visrect.top ); wine_tsx11_unlock(); + add_device_bounds( physDev, &dst->visrect ); return TRUE; } @@ -830,6 +832,8 @@ BOOL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst, height = dst->visrect.bottom - dst->visrect.top; opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; + add_device_bounds( physDevDst, &dst->visrect ); + /* a few optimizations for single-op ROPs */ if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST)) { @@ -1302,6 +1306,7 @@ DWORD X11DRV_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info } if (restore_region) restore_clipping_region( physdev ); + add_device_bounds( physdev, &dst->visrect ); } image->data = NULL; } diff --git a/dlls/winex11.drv/graphics.c b/dlls/winex11.drv/graphics.c index f21c3eb6548..b9149bcbde0 100644 --- a/dlls/winex11.drv/graphics.c +++ b/dlls/winex11.drv/graphics.c @@ -104,6 +104,42 @@ static RECT get_device_rect( HDC hdc, int left, int top, int right, int bottom ) return rect; } +static void add_pen_device_bounds( X11DRV_PDEVICE *dev, const POINT *points, int count ) +{ + RECT bounds, rect; + int width = 0; + + reset_bounds( &bounds ); + + if (dev->pen.type & PS_GEOMETRIC || dev->pen.width > 1) + { + /* Windows uses some heuristics to estimate the distance from the point that will be painted */ + width = dev->pen.width + 2; + if (dev->pen.linejoin == PS_JOIN_MITER) + { + width *= 5; + if (dev->pen.endcap == PS_ENDCAP_SQUARE) width = (width * 3 + 1) / 2; + } + else + { + if (dev->pen.endcap == PS_ENDCAP_SQUARE) width -= width / 4; + else width = (width + 1) / 2; + } + } + + while (count-- > 0) + { + rect.left = points->x - width; + rect.top = points->y - width; + rect.right = points->x + width + 1; + rect.bottom = points->y + width + 1; + add_bounds_rect( &bounds, &rect ); + points++; + } + + add_device_bounds( dev, &bounds ); +} + /*********************************************************************** * X11DRV_GetRegionData * @@ -506,12 +542,14 @@ BOOL X11DRV_LineTo( PHYSDEV dev, INT x, INT y ) X11DRV_PDEVICE *physDev = get_x11drv_dev( dev ); POINT pt[2]; - if (X11DRV_SetupGCForPen( physDev )) { - GetCurrentPositionEx( dev->hdc, &pt[0] ); - pt[1].x = x; - pt[1].y = y; - LPtoDP( dev->hdc, pt, 2 ); + GetCurrentPositionEx( dev->hdc, &pt[0] ); + pt[1].x = x; + pt[1].y = y; + LPtoDP( dev->hdc, pt, 2 ); + add_pen_device_bounds( physDev, pt, 2 ); + if (X11DRV_SetupGCForPen( physDev )) + { wine_tsx11_lock(); XDrawLine(gdi_display, physDev->drawable, physDev->gc, physDev->dc_rect.left + pt[0].x, physDev->dc_rect.top + pt[0].y, @@ -670,6 +708,7 @@ static BOOL X11DRV_DrawArc( PHYSDEV dev, INT left, INT top, INT right, INT botto } physDev->pen.width = oldwidth; + add_pen_device_bounds( physDev, (POINT *)&rc, 2 ); return TRUE; } @@ -748,6 +787,7 @@ BOOL X11DRV_Ellipse( PHYSDEV dev, INT left, INT top, INT right, INT bottom ) } physDev->pen.width = oldwidth; + add_pen_device_bounds( physDev, (POINT *)&rc, 2 ); return TRUE; } @@ -784,7 +824,9 @@ BOOL X11DRV_Rectangle(PHYSDEV dev, INT left, INT top, INT right, INT bottom) if(physDev->pen.type != PS_GEOMETRIC) physDev->pen.linejoin = PS_JOIN_MITER; - if ((rc.right > rc.left + width) && (rc.bottom > rc.top + width)) + rc.right--; + rc.bottom--; + if ((rc.right >= rc.left + width) && (rc.bottom >= rc.top + width)) { if (X11DRV_SetupGCForBrush( physDev )) { @@ -792,7 +834,7 @@ BOOL X11DRV_Rectangle(PHYSDEV dev, INT left, INT top, INT right, INT bottom) XFillRectangle( gdi_display, physDev->drawable, physDev->gc, physDev->dc_rect.left + rc.left + (width + 1) / 2, physDev->dc_rect.top + rc.top + (width + 1) / 2, - rc.right-rc.left-width-1, rc.bottom-rc.top-width-1); + rc.right-rc.left-width, rc.bottom-rc.top-width); wine_tsx11_unlock(); } } @@ -801,12 +843,13 @@ BOOL X11DRV_Rectangle(PHYSDEV dev, INT left, INT top, INT right, INT bottom) wine_tsx11_lock(); XDrawRectangle( gdi_display, physDev->drawable, physDev->gc, physDev->dc_rect.left + rc.left, physDev->dc_rect.top + rc.top, - rc.right-rc.left-1, rc.bottom-rc.top-1 ); + rc.right-rc.left, rc.bottom-rc.top ); wine_tsx11_unlock(); } physDev->pen.width = oldwidth; physDev->pen.linejoin = oldjoinstyle; + add_pen_device_bounds( physDev, (POINT *)&rc, 2 ); return TRUE; } @@ -1000,6 +1043,7 @@ BOOL X11DRV_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom, physDev->pen.width = oldwidth; physDev->pen.endcap = oldendcap; + add_pen_device_bounds( physDev, (POINT *)&rc, 2 ); return TRUE; } @@ -1012,6 +1056,7 @@ COLORREF X11DRV_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color ) X11DRV_PDEVICE *physDev = get_x11drv_dev( dev ); unsigned long pixel; POINT pt; + RECT rect; pt.x = x; pt.y = y; @@ -1025,6 +1070,8 @@ COLORREF X11DRV_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color ) physDev->dc_rect.left + pt.x, physDev->dc_rect.top + pt.y ); wine_tsx11_unlock(); + SetRect( &rect, pt.x, pt.y, pt.x + 1, pt.y + 1 ); + add_device_bounds( physDev, &rect ); return X11DRV_PALETTE_ToLogical(physDev, pixel); } @@ -1035,6 +1082,7 @@ COLORREF X11DRV_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color ) BOOL X11DRV_PaintRgn( PHYSDEV dev, HRGN hrgn ) { X11DRV_PDEVICE *physDev = get_x11drv_dev( dev ); + RECT rc; if (X11DRV_SetupGCForBrush( physDev )) { @@ -1055,6 +1103,11 @@ BOOL X11DRV_PaintRgn( PHYSDEV dev, HRGN hrgn ) wine_tsx11_unlock(); HeapFree( GetProcessHeap(), 0, data ); } + if (GetRgnBox( hrgn, &rc )) + { + LPtoDP( dev->hdc, (POINT *)&rc, 2 ); + add_device_bounds( physDev, &rc ); + } return TRUE; } @@ -1072,6 +1125,7 @@ BOOL X11DRV_Polygon( PHYSDEV dev, const POINT* pt, INT count ) if (!points) return FALSE; memcpy( points, pt, count * sizeof(*pt) ); LPtoDP( dev->hdc, points, count ); + add_pen_device_bounds( physDev, points, count ); if (!(xpoints = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (count+1) ))) { @@ -1127,6 +1181,7 @@ BOOL X11DRV_PolyPolygon( PHYSDEV dev, const POINT* pt, const INT* counts, UINT p if (!points) return FALSE; memcpy( points, pt, total * sizeof(*pt) ); LPtoDP( dev->hdc, points, total ); + add_pen_device_bounds( physDev, points, total ); if (X11DRV_SetupGCForBrush( physDev )) { @@ -1197,6 +1252,7 @@ BOOL X11DRV_PolyPolyline( PHYSDEV dev, const POINT* pt, const DWORD* counts, DWO if (!points) return FALSE; memcpy( points, pt, total * sizeof(*pt) ); LPtoDP( dev->hdc, points, total ); + add_pen_device_bounds( physDev, points, total ); if (X11DRV_SetupGCForPen ( physDev )) { @@ -1235,7 +1291,7 @@ BOOL X11DRV_PolyPolyline( PHYSDEV dev, const POINT* pt, const DWORD* counts, DWO static void X11DRV_InternalFloodFill(XImage *image, X11DRV_PDEVICE *physDev, int x, int y, int xOrg, int yOrg, - unsigned long pixel, WORD fillType ) + unsigned long pixel, WORD fillType, RECT *bounds ) { int left, right; @@ -1250,6 +1306,10 @@ static void X11DRV_InternalFloodFill(XImage *image, X11DRV_PDEVICE *physDev, left = right = x; while ((left > 0) && TO_FLOOD( left-1, y )) left--; while ((right < image->width) && TO_FLOOD( right, y )) right++; + bounds->left = min( bounds->left, left ); + bounds->top = min( bounds->top, y ); + bounds->right = max( bounds->right, right ); + bounds->bottom = max( bounds->bottom, y + 1 ); XFillRectangle( gdi_display, physDev->drawable, physDev->gc, xOrg + left, yOrg + y, right-left, 1 ); @@ -1272,7 +1332,7 @@ static void X11DRV_InternalFloodFill(XImage *image, X11DRV_PDEVICE *physDev, if (x >= right) break; while ((x < right) && TO_FLOOD(x,y)) x++; X11DRV_InternalFloodFill(image, physDev, x-1, y, - xOrg, yOrg, pixel, fillType ); + xOrg, yOrg, pixel, fillType, bounds ); } } @@ -1287,7 +1347,7 @@ static void X11DRV_InternalFloodFill(XImage *image, X11DRV_PDEVICE *physDev, if (x >= right) break; while ((x < right) && TO_FLOOD(x,y)) x++; X11DRV_InternalFloodFill(image, physDev, x-1, y, - xOrg, yOrg, pixel, fillType ); + xOrg, yOrg, pixel, fillType, bounds ); } } #undef TO_FLOOD @@ -1306,7 +1366,7 @@ BOOL X11DRV_ExtFloodFill( PHYSDEV dev, INT x, INT y, COLORREF color, UINT fillTy { X11DRV_PDEVICE *physDev = get_x11drv_dev( dev ); XImage *image; - RECT rect; + RECT rect, bounds; POINT pt; TRACE("X11DRV_ExtFloodFill %d,%d %06x %d\n", x, y, color, fillType ); @@ -1345,14 +1405,19 @@ BOOL X11DRV_ExtFloodFill( PHYSDEV dev, INT x, INT y, COLORREF color, UINT fillTy { unsigned long pixel = X11DRV_PALETTE_ToPhysical( physDev, color ); + reset_bounds( &bounds ); + wine_tsx11_lock(); X11DRV_InternalFloodFill(image, physDev, pt.x - rect.left, pt.y - rect.top, physDev->dc_rect.left + rect.left, physDev->dc_rect.top + rect.top, - pixel, fillType ); + pixel, fillType, &bounds ); wine_tsx11_unlock(); + + OffsetRect( &bounds, rect.left, rect.top ); + add_device_bounds( physDev, &bounds ); } wine_tsx11_lock(); @@ -1371,6 +1436,7 @@ BOOL X11DRV_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert, const GRADIENT_RECT *rect = grad_array; TRIVERTEX v[2]; POINT pt[2]; + RECT rc, bounds; unsigned int i; XGCValues val; @@ -1389,10 +1455,11 @@ BOOL X11DRV_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert, XChangeGC( gdi_display, physdev->gc, GCFunction | GCLineWidth | GCLineStyle | GCCapStyle | GCFillStyle, &val ); wine_tsx11_unlock(); + reset_bounds( &bounds ); for (i = 0; i < ngrad; i++, rect++) { - int pos, x, dx; + int x, dx; v[0] = vert_array[rect->UpperLeft]; v[1] = vert_array[rect->LowerRight]; @@ -1409,7 +1476,12 @@ BOOL X11DRV_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert, v[1] = vert_array[rect->UpperLeft]; dx = -dx; } - for (x = 0, pos = min( pt[0].x, pt[1].x ); x < dx; x++, pos++) + rc.left = min( pt[0].x, pt[1].x ); + rc.top = min( pt[0].y, pt[1].y ); + rc.right = max( pt[0].x, pt[1].x ); + rc.bottom = max( pt[0].y, pt[1].y ); + add_bounds_rect( &bounds, &rc ); + for (x = 0; x < dx; x++) { int color = X11DRV_PALETTE_ToPhysical( physdev, RGB( (v[0].Red * (dx - x) + v[1].Red * x) / dx / 256, @@ -1419,11 +1491,12 @@ BOOL X11DRV_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert, wine_tsx11_lock(); XSetForeground( gdi_display, physdev->gc, color ); XDrawLine( gdi_display, physdev->drawable, physdev->gc, - physdev->dc_rect.left + pos, physdev->dc_rect.top + pt[0].y, - physdev->dc_rect.left + pos, physdev->dc_rect.top + pt[1].y ); + physdev->dc_rect.left + rc.left + x, physdev->dc_rect.top + rc.top, + physdev->dc_rect.left + rc.left + x, physdev->dc_rect.top + rc.bottom ); wine_tsx11_unlock(); } } + add_device_bounds( physdev, &bounds ); return TRUE; case GRADIENT_FILL_RECT_V: @@ -1436,10 +1509,11 @@ BOOL X11DRV_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert, XChangeGC( gdi_display, physdev->gc, GCFunction | GCLineWidth | GCLineStyle | GCCapStyle | GCFillStyle, &val ); wine_tsx11_unlock(); + reset_bounds( &bounds ); for (i = 0; i < ngrad; i++, rect++) { - int pos, y, dy; + int y, dy; v[0] = vert_array[rect->UpperLeft]; v[1] = vert_array[rect->LowerRight]; @@ -1456,7 +1530,12 @@ BOOL X11DRV_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert, v[1] = vert_array[rect->UpperLeft]; dy = -dy; } - for (y = 0, pos = min( pt[0].y, pt[1].y ); y < dy; y++, pos++) + rc.left = min( pt[0].x, pt[1].x ); + rc.top = min( pt[0].y, pt[1].y ); + rc.right = max( pt[0].x, pt[1].x ); + rc.bottom = max( pt[0].y, pt[1].y ); + add_bounds_rect( &bounds, &rc ); + for (y = 0; y < dy; y++) { int color = X11DRV_PALETTE_ToPhysical( physdev, RGB( (v[0].Red * (dy - y) + v[1].Red * y) / dy / 256, @@ -1466,11 +1545,12 @@ BOOL X11DRV_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert, wine_tsx11_lock(); XSetForeground( gdi_display, physdev->gc, color ); XDrawLine( gdi_display, physdev->drawable, physdev->gc, - physdev->dc_rect.left + pt[0].x, physdev->dc_rect.top + pos, - physdev->dc_rect.left + pt[1].x, physdev->dc_rect.top + pos ); + physdev->dc_rect.left + rc.left, physdev->dc_rect.top + rc.top + y, + physdev->dc_rect.left + rc.right, physdev->dc_rect.top + rc.top + y ); wine_tsx11_unlock(); } } + add_device_bounds( physdev, &bounds ); return TRUE; } diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index a98c9ac618b..ecedbdf6410 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -118,6 +118,7 @@ static X11DRV_PDEVICE *create_x11_physdev( Drawable drawable ) if (!(physDev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physDev) ))) return NULL; + reset_bounds( &physDev->bounds ); wine_tsx11_lock(); physDev->drawable = drawable; physDev->gc = XCreateGC( gdi_display, drawable, 0, NULL ); @@ -187,6 +188,31 @@ static BOOL X11DRV_DeleteDC( PHYSDEV dev ) } +void add_device_bounds( X11DRV_PDEVICE *dev, const RECT *rect ) +{ + RECT rc; + + if (dev->region && GetRgnBox( dev->region, &rc )) + { + if (IntersectRect( &rc, &rc, rect )) add_bounds_rect( &dev->bounds, &rc ); + } + else add_bounds_rect( &dev->bounds, rect ); +} + +/*********************************************************************** + * dibdrv_GetBoundsRect + */ +static UINT X11DRV_GetBoundsRect( PHYSDEV dev, RECT *rect, UINT flags ) +{ + X11DRV_PDEVICE *pdev = get_x11drv_dev( dev ); + + if (IsRectEmpty( &pdev->bounds )) return DCB_RESET; + if (rect) *rect = pdev->bounds; + if (flags & DCB_RESET) reset_bounds( &pdev->bounds ); + return DCB_SET; +} + + /*********************************************************************** * GetDeviceCaps (X11DRV.@) */ @@ -477,7 +503,7 @@ static const struct gdi_dc_funcs x11drv_funcs = NULL, /* pFrameRgn */ NULL, /* pGdiComment */ NULL, /* pGdiRealizationInfo */ - NULL, /* pGetBoundsRect */ + X11DRV_GetBoundsRect, /* pGetBoundsRect */ NULL, /* pGetCharABCWidths */ NULL, /* pGetCharABCWidthsI */ NULL, /* pGetCharWidth */ diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index f285f0497e4..566ee652a9d 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2256,6 +2256,7 @@ static void WINAPI X11DRV_wglGetIntegerv(GLenum pname, GLint* params) void flush_gl_drawable(X11DRV_PDEVICE *physDev) { int w, h; + RECT rect; if (!physDev->gl_copy || !physDev->current_pf) return; @@ -2275,6 +2276,8 @@ void flush_gl_drawable(X11DRV_PDEVICE *physDev) XCopyArea(gdi_display, src, physDev->drawable, physDev->gc, 0, 0, w, h, physDev->dc_rect.left, physDev->dc_rect.top); wine_tsx11_unlock(); + SetRect( &rect, 0, 0, w, h ); + add_device_bounds( physDev, &rect ); } } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 91c895d85d7..28040f67dba 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -26,6 +26,7 @@ # error You must include config.h to use this header #endif +#include #include #include #include @@ -122,6 +123,7 @@ typedef struct Drawable drawable; RECT dc_rect; /* DC rectangle relative to drawable */ RECT drawable_rect; /* Drawable rectangle relative to screen */ + RECT bounds; /* Graphics bounds */ HRGN region; /* Device region (visible region & clip region) */ X_PHYSPEN pen; X_PHYSBRUSH brush; @@ -140,6 +142,21 @@ static inline X11DRV_PDEVICE *get_x11drv_dev( PHYSDEV dev ) return (X11DRV_PDEVICE *)dev; } +static inline void reset_bounds( RECT *bounds ) +{ + bounds->left = bounds->top = INT_MAX; + bounds->right = bounds->bottom = INT_MIN; +} + +static inline void add_bounds_rect( RECT *bounds, const RECT *rect ) +{ + if (rect->left >= rect->right || rect->top >= rect->bottom) return; + bounds->left = min( bounds->left, rect->left ); + bounds->top = min( bounds->top, rect->top ); + bounds->right = max( bounds->right, rect->right ); + bounds->bottom = max( bounds->bottom, rect->bottom ); +} + extern X_PHYSBITMAP BITMAP_stock_phys_bitmap DECLSPEC_HIDDEN; /* phys bitmap for the default stock bitmap */ /* Retrieve the GC used for bitmap operations */ @@ -234,6 +251,7 @@ extern DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image, extern RGNDATA *X11DRV_GetRegionData( HRGN hrgn, HDC hdc_lptodp ) DECLSPEC_HIDDEN; extern BOOL add_extra_clipping_region( X11DRV_PDEVICE *dev, HRGN rgn ) DECLSPEC_HIDDEN; extern void restore_clipping_region( X11DRV_PDEVICE *dev ) DECLSPEC_HIDDEN; +extern void add_device_bounds( X11DRV_PDEVICE *dev, const RECT *rect ) DECLSPEC_HIDDEN; extern void execute_rop( X11DRV_PDEVICE *physdev, Pixmap src_pixmap, GC gc, const RECT *visrect, DWORD rop ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/xrender.c b/dlls/winex11.drv/xrender.c index e72ae6edb0c..11b2ccf5bf2 100644 --- a/dlls/winex11.drv/xrender.c +++ b/dlls/winex11.drv/xrender.c @@ -1680,6 +1680,7 @@ static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, POINT offset, desired, current; int render_op = PictOpOver; XRenderColor col; + RECT rect, bounds; get_xrender_color( physdev, GetTextColor( physdev->dev.hdc ), &col ); pict = get_xrender_picture( physdev, 0, (flags & ETO_CLIPPED) ? lprect : NULL ); @@ -1702,6 +1703,7 @@ static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, lprect->right - lprect->left, lprect->bottom - lprect->top ); wine_tsx11_unlock(); + add_device_bounds( physdev->x11dev, lprect ); } if(count == 0) return TRUE; @@ -1750,6 +1752,7 @@ static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, if (physdev->format == WXR_FORMAT_MONO && col.red == 0 && col.green == 0 && col.blue == 0) render_op = PictOpOutReverse; /* This gives us 'black' text */ + reset_bounds( &bounds ); for(idx = 0; idx < count; idx++) { elts[idx].glyphset = formatEntry->glyphset; @@ -1761,6 +1764,12 @@ static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, current.x += (elts[idx].xOff + formatEntry->gis[wstr[idx]].xOff); current.y += (elts[idx].yOff + formatEntry->gis[wstr[idx]].yOff); + rect.left = desired.x - physdev->x11dev->dc_rect.left - formatEntry->gis[wstr[idx]].x; + rect.top = desired.y - physdev->x11dev->dc_rect.top - formatEntry->gis[wstr[idx]].y; + rect.right = rect.left + formatEntry->gis[wstr[idx]].width; + rect.bottom = rect.top + formatEntry->gis[wstr[idx]].height; + add_bounds_rect( &bounds, &rect ); + if(!lpDx) { desired.x += formatEntry->gis[wstr[idx]].xOff; @@ -1792,6 +1801,7 @@ static BOOL xrenderdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, HeapFree(GetProcessHeap(), 0, elts); LeaveCriticalSection(&xrender_cs); + add_device_bounds( physdev->x11dev, &bounds ); return TRUE; } @@ -2170,6 +2180,7 @@ static BOOL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst, } else xrender_stretch_blit( physdev_src, physdev_dst, 0, src, dst ); + add_device_bounds( physdev_dst->x11dev, &dst->visrect ); return TRUE; x11drv_fallback: @@ -2272,6 +2283,8 @@ static DWORD xrenderdrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMA } else xrender_put_image( src_pixmap, src_pict, mask_pict, clip, physdev->pict_format, physdev, 0, src, dst, use_repeat ); + + add_device_bounds( physdev->x11dev, &dst->visrect ); } wine_tsx11_lock(); @@ -2354,6 +2367,7 @@ static DWORD xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct wine_tsx11_unlock(); LeaveCriticalSection( &xrender_cs ); + add_device_bounds( physdev->x11dev, &dst->visrect ); } return ret; @@ -2459,6 +2473,7 @@ static BOOL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst, wine_tsx11_unlock(); LeaveCriticalSection( &xrender_cs ); + add_device_bounds( physdev_dst->x11dev, &dst->visrect ); return TRUE; } @@ -2476,6 +2491,7 @@ static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG n Picture src_pict, dst_pict; unsigned int i; const GRADIENT_RECT *rect = grad_array; + RECT rc; POINT pt[2]; if (!pXRenderCreateLinearGradient) goto fallback; @@ -2535,8 +2551,13 @@ static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG n } } - TRACE( "%u gradient %d,%d - %d,%d colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n", - mode, pt[0].x, pt[0].y, pt[1].x, pt[1].y, + rc.left = min( pt[0].x, pt[1].x ); + rc.top = min( pt[0].y, pt[1].y ); + rc.right = max( pt[0].x, pt[1].x ); + rc.bottom = max( pt[0].y, pt[1].y ); + + TRACE( "%u gradient %s colors %04x,%04x,%04x,%04x -> %04x,%04x,%04x,%04x\n", + mode, wine_dbgstr_rect( &rc ), colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha, colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha ); @@ -2545,12 +2566,13 @@ static BOOL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG n wine_tsx11_lock(); src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 ); xrender_blit( PictOpSrc, src_pict, 0, dst_pict, - 0, 0, abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y), - physdev->x11dev->dc_rect.left + min( pt[0].x, pt[1].x ), - physdev->x11dev->dc_rect.top + min( pt[0].y, pt[1].y ), - abs(pt[1].x - pt[0].x), abs(pt[1].y - pt[0].y), 1, 1 ); + 0, 0, rc.right - rc.left, rc.bottom - rc.top, + physdev->x11dev->dc_rect.left + rc.left, + physdev->x11dev->dc_rect.top + rc.top, + rc.right - rc.left, rc.bottom - rc.top, 1, 1 ); pXRenderFreePicture( gdi_display, src_pict ); wine_tsx11_unlock(); + add_device_bounds( physdev->x11dev, &rc ); } return TRUE; }