Merge inbound to mozilla-central. a=merge
authorNoemi Erli <nerli@mozilla.com>
Tue, 16 Jul 2019 00:42:51 +0300
changeset 482809 c0bcda96a954fe7a3700466bda256aea58189ac9
parent 482808 1af0dca460dd7362116f252a3be4b01c2a1d8b7d (current diff)
parent 482750 9eec8911e1825433064c122838401e473e298f52 (diff)
child 482810 4d719512b650570bcb67c44ee6cdbdd17d1ad12a
child 482850 a7027eecbcdd9aad592e4b06fe1fbb602a801ddf
child 482863 57e096cabc296b897baec44b65ece648b54463c0
push id113692
push usernerli@mozilla.com
push dateMon, 15 Jul 2019 21:50:20 +0000
treeherdermozilla-inbound@c0bcda96a954 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone70.0a1
first release with
nightly linux32
c0bcda96a954 / 70.0a1 / 20190715214335 / files
nightly linux64
c0bcda96a954 / 70.0a1 / 20190715214335 / files
nightly mac
c0bcda96a954 / 70.0a1 / 20190715214335 / files
nightly win32
c0bcda96a954 / 70.0a1 / 20190715214335 / files
nightly win64
c0bcda96a954 / 70.0a1 / 20190715214335 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
dom/base/nsContentUtils.cpp
testing/web-platform/meta/css/cssom-view/scroll-behavior-default-css.html.ini
testing/web-platform/meta/longtask-timing/__dir__.ini
testing/web-platform/meta/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html.ini
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -2447,18 +2447,17 @@ Accessible* Accessible::CurrentItem() co
   // with the aria-activedescendant attribute.
   nsAutoString id;
   if (HasOwnContent() && mContent->IsElement() &&
       mContent->AsElement()->GetAttr(kNameSpaceID_None,
                                      nsGkAtoms::aria_activedescendant, id)) {
     dom::Document* DOMDoc = mContent->OwnerDoc();
     dom::Element* activeDescendantElm = DOMDoc->GetElementById(id);
     if (activeDescendantElm) {
-      if (nsContentUtils::ContentIsDescendantOf(mContent,
-                                                activeDescendantElm)) {
+      if (mContent->IsInclusiveDescendantOf(activeDescendantElm)) {
         // Don't want a cyclical descendant relationship. That would be bad.
         return nullptr;
       }
 
       DocAccessible* document = Document();
       if (document) return document->GetAccessible(activeDescendantElm);
     }
   }
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -1933,17 +1933,17 @@ void DocAccessible::DoARIAOwnsRelocation
   uint32_t idx = 0;
   while (nsIContent* childEl = iter.NextElem()) {
     Accessible* child = GetAccessible(childEl);
     auto insertIdx = aOwner->ChildCount() - owned->Length() + idx;
 
     // Make an attempt to create an accessible if it wasn't created yet.
     if (!child) {
       // An owned child cannot be an ancestor of the owner.
-      if (nsContentUtils::ContentIsDescendantOf(aOwner->Elm(), childEl)) {
+      if (aOwner->Elm()->IsInclusiveDescendantOf(childEl)) {
         continue;
       }
 
       if (aOwner->IsAcceptableChild(childEl)) {
         child = GetAccService()->CreateAccessible(childEl, aOwner);
         if (child) {
           TreeMutation imut(aOwner);
           aOwner->InsertChildAt(insertIdx, child);
--- a/accessible/generic/HyperTextAccessible.cpp
+++ b/accessible/generic/HyperTextAccessible.cpp
@@ -1525,22 +1525,22 @@ bool HyperTextAccessible::SelectionBound
     nsINode* tempNode = startNode;
     startNode = endNode;
     endNode = tempNode;
     int32_t tempOffset = startOffset;
     startOffset = endOffset;
     endOffset = tempOffset;
   }
 
-  if (!nsContentUtils::ContentIsDescendantOf(startNode, mContent))
+  if (!startNode->IsInclusiveDescendantOf(mContent))
     *aStartOffset = 0;
   else
     *aStartOffset = DOMPointToOffset(startNode, startOffset);
 
-  if (!nsContentUtils::ContentIsDescendantOf(endNode, mContent))
+  if (!endNode->IsInclusiveDescendantOf(mContent))
     *aEndOffset = CharacterCount();
   else
     *aEndOffset = DOMPointToOffset(endNode, endOffset, true);
   return true;
 }
 
 bool HyperTextAccessible::SetSelectionBoundsAt(int32_t aSelectionNum,
                                                int32_t aStartOffset,
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,5 +1,5 @@
 This is the PDF.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 2.3.13
+Current extension version is: 2.3.27
 
-Taken from upstream commit: 28326165
+Taken from upstream commit: 13ebfec9
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -118,18 +118,18 @@ return /******/ (function(modules) { // 
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.3.13';
-var pdfjsBuild = '28326165';
+var pdfjsVersion = '2.3.27';
+var pdfjsBuild = '13ebfec9';
 
 var pdfjsSharedUtil = __w_pdfjs_require__(1);
 
 var pdfjsDisplayAPI = __w_pdfjs_require__(6);
 
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(18);
 
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(19);
@@ -1299,17 +1299,17 @@ function _fetchDocument(worker, source, 
   if (pdfDataRangeTransport) {
     source.length = pdfDataRangeTransport.length;
     source.initialData = pdfDataRangeTransport.initialData;
     source.progressiveDone = pdfDataRangeTransport.progressiveDone;
   }
 
   return worker.messageHandler.sendWithPromise('GetDocRequest', {
     docId,
-    apiVersion: '2.3.13',
+    apiVersion: '2.3.27',
     source: {
       data: source.data,
       url: source.url,
       password: source.password,
       disableAutoFetch: source.disableAutoFetch,
       rangeChunkSize: source.rangeChunkSize,
       length: source.length
     },
@@ -2615,16 +2615,18 @@ class WorkerTransport {
           intentState.renderTasks[i].operatorListChanged();
         }
 
         page._tryCleanup();
       }
 
       if (intentState.displayReadyCapability) {
         intentState.displayReadyCapability.reject(new Error(data.error));
+      } else if (intentState.opListReadCapability) {
+        intentState.opListReadCapability.reject(new Error(data.error));
       } else {
         throw new Error(data.error);
       }
     }, this);
     messageHandler.on('UnsupportedFeature', this._onUnsupportedFeature, this);
     messageHandler.on('JpegDecode', function (data) {
       if (this.destroyed) {
         return Promise.reject(new Error('Worker was destroyed'));
@@ -3093,19 +3095,19 @@ const InternalRenderTask = function Inte
       }
     }
 
   }
 
   return InternalRenderTask;
 }();
 
-const version = '2.3.13';
+const version = '2.3.27';
 exports.version = version;
-const build = '28326165';
+const build = '13ebfec9';
 exports.build = build;
 
 /***/ }),
 /* 7 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
@@ -4898,25 +4900,30 @@ var CanvasGraphics = function CanvasGrap
     },
     closePath: function CanvasGraphics_closePath() {
       this.ctx.closePath();
     },
     stroke: function CanvasGraphics_stroke(consumePath) {
       consumePath = typeof consumePath !== 'undefined' ? consumePath : true;
       var ctx = this.ctx;
       var strokeColor = this.current.strokeColor;
-      ctx.lineWidth = Math.max(this.getSinglePixelWidth() * MIN_WIDTH_FACTOR, this.current.lineWidth);
       ctx.globalAlpha = this.current.strokeAlpha;
 
       if (strokeColor && strokeColor.hasOwnProperty('type') && strokeColor.type === 'Pattern') {
         ctx.save();
+        let transform = ctx.mozCurrentTransform;
+
+        const scale = _util.Util.singularValueDecompose2dScale(transform)[0];
+
         ctx.strokeStyle = strokeColor.getPattern(ctx, this);
+        ctx.lineWidth = Math.max(this.getSinglePixelWidth() * MIN_WIDTH_FACTOR, this.current.lineWidth * scale);
         ctx.stroke();
         ctx.restore();
       } else {
+        ctx.lineWidth = Math.max(this.getSinglePixelWidth() * MIN_WIDTH_FACTOR, this.current.lineWidth);
         ctx.stroke();
       }
 
       if (consumePath) {
         this.consumePath();
       }
 
       ctx.globalAlpha = this.current.fillAlpha;
@@ -5903,27 +5910,42 @@ Object.defineProperty(exports, "__esModu
   value: true
 });
 exports.getShadingPatternFromIR = getShadingPatternFromIR;
 exports.TilingPattern = void 0;
 
 var _util = __w_pdfjs_require__(1);
 
 var ShadingIRs = {};
+
+function applyBoundingBox(ctx, bbox) {
+  if (!bbox || typeof Path2D === 'undefined') {
+    return;
+  }
+
+  const width = bbox[2] - bbox[0];
+  const height = bbox[3] - bbox[1];
+  const region = new Path2D();
+  region.rect(bbox[0], bbox[1], width, height);
+  ctx.clip(region);
+}
+
 ShadingIRs.RadialAxial = {
   fromIR: function RadialAxial_fromIR(raw) {
     var type = raw[1];
-    var colorStops = raw[2];
-    var p0 = raw[3];
-    var p1 = raw[4];
-    var r0 = raw[5];
-    var r1 = raw[6];
+    var bbox = raw[2];
+    var colorStops = raw[3];
+    var p0 = raw[4];
+    var p1 = raw[5];
+    var r0 = raw[6];
+    var r1 = raw[7];
     return {
       type: 'Pattern',
       getPattern: function RadialAxial_getPattern(ctx) {
+        applyBoundingBox(ctx, bbox);
         var grad;
 
         if (type === 'axial') {
           grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]);
         } else if (type === 'radial') {
           grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1);
         }
 
@@ -6141,20 +6163,22 @@ var createMeshCanvas = function createMe
 
 ShadingIRs.Mesh = {
   fromIR: function Mesh_fromIR(raw) {
     var coords = raw[2];
     var colors = raw[3];
     var figures = raw[4];
     var bounds = raw[5];
     var matrix = raw[6];
+    var bbox = raw[7];
     var background = raw[8];
     return {
       type: 'Pattern',
       getPattern: function Mesh_getPattern(ctx, owner, shadingFill) {
+        applyBoundingBox(ctx, bbox);
         var scale;
 
         if (shadingFill) {
           scale = _util.Util.singularValueDecompose2dScale(ctx.mozCurrentTransform);
         } else {
           scale = _util.Util.singularValueDecompose2dScale(owner.baseTransform);
 
           if (matrix) {
@@ -6385,26 +6409,22 @@ function wrapReason(reason) {
 function makeReasonSerializable(reason) {
   if (!(reason instanceof Error) || reason instanceof _util.AbortException || reason instanceof _util.MissingPDFException || reason instanceof _util.UnexpectedResponseException || reason instanceof _util.UnknownErrorException) {
     return reason;
   }
 
   return new _util.UnknownErrorException(reason.message, reason.toString());
 }
 
-function resolveOrReject(capability, success, reason) {
-  if (success) {
+function resolveOrReject(capability, data) {
+  if (data.success) {
     capability.resolve();
   } else {
-    capability.reject(reason);
-  }
-}
-
-function finalize(promise) {
-  return Promise.resolve(promise).catch(() => {});
+    capability.reject(wrapReason(data.reason));
+  }
 }
 
 function MessageHandler(sourceName, targetName, comObj) {
   this.sourceName = sourceName;
   this.targetName = targetName;
   this.comObj = comObj;
   this.callbackId = 1;
   this.streamId = 1;
@@ -6681,29 +6701,29 @@ MessageHandler.prototype = {
         success,
         streamId,
         reason
       });
     };
 
     let deleteStreamController = () => {
       Promise.all([this.streamControllers[data.streamId].startCall, this.streamControllers[data.streamId].pullCall, this.streamControllers[data.streamId].cancelCall].map(function (capability) {
-        return capability && finalize(capability.promise);
+        return capability && capability.promise.catch(function () {});
       })).then(() => {
         delete this.streamControllers[data.streamId];
       });
     };
 
     switch (data.stream) {
       case 'start_complete':
-        resolveOrReject(this.streamControllers[data.streamId].startCall, data.success, wrapReason(data.reason));
+        resolveOrReject(this.streamControllers[data.streamId].startCall, data);
         break;
 
       case 'pull_complete':
-        resolveOrReject(this.streamControllers[data.streamId].pullCall, data.success, wrapReason(data.reason));
+        resolveOrReject(this.streamControllers[data.streamId].pullCall, data);
         break;
 
       case 'pull':
         if (!this.streamSinks[data.streamId]) {
           sendStreamResponse({
             stream: 'pull_complete',
             success: true
           });
@@ -6752,17 +6772,17 @@ MessageHandler.prototype = {
 
       case 'error':
         (0, _util.assert)(this.streamControllers[data.streamId], 'error should have stream controller');
         this.streamControllers[data.streamId].controller.error(wrapReason(data.reason));
         deleteStreamController();
         break;
 
       case 'cancel_complete':
-        resolveOrReject(this.streamControllers[data.streamId].cancelCall, data.success, wrapReason(data.reason));
+        resolveOrReject(this.streamControllers[data.streamId].cancelCall, data);
         deleteStreamController();
         break;
 
       case 'cancel':
         if (!this.streamSinks[data.streamId]) {
           break;
         }
 
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -118,18 +118,18 @@ return /******/ (function(modules) { // 
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-const pdfjsVersion = '2.3.13';
-const pdfjsBuild = '28326165';
+const pdfjsVersion = '2.3.27';
+const pdfjsBuild = '13ebfec9';
 
 const pdfjsCoreWorker = __w_pdfjs_require__(1);
 
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 1 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
@@ -235,17 +235,17 @@ var WorkerMessageHandler = {
 
   createDocumentHandler(docParams, port) {
     var pdfManager;
     var terminated = false;
     var cancelXHRs = null;
     var WorkerTasks = [];
     const verbosity = (0, _util.getVerbosityLevel)();
     let apiVersion = docParams.apiVersion;
-    let workerVersion = '2.3.13';
+    let workerVersion = '2.3.27';
 
     if (apiVersion !== workerVersion) {
       throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
     }
 
     var docId = docParams.docId;
     var docBaseUrl = docParams.docBaseUrl;
     var workerHandlerName = docParams.docId + '_worker';
@@ -37938,16 +37938,24 @@ Shadings.RadialAxial = function RadialAx
   function RadialAxial(dict, matrix, xref, res, pdfFunctionFactory) {
     this.matrix = matrix;
     this.coordsArr = dict.getArray('Coords');
     this.shadingType = dict.get('ShadingType');
     this.type = 'Pattern';
     var cs = dict.get('ColorSpace', 'CS');
     cs = _colorspace.ColorSpace.parse(cs, xref, res, pdfFunctionFactory);
     this.cs = cs;
+    const bbox = dict.getArray('BBox');
+
+    if (Array.isArray(bbox) && bbox.length === 4) {
+      this.bbox = _util.Util.normalizeRect(bbox);
+    } else {
+      this.bbox = null;
+    }
+
     var t0 = 0.0,
         t1 = 1.0;
 
     if (dict.has('Domain')) {
       var domainArr = dict.getArray('Domain');
       t0 = domainArr[0];
       t1 = domainArr[1];
     }
@@ -38053,17 +38061,17 @@ Shadings.RadialAxial = function RadialAx
         if (shadingType === ShadingType.RADIAL) {
           var scale = _util.Util.singularValueDecompose2dScale(matrix);
 
           r0 *= scale[0];
           r1 *= scale[1];
         }
       }
 
-      return ['RadialAxial', type, this.colorStops, p0, p1, r0, r1];
+      return ['RadialAxial', type, this.bbox, this.colorStops, p0, p1, r0, r1];
     }
   };
   return RadialAxial;
 }();
 
 Shadings.Mesh = function MeshClosure() {
   function MeshStreamReader(stream, context) {
     this.stream = stream;
@@ -38670,17 +38678,24 @@ Shadings.Mesh = function MeshClosure() {
     if (!(0, _primitives.isStream)(stream)) {
       throw new _util.FormatError('Mesh data is not a stream');
     }
 
     var dict = stream.dict;
     this.matrix = matrix;
     this.shadingType = dict.get('ShadingType');
     this.type = 'Pattern';
-    this.bbox = dict.getArray('BBox');
+    const bbox = dict.getArray('BBox');
+
+    if (Array.isArray(bbox) && bbox.length === 4) {
+      this.bbox = _util.Util.normalizeRect(bbox);
+    } else {
+      this.bbox = null;
+    }
+
     var cs = dict.get('ColorSpace', 'CS');
     cs = _colorspace.ColorSpace.parse(cs, xref, res, pdfFunctionFactory);
     this.cs = cs;
     this.background = dict.has('Background') ? cs.getRgb(dict.get('Background'), 0) : null;
     var fnObj = dict.get('Function');
     var fn = fnObj ? pdfFunctionFactory.createFromArray(fnObj) : null;
     this.coords = [];
     this.colors = [];
@@ -44566,26 +44581,22 @@ function wrapReason(reason) {
 function makeReasonSerializable(reason) {
   if (!(reason instanceof Error) || reason instanceof _util.AbortException || reason instanceof _util.MissingPDFException || reason instanceof _util.UnexpectedResponseException || reason instanceof _util.UnknownErrorException) {
     return reason;
   }
 
   return new _util.UnknownErrorException(reason.message, reason.toString());
 }
 
-function resolveOrReject(capability, success, reason) {
-  if (success) {
+function resolveOrReject(capability, data) {
+  if (data.success) {
     capability.resolve();
   } else {
-    capability.reject(reason);
-  }
-}
-
-function finalize(promise) {
-  return Promise.resolve(promise).catch(() => {});
+    capability.reject(wrapReason(data.reason));
+  }
 }
 
 function MessageHandler(sourceName, targetName, comObj) {
   this.sourceName = sourceName;
   this.targetName = targetName;
   this.comObj = comObj;
   this.callbackId = 1;
   this.streamId = 1;
@@ -44862,29 +44873,29 @@ MessageHandler.prototype = {
         success,
         streamId,
         reason
       });
     };
 
     let deleteStreamController = () => {
       Promise.all([this.streamControllers[data.streamId].startCall, this.streamControllers[data.streamId].pullCall, this.streamControllers[data.streamId].cancelCall].map(function (capability) {
-        return capability && finalize(capability.promise);
+        return capability && capability.promise.catch(function () {});
       })).then(() => {
         delete this.streamControllers[data.streamId];
       });
     };
 
     switch (data.stream) {
       case 'start_complete':
-        resolveOrReject(this.streamControllers[data.streamId].startCall, data.success, wrapReason(data.reason));
+        resolveOrReject(this.streamControllers[data.streamId].startCall, data);
         break;
 
       case 'pull_complete':
-        resolveOrReject(this.streamControllers[data.streamId].pullCall, data.success, wrapReason(data.reason));
+        resolveOrReject(this.streamControllers[data.streamId].pullCall, data);
         break;
 
       case 'pull':
         if (!this.streamSinks[data.streamId]) {
           sendStreamResponse({
             stream: 'pull_complete',
             success: true
           });
@@ -44933,17 +44944,17 @@ MessageHandler.prototype = {
 
       case 'error':
         (0, _util.assert)(this.streamControllers[data.streamId], 'error should have stream controller');
         this.streamControllers[data.streamId].controller.error(wrapReason(data.reason));
         deleteStreamController();
         break;
 
       case 'cancel_complete':
-        resolveOrReject(this.streamControllers[data.streamId].cancelCall, data.success, wrapReason(data.reason));
+        resolveOrReject(this.streamControllers[data.streamId].cancelCall, data);
         deleteStreamController();
         break;
 
       case 'cancel':
         if (!this.streamSinks[data.streamId]) {
           break;
         }
 
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -9629,17 +9629,18 @@ class PDFPageView {
       rotation: totalRotation
     });
 
     if (this.svg) {
       this.cssTransform(this.svg, true);
       this.eventBus.dispatch('pagerendered', {
         source: this,
         pageNumber: this.id,
-        cssTransform: true
+        cssTransform: true,
+        timestamp: performance.now()
       });
       return;
     }
 
     let isScalingRestricted = false;
 
     if (this.canvas && this.maxCanvasPixels > 0) {
       let outputScale = this.outputScale;
@@ -9650,17 +9651,18 @@ class PDFPageView {
     }
 
     if (this.canvas) {
       if (this.useOnlyCssZoom || this.hasRestrictedScaling && isScalingRestricted) {
         this.cssTransform(this.canvas, true);
         this.eventBus.dispatch('pagerendered', {
           source: this,
           pageNumber: this.id,
-          cssTransform: true
+          cssTransform: true,
+          timestamp: performance.now()
         });
         return;
       }
 
       if (!this.zoomLayer && !this.canvas.hasAttribute('hidden')) {
         this.zoomLayer = this.canvas.parentNode;
         this.zoomLayer.style.position = 'absolute';
       }
@@ -9856,17 +9858,18 @@ class PDFPageView {
 
       if (this.onAfterDraw) {
         this.onAfterDraw();
       }
 
       this.eventBus.dispatch('pagerendered', {
         source: this,
         pageNumber: this.id,
-        cssTransform: false
+        cssTransform: false,
+        timestamp: performance.now()
       });
 
       if (error) {
         throw error;
       }
     };
 
     let paintTask = this.renderer === _ui_utils.RendererType.SVG ? this.paintOnSvg(canvasWrapper) : this.paintOnCanvas(canvasWrapper);
--- a/browser/extensions/pdfjs/moz.yaml
+++ b/browser/extensions/pdfjs/moz.yaml
@@ -15,15 +15,15 @@ origin:
   description: Portable Document Format (PDF) viewer that is built with HTML5
 
   # Full URL for the package's homepage/etc
   # Usually different from repository url
   url: https://github.com/mozilla/pdf.js
 
   # Human-readable identifier for this version/release
   # Generally "version NNN", "tag SSS", "bookmark SSS"
-  release: version 2.3.13
+  release: version 2.3.27
 
   # The package's license, where possible using the mnemonic from
   # https://spdx.org/licenses/
   # Multiple licenses can be specified (as a YAML list)
   # A "LICENSE" file must exist containing the full license text
   license: Apache-2.0
--- a/devtools/shared/defer.js
+++ b/devtools/shared/defer.js
@@ -1,19 +1,14 @@
 /* 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/. */
 
 "use strict";
 
-// We have to keep using Promise.jsm here, because DOM Promises
-// start freezing during panel iframes destruction.
-// More info in bug 1454373 comment 15.
-const Promise = require("promise");
-
 /**
  * Returns a deferred object, with a resolve and reject property.
  * https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred
  */
 module.exports = function defer() {
   let resolve, reject;
   const promise = new Promise(function() {
     resolve = arguments[0];
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -9323,18 +9323,17 @@ nsINode* Document::AdoptNode(nsINode& aA
       // We don't want to adopt an element into its own contentDocument or into
       // a descendant contentDocument, so we check if the frameElement of this
       // document or any of its parents is the adopted node or one of its
       // descendants.
       Document* doc = this;
       do {
         if (nsPIDOMWindowOuter* win = doc->GetWindow()) {
           nsCOMPtr<nsINode> node = win->GetFrameElementInternal();
-          if (node &&
-              nsContentUtils::ContentIsDescendantOf(node, adoptedNode)) {
+          if (node && node->IsInclusiveDescendantOf(adoptedNode)) {
             rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
             return nullptr;
           }
         }
       } while ((doc = doc->GetParentDocument()));
 
       // Remove from parent.
       nsCOMPtr<nsINode> parent = adoptedNode->GetParentNode();
--- a/dom/base/NodeIterator.cpp
+++ b/dom/base/NodeIterator.cpp
@@ -62,17 +62,17 @@ bool NodeIterator::NodePointer::MoveToPr
 
 void NodeIterator::NodePointer::AdjustAfterRemoval(
     nsINode* aRoot, nsINode* aContainer, nsIContent* aChild,
     nsIContent* aPreviousSibling) {
   // If mNode is null or the root there is nothing to do.
   if (!mNode || mNode == aRoot) return;
 
   // check if ancestor was removed
-  if (!nsContentUtils::ContentIsDescendantOf(mNode, aChild)) return;
+  if (!mNode->IsInclusiveDescendantOf(aChild)) return;
 
   if (mBeforeNode) {
     // Try the next sibling
     nsINode* nextSibling = aPreviousSibling ? aPreviousSibling->GetNextSibling()
                                             : aContainer->GetFirstChild();
 
     if (nextSibling) {
       mNode = nextSibling;
--- a/dom/base/Selection.cpp
+++ b/dom/base/Selection.cpp
@@ -268,17 +268,17 @@ bool IsValidSelectionPoint(nsFrameSelect
   nsIContent* limiter = aFrameSel->GetLimiter();
   if (limiter && limiter != aNode && limiter != aNode->GetParent()) {
     // if newfocus == the limiter. that's ok. but if not there and not parent
     // bad
     return false;  // not in the right content. tLimiter said so
   }
 
   limiter = aFrameSel->GetAncestorLimiter();
-  return !limiter || nsContentUtils::ContentIsDescendantOf(aNode, limiter);
+  return !limiter || aNode->IsInclusiveDescendantOf(limiter);
 }
 
 namespace mozilla {
 struct MOZ_RAII AutoPrepareFocusRange {
   AutoPrepareFocusRange(Selection* aSelection, bool aContinueSelection,
                         bool aMultipleSelection
                             MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
@@ -3129,20 +3129,20 @@ Element* Selection::GetCommonEditingHost
     }
     if (!editingHost) {
       editingHost = foundEditingHost;
       continue;
     }
     if (editingHost == foundEditingHost) {
       continue;
     }
-    if (nsContentUtils::ContentIsDescendantOf(foundEditingHost, editingHost)) {
+    if (foundEditingHost->IsInclusiveDescendantOf(editingHost)) {
       continue;
     }
-    if (nsContentUtils::ContentIsDescendantOf(editingHost, foundEditingHost)) {
+    if (editingHost->IsInclusiveDescendantOf(foundEditingHost)) {
       editingHost = foundEditingHost;
       continue;
     }
     // editingHost and foundEditingHost are not a descendant of the other.
     // So, there is no common editing host.
     return nullptr;
   }
   return editingHost;
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -2177,30 +2177,16 @@ nsINode* nsContentUtils::GetCrossDocPare
     return parent;
   }
 
   Document* doc = aChild->AsDocument();
   Document* parentDoc = doc->GetParentDocument();
   return parentDoc ? parentDoc->FindContentForSubDocument(doc) : nullptr;
 }
 
-// static
-bool nsContentUtils::ContentIsDescendantOf(const nsINode* aPossibleDescendant,
-                                           const nsINode* aPossibleAncestor) {
-  MOZ_ASSERT(aPossibleDescendant, "The possible descendant is null!");
-  MOZ_ASSERT(aPossibleAncestor, "The possible ancestor is null!");
-
-  do {
-    if (aPossibleDescendant == aPossibleAncestor) return true;
-    aPossibleDescendant = aPossibleDescendant->GetParentNode();
-  } while (aPossibleDescendant);
-
-  return false;
-}
-
 bool nsContentUtils::ContentIsHostIncludingDescendantOf(
     const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor) {
   MOZ_ASSERT(aPossibleDescendant, "The possible descendant is null!");
   MOZ_ASSERT(aPossibleAncestor, "The possible ancestor is null!");
 
   do {
     if (aPossibleDescendant == aPossibleAncestor) return true;
     if (aPossibleDescendant->IsDocumentFragment()) {
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -331,51 +331,35 @@ class nsContentUtils {
 
   /**
    * Returns the parent node of aChild crossing document boundaries.
    * Uses the parent node in the composed document.
    */
   static nsINode* GetCrossDocParentNode(nsINode* aChild);
 
   /**
-   * Do not ever pass null pointers to this method.  If one of your
-   * nsIContents is null, you have to decide for yourself what
-   * "IsDescendantOf" really means.
-   *
-   * @param  aPossibleDescendant node to test for being a descendant of
-   *         aPossibleAncestor
-   * @param  aPossibleAncestor node to test for being an ancestor of
-   *         aPossibleDescendant
-   * @return true if aPossibleDescendant is a descendant of
-   *         aPossibleAncestor (or is aPossibleAncestor).  false
-   *         otherwise.
-   */
-  static bool ContentIsDescendantOf(const nsINode* aPossibleDescendant,
-                                    const nsINode* aPossibleAncestor);
-
-  /**
-   * Similar to ContentIsDescendantOf, except will treat an HTMLTemplateElement
-   * or ShadowRoot as an ancestor of things in the corresponding
-   * DocumentFragment. See the concept of "host-including inclusive ancestor" in
-   * the DOM specification.
+   * Similar to nsINode::IsInclusiveDescendantOf, except will treat an
+   * HTMLTemplateElement or ShadowRoot as an ancestor of things in the
+   * corresponding DocumentFragment. See the concept of "host-including
+   * inclusive ancestor" in the DOM specification.
    */
   static bool ContentIsHostIncludingDescendantOf(
       const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor);
 
   /**
    * Similar to above, but does special case only ShadowRoot,
    * not HTMLTemplateElement.
    */
   static bool ContentIsShadowIncludingDescendantOf(
       const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor);
 
   /**
-   * Similar to ContentIsDescendantOf except it crosses document boundaries,
-   * this function uses ancestor/descendant relations in the composed document
-   * (see shadow DOM spec).
+   * Similar to nsINode::IsInclusiveDescendantOf except it crosses document
+   * boundaries, this function uses ancestor/descendant relations in the
+   * composed document (see shadow DOM spec).
    */
   static bool ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant,
                                             nsINode* aPossibleAncestor);
 
   /**
    * As with ContentIsCrossDocDescendantOf but crosses shadow boundaries but not
    * cross document boundaries.
    *
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -2708,21 +2708,21 @@ nsresult nsFocusManager::DetermineElemen
     nsAutoString retarget;
 
     if (rootContent->GetAttr(kNameSpaceID_None,
                              nsGkAtoms::retargetdocumentfocus, retarget)) {
       nsIContent* retargetElement = doc->GetElementById(retarget);
       // The common case here is the urlbar where focus is on the anonymous
       // input inside the textbox, but the retargetdocumentfocus attribute
       // refers to the textbox. The Contains check will return false and the
-      // ContentIsDescendantOf check will return true in this case.
-      if (retargetElement && (retargetElement == startContent ||
-                              (!retargetElement->Contains(startContent) &&
-                               nsContentUtils::ContentIsDescendantOf(
-                                   startContent, retargetElement)))) {
+      // IsInclusiveDescendantOf check will return true in this case.
+      if (retargetElement &&
+          (retargetElement == startContent ||
+           (!retargetElement->Contains(startContent) &&
+            startContent->IsInclusiveDescendantOf(retargetElement)))) {
         startContent = rootContent;
       }
     }
   }
 
   NS_ASSERTION(startContent, "starting content not set");
 
   // keep a reference to the starting content. If we find that again, it means
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -112,16 +112,30 @@
 
 #ifdef ACCESSIBILITY
 #  include "mozilla/dom/AccessibleNode.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
+bool nsINode::IsInclusiveDescendantOf(const nsINode* aNode) const {
+  MOZ_ASSERT(aNode, "The node is nullptr.");
+
+  const nsINode* node = this;
+  do {
+    if (node == aNode) {
+      return true;
+    }
+    node = node->GetParentNode();
+  } while (node);
+
+  return false;
+}
+
 nsINode::nsSlots::nsSlots() : mWeakReference(nullptr) {}
 
 nsINode::nsSlots::~nsSlots() {
   if (mChildNodes) {
     mChildNodes->InvalidateCacheIfAvailable();
   }
 
   if (mWeakReference) {
@@ -2457,17 +2471,17 @@ bool nsINode::Contains(const nsINode* aO
   if (!IsElement() && !IsDocumentFragment()) {
     return false;
   }
 
   if (AsContent()->GetBindingParent() != other->GetBindingParent()) {
     return false;
   }
 
-  return nsContentUtils::ContentIsDescendantOf(other, this);
+  return other->IsInclusiveDescendantOf(this);
 }
 
 uint32_t nsINode::Length() const {
   switch (NodeType()) {
     case DOCUMENT_TYPE_NODE:
       return 0;
 
     case TEXT_NODE:
@@ -2535,17 +2549,17 @@ inline static Element* FindMatchingEleme
 
   // XXXbz: Should we fall back to the tree walk if |elements| is long,
   // for some value of "long"?
   for (Element* element : *elements) {
     if (MOZ_UNLIKELY(element == &aRoot)) {
       continue;
     }
 
-    if (!nsContentUtils::ContentIsDescendantOf(element, &aRoot)) {
+    if (!element->IsInclusiveDescendantOf(&aRoot)) {
       continue;
     }
 
     // We have an element with the right id and it's a strict descendant
     // of aRoot.
     return element;
   }
 
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -413,16 +413,23 @@ class nsINode : public mozilla::dom::Eve
   /**
    * Returns true if this is a document fragment node.
    */
   bool IsDocumentFragment() const {
     return NodeType() == DOCUMENT_FRAGMENT_NODE;
   }
 
   /**
+   * https://dom.spec.whatwg.org/#concept-tree-inclusive-descendant
+   *
+   * @param aNode must not be nullptr.
+   */
+  bool IsInclusiveDescendantOf(const nsINode* aNode) const;
+
+  /**
    * Return this node as a document fragment. Asserts IsDocumentFragment().
    *
    * This is defined inline in DocumentFragment.h.
    */
   inline mozilla::dom::DocumentFragment* AsDocumentFragment();
   inline const mozilla::dom::DocumentFragment* AsDocumentFragment() const;
 
   virtual JSObject* WrapObject(JSContext* aCx,
@@ -1313,20 +1320,19 @@ class nsINode : public mozilla::dom::Eve
 
   bool UnoptimizableCCNode() const;
 
  private:
   mozilla::dom::SVGUseElement* DoGetContainingSVGUseShadowHost() const;
 
   nsIContent* GetNextNodeImpl(const nsINode* aRoot,
                               const bool aSkipChildren) const {
-    // Can't use nsContentUtils::ContentIsDescendantOf here, since we
-    // can't include it here.
 #ifdef DEBUG
     if (aRoot) {
+      // TODO: perhaps nsINode::IsInclusiveDescendantOf could be used instead.
       const nsINode* cur = this;
       for (; cur; cur = cur->GetParentNode())
         if (cur == aRoot) break;
       NS_ASSERTION(cur, "aRoot not an ancestor of |this|?");
     }
 #endif
     if (!aSkipChildren) {
       nsIContent* kid = GetFirstChild();
@@ -1356,20 +1362,19 @@ class nsINode : public mozilla::dom::Eve
   /**
    * Get the previous nsIContent in the pre-order tree traversal of the DOM.  If
    * aRoot is non-null, then it must be an ancestor of |this|
    * (possibly equal to |this|) and only nsIContents that are descendants of
    * aRoot, including aRoot itself, will be returned.  Returns
    * null if there are no more nsIContents to traverse.
    */
   nsIContent* GetPreviousContent(const nsINode* aRoot = nullptr) const {
-    // Can't use nsContentUtils::ContentIsDescendantOf here, since we
-    // can't include it here.
 #ifdef DEBUG
     if (aRoot) {
+      // TODO: perhaps nsINode::IsInclusiveDescendantOf could be used instead.
       const nsINode* cur = this;
       for (; cur; cur = cur->GetParentNode())
         if (cur == aRoot) break;
       NS_ASSERTION(cur, "aRoot not an ancestor of |this|?");
     }
 #endif
 
     if (this == aRoot) {
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -682,18 +682,17 @@ void nsRange::ContentRemoved(nsIContent*
     // we can just invalidate the offset.
     if (aChild == mStart.Ref()) {
       newStart.SetAfterRef(container, aPreviousSibling);
     } else {
       newStart = mStart;
       newStart.InvalidateOffset();
     }
   } else {
-    gravitateStart =
-        Some(nsContentUtils::ContentIsDescendantOf(mStart.Container(), aChild));
+    gravitateStart = Some(mStart.Container()->IsInclusiveDescendantOf(aChild));
     if (gravitateStart.value()) {
       newStart.SetAfterRef(container, aPreviousSibling);
     }
   }
 
   // Do same thing for end boundry.
   if (container == mEnd.Container()) {
     if (aChild == mEnd.Ref()) {
@@ -701,18 +700,17 @@ void nsRange::ContentRemoved(nsIContent*
     } else {
       newEnd = mEnd;
       newEnd.InvalidateOffset();
     }
   } else {
     if (mStart.Container() == mEnd.Container() && gravitateStart.isSome()) {
       gravitateEnd = gravitateStart.value();
     } else {
-      gravitateEnd =
-          nsContentUtils::ContentIsDescendantOf(mEnd.Container(), aChild);
+      gravitateEnd = mEnd.Container()->IsInclusiveDescendantOf(aChild);
     }
     if (gravitateEnd) {
       newEnd.SetAfterRef(container, aPreviousSibling);
     }
   }
 
   if (newStart.IsSet() || newEnd.IsSet()) {
     DoSetRange(newStart.IsSet() ? newStart : mStart.AsRaw(),
@@ -772,17 +770,17 @@ int16_t nsRange::ComparePoint(const RawR
   }
 
   // our range is in a good state?
   if (!mIsPositioned) {
     aRv.Throw(NS_ERROR_NOT_INITIALIZED);
     return 0;
   }
 
-  if (!nsContentUtils::ContentIsDescendantOf(aPoint.Container(), mRoot)) {
+  if (!aPoint.Container()->IsInclusiveDescendantOf(mRoot)) {
     aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
     return 0;
   }
 
   if (aPoint.Container()->NodeType() == nsINode::DOCUMENT_TYPE_NODE) {
     aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
     return 0;
   }
@@ -867,20 +865,18 @@ void nsRange::DoSetRange(const RangeBoun
                          bool aNotInsertedYet /* = false */) {
   MOZ_ASSERT((aStartBoundary.IsSet() && aEndBoundary.IsSet() && aRootNode) ||
                  (!aStartBoundary.IsSet() && !aEndBoundary.IsSet()),
              "Set all or none");
 
   MOZ_ASSERT(
       !aRootNode || (!aStartBoundary.IsSet() && !aEndBoundary.IsSet()) ||
           aNotInsertedYet ||
-          (nsContentUtils::ContentIsDescendantOf(aStartBoundary.Container(),
-                                                 aRootNode) &&
-           nsContentUtils::ContentIsDescendantOf(aEndBoundary.Container(),
-                                                 aRootNode) &&
+          (aStartBoundary.Container()->IsInclusiveDescendantOf(aRootNode) &&
+           aEndBoundary.Container()->IsInclusiveDescendantOf(aRootNode) &&
            aRootNode ==
                RangeUtils::ComputeRootNode(aStartBoundary.Container()) &&
            aRootNode == RangeUtils::ComputeRootNode(aEndBoundary.Container())),
       "Wrong root");
 
   MOZ_ASSERT(
       !aRootNode || (!aStartBoundary.IsSet() && !aEndBoundary.IsSet()) ||
           (aStartBoundary.Container()->IsContent() &&
@@ -1658,17 +1654,17 @@ nsresult nsRange::CutContents(DocumentFr
 
     // Before we delete anything, advance the iterator to the next node that's
     // not a descendant of this one.  XXX It's a bit silly to iterate through
     // the descendants only to throw them out, we should use an iterator that
     // skips the descendants to begin with.
 
     iter.Next();
     nsCOMPtr<nsINode> nextNode = iter.GetCurrentNode();
-    while (nextNode && nsContentUtils::ContentIsDescendantOf(nextNode, node)) {
+    while (nextNode && nextNode->IsInclusiveDescendantOf(node)) {
       iter.Next();
       nextNode = iter.GetCurrentNode();
     }
 
     handled = false;
 
     // If it's CharacterData, make sure we might need to delete
     // part of the data, instead of removing the whole node.
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -2869,17 +2869,17 @@ void CanvasRenderingContext2D::DrawFocus
 }
 
 bool CanvasRenderingContext2D::DrawCustomFocusRing(
     mozilla::dom::Element& aElement) {
   EnsureUserSpacePath();
 
   HTMLCanvasElement* canvas = GetCanvas();
 
-  if (!canvas || !nsContentUtils::ContentIsDescendantOf(&aElement, canvas)) {
+  if (!canvas || !aElement.IsInclusiveDescendantOf(canvas)) {
     return false;
   }
 
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm) {
     // check that the element is focused
     if (&aElement == fm->GetFocusedElement()) {
       if (nsPIDOMWindowOuter* window = aElement.OwnerDoc()->GetWindow()) {
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -1303,18 +1303,18 @@ nsresult ContentEventHandler::OnQuerySel
     aEvent->mSucceeded = true;
     return NS_OK;
   }
 
   nsINode* const startNode = mFirstSelectedRawRange.GetStartContainer();
   nsINode* const endNode = mFirstSelectedRawRange.GetEndContainer();
 
   // Make sure the selection is within the root content range.
-  if (!nsContentUtils::ContentIsDescendantOf(startNode, mRootContent) ||
-      !nsContentUtils::ContentIsDescendantOf(endNode, mRootContent)) {
+  if (!startNode->IsInclusiveDescendantOf(mRootContent) ||
+      !endNode->IsInclusiveDescendantOf(mRootContent)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   NS_ASSERTION(aEvent->mReply.mString.IsEmpty(),
                "The reply string must be empty");
 
   LineBreakType lineBreakType = GetLineBreakType(aEvent);
   rv = GetStartOffset(mFirstSelectedRawRange, &aEvent->mReply.mOffset,
@@ -2517,32 +2517,30 @@ nsresult ContentEventHandler::OnQueryCha
     eventOnRoot.mRefPoint += aEvent->mWidget->WidgetToScreenOffset() -
                              rootWidget->WidgetToScreenOffset();
   }
   nsPoint ptInRoot =
       nsLayoutUtils::GetEventCoordinatesRelativeTo(&eventOnRoot, rootFrame);
 
   nsIFrame* targetFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot);
   if (!targetFrame || !targetFrame->GetContent() ||
-      !nsContentUtils::ContentIsDescendantOf(targetFrame->GetContent(),
-                                             mRootContent)) {
+      !targetFrame->GetContent()->IsInclusiveDescendantOf(mRootContent)) {
     // There is no character at the point.
     aEvent->mSucceeded = true;
     return NS_OK;
   }
   nsPoint ptInTarget = ptInRoot + rootFrame->GetOffsetToCrossDoc(targetFrame);
   int32_t rootAPD = rootFrame->PresContext()->AppUnitsPerDevPixel();
   int32_t targetAPD = targetFrame->PresContext()->AppUnitsPerDevPixel();
   ptInTarget = ptInTarget.ScaleToOtherAppUnits(rootAPD, targetAPD);
 
   nsIFrame::ContentOffsets tentativeCaretOffsets =
       targetFrame->GetContentOffsetsFromPoint(ptInTarget);
   if (!tentativeCaretOffsets.content ||
-      !nsContentUtils::ContentIsDescendantOf(tentativeCaretOffsets.content,
-                                             mRootContent)) {
+      !tentativeCaretOffsets.content->IsInclusiveDescendantOf(mRootContent)) {
     // There is no character nor tentative caret point at the point.
     aEvent->mSucceeded = true;
     return NS_OK;
   }
 
   rv = GetFlatTextLengthInRange(
       NodePosition(mRootContent, 0), NodePosition(tentativeCaretOffsets),
       mRootContent, &aEvent->mReply.mTentativeCaretOffset,
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -385,17 +385,17 @@ nsresult IMEStateManager::OnRemoveConten
           compositionInContent->NotifyIME(REQUEST_TO_CANCEL_COMPOSITION);
       if (NS_FAILED(rv)) {
         compositionInContent->NotifyIME(REQUEST_TO_COMMIT_COMPOSITION);
       }
     }
   }
 
   if (!sPresContext || !sContent ||
-      !nsContentUtils::ContentIsDescendantOf(sContent, aContent)) {
+      !sContent->IsInclusiveDescendantOf(aContent)) {
     return NS_OK;
   }
 
   MOZ_LOG(sISMLog, LogLevel::Info,
           ("OnRemoveContent(aPresContext=0x%p, aContent=0x%p), "
            "sPresContext=0x%p, sContent=0x%p, sTextCompositions=0x%p",
            aPresContext, aContent, sPresContext.get(), sContent.get(),
            sTextCompositions));
--- a/dom/events/PointerEventHandler.cpp
+++ b/dom/events/PointerEventHandler.cpp
@@ -367,18 +367,17 @@ nsIContent* PointerEventHandler::GetPoin
 
 /* static */
 void PointerEventHandler::ReleaseIfCaptureByDescendant(nsIContent* aContent) {
   // We should check that aChild does not contain pointer capturing elements.
   // If it does we should release the pointer capture for the elements.
   for (auto iter = sPointerCaptureList->Iter(); !iter.Done(); iter.Next()) {
     PointerCaptureInfo* data = iter.UserData();
     if (data && data->mPendingContent &&
-        nsContentUtils::ContentIsDescendantOf(data->mPendingContent,
-                                              aContent)) {
+        data->mPendingContent->IsInclusiveDescendantOf(aContent)) {
       ReleasePointerCaptureById(iter.Key());
     }
   }
 }
 
 /* static */
 void PointerEventHandler::PreHandlePointerEventsPreventDefault(
     WidgetPointerEvent* aPointerEvent, WidgetGUIEvent* aMouseOrTouchEvent) {
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -925,16 +925,16 @@ TextComposition* TextCompositionArray::G
   return ElementAt(i);
 }
 
 TextComposition* TextCompositionArray::GetCompositionInContent(
     nsPresContext* aPresContext, nsIContent* aContent) {
   // There should be only one composition per content object.
   for (index_type i = Length(); i > 0; --i) {
     nsINode* node = ElementAt(i - 1)->GetEventTargetNode();
-    if (node && nsContentUtils::ContentIsDescendantOf(node, aContent)) {
+    if (node && node->IsInclusiveDescendantOf(aContent)) {
       return ElementAt(i - 1);
     }
   }
   return nullptr;
 }
 
 }  // namespace mozilla
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -292,17 +292,17 @@ static void CollectOrphans(nsINode* aRem
     // node is in fact a descendant of the form and hence should stay in the
     // form.  If it _is_ set, then we need to check whether the node is a
     // descendant of aRemovalRoot.  If it is, we leave it in the form.
 #ifdef DEBUG
     bool removed = false;
 #endif
     if (node->HasFlag(MAYBE_ORPHAN_FORM_ELEMENT)) {
       node->UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
-      if (!nsContentUtils::ContentIsDescendantOf(node, aRemovalRoot)) {
+      if (!node->IsInclusiveDescendantOf(aRemovalRoot)) {
         node->ClearForm(true, false);
 
         // When a form control loses its form owner, its state can change.
         node->UpdateState(true);
 #ifdef DEBUG
         removed = true;
 #endif
       }
@@ -333,17 +333,17 @@ static void CollectOrphans(nsINode* aRem
     // node is in fact a descendant of the form and hence should stay in the
     // form.  If it _is_ set, then we need to check whether the node is a
     // descendant of aRemovalRoot.  If it is, we leave it in the form.
 #ifdef DEBUG
     bool removed = false;
 #endif
     if (node->HasFlag(MAYBE_ORPHAN_FORM_ELEMENT)) {
       node->UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
-      if (!nsContentUtils::ContentIsDescendantOf(node, aRemovalRoot)) {
+      if (!node->IsInclusiveDescendantOf(aRemovalRoot)) {
         node->ClearForm(true);
 
 #ifdef DEBUG
         removed = true;
 #endif
       }
     }
 
--- a/dom/html/HTMLMetaElement.cpp
+++ b/dom/html/HTMLMetaElement.cpp
@@ -35,17 +35,17 @@ void HTMLMetaElement::SetMetaReferrer(Do
   if (!aDocument || !AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
                                  nsGkAtoms::referrer, eIgnoreCase)) {
     return;
   }
   nsAutoString content;
   GetContent(content);
 
   Element* headElt = aDocument->GetHeadElement();
-  if (headElt && nsContentUtils::ContentIsDescendantOf(this, headElt)) {
+  if (headElt && IsInclusiveDescendantOf(headElt)) {
     content = nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
         content);
     aDocument->UpdateReferrerInfoFromMeta(content, false);
   }
 }
 
 nsresult HTMLMetaElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
                                        const nsAttrValue* aValue,
@@ -86,17 +86,17 @@ nsresult HTMLMetaElement::BindToTree(Bin
   }
 
   if (StaticPrefs::security_csp_enable() && !doc.IsLoadedAsData() &&
       AttrValueIs(kNameSpaceID_None, nsGkAtoms::httpEquiv, nsGkAtoms::headerCSP,
                   eIgnoreCase)) {
     // only accept <meta http-equiv="Content-Security-Policy" content=""> if it
     // appears in the <head> element.
     Element* headElt = doc.GetHeadElement();
-    if (headElt && nsContentUtils::ContentIsDescendantOf(this, headElt)) {
+    if (headElt && IsInclusiveDescendantOf(headElt)) {
       nsAutoString content;
       GetContent(content);
       content =
           nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
               content);
 
       if (nsCOMPtr<nsIContentSecurityPolicy> csp = doc.GetCsp()) {
         if (LOG_ENABLED()) {
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -528,17 +528,17 @@ void HTMLSelectElement::Add(nsGenericHTM
   if (!aBefore) {
     Element::AppendChild(aElement, aError);
     return;
   }
 
   // Just in case we're not the parent, get the parent of the reference
   // element
   nsCOMPtr<nsINode> parent = aBefore->Element::GetParentNode();
-  if (!parent || !nsContentUtils::ContentIsDescendantOf(parent, this)) {
+  if (!parent || !parent->IsInclusiveDescendantOf(this)) {
     // NOT_FOUND_ERR: Raised if before is not a descendant of the SELECT
     // element.
     aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
     return;
   }
 
   // If the before parameter is not null, we are equivalent to the
   // insertBefore method on the parent of before.
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -505,17 +505,17 @@ HTMLFormElement* nsGenericHTMLElement::F
     if (!content && aCurrentForm) {
       // We got to the root of the subtree we're in, and we're being removed
       // from the DOM (the only time we get into this method with a non-null
       // aCurrentForm).  Check whether aCurrentForm is in the same subtree.  If
       // it is, we want to return aCurrentForm, since this case means that
       // we're one of those inputs-in-a-table that have a hacked mForm pointer
       // and a subtree containing both us and the form got removed from the
       // DOM.
-      if (nsContentUtils::ContentIsDescendantOf(aCurrentForm, prevContent)) {
+      if (aCurrentForm->IsInclusiveDescendantOf(prevContent)) {
         return aCurrentForm;
       }
     }
   }
 
   return nullptr;
 }
 
--- a/dom/xbl/nsXBLWindowKeyHandler.cpp
+++ b/dom/xbl/nsXBLWindowKeyHandler.cpp
@@ -394,18 +394,17 @@ bool nsXBLWindowKeyHandler::IsHTMLEditab
     // Note that GetActiveEditingHost finds the current editing host based on
     // the document's selection.  Even though the document selection is usually
     // collapsed to where the focus is, but the page may modify the selection
     // without our knowledge, in which case this check will do something useful.
     nsCOMPtr<Element> activeEditingHost = htmlEditor->GetActiveEditingHost();
     if (!activeEditingHost) {
       return false;
     }
-    return nsContentUtils::ContentIsDescendantOf(focusedNode,
-                                                 activeEditingHost);
+    return focusedNode->IsInclusiveDescendantOf(activeEditingHost);
   }
 
   return false;
 }
 
 //
 // WalkHandlersInternal and WalkHandlersAndExecute
 //
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -3538,29 +3538,29 @@ bool EditorBase::IsDescendantOfRoot(nsIN
   if (NS_WARN_IF(!inNode)) {
     return false;
   }
   nsIContent* root = GetRoot();
   if (NS_WARN_IF(!root)) {
     return false;
   }
 
-  return nsContentUtils::ContentIsDescendantOf(inNode, root);
+  return inNode->IsInclusiveDescendantOf(root);
 }
 
 bool EditorBase::IsDescendantOfEditorRoot(nsINode* aNode) const {
   if (NS_WARN_IF(!aNode)) {
     return false;
   }
   nsIContent* root = GetEditorRoot();
   if (NS_WARN_IF(!root)) {
     return false;
   }
 
-  return nsContentUtils::ContentIsDescendantOf(aNode, root);
+  return aNode->IsInclusiveDescendantOf(root);
 }
 
 bool EditorBase::IsContainer(nsINode* aNode) { return aNode ? true : false; }
 
 uint32_t EditorBase::CountEditableChildren(nsINode* aNode) {
   MOZ_ASSERT(aNode);
   uint32_t count = 0;
   for (nsIContent* child = aNode->GetFirstChild(); child;
--- a/editor/libeditor/EditorEventListener.cpp
+++ b/editor/libeditor/EditorEventListener.cpp
@@ -194,17 +194,17 @@ void EditorEventListener::Disconnect() {
   }
   UninstallFromEditor();
 
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm) {
     nsIContent* focusedContent = fm->GetFocusedElement();
     mozilla::dom::Element* root = mEditorBase->GetRoot();
     if (focusedContent && root &&
-        nsContentUtils::ContentIsDescendantOf(focusedContent, root)) {
+        focusedContent->IsInclusiveDescendantOf(root)) {
       // Reset the Selection ancestor limiter and SelectionController state
       // that EditorBase::InitializeSelection set up.
       mEditorBase->FinalizeSelection();
     }
   }
 
   mEditorBase = nullptr;
 }
@@ -1129,12 +1129,12 @@ bool EditorEventListener::ShouldHandleNa
     return true;
   }
 
   nsIContent* editingHost = htmlEditor->GetActiveEditingHost();
   if (!editingHost) {
     return false;
   }
 
-  return nsContentUtils::ContentIsDescendantOf(targetContent, editingHost);
+  return targetContent->IsInclusiveDescendantOf(editingHost);
 }
 
 }  // namespace mozilla
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -7126,17 +7126,17 @@ void HTMLEditRules::PromoteRange(nsRange
     RefPtr<Element> block = HTMLEditorRef().GetBlock(*startNode);
     if (block) {
       bool bIsEmptyNode = false;
       nsIContent* host = HTMLEditorRef().GetActiveEditingHost();
       if (NS_WARN_IF(!host)) {
         return;
       }
       // Make sure we don't go higher than our root element in the content tree
-      if (!nsContentUtils::ContentIsDescendantOf(host, block)) {
+      if (!host->IsInclusiveDescendantOf(block)) {
         HTMLEditorRef().IsEmptyNode(block, &bIsEmptyNode, true, false);
       }
       if (bIsEmptyNode) {
         startNode = block;
         endNode = block;
         startOffset = 0;
         endOffset = block->Length();
       }
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -4889,18 +4889,18 @@ nsIContent* HTMLEditor::GetFocusedConten
     // in designMode, nobody gets focus in most cases.
     if (inDesignMode && OurWindowHasFocus()) {
       return document->GetRootElement();
     }
     return nullptr;
   }
 
   if (inDesignMode) {
-    return OurWindowHasFocus() && nsContentUtils::ContentIsDescendantOf(
-                                      focusedContent, document)
+    return OurWindowHasFocus() &&
+                   focusedContent->IsInclusiveDescendantOf(document)
                ? focusedContent.get()
                : nullptr;
   }
 
   // We're HTML editor for contenteditable
 
   // If the focused content isn't editable, or it has independent selection,
   // we don't have focus.
@@ -5014,17 +5014,17 @@ void HTMLEditor::NotifyEditingHostMaybeC
   // Compute current editing host.
   nsIContent* editingHost = GetActiveEditingHost();
   if (NS_WARN_IF(!editingHost)) {
     return;
   }
 
   // Update selection ancestor limit if current editing host includes the
   // previous editing host.
-  if (nsContentUtils::ContentIsDescendantOf(ancestorLimiter, editingHost)) {
+  if (ancestorLimiter->IsInclusiveDescendantOf(editingHost)) {
     // Note that don't call HTMLEditor::InitializeSelectionAncestorLimit() here
     // because it may collapse selection to the first editable node.
     EditorBase::InitializeSelectionAncestorLimit(*editingHost);
   }
 }
 
 EventTarget* HTMLEditor::GetDOMEventTarget() {
   // Don't use getDocument here, because we have no way of knowing
@@ -5182,17 +5182,17 @@ bool HTMLEditor::IsAcceptableInputEvent(
     // active editing host, we should assume that the click event is targetted.
     if (targetContent == document->GetRootElement() &&
         !targetContent->HasFlag(NODE_IS_EDITABLE) &&
         editingHost == document->GetBodyElement()) {
       targetContent = editingHost;
     }
     // If the target element is neither the active editing host nor a descendant
     // of it, we may not be able to handle the event.
-    if (!nsContentUtils::ContentIsDescendantOf(targetContent, editingHost)) {
+    if (!targetContent->IsInclusiveDescendantOf(editingHost)) {
       return false;
     }
     // If the clicked element has an independent selection, we shouldn't
     // handle this click event.
     if (targetContent->HasIndependentSelection()) {
       return false;
     }
     // If the target content is editable, we should handle this event.
--- a/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
@@ -752,17 +752,17 @@ void mozInlineSpellWordUtil::BuildSoftTe
     checkBeforeOffset = INT32_MAX;
     if (IsBreakElement(node)) {
       // Since GetPreviousContent follows tree *preorder*, we're about to
       // traverse up out of 'node'. Since node induces breaks (e.g., it's a
       // block), don't bother trying to look outside it, just stop now.
       break;
     }
     // GetPreviousContent below expects mRootNode to be an ancestor of node.
-    if (!nsContentUtils::ContentIsDescendantOf(node, mRootNode)) {
+    if (!node->IsInclusiveDescendantOf(mRootNode)) {
       break;
     }
     node = node->GetPreviousContent(mRootNode);
   }
 
   // Now build up the string moving forward through the DOM until we reach
   // the soft end and *then* see a DOM word separator, a non-inline-element
   // boundary, or the hard end node.
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -4409,17 +4409,17 @@ void PresShell::ContentRemoved(nsIConten
   if (MOZ_LIKELY(!aChild->IsRootOfAnonymousSubtree())) {
     oldNextSibling = aPreviousSibling ? aPreviousSibling->GetNextSibling()
                                       : container->GetFirstChild();
   }
 
   // After removing aChild from tree we should save information about live
   // ancestor
   if (mPointerEventTarget &&
-      nsContentUtils::ContentIsDescendantOf(mPointerEventTarget, aChild)) {
+      mPointerEventTarget->IsInclusiveDescendantOf(aChild)) {
     mPointerEventTarget = aChild->GetParent();
   }
 
   mFrameConstructor->ContentRemoved(aChild, oldNextSibling,
                                     nsCSSFrameConstructor::REMOVE_CONTENT);
 
   // NOTE(emilio): It's important that this goes after the frame constructor
   // stuff, otherwise the frame constructor can't see elements which are
@@ -7408,18 +7408,17 @@ nsIFrame* PresShell::EventHandler::Compu
   // case we only want to use the popup list if the capture is
   // inside the popup.
   if (framePresContext == rootPresContext &&
       aRootFrameToHandleEvent == FrameConstructor()->GetRootFrame()) {
     return popupFrame;
   }
 
   if (aCapturingContent && !*aIsCapturingContentIgnored &&
-      nsContentUtils::ContentIsDescendantOf(aCapturingContent,
-                                            popupFrame->GetContent())) {
+      aCapturingContent->IsInclusiveDescendantOf(popupFrame->GetContent())) {
     return popupFrame;
   }
 
   return aRootFrameToHandleEvent;
 }
 
 nsIFrame*
 PresShell::EventHandler::ComputeRootFrameToHandleEventWithCapturingContent(
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -816,17 +816,17 @@ bool nsCaret::IsMenuPopupHidingCaret() {
   if (!caretContent) return true;  // No selection/caret to draw.
 
   // If there's a menu popup open before the popup with
   // the caret, don't show the caret.
   for (uint32_t i = 0; i < popups.Length(); i++) {
     nsMenuPopupFrame* popupFrame = static_cast<nsMenuPopupFrame*>(popups[i]);
     nsIContent* popupContent = popupFrame->GetContent();
 
-    if (nsContentUtils::ContentIsDescendantOf(caretContent, popupContent)) {
+    if (caretContent->IsInclusiveDescendantOf(popupContent)) {
       // The caret is in this popup. There were no menu popups before this
       // popup, so don't hide the caret.
       return false;
     }
 
     if (popupFrame->PopupType() == ePopupTypeMenu &&
         !popupFrame->IsContextMenu()) {
       // This is an open menu popup. It does not contain the caret (else we'd
--- a/layout/base/nsCounterManager.cpp
+++ b/layout/base/nsCounterManager.cpp
@@ -152,18 +152,17 @@ void nsCounterList::SetScope(nsCounterNo
                  "is for the root, startContent (which is before it) "
                  "must be too");
 
     // A reset's outer scope can't be a scope created by a sibling.
     if (!(aNode->mType == nsCounterNode::RESET &&
           nodeContent == startContent) &&
         // everything is inside the root (except the case above,
         // a second reset on the root)
-        (!startContent ||
-         nsContentUtils::ContentIsDescendantOf(nodeContent, startContent))) {
+        (!startContent || nodeContent->IsInclusiveDescendantOf(startContent))) {
       aNode->mScopeStart = start;
       aNode->mScopePrev = prev;
       return;
     }
   }
 
   aNode->mScopeStart = nullptr;
   aNode->mScopePrev = nullptr;
--- a/layout/generic/ScrollbarActivity.cpp
+++ b/layout/generic/ScrollbarActivity.cpp
@@ -139,18 +139,17 @@ void ScrollbarActivity::WillRefresh(Time
 bool ScrollbarActivity::IsStillFading(TimeStamp aTime) {
   return !mFadeBeginTime.IsNull() && (aTime - mFadeBeginTime < FadeDuration());
 }
 
 void ScrollbarActivity::HandleEventForScrollbar(const nsAString& aType,
                                                 nsIContent* aTarget,
                                                 Element* aScrollbar,
                                                 bool* aStoredHoverState) {
-  if (!aTarget || !aScrollbar ||
-      !nsContentUtils::ContentIsDescendantOf(aTarget, aScrollbar))
+  if (!aTarget || !aScrollbar || !aTarget->IsInclusiveDescendantOf(aScrollbar))
     return;
 
   if (aType.EqualsLiteral("mousedown")) {
     ActivityStarted();
   } else if (aType.EqualsLiteral("mouseup")) {
     ActivityStopped();
   } else if (aType.EqualsLiteral("mouseover") ||
              aType.EqualsLiteral("mouseout")) {
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -856,18 +856,18 @@ bool TextOverflow::CanHaveOverflowMarker
 
   // Inhibit the markers if a descendant content owns the caret.
   RefPtr<nsCaret> caret = aBlockFrame->PresShell()->GetCaret();
   if (caret && caret->IsVisible()) {
     RefPtr<dom::Selection> domSelection = caret->GetSelection();
     if (domSelection) {
       nsCOMPtr<nsIContent> content =
           nsIContent::FromNodeOrNull(domSelection->GetFocusNode());
-      if (content && nsContentUtils::ContentIsDescendantOf(
-                         content, aBlockFrame->GetContent())) {
+      if (content &&
+          content->IsInclusiveDescendantOf(aBlockFrame->GetContent())) {
         return false;
       }
     }
   }
   return true;
 }
 
 void TextOverflow::CreateMarkers(const nsLineBox* aLine, bool aCreateIStart,
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -4185,18 +4185,17 @@ nsresult nsFrame::GetDataForTableSelecti
   bool foundCell = false;
   bool foundTable = false;
 
   // Get the limiting node to stop parent frame search
   nsIContent* limiter = aFrameSelection->GetLimiter();
 
   // If our content node is an ancestor of the limiting node,
   // we should stop the search right now.
-  if (limiter && nsContentUtils::ContentIsDescendantOf(limiter, GetContent()))
-    return NS_OK;
+  if (limiter && limiter->IsInclusiveDescendantOf(GetContent())) return NS_OK;
 
   // We don't initiate row/col selection from here now,
   //  but we may in future
   // bool selectColumn = false;
   // bool selectRow = false;
 
   while (frame) {
     // Check for a table cell by querying to a known CellFrame interface
--- a/layout/generic/nsFrameSelection.cpp
+++ b/layout/generic/nsFrameSelection.cpp
@@ -174,17 +174,17 @@ bool IsValidSelectionPoint(nsFrameSelect
   nsIContent* limiter = aFrameSel->GetLimiter();
   if (limiter && limiter != aNode && limiter != aNode->GetParent()) {
     // if newfocus == the limiter. that's ok. but if not there and not parent
     // bad
     return false;  // not in the right content. tLimiter said so
   }
 
   limiter = aFrameSel->GetAncestorLimiter();
-  return !limiter || nsContentUtils::ContentIsDescendantOf(aNode, limiter);
+  return !limiter || aNode->IsInclusiveDescendantOf(limiter);
 }
 
 namespace mozilla {
 struct MOZ_RAII AutoPrepareFocusRange {
   AutoPrepareFocusRange(Selection* aSelection, bool aContinueSelection,
                         bool aMultipleSelection
                             MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
@@ -1271,19 +1271,18 @@ nsresult nsFrameSelection::TakeFocus(nsI
     bool editableCell = false;
     mCellParent = nullptr;
     RefPtr<nsPresContext> context = mPresShell->GetPresContext();
     if (context) {
       RefPtr<HTMLEditor> htmlEditor = nsContentUtils::GetHTMLEditor(context);
       if (htmlEditor) {
         nsINode* cellparent = GetCellParent(aNewFocus);
         nsCOMPtr<nsINode> editorHostNode = htmlEditor->GetActiveEditingHost();
-        editableCell =
-            cellparent && editorHostNode &&
-            nsContentUtils::ContentIsDescendantOf(cellparent, editorHostNode);
+        editableCell = cellparent && editorHostNode &&
+                       cellparent->IsInclusiveDescendantOf(editorHostNode);
         if (editableCell) {
           mCellParent = cellparent;
 #ifdef DEBUG_TABLE_SELECTION
           printf(" * TakeFocus - Collapsing into new cell\n");
 #endif
         }
       }
     }
--- a/testing/mochitest/tests/SimpleTest/MozillaLogger.js
+++ b/testing/mochitest/tests/SimpleTest/MozillaLogger.js
@@ -13,17 +13,24 @@ function importJSM(jsm) {
     return ChromeUtils.import(jsm);
   }
   /* globals SpecialPowers */
   let obj = {};
   SpecialPowers.Cu.import(jsm, obj);
   return SpecialPowers.wrap(obj);
 }
 
-let CC = (typeof Components === "object"
+// When running in release builds, we get a fake Components object in
+// web contexts, so we need to check that the Components object is sane,
+// too, not just that it exists.
+let haveComponents =
+  typeof Components === "object" &&
+  typeof Components.Constructor === "function";
+
+let CC = (haveComponents
             ? Components
             : SpecialPowers.wrap(SpecialPowers.Components)).Constructor;
 
 let ConverterOutputStream = CC("@mozilla.org/intl/converter-output-stream;1",
                                "nsIConverterOutputStream", "init");
 
 class MozillaLogger {
   get logCallback() {
--- a/testing/web-platform/meta/css/css-animations/Element-getAnimations-dynamic-changes.tentative.html.ini
+++ b/testing/web-platform/meta/css/css-animations/Element-getAnimations-dynamic-changes.tentative.html.ini
@@ -1,7 +1,3 @@
 [Element-getAnimations-dynamic-changes.tentative.html]
   disabled:
     if (os == "android") and not e10s: https://bugzilla.mozilla.org/show_bug.cgi?id=1499003
-  [Only the startTimes of existing animations are preserved]
-    expected:
-      if (os == "android") and debug: PASS
-
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-text/parsing/letter-spacing-computed.html.ini
@@ -0,0 +1,4 @@
+[letter-spacing-computed.html]
+  [Property letter-spacing value 'normal' computes to '0px']
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-text/parsing/tab-size-computed.html.ini
@@ -0,0 +1,25 @@
+[tab-size-computed.html]
+  [Property tab-size value '2.5' computes to '2.5']
+    expected: FAIL
+
+  [Property tab-size value '10px' computes to '10px']
+    expected: FAIL
+
+  [Property tab-size value '4' computes to '4']
+    expected: FAIL
+
+  [Property tab-size value '0px' computes to '0px']
+    expected: FAIL
+
+  [Property tab-size value 'calc(10px - 0.5em)' computes to '0px']
+    expected: FAIL
+
+  [Property tab-size value '0' computes to '0']
+    expected: FAIL
+
+  [Property tab-size value '16' computes to '16']
+    expected: FAIL
+
+  [Property tab-size value 'calc(10px + 0.5em)' computes to '30px']
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-text/parsing/text-align-last-computed.html.ini
@@ -0,0 +1,4 @@
+[text-align-last-computed.html]
+  [Property text-align-last value 'match-parent' computes to 'match-parent']
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-text/parsing/text-indent-computed.html.ini
@@ -0,0 +1,13 @@
+[text-indent-computed.html]
+  [Property text-indent value '10px hanging' computes to '10px hanging']
+    expected: FAIL
+
+  [Property text-indent value 'each-line hanging calc(10px + 0.5em)' computes to '30px hanging each-line']
+    expected: FAIL
+
+  [Property text-indent value '20% each-line' computes to '20% each-line']
+    expected: FAIL
+
+  [Property text-indent value 'calc(50% + 60px) hanging each-line' computes to 'calc(50% + 60px) hanging each-line']
+    expected: FAIL
+
--- a/testing/web-platform/meta/css/css-ui/appearance-textarea-001.html.ini
+++ b/testing/web-platform/meta/css/css-ui/appearance-textarea-001.html.ini
@@ -1,8 +1,7 @@
 [appearance-textarea-001.html]
   disabled:
-    if debug and os == "win" and version == "6.1.7601": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
-    if os == "win" and processor == "aarch64": https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
+    if debug and (os == "win") and (version == "6.1.7601"): https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
+    if (os == "win") and (processor == "aarch64"): https://bugzilla.mozilla.org/show_bug.cgi?id=1560360
   expected:
-    if (os == "win") and debug and (processor == "x86_64"): FAIL
     if (os == "win") and not debug: FAIL
-    if os == "win": FAIL
+    if (os == "win") and debug and not webrender: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/cssom-view/scroll-behavior-default-css.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[scroll-behavior-default-css.html]
-  disabled:
-    if os == "android": https://bugzilla.mozilla.org/show_bug.cgi?id=1565072
-
-  [Smooth scrolling of an element with default scroll-behavior]
-    expected:
-      if (os == "android") and e10s: FAIL # Bug 1565072
--- a/testing/web-platform/meta/editing/run/bold.html.ini
+++ b/testing/web-platform/meta/editing/run/bold.html.ini
@@ -485,16 +485,19 @@
     expected: FAIL
 
   [[["bold",""\]\] "foo{<i><b></b></i>}baz" compare innerHTML]
     expected: FAIL
 
   [[["bold",""\]\] "foo{<i><b></b></i>}baz" queryCommandState("bold") after]
     expected: FAIL
 
+  [bold - HTML editing conformance tests]
+    expected: FAIL
+
 
 [bold.html?1001-2000]
   [[["stylewithcss","false"\],["bold",""\]\] "foo[<span style=\\"font-weight: bold\\">bar</span>\]baz" queryCommandState("stylewithcss") before]
     expected: FAIL
 
   [[["stylewithcss","false"\],["bold",""\]\] "foo[<span style=\\"font-weight: bold\\">bar</span>\]baz" queryCommandState("bold") after]
     expected: FAIL
 
--- a/testing/web-platform/meta/html/cross-origin-opener/__dir__.ini
+++ b/testing/web-platform/meta/html/cross-origin-opener/__dir__.ini
@@ -1,4 +1,4 @@
 prefs: [browser.tabs.remote.useCrossOriginOpenerPolicy:true]
-
 disabled:
   if verify: intermittent timeouts in verify mode
+leak-threshold: [default:51200]
deleted file mode 100644
--- a/testing/web-platform/meta/mozilla-sync
+++ b/testing/web-platform/meta/mozilla-sync
@@ -1,2 +1,2 @@
-local: 70925079c98cacb0ecda0a7fe4f40af089f80056
-upstream: dcac708930b6e73bf3e7629908b6467e7644cff9
+local: 18589b83fcffad1794ee7f0e8c4e14fd87846b4a
+upstream: 8b045d6e3d77fffcfb4096697c9665225294efea
--- a/testing/web-platform/meta/service-workers/service-worker/navigation-timing.https.html.ini
+++ b/testing/web-platform/meta/service-workers/service-worker/navigation-timing.https.html.ini
@@ -1,12 +1,12 @@
 [navigation-timing.https.html]
   disabled:
     if (os == "android") and not debug: https://bugzilla.mozilla.org/show_bug.cgi?id=1560324
     if (os == "android") and not e10s: https://bugzilla.mozilla.org/show_bug.cgi?id=1499972
   [Service worker controlled navigation timing network fallback]
-    disabled: 
-      if (os == "android"): Frequently failing on geckoview (Bug 1481427)
+    disabled:
+      if os == "android": Frequently failing on geckoview (Bug 1481427)
 
   [Service worker controlled navigation timing redirect]
     disabled:
-      if (os == "android"): Frequently failing on geckoview (Bug 1560324, Bug 1481553)
+      if os == "android": Frequently failing on geckoview (Bug 1560324, Bug 1481553)
 
--- a/testing/web-platform/meta/svg/types/scripted/SVGGeometryElement.isPointInStroke-01.svg.ini
+++ b/testing/web-platform/meta/svg/types/scripted/SVGGeometryElement.isPointInStroke-01.svg.ini
@@ -1,3 +1,4 @@
 [SVGGeometryElement.isPointInStroke-01.svg]
   [SVGGeometryElement.prototype.isPointInStroke, non-finite argument.]
     expected: FAIL
+
--- a/testing/web-platform/meta/user-timing/measure-with-dict.html.ini
+++ b/testing/web-platform/meta/user-timing/measure-with-dict.html.ini
@@ -1,4 +1,7 @@
 [measure-with-dict.html]
   [measure entries' detail and start/end are customizable]
     expected: FAIL
 
+  [measure should throw a TypeError when passed an invalid argument combination]
+    expected: FAIL
+
--- a/testing/web-platform/meta/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html.ini
+++ b/testing/web-platform/meta/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html.ini
@@ -1,9 +1,4 @@
 [mediaElementAudioSourceToScriptProcessorTest.html]
   disabled:
     if (os == "mac") and (version == "OS X 10.14"): new platform
     if (os == "android") and debug: https://bugzilla.mozilla.org/show_bug.cgi?id=1546756
-
-  [All data processed correctly]
-    expected:
-      if (os == "android") and debug: PASS
-
--- a/testing/web-platform/meta/websockets/__dir__.ini
+++ b/testing/web-platform/meta/websockets/__dir__.ini
@@ -1,2 +1,2 @@
-lsan-allowed: [Alloc, Create, GetClientInfo, MakeUnique, NewPage, PLDHashTable::Add, Realloc, SetPropertyAsInterface, mozilla::BasePrincipal::CreateContentPrincipal, mozilla::SchedulerGroup::CreateEventTargetFor, mozilla::WeakPtr, mozilla::dom::WebSocket::ConstructorCommon, mozilla::dom::WebSocket::WebSocket, mozilla::extensions::ChannelWrapper::ChannelWrapper, mozilla::net::BaseWebSocketChannel::InitLoadInfo, mozilla::net::BaseWebSocketChannel::InitLoadInfoNative, mozilla::net::CookieSettings::Create, mozilla::net::LoadInfo::LoadInfo, mozilla::net::WebSocketChannelChild::AsyncOpen, mozilla::net::WebSocketEventService::GetOrCreate, mozilla::net::nsHttpTransaction::ParseHead, mozilla::net::nsStandardURL::TemplatedMutator, nsNodeSupportsWeakRefTearoff::GetWeakReference, nsSupportsWeakReference::GetWeakReference]
+lsan-allowed: [Alloc, Create, EnterJit, GetClientInfo, MakeUnique, NewPage, PLDHashTable::Add, Realloc, SetPropertyAsInterface, mozilla::BasePrincipal::CreateContentPrincipal, mozilla::SchedulerGroup::CreateEventTargetFor, mozilla::WeakPtr, mozilla::dom::WebSocket::ConstructorCommon, mozilla::dom::WebSocket::WebSocket, mozilla::extensions::ChannelWrapper::ChannelWrapper, mozilla::net::BaseWebSocketChannel::InitLoadInfo, mozilla::net::BaseWebSocketChannel::InitLoadInfoNative, mozilla::net::CookieSettings::Create, mozilla::net::LoadInfo::LoadInfo, mozilla::net::WebSocketChannelChild::AsyncOpen, mozilla::net::WebSocketEventService::GetOrCreate, mozilla::net::nsHttpTransaction::ParseHead, mozilla::net::nsStandardURL::TemplatedMutator, nsNodeSupportsWeakRefTearoff::GetWeakReference, nsSupportsWeakReference::GetWeakReference]
 leak-threshold: [default:102400, tab:51200]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/parsing/hyphens-computed.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text: getComputedValue().hyphens</title>
+<link rel="help" href="https://www.w3.org/TR/css-text-3/#propdef-hyphens">
+<meta name="assert" content="hyphens computed value is specified keyword.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("hyphens", "none");
+test_computed_value("hyphens", "manual");
+test_computed_value("hyphens", "auto");
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/parsing/letter-spacing-computed.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text: getComputedValue().letterSpacing</title>
+<link rel="help" href="https://www.w3.org/TR/css-text-3/#propdef-letter-spacing">
+<meta name="assert" content="letter-spacing computed value is an absolute length.">
+<meta name="assert" content="'normal' computes to zero.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #target {
+    font-size: 40px;
+  }
+</style>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("letter-spacing", "normal", "0px");
+
+test_computed_value("letter-spacing", "10px");
+test_computed_value("letter-spacing", "-20px");
+test_computed_value("letter-spacing", "calc(10px - 0.5em)", "-10px");
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/parsing/line-break-computed.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text: getComputedValue().lineBreak</title>
+<link rel="help" href="https://www.w3.org/TR/css-text-3/#propdef-line-break">
+<meta name="assert" content="line-break computed value is specified keyword.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("line-break", "auto");
+test_computed_value("line-break", "loose");
+test_computed_value("line-break", "normal");
+test_computed_value("line-break", "strict");
+test_computed_value("line-break", "anywhere");
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/parsing/overflow-wrap-computed.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text: getComputedValue().overflowWrap</title>
+<link rel="help" href="https://www.w3.org/TR/css-text-3/#propdef-overflow-wrap">
+<meta name="assert" content="overflow-wrap computed value is specified keyword.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("overflow-wrap", "normal");
+test_computed_value("overflow-wrap", "break-word");
+test_computed_value("overflow-wrap", "anywhere");
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/parsing/tab-size-computed.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text: getComputedValue().tabSize</title>
+<link rel="help" href="https://www.w3.org/TR/css-text-3/#propdef-tab-size">
+<meta name="assert" content="tab-size computed value is the specified number or an absolute length.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #target {
+    font-size: 40px;
+  }
+</style>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("tab-size", "0");
+test_computed_value("tab-size", "16");
+test_computed_value("tab-size", "4");
+test_computed_value("tab-size", "2.5");
+
+test_computed_value("tab-size", "0px");
+test_computed_value("tab-size", "10px");
+test_computed_value("tab-size", "calc(10px + 0.5em)", "30px");
+test_computed_value("tab-size", "calc(10px - 0.5em)", "0px");
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/parsing/text-align-last-computed.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text: getComputedValue().textAlignLast</title>
+<link rel="help" href="https://www.w3.org/TR/css-text-3/#propdef-text-align-last">
+<meta name="assert" content="text-align-last computed value is specified keyword.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("text-align-last", "auto");
+test_computed_value("text-align-last", "start");
+test_computed_value("text-align-last", "end");
+test_computed_value("text-align-last", "left");
+test_computed_value("text-align-last", "right");
+test_computed_value("text-align-last", "center");
+test_computed_value("text-align-last", "justify");
+test_computed_value("text-align-last", "match-parent");
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/parsing/text-indent-computed.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text: getComputedValue().textIndent</title>
+<link rel="help" href="https://www.w3.org/TR/css-text-3/#propdef-text-indent">
+<meta name="assert" content="text-indent computed value is computed <length-percentage> value, plus any specified keywords.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #target {
+    font-size: 40px;
+  }
+</style>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("text-indent", "10px");
+test_computed_value("text-indent", "20%");
+test_computed_value("text-indent", "calc(50% + 60px)");
+test_computed_value("text-indent", "-30px");
+test_computed_value("text-indent", "-40%");
+test_computed_value("text-indent", "calc(10px - 0.5em)", "-10px");
+
+test_computed_value("text-indent", "10px hanging");
+test_computed_value("text-indent", "20% each-line");
+test_computed_value("text-indent", "calc(50% + 60px) hanging each-line");
+test_computed_value("text-indent", "each-line hanging calc(10px + 0.5em)", "30px hanging each-line");
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/parsing/text-justify-computed.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text: getComputedValue().textJustify</title>
+<link rel="help" href="https://www.w3.org/TR/css-text-3/#propdef-text-justify">
+<meta name="assert" content="text-justify computed value is specified keyword.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("text-justify", "auto");
+test_computed_value("text-justify", "none");
+test_computed_value("text-justify", "inter-word");
+test_computed_value("text-justify", "inter-character");
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/parsing/text-transform-computed.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text: getComputedValue().textTransform</title>
+<link rel="help" href="https://www.w3.org/TR/css-text-3/#propdef-text-transform">
+<meta name="assert" content="text-transform computed value is specified keywords.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("text-transform", "none");
+
+test_computed_value("text-transform", "capitalize");
+test_computed_value("text-transform", "uppercase");
+test_computed_value("text-transform", "lowercase");
+test_computed_value("text-transform", "full-width");
+test_computed_value("text-transform", "full-size-kana");
+
+test_computed_value("text-transform", "capitalize full-width");
+test_computed_value("text-transform", "full-width full-size-kana");
+
+test_computed_value("text-transform", "uppercase full-width full-size-kana");
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/parsing/white-space-computed.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text: getComputedValue().whiteSpace</title>
+<link rel="help" href="https://www.w3.org/TR/css-text-3/#propdef-white-space">
+<meta name="assert" content="white-space computed value is specified keyword.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("white-space", "normal");
+test_computed_value("white-space", "pre");
+test_computed_value("white-space", "nowrap");
+test_computed_value("white-space", "pre-wrap");
+test_computed_value("white-space", "break-spaces");
+test_computed_value("white-space", "pre-line");
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/parsing/word-break-computed.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text: getComputedValue().wordBreak</title>
+<link rel="help" href="https://www.w3.org/TR/css-text-3/#propdef-word-break">
+<meta name="assert" content="word-break computed value is specified keyword.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("word-break", "normal");
+test_computed_value("word-break", "keep-all");
+test_computed_value("word-break", "break-all");
+test_computed_value("word-break", "break-word");
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/parsing/word-spacing-computed.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text: getComputedValue().wordSpacing</title>
+<link rel="help" href="https://www.w3.org/TR/css-text-3/#propdef-word-spacing">
+<meta name="assert" content="word-spacing computed value is an absolute length.">
+<meta name="assert" content="'normal' computes to zero.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<style>
+  #target {
+    font-size: 40px;
+  }
+</style>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("word-spacing", "normal", "0px");
+
+test_computed_value("word-spacing", "10px");
+test_computed_value("word-spacing", "-20px");
+test_computed_value("word-spacing", "calc(10px - 0.5em)", "-10px");
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/parsing/word-wrap-computed.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text: getComputedValue().wordWrap</title>
+<link rel="help" href="https://www.w3.org/TR/css-text-3/#propdef-word-wrap">
+<meta name="assert" content="word-wrap computed value is specified keyword.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("word-wrap", "normal");
+test_computed_value("word-wrap", "break-word");
+test_computed_value("word-wrap", "anywhere");
+</script>
+</body>
+</html>
--- a/testing/web-platform/tests/user-timing/measure-with-dict.html
+++ b/testing/web-platform/tests/user-timing/measure-with-dict.html
@@ -1,16 +1,22 @@
 <!DOCTYPE HTML>
 <meta charset=utf-8>
 <title>User Timing L3: measure is customizable</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="resources/user-timing-helper.js"></script>
 <script>
+  function cleanupPerformanceTimeline() {
+    performance.clearMarks();
+    performance.clearMeasures();
+  }
+
   async_test(function (t) {
+    this.add_cleanup(cleanupPerformanceTimeline);
     let measureEntries = [];
     const timeStamp1 = 784.4;
     const timeStamp2 = 1234.5;
     const timeStamp3 = 66.6;
     const timeStamp4 = 5566;
     const expectedEntries =
         [{ entryType: "measure", name: "measure1", detail: null, startTime: 0 },
         { entryType: "measure", name: "measure2", detail: null, startTime: 0 },
@@ -35,18 +41,16 @@
             measureEntries.concat(entryList.getEntries());
           if (measureEntries.length >= expectedEntries.length) {
             checkEntries(measureEntries, expectedEntries);
             observer.disconnect();
             t.done();
           }
         })
       );
-    self.performance.clearMarks();
-    self.performance.clearMeasures();
     observer.observe({ entryTypes: ["measure"] });
     self.performance.mark("mark1", { detail: { randomInfo: 3 }, startTime: timeStamp1 });
     self.performance.mark("mark2", { startTime: timeStamp2 });
 
     const returnedEntries = [];
     returnedEntries.push(self.performance.measure("measure1"));
     returnedEntries.push(self.performance.measure("measure2", undefined));
     returnedEntries.push(self.performance.measure("measure3", null));
@@ -75,15 +79,21 @@
         self.performance.measure("measure15", { start: timeStamp1, end: timeStamp2, detail: undefined }));
     returnedEntries.push(
         self.performance.measure("measure16", { start: 'mark1', end: undefined, detail: null }));
     returnedEntries.push(
         self.performance.measure("measure17", { start: timeStamp3, end: 'mark2', detail: { customInfo: 159 }}));
     checkEntries(returnedEntries, expectedEntries);
   }, "measure entries' detail and start/end are customizable");
 
-  async_test(function (t) {
-    assert_throws("SyntaxError", function() {
+  test(function () {
+    this.add_cleanup(cleanupPerformanceTimeline);
+    assert_throws(new TypeError(), function() {
       self.performance.measure("wrongUsage1", {}, 12);
-    });
-    t.done();
-  }, "measure should throw exception when passing option object and end at the same time");
+    }, "measure should throw a TypeError when passed an options object and an end time");
+    assert_throws(new TypeError(), function() {
+      self.performance.measure("wrongUsage2", {'startTime': 2}, 12);
+    }, "measure should throw a TypeError when passed an options object and an end time");
+    assert_throws(new TypeError(), function() {
+      self.performance.measure("wrongUsage3", {'startTime': 2}, 'mark1');
+    }, "measure should throw a TypeError when passed an options object and an end mark");
+  }, "measure should throw a TypeError when passed an invalid argument combination");
 </script>
--- a/testing/web-platform/tests/webvtt/rendering/cues-with-video/processing-model/basic-ref.html
+++ b/testing/web-platform/tests/webvtt/rendering/cues-with-video/processing-model/basic-ref.html
@@ -1,10 +1,11 @@
 <!DOCTYPE html>
 <title>Reference for WebVTT rendering, basic</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 html { overflow:hidden }
 body { margin:0 }
 .video {
     display: inline-block;
     width: 320px;
     height: 180px;
     position: relative;
--- a/testing/web-platform/tests/webvtt/rendering/cues-with-video/processing-model/basic.html
+++ b/testing/web-platform/tests/webvtt/rendering/cues-with-video/processing-model/basic.html
@@ -1,12 +1,13 @@
 <!DOCTYPE html>
 <html class="reftest-wait">
 <title>WebVTT rendering, basic</title>
 <link rel="match" href="basic-ref.html">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 html { overflow:hidden }
 body { margin:0 }
 ::cue {
     font-family: Ahem, sans-serif;
     color: green
 }
 </style>
--- a/testing/web-platform/tests/webvtt/rendering/cues-with-video/processing-model/line_0_is_top-ref.html
+++ b/testing/web-platform/tests/webvtt/rendering/cues-with-video/processing-model/line_0_is_top-ref.html
@@ -1,10 +1,11 @@
 <!DOCTYPE html>
 <title>Reference for WebVTT rendering, line:0 should be top line</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 html { overflow:hidden }
 body { margin:0 }
 .video {
     display: inline-block;
     width: 320px;
     height: 180px;
     position: relative;
--- a/testing/web-platform/tests/webvtt/rendering/cues-with-video/processing-model/line_0_is_top.html
+++ b/testing/web-platform/tests/webvtt/rendering/cues-with-video/processing-model/line_0_is_top.html
@@ -1,12 +1,13 @@
 <!DOCTYPE html>
 <html class="reftest-wait">
 <title>WebVTT rendering, line:0 should be top line</title>
 <link rel="match" href="line_0_is_top-ref.html">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 html { overflow:hidden }
 body { margin:0 }
 ::cue {
     font-family: Ahem, sans-serif;
     color: green
 }
 </style>
--- a/testing/web-platform/tests/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_namespace-ref.html
+++ b/testing/web-platform/tests/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_namespace-ref.html
@@ -1,10 +1,11 @@
 <!DOCTYPE html>
 <title>Reference for WebVTT rendering, ::cue(|c) should match</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 html { overflow:hidden }
 body { margin:0 }
 .video {
     display: inline-block;
     width: 320px;
     height: 180px;
     position: relative;
--- a/testing/web-platform/tests/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_namespace.html
+++ b/testing/web-platform/tests/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_namespace.html
@@ -1,12 +1,13 @@
 <!DOCTYPE html>
 <html class="reftest-wait">
 <title>WebVTT rendering, ::cue(|c) should match</title>
 <link rel="match" href="class_namespace-ref.html">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 html { overflow:hidden }
 body { margin:0 }
 ::cue {
     color: green;
     font-family: Ahem, sans-serif
 }
 ::cue(*|c) {