blob: 20053f3523920485aa2b78a54514bf384d1ce5a6 [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:526
estade16869432016-01-23 02:35:477function loadImagePath(path, callback) {
[email protected]866d940a2012-09-10 23:02:028 var img = new Image();
9 img.onerror = function() {
[email protected]30ee19bc2014-08-21 17:22:2210 console.error('Could not load action icon \'' + path + '\'.');
[email protected]866d940a2012-09-10 23:02:0211 };
12 img.onload = function() {
13 var canvas = document.createElement('canvas');
estade16869432016-01-23 02:35:4714 canvas.width = img.width;
15 canvas.height = img.height;
[email protected]866d940a2012-09-10 23:02:0216
17 var canvas_context = canvas.getContext('2d');
18 canvas_context.clearRect(0, 0, canvas.width, canvas.height);
19 canvas_context.drawImage(img, 0, 0, canvas.width, canvas.height);
20 var imageData = canvas_context.getImageData(0, 0, canvas.width,
21 canvas.height);
22 callback(imageData);
23 };
24 img.src = path;
25}
26
estade16869432016-01-23 02:35:4727function smellsLikeImageData(imageData) {
28 // See if this object at least looks like an ImageData element.
[email protected]866d940a2012-09-10 23:02:0229 // Unfortunately, we cannot use instanceof because the ImageData
30 // constructor is not public.
31 //
32 // We do this manually instead of using JSONSchema to avoid having these
33 // properties show up in the doc.
estade16869432016-01-23 02:35:4734 return (typeof imageData == 'object') && ('width' in imageData) &&
35 ('height' in imageData) && ('data' in imageData);
36}
37
38function verifyImageData(imageData) {
39 if (!smellsLikeImageData(imageData)) {
[email protected]866d940a2012-09-10 23:02:0240 throw new Error(
41 'The imageData property must contain an ImageData object or' +
42 ' dictionary of ImageData objects.');
43 }
[email protected]866d940a2012-09-10 23:02:0244}
45
[email protected]30ee19bc2014-08-21 17:22:2246/**
47 * Normalizes |details| to a format suitable for sending to the browser,
48 * for example converting ImageData to a binary representation.
49 *
50 * @param {ImageDetails} details
51 * The ImageDetails passed into an extension action-style API.
52 * @param {Function} callback
53 * The callback function to pass processed imageData back to. Note that this
54 * callback may be called reentrantly.
55 */
56function setIcon(details, callback) {
[email protected]30ee19bc2014-08-21 17:22:2257 // Note that iconIndex is actually deprecated, and only available to the
58 // pageAction API.
59 // TODO(kalman): Investigate whether this is for the pageActions API, and if
60 // so, delete it.
[email protected]866d940a2012-09-10 23:02:0261 if ('iconIndex' in details) {
[email protected]30ee19bc2014-08-21 17:22:2262 callback(details);
63 return;
64 }
[email protected]866d940a2012-09-10 23:02:0265
[email protected]30ee19bc2014-08-21 17:22:2266 if ('imageData' in details) {
estade16869432016-01-23 02:35:4767 if (smellsLikeImageData(details.imageData)) {
[email protected]30ee19bc2014-08-21 17:22:2268 var imageData = details.imageData;
69 details.imageData = {};
estade16869432016-01-23 02:35:4770 details.imageData[imageData.width.toString()] = imageData;
71 } else if (typeof details.imageData == 'object' &&
72 Object.getOwnPropertyNames(details.imageData).length !== 0) {
73 for (var sizeKey in details.imageData) {
74 verifyImageData(details.imageData[sizeKey]);
75 }
76 } else {
77 verifyImageData(false);
[email protected]30ee19bc2014-08-21 17:22:2278 }
estade16869432016-01-23 02:35:4779
[email protected]30ee19bc2014-08-21 17:22:2280 callback(SetIconCommon(details));
81 return;
82 }
83
84 if ('path' in details) {
[email protected]866d940a2012-09-10 23:02:0285 if (typeof details.path == 'object') {
86 details.imageData = {};
estade16869432016-01-23 02:35:4787 var detailKeyCount = 0;
88 for (var iconSize in details.path) {
89 ++detailKeyCount;
90 loadImagePath(details.path[iconSize], function(size, imageData) {
91 details.imageData[size] = imageData;
92 if (--detailKeyCount == 0)
[email protected]30ee19bc2014-08-21 17:22:2293 callback(SetIconCommon(details));
estade16869432016-01-23 02:35:4794 }.bind(null, iconSize));
95 }
96 if (detailKeyCount == 0)
97 throw new Error('The path property must not be empty.');
98 } else if (typeof details.path == 'string') {
99 details.imageData = {};
100 loadImagePath(details.path, function(imageData) {
101 details.imageData[imageData.width.toString()] = imageData;
102 delete details.path;
103 callback(SetIconCommon(details));
[email protected]866d940a2012-09-10 23:02:02104 });
[email protected]a5380cc72012-03-28 04:59:52105 }
[email protected]30ee19bc2014-08-21 17:22:22106 return;
[email protected]a5380cc72012-03-28 04:59:52107 }
[email protected]30ee19bc2014-08-21 17:22:22108 throw new Error('Either the path or imageData property must be specified.');
[email protected]a5380cc72012-03-28 04:59:52109}
110
rdevlin.cronin83a4b3a2015-10-28 21:43:58111exports.$set('setIcon', setIcon);