summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/resources/extensions/set_icon.js
blob: dde92745bdbb26afbf74ce0bd127ad30a4a1a5f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) 2012 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.

var SetIconCommon = requireNative('setIcon').SetIconCommon;
var sendRequest = require('sendRequest').sendRequest;

function loadImagePath(path, iconSize, actionType, callback) {
  var img = new Image();
  img.onerror = function() {
    console.error('Could not load ' + actionType + ' icon \'' +
                  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);
    var imageData = canvas_context.getImageData(0, 0, canvas.width,
                                                canvas.height);
    callback(imageData);
  };
  img.src = path;
}

function verifyImageData(imageData, iconSize) {
  // 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 imageData) ||
      !('height' in imageData) ||
      !('data' in imageData)) {
    throw new Error(
        'The imageData property must contain an ImageData object or' +
        ' dictionary of ImageData objects.');
  }

  if (imageData.width > iconSize ||
      imageData.height > iconSize) {
    throw new Error(
        'The imageData property must contain an ImageData object that ' +
        'is no larger than ' + iconSize + ' pixels square.');
  }
}

function setIcon(details, callback, name, parameters, actionType) {
  var iconSizes = [19, 38];
  if ('iconIndex' in details) {
    sendRequest(name, [details, callback], parameters);
  } else if ('imageData' in details) {
    if (typeof details.imageData == 'object') {
      var isEmpty = true;
      for (var i = 0; i < iconSizes.length; i++) {
        var sizeKey = iconSizes[i].toString();
        if (sizeKey in details.imageData) {
          verifyImageData(details.imageData[sizeKey], iconSizes[i]);
          isEmpty =false;
        }
      }

      if (!isEmpty) {
        sendRequest(name, [details, callback], parameters,
                    {nativeFunction: SetIconCommon});
      } else {
        // If details.imageData is not dictionary with keys in set {'19', '38'},
        // it must be an ImageData object.
        var sizeKey = iconSizes[0].toString();
        var imageData = details.imageData;
        details.imageData = {};
        details.imageData[sizeKey] = imageData;
        verifyImageData(details.imageData[sizeKey], iconSizes[0]);
        sendRequest(name, [details, callback], parameters,
                    {nativeFunction: SetIconCommon});
     }
    } else {
      throw new Error('imageData property has unexpected type.');
    }
  } else if ('path' in details) {
    if (typeof details.path == 'object') {
      details.imageData = {};
      var isEmpty = true;
      var processIconSize = function(index) {
        if (index == iconSizes.length) {
          delete details.path;
          if (isEmpty)
            throw new Error('The path property must not be empty.');
          sendRequest(name, [details, callback], parameters,
                      {nativeFunction: SetIconCommon});
          return;
        }
        var sizeKey = iconSizes[index].toString();
        if (!(sizeKey in details.path)) {
          processIconSize(index + 1);
          return;
        }
        isEmpty = false;
        loadImagePath(details.path[sizeKey], iconSizes[index], actionType,
          function(imageData) {
            details.imageData[sizeKey] = imageData;
            processIconSize(index + 1);
          });
      }

      processIconSize(0);
    } else if (typeof details.path == 'string') {
      var sizeKey = iconSizes[0].toString();
      details.imageData = {};
      loadImagePath(details.path, iconSizes[0], actionType,
          function(imageData) {
            details.imageData[sizeKey] = imageData;
            delete details.path;
            sendRequest(name, [details, callback], parameters,
                        {nativeFunction: SetIconCommon});
      });
    } else {
      throw new Error('The path property should contain either string or ' +
                      'dictionary of strings.');
    }
  } else {
    throw new Error(
        'Either the path or imageData property must be specified.');
  }
}

exports.setIcon = setIcon;