From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/dce.c | 170 +++++++++++++++++++++++++- dlls/win32u/driver.c | 3 +- dlls/win32u/win32u_private.h | 3 +- dlls/win32u/window.c | 4 +- dlls/wineandroid.drv/android.h | 3 +- dlls/wineandroid.drv/window.c | 4 +- dlls/winemac.drv/macdrv.h | 3 +- dlls/winemac.drv/surface.c | 4 +- dlls/winewayland.drv/waylanddrv.h | 3 +- dlls/winewayland.drv/window_surface.c | 4 +- dlls/winex11.drv/bitblt.c | 4 +- dlls/winex11.drv/x11drv.h | 3 +- include/wine/gdi_driver.h | 4 +- 13 files changed, 196 insertions(+), 16 deletions(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 8bad1949ebd..e0684c8f86f 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -138,18 +138,184 @@ static void create_offscreen_window_surface( HWND hwnd, const RECT *surface_rect *window_surface = window_surface_create( sizeof(*surface), &offscreen_window_surface_funcs, hwnd, surface_rect, info, 0 ); }
-void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_rect, +struct scaled_surface +{ + struct window_surface header; + struct window_surface *target_surface; + UINT dpi_from; + UINT dpi_to; +}; + +static struct scaled_surface *get_scaled_surface( struct window_surface *window_surface ) +{ + return CONTAINING_RECORD( window_surface, struct scaled_surface, header ); +} + +static void scaled_surface_set_clip( struct window_surface *window_surface, const RECT *rects, UINT count ) +{ + struct scaled_surface *surface = get_scaled_surface( window_surface ); + HRGN hrgn = map_dpi_region( window_surface->clip_region, surface->dpi_from, surface->dpi_to ); + window_surface_set_clip( surface->target_surface, hrgn ); + if (hrgn) NtGdiDeleteObjectApp( hrgn ); +} + +static BOOL scaled_surface_flush( struct window_surface *window_surface, const RECT *rect, const RECT *dirty, + const BITMAPINFO *color_info, const void *color_bits, BOOL shape_changed, + const BITMAPINFO *shape_info, const void *shape_bits ) +{ + struct scaled_surface *surface = get_scaled_surface( window_surface ); + RECT src = *dirty, dst; + HDC hdc_dst, hdc_src; + HBITMAP bitmap = 0; + + src.left &= ~7; + src.top &= ~7; + src.right = (src.right + 7) & ~7; + src.bottom = (src.bottom + 7) & ~7; + + dst = map_dpi_rect( src, surface->dpi_from, surface->dpi_to ); + + hdc_dst = NtGdiCreateCompatibleDC( 0 ); + hdc_src = NtGdiCreateCompatibleDC( 0 ); + + NtGdiSelectBitmap( hdc_src, window_surface->color_bitmap ); + NtGdiSelectBitmap( hdc_dst, surface->target_surface->color_bitmap ); + + NtGdiStretchBlt( hdc_dst, dst.left, dst.top, dst.right - dst.left, dst.bottom - dst.top, + hdc_src, src.left, src.top, src.right - src.left, src.bottom - src.top, + SRCCOPY, 0 ); + + NtGdiDeleteObjectApp( hdc_dst ); + NtGdiDeleteObjectApp( hdc_src ); + if (bitmap) NtGdiDeleteObjectApp( bitmap ); + + window_surface_lock( surface->target_surface ); + add_bounds_rect( &surface->target_surface->bounds, &dst ); + window_surface_unlock( surface->target_surface ); + + if (shape_changed) + { + HRGN hrgn = map_dpi_region( window_surface->shape_region, surface->dpi_from, surface->dpi_to ); + window_surface_set_shape( surface->target_surface, hrgn ); + if (hrgn) NtGdiDeleteObjectApp( hrgn ); + + window_surface_set_layered( surface->target_surface, window_surface->color_key, + window_surface->alpha_bits, window_surface->alpha_mask ); + } + + window_surface_flush( surface->target_surface ); + return TRUE; +} + +static void scaled_surface_destroy( struct window_surface *window_surface ) +{ + struct scaled_surface *surface = get_scaled_surface( window_surface ); + window_surface_release( surface->target_surface ); +} + +static const struct window_surface_funcs scaled_surface_funcs = +{ + scaled_surface_set_clip, + scaled_surface_flush, + scaled_surface_destroy +}; + +static struct window_surface *scaled_surface_create( HWND hwnd, const RECT *surface_rect, UINT dpi_from, UINT dpi_to, + struct window_surface *target_surface ) +{ + char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; + BITMAPINFO *info = (BITMAPINFO *)buffer; + struct window_surface *window_surface; + struct scaled_surface *surface; + + memset( info, 0, sizeof(*info) ); + info->bmiHeader.biSize = sizeof(info->bmiHeader); + info->bmiHeader.biWidth = surface_rect->right; + info->bmiHeader.biHeight = -surface_rect->bottom; /* top-down */ + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = 32; + info->bmiHeader.biSizeImage = get_dib_image_size( info ); + info->bmiHeader.biCompression = BI_RGB; + + if ((window_surface = window_surface_create( sizeof(*surface), &scaled_surface_funcs, hwnd, surface_rect, info, 0 ))) + { + surface = get_scaled_surface( window_surface ); + surface->target_surface = target_surface; + surface->dpi_from = dpi_from; + surface->dpi_to = dpi_to; + } + + return window_surface; +} + +static RECT get_surface_rect( RECT rect ) +{ + OffsetRect( &rect, -rect.left, -rect.top ); + + rect.left &= ~127; + rect.top &= ~127; + rect.right = max( rect.left + 128, (rect.right + 127) & ~127 ); + rect.bottom = max( rect.top + 128, (rect.bottom + 127) & ~127 ); + + return rect; +} + +void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_rect, UINT monitor_dpi, struct window_surface **window_surface ) { - if (!user_driver->pCreateWindowSurface( hwnd, create_layered, surface_rect, window_surface )) + struct window_surface *previous, *driver_surface; + UINT dpi = get_thread_dpi(); + RECT monitor_rect; + + window_surface_add_ref( (driver_surface = get_driver_window_surface( *window_surface, monitor_dpi )) ); + + /* check if the driver supports scaling window surfaces directly */ + if (user_driver->pCreateWindowSurface( hwnd, create_layered, dpi, monitor_dpi, surface_rect, &driver_surface )) { + if (*window_surface) window_surface_release( *window_surface ); + *window_surface = driver_surface; + return; + } + + monitor_rect = get_surface_rect( map_dpi_rect( *surface_rect, dpi, monitor_dpi ) ); + if (!user_driver->pCreateWindowSurface( hwnd, create_layered, monitor_dpi, monitor_dpi, &monitor_rect, &driver_surface )) + { + if (driver_surface) window_surface_release( driver_surface ); if (*window_surface) { window_surface_release( *window_surface ); /* create an offscreen window surface if the driver doesn't implement CreateWindowSurface */ create_offscreen_window_surface( hwnd, surface_rect, window_surface ); } + return; } + + if (!driver_surface) + { + if (*window_surface) window_surface_release( *window_surface ); + *window_surface = NULL; + return; + } + + /* reuse previous scaling surface, update its target to the driver surface */ + if ((previous = *window_surface) && previous->funcs == &scaled_surface_funcs) + { + struct scaled_surface *surface = get_scaled_surface( previous ); + window_surface_release( surface->target_surface ); + surface->target_surface = driver_surface; + return; + } + if (previous) window_surface_release( previous ); + + *window_surface = scaled_surface_create( hwnd, surface_rect, dpi, monitor_dpi, driver_surface ); +} + +struct window_surface *get_driver_window_surface( struct window_surface *surface, UINT monitor_dpi ) +{ + if (!surface || surface == &dummy_surface) return surface; + if (surface->funcs != &scaled_surface_funcs) return surface; + if (get_scaled_surface( surface )->dpi_to != monitor_dpi) return &dummy_surface; + return get_scaled_surface( surface )->target_surface; }
/* window surface common helpers */ diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 3e094264d15..db4a94542a1 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -891,7 +891,8 @@ extern BOOL nulldrv_GetWindowStyleMasks( HWND hwnd, UINT style, UINT ex_style, U return FALSE; }
-static BOOL nulldrv_CreateWindowSurface( HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface ) +static BOOL nulldrv_CreateWindowSurface( HWND hwnd, BOOL layered, UINT dpi_from, UINT dpi_to, + const RECT *surface_rect, struct window_surface **surface ) { return FALSE; } diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index c8b2eb4c529..1dbae4fe94d 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -45,8 +45,9 @@ extern ULONG_PTR set_icon_param( HICON handle, ULONG_PTR param );
/* dce.c */ extern struct window_surface dummy_surface; -extern void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_rect, +extern void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_rect, UINT monitor_dpi, struct window_surface **window_surface ); +extern struct window_surface *get_driver_window_surface( struct window_surface *surface, UINT monitor_dpi ); extern void erase_now( HWND hwnd, UINT rdw_flags ); extern void flush_window_surfaces( BOOL idle ); extern void move_window_bits( HWND hwnd, const RECT *visible_rect, const RECT *old_visible_rect, diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 1835bfa3f47..12b71b6de82 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1941,7 +1941,7 @@ static struct window_surface *get_window_surface( HWND hwnd, UINT swp_flags, BOO else if (create_layered || is_layered) needs_surface = TRUE;
if (needs_surface) - create_window_surface( hwnd, create_layered, surface_rect, &new_surface ); + create_window_surface( hwnd, create_layered, surface_rect, monitor_dpi, &new_surface ); else if (new_surface && new_surface != &dummy_surface) { window_surface_release( new_surface ); @@ -2108,7 +2108,7 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru } }
- user_driver->pWindowPosChanged( hwnd, insert_after, swp_flags, &monitor_rects, new_surface ); + user_driver->pWindowPosChanged( hwnd, insert_after, swp_flags, &monitor_rects, get_driver_window_surface( new_surface, monitor_dpi ) ); }
return ret; diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index 850b235f3a1..ade6eae1aa3 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -96,7 +96,8 @@ extern void ANDROID_SetCapture( HWND hwnd, UINT flags ); extern UINT ANDROID_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp ); extern LRESULT ANDROID_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ); extern BOOL ANDROID_WindowPosChanging( HWND hwnd, UINT swp_flags, BOOL shaped, const struct window_rects *rects ); -extern BOOL ANDROID_CreateWindowSurface( HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface ); +extern BOOL ANDROID_CreateWindowSurface( HWND hwnd, BOOL layered, UINT dpi_from, UINT dpi_to, + const RECT *surface_rect, struct window_surface **surface ); extern void ANDROID_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, const struct window_rects *new_rects, struct window_surface *surface );
diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index 537aae456e7..dcb4d1e1212 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -1039,13 +1039,15 @@ BOOL ANDROID_WindowPosChanging( HWND hwnd, UINT swp_flags, BOOL shaped, const st /*********************************************************************** * ANDROID_CreateWindowSurface */ -BOOL ANDROID_CreateWindowSurface( HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface ) +BOOL ANDROID_CreateWindowSurface( HWND hwnd, BOOL layered, UINT dpi_from, UINT dpi_to, + const RECT *surface_rect, struct window_surface **surface ) { struct window_surface *previous; struct android_win_data *data;
TRACE( "hwnd %p, layered %u, surface_rect %s, surface %p\n", hwnd, layered, wine_dbgstr_rect( surface_rect ), surface );
+ if (dpi_from != dpi_to) return FALSE; /* use default implementation */ if ((previous = *surface) && previous->funcs == &android_surface_funcs) return TRUE; if (!(data = get_win_data( hwnd ))) return TRUE; /* use default surface */ if (previous) window_surface_release( previous ); diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 6e506514164..b80162e522b 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -149,7 +149,8 @@ extern void macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alph extern LRESULT macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); extern BOOL macdrv_WindowPosChanging(HWND hwnd, UINT swp_flags, BOOL shaped, const struct window_rects *rects); extern BOOL macdrv_GetWindowStyleMasks(HWND hwnd, UINT style, UINT ex_style, UINT *style_mask, UINT *ex_style_mask); -extern BOOL macdrv_CreateWindowSurface(HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface); +extern BOOL macdrv_CreateWindowSurface(HWND hwnd, BOOL layered, UINT dpi_from, UINT dpi_to, + const RECT *surface_rect, struct window_surface **surface); extern void macdrv_MoveWindowBits(HWND hwnd, const struct window_rects *new_rects, const RECT *valid_rects); extern void macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, const struct window_rects *new_rects, struct window_surface *surface); diff --git a/dlls/winemac.drv/surface.c b/dlls/winemac.drv/surface.c index a849918dfa7..85170777c59 100644 --- a/dlls/winemac.drv/surface.c +++ b/dlls/winemac.drv/surface.c @@ -211,13 +211,15 @@ static struct window_surface *create_surface(HWND hwnd, macdrv_window window, co /*********************************************************************** * CreateWindowSurface (MACDRV.@) */ -BOOL macdrv_CreateWindowSurface(HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface) +BOOL macdrv_CreateWindowSurface(HWND hwnd, BOOL layered, UINT dpi_from, UINT dpi_to, + const RECT *surface_rect, struct window_surface **surface) { struct window_surface *previous; struct macdrv_win_data *data;
TRACE("hwnd %p, layered %u, surface_rect %s, surface %p\n", hwnd, layered, wine_dbgstr_rect(surface_rect), surface);
+ if (dpi_from != dpi_to) return FALSE; /* use default implementation */ if ((previous = *surface) && previous->funcs == &macdrv_surface_funcs) return TRUE; if (!(data = get_win_data(hwnd))) return TRUE; /* use default surface */ if (previous) window_surface_release(previous); diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 40f86526cd2..b0a7890b7b8 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -356,7 +356,8 @@ LRESULT WAYLAND_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, const struct window_rects *new_rects, struct window_surface *surface); BOOL WAYLAND_WindowPosChanging(HWND hwnd, UINT swp_flags, BOOL shaped, const struct window_rects *rects); -BOOL WAYLAND_CreateWindowSurface(HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface); +BOOL WAYLAND_CreateWindowSurface(HWND hwnd, BOOL layered, UINT dpi_from, UINT dpi_to, + const RECT *surface_rect, struct window_surface **surface); UINT WAYLAND_VulkanInit(UINT version, void *vulkan_handle, const struct vulkan_driver_funcs **driver_funcs); struct opengl_funcs *WAYLAND_wine_get_wgl_driver(UINT version);
diff --git a/dlls/winewayland.drv/window_surface.c b/dlls/winewayland.drv/window_surface.c index 570c186861b..bd2fae6bad0 100644 --- a/dlls/winewayland.drv/window_surface.c +++ b/dlls/winewayland.drv/window_surface.c @@ -499,13 +499,15 @@ void wayland_window_surface_update_wayland_surface(struct window_surface *window /*********************************************************************** * WAYLAND_CreateWindowSurface */ -BOOL WAYLAND_CreateWindowSurface(HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface) +BOOL WAYLAND_CreateWindowSurface(HWND hwnd, BOOL layered, UINT dpi_from, UINT dpi_to, + const RECT *surface_rect, struct window_surface **surface) { struct window_surface *previous; struct wayland_win_data *data;
TRACE("hwnd %p, layered %u, surface_rect %s, surface %p\n", hwnd, layered, wine_dbgstr_rect(surface_rect), surface);
+ if (dpi_from != dpi_to) return FALSE; /* use default implementation */ if ((previous = *surface) && previous->funcs == &wayland_window_surface_funcs) return TRUE; if (!(data = wayland_win_data_get(hwnd))) return TRUE; /* use default surface */ if (previous) window_surface_release(previous); diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c index 757386595f0..ef635ca4d24 100644 --- a/dlls/winex11.drv/bitblt.c +++ b/dlls/winex11.drv/bitblt.c @@ -1964,13 +1964,15 @@ static BOOL enable_direct_drawing( struct x11drv_win_data *data, BOOL layered ) /*********************************************************************** * CreateWindowSurface (X11DRV.@) */ -BOOL X11DRV_CreateWindowSurface( HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface ) +BOOL X11DRV_CreateWindowSurface( HWND hwnd, BOOL layered, UINT dpi_from, UINT dpi_to, + const RECT *surface_rect, struct window_surface **surface ) { struct window_surface *previous; struct x11drv_win_data *data;
TRACE( "hwnd %p, layered %u, surface_rect %s, surface %p\n", hwnd, layered, wine_dbgstr_rect( surface_rect ), surface );
+ if (dpi_from != dpi_to) return FALSE; /* use default implementation */ if (!(data = get_win_data( hwnd ))) return TRUE; /* use default surface */ if ((previous = *surface) && previous->funcs == &x11drv_surface_funcs) { diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index b87d6a87932..b5d92c9bff5 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -245,7 +245,8 @@ extern void X11DRV_UpdateLayeredWindow( HWND hwnd, UINT flags ); extern LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ); extern BOOL X11DRV_WindowPosChanging( HWND hwnd, UINT swp_flags, BOOL shaped, const struct window_rects *rects ); extern BOOL X11DRV_GetWindowStyleMasks( HWND hwnd, UINT style, UINT ex_style, UINT *style_mask, UINT *ex_style_mask ); -extern BOOL X11DRV_CreateWindowSurface( HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface ); +extern BOOL X11DRV_CreateWindowSurface( HWND hwnd, BOOL layered, UINT dpi_from, UINT dpi_to, + const RECT *surface_rect, struct window_surface **surface ); extern void X11DRV_MoveWindowBits( HWND hwnd, const struct window_rects *new_rects, const RECT *valid_rects ); extern void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, const struct window_rects *new_rects, struct window_surface *surface ); diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index fee065af71b..e1da4711846 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -219,7 +219,7 @@ struct gdi_dc_funcs };
/* increment this when you change the DC function table */ -#define WINE_GDI_DRIVER_VERSION 96 +#define WINE_GDI_DRIVER_VERSION 97
#define GDI_PRIORITY_NULL_DRV 0 /* null driver */ #define GDI_PRIORITY_FONT_DRV 100 /* any font driver */ @@ -387,7 +387,7 @@ struct user_driver_funcs LRESULT (*pWindowMessage)(HWND,UINT,WPARAM,LPARAM); BOOL (*pWindowPosChanging)(HWND,UINT,BOOL,const struct window_rects *); BOOL (*pGetWindowStyleMasks)(HWND,UINT,UINT,UINT*,UINT*); - BOOL (*pCreateWindowSurface)(HWND,BOOL,const RECT *,struct window_surface**); + BOOL (*pCreateWindowSurface)(HWND,BOOL,UINT,UINT,const RECT *,struct window_surface**); void (*pMoveWindowBits)(HWND,const struct window_rects *,const RECT *); void (*pWindowPosChanged)(HWND,HWND,UINT,const struct window_rects*,struct window_surface*); /* system parameters */