Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com --- dlls/user32/tests/win.c | 6 ++-- dlls/winex11.drv/bitblt.c | 75 +++++++++++++++++++++++++++++++++++---- 2 files changed, 72 insertions(+), 9 deletions(-)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index b50c8e1ff00..30514a05234 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -12580,7 +12580,7 @@ static void test_surface_composition(void) flush_events( TRUE ); paint_client_rect(hwnd, BGRA2RGB(COLOR1)); check_client_surface(hwnd, painted_surface, sizeof(painted_surface), FALSE); - check_screen_surface(hwnd, partial_surface, sizeof(partial_surface), TRUE); + check_screen_surface(hwnd, partial_surface, sizeof(partial_surface), FALSE);
SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE); flush_events( TRUE ); @@ -12682,7 +12682,7 @@ static void test_surface_composition(void)
SetWindowLongW(hwnd, GWL_EXSTYLE, GetWindowLongW(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); paint_client_rect(hwnd, BGRA2RGB(COLOR1)); - check_client_surface(hwnd, hidden_surface, sizeof(hidden_surface), TRUE); + check_client_surface(hwnd, hidden_surface, sizeof(hidden_surface), FALSE); check_screen_surface(hwnd, screen_surface, sizeof(screen_surface), FALSE);
ShowWindow(hwnd, SW_SHOW); @@ -12807,7 +12807,7 @@ static void test_surface_composition(void)
SetWindowLongW(hwnd, GWL_EXSTYLE, GetWindowLongW(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); paint_client_rect(hwnd, BGRA2RGB(COLOR1)); - check_client_surface(hwnd, hidden_surface, sizeof(hidden_surface), TRUE); + check_client_surface(hwnd, hidden_surface, sizeof(hidden_surface), FALSE); check_screen_surface(hwnd, screen_surface, sizeof(screen_surface), FALSE);
ret = UpdateLayeredWindow(hwnd, hdc_dst, NULL, (SIZE *)&rect.right, hdc_src, (POINT *)&rect.left, 0, NULL, ULW_OPAQUE); diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c index fad183b0b01..3a083ea415c 100644 --- a/dlls/winex11.drv/bitblt.c +++ b/dlls/winex11.drv/bitblt.c @@ -1297,6 +1297,65 @@ update_format: return ERROR_BAD_FORMAT; }
+static XImage *safe_get_image( Drawable drawable, RECT *dc_rect, XVisualInfo *vis, + int x, int y, int width, int height, BOOL *use_xfree ) +{ + XImage *image; + int dest_x = 0, dest_y = 0; + + if (width < 0 || height < 0) + return NULL; + + if (x >= dc_rect->left && y >= dc_rect->top + && x + width <= dc_rect->right && y + height <= dc_rect->bottom) + { + *use_xfree = TRUE; + return XGetImage( gdi_display, drawable, x, y, width, height, AllPlanes, ZPixmap ); + } + + *use_xfree = FALSE; + image = XCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, 0, NULL, + width, height, 32, 0 ); + if (!image) + return NULL; + + image->data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, image->bytes_per_line * image->height ); + if (!image->data) + { + XDestroyImage( image ); + return NULL; + } + + if (x >= dc_rect->right || y >= dc_rect->bottom + || x + width <= dc_rect->left || y + height <= dc_rect->top) + return image; + + if (x < dc_rect->left) + { + dest_x = dc_rect->left - x; + width -= dest_x; + x += dest_x; + } + if (y < dc_rect->top) + { + dest_y = dc_rect->top - y; + height -= dest_y; + y += dest_y; + } + if (x + width > dc_rect->right) + width -= dc_rect->right - (x + width); + if (y + height > dc_rect->bottom) + height -= dc_rect->bottom - (y + height); + + if (XGetSubImage( gdi_display, drawable, x, y, width, height, AllPlanes, ZPixmap, image, dest_x, dest_y )) + return image; + + HeapFree( GetProcessHeap(), 0, image->data ); + image->data = NULL; + XDestroyImage( image ); + return NULL; +} + /*********************************************************************** * X11DRV_GetImage */ @@ -1311,6 +1370,7 @@ DWORD CDECL X11DRV_GetImage( PHYSDEV dev, BITMAPINFO *info, struct gdi_image_bits src_bits; const XPixmapFormatValues *format; const int *mapping = NULL; + BOOL use_xfree = FALSE;
vis.depth = physdev->depth; if (physdev->color_shifts) @@ -1356,14 +1416,17 @@ DWORD CDECL X11DRV_GetImage( PHYSDEV dev, BITMAPINFO *info, OffsetRect( &src->visrect, -x, -y );
X11DRV_expect_error( gdi_display, XGetImage_handler, NULL ); - image = XGetImage( gdi_display, physdev->drawable, + image = safe_get_image ( physdev->drawable, &physdev->dc_rect, &vis, physdev->dc_rect.left + x, physdev->dc_rect.top + y, - width, height, AllPlanes, ZPixmap ); + width, height, &use_xfree ); if (X11DRV_check_error()) { /* use a temporary pixmap to avoid the BadMatch error */ Pixmap pixmap = XCreatePixmap( gdi_display, root_window, width, height, vis.depth ); GC gc = XCreateGC( gdi_display, pixmap, 0, NULL ); + int black = BlackPixel( gdi_display, DefaultScreen(gdi_display) ); + XSetForeground( gdi_display, gc, black ); + XFillRectangle( gdi_display, pixmap, gc, 0, 0, width, height );
XSetGraphicsExposures( gdi_display, gc, False ); XCopyArea( gdi_display, physdev->drawable, pixmap, gc, @@ -1385,10 +1448,10 @@ DWORD CDECL X11DRV_GetImage( PHYSDEV dev, BITMAPINFO *info, zeropad_masks[(width * image->bits_per_pixel) & 31] );
if (!ret && bits->ptr == image->data) - { - bits->free = free_ximage_bits; - image->data = NULL; - } + bits->free = use_xfree ? free_ximage_bits : free_heap_bits; + else + use_xfree ? XFree(image->data) : HeapFree( GetProcessHeap(), 0, image->data ); + image->data = NULL; XDestroyImage( image ); return ret; }