Description
What happened?
WebView2 Window Extends Beyond Content Bounds in Multi-Monitor DPI Scaling Scenarios
Environment
- WebView2 SDK: 1.0.1823.32
- .NET Framework: 4.8
- Application: WebView2 Core in VSTO Add-in for PowerPoint
- OS: Windows 10/11 (multiple versions)
- Hardware: Multi-monitor setup with different DPI scaling factors, for exampe: (primary: 150% at 1920x1200, secondary: 175% at 4K)
Issue Description
When hosting WebView2 in a multi-monitor environment with different DPI scaling factors, the WebView2 host window (Chrome_WidgetWin_0) extends beyond its content bounds. This extended section is actually displaying the content that is behind the PowerPoint slideshow presentation window which creates a very unusual user experience. This issue appears to be specific to WebView2's window management and persists regardless of DPI awareness context. We are not explicitly setting BoundsMode, but it defaults to UseRawPixels and we have tried to fix it using UseRasterizationScale without any luck. We generally get perfect placement and sizing when system dpi matches the external monitor dpi.
This was working on our initial release in 2023, when runtime version 118 was the latest stable. We noticed this regression in early 2024, and our best guess is around runtime 120 based on time and similar issues. We have been unable to test and install against these runtimes to see exactly where the regression took place.
Detailed Observations
- WebView2 Content Window:
- Correctly positioned and sized according to the bounds passed to SetBoundsAndZoomFactor
- Reports correct innerWidth (3192) and innerHeight (1756) in browser dev tools window
- When using inspect/UIAViewer, the actual size is (systemDPI - 144 or 150% Scale, external monitor DPI 168 or 175% Scale):
- Chrome_WidgetWin_1: Location:{x: -860 y: -2113 w:2736, h: 1505}
- Chrome_WidgetWin_0: Location:{x: -860 y: -2113 w:3192, h: 1756}
- Behavior with different WebView2 bounds modes:
- UseRawPixels: Content is too small, but Chrome_WidgetWin_0 is positioned correctly.
- UseRasterizationScale: Content (Chrome_WidgetWin_1) is correctly sized and positioned, but parent (Chrome_WidgetWin_0)
window still extends beyond bounds. - Setting RasterizationScale = 1 or some other value may change the size of the content but not the bounds
- PowerPoint Window:
- We initialize our WebView2 Controllers with the pptHWND and then reparent them to the slideshowHWND when the
presentation begins. - We have tried reworking this, at the cost of performance, to only initialize the WV2 controllers with the slideshowHWND but the same behavior persists.
- We have also tried ensuring the .Navigate is called with the URL only after setting the Bounds, as well as manipulating the sizing with Zoom and RasterizationScale but to no avail.
- We initialize our WebView2 Controllers with the pptHWND and then reparent them to the slideshowHWND when the
Set Bounds: {Left: 49.41426, Top: 47.61421, Width: 3192.6, Height: 1756.2}
Dev tools reported dimensions:
window.innerWidth = 1825
window.innerHeight = 1004
Expected Behavior
The WebView2 host window (Chrome_WidgetWin_0) and content window (Chrome_WidgetWin_1) should follow the bounds set via SetBoundsAndZoomFactor or Bounds = assignment.
Code Sample
// Create and initialize WebView2 for WV2EmbedManager
private async void InitializeWebView2()
{
CoreWebView2EnvironmentOptions options = new CoreWebView2EnvironmentOptions();
// pass null to use latest installed runtime
webView2Environment = await CoreWebView2Environment.CreateAsync(null, dataPath, options).ConfigureAwait(true);
// We manage cookies and authentication with an independent controller
independentController = await webView2Environment.CreateCoreWebView2ControllerAsync(pptHWND).ConfigureAwait(true);
controllersByURL = new Dictionary<string, CoreWebView2Controller>();
controllerQueue = new Queue<CoreWebView2Controller>();
for (int i = 0; i < CONTROLLER_COUNT; i++)
{
CoreWebView2Controller controller = await webView2Environment.CreateCoreWebView2ControllerAsync(pptHWND).ConfigureAwait(true);
controller.CoreWebView2.Settings.UserAgent = Util.GenerateWebView2UserAgent();
controller.CoreWebView2.Settings.AreDevToolsEnabled = Util.DevToolsEnabled();
controller.CoreWebView2.Settings.IsZoomControlEnabled = true;
controller.CoreWebView2.Settings.AreDefaultContextMenusEnabled = true;
await controller.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(listeners).ConfigureAwait(true);
controller.CoreWebView2.WebMessageReceived += HandleWebMessageReceivedEvent;
controller.CoreWebView2.NavigationCompleted += NavDone;
// We have also tried setting this to false
controller.ShouldDetectMonitorScaleChanges = true;
// We've tried to explicity set up with both BoundsMode options with different Rectangle dimensions, with different but negative results
// controller.BoundsMode = CoreWebView2BoundsMode.UseRawPixels;
// controller.BoundsMode = CoreWebView2BoundsMode.UseRasterizationScale;
// controller.RasterizationScaleChanged += HandleRasterizationScaleChanged;
// we create a controller for each slide and cache 3 at a time
// the NavDone event may fire before setting the bounds but this doesn't seem // to be the issue as cold starting a presentation from the slide with a
// a browser doesn't display this issue and refreshing the page doesn't have a
// an effect on the bounds.
controllerQueue.Enqueue(controller);
}
}
// Get bounds from PowerPoint placeholder {Left: 49.41426, Top: 47.61421, Width: 3192.6, Height: 1756.2}
RECT placeholderRect = shapeInPixels.CoordsInPixels(
placeholderShape.Top,
placeholderShape.Left,
placeholderShape.Width,
placeholderShape.Height
);
private void NavDone(object sender, CoreWebView2NavigationCompletedEventArgs args)
{
if (!(sender is CoreWebView2)) return;
if (((CoreWebView2)sender) == currentVizEmbed?.CoreWebView2)
{
// the core logic is that it sets IsVisible to true
ShowPoll();
}
}
public void BeginSlideShow(int slideshowHWND, List<PESlide> slides, Func<bool> checkEOS)
{
this.slideshowHWND = slideshowHWND;
IntPtr slideshowHandle = new IntPtr(slideshowHWND);
foreach (CoreWebView2Controller controller in controllerQueue)
{
// reset ParentWindow from from ppt HWND to SlideshowHWND
controller.ParentWindow = slideshowHandle;
}
UpdateAllSlides(slides);
this.checkEOS = checkEOS;
}
// Set bounds and zoom factor in ShowSlide(int index) method
controller.SetBoundsAndZoomFactor(
new Rectangle(
placeholderRect.X,
placeholderRect.Y,
placeholderRect.Width,
placeholderRect.Height
),
1.0 // Always set to 1.0, this doesn't seem to be the issue
);
Importance
Important. My app's user experience is significantly compromised.
Runtime Channel
Stable release (WebView2 Runtime)
Runtime Version
136.0.3240.76
SDK Version
1.0.1823.32
Framework
Other
Operating System
Windows 11
OS Version
10.0.26100
Repro steps
Reproduction Steps
- Create a PowerPoint presentation with a placeholder shape
- Use WebView2 to create a browser overlay on this placeholder
- Set browser bounds using
SetBoundsAndZoomFactor
to match placeholder dimensions - Present the PowerPoint slideshow on a secondary monitor with different DPI scaling than primary
- Observe that while content is positioned correctly, the host window extends beyond bounds if DPI scaling of secondary monitor is higher than the primary/system DPI or the web content is bigger than the bounds if lower than the system DPI.
Repros in Edge Browser
No, issue does not reproduce in the corresponding Edge version
Regression
Regression in newer Runtime
Last working version (if regression)
1.0.1823.32, Runtime: 118.0.xxxx