Skip to content

Commit 8b40e9b

Browse files
committed
WPF - Resize Hack for when browser switches from hidden to visible (#2779)
- Add 1 to the width/height rather than subtracts like the hack in the previous versions - Delay between resizes is now configurable via ResizeHackForIssue2279DelayInMs
1 parent 1e2ddba commit 8b40e9b

File tree

1 file changed

+184
-22
lines changed

1 file changed

+184
-22
lines changed

CefSharp.Wpf/ChromiumWebBrowser.cs

Lines changed: 184 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,29 @@ public class ChromiumWebBrowser : Control, IRenderWebBrowser, IWpfWebBrowser
140140
/// </summary>
141141
private static bool DesignMode;
142142

143+
private bool resizeHackForIssue2779Enabled;
144+
private CefSharp.Structs.Size? resizeHackForIssue2779Size;
145+
143146
/// <summary>
144147
/// The value for disposal, if it's 1 (one) then this instance is either disposed
145148
/// or in the process of getting disposed
146149
/// </summary>
147150
private int disposeSignaled;
148151

152+
/// <summary>
153+
/// Hack to work around issue https://github.com/cefsharp/CefSharp/issues/2779
154+
/// Enabled by default
155+
/// </summary>
156+
public bool EnableResizeHackForIssue2779 { get; set; }
157+
158+
/// <summary>
159+
/// Number of miliseconds to wait after resizing the browser when it first
160+
/// becomes visible. After the delay the browser will revert to it's
161+
/// original size.
162+
/// Hack to work around issue https://github.com/cefsharp/CefSharp/issues/2779
163+
/// </summary>
164+
public int ResizeHackForIssue2279DelayInMs { get; set; }
165+
149166
/// <summary>
150167
/// Used as workaround for issue https://github.com/cefsharp/CefSharp/issues/3021
151168
/// </summary>
@@ -643,6 +660,9 @@ public ChromiumWebBrowser(string initialAddress)
643660
[MethodImpl(MethodImplOptions.NoInlining)]
644661
private void NoInliningConstructor()
645662
{
663+
EnableResizeHackForIssue2779 = true;
664+
ResizeHackForIssue2279DelayInMs = 50;
665+
646666
//Initialize CEF if it hasn't already been initialized
647667
if (!Cef.IsInitialized)
648668
{
@@ -909,7 +929,18 @@ Rect IRenderWebBrowser.GetViewRect()
909929
/// <returns>View Rectangle</returns>
910930
protected virtual Rect GetViewRect()
911931
{
912-
return viewRect;
932+
//Take a local copy as the value is set on a different thread,
933+
//Its possible the struct is set to null after our initial check.
934+
var resizeRect = resizeHackForIssue2779Size;
935+
936+
if (resizeRect == null)
937+
{
938+
return viewRect;
939+
}
940+
941+
var size = resizeRect.Value;
942+
943+
return new Rect(0, 0, size.Width, size.Height);
913944
}
914945

915946
bool IRenderWebBrowser.GetScreenPoint(int viewX, int viewY, out int screenX, out int screenY)
@@ -1054,6 +1085,11 @@ void IRenderWebBrowser.OnPaint(PaintElementType type, Rect dirtyRect, IntPtr buf
10541085
/// <param name="height">height</param>
10551086
protected virtual void OnPaint(bool isPopup, Rect dirtyRect, IntPtr buffer, int width, int height)
10561087
{
1088+
if (resizeHackForIssue2779Enabled)
1089+
{
1090+
return;
1091+
}
1092+
10571093
var paint = Paint;
10581094
if (paint != null)
10591095
{
@@ -1868,7 +1904,7 @@ private void PresentationSourceChangedHandler(object sender, SourceChangedEventA
18681904
}
18691905
}
18701906

1871-
private void OnWindowStateChanged(object sender, EventArgs e)
1907+
private async void OnWindowStateChanged(object sender, EventArgs e)
18721908
{
18731909
var window = (Window)sender;
18741910

@@ -1879,16 +1915,54 @@ private void OnWindowStateChanged(object sender, EventArgs e)
18791915
{
18801916
if (previousWindowState == WindowState.Minimized && browser != null)
18811917
{
1882-
browser.GetHost().WasHidden(false);
1918+
await CefUiThreadRunAsync(async () =>
1919+
{
1920+
var host = browser?.GetHost();
1921+
if (host != null && !host.IsDisposed)
1922+
{
1923+
try
1924+
{
1925+
host.WasHidden(false);
1926+
1927+
await ResizeHackFor2779();
1928+
}
1929+
catch (ObjectDisposedException)
1930+
{
1931+
// Because Dispose runs in another thread there's a race condition between
1932+
// that and this code running on the CEF UI thread, so the host could be disposed
1933+
// between the check and using it. We can either synchronize access using locking
1934+
// (potentially blocking the UI thread in Dispose) or catch the extremely rare
1935+
// exception, which is what we do here
1936+
}
1937+
}
1938+
});
18831939
}
1940+
18841941
break;
18851942
}
18861943
case WindowState.Minimized:
18871944
{
1888-
if (browser != null)
1945+
await CefUiThreadRunAsync(() =>
18891946
{
1890-
browser.GetHost().WasHidden(true);
1891-
}
1947+
var host = browser?.GetHost();
1948+
if (host != null && !host.IsDisposed)
1949+
{
1950+
if (EnableResizeHackForIssue2779)
1951+
{
1952+
resizeHackForIssue2779Enabled = true;
1953+
}
1954+
1955+
try
1956+
{
1957+
host.WasHidden(true);
1958+
}
1959+
catch (ObjectDisposedException)
1960+
{
1961+
// See comment in catch in OnWindowStateChanged
1962+
}
1963+
}
1964+
});
1965+
18921966
break;
18931967
}
18941968
}
@@ -2031,6 +2105,24 @@ internal void UiThreadRunAsync(Action action, DispatcherPriority priority = Disp
20312105
}
20322106
}
20332107

2108+
protected async Task CefUiThreadRunAsync(Action action)
2109+
{
2110+
if (!IsDisposed && InternalIsBrowserInitialized())
2111+
{
2112+
if (Cef.CurrentlyOnThread(CefThreadIds.TID_UI))
2113+
{
2114+
action();
2115+
}
2116+
else
2117+
{
2118+
await Cef.UIThreadTaskFactory.StartNew(delegate
2119+
{
2120+
action();
2121+
});
2122+
}
2123+
}
2124+
}
2125+
20342126
/// <summary>
20352127
/// Runs the specific Action on the Dispatcher in an sync fashion
20362128
/// </summary>
@@ -2053,52 +2145,97 @@ private void UiThreadRunSync(Action action, DispatcherPriority priority = Dispat
20532145
/// </summary>
20542146
/// <param name="sender">The sender.</param>
20552147
/// <param name="e">The <see cref="SizeChangedEventArgs"/> instance containing the event data.</param>
2056-
private void OnActualSizeChanged(object sender, SizeChangedEventArgs e)
2148+
private async void OnActualSizeChanged(object sender, SizeChangedEventArgs e)
20572149
{
20582150
// Initialize RenderClientAdapter when WPF has calculated the actual size of current content.
20592151
CreateOffscreenBrowser(e.NewSize);
20602152

2153+
if (InternalIsBrowserInitialized())
2154+
{
2155+
await CefUiThreadRunAsync(() =>
2156+
{
2157+
SetViewRect(e);
2158+
2159+
var host = browser?.GetHost();
2160+
if (host != null && !host.IsDisposed)
2161+
{
2162+
try
2163+
{
2164+
host.WasResized();
2165+
}
2166+
catch (ObjectDisposedException)
2167+
{
2168+
// See comment in catch in OnWindowStateChanged
2169+
}
2170+
}
2171+
});
2172+
}
2173+
else
2174+
{
2175+
//If the browser hasn't been created yet then directly update the viewRect
2176+
SetViewRect(e);
2177+
}
2178+
}
2179+
2180+
private void SetViewRect(SizeChangedEventArgs e)
2181+
{
20612182
//NOTE: Previous we used Math.Ceiling to round the sizing up, we
20622183
//now set UseLayoutRounding = true; on the control so the sizes are
20632184
//already rounded to a whole number for us.
20642185
viewRect = new Rect(0, 0, (int)e.NewSize.Width, (int)e.NewSize.Height);
2065-
2066-
if (browser != null)
2067-
{
2068-
browser.GetHost().WasResized();
2069-
}
20702186
}
20712187

20722188
/// <summary>
20732189
/// Handles the <see cref="E:IsVisibleChanged" /> event.
20742190
/// </summary>
20752191
/// <param name="sender">The sender.</param>
20762192
/// <param name="args">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
2077-
private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs args)
2193+
private async void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs args)
20782194
{
20792195
var isVisible = (bool)args.NewValue;
20802196

20812197
if (browser != null)
20822198
{
2083-
var host = browser.GetHost();
2084-
host.WasHidden(!isVisible);
2199+
await CefUiThreadRunAsync(async () =>
2200+
{
2201+
var host = browser?.GetHost();
2202+
if (host != null && !host.IsDisposed)
2203+
{
2204+
try
2205+
{
2206+
host.WasHidden(!isVisible);
2207+
2208+
if (isVisible)
2209+
{
2210+
await ResizeHackFor2779();
2211+
}
2212+
else if (EnableResizeHackForIssue2779)
2213+
{
2214+
resizeHackForIssue2779Enabled = true;
2215+
}
2216+
}
2217+
catch (ObjectDisposedException)
2218+
{
2219+
// See comment in catch in OnWindowStateChanged
2220+
}
2221+
}
2222+
});
20852223

2086-
if (isVisible)
2224+
if (browser != null)
20872225
{
20882226
//Fix for #1778 - When browser becomes visible we update the zoom level
20892227
//browsers of the same origin will share the same zoomlevel and
20902228
//we need to track the update, so our ZoomLevelProperty works
20912229
//properly
2092-
host.GetZoomLevelAsync().ContinueWith(t =>
2230+
var zoomLevel = await browser.GetHost().GetZoomLevelAsync();
2231+
2232+
UiThreadRunAsync(() =>
20932233
{
20942234
if (!IsDisposed)
20952235
{
2096-
SetCurrentValue(ZoomLevelProperty, t.Result);
2236+
SetCurrentValue(ZoomLevelProperty, zoomLevel);
20972237
}
2098-
},
2099-
CancellationToken.None,
2100-
TaskContinuationOptions.OnlyOnRanToCompletion,
2101-
TaskScheduler.FromCurrentSynchronizationContext());
2238+
});
21022239
}
21032240
}
21042241
}
@@ -2738,5 +2875,30 @@ private bool InternalIsBrowserInitialized()
27382875
// Volatile.Read would likely use a memory barrier which I believe is unnecessary in this scenario
27392876
return Interlocked.CompareExchange(ref browserInitialized, 0, 0) == 1;
27402877
}
2878+
2879+
private async Task ResizeHackFor2779()
2880+
{
2881+
if (EnableResizeHackForIssue2779)
2882+
{
2883+
var host = browser?.GetHost();
2884+
if (host != null && !host.IsDisposed)
2885+
{
2886+
resizeHackForIssue2779Size = new Structs.Size(viewRect.Width + 1, viewRect.Height + 1);
2887+
host.WasResized();
2888+
2889+
await Task.Delay(ResizeHackForIssue2279DelayInMs);
2890+
2891+
if (!host.IsDisposed)
2892+
{
2893+
resizeHackForIssue2779Size = null;
2894+
host.WasResized();
2895+
2896+
resizeHackForIssue2779Enabled = false;
2897+
2898+
host.Invalidate(PaintElementType.View);
2899+
}
2900+
}
2901+
}
2902+
}
27412903
}
27422904
}

0 commit comments

Comments
 (0)