remote/browser/RemoteBrowser.cpp (206 lines of code) (raw):

#include "RemoteBrowser.h" #include "RemoteClient.h" #include "../handlers/RemoteLifespanHandler.h" #include "../router/MessageRoutersManager.h" #include "../handlers/RemoteClientHandler.h" #include "include/base/cef_callback.h" #include "include/cef_app.h" #include "include/cef_task.h" #include "include/wrapper/cef_closure_task.h" #include "include/cef_browser.h" std::mutex RemoteBrowser::ourBid2BrowserMutex; std::map<int, std::shared_ptr<RemoteBrowser>> RemoteBrowser::ourBid2Browser; std::mutex RemoteBrowser::ourCef2RemoteMutex; std::map<int, std::shared_ptr<RemoteBrowser>> RemoteBrowser::ourCef2Remote; RemoteBrowser::RemoteBrowser(int bid, std::shared_ptr<RemoteClient> owner, CefRefPtr<CefRequestContext> requestContext) : myBid(bid), myOwner(owner), myRequestContext(requestContext) { } std::shared_ptr<RemoteBrowser> RemoteBrowser::create(std::shared_ptr<RemoteClient> owner, CefRefPtr<CefRequestContext> requestContext) { std::shared_ptr<RemoteBrowser> result; { std::unique_lock lock(ourBid2BrowserMutex); static int sBid = 0; int bid = sBid++; ourBid2Browser[bid] = result = std::make_shared<RemoteBrowser>(bid, owner, requestContext); } return result; } int RemoteBrowser::getCid() const { return myOwner->getCid(); } CefRefPtr<CefRequestContext> RemoteBrowser::getRequestContext() const { return myRequestContext; } CefRefPtr<CefBrowser> RemoteBrowser::getCefBrowser() const { return myCefBrowser; } void RemoteBrowser::setCefBrowser(CefRefPtr<CefBrowser> browser) { myCefBrowser = browser; } void RemoteBrowser::linkCefBrowser(CefRefPtr<CefBrowser> browser, std::shared_ptr<RemoteBrowser> remoteBrowser) { std::unique_lock lock(ourCef2RemoteMutex); ourCef2Remote[browser->GetIdentifier()] = remoteBrowser; } void RemoteBrowser::unlinkCefBrowser(CefRefPtr<CefBrowser> browser) { std::unique_lock lock(ourCef2RemoteMutex); ourCef2Remote.erase(browser->GetIdentifier()); } std::shared_ptr<RemoteBrowser> RemoteBrowser::findByCefBrowser(CefRefPtr<CefBrowser> browser) { if (!browser) return nullptr; std::unique_lock lock(ourCef2RemoteMutex); auto i = ourCef2Remote.find(browser->GetIdentifier()); return i == ourCef2Remote.end() ? nullptr : i->second; } namespace { CefRefPtr<CefListValue> GetAllMessageRouterConfigs(); // Should be called on UI thread void createCefBrowserImpl( int cid, int bid, CefRefPtr<RemoteClientHandler> clienthandler, CefRefPtr<CefRequestContext> requestContext, std::string url, std::function<void(int)> onCreationFailed ) { CefBrowserSettings settings; // TODO: get real CefBrowserSettings from java CefWindowInfo windowInfo; windowInfo.SetAsWindowless(0); // JCEF requires Alloy runtime style for "normal" browsers in order for them // to be integratable into Java UI. windowInfo.runtime_style = CEF_RUNTIME_STYLE_ALLOY; CefRefPtr<CefDictionaryValue> extra_info; auto router_configs = GetAllMessageRouterConfigs(); if (router_configs) { // Send the message router config to CefHelperApp::OnBrowserCreated. extra_info = CefDictionaryValue::Create(); extra_info->SetList("router_configs", router_configs); } RemoteLifespanHandler* lsh = (RemoteLifespanHandler*)clienthandler->GetLifeSpanHandler().get(); lsh->addCreating(bid); //Log::trace( "CefBrowserHost::CreateBrowser cid=%d, bid=%d", cid, bid); bool result = CefBrowserHost::CreateBrowser(windowInfo, clienthandler, url, settings, extra_info, requestContext); if (!result) { Log::error( "Failed to create browser with cid=%d, bid=%d", cid, bid); lsh->removeCreating(bid); onCreationFailed(bid); } } // Should be called on UI thread void openDevToolsPopupImpl( int bid, CefRefPtr<CefBrowser> parentBrowser, CefPoint inspectAt ) { if (!parentBrowser) return; Log::trace( "ShowDevTools: bid=%d, pt=(%d,%d)", bid, inspectAt.x, inspectAt.y); CefWindowInfo windowInfo; CefBrowserSettings settings; // TODO: get real CefBrowserSettings from java parentBrowser->GetHost()->ShowDevTools(windowInfo, nullptr, settings, inspectAt); } } void RemoteBrowser::startNativeBrowserCreation(const std::string & url) { std::function remove = [=](int bid){ myOwner->eraseBrowser(bid); std::unique_lock lock(ourBid2BrowserMutex); ourBid2Browser.erase(bid); }; if (CefCurrentlyOn(TID_UI)) { createCefBrowserImpl(getCid(), myBid, myOwner->myRemoteClientHandler, myRequestContext, url, remove); } else { CefPostTask(TID_UI, base::BindOnce(&createCefBrowserImpl, getCid(), myBid, myOwner->myRemoteClientHandler, myRequestContext, url, remove)); } } void RemoteBrowser::openDevTools(int x, int y) { if (!myCefBrowser) { Log::error("Can't open dev-tools for bid=%d, because native CefBrowser wasn't created yet.", myBid); return; } if (CefCurrentlyOn(TID_UI)) { openDevToolsPopupImpl(myBid, myCefBrowser, CefPoint(x, y)); } else { CefPostTask(TID_UI, base::BindOnce(&openDevToolsPopupImpl, myBid, myCefBrowser, CefPoint(x, y))); } } void RemoteBrowser::close() { if (myIsClosing) return; //Log::trace("Scheduled closing native browser, bid=%d", myBid); myIsClosing = true; if (myCefBrowser != nullptr) myCefBrowser->GetHost()->CloseBrowser(true); } std::shared_ptr<RemoteBrowser> RemoteBrowser::find(int bid) { std::unique_lock lock(ourBid2BrowserMutex); const auto & i = ourBid2Browser.find(bid); return i == ourBid2Browser.end() ? nullptr : i->second; } std::vector<int> RemoteBrowser::enumAllBrowsers() { std::unique_lock lock(ourBid2BrowserMutex); std::vector<int> result; for (auto const& rc : ourBid2Browser) { std::shared_ptr<RemoteBrowser> b = rc.second; if (b) result.push_back(b->getBid()); } return result; } unsigned int RemoteBrowser::getAllBrowsersCount() { std::unique_lock lock(ourBid2BrowserMutex); return (unsigned int)ourBid2Browser.size(); } bool RemoteBrowser::closeAllBrowsers() { bool isEmpty = true; std::unique_lock lock(ourBid2BrowserMutex); for (auto const& rc : ourBid2Browser) { std::shared_ptr<RemoteBrowser> b = rc.second; if (b) { b->close(); isEmpty = false; } } return isEmpty; } void RemoteBrowser::onBeforeClose() { myCefBrowser = nullptr; myOwner->eraseBrowser(myBid); // Remove the link from a static map std::unique_lock lock(ourBid2BrowserMutex); ourBid2Browser.erase(myBid); } std::string RemoteBrowser::getDebugInfo(int tabs) { std::stringstream ss; for (int i = 0; i < tabs; ++i) ss << "\t"; if (myIsClosing) ss << "Closing, bid=" << myBid; else ss << "Active, bid=" << myBid; if (myRequestContext) ss << ", RequestContext=" << myRequestContext.get(); ss << std::endl; return ss.str(); } namespace { // comparator to check if configuration values are the same struct cmpCfg { bool operator()(const CefMessageRouterConfig& lValue, const CefMessageRouterConfig& rValue) const { std::less<std::string> comp; return comp(lValue.js_query_function.ToString(), rValue.js_query_function.ToString()); } }; std::set<CefMessageRouterConfig, cmpCfg> router_cfg_; base::Lock router_cfg_lock_; CefRefPtr<CefListValue> GetAllMessageRouterConfigs() { int idx = 0; static std::set<CefMessageRouterConfig, cmpCfg>::iterator iter; base::AutoLock lock_scope(router_cfg_lock_); if (router_cfg_.empty()) return nullptr; // Configuration pased to CefHelperApp::OnBrowserCreated. auto router_configs = CefListValue::Create(); for (iter = router_cfg_.begin(); iter != router_cfg_.end(); ++iter) { CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create(); dict->SetString("js_query_function", iter->js_query_function); dict->SetString("js_cancel_function", iter->js_cancel_function); router_configs->SetDictionary(idx, dict); idx++; } return router_configs; } } // static void RemoteBrowser::AddMessageRouterConfig(const CefMessageRouterConfig& cfg) { base::AutoLock lock_scope(router_cfg_lock_); router_cfg_.insert(cfg); } // static void RemoteBrowser::RemoveMessageRouterConfig(const CefMessageRouterConfig& cfg) { base::AutoLock lock_scope(router_cfg_lock_); router_cfg_.erase(cfg); }