blob: 602fc0665a5a0ca56bf8e0695b6a84e3c300e19c [file]
<!-- The <debugger-app-sk> custom element declaration.
The main application element for the Skia Debugger.
Attributes:
None.
Events:
None.
Methods:
None.
-->
<link rel=import href="/res/imp/bower_components/paper-drawer-panel/paper-drawer-panel.html">
<link rel=import href="/res/imp/bower_components/paper-header-panel/paper-header-panel.html">
<link rel=import href="/res/imp/bower_components/paper-icon-button/paper-icon-button.html">
<link rel=import href="/res/imp/bower_components/paper-toolbar/paper-toolbar.html">
<link rel=import href="/res/imp/bower_components/paper-checkbox/paper-checkbox.html">
<link rel=import href="/res/imp/bower_components/iron-icons/iron-icons.html">
<link rel=import href="/res/imp/bower_components/iron-icon/iron-icon.html">
<link rel=import href="/res/imp/bower_components/iron-flex-layout/iron-flex-layout.html">
<link rel=import href="/res/imp/bower_components/iron-selector/iron-selector.html">
<link rel=import href="/res/common/imp/9/canvas-layers.html">
<link rel=import href="/res/common/imp/9/crosshair.html">
<link rel=import href="/res/common/imp/9/details-summary.html">
<link rel=import href="/res/common/imp/9/zoom.html">
<link rel=import href="/res/common/imp/9/play.html">
<link rel=import href="/res/common/imp/9/dbg-info.html">
<link rel=import href="/res/common/imp/9/error-toast-sk.html">
<dom-module id="debugger-app-sk">
<style type="text/css" media="screen">
:root {
--paper-toolbar-background: #1f78b4;
}
:host {
display: block;
height: 100%
}
#content {
margin: 1em;
}
op-sk {
display: block;
}
details-sk.iron-selected {
background: #eee;
}
#selector {
overflow-y: scroll;
height: 80vh;
position: relative;
}
play-sk {
margin: 5px auto;
}
#center {
overflow: hidden;
}
#rendered {
margin: 0 10px;
overflow: auto;
}
* {
font-family: Helvetica,Arial,'Bitstream Vera Sans',sans-serif;
}
.hidden {
display: none;
}
.shortcuts {
margin-left: 3em;
margin-bottom: 2em;
}
.shortcuts td {
padding-left: 1em;
}
.shortcuts tr {
padding-bottom: 0.5em;
}
#colors {
margin: 1em 0;
}
#colorBreakPoint {
margin-left: 3em;
}
#download {
margin: 0 3em;
color: #1f78b4;
}
dbg-info-sk {
margin-left: 3em;
margin-bottom: 1em;
display: block;
}
</style>
<template>
<paper-header-panel>
<paper-toolbar>
<div>Skia Debugger</div>
</paper-toolbar>
<div id=content>
<h2>Upload an SKP here.</h2>
<div class="layout horizontal">
<form enctype="multipart/form-data" method="post" id=post_skp action="/new" name="fileinfo">
<label>SKP to send:</label>
<input type="file" name="file" required />
<input type="submit" value="Upload" />
</form>
<a href="/download" id=download class=hidden>Download</a>
</div>
<hr/>
<div class="layout horizontal">
<div id=left class="layout vertical flex-1">
<play-sk id=play></play-sk>
<iron-selector id=selector>
<template is="dom-repeat" items="{{cmd.commands}}" as="command">
<op-sk op="{{command}}" index="{{index}}"></op-sk>
</template>
</iron-selector>
</div>
<div id=center class="layout vertical flex-3">
<div id=rendered>
<canvas-layers-sk layers='["crosshair"]' id=layers on-tap="_crosshairClick">
<img id=img src="" class=hidden>
</canvas-layers-sk>
<crosshair-sk id=crosshair target=layers name=crosshair update_on=move></crosshair-sk>
</div>
</div>
<div id=right class="layout vertical flex-2">
<details-sk open>
<summary-sk>
Clip and Matrix
</summary-sk>
<dbg-info-sk info="{{ info }}"></dbg-info-sk>
</details-sk>
<div id=position><b>Postion:</b> ({{ x }}, {{ y }})</div>
<div id=colors><b>Color:</b> {{ rgb }} {{ hex }} </div>
<div>
<paper-checkbox disabled id=colorBreakPoint>Break on change.</paper-checkbox> <span id=prevColor></span>
</div>
<details-sk id=keyboardshortcuts class=hidden>
<summary-sk>
Keyboard shortcuts
</summary-sk>
<table class=shortcuts>
<tr><th>H</th><td>Left</td></tr>
<tr><th>L</th><td>Right</td></tr>
<tr><th>J</th><td>Down</td></tr>
<tr><th>K</th><td>Up</td></tr>
<tr><td colspan=2>Click the image again to turn off keyboard navigation.</td></tr>
</table>
</details-sk>
<zoom-sk source=img pixels=20 id=zoom></zoom-sk>
</div>
</div>
<error-toast-sk></error-toast-sk>
</div>
</paper-header-panel>
</template>
</dom-module>
<script>
Polymer({
is: "debugger-app-sk",
ready: function() {
// _targetIndex is the index of the op we are in the process of moving to.
// That is, we've requested to move to this op, but the image might not
// be loaded yet.
this._targetIndex = 0;
// Load the test image served by the debugger.
this._setCacheBreakingURL();
this.$.post_skp.action= window.location.origin + "/new";
// Can't set this as an attribute directly on iron-selector. Bah.
this.$.selector.selectedAttribute = "selected";
this.$.selector.addEventListener('iron-select', function(e) {
// Only force reloading the image if necessary.
if (this._targetIndex != e.detail.item.index) {
this._targetIndex = e.detail.item.index;
this._setCacheBreakingURL();
}
}.bind(this));
this._refreshPage();
this.$.crosshair.addEventListener('crosshair', function(e) {
this.$.zoom.x = e.detail.x;
this.$.zoom.y = e.detail.y;
}.bind(this));
this.$.zoom.addEventListener('zoom-point', function(e) {
if ( this.$.colorBreakPoint.disabled == false
&& this.$.colorBreakPoint.checked
&& this.hex != e.detail.hex) {
// We've hit a breakpoint. Stop the play and show the change in color.
this.$.prevColor.textContent = this.hex + " -> " + e.detail.hex;
this.$.play.mode = "pause";
}
this.set("rgb", e.detail.rgb);
this.set("hex", e.detail.hex);
this.set("x", e.detail.x);
this.set("y", e.detail.y);
}.bind(this));
this.$.zoom.addEventListener('zoom-loaded', function(e) {
this.$.play.movedTo(this._targetIndex);
}.bind(this));
this.$.img.addEventListener('load', function() {
this.$.download.href = window.location.origin + "/download";
this.$.download.classList.remove("hidden");
this.$.selector.scrollTop = this.$.selector.items[this._targetIndex].offsetTop;
this.$.selector.select(this._targetIndex);
}.bind(this));
this.$.play.addEventListener('moveto', function(e) {
this._targetIndex = e.detail.index;
this._setCacheBreakingURL();
}.bind(this));
this.$.play.addEventListener('mode-changed-manually', function(e) {
// Clear the breakpoint info if the user presses a button.
this.$.prevColor.textContent = "";
}.bind(this));
},
properties: {
// The commands that make up the skp.
cmd: {
type: Object,
value: function() { return { commands: [] } },
reflectToAttribute: false,
},
},
attached: function() {
document.body.addEventListener('keydown', this._keyDownHandler.bind(this), true);
},
_refreshPage: function() {
this.$.img.classList.remove("hidden");
this._setCacheBreakingURL();
sk.get("/info").then(JSON.parse).then(function(json) {
this.set('info', json);
}.bind(this)).catch(sk.errorMessage);
sk.get("/cmd").then(JSON.parse).then(function(json) {
this.set('cmd', this._addDepth(json));
this.$.play.size = json.commands.length;
this._targetIndex = json.commands.length - 1;
this._setCacheBreakingURL();
}.bind(this)).catch(sk.errorMessage);
},
_setCacheBreakingURL: function() {
var path = "/img/" + this._targetIndex + "?";
sk.get("/info/" + this._targetIndex).then(JSON.parse).then(function(json) {
this.set('info', json);
}.bind(this)).catch(sk.errorMessage);
this.$.img.src = window.location.origin + path + "?" + new Date().getTime();
},
_crosshairClick: function() {
if (this.$.crosshair.update_on === "move") {
this.$.crosshair.update_on = "click";
this.$.colorBreakPoint.disabled = false;
this.$.keyboardshortcuts.classList.remove("hidden");
} else {
this.$.crosshair.update_on = "move";
this.$.colorBreakPoint.disabled = true;
this.$.keyboardshortcuts.classList.add("hidden");
}
},
_keyDownHandler: function(e) {
var c = String.fromCharCode(e.keyCode);
switch (c) {
case "J":
this.$.crosshair.y = this.$.crosshair.y+1;
break;
case "K":
this.$.crosshair.y = this.$.crosshair.y-1;
break;
case "H":
this.$.crosshair.x = this.$.crosshair.x-1;
break;
case "L":
this.$.crosshair.x = this.$.crosshair.x+1;
break;
}
if ("JKHL".indexOf(c) != -1 ) {
e.stopPropagation();
}
},
_json: function(s) {
return JSON.stringify(s, null, 2);
},
// _addDepth cycles through the commands and set a depth based on Save/Restore pairs.
_addDepth: function(cmd) {
var commands = cmd.commands;
var depth = 0;
for (var i = 0; i < commands.length; i++) {
commands[i]._depth = depth;
if (commands[i].command == "Save") {
depth++;
} else if (commands[i].command == "Restore") {
depth--;
commands[i]._depth = depth;
}
}
return cmd;
}
});
</script>