[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc
mihaip at chromium.org
mihaip at chromium.org
Wed Dec 22 16:02:36 UTC 2010
The following commit has been merged in the debian/experimental branch:
commit 39d687f262a308d02835dc2180b224c2b1351a3c
Author: mihaip at chromium.org <mihaip at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date: Thu Nov 18 00:42:24 2010 +0000
2010-11-17 Mihai Parparita <mihaip at chromium.org>
Reviewed by Tony Chang.
Rebaseline server: add loupe for image diffs
https://bugs.webkit.org/show_bug.cgi?id=49692
Add a loupe (magnifiying glass) for inspecting image diffs. Shows an
enlarged area of the expected, actual and diff images side by side.
* Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html:
* Scripts/webkitpy/tool/commands/data/rebaselineserver/loupe.js: Added.
* Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js:
* Scripts/webkitpy/tool/commands/rebaselineserver.py:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@72262 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebKitTools/ChangeLog b/WebKitTools/ChangeLog
index a2c829e..663f551 100644
--- a/WebKitTools/ChangeLog
+++ b/WebKitTools/ChangeLog
@@ -1,3 +1,18 @@
+2010-11-17 Mihai Parparita <mihaip at chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Rebaseline server: add loupe for image diffs
+ https://bugs.webkit.org/show_bug.cgi?id=49692
+
+ Add a loupe (magnifiying glass) for inspecting image diffs. Shows an
+ enlarged area of the expected, actual and diff images side by side.
+
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/loupe.js: Added.
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js:
+ * Scripts/webkitpy/tool/commands/rebaselineserver.py:
+
2010-11-17 Steve Falkenburg <sfalken at apple.com>
Reviewed by Adam Roben.
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html
index afd2fff..8cc48c1 100644
--- a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html
+++ b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html
@@ -33,6 +33,7 @@
<title>Layout Test Rebaseline Server</title>
<link rel="stylesheet" href="/main.css" type="text/css">
<script src="/util.js"></script>
+ <script src="/loupe.js"></script>
<script src="/main.js"></script>
</head>
<body class="loading">
@@ -100,5 +101,39 @@
</tbody>
</table>
+<table id="loupe" style="display: none">
+ <tr>
+ <td colspan="3" id="loupe-info">
+ <span id="loupe-close" class="link">Close</span>
+ <label>Coordinate: <span id="loupe-coordinate"></span></label>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div class="loupe-container">
+ <canvas id="expected-loupe" width="210" height="210"></canvas>
+ <div class="center-highlight"></div>
+ </div>
+ </td>
+ <td>
+ <div class="loupe-container">
+ <canvas id="actual-loupe" width="210" height="210"></canvas>
+ <div class="center-highlight"></div>
+ </div>
+ </td>
+ <td>
+ <div class="loupe-container">
+ <canvas id="diff-loupe" width="210" height="210"></canvas>
+ <div class="center-highlight"></div>
+ </div>
+ </td>
+ </tr>
+ <tr id="loupe-colors">
+ <td><label>Exp. color: <span id="expected-loupe-color"></span></label></td>
+ <td><label>Actual color: <span id="actual-loupe-color"></span></label></td>
+ <td><label>Diff color: <span id="diff-loupe-color"></span></label></td>
+ </tr>
+</table>
+
</body>
</html>
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/loupe.js b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/loupe.js
new file mode 100644
index 0000000..41f977a
--- /dev/null
+++ b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/loupe.js
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+var LOUPE_MAGNIFICATION_FACTOR = 10;
+
+function Loupe()
+{
+ this._node = $('loupe');
+ this._currentCornerX = -1;
+ this._currentCornerY = -1;
+
+ var self = this;
+
+ function handleOutputClick(event) { self._handleOutputClick(event); }
+ $('expected-image').addEventListener('click', handleOutputClick);
+ $('actual-image').addEventListener('click', handleOutputClick);
+ $('diff-canvas').addEventListener('click', handleOutputClick);
+
+ function handleLoupeClick(event) { self._handleLoupeClick(event); }
+ $('expected-loupe').addEventListener('click', handleLoupeClick);
+ $('actual-loupe').addEventListener('click', handleLoupeClick);
+ $('diff-loupe').addEventListener('click', handleLoupeClick);
+
+ function hide(event) { self.hide(); }
+ $('loupe-close').addEventListener('click', hide);
+}
+
+Loupe.prototype._handleOutputClick = function(event)
+{
+ // The -1 compensates for the border around the image/canvas.
+ this._showFor(event.offsetX - 1, event.offsetY - 1);
+};
+
+Loupe.prototype._handleLoupeClick = function(event)
+{
+ var deltaX = Math.floor(event.offsetX/LOUPE_MAGNIFICATION_FACTOR);
+ var deltaY = Math.floor(event.offsetY/LOUPE_MAGNIFICATION_FACTOR);
+
+ this._showFor(
+ this._currentCornerX + deltaX, this._currentCornerY + deltaY);
+}
+
+Loupe.prototype.hide = function()
+{
+ this._node.style.display = 'none';
+};
+
+Loupe.prototype._showFor = function(x, y)
+{
+ this._fillFromImage(x, y, 'expected', $('expected-image'));
+ this._fillFromImage(x, y, 'actual', $('actual-image'));
+ this._fillFromCanvas(x, y, 'diff', $('diff-canvas'));
+
+ this._node.style.display = '';
+};
+
+Loupe.prototype._fillFromImage = function(x, y, type, sourceImage)
+{
+ var tempCanvas = document.createElement('canvas');
+ tempCanvas.width = sourceImage.width;
+ tempCanvas.height = sourceImage.height;
+ var tempContext = tempCanvas.getContext('2d');
+
+ tempContext.drawImage(sourceImage, 0, 0);
+
+ this._fillFromCanvas(x, y, type, tempCanvas);
+};
+
+Loupe.prototype._fillFromCanvas = function(x, y, type, canvas)
+{
+ var context = canvas.getContext('2d');
+ var sourceImageData =
+ context.getImageData(0, 0, canvas.width, canvas.height);
+
+ var targetCanvas = $(type + '-loupe');
+ var targetContext = targetCanvas.getContext('2d');
+ targetContext.fillStyle = 'rgba(255, 255, 255, 1)';
+ targetContext.fillRect(0, 0, targetCanvas.width, targetCanvas.height);
+
+ var sourceXOffset = (targetCanvas.width/LOUPE_MAGNIFICATION_FACTOR - 1)/2;
+ var sourceYOffset = (targetCanvas.height/LOUPE_MAGNIFICATION_FACTOR - 1)/2;
+
+ function readPixelComponent(x, y, component) {
+ var offset = (y * sourceImageData.width + x) * 4 + component;
+ return sourceImageData.data[offset];
+ }
+
+ for (var i = -sourceXOffset; i <= sourceXOffset; i++) {
+ for (var j = -sourceYOffset; j <= sourceYOffset; j++) {
+ var sourceX = x + i;
+ var sourceY = y + j;
+
+ var sourceR = readPixelComponent(sourceX, sourceY, 0);
+ var sourceG = readPixelComponent(sourceX, sourceY, 1);
+ var sourceB = readPixelComponent(sourceX, sourceY, 2);
+ var sourceA = readPixelComponent(sourceX, sourceY, 3)/255;
+ sourceA = Math.round(sourceA * 10)/10;
+
+ var targetX = (i + sourceXOffset) * LOUPE_MAGNIFICATION_FACTOR;
+ var targetY = (j + sourceYOffset) * LOUPE_MAGNIFICATION_FACTOR;
+ var colorString =
+ sourceR + ', ' + sourceG + ', ' + sourceB + ', ' + sourceA;
+ targetContext.fillStyle = 'rgba(' + colorString + ')';
+ targetContext.fillRect(
+ targetX, targetY,
+ LOUPE_MAGNIFICATION_FACTOR, LOUPE_MAGNIFICATION_FACTOR);
+
+ if (i == 0 && j == 0) {
+ $('loupe-coordinate').textContent = sourceX + ', ' + sourceY;
+ $(type + '-loupe-color').textContent = colorString;
+ }
+ }
+ }
+
+ this._currentCornerX = x - sourceXOffset;
+ this._currentCornerY = y - sourceYOffset;
+};
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css
index bd2cd98..6e90fe4 100644
--- a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css
+++ b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css
@@ -120,6 +120,7 @@ a, .link {
border: solid 1px #ddd;
-webkit-user-select: none;
-webkit-user-drag: none;
+ cursor: crosshair;
}
#image-outputs img.loading,
@@ -148,3 +149,65 @@ a, .link {
margin: 0;
background: #eee;
}
+
+#loupe {
+ -webkit-box-shadow: 2px 2px 5px rgba(0, 0, 0, .5);
+ position: absolute;
+ width: 634px;
+ top: 50%;
+ left: 50%;
+ margin-left: -151px;
+ margin-top: -50px;
+ background: #fff;
+ border-spacing: 0;
+ border-collapse: collapse;
+}
+
+#loupe td {
+ padding: 0;
+ border: solid 1px #ccc;
+}
+
+#loupe label {
+ color: #999;
+ padding-right: 1em;
+}
+
+#loupe span {
+ color: #000;
+ font-weight: bold;
+}
+
+#loupe canvas {
+ cursor: crosshair;
+}
+
+#loupe #loupe-close {
+ float: right;
+}
+
+#loupe #loupe-info {
+ background: #eee;
+ padding: .3em .5em;
+}
+
+#loupe #loupe-colors td {
+ text-align: center;
+}
+
+#loupe .loupe-container {
+ position: relative;
+ width: 210px;
+ height: 210px;
+}
+
+#loupe .center-highlight {
+ position: absolute;
+ width: 10px;
+ height: 10px;
+ top: 50%;
+ left: 50%;
+ margin-left: -5px;
+ margin-top: -5px;
+ outline: solid 1px #999;
+}
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js
index 21d18b7..fa037b3 100644
--- a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js
+++ b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js
@@ -34,6 +34,7 @@ var results;
var testsByFailureType = {};
var testsByDirectory = {};
var selectedTests = [];
+var loupe;
function main()
{
@@ -43,6 +44,8 @@ function main()
$('next-test').addEventListener('click', nextTest);
$('previous-test').addEventListener('click', previousTest);
+ loupe = new Loupe();
+
document.addEventListener('keydown', function(event) {
if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
return;
@@ -210,6 +213,7 @@ function selectTest()
}
updateState();
+ loupe.hide();
}
function updateState()
@@ -241,7 +245,7 @@ function displayImageResults(testName)
&& currentExpectedImageTest == testName) {
return;
}
-
+
function displayImageResult(mode, callback) {
var image = $(mode);
image.className = 'loading';
@@ -274,45 +278,45 @@ function displayImageResults(testName)
function updateImageDiff() {
if (currentExpectedImageTest != currentActualImageTest)
return;
-
+
var expectedImage = $('expected-image');
var actualImage = $('actual-image');
-
+
function getImageData(image) {
var imageCanvas = document.createElement('canvas');
imageCanvas.width = image.width;
imageCanvas.height = image.height;
imageCanvasContext = imageCanvas.getContext('2d');
-
+
imageCanvasContext.fillStyle = 'rgba(255, 255, 255, 1)';
imageCanvasContext.fillRect(
0, 0, image.width, image.height);
-
+
imageCanvasContext.drawImage(image, 0, 0);
return imageCanvasContext.getImageData(
- 0, 0, image.width, image.height);
+ 0, 0, image.width, image.height);
}
-
+
var expectedImageData = getImageData(expectedImage);
var actualImageData = getImageData(actualImage);
-
+
var diffCanvas = $('diff-canvas');
var diffCanvasContext = diffCanvas.getContext('2d');
var diffImageData =
diffCanvasContext.createImageData(diffCanvas.width, diffCanvas.height);
-
+
// Avoiding property lookups for all these during the per-pixel loop below
// provides a significant performance benefit.
var expectedWidth = expectedImage.width;
var expectedHeight = expectedImage.height;
var expected = expectedImageData.data;
-
+
var actualWidth = actualImage.width;
var actual = actualImageData.data;
-
+
var diffWidth = diffImageData.width;
var diff = diffImageData.data;
-
+
for (var x = 0; x < expectedWidth; x++) {
for (var y = 0; y < expectedHeight; y++) {
var expectedOffset = (y * expectedWidth + x) * 4;
@@ -334,7 +338,7 @@ function updateImageDiff() {
}
}
}
-
+
diffCanvasContext.putImageData(
diffImageData,
0, 0,
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py b/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py
index 3aa464a..abb2af4 100644
--- a/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py
+++ b/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py
@@ -58,6 +58,7 @@ class RebaselineHTTPServer(BaseHTTPServer.HTTPServer):
class RebaselineHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
STATIC_FILE_NAMES = frozenset([
"index.html",
+ "loupe.js",
"main.js",
"main.css",
"util.js",
--
WebKit Debian packaging
More information about the Pkg-webkit-commits
mailing list