1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4cr.define('gpu', function() {
5  /**
6   * This class provides a 'bridge' for communicating between javascript and the
7   * browser. When run outside of WebUI, e.g. as a regular webpage, it provides
8   * synthetic data to assist in testing.
9   * @constructor
10   */
11  function BrowserBridge() {
12    // If we are not running inside WebUI, output chrome.send messages
13    // to the console to help with quick-iteration debugging.
14    if (chrome.send === undefined && console.log) {
15      this.debugMode_ = true;
16      var browserBridgeTests = document.createElement('script');
17      browserBridgeTests.src = './gpu_internals/browser_bridge_tests.js';
18      document.body.appendChild(browserBridgeTests);
19    } else {
20      this.debugMode_ = false;
21    }
22
23    this.nextRequestId_ = 0;
24    this.pendingCallbacks_ = [];
25    this.logMessages_ = [];
26
27    // Tell c++ code that we are ready to receive GPU Info.
28    if (!this.debugMode_) {
29      chrome.send('browserBridgeInitialized');
30      this.beginRequestClientInfo_();
31      this.beginRequestLogMessages_();
32    }
33  }
34
35  BrowserBridge.prototype = {
36    __proto__: cr.EventTarget.prototype,
37
38    applySimulatedData_: function applySimulatedData(data) {
39      // set up things according to the simulated data
40      this.gpuInfo_ = data.gpuInfo;
41      this.clientInfo_ = data.clientInfo;
42      this.logMessages_ = data.logMessages;
43      cr.dispatchSimpleEvent(this, 'gpuInfoUpdate');
44      cr.dispatchSimpleEvent(this, 'clientInfoChange');
45      cr.dispatchSimpleEvent(this, 'logMessagesChange');
46    },
47
48    /**
49     * Returns true if the page is hosted inside Chrome WebUI
50     * Helps have behavior conditional to emulate_webui.py
51     */
52    get debugMode() {
53      return this.debugMode_;
54    },
55
56    /**
57     * Sends a message to the browser with specified args. The
58     * browser will reply asynchronously via the provided callback.
59     */
60    callAsync: function(submessage, args, callback) {
61      var requestId = this.nextRequestId_;
62      this.nextRequestId_ += 1;
63      this.pendingCallbacks_[requestId] = callback;
64      if (!args) {
65        chrome.send('callAsync', [requestId.toString(), submessage]);
66      } else {
67        var allArgs = [requestId.toString(), submessage].concat(args);
68        chrome.send('callAsync', allArgs);
69      }
70    },
71
72    /**
73     * Called by gpu c++ code when client info is ready.
74     */
75    onCallAsyncReply: function(requestId, args) {
76      if (this.pendingCallbacks_[requestId] === undefined) {
77        throw new Error('requestId ' + requestId + ' is not pending');
78      }
79      var callback = this.pendingCallbacks_[requestId];
80      callback(args);
81      delete this.pendingCallbacks_[requestId];
82    },
83
84    /**
85     * Get gpuInfo data.
86     */
87    get gpuInfo() {
88      return this.gpuInfo_;
89    },
90
91    /**
92     * Called from gpu c++ code when GPU Info is updated.
93     */
94    onGpuInfoUpdate: function(gpuInfo) {
95      this.gpuInfo_ = gpuInfo;
96      cr.dispatchSimpleEvent(this, 'gpuInfoUpdate');
97    },
98
99    /**
100     * This function begins a request for the ClientInfo. If it comes back
101     * as undefined, then we will issue the request again in 250ms.
102     */
103    beginRequestClientInfo_: function() {
104      this.callAsync('requestClientInfo', undefined, (function(data) {
105        if (data === undefined) { // try again in 250 ms
106          window.setTimeout(this.beginRequestClientInfo_.bind(this), 250);
107        } else {
108          this.clientInfo_ = data;
109          cr.dispatchSimpleEvent(this, 'clientInfoChange');
110        }
111      }).bind(this));
112    },
113
114    /**
115     * Returns information about the currently runnign Chrome build.
116     */
117    get clientInfo() {
118      return this.clientInfo_;
119    },
120
121    /**
122     * This function checks for new GPU_LOG messages.
123     * If any are found, a refresh is triggered.
124     */
125    beginRequestLogMessages_: function() {
126      this.callAsync('requestLogMessages', undefined,
127          (function(messages) {
128            if (messages.length != this.logMessages_.length) {
129              this.logMessages_ = messages;
130              cr.dispatchSimpleEvent(this, 'logMessagesChange');
131            }
132            // check again in 250 ms
133            window.setTimeout(this.beginRequestLogMessages_.bind(this), 250);
134          }).bind(this));
135    },
136
137    /**
138     * Returns an array of log messages issued by the GPU process, if any.
139     */
140    get logMessages() {
141      return this.logMessages_;
142    }
143
144  };
145
146  return {
147    BrowserBridge: BrowserBridge
148  };
149});
150