blob: dd27df97692c5ac1b4f5dffa777551db6f3d4308 [file] [log] [blame]
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Forma test report</title>
<style>
body {
font-family: "Segoe UI", Arial, sans-serif;
}
.overview {
padding: 0 1rem;
margin-bottom: 1rem;
}
.testcase {
padding: 0 1rem;
margin-bottom: 1rem;
border: 1px solid transparent;
border-radius: 0.25rem;
}
.status_KO {
color: #721c24;
background-color: #f8d7da;
border-color: #f5c6cb;
}
.status_OK {
color: #155724;
background-color: #d4edda;
border-color: #c3e6cb;
}
h3 {
margin: 10px 0;
}
pre {
margin-top: 0;
}
.note {
height: 2em;
}
.superpose {
position: relative;
width: 256px;
height: 256px;
border: 2px solid #000;
margin: 4px;
background-color: #ffffff;
}
.cpu_gpu_pair {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.diff {
display: flex;
flex-direction: row
}
.viewer {
display: flex;
flex-direction: column;
align-items: center;
image-rendering: pixelated;
}
.hide_overlay .overlay_canvas {
visibility: hidden;
}
.hide_background .background_canvas {
visibility: hidden;
}
.superpose canvas {
position: absolute;
top: 0;
left: 0;
}
img {
display: none;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 87.5%;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
.shortcuts {
margin: 1em;
text-align: right;
}
.shortcuts div {
display: inline-block;
}
.overview {
clear: both;
}
</style>
</head>
<body>
<div>
<h1 style="float:left">Forma test report</h1>
<div class="shortcuts">
<div><kbd>b</kbd> toggle background draw checker |</div>
<div><kbd>d</kbd> toggle diff overlay.</div>
</div>
</div>
<div class="overview">
<div class="template"><a class="status_{status}" href="#{name}">{name}</a></div>
</div>
<div id="root" class="hide_overlay">
<div class="template">
<div class="testcase status_{status}" id="{name}">
<h3>{name}</h3>
<pre>{message}</pre>
<div class="cpu_gpu_pair">
<div class="diff">
<div class="viewer cpu_actual">
CPU Actual
<div class="superpose">
<canvas width="256" height="256" class="background_canvas"></canvas>
<canvas width="256" height="256" class="image_canvas"></canvas>
<canvas width="256" height="256" class="overlay_canvas"></canvas>
</div>
<img src="{cpu_actual}"/>
<pre class="note"></pre>
</div>
<div class="viewer" class="cpu_expected">
CPU Expected
<div class="superpose">
<canvas width="256" height="256" class="background_canvas"></canvas>
<canvas width="256" height="256" class="image_canvas"></canvas>
<canvas width="256" height="256" class="overlay_canvas"></canvas>
</div>
<img src="{cpu_expected}"/>
<pre class="note"></pre>
</div>
</div>
<div class="diff">
<div class="viewer" class="gpu_actual">
GPU Actual
<div class="superpose">
<canvas width="256" height="256" class="background_canvas"></canvas>
<canvas width="256" height="256" class="image_canvas"></canvas>
<canvas width="256" height="256" class="overlay_canvas"></canvas>
</div>
<img src="{gpu_actual}"/>
<pre class="note"></pre>
</div>
<div class="viewer" class="gpu_expected">
GPU Expected
<div class="superpose">
<canvas width="256" height="256" class="background_canvas"></canvas>
<canvas width="256" height="256" class="image_canvas"></canvas>
<canvas width="256" height="256" class="overlay_canvas"></canvas>
</div>
<img src="{gpu_expected}"/>
<pre class="note"></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// Scale factor expressed as a bit shift.
const shift = 2;
let entries = [/* generated */];
// Get issues first and the sort by name.
entries.sort((a, b) => a.name.localeCompare(b.name));
entries.sort((a, b) => a.status.localeCompare(b.status));
// Instanciate templates.
for (const template of Array.from(document.getElementsByClassName('template'))) {
const parentNode = template.parentNode;
parentNode.removeChild(template);
for (const entry of entries) {
const elem = document.createElement("div");
var html = template.innerHTML
for (const property in entry) html = html.replaceAll(`{${property}}`, entry[property]);
elem.innerHTML = html;
parentNode.appendChild(elem);
}
console.log(template);
}
// Show color picker on hover.
document.addEventListener('mousemove', e => {
const get_row = canvas => canvas.closest(".testcase");
const get_viewer = canvas => canvas.closest(".viewer");
if (e.path[0].tagName !== "CANVAS") return;
const row = get_row(e.path[0]);
for (const canvas of Array.from(document.getElementsByClassName("image_canvas"))) {
const note = get_viewer(canvas).getElementsByClassName("note")[0];
if (get_row(canvas).isSameNode(row)) {
try {
const data = canvas.getContext("2d").getImageData(e.offsetX, e.offsetY, 1, 1).data;
const rgba = v => data[v].toString().padStart(3, " ")
note.innerHTML = `(x: ${e.offsetX >> shift}, y: ${e.offsetY >> shift})\nr: ${rgba(0)}, g: ${rgba(1)}, b: ${rgba(2)}, a: ${rgba(3)}`;
} catch (error) {
console.warn(error);
}
} else {
note.innerHTML = "";
}
}
});
// Toggle debug view on key press.
document.addEventListener('keypress', e => {
console.log(e);
let elem = document.getElementById("root");
if (e.key == "b") elem.classList.toggle("hide_background");
if (e.key == "d") elem.classList.toggle("hide_overlay");
});
function drawChecker(canvas) {
const rows = 8, cols = 8;
const w = canvas.clientWidth, h = canvas.clientHeight;
const ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, w, h);
ctx.fillStyle = "LightGray";
for (let r = 0; r < rows; r++) {
for (let c = r % 2; c < cols; c += 2) {
ctx.beginPath();
ctx.rect(w * r / rows, h * c / cols, w / rows, h / cols);
ctx.fill();
}
}
}
// Load the impage into canvas for inspection, and compute diffs.
window.onload = function () {
for (const elem of Array.from(document.getElementsByClassName("viewer"))) {
const img = elem.getElementsByTagName("img")[0];
if (img.getAttribute("src") === "null") continue;
const context = elem.getElementsByClassName("image_canvas")[0].getContext("2d");
context.webkitImageSmoothingEnabled = false;
context.mozImageSmoothingEnabled = false;
context.msImageSmoothingEnabled = false;
context.imageSmoothingEnabled = false;
context.drawImage(img, 0, 0, 256, 256);
}
for (const canvas of Array.from(document.getElementsByClassName("background_canvas"))) {
drawChecker(canvas);
}
for (const diff of Array.from(document.getElementsByClassName("diff"))) {
const canvases = diff.getElementsByClassName("image_canvas");
const w = canvases[0].clientWidth, h = canvases[0].clientHeight;
let id0 = canvases[0].getContext("2d").getImageData(0, 0, w, h);
let id1 = canvases[1].getContext("2d").getImageData(0, 0, w, h);
let d0 = id0.data, d1 = id1.data;
let colorize = (sum) => {
if (sum > 8) return [255, 60, 0, 128];
else if (sum > 4) return [255, 140, 0, 128];
return [0, 0, 0, 0];
}
let delta = (i) => Math.abs(d0[i] - d1[i]);
for (let i = w * h * 4 - 4; i >= 0; i -= 4) {
const sum = delta(i) + delta(i + 1) + delta(i + 2) + delta(i + 3);
[d0[i], d0[i + 1], d0[i + 2], d0[i + 3]] = colorize(sum);
}
for (const canvas of Array.from(diff.getElementsByClassName("overlay_canvas"))) {
canvas.getContext("2d").putImageData(id0, 0, 0);
}
}
};
</script>
</body>
</html>