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