Chromium Code Reviews| Index: headless/lib/renderer/headless_content_renderer_client.cc |
| diff --git a/headless/lib/renderer/headless_content_renderer_client.cc b/headless/lib/renderer/headless_content_renderer_client.cc |
| index 5347d6092228090a42332c32e4416f31e25080a8..9ec48df5d9346315970719d80cfeb60400594a0c 100644 |
| --- a/headless/lib/renderer/headless_content_renderer_client.cc |
| +++ b/headless/lib/renderer/headless_content_renderer_client.cc |
| @@ -4,10 +4,122 @@ |
| #include "headless/lib/renderer/headless_content_renderer_client.h" |
| +#include "base/strings/utf_string_conversions.h" |
| +#include "content/public/renderer/render_frame.h" |
| + |
| namespace headless { |
| HeadlessContentRendererClient::HeadlessContentRendererClient() {} |
| HeadlessContentRendererClient::~HeadlessContentRendererClient() {} |
| +void HeadlessContentRendererClient::RunScriptsAtDocumentStart( |
| + content::RenderFrame* render_frame) { |
| + render_frame->ExecuteJavaScript(base::UTF8ToUTF16(R"( |
| + // Shim to let code use define() instead of mojo.define() |
| + 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; |
| + }); |
| + }); |
| + moduleCache.set(name, promise); |
| + } |
| + return promise; |
| + } |
| + })(); |
| + |
| + // This code is run before the browser has sent us the mojo bindings so |
| + // we need to get fancy and use nested proxy classes to define a promise |
| + // to an arbitary window.mojo.services.myModule.myInterface. |
| + if (window.hasOwnProperty("mojo")) { |
| + let mojoBindings = new Map(); |
| + let resolvePending = true; |
| + window.mojo.services = new Proxy({}, { |
| + get: function(target, serviceName) { |
| + if (!(serviceName in target)) { |
| + var interfaceProxy = new Proxy({}, { |
| + get: function(target, interfaceName) { |
| + let name = serviceName + "::" + interfaceName; |
| + let binding = mojoBindings.get(name); |
| + if (binding === undefined) { |
| + binding = {}; |
| + binding.promise = new Promise(function(resolve, reject) { |
| + binding.resolve = resolve; |
| + binding.reject = reject; |
| + if (!resolvePending) |
| + reject(); |
| + }); |
| + mojoBindings.set(name, binding); |
| + } |
| + return binding.promise; |
| + }, |
| + set: function(target, name, value) { |
| + return false; |
| + } |
| + }); |
| + target[serviceName] = interfaceProxy; |
| + return interfaceProxy; |
| + } |
| + return target[serviceName]; |
| + }, |
| + set: function(target, name, value) { |
| + return false; |
| + } |
| + }); |
| + |
| + // Resolve promises for the listed |serviceNames|. |
| + window.mojo.resolvePromisesForService = function(serviceNames) { |
|
Eric Seckler
2016/06/14 17:50:48
I'd suggest to rename this function to ..ForServic
alex clarke (OOO till 29th)
2016/06/14 19:05:08
Makes sense, done.
|
| + let numServices = serviceNames.length; |
| + for (let i = 0; i < numServices; ++i) { |
| + let serviceName = serviceNames[i]; |
| + // Use mojo to obtain the module binding. |
| + define([ |
| + serviceName, |
| + "mojo/public/js/core", |
| + "mojo/public/js/router", |
| + "content/public/renderer/frame_service_registry", |
| + ], function(serviceMojom, mojoCore, routerModule, |
| + serviceProvider) { |
| + // A mojom binding may contain bindings for a number of intefaces. |
|
Eric Seckler
2016/06/14 17:50:48
typo (interfaces)
alex clarke (OOO till 29th)
2016/06/14 19:05:08
Done. Note to self install the spell checker on m
|
| + // Iterate through all of them and resolve any promises. |
| + for (var m in serviceMojom) { |
| + if (typeof serviceMojom[m] == "object") { |
| + let service = serviceMojom[m]; |
| + let binding = mojoBindings.get(service.name); |
| + let interface = new service.proxyClass( |
| + new routerModule.Router( |
| + serviceProvider.connectToService(service.name))); |
| + if (binding === undefined) { |
| + // Store resolved promise in case binding is requested. |
| + mojoBindings.set( |
| + service.name, {"promise": Promise.resolve(interface)}); |
| + } else { |
| + binding.resolve(interface); |
| + mojoBindings.delete(service.name); |
|
Eric Seckler
2016/06/14 17:50:48
I might be missing something, but if you delete th
alex clarke (OOO till 29th)
2016/06/14 19:05:08
Mmm yes this is a bad idea. What I really want to
|
| + } |
| + } |
| + } |
| + }); |
| + } |
| + // Reject any remaining promises. |
| + for (let [key, value] of mojoBindings) { |
| + if ("reject" in value) { |
| + value.reject(); |
| + } |
| + } |
| + // Reject any subsequent unknown properties. |
| + resolvePending = false; |
| + }; |
| + } )")); |
| +} |
| + |
| } // namespace headless |