// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include "webview_app.h" #include #include "include/cef_browser.h" #include "include/cef_command_line.h" #include "include/views/cef_browser_view.h" #include "include/views/cef_window.h" #include "include/wrapper/cef_helpers.h" namespace { // When using the Views framework this object provides the delegate // implementation for the CefWindow that hosts the Views-based browser. class SimpleWindowDelegate : public CefWindowDelegate { public: explicit SimpleWindowDelegate(CefRefPtr browser_view) : browser_view_(browser_view) {} void OnWindowCreated(CefRefPtr window) override { // Add the browser view and show the window. window->AddChildView(browser_view_); window->Show(); // Give keyboard focus to the browser view. browser_view_->RequestFocus(); } void OnWindowDestroyed(CefRefPtr window) override { browser_view_ = nullptr; } bool CanClose(CefRefPtr window) override { // Allow the window to close if the browser says it's OK. CefRefPtr browser = browser_view_->GetBrowser(); if (browser) return browser->GetHost()->TryCloseBrowser(); return true; } CefSize GetPreferredSize(CefRefPtr view) override { return CefSize(1280, 720); } private: CefRefPtr browser_view_; IMPLEMENT_REFCOUNTING(SimpleWindowDelegate); DISALLOW_COPY_AND_ASSIGN(SimpleWindowDelegate); }; class SimpleBrowserViewDelegate : public CefBrowserViewDelegate { public: SimpleBrowserViewDelegate() {} bool OnPopupBrowserViewCreated(CefRefPtr browser_view, CefRefPtr popup_browser_view, bool is_devtools) override { // Create a new top-level Window for the popup. It will show itself after // creation. CefWindow::CreateTopLevelWindow( new SimpleWindowDelegate(popup_browser_view)); // We created the Window. return true; } private: IMPLEMENT_REFCOUNTING(SimpleBrowserViewDelegate); DISALLOW_COPY_AND_ASSIGN(SimpleBrowserViewDelegate); }; } // namespace WebviewApp::WebviewApp(CefRefPtr handler) { m_handler = handler; } WebviewApp::ProcessType WebviewApp::GetProcessType(CefRefPtr command_line) { // The command-line flag won't be specified for the browser process. if (!command_line->HasSwitch("type")) { return BrowserProcess; } const std::string& process_type = command_line->GetSwitchValue("type"); if (process_type == "renderer") return RendererProcess; #if defined(OS_LINUX) else if (process_type == "zygote") return ZygoteProcess; #endif return OtherProcess; } void WebviewApp::OnBeforeCommandLineProcessing(const CefString &process_type, CefRefPtr command_line) { // Pass additional command-line flags to the browser process. if (process_type.empty()) { #ifndef WEBVIEW_CEF_GPU_TEXTURE // The GPU shared-texture path (OnAcceleratedPaint) requires the GPU // compositor; only allow disabling the GPU when it is not compiled in. if (!m_bEnableGPU) { command_line->AppendSwitch("disable-gpu"); command_line->AppendSwitch("disable-gpu-compositing"); } #endif command_line->AppendSwitch("disable-web-security"); //disable web security command_line->AppendSwitch("allow-running-insecure-content"); //allow running insecure content in secure pages // Don't create a "GPUCache" directory when cache-path is unspecified. command_line->AppendSwitch("disable-gpu-shader-disk-cache"); //disable gpu shader disk cache command_line->AppendSwitch("no-sandbox"); //http://www.chromium.org/developers/design-documents/process-models if (m_uMode == 1) { command_line->AppendSwitch("process-per-site"); //each site in its own process command_line->AppendSwitchWithValue("renderer-process-limit", "8"); //limit renderer process count to decrease memory usage } else if (m_uMode == 2) { command_line->AppendSwitch("process-per-tab"); //each tab in its own process } else if (m_uMode == 3) { command_line->AppendSwitch("single-process"); //all in one process } command_line->AppendSwitchWithValue("autoplay-policy", "no-user-gesture-required"); //autoplay policy for media //Support cross domain requests std::string values = command_line->GetSwitchValue("disable-features"); if (values == "") { values = "SameSiteByDefaultCookies,CookiesWithoutSameSiteMustBeSecure"; } else { values += ",SameSiteByDefaultCookies,CookiesWithoutSameSiteMustBeSecure"; } if (values.find("CalculateNativeWinOcclusion") == size_t(-1)) { values += ",CalculateNativeWinOcclusion"; } command_line->AppendSwitchWithValue("disable-features", values); // JJ_MKVMaker: DNS 강제 - 모든 연결을 앱 안 프록시로 (이름은 프록시가 정한 DNS 로 풂), DNS 미리 찾기 끄기 if (!m_strProxyServer.empty()) { command_line->AppendSwitchWithValue("proxy-server", m_strProxyServer); command_line->AppendSwitch("dns-prefetch-disable"); } // JJ_MKVMaker (JJ_PATCH.md 7): 관리자 권한으로 실행 중이면 Chromium 은 권한을 낮춰 다시 띄우려고 끝난다 // (CefInitialize false, 종료 코드 38). 사용자가 설정에서 고른 때만 그대로 돈다 if (m_bDoNotDeElevate) { command_line->AppendSwitch("do-not-de-elevate"); } // for unsafe domain, add domain to whitelist if (!m_strFilterDomain.empty()) { command_line->AppendSwitch("ignore-certificate-errors"); //ignore certificate errors command_line->AppendSwitchWithValue("unsafely-treat-insecure-origin-as-secure", m_strFilterDomain); } } #ifdef __APPLE__ command_line->AppendSwitch("use-mock-keychain"); // macOS now runs multi-process via bundled CEF helper apps (see the // example Runner's "Embed CEF Helpers" phase). The process model is // selected by m_uMode above, like the other platforms. #endif #ifdef __linux__ #endif } void WebviewApp::OnContextInitialized() { CEF_REQUIRE_UI_THREAD(); // CefBrowserSettings browser_settings; // browser_settings.windowless_frame_rate = 60; // // CefWindowInfo window_info; // window_info.SetAsWindowless(0); // // // create browser // CefBrowserHost::CreateBrowser(window_info, m_handler, "", browser_settings, nullptr, nullptr); } // CefRefPtr WebviewApp::GetDefaultClient() { // // Called when a new browser window is created via the Chrome runtime UI. // return WebviewHandler::GetInstance(); // } void WebviewApp::SetUnSafelyTreatInsecureOriginAsSecure(const CefString &strFilterDomain) { m_strFilterDomain = strFilterDomain; } void WebviewApp::OnWebKitInitialized() { //inject js function for jssdk std::string extensionCode = R"( var external = {}; var clientSdk = {}; (() => { clientSdk.jsCmd = (functionName, arg1, arg2, arg3) => { if (typeof arg1 === 'function') { native function jsCmd(functionName, arg1); return jsCmd(functionName, arg1); } else if (typeof arg2 === 'function') { jsonString = arg1; if (typeof arg1 !== 'string'){ jsonString = JSON.stringify(arg1); } native function jsCmd(functionName, jsonString, arg2); return jsCmd(functionName, jsonString, arg2); } else if (typeof arg3 === 'function') { jsonString = arg1; if (typeof arg1 !== 'string'){ jsonString = JSON.stringify(arg1); } native function jsCmd(functionName, jsonString, arg2, arg3); return jsCmd(functionName, jsonString, arg2, arg3); }else { } }; external.JavaScriptChannel = (n,e,r) => { var a; null == r ? a = '' : (a = '_' + new Date + (1e3 + Math.floor(8999 * Math.random())), window[a] = function (n, e) { return function () { try { e && e.call && e.call(null, arguments[1]) } finally { delete window[n] } } }(a, r)); try { external.StartRequest(external.GetNextReqID(), n, a, JSON.stringify(e || {}), '') } catch (l) { console.log('messeage send') } } external.EvaluateCallback = (nReqID, result) => { native function EvaluateCallback(); EvaluateCallback(nReqID, result); } external.StartRequest = (nReqID, strCmd, strCallBack, strArgs, strLog) => { native function StartRequest(); StartRequest(nReqID, strCmd, strCallBack, strArgs, strLog); }; external.GetNextReqID = () => { native function GetNextReqID(); return GetNextReqID(); }; })(); )"; CefRefPtr handler = new CefJSHandler(); if (!m_render_js_bridge.get()) m_render_js_bridge.reset(new CefJSBridge); handler->AttachJSBridge(m_render_js_bridge); CefRegisterExtension("v8/extern", extensionCode, handler); } void WebviewApp::OnBrowserCreated(CefRefPtr browser, CefRefPtr extra_info) { if (!m_render_js_bridge.get()) { m_render_js_bridge.reset(new CefJSBridge); } } void WebviewApp::SetProcessMode(uint32_t uMode) { m_uMode = uMode; } void WebviewApp::SetEnableGPU(bool bEnable) { m_bEnableGPU = bEnable; } void WebviewApp::OnBeforeChildProcessLaunch(CefRefPtr command_line) { } void WebviewApp::OnBrowserDestroyed(CefRefPtr browser) { } void WebviewApp::OnContextCreated(CefRefPtr browser, CefRefPtr frame, CefRefPtr context) { } void WebviewApp::OnContextReleased(CefRefPtr browser, CefRefPtr frame, CefRefPtr context) { if (m_render_js_bridge.get()) { m_render_js_bridge->RemoveCallbackFuncWithFrame(frame); } } void WebviewApp::OnUncaughtException(CefRefPtr browser, CefRefPtr frame, CefRefPtr context, CefRefPtr exception, CefRefPtr stackTrace) { } void WebviewApp::OnFocusedNodeChanged(CefRefPtr browser, CefRefPtr frame, CefRefPtr node) { //Get node attribute bool is_editable = (node.get() && node->IsEditable()); CefRefPtr message = CefProcessMessage::Create(kFocusedNodeChangedMessage); message->GetArgumentList()->SetBool(0, is_editable); if (is_editable) { CefRect rect = node->GetElementBounds(); message->GetArgumentList()->SetInt(1, rect.x); message->GetArgumentList()->SetInt(2, rect.y + rect.height); message->GetArgumentList()->SetInt(3, rect.height); } frame->SendProcessMessage(PID_BROWSER, message); } bool WebviewApp::OnProcessMessageReceived(CefRefPtr browser, CefRefPtr frame, CefProcessId source_process, CefRefPtr message) { const CefString& message_name = message->GetName(); if (message_name == kExecuteJsCallbackMessage) { int callbackId = message->GetArgumentList()->GetInt(0); bool error = message->GetArgumentList()->GetBool(1); CefString result = message->GetArgumentList()->GetString(2); if (m_render_js_bridge.get()) { m_render_js_bridge->ExecuteJSCallbackFunc(callbackId, error, result); } } return false; }