blob: b0ed2b5b5fab368781971f2bd00321114b779798 [file] [log] [blame]
[email protected]8f857ef82014-06-04 23:46:161// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]a5380cc72012-03-28 04:59:522// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]d0920e982012-04-05 07:19:295var SetIconCommon = requireNative('setIcon').SetIconCommon;
[email protected]a5380cc72012-03-28 04:59:526var sendRequest = require('sendRequest').sendRequest;
7
estade16869432016-01-23 02:35:478function loadImagePath(path, callback) {
[email protected]866d940a2012-09-10 23:02:029 var img = new Image();
10 img.onerror = function() {
[email protected]30ee19bc2014-08-21 17:22:2211 console.error('Could not load action icon \'' + path + '\'.');
[email protected]866d940a2012-09-10 23:02:0212 };
13 img.onload = function() {
14 var canvas = document.createElement('canvas');
estade16869432016-01-23 02:35:4715 canvas.width = img.width;
16 canvas.height = img.height;
[email protected]866d940a2012-09-10 23:02:0217
18 var canvas_context = canvas.getContext('2d');
19 canvas_context.clearRect(0, 0, canvas.width, canvas.height);
20 canvas_context.drawImage(img, 0, 0, canvas.width, canvas.height);
21 var imageData = canvas_context.getImageData(0, 0, canvas.width,
22 canvas.height);
23 callback(imageData);
24 };
25 img.src = path;
26}
27
estade16869432016-01-23 02:35:4728function smellsLikeImageData(imageData) {
29 // See if this object at least looks like an ImageData element.
[email protected]866d940a2012-09-10 23:02:0230 // Unfortunately, we cannot use instanceof because the ImageData
31 // constructor is not public.
32 //
33 // We do this manually instead of using JSONSchema to avoid having these
34 // properties show up in the doc.
estade16869432016-01-23 02:35:4735 return (typeof imageData == 'object') && ('width' in imageData) &&
36 ('height' in imageData) && ('data' in imageData);
37}
38
39function verifyImageData(imageData) {
40 if (!smellsLikeImageData(imageData)) {
[email protected]866d940a2012-09-10 23:02:0241 throw new Error(
42 'The imageData property must contain an ImageData object or' +
43 ' dictionary of ImageData objects.');
44 }
[email protected]866d940a2012-09-10 23:02:0245}
46
[email protected]30ee19bc2014-08-21 17:22:2247/**
48 * Normalizes |details| to a format suitable for sending to the browser,
49 * for example converting ImageData to a binary representation.
50 *
51 * @param {ImageDetails} details
52 * The ImageDetails passed into an extension action-style API.
53 * @param {Function} callback
54 * The callback function to pass processed imageData back to. Note that this
55 * callback may be called reentrantly.
56 */
57function setIcon(details, callback) {
[email protected]30ee19bc2014-08-21 17:22:2258 // Note that iconIndex is actually deprecated, and only available to the
59 // pageAction API.
60 // TODO(kalman): Investigate whether this is for the pageActions API, and if
61 // so, delete it.
[email protected]866d940a2012-09-10 23:02:0262 if ('iconIndex' in details) {
[email protected]30ee19bc2014-08-21 17:22:2263 callback(details);
64 return;
65 }
[email protected]866d940a2012-09-10 23:02:0266
[email protected]30ee19bc2014-08-21 17:22:2267 if ('imageData' in details) {
estade16869432016-01-23 02:35:4768 if (smellsLikeImageData(details.imageData)) {
[email protected]30ee19bc2014-08-21 17:22:2269 var imageData = details.imageData;
70 details.imageData = {};
estade16869432016-01-23 02:35:4771 details.imageData[imageData.width.toString()] = imageData;
72 } else if (typeof details.imageData == 'object' &&
73 Object.getOwnPropertyNames(details.imageData).length !== 0) {
74 for (var sizeKey in details.imageData) {
75 verifyImageData(details.imageData[sizeKey]);
76 }
77 } else {
78 verifyImageData(false);
[email protected]30ee19bc2014-08-21 17:22:2279 }
estade16869432016-01-23 02:35:4780
[email protected]30ee19bc2014-08-21 17:22:2281 callback(SetIconCommon(details));
82 return;
83 }
84
85 if ('path' in details) {
[email protected]866d940a2012-09-10 23:02:0286 if (typeof details.path == 'object') {
87 details.imageData = {};
estade16869432016-01-23 02:35:4788 var detailKeyCount = 0;
89 for (var iconSize in details.path) {
90 ++detailKeyCount;
91 loadImagePath(details.path[iconSize], function(size, imageData) {
92 details.imageData[size] = imageData;
93 if (--detailKeyCount == 0)
[email protected]30ee19bc2014-08-21 17:22:2294 callback(SetIconCommon(details));
estade16869432016-01-23 02:35:4795 }.bind(null, iconSize));
96 }
97 if (detailKeyCount == 0)
98 throw new Error('The path property must not be empty.');
99 } else if (typeof details.path == 'string') {
100 details.imageData = {};
101 loadImagePath(details.path, function(imageData) {
102 details.imageData[imageData.width.toString()] = imageData;
103 delete details.path;
104 callback(SetIconCommon(details));
[email protected]866d940a2012-09-10 23:02:02105 });
[email protected]a5380cc72012-03-28 04:59:52106 }
[email protected]30ee19bc2014-08-21 17:22:22107 return;
[email protected]a5380cc72012-03-28 04:59:52108 }
[email protected]30ee19bc2014-08-21 17:22:22109 throw new Error('Either the path or imageData property must be specified.');
[email protected]a5380cc72012-03-28 04:59:52110}
111
rdevlin.cronin83a4b3a2015-10-28 21:43:58112exports.$set('setIcon', setIcon);