1// Copyright 2013 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28var worker_scripts = [
29  "../csvparser.js",
30  "../splaytree.js",
31  "../codemap.js",
32  "../consarray.js",
33  "../profile.js",
34  "../profile_view.js",
35  "../logreader.js",
36  "../tickprocessor.js",
37  "composer.js",
38  "gnuplot-4.6.3-emscripten.js"
39];
40
41
42function plotWorker() {
43  var worker = null;
44
45  function initialize() {
46    ui.freeze();
47    worker = new Worker("worker.js");
48    running = false;
49
50    worker.postMessage({ "call" : "load scripts",
51                         "args" : worker_scripts });
52
53    worker.addEventListener("message", function(event) {
54      var call = delegateList[event.data["call"]];
55      call(event.data["args"]);
56    });
57  }
58
59  function scriptLoaded() {
60    ui.thaw();
61  }
62
63  // Public methods.
64  this.run = function(filename,
65                      resx, resy,
66                      distortion,
67                      range_start, range_end) {
68    var args = {
69      'file'        : filename,
70      'resx'        : resx,
71      'resy'        : resy,
72      'distortion'  : distortion,
73      'range_start' : range_start,
74      'range_end'   : range_end
75    }
76    worker.postMessage({ 'call' : 'run', 'args' : args });
77  }
78
79  this.reset = function() {
80    if (worker) worker.terminate();
81    initialize();
82  }
83
84  var delegateList = {
85    "log"         : log,
86    "error"       : logError,
87    "displayplot" : displayplot,
88    "displayprof" : displayprof,
89    "range"       : setRange,
90    "script"      : scriptLoaded,
91    "reset"       : this.reset
92  }
93}
94
95
96function UIWrapper() {
97  var input_elements = ["range_start",
98                        "range_end",
99                        "distortion",
100                        "start",
101                        "file"];
102
103  var other_elements = ["log",
104                        "plot",
105                        "prof",
106                        "instructions",
107                        "credits",
108                        "toggledisplay"];
109
110  for (var i in input_elements) {
111    var id = input_elements[i];
112    this[id] = document.getElementById(id);
113  }
114
115  for (var i in other_elements) {
116    var id = other_elements[i];
117    this[id] = document.getElementById(id);
118  }
119
120  this.freeze = function() {
121    this.plot.style.webkitFilter = "grayscale(1)";
122    this.prof.style.color = "#bbb";
123    for (var i in input_elements) {
124      this[input_elements[i]].disabled = true;
125    }
126  }
127
128  this.thaw = function() {
129    this.plot.style.webkitFilter = "";
130    this.prof.style.color = "#000";
131    for (var i in input_elements) {
132      this[input_elements[i]].disabled = false;
133    }
134  }
135
136  this.reset = function() {
137    this.thaw();
138    this.log.value = "";
139    this.range_start.value = "automatic";
140    this.range_end.value = "automatic";
141    this.toggle("plot");
142    this.plot.src = "";
143    this.prof.value = "";
144  }
145
146  this.toggle = function(mode) {
147    if (mode) this.toggledisplay.next_mode = mode;
148    if (this.toggledisplay.next_mode == "plot") {
149      this.toggledisplay.next_mode = "prof";
150      this.plot.style.display = "block";
151      this.prof.style.display = "none";
152      this.toggledisplay.innerHTML = "Show profile";
153    } else {
154      this.toggledisplay.next_mode = "plot";
155      this.plot.style.display = "none";
156      this.prof.style.display = "block";
157      this.toggledisplay.innerHTML = "Show plot";
158    }
159  }
160
161  this.info = function(field) {
162    var down_arrow = "\u25bc";
163    var right_arrow = "\u25b6";
164    if (field && this[field].style.display != "none") field = null;  // Toggle.
165    this.credits.style.display = "none";
166    this.instructions.style.display = "none";
167    if (!field) return;
168    this[field].style.display = "block";
169  }
170}
171
172
173function log(text) {
174  ui.log.value += text;
175  ui.log.scrollTop = ui.log.scrollHeight;
176}
177
178
179function logError(text) {
180  if (ui.log.value.length > 0 &&
181      ui.log.value[ui.log.value.length-1] != "\n") {
182    ui.log.value += "\n";
183  }
184  ui.log.value += "ERROR: " + text + "\n";
185  ui.log.scrollTop = ui.log.scrollHeight;
186  error_logged = true;
187}
188
189
190function displayplot(args) {
191  if (error_logged) {
192    log("Plot failed.\n\n");
193  } else {
194    log("Displaying plot. Total time: " +
195        (Date.now() - timer) / 1000 + "ms.\n\n");
196    var blob = new Blob([new Uint8Array(args.contents).buffer],
197                        { "type" : "image\/svg+xml" });
198    window.URL = window.URL || window.webkitURL;
199    ui.plot.src = window.URL.createObjectURL(blob);
200  }
201
202  ui.thaw();
203  ui.toggle("plot");
204}
205
206
207function displayprof(args) {
208  if (error_logged) return;
209  ui.prof.value = args;
210  this.prof.style.color = "";
211  ui.toggle("prof");
212}
213
214
215function start(event) {
216  error_logged = false;
217  ui.freeze();
218
219  try {
220    var file = getSelectedFile();
221    var distortion = getDistortion();
222    var range = getRange();
223  } catch (e) {
224    logError(e.message);
225    display();
226    return;
227  }
228
229  timer = Date.now();
230  worker.run(file, kResX, kResY, distortion, range[0], range[1]);
231}
232
233
234function getSelectedFile() {
235  var file = ui.file.files[0];
236  if (!file) throw Error("No valid file selected.");
237  return file;
238}
239
240
241function getDistortion() {
242  var input_distortion =
243      parseInt(ui.distortion.value, 10);
244  if (isNaN(input_distortion)) {
245    input_distortion = ui.distortion.value = 4500;
246  }
247  return input_distortion / 1000000;
248}
249
250
251function getRange() {
252  var input_start =
253      parseInt(ui.range_start.value, 10);
254  if (isNaN(input_start)) input_start = undefined;
255  var input_end =
256      parseInt(ui.range_end.value, 10);
257  if (isNaN(input_end)) input_end = undefined;
258  return [input_start, input_end];
259}
260
261
262function setRange(args) {
263  ui.range_start.value = args.start.toFixed(1);
264  ui.range_end.value = args.end.toFixed(1);
265}
266
267
268function onload() {
269  kResX = 1200;
270  kResY = 600;
271  error_logged = false;
272  ui = new UIWrapper();
273  ui.reset();
274  ui.info(null);
275  worker = new plotWorker();
276  worker.reset();
277}
278
279
280var kResX;
281var kResY;
282var error_logged;
283var ui;
284var worker;
285var timer;
286