1<!DOCTYPE html>
2<html>
3  <!--
4  Copyright 2013 Google Inc.
5
6  Use of this source code is governed by a BSD-style license that can be
7  found in the LICENSE file.
8  -->
9<head>
10  <title>Skia Debugger</title>
11  <link rel="stylesheet" type="text/css" href="debugger.css"/>
12  <script type="text/javascript">
13    "use strict";
14
15    var skia_module = null;  // Global application object.
16    var display_right_panel = null;
17    var display_bottom_row = null;
18    var overview_text = "";
19    var details_text = "Default details text.";
20    var command_list = [];
21    var command_types = {};
22    var no_filter_text = "--Filter By Available Commands--";
23
24    function openFileDialog() {
25      var event = document.createEvent("MouseEvents");
26      event.initEvent("click", true, false);
27      document.getElementById("file_open").dispatchEvent(event);
28    }
29
30    function updateOverviewDetails() {
31      var radio_buttons = document.getElementsByName("overviewdetails_radio");
32      for (var i = 0; i < radio_buttons.length; ++i) {
33        if (radio_buttons[i].checked) {
34          if (radio_buttons[i].value == "details") {
35            document.getElementById("overviewdetails").innerHTML = details_text;
36          } else {
37            document.getElementById("overviewdetails").innerHTML = overview_text;
38          }
39          return;
40        }
41      }
42      // If no radio button is checked, check the "overview" button.
43      for (var i = 0; i < radio_buttons.length; ++i) {
44        if (radio_buttons[i].value == "overview") {
45          radio_buttons[i].checked = true;
46          document.getElementById("overviewdetails").innerHTML = overview_text;
47          return;
48        }
49      }
50    }
51
52    function makeIndentString(indent_amt) {
53      var indent_str = "";
54      for (var i = 0; i < indent_amt; ++i) {
55        indent_str += "--";
56      }
57      return indent_str;
58    }
59
60    function updateCommandList(filter) {
61      var command_list_display = document.getElementById("command_list");
62      command_list_display.options.length = 0;
63      var indent = 0;
64      var indent_str = "";
65      for (var i = 0; i < command_list.length; ++i) {
66        if (command_list[i] == "Restore") {
67          indent--;
68          indent_str = makeIndentString(indent);
69        }
70        if (!filter || filter == no_filter_text || command_list[i] == filter) {
71          command_list_display.options.add(new Option(indent_str + command_list[i], i));
72        }
73        if (command_list[i] == "Save" || command_list[i] == "Save Layer") {
74          indent++;
75          indent_str = makeIndentString(indent);
76        }
77      }
78      command_list_display.selectedIndex = command_list_display.length - 1;
79
80      // TODO(borenet): Should the SKP re-draw when the command list is updated?
81      //commandSelected();
82    }
83
84    function updateFilterList() {
85      var filter_list_display = document.getElementById("command_filter");
86      filter_list_display.options.length = 0;
87      filter_list_display.options.add(new Option(no_filter_text, no_filter_text));
88      for (var command_type in command_types) {
89        if (command_types.hasOwnProperty(command_type)) {
90          filter_list_display.options.add(new Option(command_type, command_type));
91        }
92      }
93    }
94
95    function openFile(event) {
96      document.getElementById("overviewdetails").innerHTML = "";
97      var files = event.target.files;
98      if (files.length != 1) {
99        return;
100      }
101      var file = files[0];
102      var reader = new FileReader();
103      reader.onload = (function(theFile) {
104        return function(e) {
105          var data_prefix = "data:;base64,";
106          skia_module.postMessage("LoadSKP" + e.target.result.slice(data_prefix.length));
107        };
108      })(file);
109      reader.readAsDataURL(file);
110    }
111
112    function toggleInspector() {
113      var right_panel = document.getElementById("right_panel");
114      var bottom_row = document.getElementById("bottom_row");
115      if (right_panel.style.display == display_right_panel) {
116        right_panel.style.display = "none";
117        bottom_row.style.display = "none";
118      } else {
119        right_panel.style.display = display_right_panel;
120        bottom_row.style.display = display_bottom_row;
121      }
122    }
123
124    function onLoad() {
125      document.getElementById("file_open").addEventListener("change", openFile, false);
126      var right_panel = document.getElementById("right_panel");
127      var bottom_row = document.getElementById("bottom_row");
128      display_right_panel = right_panel.style.display;
129      display_bottom_row = bottom_row.style.display;
130      updateOverviewDetails();
131      updateFilterList();
132    }
133
134    // When the module loads, begin running the application.
135    function moduleDidLoad() {
136      skia_module = document.getElementById("skia_nacl");
137      sendMsg("init");
138    }
139
140    function handleMessage(message_event) {
141      var cmd_skdebugf = "SkDebugf:";
142      var cmd_clear_commands = "ClearCommands";
143      var cmd_add_command = "AddCommand:";
144      var cmd_update_commands = "UpdateCommands";
145      var cmd_set_overview = "SetOverview:";
146      var cmd_add_filter_option = "AddFilterOption";
147      if (message_event.data.indexOf(cmd_skdebugf) == 0) {
148        var msg_contents = message_event.data.slice(cmd_skdebugf.length)
149        console.log("Skia: " + msg_contents);
150      } else if (message_event.data.indexOf(cmd_clear_commands) == 0) {
151        command_list = [];
152        command_types = {};
153        updateCommandList();
154        updateFilterList();
155      } else if (message_event.data.indexOf(cmd_add_command) == 0) {
156        var command = message_event.data.slice(cmd_add_command.length);
157        command_list.push(command);
158        if (command_types[command] == undefined) {
159          command_types[command] = 1;
160        } else {
161          command_types[command]++;
162        }
163      } else if (message_event.data.indexOf(cmd_update_commands) == 0) {
164        updateCommandList();
165        updateFilterList();
166      } else if (message_event.data.indexOf(cmd_set_overview) == 0) {
167        overview_text = message_event.data.slice(cmd_set_overview.length);
168        document.getElementById("overview_radio").checked = true;
169        updateOverviewDetails();
170      } else {
171        alert(message_event.data);
172      }
173    }
174
175    // Send a message to the plugin.
176    function sendMsg(msg) {
177      if (skia_module) {
178        //console.log("Sending msg:" + msg);
179        skia_module.postMessage(msg);
180      } else {
181        alert("The Skia module has not properly loaded...");
182      }
183    }
184
185    function commandSelected() {
186      var command_list = document.getElementById("command_list");
187      var selected_index = command_list.options[command_list.selectedIndex].value;
188      if (selected_index >= 0) {
189        sendMsg("CommandSelected:" + selected_index);
190      }
191    }
192
193    function rewind() {
194      command_list.selectedIndex = 0;
195      sendMsg("Rewind");
196    }
197
198    function stepBack() {
199      if (command_list.selectedIndex > 0) {
200        command_list.selectedIndex = command_list.selectedIndex - 1;
201      }
202      sendMsg("StepBack");
203    }
204
205    function pause() {
206      sendMsg("Pause");
207    }
208
209    function stepForward() {
210      if (command_list.selectedIndex < command_list.length - 1) {
211        command_list.selectedIndex = command_list.selectedIndex + 1;
212      }
213      sendMsg("StepForward");
214    }
215
216    function play() {
217      command_list.selectedIndex = command_list.length - 1;
218      sendMsg("Play");
219    }
220  </script>
221</head>
222<body onLoad="javascript:onLoad()">
223<div id="content" class="row-set">
224  <div id="menu" class="row">
225    <ul id="menu-bar" class="dropdown-menu">
226      <li><a href="#">File</a>
227        <ul>
228          <li><a href="#" onClick="javascript:openFileDialog()">Open</a></li>
229          <li><a href="#">Save</a></li>
230          <li><a href="#">Save As</a></li>
231          <li><a href="#">Exit</a></li>
232        </ul>
233      </li>
234      <li><a href="#">Edit</a>
235        <ul>
236          <li><a href="#">Delete Command</a></li>
237          <li><a href="#">Clear Deletes</a></li>
238          <li><a href="#">Set Breakpoint</a></li>
239          <li><a href="#">Clear Breakpoints</a></li>
240        </ul>
241      </li>
242      <li><a href="#">View</a>
243        <ul>
244          <li><a href="#">Breakpoints</a></li>
245          <li><a href="#">Deleted Commands</a></li>
246          <li><a href="#">Zoom In</a></li>
247          <li><a href="#">Zoom Out</a></li>
248        </ul>
249      </li>
250      <li><a href="#">Navigate</a>
251        <ul>
252          <li><a href="#" onClick="javascript:rewind()">Rewind</a></li>
253          <li><a href="#" onClick="javascript:stepBack()">Step Back</a></li>
254          <li><a href="#" onClick="javascript:stepForward()">Step Forward</a></li>
255          <li><a href="#" onClick="javascript:play()">Play</a></li>
256          <li><a href="#" onClick="javascript:pause()">Pause</a></li>
257          <li><a href="#">Go to Line...</a></li>
258        </ul>
259      </li>
260      <li><a href="#">Window</a>
261        <ul>
262          <li><a href="#">Inspector</a></li>
263          <li><a href="#">Directory</a></li>
264        </ul>
265      </li>
266    </ul>
267  </div>
268  <div id="buttons" class="row">
269    <div class="column-set">
270      <div class="column">
271        <button onClick="javascript:rewind()"><img src="icons/rewind.png"/><br/>Rewind</button>
272        <button onClick="javascript:stepBack()"><img src="icons/previous.png"/><br/>Step Back</button>
273        <button onClick="javascript:pause()"><img src="icons/pause.png"/><br/>Pause</button>
274        <button onClick="javascript:stepForward()"><img src="icons/next.png"/><br/>Step Forward</button>
275        <button onClick="javascript:play()"><img src="icons/play.png"/><br/>Play</button>
276      </div>
277      <div class="column">
278        <button onClick="javascript:toggleInspector()"><img src="icons/inspector.png"/><br/>Inspector</button>
279      </div>
280      <div class="column">
281        <button><img src="icons/profile.png"/><br/>Profile</button>
282      </div>
283      <div class="column" style="text-align:right; vertical-align:middle;">
284        <select id="command_filter" onChange="javascript:updateCommandList(this.options[this.selectedIndex].value)"></select>
285        <button onClick="javascript:updateCommandList()"><img src="icons/reload.png" /><br/>Clear Filter</button>
286      </div>
287    </div>
288  </div>
289  <div class="row">
290    <div class="column-set">
291      <div id="left_column" class="column">
292        <div class="row-set">
293          <div id="command_list_div" class="row">
294            <form id="command_list_form">
295              <select id="command_list" size="2" onChange="javascript:commandSelected()">
296                <option value="-1">Commands go here...</option>
297              </select>
298            </form>
299          </div>
300        </div>
301      </div>
302      <div id="right_column" class="row-set">
303        <div id="top_row" class="row">
304          <div id="display_pane" class="column">
305            <div id="listener" style="width:100%; height:100%;">
306              <script type="text/javascript">
307                var listener = document.getElementById('listener');
308                listener.addEventListener('load', moduleDidLoad, true);
309                listener.addEventListener('message', handleMessage, true);
310              </script>
311              <embed name="nacl_module"
312                 id="skia_nacl"
313                 src="debugger.nmf"
314                 type="application/x-nacl"
315                 width="100%"
316                 height="100%"
317                 style="width:100%, height:100%;"/>
318            </div>
319          </div>
320          <div id="right_panel" class="column">
321            <div class="thin_outline">
322              <div id="visibility_filter" class="settings_block">
323                Visibility Filter<br/>
324                <div class="thin_outline">
325                  <form id="visibility_filter_form">
326                    <input type="radio" name="visibility_filter_radio" value="on">On<br/>
327                    <input type="radio" name="visibility_filter_radio" value="off" checked>Off
328                  </form>
329                </div>
330              </div>
331              <div id="command_scrolling" class="settings_block">
332                Command Scrolling Preferences<br/>
333                <div class="thin_outline">
334                  <div class="row-set">
335                    <div class="row">
336                      <div class="column-set">
337                        <div class="column">
338                          Current Command:
339                        </div>
340                        <div class="column" style="text-align:right; width:35%;">
341                          <input type="text" style="width:100%;"/>
342                        </div>
343                      </div>
344                    </div>
345                    <div class="row">
346                      <div class="column-set">
347                        <div class="column">
348                          Command HitBox:
349                        </div>
350                        <div class="column" style="text-align:right; width:35%;">
351                          <input type="text" style="width:100%;"/>
352                        </div>
353                      </div>
354                    </div>
355                  </div>
356                </div>
357              </div>
358              <div id="render_targets" class="settings_block">
359                Render Targets<br/>
360                <div class="thin_outline">
361                  <form id="render_targets_form">
362                    <div class="row-set">
363                      <div class="row">
364                        <div class="column-set">
365                          <div class="column">Raster:</div>
366                          <div class="column" style="text-align:right;">
367                            <input type="checkbox" name="render_targets_checkbox" value="raster" checked/>
368                          </div>
369                        </div>
370                      </div>
371                      <div class="row">
372                        <div class="column-set">
373                          <div class="column" style="padding-left:30px;">Overdraw Viz:</div>
374                          <div class="column" style="text-align:right;">
375                            <input type="checkbox" name="render_targets_checkbox" value="overdraw"/>
376                          </div>
377                        </div>
378                      </div>
379                      <div class="row">
380                        <div class="column-set">
381                          <div class="column">OpenGL</div>
382                          <div class="column" style="text-align:right;">
383                            <input type="checkbox" name="render_targets_checkbox" value="opengl"/>
384                          </div>
385                        </div>
386                      </div>
387                    </div>
388                  </form>
389                </div>
390              </div>
391              <div id="zoom_level" class="settings_block">
392                <div class="thin_outline">
393                  <div class="row-set">
394                    <div class="row">
395                      <div class="column-set">
396                        <div class="column">
397                          Zoom Level:
398                        </div>
399                        <div class="column" style="text-align:right; width:35%;">
400                          <input type="text" style="width:100%;"/>
401                        </div>
402                      </div>
403                    </div>
404                  </div>
405                </div>
406              </div>
407            </div>
408            <div id="small_window_wrapper" class="settings_block">
409              <div class="thin_outline" style="padding:0px;">
410                <div id="small_window">
411                </div>
412              </div>
413            </div>
414          </div>
415        </div>
416        <div id="bottom_row" class="row">
417          <div id="tabview" class="column">
418            <div class="row-set">
419              <div class="row" style="height:5px; overflow:auto;">
420                <form id="overviewdetails_form">
421                  <input type="radio" name="overviewdetails_radio" onChange="javascript:updateOverviewDetails()" id="overview_radio" value="overview" checked>Overview
422                  <input type="radio" name="overviewdetails_radio" onChange="javascript:updateOverviewDetails()" id="details_radio" value="details">Details
423                </form>
424              </div>
425              <div class="row">
426                <div id="overviewdetails"></div>
427              </div>
428            </div>
429          </div>
430          <div id="matrixclip" class="column">
431            Current Matrix
432            <table>
433              <tr>
434                <td><input type="text" id="matrix00" class="matrix" /></td>
435                <td><input type="text" id="matrix01" class="matrix" /></td>
436                <td><input type="text" id="matrix02" class="matrix" /></td>
437              </tr>
438              <tr>
439                <td><input type="text" id="matrix10" class="matrix" /></td>
440                <td><input type="text" id="matrix11" class="matrix" /></td>
441                <td><input type="text" id="matrix12" class="matrix" /></td>
442              </tr>
443              <tr>
444                <td><input type="text" id="matrix20" class="matrix" /></td>
445                <td><input type="text" id="matrix21" class="matrix" /></td>
446                <td><input type="text" id="matrix22" class="matrix" /></td>
447              </tr>
448            </table>
449            Current Clip
450            <table>
451              <tr>
452                <td><input type="text" id="clip00" class="matrix" /></td>
453                <td><input type="text" id="clip01" class="matrix" /></td>
454              </tr>
455              <tr>
456                <td><input type="text" id="clip10" class="matrix" /></td>
457                <td><input type="text" id="clip11" class="matrix" /></td>
458              </tr>
459            </table>
460          </div>
461        </div>
462      </div>
463    </div>
464  </div>
465</div>
466<input type="file" id="file_open" style="display:none;"/>
467</body>
468</html>
469