Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(429)

Unified Diff: headless/lib/renderer/headless_content_renderer_client.cc

Issue 2049363003: Adds support for headless chrome embedder mojo services (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix a bug with mojo bindings after the onload event fired. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698