Bug 775174 - Add invalidation timeline to reftest analyzer. r=dbaron
☠☠ backed out by f90f53a4d6b5 ☠ ☠
authorMatt Woodrow <mwoodrow@mozilla.com>
Sat, 28 Jul 2012 13:46:42 +1200
changeset 100802 6718d4c7b6c1e0ada1f1e5996d8022f59b05807a
parent 100801 7f7ccabe2e5d4703c83564b33e812fba93831d92
child 100803 8253f91b0eef44dc892eb61ae8c1e69caa927f64
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersdbaron
bugs775174
milestone17.0a1
Bug 775174 - Add invalidation timeline to reftest analyzer. r=dbaron
layout/tools/reftest/reftest-analyzer.xhtml
layout/tools/reftest/reftest.js
--- a/layout/tools/reftest/reftest-analyzer.xhtml
+++ b/layout/tools/reftest/reftest-analyzer.xhtml
@@ -25,21 +25,22 @@ Features to add:
 <head>
   <title>Reftest analyzer</title>
   <style type="text/css"><![CDATA[
 
   html, body { margin: 0; }
   html { padding: 0; }
   body { padding: 4px; }
 
-  #pixelarea, #itemlist, #images { position: absolute; }
+  #pixelarea, #itemlist, #images, #updates { position: absolute; }
   #itemlist, #images { overflow: auto; }
   #pixelarea { top: 0; left: 0; width: 320px; height: 84px; overflow: visible }
   #itemlist { top: 84px; left: 0; width: 320px; bottom: 0; }
   #images { top: 0; bottom: 0; left: 320px; right: 0; }
+  #updates { top: 30px; bottom: 0; left: 1150px; right: 0; }
 
   #leftpane { width: 320px; }
   #images { position: fixed; top: 10px; left: 340px; }
 
   form#imgcontrols { margin: 0; display: block; }
 
   #itemlist > table { border-collapse: collapse; }
   #itemlist > table > tbody > tr > td { border: 1px solid; padding: 1px; }
@@ -201,44 +202,74 @@ function log_pasted() {
   process_log(log);
 }
 
 var gTestItems;
 
 function process_log(contents) {
   var lines = contents.split(/[\r\n]+/);
   gTestItems = [];
+  var logTestIndex = 0;
   for (var j in lines) {
     var line = lines[j];
     var match = line.match(/^(?:NEXT ERROR )?REFTEST (.*)$/);
     if (!match)
       continue;
     line = match[1];
     match = line.match(/^(TEST-PASS|TEST-UNEXPECTED-PASS|TEST-KNOWN-FAIL|TEST-UNEXPECTED-FAIL|TEST-DEBUG-INFO)(\(EXPECTED RANDOM\)|) \| ([^\|]+) \|(.*)/);
     if (match) {
       var state = match[1];
       var random = match[2];
       var url = match[3];
-                        var extra = match[4];
+      var extra = match[4];
       gTestItems.push(
         {
           pass: !state.match(/DEBUG-INFO$|FAIL$/),
           // only one of the following three should ever be true
           unexpected: !!state.match(/^TEST-UNEXPECTED/),
           random: (random == "(EXPECTED RANDOM)"),
           skip: (extra == " (SKIP)"),
           url: url,
-          images: []
+          images: [],
+          updates1: [],
+          updates2: []
         });
+      logTestIndex = 0;
       continue;
     }
     match = line.match(/^  IMAGE[^:]*: (.*)$/);
     if (match) {
       var item = gTestItems[gTestItems.length - 1];
       item.images.push(match[1]);
+      continue;
+    }
+    match = line.match(/^INFO \| Saved log: START (.*)$/);
+    if (match) {
+      logTestIndex++;
+      continue;
+    }
+    match = line.match(/^INFO \| Saved log: DoDrawWindow snapshot: (.*)$/);
+    if (match) {
+      var item = gTestItems[gTestItems.length - 1];
+      if (logTestIndex == 1) {
+        item.updates1[item.updates1.length - 1].image = match[1];
+      } else {
+        item.updates2[item.updates2.length - 1].image = match[1];
+      }
+      continue;
+    }
+    match = line.match(/^INFO \| Saved log: (.*)$/);
+    if (match) {
+      var item = gTestItems[gTestItems.length - 1];
+      if (logTestIndex == 1) {
+        item.updates1.push({ text: match[1], image: ""});
+      } else {
+        item.updates2.push({ text: match[1], image: ""});
+      }
+      continue;
     }
   }
 
   build_viewer();
 }
 
 function build_viewer() {
   if (gTestItems.length == 0) {
@@ -329,29 +360,107 @@ function show_images(i) {
   } else {
     ID("imgcontrols").style.display = "";
 
     ID("image2").setAttributeNS(XLINK_NS, "xlink:href", item.images[1]);
     // Making the href be #image2 doesn't seem to work
     ID("feimage2").setAttributeNS(XLINK_NS, "xlink:href", item.images[1]);
   }
 
+  while (ID("update-contents").firstChild) {
+    ID("update-contents").removeChild(ID("update-contents").firstChild);
+  }
+
+  var paintCount = 0;
+  var insertUpdates = function(node, element, index) {
+    var tr = document.createElement("tr");
+    var td = document.createElement("td");
+    var text = document.createTextNode(element.text);
+    var image = element.image;
+    var count = paintCount;
+    if (image != "") {
+      tr.onclick = function() { clickLogData(image, index == -1 ? -1 : count); };
+      var a = document.createElement("a");
+      a.href = "#nothing" + index;
+      if (index != -1) {
+        a.appendChild(document.createTextNode("Paint " + paintCount++ + ": "));
+      }
+      a.appendChild(text);
+      td.appendChild(a);
+    } else {
+      td.appendChild(text);
+    }
+    td.className = "url";
+    tr.appendChild(td);
+    node.appendChild(tr);
+  };
+
+  for (var i = 0; i < item.updates1.length; ++i) {
+    insertUpdates(ID("update-contents"), item.updates1[i], i);
+  }
+  paintCount = 0;
+  insertUpdates(ID("update-contents"), { text: "Final Image", image: item.images[0] }, -1);
+  ID("update-contents").style.display = "";
+  ID("update-1-current-image").style.display = "";
+  
+  for (var i = 0; i < item.updates2.length; ++i) {
+    insertUpdates(ID("update-contents2"), item.updates2[i], i);
+  }
+  insertUpdates(ID("update-contents2"), { text: "Final Image", image: item.images[1] }, -1);
+  ID("update-contents2").style.display = "none";
+  ID("update-2-current-image").style.display = "none";
+
   cell.style.display = "";
 
   get_image_data(item.images[0], function(data) { gImage1Data = data });
   get_image_data(item.images[1], function(data) { gImage2Data = data });
 }
 
+function clickLogData(data, count) {
+  if (ID("image1").style.display == "") {
+    ID("image1").setAttributeNS(XLINK_NS, "xlink:href", data);
+    // Making the href be #image1 doesn't seem to work
+    ID("feimage1").setAttributeNS(XLINK_NS, "xlink:href", data);
+    if (count != -1) {
+      ID("update-1-current-image").textContent = "Current Image after paint " + count;
+    } else {
+      ID("update-1-current-image").textContent = "Current Image is the result";
+    }
+
+    get_image_data(data, function(data) { gImage1Data = data });
+
+  } else {
+    ID("image2").setAttributeNS(XLINK_NS, "xlink:href", data);
+    // Making the href be #image1 doesn't seem to work
+    ID("feimage2").setAttributeNS(XLINK_NS, "xlink:href", data);
+    if (count != -1) {
+      ID("update-2-current-image").textContent = "Current Image after paint " + count;
+    } else {
+      ID("update-2-current-image").textContent = "Current Image is the result";
+    }
+
+    get_image_data(data, function(data) { gImage2Data = data });
+  }
+}
+
 function show_image(i) {
   if (i == 1) {
     ID("image1").style.display = "";
     ID("image2").style.display = "none";
+    ID("update-contents").style.display = "";
+    ID("update-contents2").style.display = "none";
+    ID("update-1-current-image").style.display = "";
+    ID("update-2-current-image").style.display = "none";
   } else {
     ID("image1").style.display = "none";
     ID("image2").style.display = "";
+    ID("update-contents").style.display = "none";
+    ID("update-contents2").style.display = "";
+    ID("update-1-current-image").style.display = "none";
+    ID("update-2-current-image").style.display = "";
   }
 }
 
 function maybe_load_image(event) {
   switch (event.charCode) {
   case 49: // "1" key
     document.getElementById("radio1").checked = true;
     show_image(1);
@@ -568,12 +677,23 @@ function show_pixelinfo(x, y, pix1rgb, p
       </defs>
       <g onmousemove="magnify(evt)">
         <image x="0" y="0" width="100%" height="100%" id="image1" />
         <image x="0" y="0" width="100%" height="100%" id="image2" />
       </g>
       <rect id="diffrect" filter="url(#showDifferences)" pointer-events="none" x="0" y="0" width="100%" height="100%" />
     </svg>
   </div>
+  <div id="updates">
+    <div id="update-1-current-image"></div>
+    <div id="update-2-current-image" style="display:none"></div>
+    Timeline:
+    <table>
+      <tbody id="update-contents">
+      </tbody>
+      <tbody id="update-contents2" style="display:none">
+      </tbody>
+    </table>
+  </div>
 </div>
 
 </body>
 </html>
--- a/layout/tools/reftest/reftest.js
+++ b/layout/tools/reftest/reftest.js
@@ -1197,18 +1197,19 @@ function UpdateCanvasCache(url, canvas)
     }
 }
 
 // Recompute drawWindow flags for every drawWindow operation.
 // We have to do this every time since our window can be
 // asynchronously resized (e.g. by the window manager, to make
 // it fit on screen) at unpredictable times.
 // Fortunately this is pretty cheap.
-function DoDrawWindow(ctx, x, y, w, h)
+function DoDrawWindow(canvas, x, y, w, h)
 {
+    var ctx = canvas.getContext("2d");
     var flags = ctx.DRAWWINDOW_DRAW_CARET | ctx.DRAWWINDOW_DRAW_VIEW;
     var testRect = gBrowser.getBoundingClientRect();
     if (gIgnoreWindowSize ||
         (0 <= testRect.left &&
          0 <= testRect.top &&
          gContainingWindow.innerWidth >= testRect.right &&
          gContainingWindow.innerHeight >= testRect.bottom)) {
         // We can use the window's retained layer manager
@@ -1235,33 +1236,33 @@ function DoDrawWindow(ctx, x, y, w, h)
                  "; window size = " + gContainingWindow.innerWidth + "," + gContainingWindow.innerHeight +
                  "; test browser size = " + testRect.width + "," + testRect.height +
                  "\n");
     }
 
     LogInfo("DoDrawWindow " + x + "," + y + "," + w + "," + h);
     ctx.drawWindow(gContainingWindow, x, y, w, h, "rgb(255,255,255)",
                    gDrawWindowFlags);
+    LogInfo("DoDrawWindow snapshot: " + canvas.toDataURL() + "\n");
 }
 
 function InitCurrentCanvasWithSnapshot()
 {
     LogInfo("Initializing canvas snapshot");
 
     if (gURLs[0].type == TYPE_LOAD || gURLs[0].type == TYPE_SCRIPT) {
         // We don't want to snapshot this kind of test
         return false;
     }
 
     if (!gCurrentCanvas) {
         gCurrentCanvas = AllocateCanvas();
     }
 
-    var ctx = gCurrentCanvas.getContext("2d");
-    DoDrawWindow(ctx, 0, 0, gCurrentCanvas.width, gCurrentCanvas.height);
+    DoDrawWindow(gCurrentCanvas, 0, 0, gCurrentCanvas.width, gCurrentCanvas.height);
     return true;
 }
 
 function UpdateCurrentCanvasForInvalidation(rects)
 {
     LogInfo("Updating canvas for invalidation");
 
     if (!gCurrentCanvas) {
@@ -1274,17 +1275,17 @@ function UpdateCurrentCanvasForInvalidat
         // Set left/top/right/bottom to pixel boundaries
         var left = Math.floor(r.left);
         var top = Math.floor(r.top);
         var right = Math.ceil(r.right);
         var bottom = Math.ceil(r.bottom);
 
         ctx.save();
         ctx.translate(left, top);
-        DoDrawWindow(ctx, left, top, right - left, bottom - top);
+        DoDrawWindow(gCurrentCanvas, left, top, right - left, bottom - top);
         ctx.restore();
     }
 }
 
 function RecordResult(testRunTime, errorMsg, scriptResults)
 {
     LogInfo("RecordResult fired");