Skip to content

Commit ec0a62a

Browse files
authored
Merge pull request #698 from MicrosoftEdge/freeze
API Review: TryFreeze/Unfreeze
2 parents 1582e61 + 1cbc366 commit ec0a62a

1 file changed

Lines changed: 177 additions & 0 deletions

File tree

specs/Freeze.md

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# Background
2+
Edge browser has a sleeping tab feature which reduces resource usage when the tab is in the background. We are introducing WebView2 APIs
3+
to access this feature so that invisible WebView can use less resources. We'd appreciate your feedback.
4+
5+
6+
# Description
7+
You may call the `TrySuspendAsync` API to have the WebView2 consume less memory. This is useful when your Win32 app becomes invisible, or when your Universal Windows Platform app is being suspended, during the suspended event handler before completing the suspended event.
8+
9+
# Examples
10+
## .NET, WinRT
11+
```c#
12+
async protected void OnSuspending(object sender, SuspendingEventArgs args)
13+
{
14+
SuspendingDeferral deferral = args.SuspendingOperation.GetDeferral();
15+
// Ensure that CoreWebView2Controller is invisible, it must be invisible for TrySuspendAsync to succeed.
16+
// webView here is WinUI WebView2 control.
17+
// For WPF and Winforms WebView2 control, do webView.Visibility = false;
18+
webView.Visibility = Visibility.Collapsed;
19+
await webView.CoreWebView2.TrySuspendAsync();
20+
deferral.Complete();
21+
}
22+
async protected void OnResuming(object sender, Object args)
23+
{
24+
// Making a WebView2 visible will automatically resume it
25+
// But you can also explicitly call Resume without making a WebView2 visible to resume it.
26+
webView.CoreWebView2.Resume();
27+
webView.Visibility = true;
28+
}
29+
```
30+
## Win32 C++
31+
As unfreeze is very fast and automatically happens when WebView becomes visible, the app can generaly immediately call `TryFreeze` when a WebView becomes invisible.
32+
```cpp
33+
bool ViewComponent::HandleWindowMessage(
34+
HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* result)
35+
{
36+
if (message == WM_SYSCOMMAND)
37+
{
38+
if (wParam == SC_MINIMIZE)
39+
{
40+
// Hide the webview when the app window is minimized, and freeze it.
41+
m_controller->put_IsVisible(FALSE);
42+
Suspend();
43+
}
44+
else if (wParam == SC_RESTORE)
45+
{
46+
// When the app window is restored, show the webview
47+
// (unless the user has toggle visibility off).
48+
if (m_isVisible)
49+
{
50+
Resume();
51+
m_controller->put_IsVisible(TRUE);
52+
}
53+
}
54+
}
55+
}
56+
57+
void ViewComponent::Suspend()
58+
{
59+
HRESULT hr = webView->TrySuspend(
60+
Callback<ICoreWebView2StagingTrySuspendCompletedHandler>(
61+
[](HRESULT errorCode, BOOL isSuccessful) -> HRESULT {
62+
std::wstringstream formattedMessage;
63+
formattedMessage << "TrySuspend result (0x" << std::hex << errorCode
64+
<< ") " << (isSuccessful ? "succeeded" : "failed");
65+
MessageBox(nullptr, formattedMessage.str().c_str(), nullptr, MB_OK);
66+
return S_OK;
67+
})
68+
.Get());
69+
if (FAILED(hr))
70+
ShowFailure(hr, L"Call to TrySuspend failed");
71+
}
72+
73+
void ViewComponent::Resume()
74+
{
75+
wil::com_ptr<ICoreWebView2Staging2> webView;
76+
webView = m_webView.query<ICoreWebView2Staging2>();
77+
webView->Resume();
78+
}
79+
```
80+
81+
# Remarks
82+
The CoreWebView2Controller's IsVisible property must be false when the API is called. Otherwise, the
83+
API fails with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`.
84+
Suspending is similar to putting a tab to sleep in the Edge browser. Suspending pauses
85+
WebView script timers and animations, minimizes CPU usage for the associated
86+
browser renderer process and allows the operating system to reuse the memory that was
87+
used by the renderer process for other processes.
88+
Note that the Suspend is best effort and considered completed successfully once the request
89+
is sent to browser renderer process. If there is a running script, the script will continue
90+
to run and the renderer process will be suspended after that script is done.
91+
See [Sleeping Tabs FAQ](https://techcommunity.microsoft.com/t5/articles/sleeping-tabs-faq/m-p/1705434)
92+
for conditions that might prevent WebView from being suspended. In those situations,
93+
The the completed handler will be invoked with isSuccessful as false and errorCode as S_OK.
94+
The WebView will be automatically resumed when it becomes visible. Therefore, the
95+
app normally does not have to call Resume.
96+
The app can call `Resume` and then `TrySuspend` periodically for an invisible WebView so that
97+
the invisible WebView can sync up with latest data and the page ready to show fresh content
98+
when it becomes visible.
99+
All WebView APIs can still be accessed when a WebView is suspended. Some APIs like Navigate will auto resume
100+
the WebView. To avoid unexpected auto resume, check `IsSuspended` property before calling APIs that might
101+
change WebView state.
102+
103+
# API Notes
104+
See [API Details](#api-details) section below for API reference.
105+
106+
# API Details
107+
108+
## Win32 C++
109+
```IDL
110+
interface ICoreWebView2_2 : ICoreWebView2 {
111+
112+
/// An app may call the `TrySuspend` API to have the WebView2 consume less memory.
113+
/// This is useful when a Win32 app becomes invisible, or when a Universal Windows
114+
/// Platform app is being suspended, during the suspended event handler before completing
115+
/// the suspended event.
116+
/// The CoreWebView2Controller's IsVisible property must be false when the API is called.
117+
/// Otherwise, the API fails with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`.
118+
/// Suspending is similar to putting a tab to sleep in the Edge browser. Suspending pauses
119+
/// WebView script timers and animations, minimizes CPU usage for the associated
120+
/// browser renderer process and allows the operating system to reuse the memory that was
121+
/// used by the renderer process for other processes.
122+
/// Note that the Suspend is best effort and considered completed successfully once the request
123+
/// is sent to browser renderer process. If there is a running script, the script will continue
124+
/// to run and the renderer process will be suspended after that script is done.
125+
/// See [Sleeping Tabs FAQ](https://techcommunity.microsoft.com/t5/articles/sleeping-tabs-faq/m-p/1705434)
126+
/// for conditions that might prevent WebView from being suspended. In those situations,
127+
/// The the completed handler will be invoked with isSuccessful as false and errorCode as S_OK.
128+
/// The WebView will be automatically resumed when it becomes visible. Therefore, the
129+
/// app normally does not have to call Resume.
130+
/// The app can call `Resume` and then `TrySuspend` periodically for an invisible WebView so that
131+
/// the invisible WebView can sync up with latest data and the page ready to show fresh content
132+
/// when it becomes visible.
133+
/// All WebView APIs can still be accessed when a WebView is suspended. Some APIs like Navigate
134+
/// will auto resume the WebView. To avoid unexpected auto resume, check `IsSuspended` property
135+
/// before calling APIs that might change WebView state.
136+
HRESULT TrySuspend([in] ICoreWebView2StagingTrySuspendCompletedHandler* handler);
137+
138+
/// Resume the WebView so that it would resume activities on the web page.
139+
/// This API can be called while the WebView2 controller is invisible.
140+
/// The app can interact with the WebView immediately after Resume.
141+
/// WebView will be automatically resumed when it becomes visible.
142+
///
143+
/// \snippet ViewComponent.cpp ToggleIsVisibleOnMinimize
144+
///
145+
/// \snippet ViewComponent.cpp Resume
146+
///
147+
HRESULT Resume();
148+
149+
/// `TRUE` when WebView is suspended, from the time when TrySuspend has completed
150+
/// successfully until WebView is resumed.
151+
[propget] HRESULT IsSuspended([out, retval] BOOL* isSuspended);
152+
}
153+
154+
/// The caller implements this interface to receive the TryFreeze result.
155+
interface ICoreWebView2StagingTrySuspendCompletedHandler : IUnknown {
156+
157+
/// Provide the result of the TrySuspend operation.
158+
/// See [Sleeping Tabs FAQ](https://techcommunity.microsoft.com/t5/articles/sleeping-tabs-faq/m-p/1705434)
159+
/// for conditions that might prevent WebView from being suspended. In those situations,
160+
/// isSuccessful will be false and errorCode is S_OK.
161+
HRESULT Invoke([in] HRESULT errorCode, [in] BOOL isSuccessful);
162+
163+
}
164+
```
165+
## .NET WinRT
166+
```c#
167+
namespace Microsoft.Web.WebView2.Core
168+
{
169+
public partial class CoreWebView2
170+
{
171+
// There are other API in this interface that we are not showing
172+
public Task<bool> TrySuspendAsync();
173+
public void Resume();
174+
public bool IsSuspended { get; }
175+
}
176+
}
177+
```

0 commit comments

Comments
 (0)