Bug 1515942 - Enable ESLint for gfx/ (manual fixes). r=kats
authorMark Banner <standard8@mozilla.com>
Thu, 27 Dec 2018 09:45:01 +0000
changeset 511952 d6c5ea714d9dcfe4c96c86dc1c5b5c0abd19b6f2
parent 511951 cda72b927c04782a92408dabcb9b355d397b4bd5
child 511953 28a22fe8900402db17bb6eef75d764e239c9276d
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs1515942
milestone66.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 1515942 - Enable ESLint for gfx/ (manual fixes). r=kats Differential Revision: https://phabricator.services.mozilla.com/D15206
.eslintignore
.eslintrc.js
gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
gfx/layers/apz/test/mochitest/apz_test_utils.js
gfx/layers/apz/test/mochitest/helper_hittest_backface_hidden.html
gfx/layers/apz/test/mochitest/helper_overscroll_behavior_bug1494440.html
gfx/layers/apz/test/mochitest/helper_touch_action_regions.html
gfx/layers/apz/test/mochitest/test_wheel_scroll.html
gfx/layers/layerviewer/layerTreeView.js
gfx/tests/chrome/test_device_reset.html
gfx/tests/mochitest/test_acceleration.html
gfx/tests/mochitest/test_bug509244.html
tools/lint/eslint/eslint-plugin-mozilla/lib/environments/simpletest.js
--- a/.eslintignore
+++ b/.eslintignore
@@ -15,20 +15,16 @@ obj*/**
 # If you are enabling a directory, please add directory specific exclusions
 # below.
 docshell/test/browser/**
 docshell/test/iframesandbox/**
 docshell/test/mochitest/**
 extensions/cookie/**
 extensions/spellcheck/**
 extensions/universalchardet/**
-gfx/layers/**
-gfx/tests/browser/**
-gfx/tests/chrome/**
-gfx/tests/mochitest/**
 image/**
 layout/**
 modules/**
 netwerk/cookie/test/browser/**
 netwerk/test/browser/**
 netwerk/test/mochitests/**
 netwerk/test/unit*/**
 tools/update-packaging/**
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -41,10 +41,16 @@ module.exports = {
     }
   }, {
     // TODO: Bug 1513639. Temporarily turn off reject-importGlobalProperties
     // due to other ESLint enabling happening in DOM.
     "files": "dom/**",
     "rules": {
       "mozilla/reject-importGlobalProperties": "off",
     }
+  }, {
+    // TODO: Bug 1515949. Enable no-undef for gfx/
+    "files": "gfx/layers/apz/test/mochitest/**",
+    "rules": {
+      "no-undef": "off",
+    }
   }]
 };
--- a/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
+++ b/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
@@ -1,8 +1,11 @@
+// ownerGlobal isn't defined in content privileged windows.
+/* eslint-disable mozilla/use-ownerGlobal */
+
 // Utilities for synthesizing of native events.
 
 function getResolution() {
   let resolution = { value: -1 }; // bogus value in case DWU fails us
   SpecialPowers.getDOMWindowUtils(window).getResolution(resolution);
   return resolution.value;
 }
 
@@ -260,25 +263,25 @@ function synthesizeNativeTouch(aTarget, 
 // aObserver is the observer that will get registered on the very last
 //   synthesizeNativeTouch call this function makes.
 // aTouchIds is an array holding the touch ID values of each "finger".
 function* synthesizeNativeTouchSequences(aTarget, aPositions, aObserver = null, aTouchIds = [0]) {
   // We use lastNonNullValue to figure out which synthesizeNativeTouch call
   // will be the last one we make, so that we can register aObserver on it.
   var lastNonNullValue = -1;
   var yields = 0;
-  for (var i = 0; i < aPositions.length; i++) {
+  for (let i = 0; i < aPositions.length; i++) {
     if (aPositions[i] == null) {
       yields++;
       continue;
     }
     if (aPositions[i].length != aTouchIds.length) {
       throw "aPositions[" + i + "] did not have the expected number of positions; expected " + aTouchIds.length + " touch points but found " + aPositions[i].length;
     }
-    for (var j = 0; j < aTouchIds.length; j++) {
+    for (let j = 0; j < aTouchIds.length; j++) {
       if (aPositions[i][j] != null) {
         lastNonNullValue = ((i - yields) * aTouchIds.length) + j;
       }
     }
   }
   if (lastNonNullValue < 0) {
     throw "All values in positions array were null!";
   }
@@ -295,23 +298,23 @@ function* synthesizeNativeTouchSequences
   var lastSynthesizeCall = lastNonNullValue + aTouchIds.length;
 
   // track which touches are down and which are up. start with all up
   var currentPositions = new Array(aTouchIds.length);
   currentPositions.fill(null);
 
   // Iterate over the position data now, and generate the touches requested
   yields = 0;
-  for (var i = 0; i < aPositions.length; i++) {
+  for (let i = 0; i < aPositions.length; i++) {
     if (aPositions[i] == null) {
       yields++;
       yield i;
       continue;
     }
-    for (var j = 0; j < aTouchIds.length; j++) {
+    for (let j = 0; j < aTouchIds.length; j++) {
       if (aPositions[i][j] == null) {
         // null means lift the finger
         if (currentPositions[j] == null) {
           // it's already lifted, do nothing
         } else {
           // synthesize the touch-up. If this is the last call we're going to
           // make, pass the observer as well
           var thisIndex = ((i - yields) * aTouchIds.length) + j;
@@ -328,18 +331,17 @@ function* synthesizeNativeTouchSequences
   return true;
 }
 
 // Note that when calling this function you'll want to make sure that the pref
 // "apz.touch_start_tolerance" is set to 0, or some of the touchmove will get
 // consumed to overcome the panning threshold.
 function synthesizeNativeTouchDrag(aTarget, aX, aY, aDeltaX, aDeltaY, aObserver = null, aTouchId = 0) {
   var steps = Math.max(Math.abs(aDeltaX), Math.abs(aDeltaY));
-  var positions = new Array();
-  positions.push([{ x: aX, y: aY }]);
+  var positions = [[{ x: aX, y: aY }]];
   for (var i = 1; i < steps; i++) {
     var dx = i * (aDeltaX / steps);
     var dy = i * (aDeltaY / steps);
     var pos = { x: aX + dx, y: aY + dy };
     positions.push([pos]);
   }
   positions.push([{ x: aX + aDeltaX, y: aY + aDeltaY }]);
   var continuation = synthesizeNativeTouchSequences(aTarget, positions, aObserver, [aTouchId]);
--- a/gfx/layers/apz/test/mochitest/apz_test_utils.js
+++ b/gfx/layers/apz/test/mochitest/apz_test_utils.js
@@ -3,16 +3,19 @@
 // ----------------------------------------------------------------------
 // Functions that convert the APZ test data into a more usable form.
 // Every place we have a WebIDL sequence whose elements are dictionaries
 // with two elements, a key, and a value, we convert this into a JS
 // object with a property for each key/value pair. (This is the structure
 // we really want, but we can't express in directly in WebIDL.)
 // ----------------------------------------------------------------------
 
+// getHitTestConfig() expects apz_test_native_event_utils.js to be loaded as well.
+/* import-globals-from apz_test_native_event_utils.js */
+
 function convertEntries(entries) {
   var result = {};
   for (var i = 0; i < entries.length; ++i) {
     result[entries[i].key] = entries[i].value;
   }
   return result;
 }
 
@@ -82,21 +85,21 @@ function isTransformClose(a, b, name) {
 // APZC tree structure corresponding to the layer subtree for the
 // content process that triggered the paint, is reconstructed (as
 // the APZ test data only contains information abot this subtree).
 function buildApzcTree(paint) {
   // The APZC tree can potentially have multiple root nodes,
   // so we invent a node that is the parent of all roots.
   // This 'root' does not correspond to an APZC.
   var root = {scrollId: -1, children: []};
-  for (var scrollId in paint) {
+  for (let scrollId in paint) {
     paint[scrollId].children = [];
     paint[scrollId].scrollId = scrollId;
   }
-  for (var scrollId in paint) {
+  for (let scrollId in paint) {
     var parentNode = null;
     if ("hasNoParentWithSameLayersId" in paint[scrollId]) {
       parentNode = root;
     } else if ("parentScrollId" in paint[scrollId]) {
       parentNode = paint[paint[scrollId].parentScrollId];
     }
     parentNode.children.push(paint[scrollId]);
   }
@@ -293,17 +296,17 @@ function runSubtestsSeriallyInFreshWindo
           request.open("GET", url, false);
           request.send();
           return request.status !== 404;
         }
         if (!urlResolves(subtestUrl)) {
           SimpleTest.ok(false, "Subtest URL " + subtestUrl + " does not resolve. " +
               "Be sure it's present in the support-files section of mochitest.ini.");
           reject();
-          return;
+          return undefined;
         }
         w.location = subtestUrl;
         return w;
       }
 
       if (test.prefs) {
         // Got some prefs for this subtest, push them
         SpecialPowers.pushPrefEnv({"set": test.prefs}, function() {
@@ -330,16 +333,17 @@ async function waitUntilApzStable() {
     // and for those scenarios we want to flush the parent-process layer
     // tree to the compositor and wait for that as well. That way we know
     // that not only is the content-process layer tree ready in the compositor,
     // the parent-process layer tree in the compositor has the appropriate
     // RefLayer pointing to the content-process layer tree.
 
     // Sadly this helper function cannot reuse any code from other places because
     // it must be totally self-contained to be shipped over to the parent process.
+    /* eslint-env mozilla/frame-script */
     function parentProcessFlush() {
       addMessageListener("apz-flush", function() {
         ChromeUtils.import("resource://gre/modules/Services.jsm");
         var topWin = Services.wm.getMostRecentWindow("navigator:browser");
         if (!topWin) {
           topWin = Services.wm.getMostRecentWindow("navigator:geckoview");
         }
         var topUtils = topWin.windowUtils;
@@ -476,34 +480,36 @@ function runContinuation(testFunction) {
 // element is obscured by other things on top, the snapshot will include those
 // things. If it is clipped by a scroll container, the snapshot will include
 // that area anyway, so you will probably get parts of the scroll container in
 // the snapshot. If the rect extends outside the browser window then the
 // results are undefined.
 // The snapshot is returned in the form of a data URL.
 function getSnapshot(rect) {
   function parentProcessSnapshot() {
-    addMessageListener("snapshot", function(rect) {
+    addMessageListener("snapshot", function(parentRect) {
       ChromeUtils.import("resource://gre/modules/Services.jsm");
       var topWin = Services.wm.getMostRecentWindow("navigator:browser");
       if (!topWin) {
         topWin = Services.wm.getMostRecentWindow("navigator:geckoview");
       }
 
       // reposition the rect relative to the top-level browser window
-      rect = JSON.parse(rect);
-      rect.x -= topWin.mozInnerScreenX;
-      rect.y -= topWin.mozInnerScreenY;
+      parentRect = JSON.parse(parentRect);
+      parentRect.x -= topWin.mozInnerScreenX;
+      parentRect.y -= topWin.mozInnerScreenY;
 
       // take the snapshot
       var canvas = topWin.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
-      canvas.width = rect.w;
-      canvas.height = rect.h;
+      canvas.width = parentRect.w;
+      canvas.height = parentRect.h;
       var ctx = canvas.getContext("2d");
-      ctx.drawWindow(topWin, rect.x, rect.y, rect.w, rect.h, "rgb(255,255,255)", ctx.DRAWWINDOW_DRAW_VIEW | ctx.DRAWWINDOW_USE_WIDGET_LAYERS | ctx.DRAWWINDOW_DRAW_CARET);
+      ctx.drawWindow(topWin, parentRect.x, parentRect.y, parentRect.w, parentRect.h,
+        "rgb(255,255,255)",
+        ctx.DRAWWINDOW_DRAW_VIEW | ctx.DRAWWINDOW_USE_WIDGET_LAYERS | ctx.DRAWWINDOW_DRAW_CARET);
       return canvas.toDataURL();
     });
   }
 
   if (typeof getSnapshot.chromeHelper == "undefined") {
     // This is the first time getSnapshot is being called; do initialization
     getSnapshot.chromeHelper = SpecialPowers.loadChromeScript(parentProcessSnapshot);
     ApzCleanup.register(function() { getSnapshot.chromeHelper.destroy(); });
--- a/gfx/layers/apz/test/mochitest/helper_hittest_backface_hidden.html
+++ b/gfx/layers/apz/test/mochitest/helper_hittest_backface_hidden.html
@@ -48,17 +48,17 @@ function* test(testDriver) {
   // Set a displayport to ensure the subframe is layerized.
   // This is not required for exercising the behavior we want to test,
   // but it's needed to be able to assert the results reliably.
   config.utils.setDisplayPortForElement(0, 0, 1000, 1000, subframe, 1);
   yield waitForApzFlushedRepaints(testDriver);
 
   var subframeViewId = config.utils.getViewId(subframe);
 
-  var {hitInfo, scrollId} = hitTest(centerOf(subframe));
+  var {scrollId} = hitTest(centerOf(subframe));
 
   is(scrollId, subframeViewId,
      "hit the scroll frame behind the backface-visibility:hidden element");
 
   subtestDone();
 }
 
 waitUntilApzStable().then(runContinuation(test));
--- a/gfx/layers/apz/test/mochitest/helper_overscroll_behavior_bug1494440.html
+++ b/gfx/layers/apz/test/mochitest/helper_overscroll_behavior_bug1494440.html
@@ -10,17 +10,16 @@
   </iframe>
   <div style="height: 5000px;"></div><!-- So the page is scrollable as well -->
 
   <script type="application/javascript">
 
 function* test(testDriver) {
   var iframe = document.getElementById("scroll");
   var iframeWindow = iframe.contentWindow;
-  var iframeContent = iframeWindow.document.documentElement;
 
   // scroll the iframe to the bottom, such that a subsequent scroll on it
   // _would_ hand off to the page if overscroll-behavior allowed it
   iframeWindow.scrollTo(0, iframeWindow.scrollMaxY);
   yield waitForApzFlushedRepaints(testDriver);
   is(iframeWindow.scrollY, iframeWindow.scrollMaxY, "iframe has scrolled to the bottom");
 
   // Scroll over the iframe, and make sure that the page
--- a/gfx/layers/apz/test/mochitest/helper_touch_action_regions.html
+++ b/gfx/layers/apz/test/mochitest/helper_touch_action_regions.html
@@ -25,16 +25,17 @@ function listener(callback) {
 // function can be called with three values: 'start', 'report', and 'end'.
 // The 'start' invocation sets up the listeners, and should be invoked before
 // the touch events of interest are generated. This should only be called once.
 // This returns true on success, and false on failure.
 // The 'report' invocation can be invoked multiple times, and returns an object
 // (in JSON string format) containing the counters.
 // The 'end' invocation tears down the listeners, and should be invoked once
 // at the end to clean up. Returns true on success, false on failure.
+/* eslint-env mozilla/frame-script */
 function chromeTouchEventCounter(operation) {
   function chromeProcessCounter() {
     addMessageListener("start", function() {
       ChromeUtils.import("resource://gre/modules/Services.jsm");
       var topWin = Services.wm.getMostRecentWindow("navigator:browser");
       if (typeof topWin.eventCounts != "undefined") {
         dump("Found pre-existing eventCounts object on the top window!\n");
         return false;
@@ -176,17 +177,17 @@ function* test(testDriver) {
 
   // Set up the chrome process touch listener
   ok(chromeTouchEventCounter("start"), "Chrome touch counter registered");
 
   // Set up the child process events and callbacks
   var scroller = document.getElementById("scroller");
   synthesizeNativeTouch(scroller, 10, 110, SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, null, 0);
   RunAfterProcessedQueuedInputEvents(testDriver);
-  for (var i = 1; i < 10; i++) {
+  for (let i = 1; i < 10; i++) {
     synthesizeNativeTouch(scroller, 10, 110 - (i * 10), SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, null, 0);
     RunAfterProcessedQueuedInputEvents(testDriver);
   }
   synthesizeNativeTouch(scroller, 10, 10, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE, null, 0);
   RunAfterProcessedQueuedInputEvents(testDriver);
   ok(true, "Finished setting up event queue");
 
   // Get our baseline snapshot
@@ -195,17 +196,17 @@ function* test(testDriver) {
   ok(true, "Got baseline snapshot");
   var numDifferentSnapshotPairs = 0;
 
   yield; // this will tell the chrome process to synthesize the touchstart event
          // and then we wait to make sure it got processed:
   ok(waitFor("touchstart", 1), "Touchstart processed in chrome process");
 
   // Loop through the touchmove events
-  for (var i = 1; i < 10; i++) {
+  for (let i = 1; i < 10; i++) {
     yield;
     ok(waitFor("touchmove", i), "Touchmove processed in chrome process");
 
     // Take a snapshot after each touch move event. This forces
     // a composite each time, even we don't get a vsync in this
     // interval.
     var snapshot = getSnapshot(rect);
     if (lastSnapshot != snapshot) {
--- a/gfx/layers/apz/test/mochitest/test_wheel_scroll.html
+++ b/gfx/layers/apz/test/mochitest/test_wheel_scroll.html
@@ -74,20 +74,19 @@ document.getElementById("scrollbox").add
   rotation += e.deltaY * incrementForMode(e.deltaMode) * 0.2;
   document.getElementById("circle").style.transform = "rotate(" + rotation + "deg)";
   rotationAdjusted = true;
   e.preventDefault();
 });
 
 function* test(testDriver) {
   var content = document.getElementById("content");
-  for (i = 0; i < 300; i++) { // enough iterations that we would scroll to the bottom of 'content'
+  for (let i = 0; i < 300; i++) { // enough iterations that we would scroll to the bottom of 'content'
     yield synthesizeNativeWheelAndWaitForWheelEvent(content, 100, 150, 0, -5, testDriver);
   }
-  var scrollbox = document.getElementById("scrollbox");
   is(content.scrollTop > 0, true, "We should have scrolled down somewhat");
   is(content.scrollTop < content.scrollTopMax, true, "We should not have scrolled to the bottom of the scrollframe");
   is(rotationAdjusted, true, "The rotation should have been adjusted");
 }
 
 SimpleTest.waitForExplicitFinish();
 
 // If we allow smooth scrolling the "smooth" scrolling may cause the page to
--- a/gfx/layers/layerviewer/layerTreeView.js
+++ b/gfx/layers/layerviewer/layerTreeView.js
@@ -65,21 +65,19 @@ function parseDisplayList(lines) {
     if (matches[10]) { // WrapList don't provide a layer
       layerObject.layer = matches[10];
     }
     layerObject.rest = rest;
 
     // the content node name doesn't have a prefix, this makes the parsing easier
     rest = "content" + rest;
 
-    var fields = {};
     var nesting = 0;
     var startIndex;
     var lastSpace = -1;
-    var lastFieldStart = -1;
     for (var j = 0; j < rest.length; j++) {
       if (rest.charAt(j) == "(") {
         nesting++;
         if (nesting == 1) {
           startIndex = j;
         }
       } else if (rest.charAt(j) == ")") {
         nesting--;
@@ -136,17 +134,20 @@ function getDataURI(str) {
   var decoded = new Uint8Array(stride * h);
   for (var i = 0; i < len; i++) {
     var ascii = binary_string.charCodeAt(i);
     bytes[i] = ascii;
   }
 
   var ctxt = canvas.getContext("2d");
   var out = ctxt.createImageData(w, h);
-  buffer = LZ4_uncompressChunk(bytes, decoded);
+  // This is actually undefined throughout the tree and it isn't clear what it
+  // should be. Since this is only development code, leave it alone for now.
+  // eslint-disable-next-line no-undef
+  LZ4_uncompressChunk(bytes, decoded);
 
   for (var x = 0; x < w; x++) {
     for (var y = 0; y < h; y++) {
       out.data[4 * x + 4 * y * w + 0] = decoded[4 * x + y * stride + 2];
       out.data[4 * x + 4 * y * w + 1] = decoded[4 * x + y * stride + 1];
       out.data[4 * x + 4 * y * w + 2] = decoded[4 * x + y * stride + 0];
       out.data[4 * x + 4 * y * w + 3] = decoded[4 * x + y * stride + 3];
     }
@@ -247,45 +248,45 @@ function parseLayers(layersDumpLines) {
   var root;
   var objectAtIndentation = [];
   for (var i = 0; i < layersDumpLines.length; i++) {
     // Something like 'ThebesLayerComposite (0x12104cc00) [shadow-visible=< (x=0, y=0, w=1920, h=158); >] [visible=< (x=0, y=0, w=1920, h=158); >] [opaqueContent] [valid=< (x=0, y=0, w=1920, h=2218); >]'
     var line = layersDumpLines[i].name || layersDumpLines[i];
 
     var tileMatches = line.match("(\\s*)Tile \\(x=(.*), y=(.*)\\): (.*)");
     if (tileMatches) {
-      var indentation = Math.floor(matches[1].length / 2);
+      let indentation = Math.floor(matches[1].length / 2);
       var x = tileMatches[2];
       var y = tileMatches[3];
       var dataUri = tileMatches[4];
-      var parent = objectAtIndentation[indentation - 1];
+      let parent = objectAtIndentation[indentation - 1];
       var tiles = parent.tiles || {};
 
       tiles[x] = tiles[x] || {};
       tiles[x][y] = dataUri;
 
       parent.tiles = tiles;
 
       continue;
     }
 
     var surfaceMatches = line.match("(\\s*)Surface: (.*)");
     if (surfaceMatches) {
-      var indentation = Math.floor(matches[1].length / 2);
-      var parent = objectAtIndentation[indentation - 1] || objectAtIndentation[indentation - 2];
+      let indentation = Math.floor(matches[1].length / 2);
+      let parent = objectAtIndentation[indentation - 1] || objectAtIndentation[indentation - 2];
 
       var surfaceURI = surfaceMatches[2];
       if (parent.surfaceURI != null) {
         console.log("error: surfaceURI already set for this layer " + parent.line);
       }
       parent.surfaceURI = surfaceURI;
 
       // Look for the buffer-rect offset
       var contentHostLine = layersDumpLines[i - 2].name || layersDumpLines[i - 2];
-      var matches = contentHostLine.match(LAYERS_LINE_REGEX);
+      let matches = contentHostLine.match(LAYERS_LINE_REGEX);
       if (matches) {
         var contentHostRest = matches[4];
         parent.contentHostProp = {};
         parseProperties(contentHostRest, parent.contentHostProp);
       }
 
       continue;
     }
@@ -293,17 +294,17 @@ function parseLayers(layersDumpLines) {
     var layerObject = {
       line,
       children: [],
     };
     if (!root) {
       root = layerObject;
     }
 
-    var matches = line.match(LAYERS_LINE_REGEX);
+    let matches = line.match(LAYERS_LINE_REGEX);
     if (!matches) {
       continue; // Something like a texturehost dump. Safe to ignore
     }
 
     if (matches[2].includes("TiledContentHost") ||
         matches[2].includes("ContentHost") ||
         matches[2].includes("ContentClient") ||
         matches[2].includes("MemoryTextureHost") ||
@@ -330,37 +331,37 @@ function parseLayers(layersDumpLines) {
     layerObject.address = matches[3];
 
     var rest = matches[4];
 
     function parseProperties(rest, layerObject) {
       var fields = [];
       var nesting = 0;
       var startIndex;
-      for (var j = 0; j < rest.length; j++) {
+      for (let j = 0; j < rest.length; j++) {
         if (rest.charAt(j) == "[") {
           nesting++;
           if (nesting == 1) {
             startIndex = j;
           }
         } else if (rest.charAt(j) == "]") {
           nesting--;
           if (nesting == 0) {
             fields.push(rest.substring(startIndex + 1, j));
           }
         }
       }
 
-      for (var j = 0; j < fields.length; j++) {
+      for (let j = 0; j < fields.length; j++) {
         // Something like 'valid=< (x=0, y=0, w=1920, h=2218); >' or 'opaqueContent'
         var field = fields[j];
         // dump("FIELD: " + field + "\n");
         var parts = field.split("=", 2);
         var fieldName = parts[0];
-        var rest = field.substring(fieldName.length + 1);
+        rest = field.substring(fieldName.length + 1);
         if (parts.length == 1) {
           layerObject[fieldName] = "true";
           layerObject[fieldName].type = "bool";
           continue;
         }
         var float = parseFloat_cleo(rest);
         if (float) {
           layerObject[fieldName] = float;
@@ -441,17 +442,17 @@ function populateLayers(root, displayLis
     if (!displayList) {
       return items;
     }
     if (displayList.layer == root.address) {
       items.push(displayList);
     }
     for (var i = 0; i < displayList.children.length; i++) {
       var subDisplayItems = getDisplayItemForLayer(displayList.children[i]);
-      for (var j = 0; j < subDisplayItems.length; j++) {
+      for (let j = 0; j < subDisplayItems.length; j++) {
         items.push(subDisplayItems[j]);
       }
     }
     return items;
   }
   var elem = createElement("div", {
     className: "layerObjectDescription",
     textContent: root.line,
@@ -516,17 +517,17 @@ function populateLayers(root, displayLis
           height: clip[3] + "px",
           position: "absolute",
           overflow: "hidden",
           pointerEvents: "none",
         },
       });
       layerViewportMatrix[4] += -clip[0];
       layerViewportMatrix[5] += -clip[1];
-      layerViewport.style.transform = "translate(-" + clip[0] + "px, -" + clip[1] + "px" + ")";
+      layerViewport.style.transform = "translate(-" + clip[0] + "px, -" + clip[1] + "px)";
     }
     if (root["shadow-transform"] || root.transform) {
       var matrix = root["shadow-transform"] || root.transform;
       layerViewportMatrix[0] = matrix[0][0];
       layerViewportMatrix[1] = matrix[0][1];
       layerViewportMatrix[2] = matrix[1][0];
       layerViewportMatrix[3] = matrix[1][1];
       layerViewportMatrix[4] += matrix[2][0];
@@ -539,18 +540,18 @@ function populateLayers(root, displayLis
     }
     if (clipElem) {
       previewParent.appendChild(clipElem);
       clipElem.appendChild(layerViewport);
     } else {
       previewParent.appendChild(layerViewport);
     }
     previewParent = layerViewport;
-    for (var i = 0; i < visibleRegion.length; i++) {
-      var rect2d = visibleRegion[i];
+    for (let i = 0; i < visibleRegion.length; i++) {
+      let rect2d = visibleRegion[i];
       var layerPreview = createElement("div", {
         id: root.address + "_visible_part" + i + "-" + visibleRegion.length,
         className: "layerPreview",
         style: {
           position: "absolute",
           left: rect2d[0] + "px",
           top: rect2d[1] + "px",
           width: rect2d[2] + "px",
@@ -624,17 +625,17 @@ function populateLayers(root, displayLis
         };
         layerPreview.onmouseout = function() {
           this.mouseoverElem.onmouseout();
         };
       }
     }
 
     var layerDisplayItems = getDisplayItemForLayer(displayList);
-    for (var i = 0; i < layerDisplayItems.length; i++) {
+    for (let i = 0; i < layerDisplayItems.length; i++) {
       var displayItem = layerDisplayItems[i];
       var displayElem = createElement("div", {
         className: "layerObjectDescription",
         textContent: "            " + trim(displayItem.line),
         style: {
           whiteSpace: "pre",
         },
         displayItem,
@@ -661,17 +662,16 @@ function populateLayers(root, displayLis
               description += "<br>Z: " + this.displayItem.z;
             }
             // At the end
             if (this.displayItem.rest) {
               description += "<br>" + this.displayItem.rest;
             }
 
             var box = this.diPreview.getBoundingClientRect();
-            var pageBox = document.body.getBoundingClientRect();
             this.diPreview.tooltip = createElement("div", {
               className: "csstooltip",
               innerHTML: description,
               style: {
                 top: Math.min(box.bottom, document.documentElement.clientHeight - 150) + "px",
                 left: box.left + "px",
               },
             });
@@ -682,32 +682,32 @@ function populateLayers(root, displayLis
         onmouseout() {
           if (this.diPreview) {
             this.diPreview.classList.remove("displayHover");
             document.body.removeChild(this.diPreview.tooltip);
           }
         },
       });
 
-      var icon = createElement("img", {
+      icon = createElement("img", {
         style: {
           width: "12px",
           height: "12px",
           marginLeft: "4px",
           marginRight: "4px",
         },
       });
       displayElem.insertBefore(icon, displayElem.firstChild);
       pane.appendChild(displayElem);
       // bounds doesn't adjust for within the layer. It's not a bad fallback but
       // will have the wrong offset
-      var rect2d = displayItem.layerBounds || displayItem.bounds;
+      let rect2d = displayItem.layerBounds || displayItem.bounds;
       if (rect2d) { // This doesn't place them corectly
         var appUnitsToPixels = 60 / contentScale;
-        diPreview = createElement("div", {
+        let diPreview = createElement("div", {
           id: "displayitem_" + displayItem.content + "_" + displayItem.address,
           className: "layerPreview",
           style: {
             position: "absolute",
             left: rect2d[0] / appUnitsToPixels + "px",
             top: rect2d[1] / appUnitsToPixels + "px",
             width: rect2d[2] / appUnitsToPixels + "px",
             height: rect2d[3] / appUnitsToPixels + "px",
@@ -731,18 +731,16 @@ function populateLayers(root, displayLis
 
   for (var i = 0; i < root.children.length; i++) {
     populateLayers(root.children[i], displayList, pane, previewParent, hasSeenRoot, contentScale, rootPreviewParent);
   }
 }
 
 // This function takes a stdout snippet and finds the frames
 function parseMultiLineDump(log) {
-  var lines = log.split("\n");
-
   var container = createElement("div", {
     style: {
       height: "100%",
       position: "relative",
     },
   });
 
   var layerManagerFirstLine = "[a-zA-Z]*LayerManager \\(.*$\n";
@@ -869,16 +867,8 @@ function parseDump(log, displayList, com
     },
   });
   mainDiv.appendChild(previewDiv);
 
   var root = parseLayers(log);
   populateLayers(root, displayList, layerListPane, previewDiv);
   return container;
 }
-
-function tab_showLayersDump(layersDumpLines, compositeTitle, compositeTime) {
-  var container = parseDump(layersDumpLines, compositeTitle, compositeTime);
-
-  gTabWidget.addTab("LayerTree", container);
-  gTabWidget.selectTab("LayerTree");
-}
-
--- a/gfx/tests/chrome/test_device_reset.html
+++ b/gfx/tests/chrome/test_device_reset.html
@@ -9,21 +9,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
     <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
   </head>
   <body>
     <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1274663">Mozilla Bug 1274663</a>
     <script>
       var importObj = {};
 
-      var Cc = SpecialPowers.Cc;
-      var Ci = SpecialPowers.Ci;
-
       var sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
-      var xr = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
 
       var windows = SpecialPowers.Services.ww.getWindowEnumerator();
       var windowutils;
       while (windows.hasMoreElements()) {
         windowutils = windows.getNext().windowUtils;
       }
 
       const PAGE_WIDTH = 200;
--- a/gfx/tests/mochitest/test_acceleration.html
+++ b/gfx/tests/mochitest/test_acceleration.html
@@ -7,34 +7,34 @@ https://bugzilla.mozilla.org/show_bug.cg
   <title>Test hardware acceleration</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=627498">Mozilla Bug 627498</a>
 <p id="display"></p>
 <div id="content" style="display: none">
-  
+
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 // Make sure that acceleration is enabled/disabled the way we expect it to be
 // based on platform.
 
 SimpleTest.waitForExplicitFinish();
 
 addEventListener("pageshow", runTest, false);
 
 function runTest() {
   var Cc = SpecialPowers.Cc;
   var Ci = SpecialPowers.Ci;
 
   var sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
-  var xr = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
+  var xr = SpecialPowers.Services.appinfo;
 
   var windows = SpecialPowers.Services.ww.getWindowEnumerator();
   var windowutils;
   var acceleratedWindows = 0;
   var advancedLayersWindows = 0;
   var webrenderWindows = 0;
   var layerManagerLog = [];
   while (windows.hasMoreElements()) {
--- a/gfx/tests/mochitest/test_bug509244.html
+++ b/gfx/tests/mochitest/test_bug509244.html
@@ -7,17 +7,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <title>Test for Bug 509244</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=509244">Mozilla Bug 509244</a>
 <p id="display">A</p>
 <div id="content" style="display: none">
-  
+
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 509244 **/
 
 function flush() { document.documentElement.offsetHeight; }
 
@@ -26,19 +26,17 @@ var text = document.getElementById("disp
 // layout text, caching monospace font
 text.style.fontFamily = "monospace";
 flush();
 // relayout text so that monospace font is no longer used (but cached)
 text.style.fontFamily = "sans-serif";
 flush();
 
 // flush cache
-var os = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
-         .getService(SpecialPowers.Ci.nsIObserverService);
-os.notifyObservers(null, "memory-pressure", "heap-minimize");
+SpecialPowers.Services.obs.notifyObservers(null, "memory-pressure", "heap-minimize");
 
 // reuse font that was flushed from cache
 text.style.fontFamily = "monospace";
 flush();
 
 ok(true, "not crashed");
 
 </script>
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/simpletest.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/simpletest.js
@@ -20,16 +20,17 @@ var globals = require("../globals");
 // When updating this list, be sure to also update the 'support-files' config
 // in `tools/lint/eslint.yml`.
 const simpleTestFiles = [
   "ExtensionTestUtils.js",
   "EventUtils.js",
   "MockObjects.js",
   "SimpleTest.js",
   "WindowSnapshot.js",
+  "paint_listener.js",
 ];
 const simpleTestPath = "testing/mochitest/tests/SimpleTest";
 
 function getScriptGlobals() {
   let fileGlobals = [];
   let root = helpers.rootDir;
   for (let file of simpleTestFiles) {
     let fileName = path.join(root, simpleTestPath, file);