Bug 1375903 - Enable eslint on testing/talos - additional changes; r=jmaher
authorGeoff Brown <gbrown@mozilla.com>
Wed, 28 Jun 2017 06:58:03 -0600
changeset 366605 a13cfd0bbb4fc699b4cd7f0d99f7bb16100b2035
parent 366604 9a5100785d8fa93389e80dc055032d9453967443
child 366606 a872b197585ae9bd09e3bb51b93a95ff27491776
push id45679
push usercbook@mozilla.com
push dateThu, 29 Jun 2017 13:53:31 +0000
treeherderautoland@365525f12a1f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmaher
bugs1375903
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1375903 - Enable eslint on testing/talos - additional changes; r=jmaher
.eslintignore
testing/talos/.eslintrc.js
testing/talos/talos/base_profile/prefs.js
testing/talos/talos/generate-tart-xpi.html
testing/talos/talos/generate-tresize-xpi.html
testing/talos/talos/pageloader/chrome/Profiler.js
testing/talos/talos/pageloader/chrome/memory.js
testing/talos/talos/pageloader/chrome/pageloader.js
testing/talos/talos/pageloader/chrome/report.js
testing/talos/talos/pageloader/chrome/tscroll.js
testing/talos/talos/pageloader/components/tp-cmdline.js
testing/talos/talos/scripts/talos-debug.js
testing/talos/talos/scripts/xpigen.js
testing/talos/talos/startup_test/tpaint.html
testing/talos/talos/startup_test/tresize/addon/content/tresize.js
testing/talos/talos/talos-powers/chrome/talos-powers-content.js
testing/talos/talos/talos-powers/components/TalosPowersService.js
testing/talos/talos/tests/a11y/a11y.js
testing/talos/talos/tests/a11y/dhtml.html
testing/talos/talos/tests/a11y/tablemutation.html
testing/talos/talos/tests/devtools/addon/content/addon-test-frontend.js
testing/talos/talos/tests/devtools/addon/content/damp.html
testing/talos/talos/tests/devtools/addon/content/damp.js
testing/talos/talos/tests/perf-reftest/bloom-basic-ref.html
testing/talos/talos/tests/perf-reftest/bloom-basic.html
testing/talos/talos/tests/quit.js
testing/talos/talos/tests/tabpaint/bootstrap.js
testing/talos/talos/tests/tabswitch/bootstrap.js
testing/talos/talos/tests/tart/addon/content/tart.html
testing/talos/talos/tests/tart/addon/content/tart.js
testing/talos/talos/tests/video/video_playback.html
testing/talos/talos/tests/webgl/benchmarks/terrain/perftest.html
testing/talos/talos/tests/webgl/benchmarks/video/video_upload.html
--- a/.eslintignore
+++ b/.eslintignore
@@ -301,16 +301,17 @@ services/sync/services-sync.js
 testing/marionette/**
 testing/mochitest/**
 # third party modules
 testing/modules/ajv-4.1.1.js
 testing/modules/sinon-2.3.2.js
 # octothorpe used for pref file comment causes parsing error
 testing/mozbase/mozprofile/tests/files/prefs_with_comments.js
 testing/talos/talos/scripts/jszip.min.js
+testing/talos/talos/startup_test/sessionrestore/profile/sessionstore.js
 testing/talos/talos/tests/canvasmark/**
 testing/talos/talos/tests/dromaeo/**
 testing/talos/talos/tests/v8_7/**
 testing/talos/talos/tests/kraken/**
 
 testing/web-platform/**
 testing/xpcshell/moz-http2/**
 testing/xpcshell/node-http2/**
new file mode 100644
--- /dev/null
+++ b/testing/talos/.eslintrc.js
@@ -0,0 +1,26 @@
+"use strict";
+
+module.exports = {
+
+  globals: {
+    "Cc": false,
+    "Ci": false,
+    "Cu": false,
+    "content": true,
+    "dumpLog": false,
+    "netscape": false,
+    "addMessageListener": false,
+    "goQuitApplication": false,
+    "MozillaFileLogger": false,
+    "Profiler": true,
+    "Services": false,
+    "gBrowser": false,
+    "removeMessageListener": false,
+    "sendAsyncMessage": false,
+    "sendSyncMessage": false,
+    "TalosPowersContent": true,
+    "TalosPowersParent": true,
+    "TalosContentProfiler": true,
+    "tpRecordTime": true
+  }
+};
--- a/testing/talos/talos/base_profile/prefs.js
+++ b/testing/talos/talos/base_profile/prefs.js
@@ -1,11 +1,12 @@
 // This file is needed to work around a Firefox bug where capability.principal
 // prefs in user.js don't get recognized until the second browser launch
 // which is too late for our purposes of using quit.js. Loading the principals
 // from prefs.js avoids this issue.
+/* globals user_pref */
 user_pref("capability.principal.codebase.p0.granted", "UniversalPreferencesWrite UniversalXPConnect UniversalPreferencesRead");
 user_pref("capability.principal.codebase.p0.id", "file://");
 user_pref("capability.principal.codebase.p0.subjectName", "");
 user_pref("capability.principal.codebase.p1.granted", "UniversalPreferencesWrite UniversalXPConnect UniversalPreferencesRead");
 user_pref("capability.principal.codebase.p1.id", "http://localhost");
 user_pref("capability.principal.codebase.p1.subjectName", "");
 user_pref("signed.applets.codebase_principal_support", true);
--- a/testing/talos/talos/generate-tart-xpi.html
+++ b/testing/talos/talos/generate-tart-xpi.html
@@ -6,16 +6,17 @@
  -->
 <head>
   <meta charset="UTF-8"/>
   <title>TART/CART addon xpi generator</title>
   <script src="scripts/jszip.min.js"></script>
   <script src="scripts/xpigen.js"></script>
 
   <script>
+    /* import-globals-from scripts/xpigen.js */
     var base = "tests/tart/addon/";
     var files = [
       "chrome.manifest",
       "install.rdf",
       "content/framescript.js",
       "content/tart.overlay.xul",
       "content/tart.html",
       "content/tart.ico",
--- a/testing/talos/talos/generate-tresize-xpi.html
+++ b/testing/talos/talos/generate-tresize-xpi.html
@@ -6,16 +6,17 @@
  -->
 <head>
   <meta charset="UTF-8"/>
   <title>Tresize addon xpi generator</title>
   <script src="scripts/jszip.min.js"></script>
   <script src="scripts/xpigen.js"></script>
 
   <script>
+    /* import-globals-from scripts/xpigen.js */
     var base = "startup_test/tresize/addon/";
     var files = [
       "chrome.manifest",
       "install.rdf",
       "content/framescript.js",
       "content/Profiler.js",
       "content/tresize.overlay.xul",
       "content/tresize.js",
--- a/testing/talos/talos/pageloader/chrome/Profiler.js
+++ b/testing/talos/talos/pageloader/chrome/Profiler.js
@@ -101,17 +101,17 @@ var Profiler;
     finishTest: function Profiler__finishTest() {
       if (_profiler && enabled) {
         _profiler.dumpProfileToFile(profiler_dir + "/" + currentTest + ".profile");
         _profiler.StopProfiler();
       }
     },
     finishTestAsync: function Profiler__finishTest() {
       if (!(_profiler && enabled)) {
-        return;
+        return undefined;
       }
       return new Promise((resolve, reject) => {
         Services.profiler.getProfileDataAsync().then((profile) => {
           let profileFile = profiler_dir + "/" + currentTest + ".profile";
 
           Components.utils.import("resource://gre/modules/NetUtil.jsm");
           Components.utils.import("resource://gre/modules/FileUtils.jsm");
 
--- a/testing/talos/talos/pageloader/chrome/memory.js
+++ b/testing/talos/talos/pageloader/chrome/memory.js
@@ -1,8 +1,9 @@
+/* import-globals-from pageloader.js */
 
 var gChildProcess = true;
 var gMemCallback = null;
 
 
 /*
  * Initialize memory collector.  Determine if we have a child process.
  */
--- a/testing/talos/talos/pageloader/chrome/pageloader.js
+++ b/testing/talos/talos/pageloader/chrome/pageloader.js
@@ -1,12 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+/* import-globals-from memory.js */
+/* import-globals-from report.js */
+
 try {
   if (Cc === undefined) {
     var Cc = Components.classes;
     var Ci = Components.interfaces;
   }
 } catch (ex) {}
 
 Components.utils.import("resource://gre/modules/Services.jsm");
@@ -101,16 +104,17 @@ SingleTimeout.prototype.register = funct
 SingleTimeout.prototype.clear = function() {
   if (this.timeoutEvent !== undefined) {
     clearTimeout(this.timeoutEvent);
     this.timeoutEvent = undefined;
   }
 };
 
 var failTimeout = new SingleTimeout();
+var renderReport;
 
 function plInit() {
   if (running) {
     return;
   }
   running = true;
 
   cycle = 0;
@@ -209,18 +213,17 @@ function plInit() {
       .createInstance(Ci.nsISupportsString);
     blank.data = "about:blank";
 
     let toolbars = "all";
     if (!args.useBrowserChrome) {
       toolbars = "titlebar,resizable";
     }
 
-    browserWindow = wwatch.openWindow
-      (null, "chrome://browser/content/", "_blank",
+    browserWindow = wwatch.openWindow(null, "chrome://browser/content/", "_blank",
        `chrome,${toolbars},dialog=no,width=${winWidth},height=${winHeight}`, blank);
 
     gPaintWindow = browserWindow;
     // get our window out of the way
     window.resizeTo(10, 10);
 
     var browserLoadFunc = function(ev) {
       browserWindow.removeEventListener("load", browserLoadFunc, true);
@@ -309,16 +312,17 @@ function plPageFlags() {
 }
 
 var ContentListener = {
   receiveMessage(message) {
     switch (message.name) {
       case "PageLoader:LoadEvent": return plLoadHandlerMessage(message);
       case "PageLoader:RecordTime": return plRecordTimeMessage(message);
     }
+    return undefined;
   },
 };
 
 // load the current page, start timing
 var removeLastAddedListener = null;
 var removeLastAddedMsgListener = null;
 function plLoadPage() {
   var pageName = pages[pageIndex].url.spec;
@@ -520,17 +524,17 @@ function plRecordTime(time) {
       } else {
         report.recordTime(names[t], times[t]);
       }
     }
   } else {
     report.recordTime(recordedName, time);
   }
   if (noisy) {
-    dumpLine("Cycle " + (cycle + 1) + "(" + pageCycle + ")" + ": loaded " + pageName + " (next: " + nextName + ")");
+    dumpLine("Cycle " + (cycle + 1) + "(" + pageCycle + "): loaded " + pageName + " (next: " + nextName + ")");
   }
 }
 
 function plLoadHandlerCapturing(evt) {
   // make sure we pick up the right load event
   if (evt.type != "load" ||
        evt.originalTarget.defaultView.frameElement)
       return;
--- a/testing/talos/talos/pageloader/chrome/report.js
+++ b/testing/talos/talos/pageloader/chrome/report.js
@@ -43,17 +43,17 @@ function findCommonPrefixLength(strs) {
 // Constructor
 function Report() {
   this.timeVals = {};
   this.totalCCTime = 0;
   this.showTotalCCTime = false;
 }
 
 Report.prototype.pageNames = function() {
-  var retval = new Array();
+  var retval = [];
   for (var page in this.timeVals) {
     retval.push(page);
   }
   return retval;
 }
 
 Report.prototype.getReport = function() {
 
@@ -148,17 +148,17 @@ Report.prototype.getReportSummary = func
   }
   report += "-------- Summary: end --------\n";
 
   return report;
 }
 
 Report.prototype.recordTime = function(pageName, ms) {
   if (this.timeVals[pageName] == undefined) {
-    this.timeVals[pageName] = new Array();
+    this.timeVals[pageName] = [];
   }
   this.timeVals[pageName].push(ms);
 }
 
 Report.prototype.recordCCTime = function(ms) {
   this.totalCCTime += ms;
   this.showTotalCCTime = true;
 }
--- a/testing/talos/talos/pageloader/chrome/tscroll.js
+++ b/testing/talos/talos/pageloader/chrome/tscroll.js
@@ -210,26 +210,24 @@ function testScroll(target, stepSize, op
     }
 
     function stopFrameTimeRecording(handle, cb) {
       TalosPowersParent.exec("stopFrameTimeRecording", handle, cb, win);
     }
 
     return new Promise(function(resolve, reject) {
       setSmooth();
-      var startts = Date.now();
 
       var handle = -1;
       startFrameTimeRecording(function(rv) {
         handle = rv;
       });
 
       // Get the measurements after APZ_MEASURE_MS of scrolling
       setTimeout(function() {
-        var endts = Date.now();
 
         stopFrameTimeRecording(handle, function(intervals) {
           function average(arr) {
               var sum = 0;
               for (var i = 0; i < arr.length; i++)
                 sum += arr[i];
               return arr.length ? sum / arr.length : 0;
           }
--- a/testing/talos/talos/pageloader/components/tp-cmdline.js
+++ b/testing/talos/talos/pageloader/components/tp-cmdline.js
@@ -175,17 +175,17 @@ var PageLoaderCmdLineModule =
                             "m-tp",
                             TP_CMDLINE_CONTRACTID, true, true);
   },
 
   unregisterSelf(compMgr, fileSpec, location) {
     compMgr = compMgr.QueryInterface(nsIComponentRegistrar);
 
     compMgr.unregisterFactoryLocation(TP_CMDLINE_CLSID, fileSpec);
-    catman = Components.classes[CATMAN_CONTRACTID].getService(nsICategoryManager);
+    var catman = Components.classes[CATMAN_CONTRACTID].getService(nsICategoryManager);
     catman.deleteCategoryEntry("command-line-handler",
                                "m-tp", true);
   },
 
   getClassObject(compMgr, cid, iid) {
     return NSGetFactory(cid);
   },
 
--- a/testing/talos/talos/scripts/talos-debug.js
+++ b/testing/talos/talos/scripts/talos-debug.js
@@ -28,16 +28,17 @@ window.talosDebug = {
 
   average(values) {
     var d = window.talosDebug;
     return values.length ? d.sum(values) / values.length : 999999;
   },
 
   median(values) {
     var clone = values.slice(0);
+    // eslint-disable-next-line no-nested-ternary
     var sorted = clone.sort(function(a, b) { return (a > b) ? 1 : ((a < b) ? -1 : 0); });
     var len = values.length;
     if (!len)
       return 999999;
     if (len % 2) // We have a middle number
       return sorted[(len - 1) / 2];
     return (sorted[len / 2] + sorted[len / 2 - 1]) / 2; // Average value of the two middle items.
   },
@@ -71,24 +72,24 @@ window.talosDebug = {
 
     function windowStd(from, winSize) {
       var win = values.slice(from, from + winSize);
       return d.stddev(win, d.median(values));
     }
 
     var stableFrom = -1;
     var overallAverage = d.median(values);
-    var overallStd = d.stddev(values, overallAverage);
+    // var overallStd = d.stddev(values, overallAverage);
     for (var winWidth = MIN_WIDTH; winWidth < (MAX_WIDTH + 1); winWidth++) {
       var prevStd = windowStd(0, winWidth);
       for (var i = 1; i < values.length - winWidth - 3; i++) {
         var w0 = windowStd(i + 0, winWidth);
         var w1 = windowStd(i + 1, winWidth);
         var w2 = windowStd(i + 2, winWidth);
-        var currWindow = values.slice(i, i + winWidth);
+        // var currWindow = values.slice(i, i + winWidth);
         if (w0 >= prevStd && !(w1 < w0 && w2 < w1)) {
           if (i > stableFrom)
             stableFrom = i;
           break;
         }
         prevStd = w0;
       }
     }
@@ -130,17 +131,17 @@ window.talosDebug = {
       return;
 
     var collection = ("" + dataCSV).split(",").map(function(item) { return parseFloat(item); });
     var res = d.statsDisplay(collection);
 
     var warmup = (d.ignore >= 0) ? d.ignore : d.detectWarmup(collection);
     if (warmup >= 0) {
       res += "\n\nWarmup " + ((d.ignore >= 0) ? "requested: " : "auto-detected: ") + warmup;
-      warmedUp = collection.slice(warmup);
+      var warmedUp = collection.slice(warmup);
       if (warmup) {
         res += "\nAfter ignoring first " + (warmup > 1 ? (warmup + " items") : "item") + ":\n";
         res += d.statsDisplay(warmedUp);
       }
     } else {
       res += "\n\nWarmup auto-detection: Failed.";
     }
 
--- a/testing/talos/talos/scripts/xpigen.js
+++ b/testing/talos/talos/scripts/xpigen.js
@@ -1,28 +1,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+/* globals JSZip */
+
+/* eslint-disable no-nested-ternary */
+
 // base: relative or absolute path (http[s] or file, untested with ftp)
 // files: array of file names relative to base to include at the zip
 // callbacks: object with optional functions:
 //            onsuccess(result), onerror(exception), onprogress(percentage)
 function createXpiDataUri(base, files, callbacks) {
 
   // Synchronous XHR for http[s]/file (untested ftp), throws on any error
   // Note that on firefox, file:// XHR can't access files outside base dir
   function readBinFile(url) {
-    // The DOM will qualify the URI for us if it's relative (not IE6)
-    function isFileUri(uri) {
-      var a = document.createElement("a");
-      a.href = uri;
-      return a.href.toLowerCase().indexOf("file://") == 0;
-    }
-
     var r =  new XMLHttpRequest();
     r.open("GET", url, false);
     r.requestType = "arraybuffer";
     r.overrideMimeType("text/plain; charset=x-user-defined");
     try { r.send(); } catch (e) { throw "FileNotRetrieved: " + url + " - " + e; }
     // For 'file://' Firefox sets status=0 on success or throws otherwise
     // In Firefox 34-ish onwards, success status is 200.
     if (!(r.readyState == 4 && (r.status == 0 || r.status == 200)))
--- a/testing/talos/talos/startup_test/tpaint.html
+++ b/testing/talos/talos/startup_test/tpaint.html
@@ -63,17 +63,17 @@ async function reportTimes() {
     if (time < min)
       min = time;
     if (time > max)
       max = time;
   }
   avg = (avg / count).toFixed(2);
   min = min.toFixed(2);
   max = max.toFixed(2);
-  med = calcMedian(openTimes);
+  var med = calcMedian(openTimes);
 
   if (auto) {
     dumpLog("__start_report" + openTimes.join("|") + "__end_report");
     var now = (new Date()).getTime();
     dumpLog("__startTimestamp" + now + "__endTimestamp\n");
     dumpLog("openingTimes=" + openTimes.slice(1) + "\n");
     dumpLog("avgOpenTime:" + avg + "\n" );
     dumpLog("minOpenTime:" + min + "\n" );
@@ -92,25 +92,27 @@ async function reportTimes() {
 
 async function childIsOpen() {
   kidEndTime = window.performance.now();
   await TalosContentProfiler.pause("tpaint " + windowIndex);
   openTimes[windowIndex] = kidEndTime - kidStartTime;
   scheduleNextWindow();
 }
 
+/* eslint-disable no-useless-concat */
 var kidHTML = "<html><meta charset='utf-8'><script>" +
               "var e = 'MozAfterPaint';" +
               "function done() {" +
               "  window.removeEventListener(e, done, true);" +
               "  window.opener.childIsOpen();" +
               "  window.close();" +
               "}" +
               "window.addEventListener(e, done, true);" +
               "</" + "script>TPAINT</html>";
+/* eslint-enable no-useless-concat */
 var kidURI = "data:text/html," + encodeURI(kidHTML);
 
 async function openWindow() {
   await TalosContentProfiler.resume("tpaint " + windowIndex);
   kidStartTime = window.performance.now();
   kid = window.open(kidURI);
 }
 
--- a/testing/talos/talos/startup_test/tresize/addon/content/tresize.js
+++ b/testing/talos/talos/startup_test/tresize/addon/content/tresize.js
@@ -1,17 +1,17 @@
 /*
  * tresize-test - A purer form of paint measurement than tpaint. This
  * test opens a single window positioned at 10,10 and sized to 425,425,
  * then resizes the window outward |max| times measuring the amount of
  * time it takes to repaint each resize. Dumps the resulting dataset
  * and average to stdout or logfile.
  */
 
-var dataSet = new Array();
+var dataSet = [];
 var windowSize = 425;
 var resizeIncrement = 2;
 var count = 0;
 var max = 300;
 
 var dumpDataSet = false;
 var doneCallback = null;
 
--- a/testing/talos/talos/talos-powers/chrome/talos-powers-content.js
+++ b/testing/talos/talos/talos-powers/chrome/talos-powers-content.js
@@ -1,14 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // This file is loaded as a framescript
 
+/* globals docShell */
+
 var { interfaces: Ci, utils: Cu } = Components;
 
 /**
  * Content that wants to quit the whole session should
  * fire the TalosQuitApplication custom event. This will
  * attempt to force-quit the browser.
  */
 addEventListener("TalosQuitApplication", event => {
--- a/testing/talos/talos/talos-powers/components/TalosPowersService.js
+++ b/testing/talos/talos/talos-powers/components/TalosPowersService.js
@@ -183,17 +183,16 @@ TalosPowersService.prototype = {
         // in order, we know that by the time that the child services the
         // ACK message, that the profiler has started in its process.
         mm.sendAsyncMessage(ACK_NAME, { name });
         break;
       }
 
       case "Profiler:Finish": {
         // The test is done. Dump the profile.
-        let profileFile = data.profileFile;
         this.profilerFinish(data.profileFile).then(() => {
           mm.sendAsyncMessage(ACK_NAME, { name });
         });
         break;
       }
 
       case "Profiler:Pause": {
         this.profilerPause(data.marker);
--- a/testing/talos/talos/tests/a11y/a11y.js
+++ b/testing/talos/talos/tests/a11y/a11y.js
@@ -1,8 +1,9 @@
+/* globals acc:true, gAccService:true, nsIAccessible:true, nsIDOMNode:true */
 gAccService = 0;
 
 // Make sure not to touch Components before potentially invoking enablePrivilege,
 // because otherwise it won't be there.
 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 nsIAccessible = Components.interfaces.nsIAccessible;
 nsIDOMNode = Components.interfaces.nsIDOMNode;
 
--- a/testing/talos/talos/tests/a11y/dhtml.html
+++ b/testing/talos/talos/tests/a11y/dhtml.html
@@ -1,15 +1,16 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <meta charset="utf-8">
 <head>
 <title>accessibility perf for dhtml</title>
 <script src="a11y.js"></script>
 <script>
+  /* import-globals-from a11y.js */
   // based on: http://hacks.mozilla.org/2010/05/better-performance-with-lazy-frame-construction/
   var ppDate = null;
 
   function doInsertion() {
     if (!initAccessibility()) {
       dump("__FAILinit:AccessibilityUnvailable__FAIL");
       return;
     }
--- a/testing/talos/talos/tests/a11y/tablemutation.html
+++ b/testing/talos/talos/tests/a11y/tablemutation.html
@@ -71,18 +71,21 @@
 <tr><td>Row #0</td><td>348003</td><td>745393</td><td>658838</td><td>273744</td></tr><tr><td>Row #1</td><td>482498</td><td>724073</td><td>792474</td><td>549091</td></tr><tr><td>Row #2</td><td>639859</td><td>151692</td><td>251949</td><td>323840</td></tr><tr><td>Row #3</td><td>269274</td><td>211292</td><td>892989</td><td>473276</td></tr><tr><td>Row #4</td><td>148736</td><td>438719</td><td>789802</td><td>986023</td></tr><tr><td>Row #5</td><td>999863</td><td>782360</td><td>648663</td><td>959764</td></tr><tr><td>Row #6</td><td>302562</td><td>122962</td><td>623747</td><td>961374</td></tr><tr><td>Row #7</td><td>620408</td><td>740513</td><td>562968</td><td>868412</td></tr><tr><td>Row #8</td><td>485907</td><td>221807</td><td>142157</td><td>868405</td></tr><tr><td>Row #9</td><td>845880</td><td>834632</td><td>417497</td><td>485740</td></tr><tr><td>Row #10</td><td>886324</td><td>569447</td><td>709581</td><td>155598</td></tr><tr><td>Row #11</td><td>680740</td><td>602570</td><td>528874</td><td>729476</td></tr><tr><td>Row #12</td><td>941289</td><td>318677</td><td>715499</td><td>941153</td></tr><tr><td>Row #13</td><td>101037</td><td>364163</td><td>900918</td><td>303600</td></tr><tr><td>Row #14</td><td>387126</td><td>524665</td><td>264974</td><td>907534</td></tr><tr><td>Row #15</td><td>265179</td><td>727943</td><td>775947</td><td>651086</td></tr><tr><td>Row #16</td><td>849750</td><td>818104</td><td>519492</td><td>695631</td></tr><tr><td>Row #17</td><td>652736</td><td>836990</td><td>181371</td><td>539061</td></tr><tr><td>Row #18</td><td>406437</td><td>790952</td><td>594659</td><td>987177</td></tr><tr><td>Row #19</td><td>393523</td><td>123534</td><td>716653</td><td>334813</td></tr><tr><td>Row #20</td><td>342211</td><td>432153</td><td>275966</td><td>343248</td></tr><tr><td>Row #21</td><td>696316</td><td>176885</td><td>546849</td><td>983442</td></tr><tr><td>Row #22</td><td>601550</td><td>711824</td><td>890977</td><td>766730</td></tr><tr><td>Row #23</td><td>439767</td><td>666925</td><td>417816</td><td>289518</td></tr><tr><td>Row #24</td><td>485029</td><td>837309</td><td>885150</td><td>137766</td></tr>
 <tr><td>Row #0</td><td>348003</td><td>745393</td><td>658838</td><td>273744</td></tr><tr><td>Row #1</td><td>482498</td><td>724073</td><td>792474</td><td>549091</td></tr><tr><td>Row #2</td><td>639859</td><td>151692</td><td>251949</td><td>323840</td></tr><tr><td>Row #3</td><td>269274</td><td>211292</td><td>892989</td><td>473276</td></tr><tr><td>Row #4</td><td>148736</td><td>438719</td><td>789802</td><td>986023</td></tr><tr><td>Row #5</td><td>999863</td><td>782360</td><td>648663</td><td>959764</td></tr><tr><td>Row #6</td><td>302562</td><td>122962</td><td>623747</td><td>961374</td></tr><tr><td>Row #7</td><td>620408</td><td>740513</td><td>562968</td><td>868412</td></tr><tr><td>Row #8</td><td>485907</td><td>221807</td><td>142157</td><td>868405</td></tr><tr><td>Row #9</td><td>845880</td><td>834632</td><td>417497</td><td>485740</td></tr><tr><td>Row #10</td><td>886324</td><td>569447</td><td>709581</td><td>155598</td></tr><tr><td>Row #11</td><td>680740</td><td>602570</td><td>528874</td><td>729476</td></tr><tr><td>Row #12</td><td>941289</td><td>318677</td><td>715499</td><td>941153</td></tr><tr><td>Row #13</td><td>101037</td><td>364163</td><td>900918</td><td>303600</td></tr><tr><td>Row #14</td><td>387126</td><td>524665</td><td>264974</td><td>907534</td></tr><tr><td>Row #15</td><td>265179</td><td>727943</td><td>775947</td><td>651086</td></tr><tr><td>Row #16</td><td>849750</td><td>818104</td><td>519492</td><td>695631</td></tr><tr><td>Row #17</td><td>652736</td><td>836990</td><td>181371</td><td>539061</td></tr><tr><td>Row #18</td><td>406437</td><td>790952</td><td>594659</td><td>987177</td></tr><tr><td>Row #19</td><td>393523</td><td>123534</td><td>716653</td><td>334813</td></tr><tr><td>Row #20</td><td>342211</td><td>432153</td><td>275966</td><td>343248</td></tr><tr><td>Row #21</td><td>696316</td><td>176885</td><td>546849</td><td>983442</td></tr><tr><td>Row #22</td><td>601550</td><td>711824</td><td>890977</td><td>766730</td></tr><tr><td>Row #23</td><td>439767</td><td>666925</td><td>417816</td><td>289518</td></tr><tr><td>Row #24</td><td>485029</td><td>837309</td><td>885150</td><td>137766</td></tr>
 <tr><td>Row #0</td><td>348003</td><td>745393</td><td>658838</td><td>273744</td></tr><tr><td>Row #1</td><td>482498</td><td>724073</td><td>792474</td><td>549091</td></tr><tr><td>Row #2</td><td>639859</td><td>151692</td><td>251949</td><td>323840</td></tr><tr><td>Row #3</td><td>269274</td><td>211292</td><td>892989</td><td>473276</td></tr><tr><td>Row #4</td><td>148736</td><td>438719</td><td>789802</td><td>986023</td></tr><tr><td>Row #5</td><td>999863</td><td>782360</td><td>648663</td><td>959764</td></tr><tr><td>Row #6</td><td>302562</td><td>122962</td><td>623747</td><td>961374</td></tr><tr><td>Row #7</td><td>620408</td><td>740513</td><td>562968</td><td>868412</td></tr><tr><td>Row #8</td><td>485907</td><td>221807</td><td>142157</td><td>868405</td></tr><tr><td>Row #9</td><td>845880</td><td>834632</td><td>417497</td><td>485740</td></tr><tr><td>Row #10</td><td>886324</td><td>569447</td><td>709581</td><td>155598</td></tr><tr><td>Row #11</td><td>680740</td><td>602570</td><td>528874</td><td>729476</td></tr><tr><td>Row #12</td><td>941289</td><td>318677</td><td>715499</td><td>941153</td></tr><tr><td>Row #13</td><td>101037</td><td>364163</td><td>900918</td><td>303600</td></tr><tr><td>Row #14</td><td>387126</td><td>524665</td><td>264974</td><td>907534</td></tr><tr><td>Row #15</td><td>265179</td><td>727943</td><td>775947</td><td>651086</td></tr><tr><td>Row #16</td><td>849750</td><td>818104</td><td>519492</td><td>695631</td></tr><tr><td>Row #17</td><td>652736</td><td>836990</td><td>181371</td><td>539061</td></tr><tr><td>Row #18</td><td>406437</td><td>790952</td><td>594659</td><td>987177</td></tr><tr><td>Row #19</td><td>393523</td><td>123534</td><td>716653</td><td>334813</td></tr><tr><td>Row #20</td><td>342211</td><td>432153</td><td>275966</td><td>343248</td></tr><tr><td>Row #21</td><td>696316</td><td>176885</td><td>546849</td><td>983442</td></tr><tr><td>Row #22</td><td>601550</td><td>711824</td><td>890977</td><td>766730</td></tr><tr><td>Row #23</td><td>439767</td><td>666925</td><td>417816</td><td>289518</td></tr><tr><td>Row #24</td><td>485029</td><td>837309</td><td>885150</td><td>137766</td></tr>
 </table>
 </div>
 
 </body>
 <script>
+/* import-globals-from a11y.js */
 window.onload = function() {
-  setTimeout("mutateTable()", 100);
+  setTimeout(function() {
+    mutateTable();
+  }, 100);
 };
 function mutateTable() {
   var htmTable = document.getElementById("datatable");
   var TableRows = [ ];
 
   // Locate all TR elements of the table
   var htmRow = htmTable.childNodes[0];
   while (htmRow) {
--- a/testing/talos/talos/tests/devtools/addon/content/addon-test-frontend.js
+++ b/testing/talos/talos/tests/devtools/addon/content/addon-test-frontend.js
@@ -1,11 +1,13 @@
 // This file is the common bits for the test runner frontend, originally
 // extracted out of the tart.html frontend when creating the damp test.
 
+/* globals updateConfig, defaultConfig, config */ /* from damp.html */
+
 function $(id) {
   return document.getElementById(id);
 }
 
 // Executes command at the chrome process.
 // Limited to one argument (data), which is enough for TART.
 // doneCallback will be called once done and, if applicable, with the result as argument.
 // Execution might finish quickly (e.g. when setting prefs) or
--- a/testing/talos/talos/tests/devtools/addon/content/damp.html
+++ b/testing/talos/talos/tests/devtools/addon/content/damp.html
@@ -32,26 +32,26 @@ var testsInfo = {
   saveAndReadHeapSnapshot: "Measure open/close toolbox on memory panel and save/read heap snapshot",
   consoleBulkLogging: "Measure time for a bunch of sync console.log statements to appear",
   consoleStreamLogging: "Measure rAF on page during a stream of console.log statements",
 };
 
 function updateConfig() {
   config = {subtests: []};
   for (var test in defaultConfig.subtests) {
-    if ($("subtest-" + test).checked) {
+    if ($("subtest-" + test).checked) { // eslint-disable-line no-undef
       config.subtests.push(test);
     }
   }
 
-  var repeat = $("repeat").value;
+  var repeat = $("repeat").value; // eslint-disable-line no-undef
   config.repeat = isNaN(repeat) ? 1 : repeat;
 
   // use 1ms rest as a minimum.
-  var rest = $("rest").value;
+  var rest = $("rest").value; // eslint-disable-line no-undef
   config.rest = Math.max(1, isNaN(rest) ? defaultConfig.rest : rest);
 }
 </script>
 <script src="addon-test-frontend.js"></script>
 </head>
 <body style="font-family:sans-serif;">
 <h4>DAMP - Devtools At Maximum Performance</h4>
 <div id="hide-during-run">
--- a/testing/talos/talos/tests/devtools/addon/content/damp.js
+++ b/testing/talos/talos/tests/devtools/addon/content/damp.js
@@ -9,16 +9,18 @@ const ThreadSafeChromeUtils = devtools.r
 const { EVENTS } = devtools.require("devtools/client/netmonitor/src/constants");
 const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
 
 const webserver = Services.prefs.getCharPref("addon.test.damp.webserver");
 
 const SIMPLE_URL = webserver + "/tests/devtools/addon/content/pages/simple.html";
 const COMPLICATED_URL = webserver + "/tests/tp5n/bild.de/www.bild.de/index.html";
 
+/* globals res:true */
+
 function Damp() {
   // Path to the temp file where the heap snapshot file is saved. Set by
   // saveHeapSnapshot and read by readHeapSnapshot.
   this._heapSnapshotFilePath = null;
   // HeapSnapshot instance. Set by readHeapSnapshot, used by takeCensus.
   this._snapshot = null;
 
   // Use the old console for now: https://bugzilla.mozilla.org/show_bug.cgi?id=1306780
@@ -27,39 +29,36 @@ function Damp() {
 
 Damp.prototype = {
 
   addTab(url) {
     return new Promise((resolve, reject) => {
       let tab = this._win.gBrowser.selectedTab = this._win.gBrowser.addTab(url);
       let browser = tab.linkedBrowser;
       browser.addEventListener("load", function onload() {
-        browser.removeEventListener("load", onload, true);
         resolve(tab);
-      }, true);
+      }, {capture: true, once: true});
     });
   },
 
   closeCurrentTab() {
     this._win.BrowserCloseTabOrWindow();
     return this._win.gBrowser.selectedTab;
   },
 
   reloadPage() {
     let startReloadTimestamp = performance.now();
     return new Promise((resolve, reject) => {
       let browser = gBrowser.selectedBrowser;
-      let self = this;
       browser.addEventListener("load", function onload() {
-        browser.removeEventListener("load", onload, true);
         let stopReloadTimestamp = performance.now();
         resolve({
           time: stopReloadTimestamp - startReloadTimestamp
         });
-      }, true);
+      }, {capture: true, once: true});
       browser.reload();
     });
   },
 
   openToolbox(tool = "webconsole") {
     let tab = getActiveTab(getMostRecentBrowserWindow());
     let target = devtools.TargetFactory.forTab(tab);
     let startRecordTimestamp = performance.now();
@@ -176,18 +175,17 @@ Damp.prototype = {
 
   // Log a stream of console messages, 1 per rAF.  Then record the average
   // time per rAF.  The idea is that the console being slow can slow down
   // content (i.e. Bug 1237368).
   _consoleStreamLoggingTest: Task.async(function*() {
     let TOTAL_MESSAGES = 100;
     let tab = yield this.testSetup(SIMPLE_URL);
     let messageManager = tab.linkedBrowser.messageManager;
-    let {toolbox} = yield this.openToolbox("webconsole");
-    let webconsole = toolbox.getPanel("webconsole");
+    yield this.openToolbox("webconsole");
 
     // Load a frame script using a data URI so we can do logs
     // from the page.  So this is running in content.
     messageManager.loadFrameScript("data:,(" + encodeURIComponent(
       `function () {
         let count = 0;
         let startTime = content.performance.now();
         function log() {
--- a/testing/talos/talos/tests/perf-reftest/bloom-basic-ref.html
+++ b/testing/talos/talos/tests/perf-reftest/bloom-basic-ref.html
@@ -1,13 +1,14 @@
 <!DOCTYPE html>
 <html>
   <head>
     <script src="util.js"></script>
     <script>
+/* import-globals-from util.js */
 window.onload = function() {
   document.head.appendChild(build_rule("span > div", 10000, "{ color: blue; } "));
   let dom = build_dom(5000, "div");
 
   let start = performance.now();
   document.body.appendChild(dom);
   window.foo = window.getComputedStyle(document.body).color;
   let end = performance.now();
--- a/testing/talos/talos/tests/perf-reftest/bloom-basic.html
+++ b/testing/talos/talos/tests/perf-reftest/bloom-basic.html
@@ -1,13 +1,14 @@
 <!DOCTYPE html>
 <html>
   <head>
     <script src="util.js"></script>
     <script>
+/* import-globals-from util.js */
 window.onload = function() {
   document.head.appendChild(build_rule("span div", 10000, "{ color: blue; } "));
   let dom = build_dom(5000, "div");
 
   let start = performance.now();
   document.body.appendChild(dom);
   window.foo = window.getComputedStyle(document.body).color;
   let end = performance.now();
--- a/testing/talos/talos/tests/quit.js
+++ b/testing/talos/talos/tests/quit.js
@@ -74,17 +74,17 @@ function goQuitApplication(waitForSafeBr
 
   var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"]
                  .getService(Components.interfaces.nsIXULRuntime);
   if (xulRuntime.processType == xulRuntime.PROCESS_TYPE_CONTENT) {
     // If we're running in a remote browser, emit an event for a
     // frame script to pick up to quit the whole browser.
     var event = new CustomEvent("TalosQuitApplication", {bubbles: true, detail: {waitForSafeBrowsing}});
     document.dispatchEvent(event);
-    return;
+    return false;
   }
 
   if (waitForSafeBrowsing) {
     var SafeBrowsing = Components.utils.
       import("resource://gre/modules/SafeBrowsing.jsm", {}).SafeBrowsing;
 
     var whenDone = () => {
       goQuitApplication(false);
--- a/testing/talos/talos/tests/tabpaint/bootstrap.js
+++ b/testing/talos/talos/tests/tabpaint/bootstrap.js
@@ -147,17 +147,16 @@ var TabPaint = {
    * @param gBrowser (<xul:tabbrowser>)
    *        The tabbrowser of the window to use.
    *
    * @return Promise
    *         Resolves once the tab has been fully removed. Resolves
    *         with the time (in ms) it took to open the tab from the parent.
    */
   openTabFromParent(gBrowser) {
-    let win = gBrowser.ownerGlobal;
     return new Promise((resolve) => {
       this.Profiler.resume("tabpaint parent start");
 
       gBrowser.selectedTab = gBrowser.addTab(TARGET_URI + "?" + Date.now(), {
         triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
       });
 
       this.whenTabShown().then(({tab, delta}) => {
@@ -176,17 +175,16 @@ var TabPaint = {
    * @param gBrowser (<xul:tabbrowser>)
    *        The tabbrowser of the window to use.
    *
    * @return Promise
    *         Resolves once the tab has been fully removed. Resolves
    *         with the time (in ms) it took to open the tab from content.
    */
   openTabFromContent(gBrowser) {
-    let win = gBrowser.ownerGlobal;
     return new Promise((resolve) => {
       this.Profiler.resume("tabpaint content start");
 
       Services.mm.broadcastAsyncMessage("TabPaint:OpenFromContent");
 
       this.whenTabShown().then(({tab, delta}) => {
         this.Profiler.pause("tabpaint content end");
         this.removeTab(tab).then(() => {
@@ -222,17 +220,17 @@ var TabPaint = {
       let {messageManager: mm, frameLoader} = tab.linkedBrowser;
       mm.addMessageListener("SessionStore:update", function onMessage(msg) {
         if (msg.targetFrameLoader == frameLoader && msg.data.isFinal) {
           mm.removeMessageListener("SessionStore:update", onMessage);
           resolve();
         }
       }, true);
 
-      tab.ownerDocument.defaultView.gBrowser.removeTab(tab);
+      tab.ownerGlobal.gBrowser.removeTab(tab);
     });
   },
 
   /**
    * Sends the results down to the tabpaint-test.html page, which will
    * pipe them out to the console.
    *
    * @param results (Object)
--- a/testing/talos/talos/tests/tabswitch/bootstrap.js
+++ b/testing/talos/talos/tests/tabswitch/bootstrap.js
@@ -1,11 +1,13 @@
 
 // -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
 
+/* globals APP_SHUTDOWN */
+
 var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/Timer.jsm");
 Cu.import("resource://gre/modules/RemotePageManager.jsm");
 
@@ -36,19 +38,18 @@ var windowListener = {
 
   onWindowTitleChange(aWindow, aTitle) {
   }
 };
 
 function promiseOneEvent(target, eventName, capture) {
   let deferred = Promise.defer();
   target.addEventListener(eventName, function handler(event) {
-    target.removeEventListener(eventName, handler, capture);
     deferred.resolve();
-  }, capture);
+  }, {capture, once: true});
   return deferred.promise;
 }
 
 function executeSoon(callback) {
   Services.tm.dispatchToMainThread(callback);
 }
 
 /**
@@ -264,19 +265,18 @@ function switchToTab(tab) {
  *        switch.
  * @returns Promise
  *        Resolves once the TabSwitchDone event is fired.
  */
 function waitForTabSwitchDone(browser) {
   return new Promise((resolve) => {
     let gBrowser = browser.ownerGlobal.gBrowser;
     gBrowser.addEventListener("TabSwitchDone", function onTabSwitchDone() {
-      gBrowser.removeEventListener("TabSwitchDone", onTabSwitchDone);
       resolve();
-    });
+    }, {once: true});
   });
 }
 
 /**
  * For some <xul:browser>, returns a Promise that resolves once its
  * content has been presented to the user.
  *
  * @param browser (<xul:browser>)
--- a/testing/talos/talos/tests/tart/addon/content/tart.html
+++ b/testing/talos/talos/tests/tart/addon/content/tart.html
@@ -186,17 +186,18 @@ function updateConfig() {
       config.subtests.push(test);
     }
   }
 
   var repeat = $("repeat").value;
   config.repeat = isNaN(repeat) ? 1 : repeat;
 
   var rest = $("rest").value;
-  config.rest = isNaN(rest) ? 500 : (rest ? rest : 1); // 500ms default, use 1ms as minimum
+  config.rest = isNaN(rest) ? 500 : rest; // 500ms default, use 1ms as minimum
+  config.rest = config.rest ? config.rest : 1;
 
   config.tickle = $("tickle").checked;
 
   config.controlProfiler = $("controlProfiler").checked;
 }
 
 // E.g. returns "world" for key "hello", "2014" for key "year", and "" for key "dummy":
 // http://localhost/x.html#hello=world&x=12&year=2014
--- a/testing/talos/talos/tests/tart/addon/content/tart.js
+++ b/testing/talos/talos/tests/tart/addon/content/tart.js
@@ -25,16 +25,18 @@
 //   V - Different DPIs
 //   V - with fade only (no tab open/close overhead)
 //   X - tab drag
 //   X - tab remove from the middle
 //   X - Without add-tab button -> can be hidden while testing manually. in talos always with the button
 let aboutNewTabService = Components.classes["@mozilla.org/browser/aboutnewtab-service;1"]
                                    .getService(Components.interfaces.nsIAboutNewTabService);
 
+/* globals res:true, sequenceArray:true */
+
 function Tart() {
 }
 
 Tart.prototype = {
   // Detector methods expect 'this' to be the detector object.
   // Detectors must support measureNow(e) which indicates to collect the intervals and stop the recording.
   // Detectors may support keepListening(e) to indicate to keep waiting before continuing to the next animation.
 
@@ -267,33 +269,30 @@ Tart.prototype = {
       //    (e.g. if the reference duration is 250ms then average of the last 125ms,
       //     regardless of the actual animation duration in practice)
       // 2. Average interval for the entire animation.
       // 3. Absolute difference between reference duration to actual diration.
 
       var sumLastHalf = 0;
       var countLastHalf = 0;
       var sumMost = 0;
-      var countMost = 0;
       var sum = 0;
       for (var i = intervals.length - 1; i >= 0; i--) {
         sum += intervals[i];
         if (sumLastHalf < referenceDuration / 2) {
           sumLastHalf += intervals[i];
           countLastHalf++;
         }
         if (sumMost < referenceDuration * .85) {
           sumMost += intervals[i];
-          countMost++;
         }
       }
       dump("overall: " + sum + "\n");
 
       var averageLastHalf = countLastHalf ? sumLastHalf / countLastHalf : 0;
-      var averageMost    = countMost ? sumMost / countMost : 0;
       var averageOverall = intervals.length ? sum / intervals.length : 0;
       var durationDiff = Math.abs(recordingAbsoluteDuration - referenceDuration);
 
       self._results.push({name: name + ".raw.TART",   value: intervals}); // Just for display if running manually - Not collected for talos.
       self._results.push({name: name + ".half.TART",  value: averageLastHalf});
       self._results.push({name: name + ".all.TART",   value: averageOverall});
       self._results.push({name: name + ".error.TART", value: durationDiff});
     }
@@ -346,16 +345,17 @@ Tart.prototype = {
         }
 
         self._win.document.getElementById(id).style.opacity = orig;
         return rAF(f);
       }
 
       tickleLoop();
 
+      return false;
     }
 
     setTimeout(function() {
       trigger(function() {
         timeoutId = setTimeout(transEnd, 3000);
         recordingHandle = startRecord();
         triggerFunc(); // also chooses detector
         detector = self._endDetection;
--- a/testing/talos/talos/tests/video/video_playback.html
+++ b/testing/talos/talos/tests/video/video_playback.html
@@ -19,16 +19,18 @@ var test = [
   "testsrc.480p.60fps.webm",
   "testsrc.1080p.60fps.mp4",
 ];
 var viewModeIndex = 0;
 // Remove fullscreen mode since it causes intermittent failures on try server. See bug 1192317.
 var viewMode = [1, 1.1, 2];
 var testResult = {names: [], values: []};
 
+/* globals readyToStart:true */
+
 function init() {
   TalosPowersContent.focus(content_focused)
 }
 
 function content_focused() {
   vdo = document.getElementById("vdo");
   vdo.addEventListener("loadeddata", prepare);
   document.addEventListener("fullscreenchange", fullscreen);
@@ -131,16 +133,17 @@ function reportResult() {
 
   if (window.tpRecordTime) {
     // Within talos - report the results
     return tpRecordTime(testResult.values.join(","), 0, testResult.names.join(","));
   }
     // Local run in a plain browser, display the formatted report
     alert(msg);
 
+  return undefined;
 }
 </script>
 
 </head>
 <body id="body" onload="init();">
 <video id="vdo" width="100%" height="100%">
 </video>
 </body>
--- a/testing/talos/talos/tests/webgl/benchmarks/terrain/perftest.html
+++ b/testing/talos/talos/tests/webgl/benchmarks/terrain/perftest.html
@@ -1,404 +1,404 @@
-<html>
-<!--
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
- Version 1.1
-   - Added viewport rotation.
-   - Adapted for talos with with 4 runs on combinations of alpha/antialias
-
- Version 1.0
-   - Benoit Jacob's WebGL tutorial demos: http://bjacob.github.io/webgl-tutorial/12-texture.html
--->
-<head>
-<meta charset="utf-8"/>
-<script src="../../../../scripts/Profiler.js"></script>
-<script type="x-shader/x-vertex" id="vertexShader">
-  attribute vec3 vertexPosition;
-  attribute vec3 normalVector;
-  attribute vec2 textureCoord;
-  uniform mat4 modelview;
-  uniform mat4 projection;
-  varying vec3 varyingNormalVector;
-  varying vec2 varyingTextureCoord;
-  void main(void) {
-    gl_Position = projection * modelview * vec4(vertexPosition, 1.0);
-    varyingNormalVector = normalVector;
-    varyingTextureCoord = textureCoord;
-  }
-</script>
-<script type="x-shader/x-fragment" id="fragmentShader">
-  precision mediump float;
-  varying vec3 varyingNormalVector;
-  uniform vec3 lightDirection;
-  uniform sampler2D grassTextureSampler;
-  varying vec2 varyingTextureCoord;
-  void main(void) {
-    vec3 grassColor = texture2D(grassTextureSampler, varyingTextureCoord).rgb;
-    const float ambientLight = 0.3;
-    const float diffuseLight = 0.7;
-    float c = clamp(dot(normalize(varyingNormalVector), lightDirection), 0.0, 1.0);
-    vec3 resultColor = grassColor * (c * diffuseLight + ambientLight);
-    gl_FragColor = vec4(resultColor, 1);
-  }
-</script>
-<script>
-  var gl;
-
-  var modelviewUniformLoc;
-  var projectionUniformLoc;
-  var lightDirectionUniformLoc;
-  var grassTextureSamplerUniformLoc;
-
-  var modelviewMatrix = new Float32Array(16);
-  var projectionMatrix = new Float32Array(16);
-
-  var terrainSize = 32;
-  var aspectRatio;
-
-  function startTest(alpha, antialias, doneCallback) {
-    gl = document.getElementById("c").getContext("webgl", {alpha: alpha, antialias: antialias});
-
-    var grassImage = document.getElementById("grass");
-    var grassTexture = gl.createTexture();
-    gl.bindTexture(gl.TEXTURE_2D, grassTexture);
-    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, grassImage);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
-    gl.generateMipmap(gl.TEXTURE_2D);
-
-    var vertexShader = gl.createShader(gl.VERTEX_SHADER);
-    var vertexShaderString = document.getElementById("vertexShader").text;
-    gl.shaderSource(vertexShader, vertexShaderString);
-    gl.compileShader(vertexShader);
-
-    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
-    var fragmentShaderString = document.getElementById("fragmentShader").text;
-    gl.shaderSource(fragmentShader, fragmentShaderString);
-    gl.compileShader(fragmentShader);
-
-    var program = gl.createProgram();
-    gl.attachShader(program, vertexShader);
-    gl.attachShader(program, fragmentShader);
-    gl.linkProgram(program);
-    gl.useProgram(program);
-
-    var vertexPositionAttrLoc = gl.getAttribLocation(program, "vertexPosition");
-    gl.enableVertexAttribArray(vertexPositionAttrLoc);
-    var normalVectorAttrLoc = gl.getAttribLocation(program, "normalVector");
-    gl.enableVertexAttribArray(normalVectorAttrLoc);
-    var textureCoordAttrLoc = gl.getAttribLocation(program, "textureCoord");
-    gl.enableVertexAttribArray(textureCoordAttrLoc);
-
-    modelviewUniformLoc = gl.getUniformLocation(program, "modelview");
-    projectionUniformLoc = gl.getUniformLocation(program, "projection");
-    lightDirectionUniformLoc = gl.getUniformLocation(program, "lightDirection");
-    grassTextureSamplerUniformLoc = gl.getUniformLocation(program, "grassTextureSampler");
-
-    var vertices = new Float32Array(terrainSize * terrainSize * 3);
-    var normalVectors = new Float32Array(terrainSize * terrainSize * 3);
-    var textureCoords = new Float32Array(terrainSize * terrainSize * 2);
-
-    for (var i = 0; i < terrainSize; i++) {
-      for (var j = 0; j < terrainSize; j++) {
-        var a = 2 * Math.PI * i / terrainSize;
-        var b = 2 * Math.PI * j / terrainSize;
-        var height = 4 * Math.cos(a) + 6 * Math.sin(b) + Math.cos(4 * a) + Math.sin(5 * b);
-        vertices[3 * (i + terrainSize * j) + 0] = i;
-        vertices[3 * (i + terrainSize * j) + 1] = height;
-        vertices[3 * (i + terrainSize * j) + 2] = j;
-
-        var d_y_d_x = (2 * Math.PI / terrainSize) * (- 4 * Math.sin(a) - 4 * Math.sin(4 * a));
-        var d_y_d_z = (2 * Math.PI / terrainSize) * (6 * Math.cos(b) + 5 * Math.cos(5 * b));
-        var normal_x = d_y_d_x;
-        var normal_y = -1;
-        var normal_z = d_y_d_z;
-        var normal_length = Math.sqrt(normal_x * normal_x + normal_y * normal_y + normal_z * normal_z);
-        normalVectors[3 * (i + terrainSize * j) + 0] = normal_x / normal_length;
-        normalVectors[3 * (i + terrainSize * j) + 1] = normal_y / normal_length;
-        normalVectors[3 * (i + terrainSize * j) + 2] = normal_z / normal_length;
-
-        var textureRepeatingSpeed = 0.5;
-        textureCoords[2 * (i + terrainSize * j) + 0] = i * textureRepeatingSpeed;
-        textureCoords[2 * (i + terrainSize * j) + 1] = j * textureRepeatingSpeed;
-      }
-    }
-
-    var vertexPositionBuffer = gl.createBuffer();
-    gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
-    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
-    gl.vertexAttribPointer(vertexPositionAttrLoc, 3, gl.FLOAT, false, 0, 0);
-
-    var normalVectorBuffer = gl.createBuffer();
-    gl.bindBuffer(gl.ARRAY_BUFFER, normalVectorBuffer);
-    gl.bufferData(gl.ARRAY_BUFFER, normalVectors, gl.STATIC_DRAW);
-    gl.vertexAttribPointer(normalVectorAttrLoc, 3, gl.FLOAT, false, 0, 0);
-
-    var textureCoordBuffer = gl.createBuffer();
-    gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
-    gl.bufferData(gl.ARRAY_BUFFER, textureCoords, gl.STATIC_DRAW);
-    gl.vertexAttribPointer(textureCoordAttrLoc, 2, gl.FLOAT, false, 0, 0);
-
-    var indexBuffer = gl.createBuffer();
-    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
-    var indices = [];
-    for (var i = 0; i < terrainSize - 1; i++) {
-      for (var j = 0; j < terrainSize - 1; j++) {
-        indices.push(i   + terrainSize * j);
-        indices.push(i+1 + terrainSize * j);
-        indices.push(i+1 + terrainSize * (j+1));
-
-        indices.push(i   + terrainSize * j);
-        indices.push(i+1 + terrainSize * (j+1));
-        indices.push(i   + terrainSize * (j+1));
-      }
-    }
-    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
-
-    gl.enable(gl.DEPTH_TEST);
-
-    onresize();
-    window.addEventListener("resize", onresize);
-
-    startTestLoop(doneCallback);
-  }
-
-  function average(arr) {
-    var sum = 0;
-    for (var i in arr)
-      sum += arr[i];
-    return sum / (arr.length || 1);
-  }
-
-  // We use sample stddev and not population stddev because
-  // well.. it's a sample and we can't collect all/infinite number of frames.
-  function sampleStdDev(arr) {
-    if (arr.length <= 1) {
-      return 0;
-    }
-    var avg = average(arr);
-
-    var squareDiffArr = arr.map( function(v) { return Math.pow(v - avg, 2); } );
-    var sum = squareDiffArr.reduce( function(a, b) { return a + b; } );
-    var rv = Math.sqrt(sum / (arr.length - 1));
-    return rv;
-  }
-
-  const PRETEST_DELAY_MS  = 500;
-  const WARMUP_TIMESTAMPS = 30; // Must be at least 2
-  const MEASURED_FRAMES   = 100;
-
-  var gDoneCallback = function placeholder(intervals) {};
-  var gCurrentTimestamp = 0;
-  var gResultTimestamps = [];
-
-  function startTestLoop(doneCallback) {
-    gDoneCallback = doneCallback;
-    gCurrentTimestamp = 0;
-    gResultTimestamps = new Array(WARMUP_TIMESTAMPS + MEASURED_FRAMES);
-
-    Profiler.resume("Starting requestAnimationFrame loop", true);
-    requestAnimationFrame(draw);
-  }
-
-  function draw(timestamp) {
-    // It's possible that under some implementations (even if not our current one), 
-    // the rAF callback arg will be in some way "optimized", e.g. always point to the
-    // estimated next vsync timestamp, in order to allow the callee to have less
-    // jitter in its time-dependent positioning/processing.
-    // Such behaviour would harm our measurements, especially with vsync off.
-    // performance.now() will not have this potential issue and is high-resolution.
-    gResultTimestamps[gCurrentTimestamp++] = performance.now();
-    var recordedTimestamps = gCurrentTimestamp;
-    if (recordedTimestamps >= WARMUP_TIMESTAMPS + MEASURED_FRAMES) {
-      Profiler.pause("Stopping requestAnimationFrame loop", true);
-      var intervals = [];
-      var lastWarmupTimestampId = WARMUP_TIMESTAMPS - 1;
-      for (var i = lastWarmupTimestampId + 1; i < gResultTimestamps.length; i++) {
-        intervals.push(gResultTimestamps[i] - gResultTimestamps[i - 1]);
-      }
-
-      gDoneCallback(intervals);
-      return;
-    }
-
-    // Used for rendering reproducible frames which are independent of actual performance (timestamps).
-    var simulatedTimestamp = gCurrentTimestamp * 1000 / 60;
-
-    var speed = 0.001;
-    var angle =  simulatedTimestamp * speed;
-    var c = Math.cos(angle / 10);
-    var s = Math.sin(angle / 10);
-    var light_x = Math.cos(angle);
-    var light_y = -1;
-    var light_z = Math.sin(angle);
-    var l = Math.sqrt(light_x * light_x + light_y * light_y + light_z * light_z);
-    light_x /= l;
-    light_y /= l;
-    light_z /= l;
-    gl.uniform3f(lightDirectionUniformLoc, light_x, light_y, light_z);
-
-    modelviewMatrix[0]  = c;
-    modelviewMatrix[1]  = 0;
-    modelviewMatrix[2]  = s;
-    modelviewMatrix[3]  = 0;
-
-    modelviewMatrix[4]  = 0;
-    modelviewMatrix[5]  = 1;
-    modelviewMatrix[6]  = 0;
-    modelviewMatrix[7]  = 0;
-
-    modelviewMatrix[8]  = -s;
-    modelviewMatrix[9]  = 0;
-    modelviewMatrix[10] = c;
-    modelviewMatrix[11] = 0;
-
-    modelviewMatrix[12] = - terrainSize / 2;
-    modelviewMatrix[13] = 0;
-    modelviewMatrix[14] = - terrainSize;
-    modelviewMatrix[15] = 1;
-
-    gl.uniformMatrix4fv(modelviewUniformLoc, false, modelviewMatrix);
-
-    var fieldOfViewY = Math.PI / 4;
-    aspectRatio = gl.drawingBufferWidth / gl.drawingBufferHeight;
-    var zNear = 1;
-    var zFar = terrainSize;
-
-    projectionMatrix[0]  = fieldOfViewY / aspectRatio;
-    projectionMatrix[1]  = 0;
-    projectionMatrix[2]  = 0;
-    projectionMatrix[3]  = 0;
-
-    projectionMatrix[4]  = 0;
-    projectionMatrix[5]  = fieldOfViewY;
-    projectionMatrix[6]  = 0;
-    projectionMatrix[7]  = 0;
-
-    projectionMatrix[8]  = 0;
-    projectionMatrix[9]  = 0;
-    projectionMatrix[10] = (zNear + zFar) / (zNear - zFar);
-    projectionMatrix[11] = -1;
-
-    projectionMatrix[12] = 0;
-    projectionMatrix[13] = 0;
-    projectionMatrix[14] = 2 * zNear * zFar / (zNear - zFar);
-    projectionMatrix[15] = 0;
-
-    gl.uniformMatrix4fv(projectionUniformLoc, false, projectionMatrix);
-
-    gl.uniform1f(grassTextureSamplerUniformLoc, 0);
-
-    gl.clearColor(0.4, 0.6, 1.0, 0.5);
-    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
-    gl.drawElements(gl.TRIANGLES, (terrainSize - 1) * (terrainSize - 1) * 6, gl.UNSIGNED_SHORT, 0);
-
-    if (gCurrentTimestamp == 1) {
-      // First frame only - wait a bit (after rendering the scene once)
-      requestAnimationFrame(function() {
-        setTimeout(requestAnimationFrame, PRETEST_DELAY_MS, draw);
-      });
-    } else {
-      requestAnimationFrame(draw);
-    }
-  }
-
-  function onresize() {
-    var canvas =  document.getElementById("c");
-    canvas.width = window.innerWidth;
-    canvas.height = window.innerHeight;
-    aspectRatio = canvas.width / canvas.height;
-    gl.viewport(0, 0, canvas.width, canvas.height);
-  }
-
-  var gResults = {values: [], names: [], raw: []};
-
-  function setupAndRun(alpha, antialias, name, doneCallback) {
-    // Remove the old canvas if exists, and create a new one for the new run
-    var c = document.getElementById("c");
-    if (c)
-        c.parentNode.removeChild(c);
-    c = document.createElement("canvas");
-    c.id = "c";
-    document.body.insertBefore(c, document.body.firstChild)
-
-    // Trigger the run with specified args, with callback function to process the result
-    startTest(alpha, antialias, function(intervals) {
-        gResults.names.push(name);
-        gResults.raw.push(intervals);
-        setTimeout(doneCallback, 0);
-    });
-  }
-
-  function reportResults(results) {
-    // Format a nice human-readable report
-    var msg = "";
-    for (var i = 0; i < results.names.length; i++) {
-      var data = results.raw[i];
-      var avg   = average(data);
-      gResults.values.push(avg); // This is the only "official" reported value for this set
-      var sd = sampleStdDev(data);
-
-      // Compose a nice human readable message. Not used officially anywhere.
-      msg += results.names[i] + "= Average: " + avg.toFixed(2)
-           + "  stddev: " + sd.toFixed(1) + " (" + (100 * sd / avg).toFixed(1) + "%)"
-           + "\nIntervals: " + data.map(function(v) {
-                // Display with 1 decimal point digit, and make excessively big values noticeable.
-                var value = v.toFixed(1);
-                // Not scientific, but intervals over 2 * average are.. undesirable.
-                var threshold = avg * 2;
-                return v < threshold ? value : " [_" + value + "_] ";
-             }).join("  ")
-           + "\n\n";
-    }
-    dump(msg); // Put the readable report at talos run-log
-
-    if (window.tpRecordTime) {
-      // within talos - report the results
-      return tpRecordTime(results.values.join(","), 0, results.names.join(","));
-    } else {
-      // Local run in a plain browser, display the formatted report
-      alert(msg);
-    }
-  }
-
-  // The full test starts here
-  function test() {
-    // We initially hide the <body>, to reduce the chance of spinning our wheels
-    // with incremental ASAP-paint-mode paints during pageload. Now that onload
-    // has fired, we un-hide it:
-    document.body.style.display = "";
-
-    gResults = {values: [], names: [], raw: []};
-    // This test measures average frame interval during WebGL animation as follows:
-    // 1. Creates a new WebGL canvas.
-    // 2. setup the scene and render 1 frame.
-    // 3. Idle a bit (500ms).
-    // 4. Render/Animate several (129) frames using requestAnimationFrame.
-    // 5. Average the intervals of the last (100) frames <-- the result.
-    //
-    // The reason for the initial idle is to allow some internal cleanups (like CC/GC etc).
-    // The unmeasured warmup rendering intervals are to allow Firefox to settle at a consistent rate.
-    // The idle + warmup are common practices in benchmarking where we're mostly interested
-    // in the stable/consistent throughput rather than in the throughput during transition state
-    // from idle to iterating.
-
-    // Run the same sequence 4 times for all combination of alpha and antialias
-    // (Not using promises chaining for better compatibility, ending up with nesting instead)
-    // talos unfortunately trims common prefixes, so we prefix with a running number to keep the full name
-    setupAndRun(false, false, "0.WebGL-terrain-alpha-no-AA-no", function() {
-      setupAndRun(false, true,  "1.WebGL-terrain-alpha-no-AA-yes", function() {
-        setupAndRun(true,  false, "2.WebGL-terrain-alpha-yes-AA-no", function() {
-          setupAndRun(true,  true,  "3.WebGL-terrain-alpha-yes-AA-yes", function() {
-            reportResults(gResults);
-          })
-        })
-      })
-    });
-  }
-</script>
-</head>
-<body onload="test();" style="overflow:hidden; margin:0; display:none">
-<canvas id="c"></canvas>
-<img src="grass.jpeg" style="display:none" id="grass"/>
-</body>
+<html>
+<!--
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+ Version 1.1
+   - Added viewport rotation.
+   - Adapted for talos with with 4 runs on combinations of alpha/antialias
+
+ Version 1.0
+   - Benoit Jacob's WebGL tutorial demos: http://bjacob.github.io/webgl-tutorial/12-texture.html
+-->
+<head>
+<meta charset="utf-8"/>
+<script src="../../../../scripts/Profiler.js"></script>
+<script type="x-shader/x-vertex" id="vertexShader">
+  attribute vec3 vertexPosition;
+  attribute vec3 normalVector;
+  attribute vec2 textureCoord;
+  uniform mat4 modelview;
+  uniform mat4 projection;
+  varying vec3 varyingNormalVector;
+  varying vec2 varyingTextureCoord;
+  void main(void) {
+    gl_Position = projection * modelview * vec4(vertexPosition, 1.0);
+    varyingNormalVector = normalVector;
+    varyingTextureCoord = textureCoord;
+  }
+</script>
+<script type="x-shader/x-fragment" id="fragmentShader">
+  precision mediump float;
+  varying vec3 varyingNormalVector;
+  uniform vec3 lightDirection;
+  uniform sampler2D grassTextureSampler;
+  varying vec2 varyingTextureCoord;
+  void main(void) {
+    vec3 grassColor = texture2D(grassTextureSampler, varyingTextureCoord).rgb;
+    const float ambientLight = 0.3;
+    const float diffuseLight = 0.7;
+    float c = clamp(dot(normalize(varyingNormalVector), lightDirection), 0.0, 1.0);
+    vec3 resultColor = grassColor * (c * diffuseLight + ambientLight);
+    gl_FragColor = vec4(resultColor, 1);
+  }
+</script>
+<script>
+  var gl;
+
+  var modelviewUniformLoc;
+  var projectionUniformLoc;
+  var lightDirectionUniformLoc;
+  var grassTextureSamplerUniformLoc;
+
+  var modelviewMatrix = new Float32Array(16);
+  var projectionMatrix = new Float32Array(16);
+
+  var terrainSize = 32;
+  var aspectRatio;
+
+  function startTest(alpha, antialias, doneCallback) {
+    gl = document.getElementById("c").getContext("webgl", {alpha, antialias});
+
+    var grassImage = document.getElementById("grass");
+    var grassTexture = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, grassTexture);
+    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, grassImage);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
+    gl.generateMipmap(gl.TEXTURE_2D);
+
+    var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    var vertexShaderString = document.getElementById("vertexShader").text;
+    gl.shaderSource(vertexShader, vertexShaderString);
+    gl.compileShader(vertexShader);
+
+    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+    var fragmentShaderString = document.getElementById("fragmentShader").text;
+    gl.shaderSource(fragmentShader, fragmentShaderString);
+    gl.compileShader(fragmentShader);
+
+    var program = gl.createProgram();
+    gl.attachShader(program, vertexShader);
+    gl.attachShader(program, fragmentShader);
+    gl.linkProgram(program);
+    gl.useProgram(program);
+
+    var vertexPositionAttrLoc = gl.getAttribLocation(program, "vertexPosition");
+    gl.enableVertexAttribArray(vertexPositionAttrLoc);
+    var normalVectorAttrLoc = gl.getAttribLocation(program, "normalVector");
+    gl.enableVertexAttribArray(normalVectorAttrLoc);
+    var textureCoordAttrLoc = gl.getAttribLocation(program, "textureCoord");
+    gl.enableVertexAttribArray(textureCoordAttrLoc);
+
+    modelviewUniformLoc = gl.getUniformLocation(program, "modelview");
+    projectionUniformLoc = gl.getUniformLocation(program, "projection");
+    lightDirectionUniformLoc = gl.getUniformLocation(program, "lightDirection");
+    grassTextureSamplerUniformLoc = gl.getUniformLocation(program, "grassTextureSampler");
+
+    var vertices = new Float32Array(terrainSize * terrainSize * 3);
+    var normalVectors = new Float32Array(terrainSize * terrainSize * 3);
+    var textureCoords = new Float32Array(terrainSize * terrainSize * 2);
+
+    for (var i = 0; i < terrainSize; i++) {
+      for (var j = 0; j < terrainSize; j++) {
+        var a = 2 * Math.PI * i / terrainSize;
+        var b = 2 * Math.PI * j / terrainSize;
+        var height = 4 * Math.cos(a) + 6 * Math.sin(b) + Math.cos(4 * a) + Math.sin(5 * b);
+        vertices[3 * (i + terrainSize * j) + 0] = i;
+        vertices[3 * (i + terrainSize * j) + 1] = height;
+        vertices[3 * (i + terrainSize * j) + 2] = j;
+
+        var d_y_d_x = (2 * Math.PI / terrainSize) * (-4 * Math.sin(a) - 4 * Math.sin(4 * a));
+        var d_y_d_z = (2 * Math.PI / terrainSize) * (6 * Math.cos(b) + 5 * Math.cos(5 * b));
+        var normal_x = d_y_d_x;
+        var normal_y = -1;
+        var normal_z = d_y_d_z;
+        var normal_length = Math.sqrt(normal_x * normal_x + normal_y * normal_y + normal_z * normal_z);
+        normalVectors[3 * (i + terrainSize * j) + 0] = normal_x / normal_length;
+        normalVectors[3 * (i + terrainSize * j) + 1] = normal_y / normal_length;
+        normalVectors[3 * (i + terrainSize * j) + 2] = normal_z / normal_length;
+
+        var textureRepeatingSpeed = 0.5;
+        textureCoords[2 * (i + terrainSize * j) + 0] = i * textureRepeatingSpeed;
+        textureCoords[2 * (i + terrainSize * j) + 1] = j * textureRepeatingSpeed;
+      }
+    }
+
+    var vertexPositionBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
+    gl.vertexAttribPointer(vertexPositionAttrLoc, 3, gl.FLOAT, false, 0, 0);
+
+    var normalVectorBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, normalVectorBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, normalVectors, gl.STATIC_DRAW);
+    gl.vertexAttribPointer(normalVectorAttrLoc, 3, gl.FLOAT, false, 0, 0);
+
+    var textureCoordBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, textureCoords, gl.STATIC_DRAW);
+    gl.vertexAttribPointer(textureCoordAttrLoc, 2, gl.FLOAT, false, 0, 0);
+
+    var indexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+    var indices = [];
+    for (var k = 0; k < terrainSize - k; k++) {
+      for (var l = 0; l < terrainSize - 1; l++) {
+        indices.push(k + terrainSize * l);
+        indices.push(k + 1 + terrainSize * l);
+        indices.push(k + 1 + terrainSize * (l + 1));
+
+        indices.push(k + terrainSize * l);
+        indices.push(k + 1 + terrainSize * (l + 1));
+        indices.push(k + terrainSize * (l + 1));
+      }
+    }
+    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
+
+    gl.enable(gl.DEPTH_TEST);
+
+    onresize();
+    window.addEventListener("resize", onresize);
+
+    startTestLoop(doneCallback);
+  }
+
+  function average(arr) {
+    var sum = 0;
+    for (var i in arr)
+      sum += arr[i];
+    return sum / (arr.length || 1);
+  }
+
+  // We use sample stddev and not population stddev because
+  // well.. it's a sample and we can't collect all/infinite number of frames.
+  function sampleStdDev(arr) {
+    if (arr.length <= 1) {
+      return 0;
+    }
+    var avg = average(arr);
+
+    var squareDiffArr = arr.map( function(v) { return Math.pow(v - avg, 2); } );
+    var sum = squareDiffArr.reduce( function(a, b) { return a + b; } );
+    var rv = Math.sqrt(sum / (arr.length - 1));
+    return rv;
+  }
+
+  const PRETEST_DELAY_MS  = 500;
+  const WARMUP_TIMESTAMPS = 30; // Must be at least 2
+  const MEASURED_FRAMES   = 100;
+
+  var gDoneCallback = function placeholder(intervals) {};
+  var gCurrentTimestamp = 0;
+  var gResultTimestamps = [];
+
+  function startTestLoop(doneCallback) {
+    gDoneCallback = doneCallback;
+    gCurrentTimestamp = 0;
+    gResultTimestamps = new Array(WARMUP_TIMESTAMPS + MEASURED_FRAMES);
+
+    Profiler.resume("Starting requestAnimationFrame loop", true);
+    requestAnimationFrame(draw);
+  }
+
+  function draw(timestamp) {
+    // It's possible that under some implementations (even if not our current one),
+    // the rAF callback arg will be in some way "optimized", e.g. always point to the
+    // estimated next vsync timestamp, in order to allow the callee to have less
+    // jitter in its time-dependent positioning/processing.
+    // Such behaviour would harm our measurements, especially with vsync off.
+    // performance.now() will not have this potential issue and is high-resolution.
+    gResultTimestamps[gCurrentTimestamp++] = performance.now();
+    var recordedTimestamps = gCurrentTimestamp;
+    if (recordedTimestamps >= WARMUP_TIMESTAMPS + MEASURED_FRAMES) {
+      Profiler.pause("Stopping requestAnimationFrame loop", true);
+      var intervals = [];
+      var lastWarmupTimestampId = WARMUP_TIMESTAMPS - 1;
+      for (var i = lastWarmupTimestampId + 1; i < gResultTimestamps.length; i++) {
+        intervals.push(gResultTimestamps[i] - gResultTimestamps[i - 1]);
+      }
+
+      gDoneCallback(intervals);
+      return;
+    }
+
+    // Used for rendering reproducible frames which are independent of actual performance (timestamps).
+    var simulatedTimestamp = gCurrentTimestamp * 1000 / 60;
+
+    var speed = 0.001;
+    var angle =  simulatedTimestamp * speed;
+    var c = Math.cos(angle / 10);
+    var s = Math.sin(angle / 10);
+    var light_x = Math.cos(angle);
+    var light_y = -1;
+    var light_z = Math.sin(angle);
+    var l = Math.sqrt(light_x * light_x + light_y * light_y + light_z * light_z);
+    light_x /= l;
+    light_y /= l;
+    light_z /= l;
+    gl.uniform3f(lightDirectionUniformLoc, light_x, light_y, light_z);
+
+    modelviewMatrix[0]  = c;
+    modelviewMatrix[1]  = 0;
+    modelviewMatrix[2]  = s;
+    modelviewMatrix[3]  = 0;
+
+    modelviewMatrix[4]  = 0;
+    modelviewMatrix[5]  = 1;
+    modelviewMatrix[6]  = 0;
+    modelviewMatrix[7]  = 0;
+
+    modelviewMatrix[8]  = -s;
+    modelviewMatrix[9]  = 0;
+    modelviewMatrix[10] = c;
+    modelviewMatrix[11] = 0;
+
+    modelviewMatrix[12] = -terrainSize / 2;
+    modelviewMatrix[13] = 0;
+    modelviewMatrix[14] = -terrainSize;
+    modelviewMatrix[15] = 1;
+
+    gl.uniformMatrix4fv(modelviewUniformLoc, false, modelviewMatrix);
+
+    var fieldOfViewY = Math.PI / 4;
+    aspectRatio = gl.drawingBufferWidth / gl.drawingBufferHeight;
+    var zNear = 1;
+    var zFar = terrainSize;
+
+    projectionMatrix[0]  = fieldOfViewY / aspectRatio;
+    projectionMatrix[1]  = 0;
+    projectionMatrix[2]  = 0;
+    projectionMatrix[3]  = 0;
+
+    projectionMatrix[4]  = 0;
+    projectionMatrix[5]  = fieldOfViewY;
+    projectionMatrix[6]  = 0;
+    projectionMatrix[7]  = 0;
+
+    projectionMatrix[8]  = 0;
+    projectionMatrix[9]  = 0;
+    projectionMatrix[10] = (zNear + zFar) / (zNear - zFar);
+    projectionMatrix[11] = -1;
+
+    projectionMatrix[12] = 0;
+    projectionMatrix[13] = 0;
+    projectionMatrix[14] = 2 * zNear * zFar / (zNear - zFar);
+    projectionMatrix[15] = 0;
+
+    gl.uniformMatrix4fv(projectionUniformLoc, false, projectionMatrix);
+
+    gl.uniform1f(grassTextureSamplerUniformLoc, 0);
+
+    gl.clearColor(0.4, 0.6, 1.0, 0.5);
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+    gl.drawElements(gl.TRIANGLES, (terrainSize - 1) * (terrainSize - 1) * 6, gl.UNSIGNED_SHORT, 0);
+
+    if (gCurrentTimestamp == 1) {
+      // First frame only - wait a bit (after rendering the scene once)
+      requestAnimationFrame(function() {
+        setTimeout(requestAnimationFrame, PRETEST_DELAY_MS, draw);
+      });
+    } else {
+      requestAnimationFrame(draw);
+    }
+  }
+
+  function onresize() {
+    var canvas =  document.getElementById("c");
+    canvas.width = window.innerWidth;
+    canvas.height = window.innerHeight;
+    aspectRatio = canvas.width / canvas.height;
+    gl.viewport(0, 0, canvas.width, canvas.height);
+  }
+
+  var gResults = {values: [], names: [], raw: []};
+
+  function setupAndRun(alpha, antialias, name, doneCallback) {
+    // Remove the old canvas if exists, and create a new one for the new run
+    var c = document.getElementById("c");
+    if (c)
+        c.remove();
+    c = document.createElement("canvas");
+    c.id = "c";
+    document.body.insertBefore(c, document.body.firstChild)
+
+    // Trigger the run with specified args, with callback function to process the result
+    startTest(alpha, antialias, function(intervals) {
+        gResults.names.push(name);
+        gResults.raw.push(intervals);
+        setTimeout(doneCallback, 0);
+    });
+  }
+
+  function reportResults(results) {
+    // Format a nice human-readable report
+    var msg = "";
+    for (var i = 0; i < results.names.length; i++) {
+      var data = results.raw[i];
+      var avg   = average(data);
+      gResults.values.push(avg); // This is the only "official" reported value for this set
+      var sd = sampleStdDev(data);
+
+      // Compose a nice human readable message. Not used officially anywhere.
+      msg += results.names[i] + "= Average: " + avg.toFixed(2)
+           + "  stddev: " + sd.toFixed(1) + " (" + (100 * sd / avg).toFixed(1) + "%)"
+           + "\nIntervals: " + data.map(function(v) {
+                // Display with 1 decimal point digit, and make excessively big values noticeable.
+                var value = v.toFixed(1);
+                // Not scientific, but intervals over 2 * average are.. undesirable.
+                var threshold = avg * 2;
+                return v < threshold ? value : " [_" + value + "_] ";
+             }).join("  ")
+           + "\n\n";
+    }
+    dump(msg); // Put the readable report at talos run-log
+
+    if (window.tpRecordTime) {
+      // within talos - report the results
+      return tpRecordTime(results.values.join(","), 0, results.names.join(","));
+    }
+    // Local run in a plain browser, display the formatted report
+    alert(msg);
+    return undefined;
+  }
+
+  // The full test starts here
+  function test() {
+    // We initially hide the <body>, to reduce the chance of spinning our wheels
+    // with incremental ASAP-paint-mode paints during pageload. Now that onload
+    // has fired, we un-hide it:
+    document.body.style.display = "";
+
+    gResults = {values: [], names: [], raw: []};
+    // This test measures average frame interval during WebGL animation as follows:
+    // 1. Creates a new WebGL canvas.
+    // 2. setup the scene and render 1 frame.
+    // 3. Idle a bit (500ms).
+    // 4. Render/Animate several (129) frames using requestAnimationFrame.
+    // 5. Average the intervals of the last (100) frames <-- the result.
+    //
+    // The reason for the initial idle is to allow some internal cleanups (like CC/GC etc).
+    // The unmeasured warmup rendering intervals are to allow Firefox to settle at a consistent rate.
+    // The idle + warmup are common practices in benchmarking where we're mostly interested
+    // in the stable/consistent throughput rather than in the throughput during transition state
+    // from idle to iterating.
+
+    // Run the same sequence 4 times for all combination of alpha and antialias
+    // (Not using promises chaining for better compatibility, ending up with nesting instead)
+    // talos unfortunately trims common prefixes, so we prefix with a running number to keep the full name
+    setupAndRun(false, false, "0.WebGL-terrain-alpha-no-AA-no", function() {
+      setupAndRun(false, true, "1.WebGL-terrain-alpha-no-AA-yes", function() {
+        setupAndRun(true, false, "2.WebGL-terrain-alpha-yes-AA-no", function() {
+          setupAndRun(true, true, "3.WebGL-terrain-alpha-yes-AA-yes", function() {
+            reportResults(gResults);
+          })
+        })
+      })
+    });
+  }
+</script>
+</head>
+<body onload="test();" style="overflow:hidden; margin:0; display:none">
+<canvas id="c"></canvas>
+<img src="grass.jpeg" style="display:none" id="grass"/>
+</body>
--- a/testing/talos/talos/tests/webgl/benchmarks/video/video_upload.html
+++ b/testing/talos/talos/tests/webgl/benchmarks/video/video_upload.html
@@ -52,15 +52,16 @@ function reportResult(totalTime, totalTi
 
   if (window.tpRecordTime) {
     // Within talos - report the results
     return tpRecordTime(meanTickTime, 0, desc);
   }
     // Local run in a plain browser, display the formatted report
     alert("[talos glvideo result] " + text);
 
+  return undefined;
 }
 </script>
 
 </head>
 <body id="body" onload="init();">
 </body>
 </html>