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..ce98c4ecc4caa5191add7024f430572472c0b8e0 100644 |
| --- a/headless/lib/renderer/headless_content_renderer_client.cc |
| +++ b/headless/lib/renderer/headless_content_renderer_client.cc |
| @@ -4,10 +4,134 @@ |
| #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"( |
|
dcheng
2016/06/21 14:52:10
Raw string literals are still banned AFAIK.
alex clarke (OOO till 29th)
2016/06/21 16:15:17
Ah so they are :/ I got confused because they are
|
| + // 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); |
| + 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; |
| + |
| + // Factory for returning the second level dynamic property which |
| + // resolves to a promise to the corresponding mojo interface... |
| + let interfaceProxyFactory = function(serviceName) { |
| + return 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) { |
| + throw new Error( |
| + 'Assignment to the mojo services proxy is not allowed'); |
| + } |
| + }); |
| + }; |
| + |
| + // Top level dynamic property. |
| + window.mojo.services = new Proxy({}, { |
| + get: function(target, serviceName) { |
| + if (!(serviceName in target)) { |
| + let interfaceProxy = interfaceProxyFactory(serviceName); |
| + target[serviceName] = interfaceProxy; |
| + return interfaceProxy; |
| + } |
| + return target[serviceName]; |
| + }, |
| + set: function(target, name, value) { |
| + throw new Error( |
| + 'Assignment to the mojo services proxy is not allowed'); |
| + } |
| + }); |
| + |
| + // Resolve promises for the listed |serviceNames|. |
| + window.mojo.resolvePromisesForServices_ = function(serviceNames) { |
| + 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 |
| + // interfaces. Iterate through all of them and resolve any |
| + // promises. |
| + for (let 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); |
| + // Since this promise has been resolved we don't want to try |
| + // and reject it below! |
| + delete binding.reject; |
| + } |
| + } |
| + } |
| + }); |
| + } |
| + // Reject any remaining promises that didn't get resolved. |
| + for (let [key, value] of mojoBindings) { |
| + if ("reject" in value) { |
| + value.reject(); |
| + } |
| + } |
| + // Reject any subsequent unknown properties. |
| + resolvePending = false; |
| + }; |
| + } )")); |
| +} |
| + |
| } // namespace headless |