Index: headless/lib/browser/headless_web_contents_impl.cc |
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc |
index 96c90ae99dadcb266392a12af636e1b76b2faabc..a675205394a58a40ad60c9b845b54bfc9f447e82 100644 |
--- a/headless/lib/browser/headless_web_contents_impl.cc |
+++ b/headless/lib/browser/headless_web_contents_impl.cc |
@@ -7,6 +7,7 @@ |
#include "base/bind.h" |
#include "base/memory/ptr_util.h" |
#include "base/memory/weak_ptr.h" |
+#include "base/strings/utf_string_conversions.h" |
#include "base/trace_event/trace_event.h" |
#include "content/public/browser/devtools_agent_host.h" |
#include "content/public/browser/navigation_handle.h" |
@@ -79,6 +80,7 @@ std::unique_ptr<HeadlessWebContentsImpl> HeadlessWebContentsImpl::Create( |
base::WrapUnique(new HeadlessWebContentsImpl( |
content::WebContents::Create(create_params), browser)); |
+ headless_web_contents->InstallMojoServices(builder->embedder_mojo_services_); |
headless_web_contents->InitializeScreen(parent_window, builder->window_size_); |
if (!headless_web_contents->OpenURL(builder->initial_url_)) |
return nullptr; |
@@ -110,10 +112,65 @@ void HeadlessWebContentsImpl::InitializeScreen(aura::Window* parent_window, |
host_view->SetSize(initial_size); |
} |
+void HeadlessWebContentsImpl::InstallMojoServices( |
+ std::list<EmbedderMojoService>& embedder_mojo_services) { |
+ embedder_mojo_services_ = std::move(embedder_mojo_services); |
+ |
+ if (embedder_mojo_services_.empty()) |
+ return; |
+ |
+ web_contents_->GetRenderViewHost()->AllowBindings( |
+ content::BINDINGS_POLICY_MOJO); |
+ content::ServiceRegistry* service_registry = |
+ web_contents_->GetRenderViewHost()->GetMainFrame()->GetServiceRegistry(); |
+ |
+ for (const EmbedderMojoService& service : embedder_mojo_services_) { |
+ service_registry->AddService(service.service_name, |
+ std::move(service.service_factory), |
+ browser_->BrowserMainThread()); |
+ } |
+} |
+ |
+void HeadlessWebContentsImpl::DocumentOnLoadCompletedInMainFrame() { |
Sami
2016/06/10 10:27:38
Is there an earlier event we could use? It might b
alex clarke (OOO till 29th)
2016/06/11 20:51:50
I've refactored this to:
1. Install the mojo.def
|
+ if (embedder_mojo_services_.empty()) |
+ return; |
+ |
+ // content::BINDINGS_POLICY_MOJO causes 'mojo.define' to be installed in the |
+ // global v8 context. However the autogenerated mojo bindings assume 'define' |
+ // is installed. We run some JS here to implement the expected 'define' |
+ // method. |
+ content::RenderFrameHost* render_frame_host = web_contents_->GetMainFrame(); |
+ render_frame_host->ExecuteJavaScriptForTests(base::UTF8ToUTF16(R"( |
Sami
2016/06/10 10:27:38
Was there a non-test interface we could use for th
alex clarke (OOO till 29th)
2016/06/11 20:51:50
Yes. this has been moved.
|
+ window.define = (function() { |
+ let moduleCache = new Map(); |
+ return function(name, deps, factory) { |
+ let promise = moduleCache.get(name); |
+ if (promise === undefined) { |
+ // This promise must be cached as mojo.define will only call the |
+ // factory function the first time the module is defined. |
+ promise = new Promise(resolve => { |
+ mojo.define(name, deps, (...modules) => { |
+ let result = factory(...modules); |
+ resolve(result); |
+ return result; |
Sami
2016/06/10 10:27:38
Do you need both resolve and return?
alex clarke (OOO till 29th)
2016/06/11 20:51:50
Apparently the resolve isn't needed?!
|
+ }); |
+ }); |
+ moduleCache.set(name, promise); |
+ } |
+ return promise; |
+ } |
+ })(); )")); |
+ |
+ for (const EmbedderMojoService& service : embedder_mojo_services_) { |
+ render_frame_host->ExecuteJavaScript(base::UTF8ToUTF16(service.js_binding)); |
+ } |
+} |
+ |
HeadlessWebContentsImpl::HeadlessWebContentsImpl( |
content::WebContents* web_contents, |
HeadlessBrowserImpl* browser) |
- : web_contents_delegate_(new HeadlessWebContentsImpl::Delegate(browser)), |
+ : content::WebContentsObserver(web_contents), |
+ web_contents_delegate_(new HeadlessWebContentsImpl::Delegate(browser)), |
web_contents_(web_contents), |
browser_(browser) { |
web_contents_->SetDelegate(web_contents_delegate_.get()); |
@@ -196,8 +253,30 @@ HeadlessWebContents::Builder& HeadlessWebContents::Builder::SetBrowserContext( |
return *this; |
} |
+HeadlessWebContents::Builder& |
+HeadlessWebContents::Builder::AddEmbedderMojoService( |
+ const std::string& service_name, |
+ const base::Callback<void(mojo::ScopedMessagePipeHandle)>& service_factory, |
+ const std::string& js_binding) { |
+ embedder_mojo_services_.emplace_back(service_name, service_factory, |
+ js_binding); |
+ return *this; |
+} |
+ |
HeadlessWebContents* HeadlessWebContents::Builder::Build() { |
return browser_->CreateWebContents(this); |
} |
+HeadlessWebContents::Builder::EmbedderMojoService::EmbedderMojoService() {} |
+ |
+HeadlessWebContents::Builder::EmbedderMojoService::EmbedderMojoService( |
+ const std::string& service_name, |
+ const base::Callback<void(mojo::ScopedMessagePipeHandle)>& service_factory, |
+ const std::string& js_binding) |
+ : service_name(service_name), |
+ service_factory(service_factory), |
+ js_binding(js_binding) {} |
+ |
+HeadlessWebContents::Builder::EmbedderMojoService::~EmbedderMojoService() {} |
+ |
} // namespace headless |