Index: chrome/renderer/resources/extensions/extension_process_bindings.js |
diff --git a/chrome/renderer/resources/extensions/extension_process_bindings.js b/chrome/renderer/resources/extensions/extension_process_bindings.js |
deleted file mode 100644 |
index 96db3680440ac2be55915a2ea65468198c0fe7c2..0000000000000000000000000000000000000000 |
--- a/chrome/renderer/resources/extensions/extension_process_bindings.js |
+++ /dev/null |
@@ -1,1058 +0,0 @@ |
-// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-// This script contains privileged chrome extension related javascript APIs. |
-// It is loaded by pages whose URL has the chrome-extension protocol. |
- |
-var chrome = chrome || {}; |
-(function() { |
- native function GetExtensionAPIDefinition(); |
- native function StartRequest(); |
- native function GetChromeHidden(); |
- native function GetNextRequestId(); |
- native function Print(); |
- |
- native function GetCurrentPageActions(extensionId); |
- native function GetExtensionViews(); |
- native function GetNextContextMenuId(); |
- native function GetNextTtsEventId(); |
- native function OpenChannelToTab(); |
- native function GetRenderViewId(); |
- native function SetIconCommon(); |
- native function GetUniqueSubEventName(eventName); |
- native function GetLocalFileSystem(name, path); |
- native function DecodeJPEG(jpegImage); |
- native function CreateBlob(filePath); |
- |
- var chromeHidden = GetChromeHidden(); |
- |
- if (!chrome) |
- chrome = {}; |
- |
- function forEach(dict, f) { |
- for (key in dict) { |
- if (dict.hasOwnProperty(key)) |
- f(key, dict[key]); |
- } |
- } |
- |
- // Validate arguments. |
- chromeHidden.validationTypes = []; |
- chromeHidden.validate = function(args, schemas) { |
- if (args.length > schemas.length) |
- throw new Error("Too many arguments."); |
- |
- for (var i = 0; i < schemas.length; i++) { |
- if (i in args && args[i] !== null && args[i] !== undefined) { |
- var validator = new chromeHidden.JSONSchemaValidator(); |
- validator.addTypes(chromeHidden.validationTypes); |
- validator.validate(args[i], schemas[i]); |
- if (validator.errors.length == 0) |
- continue; |
- |
- var message = "Invalid value for argument " + (i + 1) + ". "; |
- for (var i = 0, err; err = validator.errors[i]; i++) { |
- if (err.path) { |
- message += "Property '" + err.path + "': "; |
- } |
- message += err.message; |
- message = message.substring(0, message.length - 1); |
- message += ", "; |
- } |
- message = message.substring(0, message.length - 2); |
- message += "."; |
- |
- throw new Error(message); |
- } else if (!schemas[i].optional) { |
- throw new Error("Parameter " + (i + 1) + " is required."); |
- } |
- } |
- }; |
- |
- // Callback handling. |
- var requests = []; |
- chromeHidden.handleResponse = function(requestId, name, |
- success, response, error) { |
- try { |
- var request = requests[requestId]; |
- if (success) { |
- delete chrome.extension.lastError; |
- } else { |
- if (!error) { |
- error = "Unknown error."; |
- } |
- console.error("Error during " + name + ": " + error); |
- chrome.extension.lastError = { |
- "message": error |
- }; |
- } |
- |
- if (request.customCallback) { |
- request.customCallback(name, request, response); |
- } |
- |
- if (request.callback) { |
- // Callbacks currently only support one callback argument. |
- var callbackArgs = response ? [chromeHidden.JSON.parse(response)] : []; |
- |
- // Validate callback in debug only -- and only when the |
- // caller has provided a callback. Implementations of api |
- // calls my not return data if they observe the caller |
- // has not provided a callback. |
- if (chromeHidden.validateCallbacks && !error) { |
- try { |
- if (!request.callbackSchema.parameters) { |
- throw "No callback schemas defined"; |
- } |
- |
- if (request.callbackSchema.parameters.length > 1) { |
- throw "Callbacks may only define one parameter"; |
- } |
- |
- chromeHidden.validate(callbackArgs, |
- request.callbackSchema.parameters); |
- } catch (exception) { |
- return "Callback validation error during " + name + " -- " + |
- exception.stack; |
- } |
- } |
- |
- if (response) { |
- request.callback(callbackArgs[0]); |
- } else { |
- request.callback(); |
- } |
- } |
- } finally { |
- delete requests[requestId]; |
- delete chrome.extension.lastError; |
- } |
- |
- return undefined; |
- }; |
- |
- function prepareRequest(args, argSchemas) { |
- var request = {}; |
- var argCount = args.length; |
- |
- // Look for callback param. |
- if (argSchemas.length > 0 && |
- args.length == argSchemas.length && |
- argSchemas[argSchemas.length - 1].type == "function") { |
- request.callback = args[argSchemas.length - 1]; |
- request.callbackSchema = argSchemas[argSchemas.length - 1]; |
- --argCount; |
- } |
- |
- request.args = []; |
- for (var k = 0; k < argCount; k++) { |
- request.args[k] = args[k]; |
- } |
- |
- return request; |
- } |
- |
- // Send an API request and optionally register a callback. |
- // |opt_args| is an object with optional parameters as follows: |
- // - noStringify: true if we should not stringify the request arguments. |
- // - customCallback: a callback that should be called instead of the standard |
- // callback. |
- // - nativeFunction: the v8 native function to handle the request, or |
- // StartRequest if missing. |
- // - forIOThread: true if this function should be handled on the browser IO |
- // thread. |
- function sendRequest(functionName, args, argSchemas, opt_args) { |
- if (!opt_args) |
- opt_args = {}; |
- var request = prepareRequest(args, argSchemas); |
- if (opt_args.customCallback) { |
- request.customCallback = opt_args.customCallback; |
- } |
- // JSON.stringify doesn't support a root object which is undefined. |
- if (request.args === undefined) |
- request.args = null; |
- |
- var sargs = opt_args.noStringify ? |
- request.args : chromeHidden.JSON.stringify(request.args); |
- var nativeFunction = opt_args.nativeFunction || StartRequest; |
- |
- var requestId = GetNextRequestId(); |
- requests[requestId] = request; |
- var hasCallback = |
- (request.callback || opt_args.customCallback) ? true : false; |
- return nativeFunction(functionName, sargs, requestId, hasCallback, |
- opt_args.forIOThread); |
- } |
- |
- // --- Setup additional api's not currently handled in common/extensions/api |
- |
- // WebRequestEvent object. This is used for special webRequest events with |
- // extra parameters. Each invocation of addListener creates a new named |
- // sub-event. That sub-event is associated with the extra parameters in the |
- // browser process, so that only it is dispatched when the main event occurs |
- // matching the extra parameters. |
- // |
- // Example: |
- // chrome.webRequest.onBeforeRequest.addListener( |
- // callback, {urls: "http://*.google.com/*"}); |
- // ^ callback will only be called for onBeforeRequests matching the filter. |
- chrome.WebRequestEvent = |
- function(eventName, opt_argSchemas, opt_extraArgSchemas) { |
- if (typeof eventName != "string") |
- throw new Error("chrome.WebRequestEvent requires an event name."); |
- |
- this.eventName_ = eventName; |
- this.argSchemas_ = opt_argSchemas; |
- this.extraArgSchemas_ = opt_extraArgSchemas; |
- this.subEvents_ = []; |
- }; |
- |
- // Test if the given callback is registered for this event. |
- chrome.WebRequestEvent.prototype.hasListener = function(cb) { |
- return this.findListener_(cb) > -1; |
- }; |
- |
- // Test if any callbacks are registered fur thus event. |
- chrome.WebRequestEvent.prototype.hasListeners = function(cb) { |
- return this.subEvents_.length > 0; |
- }; |
- |
- // Registers a callback to be called when this event is dispatched. If |
- // opt_filter is specified, then the callback is only called for events that |
- // match the given filters. If opt_extraInfo is specified, the given optional |
- // info is sent to the callback. |
- chrome.WebRequestEvent.prototype.addListener = |
- function(cb, opt_filter, opt_extraInfo) { |
- var subEventName = GetUniqueSubEventName(this.eventName_); |
- // Note: this could fail to validate, in which case we would not add the |
- // subEvent listener. |
- chromeHidden.validate(Array.prototype.slice.call(arguments, 1), |
- this.extraArgSchemas_); |
- chrome.experimental.webRequest.addEventListener( |
- cb, opt_filter, opt_extraInfo, this.eventName_, subEventName); |
- |
- var subEvent = new chrome.Event(subEventName, this.argSchemas_); |
- var subEventCallback = cb; |
- if (opt_extraInfo && opt_extraInfo.indexOf("blocking") >= 0) { |
- var eventName = this.eventName_; |
- subEventCallback = function() { |
- var requestId = arguments[0].requestId; |
- try { |
- var result = cb.apply(null, arguments); |
- chrome.experimental.webRequest.eventHandled( |
- eventName, subEventName, requestId, result); |
- } catch (e) { |
- chrome.experimental.webRequest.eventHandled( |
- eventName, subEventName, requestId); |
- throw e; |
- } |
- }; |
- } else if (opt_extraInfo && opt_extraInfo.indexOf("asyncBlocking") >= 0) { |
- var eventName = this.eventName_; |
- subEventCallback = function() { |
- var details = arguments[0]; |
- var requestId = details.requestId; |
- var handledCallback = function(response) { |
- chrome.experimental.webRequest.eventHandled( |
- eventName, subEventName, requestId, response); |
- }; |
- cb.apply(null, [details, handledCallback]); |
- }; |
- } |
- this.subEvents_.push( |
- {subEvent: subEvent, callback: cb, subEventCallback: subEventCallback}); |
- subEvent.addListener(subEventCallback); |
- }; |
- |
- // Unregisters a callback. |
- chrome.WebRequestEvent.prototype.removeListener = function(cb) { |
- var idx = this.findListener_(cb); |
- if (idx < 0) { |
- return; |
- } |
- |
- var e = this.subEvents_[idx]; |
- e.subEvent.removeListener(e.subEventCallback); |
- if (e.subEvent.hasListeners()) { |
- console.error( |
- "Internal error: webRequest subEvent has orphaned listeners."); |
- } |
- this.subEvents_.splice(idx, 1); |
- }; |
- |
- chrome.WebRequestEvent.prototype.findListener_ = function(cb) { |
- for (var i in this.subEvents_) { |
- var e = this.subEvents_[i]; |
- if (e.callback === cb) { |
- if (e.subEvent.findListener_(e.subEventCallback) > -1) |
- return i; |
- console.error("Internal error: webRequest subEvent has no callback."); |
- } |
- } |
- |
- return -1; |
- }; |
- |
- function CustomBindingsObject() { |
- } |
- CustomBindingsObject.prototype.setSchema = function(schema) { |
- // The functions in the schema are in list form, so we move them into a |
- // dictionary for easier access. |
- var self = this; |
- self.parameters = {}; |
- schema.functions.forEach(function(f) { |
- self.parameters[f.name] = f.parameters; |
- }); |
- }; |
- |
- function extendSchema(schema) { |
- var extendedSchema = schema.slice(); |
- extendedSchema.unshift({'type': 'string'}); |
- return extendedSchema; |
- } |
- |
- var customBindings = {}; |
- |
- function setupChromeSetting() { |
- function ChromeSetting(prefKey, valueSchema) { |
- this.get = function(details, callback) { |
- var getSchema = this.parameters.get; |
- chromeHidden.validate([details, callback], getSchema); |
- return sendRequest('types.ChromeSetting.get', |
- [prefKey, details, callback], |
- extendSchema(getSchema)); |
- }; |
- this.set = function(details, callback) { |
- var setSchema = this.parameters.set.slice(); |
- setSchema[0].properties.value = valueSchema; |
- chromeHidden.validate([details, callback], setSchema); |
- return sendRequest('types.ChromeSetting.set', |
- [prefKey, details, callback], |
- extendSchema(setSchema)); |
- }; |
- this.clear = function(details, callback) { |
- var clearSchema = this.parameters.clear; |
- chromeHidden.validate([details, callback], clearSchema); |
- return sendRequest('types.ChromeSetting.clear', |
- [prefKey, details, callback], |
- extendSchema(clearSchema)); |
- }; |
- this.onChange = new chrome.Event('types.ChromeSetting.' + prefKey + |
- '.onChange'); |
- }; |
- ChromeSetting.prototype = new CustomBindingsObject(); |
- customBindings['ChromeSetting'] = ChromeSetting; |
- } |
- |
- function setupContentSetting() { |
- function ContentSetting(contentType, settingSchema) { |
- this.get = function(details, callback) { |
- var getSchema = this.parameters.get; |
- chromeHidden.validate([details, callback], getSchema); |
- return sendRequest('contentSettings.get', |
- [contentType, details, callback], |
- extendSchema(getSchema)); |
- }; |
- this.set = function(details, callback) { |
- var setSchema = this.parameters.set.slice(); |
- setSchema[0].properties.setting = settingSchema; |
- chromeHidden.validate([details, callback], setSchema); |
- return sendRequest('contentSettings.set', |
- [contentType, details, callback], |
- extendSchema(setSchema)); |
- }; |
- this.clear = function(details, callback) { |
- var clearSchema = this.parameters.clear; |
- chromeHidden.validate([details, callback], clearSchema); |
- return sendRequest('contentSettings.clear', |
- [contentType, details, callback], |
- extendSchema(clearSchema)); |
- }; |
- this.getResourceIdentifiers = function(callback) { |
- var schema = this.parameters.getResourceIdentifiers; |
- chromeHidden.validate([callback], schema); |
- return sendRequest( |
- 'contentSettings.getResourceIdentifiers', |
- [contentType, callback], |
- extendSchema(schema)); |
- }; |
- } |
- ContentSetting.prototype = new CustomBindingsObject(); |
- customBindings['ContentSetting'] = ContentSetting; |
- } |
- |
- function setupInputEvents() { |
- chrome.experimental.input.onKeyEvent.dispatch = |
- function(engineID, keyData) { |
- var args = Array.prototype.slice.call(arguments); |
- if (this.validate_) { |
- var validationErrors = this.validate_(args); |
- if (validationErrors) { |
- chrome.experimental.input.eventHandled(requestId, false); |
- return validationErrors; |
- } |
- } |
- if (this.listeners_.length > 1) { |
- console.error("Too many listeners for 'onKeyEvent': " + e.stack); |
- chrome.experimental.input.eventHandled(requestId, false); |
- return; |
- } |
- for (var i = 0; i < this.listeners_.length; i++) { |
- try { |
- var requestId = keyData.requestId; |
- var result = this.listeners_[i].apply(null, args); |
- chrome.experimental.input.eventHandled(requestId, result); |
- } catch (e) { |
- console.error("Error in event handler for 'onKeyEvent': " + e.stack); |
- chrome.experimental.input.eventHandled(requestId, false); |
- } |
- } |
- }; |
- } |
- |
- // Page action events send (pageActionId, {tabId, tabUrl}). |
- function setupPageActionEvents(extensionId) { |
- var pageActions = GetCurrentPageActions(extensionId); |
- |
- var oldStyleEventName = "pageActions"; |
- // TODO(EXTENSIONS_DEPRECATED): only one page action |
- for (var i = 0; i < pageActions.length; ++i) { |
- // Setup events for each extension_id/page_action_id string we find. |
- chrome.pageActions[pageActions[i]] = new chrome.Event(oldStyleEventName); |
- } |
- } |
- |
- function setupHiddenContextMenuEvent(extensionId) { |
- chromeHidden.contextMenus = {}; |
- chromeHidden.contextMenus.handlers = {}; |
- var eventName = "contextMenus"; |
- chromeHidden.contextMenus.event = new chrome.Event(eventName); |
- chromeHidden.contextMenus.ensureListenerSetup = function() { |
- if (chromeHidden.contextMenus.listening) { |
- return; |
- } |
- chromeHidden.contextMenus.listening = true; |
- chromeHidden.contextMenus.event.addListener(function() { |
- // An extension context menu item has been clicked on - fire the onclick |
- // if there is one. |
- var id = arguments[0].menuItemId; |
- var onclick = chromeHidden.contextMenus.handlers[id]; |
- if (onclick) { |
- onclick.apply(null, arguments); |
- } |
- }); |
- }; |
- } |
- |
- // Remove invalid characters from |text| so that it is suitable to use |
- // for |AutocompleteMatch::contents|. |
- function sanitizeString(text) { |
- // NOTE: This logic mirrors |AutocompleteMatch::SanitizeString()|. |
- // 0x2028 = line separator; 0x2029 = paragraph separator. |
- var kRemoveChars = /(\r|\n|\t|\u2028|\u2029)/gm; |
- return text.trimLeft().replace(kRemoveChars, ''); |
- } |
- |
- // Parses the xml syntax supported by omnibox suggestion results. Returns an |
- // object with two properties: 'description', which is just the text content, |
- // and 'descriptionStyles', which is an array of style objects in a format |
- // understood by the C++ backend. |
- function parseOmniboxDescription(input) { |
- var domParser = new DOMParser(); |
- |
- // The XML parser requires a single top-level element, but we want to |
- // support things like 'hello, <match>world</match>!'. So we wrap the |
- // provided text in generated root level element. |
- var root = domParser.parseFromString( |
- '<fragment>' + input + '</fragment>', 'text/xml'); |
- |
- // DOMParser has a terrible error reporting facility. Errors come out nested |
- // inside the returned document. |
- var error = root.querySelector('parsererror div'); |
- if (error) { |
- throw new Error(error.textContent); |
- } |
- |
- // Otherwise, it's valid, so build up the result. |
- var result = { |
- description: '', |
- descriptionStyles: [] |
- }; |
- |
- // Recursively walk the tree. |
- (function(node) { |
- for (var i = 0, child; child = node.childNodes[i]; i++) { |
- // Append text nodes to our description. |
- if (child.nodeType == Node.TEXT_NODE) { |
- result.description += sanitizeString(child.nodeValue); |
- continue; |
- } |
- |
- // Process and descend into a subset of recognized tags. |
- if (child.nodeType == Node.ELEMENT_NODE && |
- (child.nodeName == 'dim' || child.nodeName == 'match' || |
- child.nodeName == 'url')) { |
- var style = { |
- 'type': child.nodeName, |
- 'offset': result.description.length |
- }; |
- result.descriptionStyles.push(style); |
- arguments.callee(child); |
- style.length = result.description.length - style.offset; |
- continue; |
- } |
- |
- // Descend into all other nodes, even if they are unrecognized, for |
- // forward compat. |
- arguments.callee(child); |
- } |
- })(root); |
- |
- return result; |
- } |
- |
- function setupOmniboxEvents() { |
- chrome.omnibox.onInputChanged.dispatch = |
- function(text, requestId) { |
- var suggestCallback = function(suggestions) { |
- chrome.omnibox.sendSuggestions(requestId, suggestions); |
- }; |
- chrome.Event.prototype.dispatch.apply(this, [text, suggestCallback]); |
- }; |
- } |
- |
- function setupTtsEvents() { |
- chromeHidden.tts = {}; |
- chromeHidden.tts.handlers = {}; |
- chrome.ttsEngine.onSpeak.dispatch = |
- function(text, options, requestId) { |
- var sendTtsEvent = function(event) { |
- chrome.ttsEngine.sendTtsEvent(requestId, event); |
- }; |
- chrome.Event.prototype.dispatch.apply( |
- this, [text, options, sendTtsEvent]); |
- }; |
- try { |
- chrome.tts.onEvent.addListener( |
- function(event) { |
- var eventHandler = chromeHidden.tts.handlers[event.srcId]; |
- if (eventHandler) { |
- eventHandler({ |
- type: event.type, |
- charIndex: event.charIndex, |
- errorMessage: event.errorMessage |
- }); |
- if (event.isFinalEvent) { |
- delete chromeHidden.tts.handlers[event.srcId]; |
- } |
- } |
- }); |
- } catch (e) { |
- // This extension doesn't have permission to access TTS, so we |
- // can safely ignore this. |
- } |
- } |
- |
- // Get the platform from navigator.appVersion. |
- function getPlatform() { |
- var platforms = [ |
- [/CrOS Touch/, "chromeos touch"], |
- [/CrOS/, "chromeos"], |
- [/Linux/, "linux"], |
- [/Mac/, "mac"], |
- [/Win/, "win"], |
- ]; |
- |
- for (var i = 0; i < platforms.length; i++) { |
- if (platforms[i][0].test(navigator.appVersion)) { |
- return platforms[i][1]; |
- } |
- } |
- return "unknown"; |
- } |
- |
- chromeHidden.onLoad.addListener(function(extensionId, isExtensionProcess, |
- isIncognitoProcess) { |
- if (!isExtensionProcess) |
- return; |
- |
- // Setup the ChromeSetting class so we can use it to construct |
- // ChromeSetting objects from the API definition. |
- setupChromeSetting(); |
- |
- // Setup the ContentSetting class so we can use it to construct |
- // ContentSetting objects from the API definition. |
- setupContentSetting(); |
- |
- // |apiFunctions| is a hash of name -> object that stores the |
- // name & definition of the apiFunction. Custom handling of api functions |
- // is implemented by adding a "handleRequest" function to the object. |
- var apiFunctions = {}; |
- |
- // Read api definitions and setup api functions in the chrome namespace. |
- // TODO(rafaelw): Consider defining a json schema for an api definition |
- // and validating either here, in a unit_test or both. |
- // TODO(rafaelw): Handle synchronous functions. |
- // TOOD(rafaelw): Consider providing some convenient override points |
- // for api functions that wish to insert themselves into the call. |
- var apiDefinitions = chromeHidden.JSON.parse(GetExtensionAPIDefinition()); |
- var platform = getPlatform(); |
- |
- apiDefinitions.forEach(function(apiDef) { |
- // Check platform, if apiDef has platforms key. |
- if (apiDef.platforms && apiDef.platforms.indexOf(platform) == -1) { |
- return; |
- } |
- |
- var module = chrome; |
- var namespaces = apiDef.namespace.split('.'); |
- for (var index = 0, name; name = namespaces[index]; index++) { |
- module[name] = module[name] || {}; |
- module = module[name]; |
- } |
- |
- // Add types to global validationTypes |
- if (apiDef.types) { |
- apiDef.types.forEach(function(t) { |
- chromeHidden.validationTypes.push(t); |
- if (t.type == 'object' && customBindings[t.id]) { |
- customBindings[t.id].prototype.setSchema(t); |
- } |
- }); |
- } |
- |
- // Setup Functions. |
- if (apiDef.functions) { |
- apiDef.functions.forEach(function(functionDef) { |
- // Module functions may have been defined earlier by hand. Don't |
- // clobber them. |
- if (module[functionDef.name]) |
- return; |
- |
- var apiFunction = {}; |
- apiFunction.definition = functionDef; |
- apiFunction.name = apiDef.namespace + "." + functionDef.name; |
- apiFunctions[apiFunction.name] = apiFunction; |
- |
- module[functionDef.name] = (function() { |
- var args = arguments; |
- if (this.updateArgumentsPreValidate) |
- args = this.updateArgumentsPreValidate.apply(this, args); |
- chromeHidden.validate(args, this.definition.parameters); |
- if (this.updateArgumentsPostValidate) |
- args = this.updateArgumentsPostValidate.apply(this, args); |
- |
- var retval; |
- if (this.handleRequest) { |
- retval = this.handleRequest.apply(this, args); |
- } else { |
- retval = sendRequest(this.name, args, |
- this.definition.parameters, |
- {customCallback: this.customCallback}); |
- } |
- |
- // Validate return value if defined - only in debug. |
- if (chromeHidden.validateCallbacks && |
- chromeHidden.validate && |
- this.definition.returns) { |
- chromeHidden.validate([retval], [this.definition.returns]); |
- } |
- return retval; |
- }).bind(apiFunction); |
- }); |
- } |
- |
- // Setup Events |
- if (apiDef.events) { |
- apiDef.events.forEach(function(eventDef) { |
- // Module events may have been defined earlier by hand. Don't clobber |
- // them. |
- if (module[eventDef.name]) |
- return; |
- |
- var eventName = apiDef.namespace + "." + eventDef.name; |
- if (apiDef.namespace == "experimental.webRequest") { |
- module[eventDef.name] = new chrome.WebRequestEvent(eventName, |
- eventDef.parameters, eventDef.extraParameters); |
- } else { |
- module[eventDef.name] = new chrome.Event(eventName, |
- eventDef.parameters); |
- } |
- }); |
- } |
- |
- function addProperties(m, def) { |
- // Parse any values defined for properties. |
- if (def.properties) { |
- forEach(def.properties, function(prop, property) { |
- var value = property.value; |
- if (value) { |
- if (property.type === 'integer') { |
- value = parseInt(value); |
- } else if (property.type === 'boolean') { |
- value = value === "true"; |
- } else if (property["$ref"]) { |
- var constructor = customBindings[property["$ref"]]; |
- var args = value; |
- // For an object property, |value| is an array of constructor |
- // arguments, but we want to pass the arguments directly |
- // (i.e. not as an array), so we have to fake calling |new| on |
- // the constructor. |
- value = { __proto__: constructor.prototype }; |
- constructor.apply(value, args); |
- } else if (property.type === 'object') { |
- // Recursively add properties. |
- addProperties(value, property); |
- } else if (property.type !== 'string') { |
- throw "NOT IMPLEMENTED (extension_api.json error): Cannot " + |
- "parse values for type \"" + property.type + "\""; |
- } |
- } |
- if (value) { |
- m[prop] = value; |
- } |
- }); |
- } |
- } |
- |
- addProperties(module, apiDef); |
- }); |
- |
- // getTabContentses is retained for backwards compatibility |
- // See http://crbug.com/21433 |
- chrome.extension.getTabContentses = chrome.extension.getExtensionTabs; |
- // TOOD(mihaip): remove this alias once the webstore stops calling |
- // beginInstallWithManifest2. |
- // See http://crbug.com/100242 |
- chrome.webstorePrivate.beginInstallWithManifest2 = |
- chrome.webstorePrivate.beginInstallWithManifest3; |
- |
- apiFunctions["tabs.connect"].handleRequest = function(tabId, connectInfo) { |
- var name = ""; |
- if (connectInfo) { |
- name = connectInfo.name || name; |
- } |
- var portId = OpenChannelToTab(tabId, chromeHidden.extensionId, name); |
- return chromeHidden.Port.createPort(portId, name); |
- }; |
- |
- apiFunctions["tabs.sendRequest"].handleRequest = |
- function(tabId, request, responseCallback) { |
- var port = chrome.tabs.connect(tabId, |
- {name: chromeHidden.kRequestChannel}); |
- port.postMessage(request); |
- port.onDisconnect.addListener(function() { |
- // For onDisconnects, we only notify the callback if there was an error. |
- if (chrome.extension.lastError && responseCallback) |
- responseCallback(); |
- }); |
- port.onMessage.addListener(function(response) { |
- try { |
- if (responseCallback) |
- responseCallback(response); |
- } finally { |
- port.disconnect(); |
- port = null; |
- } |
- }); |
- }; |
- |
- apiFunctions["experimental.savePage.saveAsMHTML"].customCallback = |
- function(name, request, response) { |
- var params = chromeHidden.JSON.parse(response); |
- var path = params.mhtmlFilePath; |
- var size = params.mhtmlFileLength; |
- |
- if (request.callback) |
- request.callback(CreateBlob(path, size)); |
- |
- request.callback = null; |
- }; |
- |
- apiFunctions["fileBrowserPrivate.requestLocalFileSystem"].customCallback = |
- function(name, request, response) { |
- var resp = response ? [chromeHidden.JSON.parse(response)] : []; |
- var fs = null; |
- if (!resp[0].error) |
- fs = GetLocalFileSystem(resp[0].name, resp[0].path); |
- if (request.callback) |
- request.callback(fs); |
- request.callback = null; |
- }; |
- |
- apiFunctions["chromePrivate.decodeJPEG"].handleRequest = |
- function(jpeg_image) { |
- return DecodeJPEG(jpeg_image); |
- }; |
- |
- apiFunctions["extension.getViews"].handleRequest = function(properties) { |
- var windowId = -1; |
- var type = "ALL"; |
- if (typeof(properties) != "undefined") { |
- if (typeof(properties.type) != "undefined") { |
- type = properties.type; |
- } |
- if (typeof(properties.windowId) != "undefined") { |
- windowId = properties.windowId; |
- } |
- } |
- return GetExtensionViews(windowId, type) || null; |
- }; |
- |
- apiFunctions["extension.getBackgroundPage"].handleRequest = function() { |
- return GetExtensionViews(-1, "BACKGROUND")[0] || null; |
- }; |
- |
- apiFunctions["extension.getExtensionTabs"].handleRequest = |
- function(windowId) { |
- if (typeof(windowId) == "undefined") |
- windowId = -1; |
- return GetExtensionViews(windowId, "TAB"); |
- }; |
- |
- apiFunctions["devtools.getTabEvents"].handleRequest = function(tabId) { |
- var tabIdProxy = {}; |
- var functions = ["onPageEvent", "onTabClose"]; |
- functions.forEach(function(name) { |
- // Event disambiguation is handled by name munging. See |
- // chrome/browser/extensions/extension_devtools_events.h for the C++ |
- // equivalent of this logic. |
- tabIdProxy[name] = new chrome.Event("devtools." + tabId + "." + name); |
- }); |
- return tabIdProxy; |
- }; |
- |
- var canvas; |
- function setIconCommon(details, name, parameters, actionType, iconSize, |
- nativeFunction) { |
- if ("iconIndex" in details) { |
- sendRequest(name, [details], parameters); |
- } else if ("imageData" in details) { |
- // Verify that this at least looks like an ImageData element. |
- // Unfortunately, we cannot use instanceof because the ImageData |
- // constructor is not public. |
- // |
- // We do this manually instead of using JSONSchema to avoid having these |
- // properties show up in the doc. |
- if (!("width" in details.imageData) || |
- !("height" in details.imageData) || |
- !("data" in details.imageData)) { |
- throw new Error( |
- "The imageData property must contain an ImageData object."); |
- } |
- |
- if (details.imageData.width > iconSize || |
- details.imageData.height > iconSize) { |
- throw new Error( |
- "The imageData property must contain an ImageData object that " + |
- "is no larger than " + iconSize + " pixels square."); |
- } |
- |
- sendRequest(name, [details], parameters, |
- {noStringify: true, nativeFunction: nativeFunction}); |
- } else if ("path" in details) { |
- var img = new Image(); |
- img.onerror = function() { |
- console.error("Could not load " + actionType + " icon '" + |
- details.path + "'."); |
- }; |
- img.onload = function() { |
- var canvas = document.createElement("canvas"); |
- canvas.width = img.width > iconSize ? iconSize : img.width; |
- canvas.height = img.height > iconSize ? iconSize : img.height; |
- |
- var canvas_context = canvas.getContext('2d'); |
- canvas_context.clearRect(0, 0, canvas.width, canvas.height); |
- canvas_context.drawImage(img, 0, 0, canvas.width, canvas.height); |
- delete details.path; |
- details.imageData = canvas_context.getImageData(0, 0, canvas.width, |
- canvas.height); |
- sendRequest(name, [details], parameters, |
- {noStringify: true, nativeFunction: nativeFunction}); |
- }; |
- img.src = details.path; |
- } else { |
- throw new Error( |
- "Either the path or imageData property must be specified."); |
- } |
- } |
- |
- function setExtensionActionIconCommon(details, name, parameters, |
- actionType) { |
- var EXTENSION_ACTION_ICON_SIZE = 19; |
- setIconCommon(details, name, parameters, actionType, |
- EXTENSION_ACTION_ICON_SIZE, SetIconCommon); |
- } |
- |
- apiFunctions["browserAction.setIcon"].handleRequest = function(details) { |
- setExtensionActionIconCommon( |
- details, this.name, this.definition.parameters, "browser action"); |
- }; |
- |
- apiFunctions["pageAction.setIcon"].handleRequest = function(details) { |
- setExtensionActionIconCommon( |
- details, this.name, this.definition.parameters, "page action"); |
- }; |
- |
- apiFunctions["experimental.sidebar.setIcon"].handleRequest = |
- function(details) { |
- var SIDEBAR_ICON_SIZE = 16; |
- setIconCommon( |
- details, this.name, this.definition.parameters, "sidebar", |
- SIDEBAR_ICON_SIZE, SetIconCommon); |
- }; |
- |
- apiFunctions["contextMenus.create"].handleRequest = |
- function() { |
- var args = arguments; |
- var id = GetNextContextMenuId(); |
- args[0].generatedId = id; |
- sendRequest(this.name, args, this.definition.parameters, |
- {customCallback: this.customCallback}); |
- return id; |
- }; |
- |
- apiFunctions["omnibox.setDefaultSuggestion"].handleRequest = |
- function(details) { |
- var parseResult = parseOmniboxDescription(details.description); |
- sendRequest(this.name, [parseResult], this.definition.parameters); |
- }; |
- |
- apiFunctions["experimental.webRequest.addEventListener"].handleRequest = |
- function() { |
- var args = Array.prototype.slice.call(arguments); |
- sendRequest(this.name, args, this.definition.parameters, |
- {forIOThread: true}); |
- }; |
- |
- apiFunctions["experimental.webRequest.eventHandled"].handleRequest = |
- function() { |
- var args = Array.prototype.slice.call(arguments); |
- sendRequest(this.name, args, this.definition.parameters, |
- {forIOThread: true}); |
- }; |
- |
- apiFunctions["experimental.webRequest.handlerBehaviorChanged"]. |
- handleRequest = function() { |
- var args = Array.prototype.slice.call(arguments); |
- sendRequest(this.name, args, this.definition.parameters, |
- {forIOThread: true}); |
- }; |
- |
- apiFunctions["contextMenus.create"].customCallback = |
- function(name, request, response) { |
- if (chrome.extension.lastError) { |
- return; |
- } |
- |
- var id = request.args[0].generatedId; |
- |
- // Set up the onclick handler if we were passed one in the request. |
- var onclick = request.args.length ? request.args[0].onclick : null; |
- if (onclick) { |
- chromeHidden.contextMenus.ensureListenerSetup(); |
- chromeHidden.contextMenus.handlers[id] = onclick; |
- } |
- }; |
- |
- apiFunctions["contextMenus.remove"].customCallback = |
- function(name, request, response) { |
- if (chrome.extension.lastError) { |
- return; |
- } |
- var id = request.args[0]; |
- delete chromeHidden.contextMenus.handlers[id]; |
- }; |
- |
- apiFunctions["contextMenus.update"].customCallback = |
- function(name, request, response) { |
- if (chrome.extension.lastError) { |
- return; |
- } |
- var id = request.args[0]; |
- if (request.args[1].onclick) { |
- chromeHidden.contextMenus.handlers[id] = request.args[1].onclick; |
- } |
- }; |
- |
- apiFunctions["contextMenus.removeAll"].customCallback = |
- function(name, request, response) { |
- if (chrome.extension.lastError) { |
- return; |
- } |
- chromeHidden.contextMenus.handlers = {}; |
- }; |
- |
- apiFunctions["tabs.captureVisibleTab"].updateArgumentsPreValidate = |
- function() { |
- // Old signature: |
- // captureVisibleTab(int windowId, function callback); |
- // New signature: |
- // captureVisibleTab(int windowId, object details, function callback); |
- // |
- // TODO(skerner): The next step to omitting optional arguments is the |
- // replacement of this code with code that matches arguments by type. |
- // Once this is working for captureVisibleTab() it can be enabled for |
- // the rest of the API. See crbug/29215 . |
- if (arguments.length == 2 && typeof(arguments[1]) == "function") { |
- // If the old signature is used, add a null details object. |
- newArgs = [arguments[0], null, arguments[1]]; |
- } else { |
- newArgs = arguments; |
- } |
- return newArgs; |
- }; |
- |
- apiFunctions["omnibox.sendSuggestions"].updateArgumentsPostValidate = |
- function(requestId, userSuggestions) { |
- var suggestions = []; |
- for (var i = 0; i < userSuggestions.length; i++) { |
- var parseResult = parseOmniboxDescription( |
- userSuggestions[i].description); |
- parseResult.content = userSuggestions[i].content; |
- suggestions.push(parseResult); |
- } |
- return [requestId, suggestions]; |
- }; |
- |
- apiFunctions["tts.speak"].handleRequest = function() { |
- var args = arguments; |
- if (args.length > 1 && args[1] && args[1].onEvent) { |
- var id = GetNextTtsEventId(); |
- args[1].srcId = id; |
- chromeHidden.tts.handlers[id] = args[1].onEvent; |
- } |
- sendRequest(this.name, args, this.definition.parameters); |
- return id; |
- }; |
- |
- if (chrome.test) { |
- chrome.test.getApiDefinitions = GetExtensionAPIDefinition; |
- } |
- |
- setupPageActionEvents(extensionId); |
- setupHiddenContextMenuEvent(extensionId); |
- setupInputEvents(); |
- setupOmniboxEvents(); |
- setupTtsEvents(); |
- }); |
- |
- if (!chrome.experimental) |
- chrome.experimental = {}; |
- |
- if (!chrome.experimental.accessibility) |
- chrome.experimental.accessibility = {}; |
- |
- if (!chrome.experimental.speechInput) |
- chrome.experimental.speechInput = {}; |
- |
- if (!chrome.tts) |
- chrome.tts = {}; |
- |
- if (!chrome.ttsEngine) |
- chrome.ttsEngine = {}; |
- |
- if (!chrome.experimental.downloads) |
- chrome.experimental.downloads = {}; |
-})(); |