summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/resources/renderer_extension_bindings.js
blob: 401f82ccb5243d6603cdad26f78c23625bc4f8af (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
var chromium = chromium || {};
(function () {
  native function OpenChannelToExtension(id);
  native function PostMessage(portId, msg);
  native function RegisterScriptAPI(private);
  // chromium: Public API.

  // Represents info we know about a chrome extension.
  chromium.Extension = function(id) {
    this.id_ = id;
  };

  // Opens a channel to the extension for message passing.
  chromium.Extension.prototype.openChannel = function() {
    portId = OpenChannelToExtension(this.id_);
    if (portId == -1)
      throw new Error('No such extension \"' + this.id_ + '\"');
    return new Port(portId);
  };

  // Adds a listener that fires when a renderer opens a channel to talk
  // to us.
  chromium.addConnectListener = function(callback) {
    chromium.addEventListener('channel-connect',
        function (e) { callback(e.data.port); });
  };

  // Adds a generic event listener.
  chromium.addEventListener = function(type, callback) {
    var listeners = getPrivateData().eventListeners;
    if (!listeners[type])
      listeners[type] = [];
    listeners[type].push(callback);
  };

  // Dispatches the given event to anyone listening for that event.
  chromium.dispatchEvent = function(type, data) {
    var event = {type: type, data: data};
    var listeners = getPrivateData().eventListeners;
    for (var i in listeners[type]) {
      listeners[type][i](event);
    }
  };

  // Private API.

  // Always access privateData through this function, to ensure that we
  // have registered our native API.  We do this lazily to avoid registering
  // on pages that don't use these bindings.
  function getPrivateData() {
    if (!scriptAPI.registered_) {
      RegisterScriptAPI(scriptAPI);
      scriptAPI.registered_ = true;
    }
    return privateData;
  }
  var privateData = {
    eventListeners: {},
    ports: {}
  };

  // Represents a port through which we can send messages to another process.
  var Port = function(portId) {
    // TODO(mpcomplete): we probably want to hide this portId_ so
    // it can't be guessed at.  One idea is to expose v8's SetHiddenValue
    // to our extension.
    this.portId_ = portId;
    getPrivateData().ports[portId] = this;
  };

  // Sends a message to the other side of the channel.
  Port.prototype.postMessage = function(msg) {
    PostMessage(this.portId_, msg);
  };

  // Script API: javascript APIs exposed to C++ only.
  // This object allows our native code to call back to us through a
  // private interface that isn't exposed to web content.
  var scriptAPI = {};

  // Called by native code when a channel has been opened to this process.
  scriptAPI.dispatchOnConnect = function(portId) {
    chromium.dispatchEvent('channel-connect', {port: new Port(portId)});
  };

  // Called by native code when a message has been sent over the given
  // channel.
  scriptAPI.dispatchOnMessage = function(msg, portId) {
    var port = getPrivateData().ports[portId];
    if (port && port.onMessage)
      port.onMessage(msg, port);
  };
})();