Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / renderer / resources / extensions / runtime_custom_bindings.js
blobadd47ccc06e5e10075510a1e91b8293e8473da23
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Custom binding for the runtime API.
7 var binding = require('binding').Binding.create('runtime');
9 var messaging = require('messaging');
10 var runtimeNatives = requireNative('runtime');
11 var unloadEvent = require('unload_event');
12 var process = requireNative('process');
13 var forEach = require('utils').forEach;
15 var backgroundPage = window;
16 var backgroundRequire = require;
17 var contextType = process.GetContextType();
18 if (contextType == 'BLESSED_EXTENSION' ||
19     contextType == 'UNBLESSED_EXTENSION') {
20   var manifest = runtimeNatives.GetManifest();
21   if (manifest.app && manifest.app.background) {
22     // Get the background page if one exists. Otherwise, default to the current
23     // window.
24     backgroundPage = runtimeNatives.GetExtensionViews(-1, 'BACKGROUND')[0];
25     if (backgroundPage) {
26       var GetModuleSystem = requireNative('v8_context').GetModuleSystem;
27       backgroundRequire = GetModuleSystem(backgroundPage).require;
28     } else {
29       backgroundPage = window;
30     }
31   }
34 // For packaged apps, all windows use the bindFileEntryCallback from the
35 // background page so their FileEntry objects have the background page's context
36 // as their own.  This allows them to be used from other windows (including the
37 // background page) after the original window is closed.
38 if (window == backgroundPage) {
39   var lastError = require('lastError');
40   var fileSystemNatives = requireNative('file_system_natives');
41   var GetIsolatedFileSystem = fileSystemNatives.GetIsolatedFileSystem;
42   var bindDirectoryEntryCallback = function(functionName, apiFunctions) {
43     apiFunctions.setCustomCallback(functionName,
44         function(name, request, response) {
45       if (request.callback && response) {
46         var callback = request.callback;
47         request.callback = null;
49         var fileSystemId = response.fileSystemId;
50         var baseName = response.baseName;
51         var fs = GetIsolatedFileSystem(fileSystemId);
53         try {
54           fs.root.getDirectory(baseName, {}, callback, function(fileError) {
55             lastError.run('runtime.' + functionName,
56                           'Error getting Entry, code: ' + fileError.code,
57                           request.stack,
58                           callback);
59           });
60         } catch (e) {
61           lastError.run('runtime.' + functionName,
62                         'Error: ' + e.stack,
63                         request.stack,
64                         callback);
65         }
66       }
67     });
68   };
69 } else {
70   // Force the runtime API to be loaded in the background page. Using
71   // backgroundPageModuleSystem.require('runtime') is insufficient as
72   // requireNative is only allowed while lazily loading an API.
73   backgroundPage.chrome.runtime;
74   var bindDirectoryEntryCallback = backgroundRequire(
75       'runtime').bindDirectoryEntryCallback;
78 binding.registerCustomHook(function(binding, id, contextType) {
79   var apiFunctions = binding.apiFunctions;
80   var runtime = binding.compiledApi;
82   //
83   // Unprivileged APIs.
84   //
86   runtime.id = id;
88   apiFunctions.setHandleRequest('getManifest', function() {
89     return runtimeNatives.GetManifest();
90   });
92   apiFunctions.setHandleRequest('getURL', function(path) {
93     path = String(path);
94     if (!path.length || path[0] != '/')
95       path = '/' + path;
96     return 'chrome-extension://' + id + path;
97   });
99   var sendMessageUpdateArguments = messaging.sendMessageUpdateArguments;
100   apiFunctions.setUpdateArgumentsPreValidate('sendMessage',
101       $Function.bind(sendMessageUpdateArguments, null, 'sendMessage',
102                      true /* hasOptionsArgument */));
103   apiFunctions.setUpdateArgumentsPreValidate('sendNativeMessage',
104       $Function.bind(sendMessageUpdateArguments, null, 'sendNativeMessage',
105                      false /* hasOptionsArgument */));
107   apiFunctions.setHandleRequest('sendMessage',
108       function(targetId, message, options, responseCallback) {
109     var connectOptions = {name: messaging.kMessageChannel};
110     forEach(options, function(k, v) {
111       connectOptions[k] = v;
112     });
113     var port = runtime.connect(targetId || runtime.id, connectOptions);
114     messaging.sendMessageImpl(port, message, responseCallback);
115   });
117   apiFunctions.setHandleRequest('sendNativeMessage',
118                                 function(targetId, message, responseCallback) {
119     var port = runtime.connectNative(targetId);
120     messaging.sendMessageImpl(port, message, responseCallback);
121   });
123   apiFunctions.setUpdateArgumentsPreValidate('connect', function() {
124     // Align missing (optional) function arguments with the arguments that
125     // schema validation is expecting, e.g.
126     //   runtime.connect()   -> runtime.connect(null, null)
127     //   runtime.connect({}) -> runtime.connect(null, {})
128     var nextArg = 0;
130     // targetId (first argument) is optional.
131     var targetId = null;
132     if (typeof(arguments[nextArg]) == 'string')
133       targetId = arguments[nextArg++];
135     // connectInfo (second argument) is optional.
136     var connectInfo = null;
137     if (typeof(arguments[nextArg]) == 'object')
138       connectInfo = arguments[nextArg++];
140     if (nextArg != arguments.length)
141       throw new Error('Invalid arguments to connect.');
142     return [targetId, connectInfo];
143   });
145   apiFunctions.setUpdateArgumentsPreValidate('connectNative',
146                                              function(appName) {
147     if (typeof(appName) !== 'string') {
148       throw new Error('Invalid arguments to connectNative.');
149     }
150     return [appName];
151   });
153   apiFunctions.setHandleRequest('connect', function(targetId, connectInfo) {
154     // Don't let orphaned content scripts communicate with their extension.
155     // http://crbug.com/168263
156     if (unloadEvent.wasDispatched)
157       throw new Error('Error connecting to extension ' + targetId);
159     if (!targetId)
160       targetId = runtime.id;
162     var name = '';
163     if (connectInfo && connectInfo.name)
164       name = connectInfo.name;
166     var includeTlsChannelId =
167       !!(connectInfo && connectInfo.includeTlsChannelId);
169     var portId = runtimeNatives.OpenChannelToExtension(targetId, name,
170                                                        includeTlsChannelId);
171     if (portId >= 0)
172       return messaging.createPort(portId, name);
173   });
175   //
176   // Privileged APIs.
177   //
178   if (contextType != 'BLESSED_EXTENSION')
179     return;
181   apiFunctions.setHandleRequest('connectNative',
182                                 function(nativeAppName) {
183     if (!unloadEvent.wasDispatched) {
184       var portId = runtimeNatives.OpenChannelToNativeApp(runtime.id,
185                                                          nativeAppName);
186       if (portId >= 0)
187         return messaging.createPort(portId, '');
188     }
189     throw new Error('Error connecting to native app: ' + nativeAppName);
190   });
192   apiFunctions.setCustomCallback('getBackgroundPage',
193                                  function(name, request, response) {
194     if (request.callback) {
195       var bg = runtimeNatives.GetExtensionViews(-1, 'BACKGROUND')[0] || null;
196       request.callback(bg);
197     }
198     request.callback = null;
199   });
201   bindDirectoryEntryCallback('getPackageDirectoryEntry', apiFunctions);
204 exports.bindDirectoryEntryCallback = bindDirectoryEntryCallback;
205 exports.binding = binding.generate();