| 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"(
|
| + // 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
|
|
|