Skip to content

Commit c8339c8

Browse files
committed
Enable support for CEF 6613+ and Chrome Runtime
Add a dummy Browser Client to introduce limitations into the Chrome UI windows that can be opened in uncontrolled edge cases. Chrome UI windows are unmanaged by default. By returning something other than null in GetDefaultClient() we can lock it down in various ways. OnBeforePopup, OnOpenURLFromTab can probably be removed as they don't get called. There's no direct way to stop the Chrome UI window from being opened, so instead close it immediately. Disable Various Chrome Settings in custom docks & browser sources via SetPreferences. For more, check `chrome/common/pref_names.h`. Chrome's default error display is now used by CEF, so on top of the existing override in browser docks, a similar override has been added to browser sources which just redirects to about:blank. Also blocks - Chrome Extensions, as they are largely untested and unpredictable - MediaRouter, which provides Cast.. functionality - CalculateNativeWinOcclusion, which lowers FPS for hidden pages - LiveCaption, which provides automatic captions - DocumentPictureInPictureAPI, which provides PiP widgets (YouTube) - StorageNotificationService, when approaching low cache space A data migration function is included. It moves some directories into a new 'Default' profile subdirectory, and performs the necessary renaming of certain files to ensure the new Profile loads. Additionally, the cookie directories for each service integration must be moved into the root config directory, as subdirectories in their current form (obs_profile_cookies/<cookie_id>) are not supported. This is intentional, and according to Marshall this was never a supported setup. cache_path *must* be a direct child of the root_cache_path. Invalid cache_path_ is silently treated as Incognito Mode and cookies are not stored.
1 parent 68af8e8 commit c8339c8

14 files changed

Lines changed: 391 additions & 7 deletions

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ target_sources(
2525
browser-app.hpp
2626
browser-client.cpp
2727
browser-client.hpp
28+
browser-dummy-client.cpp
29+
browser-dummy-client.hpp
2830
browser-scheme.cpp
2931
browser-scheme.hpp
3032
browser-version.h

browser-app.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,62 @@ CefRefPtr<CefBrowserProcessHandler> BrowserApp::GetBrowserProcessHandler()
4848
return this;
4949
}
5050

51+
CefRefPtr<CefClient> BrowserApp::GetDefaultClient()
52+
{
53+
return GetDummy();
54+
}
55+
5156
void BrowserApp::OnRegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar)
5257
{
5358
registrar->AddCustomScheme("http", CEF_SCHEME_OPTION_STANDARD | CEF_SCHEME_OPTION_CORS_ENABLED);
5459
}
5560

61+
void BrowserApp::OnContextInitialized()
62+
{
63+
// Without a default client, CefBrowser is unmanaged, allowing full-blown Chromium windows outside of our control
64+
// We don't actually want those, so define a dummy client which will automatically close any such windows
65+
dummy = new BrowserDummyClient();
66+
67+
CefRefPtr<CefRequestContext> requestContext = CefRequestContext::GetGlobalContext();
68+
CefString errorMessage;
69+
CefRefPtr<CefValue> optionValue = CefValue::Create();
70+
71+
constexpr std::array<std::string_view, 20> kBrowserFeaturesToDisable{
72+
"autofill.credit_card_enabled",
73+
"autofill.enabled",
74+
"autofill.iban_enabled",
75+
"autofill.payment_card_benefits",
76+
"autofill.payment_cvc_storage",
77+
"autofill.profile_enabled",
78+
"autologin.enabled",
79+
"browser_labs_enabled",
80+
"credentials_enable_autosignin",
81+
"credentials_enable_service",
82+
"payments.can_make_payment_enabled",
83+
"printing.enabled",
84+
"search.suggest_enabled",
85+
"shopping_list_enabled",
86+
"side_panel.google_search_side_panel_enabled",
87+
"side_search.enabled",
88+
"signin.allowed",
89+
"signin.allowed_on_next_startup",
90+
"translate",
91+
"url_keyed_anonymized_data_collection.enabled"};
92+
93+
constexpr std::array<std::string_view, 2> kBrowserFeaturesToEnable{"extensions.block_external_extensions",
94+
"extensions.disabled"};
95+
96+
optionValue->SetBool(false);
97+
for (std::string_view feature : kBrowserFeaturesToDisable) {
98+
requestContext->SetPreference(feature.data(), optionValue.get(), errorMessage);
99+
}
100+
101+
optionValue->SetBool(true);
102+
for (std::string_view feature : kBrowserFeaturesToEnable) {
103+
requestContext->SetPreference(feature.data(), optionValue.get(), errorMessage);
104+
}
105+
}
106+
56107
void BrowserApp::OnBeforeChildProcessLaunch(CefRefPtr<CefCommandLine> command_line)
57108
{
58109
#ifdef _WIN32
@@ -82,16 +133,35 @@ void BrowserApp::OnBeforeCommandLineProcessing(const CefString &, CefRefPtr<CefC
82133
disableFeatures += ",EnableWindowsGamingInputDataFetcher";
83134
#endif
84135
disableFeatures += ",WebBluetooth";
136+
disableFeatures += ",MediaRouter";
137+
disableFeatures += ",CalculateNativeWinOcclusion";
138+
disableFeatures += ",LiveCaption";
139+
// https://github.com/chromiumembedded/cef/issues/3966
140+
disableFeatures += ".StorageNotificationService";
85141
command_line->AppendSwitchWithValue("disable-features", disableFeatures);
86142
} else {
87143
command_line->AppendSwitchWithValue("disable-features", "WebBluetooth,"
88144
#ifdef _WIN32
89145
"EnableWindowsGamingInputDataFetcher,"
90146
#endif
147+
"MediaRouter,"
148+
"CalculateNativeWinOcclusion,"
149+
"LiveCaption,"
150+
"StorageNotificationService,"
91151
"HardwareMediaKeyHandling");
92152
}
93153

154+
if (command_line->HasSwitch("disable-blink-features")) {
155+
std::string disableBlinkFeatures = command_line->GetSwitchValue("disable-blink-features");
156+
disableBlinkFeatures += ",DocumentPictureInPictureAPI";
157+
command_line->AppendSwitchWithValue("disable-blink-features", disableBlinkFeatures);
158+
} else {
159+
command_line->AppendSwitchWithValue("disable-blink-features", "DocumentPictureInPictureAPI");
160+
}
161+
94162
command_line->AppendSwitchWithValue("autoplay-policy", "no-user-gesture-required");
163+
command_line->AppendSwitch("disable-extensions");
164+
command_line->AppendSwitch("hide-crash-restore-bubble");
95165
#ifdef __APPLE__
96166
command_line->AppendSwitch("use-mock-keychain");
97167
#elif !defined(_WIN32)

browser-app.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <unordered_map>
2323
#include <functional>
2424
#include "cef-headers.hpp"
25+
#include "browser-dummy-client.hpp"
2526

2627
typedef std::function<void(CefRefPtr<CefBrowser>)> BrowserFunc;
2728

@@ -85,6 +86,8 @@ class BrowserApp : public CefApp, public CefRenderProcessHandler, public CefBrow
8586

8687
virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override;
8788
virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override;
89+
virtual CefRefPtr<CefClient> GetDefaultClient() override;
90+
virtual void OnContextInitialized() override;
8891
virtual void OnBeforeChildProcessLaunch(CefRefPtr<CefCommandLine> command_line) override;
8992
virtual void OnRegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar) override;
9093
virtual void OnBeforeCommandLineProcessing(const CefString &process_type,
@@ -106,5 +109,9 @@ class BrowserApp : public CefApp, public CefRenderProcessHandler, public CefBrow
106109
QTimer frameTimer;
107110
#endif
108111

112+
CefRefPtr<BrowserDummyClient> dummy = nullptr;
113+
114+
BrowserDummyClient *GetDummy() const { return dummy.get(); };
115+
109116
IMPLEMENT_REFCOUNTING(BrowserApp);
110117
};

browser-client.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,17 @@ void BrowserClient::OnLoadEnd(CefRefPtr<CefBrowser>, CefRefPtr<CefFrame> frame,
626626
}
627627
}
628628

629+
void BrowserClient::OnLoadError(CefRefPtr<CefBrowser>, [[maybe_unused]] CefRefPtr<CefFrame> frame,
630+
CefLoadHandler::ErrorCode, const CefString &, const CefString &)
631+
{
632+
#if CHROME_VERSION_BUILD > 6533
633+
// CEF doesn't currently provide a way to properly disable/override the default Chrome error page
634+
// https://github.com/obsproject/obs-studio/issues/13499
635+
// FIXME: https://github.com/chromiumembedded/cef/issues/3852
636+
frame->LoadURL("about:blank");
637+
#endif
638+
}
639+
629640
bool BrowserClient::OnConsoleMessage(CefRefPtr<CefBrowser>, cef_log_severity_t level, const CefString &message,
630641
const CefString &source, int line)
631642
{

browser-client.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,5 +146,9 @@ class BrowserClient : public CefClient,
146146
/* CefLoadHandler */
147147
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int httpStatusCode) override;
148148

149+
virtual void OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame,
150+
CefLoadHandler::ErrorCode errorCode, const CefString &errorText,
151+
const CefString &failedUrl) override;
152+
149153
IMPLEMENT_REFCOUNTING(BrowserClient);
150154
};

browser-dummy-client.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
#include "browser-dummy-client.hpp"
3+
4+
CefRefPtr<CefCommandHandler> BrowserDummyClient::GetCommandHandler()
5+
{
6+
return this;
7+
}
8+
9+
CefRefPtr<CefRequestHandler> BrowserDummyClient::GetRequestHandler()
10+
{
11+
return this;
12+
}
13+
14+
CefRefPtr<CefLifeSpanHandler> BrowserDummyClient::GetLifeSpanHandler()
15+
{
16+
return this;
17+
}
18+
19+
bool BrowserDummyClient::OnChromeCommand(CefRefPtr<CefBrowser>, int, cef_window_open_disposition_t)
20+
{
21+
return true;
22+
}
23+
24+
bool BrowserDummyClient::IsChromeAppMenuItemVisible(CefRefPtr<CefBrowser>, int)
25+
{
26+
return false;
27+
}
28+
29+
bool BrowserDummyClient::IsChromeToolbarButtonVisible(cef_chrome_toolbar_button_type_t)
30+
{
31+
return false;
32+
}
33+
34+
bool BrowserDummyClient::IsChromePageActionIconVisible(cef_chrome_page_action_icon_type_t)
35+
{
36+
return false;
37+
}
38+
39+
bool BrowserDummyClient::IsChromeAppMenuItemEnabled(CefRefPtr<CefBrowser>, int)
40+
{
41+
return false;
42+
}
43+
44+
bool BrowserDummyClient::OnBeforePopup(CefRefPtr<CefBrowser>, CefRefPtr<CefFrame>,
45+
#if CHROME_VERSION_BUILD >= 6834
46+
int,
47+
#endif
48+
const CefString &, const CefString &, cef_window_open_disposition_t, bool,
49+
const CefPopupFeatures &, CefWindowInfo &, CefRefPtr<CefClient> &,
50+
CefBrowserSettings &, CefRefPtr<CefDictionaryValue> &, bool *)
51+
{
52+
return true;
53+
}
54+
55+
void BrowserDummyClient::OnAfterCreated(CefRefPtr<CefBrowser> browser)
56+
{
57+
if (browser && browser->GetHost()) {
58+
browser->GetHost()->CloseBrowser(false);
59+
}
60+
}
61+
62+
bool BrowserDummyClient::OnOpenURLFromTab(CefRefPtr<CefBrowser>, CefRefPtr<CefFrame>, const CefString &,
63+
CefRequestHandler::WindowOpenDisposition, bool)
64+
{
65+
return true;
66+
}
67+
68+
bool BrowserDummyClient::OnBeforeBrowse(CefRefPtr<CefBrowser>, CefRefPtr<CefFrame>, CefRefPtr<CefRequest>, bool, bool)
69+
{
70+
return true;
71+
}

browser-dummy-client.hpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#pragma once
2+
3+
#include "cef-headers.hpp"
4+
5+
class BrowserDummyClient : public CefClient,
6+
public CefCommandHandler,
7+
public CefRequestHandler,
8+
public CefLifeSpanHandler {
9+
public:
10+
virtual CefRefPtr<CefCommandHandler> GetCommandHandler() override;
11+
virtual CefRefPtr<CefRequestHandler> GetRequestHandler() override;
12+
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override;
13+
14+
/* CefCommandHandler */
15+
virtual bool OnChromeCommand(CefRefPtr<CefBrowser> browser, int command_id,
16+
cef_window_open_disposition_t disposition) override;
17+
virtual bool IsChromeAppMenuItemVisible(CefRefPtr<CefBrowser> browser, int command_id) override;
18+
virtual bool IsChromeToolbarButtonVisible(cef_chrome_toolbar_button_type_t button_type) override;
19+
20+
virtual bool IsChromePageActionIconVisible(cef_chrome_page_action_icon_type_t icon_type) override;
21+
22+
virtual bool IsChromeAppMenuItemEnabled(CefRefPtr<CefBrowser> browser, int command_id) override;
23+
24+
/* CefLifeSpanHandler */
25+
virtual bool OnBeforePopup(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame,
26+
#if CHROME_VERSION_BUILD >= 6834
27+
int,
28+
#endif
29+
const CefString &target_url, const CefString &target_frame_name,
30+
cef_window_open_disposition_t target_disposition, bool user_gesture,
31+
const CefPopupFeatures &popupFeatures, CefWindowInfo &windowInfo,
32+
CefRefPtr<CefClient> &client, CefBrowserSettings &settings,
33+
CefRefPtr<CefDictionaryValue> &extra_info, bool *no_javascript_access) override;
34+
35+
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
36+
37+
/* CefRequestHandler */
38+
virtual bool OnOpenURLFromTab(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame,
39+
const CefString &target_url,
40+
CefRequestHandler::WindowOpenDisposition target_disposition,
41+
bool user_gesture) override;
42+
43+
virtual bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame,
44+
CefRefPtr<CefRequest> request, bool user_gesture, bool is_redirect) override;
45+
46+
IMPLEMENT_REFCOUNTING(BrowserDummyClient);
47+
};

cmake/os-linux.cmake

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ add_executable(OBS::browser-helper ALIAS browser-helper)
1414

1515
target_sources(
1616
browser-helper PRIVATE # cmake-format: sortable
17-
browser-app.cpp browser-app.hpp cef-headers.hpp obs-browser-page/obs-browser-page-main.cpp)
17+
browser-app.cpp browser-app.hpp browser-dummy-client.hpp browser-dummy-client.cpp
18+
cef-headers.hpp obs-browser-page/obs-browser-page-main.cpp)
1819

1920
target_include_directories(browser-helper PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/deps"
2021
"${CMAKE_CURRENT_SOURCE_DIR}/obs-browser-page")

cmake/os-macos.cmake

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ foreach(helper IN LISTS helper_suffixes)
3131

3232
target_sources(
3333
${target_name} PRIVATE # cmake-format: sortable
34-
browser-app.cpp browser-app.hpp cef-headers.hpp obs-browser-page/obs-browser-page-main.cpp)
34+
browser-app.cpp browser-app.hpp browser-dummy-client.hpp browser-dummy-client.cpp
35+
cef-headers.hpp obs-browser-page/obs-browser-page-main.cpp)
3536

3637
target_compile_definitions(${target_name} PRIVATE ENABLE_BROWSER_SHARED_TEXTURE)
3738

cmake/os-windows.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ add_executable(OBS::browser-helper ALIAS obs-browser-helper)
1313
target_sources(
1414
obs-browser-helper
1515
PRIVATE # cmake-format: sortable
16-
browser-app.cpp browser-app.hpp cef-headers.hpp obs-browser-page.manifest
17-
obs-browser-page/obs-browser-page-main.cpp)
16+
browser-app.cpp browser-app.hpp browser-dummy-client.hpp browser-dummy-client.cpp
17+
cef-headers.hpp obs-browser-page.manifest obs-browser-page/obs-browser-page-main.cpp)
1818

1919
configure_file(cmake/windows/obs-module-helper.rc.in obs-browser-page.rc)
2020
target_sources(obs-browser-helper PRIVATE obs-browser-page.rc)

0 commit comments

Comments
 (0)