diff options
Diffstat (limited to 'chrome/renderer')
4 files changed, 202 insertions, 0 deletions
diff --git a/chrome/renderer/extensions/dispatcher.cc b/chrome/renderer/extensions/dispatcher.cc index dcd161f..a76441f 100644 --- a/chrome/renderer/extensions/dispatcher.cc +++ b/chrome/renderer/extensions/dispatcher.cc @@ -632,6 +632,7 @@ void Dispatcher::PopulateSourceMap() { // Libraries. source_map_.RegisterSource("contentWatcher", IDR_CONTENT_WATCHER_JS); + source_map_.RegisterSource("imageUtil", IDR_IMAGE_UTIL_JS); source_map_.RegisterSource("lastError", IDR_LAST_ERROR_JS); source_map_.RegisterSource("schemaUtils", IDR_SCHEMA_UTILS_JS); source_map_.RegisterSource("sendRequest", IDR_SEND_REQUEST_JS); @@ -659,6 +660,8 @@ void Dispatcher::PopulateSourceMap() { IDR_EXPERIMENTAL_MEDIA_GALLERIES_CUSTOM_BINDINGS_JS); source_map_.RegisterSource("experimental.offscreen", IDR_EXPERIMENTAL_OFFSCREENTABS_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("experimental.notification", + IDR_NOTIFICATION_CUSTOM_BINDINGS_JS); source_map_.RegisterSource("extension", IDR_EXTENSION_CUSTOM_BINDINGS_JS); source_map_.RegisterSource("fileBrowserHandler", IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS); diff --git a/chrome/renderer/resources/extensions/image_util.js b/chrome/renderer/resources/extensions/image_util.js new file mode 100644 index 0000000..4f418e2 --- /dev/null +++ b/chrome/renderer/resources/extensions/image_util.js @@ -0,0 +1,69 @@ +// Copyright 2013 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 function takes an object |imageSpec| with the key |path| - +// corresponding to the internet URL to be translated - and optionally +// |width| and |height| which are the maximum dimensions to be used when +// converting the image. +function loadDataUrl(imageSpec, callbacks) { + var path = imageSpec.path; + var img = new Image(); + if (typeof callbacks.onerror === 'function') { + img.onerror = function() { + callbacks.onerror({ problem: 'could_not_load', path: path }); + }; + } + img.onload = function() { + var canvas = document.createElement('canvas'); + + canvas.width = img.width; + if (imageSpec.width && imageSpec.width < img.width) + canvas.width = imageSpec.width; + canvas.height = img.height; + if (imageSpec.height && imageSpec.height < img.height) + canvas.height = imageSpec.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); + try { + var dataUrl = canvas.toDataURL(); + if (typeof callbacks.oncomplete === 'function') { + callbacks.oncomplete(dataUrl); + } + } catch (e) { + if (typeof callbacks.onerror === 'function') { + callbacks.onerror({ problem: 'data_url_unavailable', path: path }); + } + } + } + img.src = path; +} + +function on_complete_index(index, err, loading, finished, callbacks) { + return function(imageData) { + delete loading[index]; + finished[index] = imageData; + if (err) + callbacks.onerror(index); + if (Object.keys(loading).length == 0) + callbacks.oncomplete(finished); + } +} + +function loadAllImages(imageSpecs, callbacks) { + var loading = {}, finished = [], + index, pathname; + + for (var index = 0; index < imageSpecs.length; index++) { + loading[index] = imageSpecs[index]; + loadDataUrl(imageSpecs[index], { + oncomplete: on_complete_index(index, false, loading, finished, callbacks), + onerror: on_complete_index(index, true, loading, finished, callbacks) + }); + } +} + +exports.loadDataUrl = loadDataUrl; +exports.loadAllImages = loadAllImages; diff --git a/chrome/renderer/resources/extensions/notification_custom_bindings.js b/chrome/renderer/resources/extensions/notification_custom_bindings.js new file mode 100644 index 0000000..b88be09 --- /dev/null +++ b/chrome/renderer/resources/extensions/notification_custom_bindings.js @@ -0,0 +1,128 @@ +// Copyright 2013 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. + +// Custom bindings for the notification API. + +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); +var sendRequest = require('sendRequest').sendRequest; +var imageUtil = require('imageUtil'); +var lastError = require('lastError'); + +function url_getter(context, key) { + var f = function() { + return this[key]; + }; + return f.bind(context); +} + +function url_setter(context, key) { + var f = function(val) { + this[key] = val; + }; + return f.bind(context); +} + +function replaceNotificationOptionURLs(notification_details, callback) { + // A URL Spec is an object with the following keys: + // path: The resource to be downloaded. + // callback: A function to be called when the URL is complete. It + // should accept an ImageData object and set the appropriate + // field in the output of create. + + // TODO(dewittj): Try to remove hard-coding. + // |iconUrl| is required. + var url_specs = [{ + path: notification_details.iconUrl, + width: 80, + height: 80, + callback: url_setter(notification_details, 'iconUrl') + }]; + + // |secondIconUrl| is optional. + if (notification_details.secondIconUrl) { + url_specs.push({ + path: notification_details.secondIconUrl, + width: 80, + height: 80, + callback: url_setter(notification_details, 'secondIconUrl') + }); + } + + // |imageUrl| is optional. + if (notification_details.imageUrl) { + url_specs.push({ + path: notification_details.imageUrl, + width: 300, + height: 300, + callback: url_setter(notification_details, 'imageUrl') + }); + } + + // Each button has an optional icon. + var button_list = notification_details.buttons; + if (button_list && typeof button_list.length === 'number') { + var num_buttons = button_list.length; + for (var i = 0; i < num_buttons; i++) { + if (button_list[i].iconUrl) { + url_specs.push({ + path: button_list[i].iconUrl, + width: 16, + height: 16, + callback: url_setter(button_list[i], 'iconUrl') + }); + } + } + } + + var errors = 0; + + imageUtil.loadAllImages(url_specs, { + onerror: function(index) { + errors++; + }, + oncomplete: function(imageData) { + if (errors > 0) { + callback(false); + return; + } + for (var index = 0; index < url_specs.length; index++) { + var url_spec = url_specs[index]; + url_spec.callback(imageData[index]); + } + callback(true); + } + }); +} + +function genHandle(failure_function) { + return function(id, input_notification_details, callback) { + // TODO(dewittj): Remove this hack. This is used as a way to deep + // copy a complex JSON object. + var notification_details = JSON.parse( + JSON.stringify(input_notification_details)); + var that = this; + replaceNotificationOptionURLs(notification_details, function(success) { + if (success) { + sendRequest(that.name, + [id, notification_details, callback], + that.definition.parameters); + return; + } + lastError.set('Unable to download all specified images.'); + failure_function(callback, id); + }); + }; +} + +var handleCreate = genHandle(function(callback, id) { callback(id); }); +var handleUpdate = genHandle(function(callback, id) { callback(false); }); + +var experimentalNotificationCustomHook = function(bindingsAPI, extensionId) { + var apiFunctions = bindingsAPI.apiFunctions; + apiFunctions.setHandleRequest('create', handleCreate); + apiFunctions.setHandleRequest('update', handleCreate); +}; + +chromeHidden.registerCustomHook('experimental.notification', + experimentalNotificationCustomHook); diff --git a/chrome/renderer/resources/renderer_resources.grd b/chrome/renderer/resources/renderer_resources.grd index 1643ff4..225a75d 100644 --- a/chrome/renderer/resources/renderer_resources.grd +++ b/chrome/renderer/resources/renderer_resources.grd @@ -37,6 +37,7 @@ without changes to the corresponding grd file. fb9 --> <!-- Libraries. --> <include name="IDR_TAG_WATCHER_JS" file="extensions\tag_watcher.js" type="BINDATA" /> + <include name="IDR_IMAGE_UTIL_JS" file="extensions\image_util.js" type="BINDATA" /> <include name="IDR_LAST_ERROR_JS" file="extensions\last_error.js" type="BINDATA" /> <include name="IDR_SCHEMA_UTILS_JS" file="extensions\schema_utils.js" type="BINDATA" /> <include name="IDR_SEND_REQUEST_JS" file="extensions\send_request.js" type="BINDATA" /> @@ -65,6 +66,7 @@ without changes to the corresponding grd file. fb9 --> <include name="IDR_I18N_CUSTOM_BINDINGS_JS" file="extensions\i18n_custom_bindings.js" type="BINDATA" /> <include name="IDR_INPUT_IME_CUSTOM_BINDINGS_JS" file="extensions\input.ime_custom_bindings.js" type="BINDATA" /> <include name="IDR_MEDIA_GALLERIES_CUSTOM_BINDINGS_JS" file="extensions\media_galleries_custom_bindings.js" type="BINDATA" /> + <include name="IDR_NOTIFICATION_CUSTOM_BINDINGS_JS" file="extensions\notification_custom_bindings.js" type="BINDATA" /> <include name="IDR_OMNIBOX_CUSTOM_BINDINGS_JS" file="extensions\omnibox_custom_bindings.js" type="BINDATA" /> <include name="IDR_PAGE_ACTIONS_CUSTOM_BINDINGS_JS" file="extensions\page_actions_custom_bindings.js" type="BINDATA" /> <include name="IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS" file="extensions\page_action_custom_bindings.js" type="BINDATA" /> |