Merge inbound to mozilla-central. a=merge
authorCsoregi Natalia <ncsoregi@mozilla.com>
Mon, 31 Dec 2018 17:58:44 +0200
changeset 509286 83d06ab87e742c2eb63bce720741c0a222d20f36
parent 509275 ad2f233430e80a4c3764e5aacfbb164d169a9cac (current diff)
parent 509285 275c43b8572c70306e56d30e1f4e3df2f1c7090f (diff)
child 509300 c6e2a237b5940a7e607bc5fc19b73045692e0d7b
child 509308 6157629ebfa11147618ffc8322d79958229036ca
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
dom/smil/nsSMILAnimationFunction.cpp
dom/smil/nsSMILAnimationFunction.h
dom/smil/nsSMILSetAnimationFunction.cpp
dom/smil/nsSMILSetAnimationFunction.h
--- 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.1.132
+Current extension version is: 2.1.145
 
-Taken from upstream commit: d3868e1b
+Taken from upstream commit: d8f201ea
--- 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.1.132';
-var pdfjsBuild = 'd3868e1b';
+var pdfjsVersion = '2.1.145';
+var pdfjsBuild = 'd8f201ea';
 
 var pdfjsSharedUtil = __w_pdfjs_require__(1);
 
 var pdfjsDisplayAPI = __w_pdfjs_require__(7);
 
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(19);
 
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(20);
@@ -230,17 +230,17 @@ Object.defineProperty(exports, "Readable
   }
 });
 Object.defineProperty(exports, "URL", {
   enumerable: true,
   get: function () {
     return _url_polyfill.URL;
   }
 });
-exports.createObjectURL = exports.FormatError = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PermissionFlag = exports.PasswordResponses = exports.PasswordException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = void 0;
+exports.createObjectURL = exports.FormatError = exports.XRefParseException = exports.XRefEntryException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PermissionFlag = exports.PasswordResponses = exports.PasswordException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = void 0;
 
 __w_pdfjs_require__(2);
 
 var _streams_polyfill = __w_pdfjs_require__(4);
 
 var _url_polyfill = __w_pdfjs_require__(6);
 
 const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
@@ -690,16 +690,29 @@ var MissingDataException = function Miss
   MissingDataException.prototype = new Error();
   MissingDataException.prototype.name = 'MissingDataException';
   MissingDataException.constructor = MissingDataException;
   return MissingDataException;
 }();
 
 exports.MissingDataException = MissingDataException;
 
+const XRefEntryException = function XRefEntryExceptionClosure() {
+  function XRefEntryException(msg) {
+    this.message = msg;
+  }
+
+  XRefEntryException.prototype = new Error();
+  XRefEntryException.prototype.name = 'XRefEntryException';
+  XRefEntryException.constructor = XRefEntryException;
+  return XRefEntryException;
+}();
+
+exports.XRefEntryException = XRefEntryException;
+
 var XRefParseException = function XRefParseExceptionClosure() {
   function XRefParseException(msg) {
     this.message = msg;
   }
 
   XRefParseException.prototype = new Error();
   XRefParseException.prototype.name = 'XRefParseException';
   XRefParseException.constructor = XRefParseException;
@@ -5136,17 +5149,17 @@ function _fetchDocument(worker, source, 
 
   if (pdfDataRangeTransport) {
     source.length = pdfDataRangeTransport.length;
     source.initialData = pdfDataRangeTransport.initialData;
   }
 
   return worker.messageHandler.sendWithPromise('GetDocRequest', {
     docId,
-    apiVersion: '2.1.132',
+    apiVersion: '2.1.145',
     source: {
       data: source.data,
       url: source.url,
       password: source.password,
       disableAutoFetch: source.disableAutoFetch,
       rangeChunkSize: source.rangeChunkSize,
       length: source.length
     },
@@ -6867,19 +6880,19 @@ const InternalRenderTask = function Inte
       }
     }
 
   }
 
   return InternalRenderTask;
 }();
 
-const version = '2.1.132';
+const version = '2.1.145';
 exports.version = version;
-const build = 'd3868e1b';
+const build = 'd8f201ea';
 exports.build = build;
 
 /***/ }),
 /* 8 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
@@ -8779,21 +8792,20 @@ var CanvasGraphics = function CanvasGrap
 
       if (fontObj.isType3Font) {
         return;
       }
 
       var name = fontObj.loadedName || 'sans-serif';
       var bold = fontObj.black ? '900' : fontObj.bold ? 'bold' : 'normal';
       var italic = fontObj.italic ? 'italic' : 'normal';
-      var typeface = '"' + name + '", ' + fontObj.fallbackName;
+      var typeface = `"${name}", ${fontObj.fallbackName}`;
       var browserFontSize = size < MIN_FONT_SIZE ? MIN_FONT_SIZE : size > MAX_FONT_SIZE ? MAX_FONT_SIZE : size;
       this.current.fontSizeScale = size / browserFontSize;
-      var rule = italic + ' ' + bold + ' ' + browserFontSize + 'px ' + typeface;
-      this.ctx.font = rule;
+      this.ctx.font = `${italic} ${bold} ${browserFontSize}px ${typeface}`;
     },
     setTextRenderingMode: function CanvasGraphics_setTextRenderingMode(mode) {
       this.current.textRenderingMode = mode;
     },
     setTextRise: function CanvasGraphics_setTextRise(rise) {
       this.current.textRise = rise;
     },
     moveText: function CanvasGraphics_moveText(x, y) {
@@ -12339,24 +12351,24 @@ var renderTextLayer = function renderTex
       }
 
       let width = this._layoutTextCtx.measureText(textDiv.textContent).width;
 
       let transform = '';
 
       if (textDivProperties.canvasWidth !== 0 && width > 0) {
         textDivProperties.scale = textDivProperties.canvasWidth / width;
-        transform = 'scaleX(' + textDivProperties.scale + ')';
+        transform = `scaleX(${textDivProperties.scale})`;
       }
 
       if (textDivProperties.angle !== 0) {
-        transform = 'rotate(' + textDivProperties.angle + 'deg) ' + transform;
-      }
-
-      if (transform !== '') {
+        transform = `rotate(${textDivProperties.angle}deg) ${transform}`;
+      }
+
+      if (transform.length > 0) {
         textDivProperties.originalTransform = transform;
         textDiv.style.transform = transform;
       }
 
       this._textDivProperties.set(textDiv, textDivProperties);
 
       textLayerFrag.appendChild(textDiv);
     },
--- 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";
 
 
-var pdfjsVersion = '2.1.132';
-var pdfjsBuild = 'd3868e1b';
+var pdfjsVersion = '2.1.145';
+var pdfjsBuild = 'd8f201ea';
 
 var pdfjsCoreWorker = __w_pdfjs_require__(1);
 
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 1 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
@@ -370,17 +370,17 @@ var WorkerMessageHandler = {
   },
 
   createDocumentHandler(docParams, port) {
     var pdfManager;
     var terminated = false;
     var cancelXHRs = null;
     var WorkerTasks = [];
     let apiVersion = docParams.apiVersion;
-    let workerVersion = '2.1.132';
+    let workerVersion = '2.1.145';
 
     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';
@@ -398,38 +398,30 @@ var WorkerMessageHandler = {
     }
 
     function finishWorkerTask(task) {
       task.finish();
       var i = WorkerTasks.indexOf(task);
       WorkerTasks.splice(i, 1);
     }
 
-    function loadDocument(recoveryMode) {
-      var loadDocumentCapability = (0, _util.createPromiseCapability)();
-
-      var parseSuccess = function parseSuccess() {
-        Promise.all([pdfManager.ensureDoc('numPages'), pdfManager.ensureDoc('fingerprint')]).then(function ([numPages, fingerprint]) {
-          loadDocumentCapability.resolve({
-            numPages,
-            fingerprint
-          });
-        }, parseFailure);
-      };
-
-      var parseFailure = function parseFailure(e) {
-        loadDocumentCapability.reject(e);
-      };
-
-      pdfManager.ensureDoc('checkHeader', []).then(function () {
-        pdfManager.ensureDoc('parseStartXRef', []).then(function () {
-          pdfManager.ensureDoc('parse', [recoveryMode]).then(parseSuccess, parseFailure);
-        }, parseFailure);
-      }, parseFailure);
-      return loadDocumentCapability.promise;
+    async function loadDocument(recoveryMode) {
+      await pdfManager.ensureDoc('checkHeader');
+      await pdfManager.ensureDoc('parseStartXRef');
+      await pdfManager.ensureDoc('parse', [recoveryMode]);
+
+      if (!recoveryMode) {
+        await pdfManager.ensureDoc('checkFirstPage');
+      }
+
+      const [numPages, fingerprint] = await Promise.all([pdfManager.ensureDoc('numPages'), pdfManager.ensureDoc('fingerprint')]);
+      return {
+        numPages,
+        fingerprint
+      };
     }
 
     function getPdfManager(data, evaluatorOptions) {
       var pdfManagerCapability = (0, _util.createPromiseCapability)();
       var pdfManager;
       var source = data.source;
 
       if (source.data) {
@@ -875,17 +867,17 @@ Object.defineProperty(exports, "Readable
   }
 });
 Object.defineProperty(exports, "URL", {
   enumerable: true,
   get: function () {
     return _url_polyfill.URL;
   }
 });
-exports.createObjectURL = exports.FormatError = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PermissionFlag = exports.PasswordResponses = exports.PasswordException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = void 0;
+exports.createObjectURL = exports.FormatError = exports.XRefParseException = exports.XRefEntryException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PermissionFlag = exports.PasswordResponses = exports.PasswordException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = void 0;
 
 __w_pdfjs_require__(3);
 
 var _streams_polyfill = __w_pdfjs_require__(5);
 
 var _url_polyfill = __w_pdfjs_require__(7);
 
 const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
@@ -1335,16 +1327,29 @@ var MissingDataException = function Miss
   MissingDataException.prototype = new Error();
   MissingDataException.prototype.name = 'MissingDataException';
   MissingDataException.constructor = MissingDataException;
   return MissingDataException;
 }();
 
 exports.MissingDataException = MissingDataException;
 
+const XRefEntryException = function XRefEntryExceptionClosure() {
+  function XRefEntryException(msg) {
+    this.message = msg;
+  }
+
+  XRefEntryException.prototype = new Error();
+  XRefEntryException.prototype.name = 'XRefEntryException';
+  XRefEntryException.constructor = XRefEntryException;
+  return XRefEntryException;
+}();
+
+exports.XRefEntryException = XRefEntryException;
+
 var XRefParseException = function XRefParseExceptionClosure() {
   function XRefParseException(msg) {
     this.message = msg;
   }
 
   XRefParseException.prototype = new Error();
   XRefParseException.prototype.name = 'XRefParseException';
   XRefParseException.constructor = XRefParseException;
@@ -6367,25 +6372,25 @@ var _crypto = __w_pdfjs_require__(24);
 var _parser = __w_pdfjs_require__(13);
 
 var _operator_list = __w_pdfjs_require__(27);
 
 var _evaluator = __w_pdfjs_require__(28);
 
 var _function = __w_pdfjs_require__(42);
 
-var Page = function PageClosure() {
-  var DEFAULT_USER_UNIT = 1.0;
-  var LETTER_SIZE_MEDIABOX = [0, 0, 612, 792];
-
-  function isAnnotationRenderable(annotation, intent) {
-    return intent === 'display' && annotation.viewable || intent === 'print' && annotation.printable;
-  }
-
-  function Page({
+const DEFAULT_USER_UNIT = 1.0;
+const LETTER_SIZE_MEDIABOX = [0, 0, 612, 792];
+
+function isAnnotationRenderable(annotation, intent) {
+  return intent === 'display' && annotation.viewable || intent === 'print' && annotation.printable;
+}
+
+class Page {
+  constructor({
     pdfManager,
     xref,
     pageIndex,
     pageDict,
     ref,
     fontCache,
     builtInCMapCache,
     pdfFunctionFactory
@@ -6395,626 +6400,628 @@ var Page = function PageClosure() {
     this.pageDict = pageDict;
     this.xref = xref;
     this.ref = ref;
     this.fontCache = fontCache;
     this.builtInCMapCache = builtInCMapCache;
     this.pdfFunctionFactory = pdfFunctionFactory;
     this.evaluatorOptions = pdfManager.evaluatorOptions;
     this.resourcesPromise = null;
-    var uniquePrefix = 'p' + this.pageIndex + '_';
-    var idCounters = {
+    const uniquePrefix = `p${this.pageIndex}_`;
+    const idCounters = {
       obj: 0
     };
     this.idFactory = {
       createObjId() {
         return uniquePrefix + ++idCounters.obj;
       }
 
     };
   }
 
-  Page.prototype = {
-    _getInheritableProperty(key, getArray = false) {
-      let value = (0, _util.getInheritableProperty)({
-        dict: this.pageDict,
-        key,
-        getArray,
-        stopWhenFound: false
-      });
-
-      if (!Array.isArray(value)) {
-        return value;
-      }
-
-      if (value.length === 1 || !(0, _primitives.isDict)(value[0])) {
-        return value[0];
-      }
-
-      return _primitives.Dict.merge(this.xref, value);
-    },
-
-    get content() {
-      return this.pageDict.get('Contents');
-    },
-
-    get resources() {
-      return (0, _util.shadow)(this, 'resources', this._getInheritableProperty('Resources') || _primitives.Dict.empty);
-    },
-
-    get mediaBox() {
-      var mediaBox = this._getInheritableProperty('MediaBox', true);
-
-      if (!Array.isArray(mediaBox) || mediaBox.length !== 4) {
-        return (0, _util.shadow)(this, 'mediaBox', LETTER_SIZE_MEDIABOX);
-      }
-
-      return (0, _util.shadow)(this, 'mediaBox', mediaBox);
-    },
-
-    get cropBox() {
-      var cropBox = this._getInheritableProperty('CropBox', true);
-
-      if (!Array.isArray(cropBox) || cropBox.length !== 4) {
-        return (0, _util.shadow)(this, 'cropBox', this.mediaBox);
-      }
-
-      return (0, _util.shadow)(this, 'cropBox', cropBox);
-    },
-
-    get userUnit() {
-      var obj = this.pageDict.get('UserUnit');
-
-      if (!(0, _util.isNum)(obj) || obj <= 0) {
-        obj = DEFAULT_USER_UNIT;
-      }
-
-      return (0, _util.shadow)(this, 'userUnit', obj);
-    },
-
-    get view() {
-      var mediaBox = this.mediaBox,
+  _getInheritableProperty(key, getArray = false) {
+    const value = (0, _util.getInheritableProperty)({
+      dict: this.pageDict,
+      key,
+      getArray,
+      stopWhenFound: false
+    });
+
+    if (!Array.isArray(value)) {
+      return value;
+    }
+
+    if (value.length === 1 || !(0, _primitives.isDict)(value[0])) {
+      return value[0];
+    }
+
+    return _primitives.Dict.merge(this.xref, value);
+  }
+
+  get content() {
+    return this.pageDict.get('Contents');
+  }
+
+  get resources() {
+    return (0, _util.shadow)(this, 'resources', this._getInheritableProperty('Resources') || _primitives.Dict.empty);
+  }
+
+  get mediaBox() {
+    const mediaBox = this._getInheritableProperty('MediaBox', true);
+
+    if (!Array.isArray(mediaBox) || mediaBox.length !== 4) {
+      return (0, _util.shadow)(this, 'mediaBox', LETTER_SIZE_MEDIABOX);
+    }
+
+    return (0, _util.shadow)(this, 'mediaBox', mediaBox);
+  }
+
+  get cropBox() {
+    const cropBox = this._getInheritableProperty('CropBox', true);
+
+    if (!Array.isArray(cropBox) || cropBox.length !== 4) {
+      return (0, _util.shadow)(this, 'cropBox', this.mediaBox);
+    }
+
+    return (0, _util.shadow)(this, 'cropBox', cropBox);
+  }
+
+  get userUnit() {
+    let obj = this.pageDict.get('UserUnit');
+
+    if (!(0, _util.isNum)(obj) || obj <= 0) {
+      obj = DEFAULT_USER_UNIT;
+    }
+
+    return (0, _util.shadow)(this, 'userUnit', obj);
+  }
+
+  get view() {
+    const mediaBox = this.mediaBox,
           cropBox = this.cropBox;
 
-      if (mediaBox === cropBox) {
-        return (0, _util.shadow)(this, 'view', mediaBox);
-      }
-
-      var intersection = _util.Util.intersect(cropBox, mediaBox);
-
-      return (0, _util.shadow)(this, 'view', intersection || mediaBox);
-    },
-
-    get rotate() {
-      var rotate = this._getInheritableProperty('Rotate') || 0;
-
-      if (rotate % 90 !== 0) {
-        rotate = 0;
-      } else if (rotate >= 360) {
-        rotate = rotate % 360;
-      } else if (rotate < 0) {
-        rotate = (rotate % 360 + 360) % 360;
-      }
-
-      return (0, _util.shadow)(this, 'rotate', rotate);
-    },
-
-    getContentStream: function Page_getContentStream() {
-      var content = this.content;
-      var stream;
-
-      if (Array.isArray(content)) {
-        var xref = this.xref;
-        var i,
-            n = content.length;
-        var streams = [];
-
-        for (i = 0; i < n; ++i) {
-          streams.push(xref.fetchIfRef(content[i]));
-        }
-
-        stream = new _stream.StreamsSequenceStream(streams);
-      } else if ((0, _primitives.isStream)(content)) {
-        stream = content;
-      } else {
-        stream = new _stream.NullStream();
-      }
-
-      return stream;
-    },
-    loadResources: function Page_loadResources(keys) {
-      if (!this.resourcesPromise) {
-        this.resourcesPromise = this.pdfManager.ensure(this, 'resources');
-      }
-
-      return this.resourcesPromise.then(() => {
-        let objectLoader = new _obj.ObjectLoader(this.resources, keys, this.xref);
-        return objectLoader.load();
-      });
-    },
-
-    getOperatorList({
+    if (mediaBox === cropBox) {
+      return (0, _util.shadow)(this, 'view', mediaBox);
+    }
+
+    const intersection = _util.Util.intersect(cropBox, mediaBox);
+
+    return (0, _util.shadow)(this, 'view', intersection || mediaBox);
+  }
+
+  get rotate() {
+    let rotate = this._getInheritableProperty('Rotate') || 0;
+
+    if (rotate % 90 !== 0) {
+      rotate = 0;
+    } else if (rotate >= 360) {
+      rotate = rotate % 360;
+    } else if (rotate < 0) {
+      rotate = (rotate % 360 + 360) % 360;
+    }
+
+    return (0, _util.shadow)(this, 'rotate', rotate);
+  }
+
+  getContentStream() {
+    const content = this.content;
+    let stream;
+
+    if (Array.isArray(content)) {
+      const xref = this.xref;
+      const streams = [];
+
+      for (const stream of content) {
+        streams.push(xref.fetchIfRef(stream));
+      }
+
+      stream = new _stream.StreamsSequenceStream(streams);
+    } else if ((0, _primitives.isStream)(content)) {
+      stream = content;
+    } else {
+      stream = new _stream.NullStream();
+    }
+
+    return stream;
+  }
+
+  loadResources(keys) {
+    if (!this.resourcesPromise) {
+      this.resourcesPromise = this.pdfManager.ensure(this, 'resources');
+    }
+
+    return this.resourcesPromise.then(() => {
+      const objectLoader = new _obj.ObjectLoader(this.resources, keys, this.xref);
+      return objectLoader.load();
+    });
+  }
+
+  getOperatorList({
+    handler,
+    task,
+    intent,
+    renderInteractiveForms
+  }) {
+    const contentStreamPromise = this.pdfManager.ensure(this, 'getContentStream');
+    const resourcesPromise = this.loadResources(['ExtGState', 'ColorSpace', 'Pattern', 'Shading', 'XObject', 'Font']);
+    const partialEvaluator = new _evaluator.PartialEvaluator({
+      pdfManager: this.pdfManager,
+      xref: this.xref,
       handler,
-      task,
-      intent,
-      renderInteractiveForms
-    }) {
-      var contentStreamPromise = this.pdfManager.ensure(this, 'getContentStream');
-      var resourcesPromise = this.loadResources(['ExtGState', 'ColorSpace', 'Pattern', 'Shading', 'XObject', 'Font']);
-      var partialEvaluator = new _evaluator.PartialEvaluator({
+      pageIndex: this.pageIndex,
+      idFactory: this.idFactory,
+      fontCache: this.fontCache,
+      builtInCMapCache: this.builtInCMapCache,
+      options: this.evaluatorOptions,
+      pdfFunctionFactory: this.pdfFunctionFactory
+    });
+    const dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
+    const pageListPromise = dataPromises.then(([contentStream]) => {
+      const opList = new _operator_list.OperatorList(intent, handler, this.pageIndex);
+      handler.send('StartRenderPage', {
+        transparency: partialEvaluator.hasBlendModes(this.resources),
+        pageIndex: this.pageIndex,
+        intent
+      });
+      return partialEvaluator.getOperatorList({
+        stream: contentStream,
+        task,
+        resources: this.resources,
+        operatorList: opList
+      }).then(function () {
+        return opList;
+      });
+    });
+    return Promise.all([pageListPromise, this._parsedAnnotations]).then(function ([pageOpList, annotations]) {
+      if (annotations.length === 0) {
+        pageOpList.flush(true);
+        return pageOpList;
+      }
+
+      const opListPromises = [];
+
+      for (const annotation of annotations) {
+        if (isAnnotationRenderable(annotation, intent)) {
+          opListPromises.push(annotation.getOperatorList(partialEvaluator, task, renderInteractiveForms));
+        }
+      }
+
+      return Promise.all(opListPromises).then(function (opLists) {
+        pageOpList.addOp(_util.OPS.beginAnnotations, []);
+
+        for (const opList of opLists) {
+          pageOpList.addOpList(opList);
+        }
+
+        pageOpList.addOp(_util.OPS.endAnnotations, []);
+        pageOpList.flush(true);
+        return pageOpList;
+      });
+    });
+  }
+
+  extractTextContent({
+    handler,
+    task,
+    normalizeWhitespace,
+    sink,
+    combineTextItems
+  }) {
+    const contentStreamPromise = this.pdfManager.ensure(this, 'getContentStream');
+    const resourcesPromise = this.loadResources(['ExtGState', 'XObject', 'Font']);
+    const dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
+    return dataPromises.then(([contentStream]) => {
+      const partialEvaluator = new _evaluator.PartialEvaluator({
         pdfManager: this.pdfManager,
         xref: this.xref,
         handler,
         pageIndex: this.pageIndex,
         idFactory: this.idFactory,
         fontCache: this.fontCache,
         builtInCMapCache: this.builtInCMapCache,
         options: this.evaluatorOptions,
         pdfFunctionFactory: this.pdfFunctionFactory
       });
-      var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
-      var pageListPromise = dataPromises.then(([contentStream]) => {
-        var opList = new _operator_list.OperatorList(intent, handler, this.pageIndex);
-        handler.send('StartRenderPage', {
-          transparency: partialEvaluator.hasBlendModes(this.resources),
-          pageIndex: this.pageIndex,
-          intent
-        });
-        return partialEvaluator.getOperatorList({
-          stream: contentStream,
-          task,
-          resources: this.resources,
-          operatorList: opList
-        }).then(function () {
-          return opList;
-        });
-      });
-      return Promise.all([pageListPromise, this._parsedAnnotations]).then(function ([pageOpList, annotations]) {
-        if (annotations.length === 0) {
-          pageOpList.flush(true);
-          return pageOpList;
-        }
-
-        var i,
-            ii,
-            opListPromises = [];
-
-        for (i = 0, ii = annotations.length; i < ii; i++) {
-          if (isAnnotationRenderable(annotations[i], intent)) {
-            opListPromises.push(annotations[i].getOperatorList(partialEvaluator, task, renderInteractiveForms));
-          }
-        }
-
-        return Promise.all(opListPromises).then(function (opLists) {
-          pageOpList.addOp(_util.OPS.beginAnnotations, []);
-
-          for (i = 0, ii = opLists.length; i < ii; i++) {
-            pageOpList.addOpList(opLists[i]);
-          }
-
-          pageOpList.addOp(_util.OPS.endAnnotations, []);
-          pageOpList.flush(true);
-          return pageOpList;
-        });
-      });
-    },
-
-    extractTextContent({
-      handler,
-      task,
-      normalizeWhitespace,
-      sink,
-      combineTextItems
-    }) {
-      var contentStreamPromise = this.pdfManager.ensure(this, 'getContentStream');
-      var resourcesPromise = this.loadResources(['ExtGState', 'XObject', 'Font']);
-      var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
-      return dataPromises.then(([contentStream]) => {
-        var partialEvaluator = new _evaluator.PartialEvaluator({
-          pdfManager: this.pdfManager,
-          xref: this.xref,
-          handler,
-          pageIndex: this.pageIndex,
-          idFactory: this.idFactory,
-          fontCache: this.fontCache,
-          builtInCMapCache: this.builtInCMapCache,
-          options: this.evaluatorOptions,
-          pdfFunctionFactory: this.pdfFunctionFactory
-        });
-        return partialEvaluator.getTextContent({
-          stream: contentStream,
-          task,
-          resources: this.resources,
-          normalizeWhitespace,
-          combineTextItems,
-          sink
-        });
-      });
-    },
-
-    getAnnotationsData(intent) {
-      return this._parsedAnnotations.then(function (annotations) {
-        let annotationsData = [];
-
-        for (let i = 0, ii = annotations.length; i < ii; i++) {
-          if (!intent || isAnnotationRenderable(annotations[i], intent)) {
-            annotationsData.push(annotations[i].data);
-          }
-        }
-
-        return annotationsData;
-      });
-    },
-
-    get annotations() {
-      return (0, _util.shadow)(this, 'annotations', this._getInheritableProperty('Annots') || []);
-    },
-
-    get _parsedAnnotations() {
-      const parsedAnnotations = this.pdfManager.ensure(this, 'annotations').then(() => {
-        const annotationRefs = this.annotations;
-        const annotationPromises = [];
-
-        for (let i = 0, ii = annotationRefs.length; i < ii; i++) {
-          annotationPromises.push(_annotation.AnnotationFactory.create(this.xref, annotationRefs[i], this.pdfManager, this.idFactory));
-        }
-
-        return Promise.all(annotationPromises).then(function (annotations) {
-          return annotations.filter(function isDefined(annotation) {
-            return !!annotation;
-          });
-        }, function (reason) {
-          (0, _util.warn)(`_parsedAnnotations: "${reason}".`);
-          return [];
-        });
-      });
-      return (0, _util.shadow)(this, '_parsedAnnotations', parsedAnnotations);
-    }
-
-  };
-  return Page;
-}();
+      return partialEvaluator.getTextContent({
+        stream: contentStream,
+        task,
+        resources: this.resources,
+        normalizeWhitespace,
+        combineTextItems,
+        sink
+      });
+    });
+  }
+
+  getAnnotationsData(intent) {
+    return this._parsedAnnotations.then(function (annotations) {
+      const annotationsData = [];
+
+      for (let i = 0, ii = annotations.length; i < ii; i++) {
+        if (!intent || isAnnotationRenderable(annotations[i], intent)) {
+          annotationsData.push(annotations[i].data);
+        }
+      }
+
+      return annotationsData;
+    });
+  }
+
+  get annotations() {
+    return (0, _util.shadow)(this, 'annotations', this._getInheritableProperty('Annots') || []);
+  }
+
+  get _parsedAnnotations() {
+    const parsedAnnotations = this.pdfManager.ensure(this, 'annotations').then(() => {
+      const annotationRefs = this.annotations;
+      const annotationPromises = [];
+
+      for (let i = 0, ii = annotationRefs.length; i < ii; i++) {
+        annotationPromises.push(_annotation.AnnotationFactory.create(this.xref, annotationRefs[i], this.pdfManager, this.idFactory));
+      }
+
+      return Promise.all(annotationPromises).then(function (annotations) {
+        return annotations.filter(function isDefined(annotation) {
+          return !!annotation;
+        });
+      }, function (reason) {
+        (0, _util.warn)(`_parsedAnnotations: "${reason}".`);
+        return [];
+      });
+    });
+    return (0, _util.shadow)(this, '_parsedAnnotations', parsedAnnotations);
+  }
+
+}
 
 exports.Page = Page;
-
-var PDFDocument = function PDFDocumentClosure() {
-  var FINGERPRINT_FIRST_BYTES = 1024;
-  var EMPTY_FINGERPRINT = '\x00\x00\x00\x00\x00\x00\x00' + '\x00\x00\x00\x00\x00\x00\x00\x00\x00';
-
-  function PDFDocument(pdfManager, arg) {
-    var stream;
+const FINGERPRINT_FIRST_BYTES = 1024;
+const EMPTY_FINGERPRINT = '\x00\x00\x00\x00\x00\x00\x00' + '\x00\x00\x00\x00\x00\x00\x00\x00\x00';
+
+function find(stream, needle, limit, backwards) {
+  const pos = stream.pos;
+  const end = stream.end;
+
+  if (pos + limit > end) {
+    limit = end - pos;
+  }
+
+  const strBuf = [];
+
+  for (let i = 0; i < limit; ++i) {
+    strBuf.push(String.fromCharCode(stream.getByte()));
+  }
+
+  const str = strBuf.join('');
+  stream.pos = pos;
+  const index = backwards ? str.lastIndexOf(needle) : str.indexOf(needle);
+
+  if (index === -1) {
+    return false;
+  }
+
+  stream.pos += index;
+  return true;
+}
+
+class PDFDocument {
+  constructor(pdfManager, arg) {
+    let stream;
 
     if ((0, _primitives.isStream)(arg)) {
       stream = arg;
     } else if ((0, _util.isArrayBuffer)(arg)) {
       stream = new _stream.Stream(arg);
     } else {
       throw new Error('PDFDocument: Unknown argument type');
     }
 
     if (stream.length <= 0) {
-      throw new Error('PDFDocument: stream must have data');
+      throw new Error('PDFDocument: Stream must have data');
     }
 
     this.pdfManager = pdfManager;
     this.stream = stream;
     this.xref = new _obj.XRef(stream, pdfManager);
-    let evaluatorOptions = pdfManager.evaluatorOptions;
     this.pdfFunctionFactory = new _function.PDFFunctionFactory({
       xref: this.xref,
-      isEvalSupported: evaluatorOptions.isEvalSupported
+      isEvalSupported: pdfManager.evaluatorOptions.isEvalSupported
     });
     this._pagePromises = [];
   }
 
-  function find(stream, needle, limit, backwards) {
-    var pos = stream.pos;
-    var end = stream.end;
-    var strBuf = [];
-
-    if (pos + limit > end) {
-      limit = end - pos;
-    }
-
-    for (var n = 0; n < limit; ++n) {
-      strBuf.push(String.fromCharCode(stream.getByte()));
-    }
-
-    var str = strBuf.join('');
-    stream.pos = pos;
-    var index = backwards ? str.lastIndexOf(needle) : str.indexOf(needle);
-
-    if (index === -1) {
-      return false;
-    }
-
-    stream.pos += index;
-    return true;
-  }
-
-  const DocumentInfoValidators = {
-    Title: _util.isString,
-    Author: _util.isString,
-    Subject: _util.isString,
-    Keywords: _util.isString,
-    Creator: _util.isString,
-    Producer: _util.isString,
-    CreationDate: _util.isString,
-    ModDate: _util.isString,
-    Trapped: _primitives.isName
-  };
-  PDFDocument.prototype = {
-    parse: function PDFDocument_parse(recoveryMode) {
-      this.setup(recoveryMode);
-      var version = this.catalog.catDict.get('Version');
-
-      if ((0, _primitives.isName)(version)) {
-        this.pdfFormatVersion = version.name;
-      }
-
-      try {
-        this.acroForm = this.catalog.catDict.get('AcroForm');
-
-        if (this.acroForm) {
-          this.xfa = this.acroForm.get('XFA');
-          var fields = this.acroForm.get('Fields');
-
-          if ((!fields || !Array.isArray(fields) || fields.length === 0) && !this.xfa) {
-            this.acroForm = null;
-          }
-        }
-      } catch (ex) {
-        if (ex instanceof _util.MissingDataException) {
-          throw ex;
-        }
-
-        (0, _util.info)('Something wrong with AcroForm entry');
-        this.acroForm = null;
-      }
-    },
-
-    get linearization() {
-      let linearization = null;
-
-      try {
-        linearization = _parser.Linearization.create(this.stream);
-      } catch (err) {
-        if (err instanceof _util.MissingDataException) {
-          throw err;
-        }
-
-        (0, _util.info)(err);
-      }
-
-      return (0, _util.shadow)(this, 'linearization', linearization);
-    },
-
-    get startXRef() {
-      var stream = this.stream;
-      var startXRef = 0;
-      var linearization = this.linearization;
-
-      if (linearization) {
-        stream.reset();
-
-        if (find(stream, 'endobj', 1024)) {
-          startXRef = stream.pos + 6;
-        }
-      } else {
-        var step = 1024;
-        var found = false,
-            pos = stream.end;
-
-        while (!found && pos > 0) {
-          pos -= step - 'startxref'.length;
-
-          if (pos < 0) {
-            pos = 0;
-          }
-
-          stream.pos = pos;
-          found = find(stream, 'startxref', step, true);
-        }
-
-        if (found) {
-          stream.skip(9);
-          var ch;
-
-          do {
-            ch = stream.getByte();
-          } while ((0, _util.isSpace)(ch));
-
-          var str = '';
-
-          while (ch >= 0x20 && ch <= 0x39) {
-            str += String.fromCharCode(ch);
-            ch = stream.getByte();
-          }
-
-          startXRef = parseInt(str, 10);
-
-          if (isNaN(startXRef)) {
-            startXRef = 0;
-          }
-        }
-      }
-
-      return (0, _util.shadow)(this, 'startXRef', startXRef);
-    },
-
-    checkHeader: function PDFDocument_checkHeader() {
-      var stream = this.stream;
+  parse(recoveryMode) {
+    this.setup(recoveryMode);
+    const version = this.catalog.catDict.get('Version');
+
+    if ((0, _primitives.isName)(version)) {
+      this.pdfFormatVersion = version.name;
+    }
+
+    try {
+      this.acroForm = this.catalog.catDict.get('AcroForm');
+
+      if (this.acroForm) {
+        this.xfa = this.acroForm.get('XFA');
+        const fields = this.acroForm.get('Fields');
+
+        if ((!fields || !Array.isArray(fields) || fields.length === 0) && !this.xfa) {
+          this.acroForm = null;
+        }
+      }
+    } catch (ex) {
+      if (ex instanceof _util.MissingDataException) {
+        throw ex;
+      }
+
+      (0, _util.info)('Cannot fetch AcroForm entry; assuming no AcroForms are present');
+      this.acroForm = null;
+    }
+  }
+
+  get linearization() {
+    let linearization = null;
+
+    try {
+      linearization = _parser.Linearization.create(this.stream);
+    } catch (err) {
+      if (err instanceof _util.MissingDataException) {
+        throw err;
+      }
+
+      (0, _util.info)(err);
+    }
+
+    return (0, _util.shadow)(this, 'linearization', linearization);
+  }
+
+  get startXRef() {
+    const stream = this.stream;
+    let startXRef = 0;
+
+    if (this.linearization) {
       stream.reset();
 
-      if (find(stream, '%PDF-', 1024)) {
-        stream.moveStart();
-        var MAX_VERSION_LENGTH = 12;
-        var version = '',
-            ch;
-
-        while ((ch = stream.getByte()) > 0x20) {
-          if (version.length >= MAX_VERSION_LENGTH) {
-            break;
-          }
-
-          version += String.fromCharCode(ch);
-        }
-
-        if (!this.pdfFormatVersion) {
-          this.pdfFormatVersion = version.substring(5);
-        }
-
-        return;
-      }
-    },
-    parseStartXRef: function PDFDocument_parseStartXRef() {
-      var startXRef = this.startXRef;
-      this.xref.setStartXRef(startXRef);
-    },
-    setup: function PDFDocument_setup(recoveryMode) {
-      this.xref.parse(recoveryMode);
-      this.catalog = new _obj.Catalog(this.pdfManager, this.xref);
-    },
-
-    get numPages() {
-      var linearization = this.linearization;
-      var num = linearization ? linearization.numPages : this.catalog.numPages;
-      return (0, _util.shadow)(this, 'numPages', num);
-    },
-
-    get documentInfo() {
-      const docInfo = {
-        PDFFormatVersion: this.pdfFormatVersion,
-        IsLinearized: !!this.linearization,
-        IsAcroFormPresent: !!this.acroForm,
-        IsXFAPresent: !!this.xfa
-      };
-      let infoDict;
-
-      try {
-        infoDict = this.xref.trailer.get('Info');
-      } catch (err) {
-        if (err instanceof _util.MissingDataException) {
-          throw err;
-        }
-
-        (0, _util.info)('The document information dictionary is invalid.');
-      }
-
-      if ((0, _primitives.isDict)(infoDict)) {
-        for (let key of infoDict.getKeys()) {
-          const value = infoDict.get(key);
-
-          if (DocumentInfoValidators[key]) {
-            if (DocumentInfoValidators[key](value)) {
-              docInfo[key] = typeof value !== 'string' ? value : (0, _util.stringToPDFString)(value);
-            } else {
-              (0, _util.info)(`Bad value in document info for "${key}".`);
-            }
-          } else if (typeof key === 'string') {
-            let customValue;
-
-            if ((0, _util.isString)(value)) {
-              customValue = (0, _util.stringToPDFString)(value);
-            } else if ((0, _primitives.isName)(value) || (0, _util.isNum)(value) || (0, _util.isBool)(value)) {
-              customValue = value;
-            } else {
-              (0, _util.info)(`Unsupported value in document info for (custom) "${key}".`);
-              continue;
-            }
-
-            if (!docInfo['Custom']) {
-              docInfo['Custom'] = Object.create(null);
-            }
-
-            docInfo['Custom'][key] = customValue;
-          }
-        }
-      }
-
-      return (0, _util.shadow)(this, 'documentInfo', docInfo);
-    },
-
-    get fingerprint() {
-      var xref = this.xref,
-          hash,
-          fileID = '';
-      var idArray = xref.trailer.get('ID');
-
-      if (Array.isArray(idArray) && idArray[0] && (0, _util.isString)(idArray[0]) && idArray[0] !== EMPTY_FINGERPRINT) {
-        hash = (0, _util.stringToBytes)(idArray[0]);
-      } else {
-        if (this.stream.ensureRange) {
-          this.stream.ensureRange(0, Math.min(FINGERPRINT_FIRST_BYTES, this.stream.end));
-        }
-
-        hash = (0, _crypto.calculateMD5)(this.stream.bytes.subarray(0, FINGERPRINT_FIRST_BYTES), 0, FINGERPRINT_FIRST_BYTES);
-      }
-
-      for (var i = 0, n = hash.length; i < n; i++) {
-        var hex = hash[i].toString(16);
-        fileID += hex.length === 1 ? '0' + hex : hex;
-      }
-
-      return (0, _util.shadow)(this, 'fingerprint', fileID);
-    },
-
-    _getLinearizationPage(pageIndex) {
-      const {
-        catalog,
-        linearization
-      } = this;
-      (0, _util.assert)(linearization && linearization.pageFirst === pageIndex);
-      const ref = new _primitives.Ref(linearization.objectNumberFirst, 0);
-      return this.xref.fetchAsync(ref).then(obj => {
-        if ((0, _primitives.isDict)(obj, 'Page') || (0, _primitives.isDict)(obj) && !obj.has('Type') && obj.has('Contents')) {
-          if (ref && !catalog.pageKidsCountCache.has(ref)) {
-            catalog.pageKidsCountCache.put(ref, 1);
-          }
-
-          return [obj, ref];
-        }
-
-        throw new _util.FormatError('The Linearization dictionary doesn\'t point ' + 'to a valid Page dictionary.');
-      }).catch(reason => {
-        (0, _util.info)(reason);
-        return catalog.getPageDict(pageIndex);
-      });
-    },
-
-    getPage(pageIndex) {
-      if (this._pagePromises[pageIndex] !== undefined) {
-        return this._pagePromises[pageIndex];
-      }
-
-      const {
-        catalog,
-        linearization
-      } = this;
-      const promise = linearization && linearization.pageFirst === pageIndex ? this._getLinearizationPage(pageIndex) : catalog.getPageDict(pageIndex);
-      return this._pagePromises[pageIndex] = promise.then(([pageDict, ref]) => {
-        return new Page({
-          pdfManager: this.pdfManager,
-          xref: this.xref,
-          pageIndex,
-          pageDict,
-          ref,
-          fontCache: catalog.fontCache,
-          builtInCMapCache: catalog.builtInCMapCache,
-          pdfFunctionFactory: this.pdfFunctionFactory
-        });
-      });
-    },
-
-    cleanup: function PDFDocument_cleanup() {
-      return this.catalog.cleanup();
-    }
-  };
-  return PDFDocument;
-}();
+      if (find(stream, 'endobj', 1024)) {
+        startXRef = stream.pos + 6;
+      }
+    } else {
+      const step = 1024;
+      const startXRefLength = 'startxref'.length;
+      let found = false,
+          pos = stream.end;
+
+      while (!found && pos > 0) {
+        pos -= step - startXRefLength;
+
+        if (pos < 0) {
+          pos = 0;
+        }
+
+        stream.pos = pos;
+        found = find(stream, 'startxref', step, true);
+      }
+
+      if (found) {
+        stream.skip(9);
+        let ch;
+
+        do {
+          ch = stream.getByte();
+        } while ((0, _util.isSpace)(ch));
+
+        let str = '';
+
+        while (ch >= 0x20 && ch <= 0x39) {
+          str += String.fromCharCode(ch);
+          ch = stream.getByte();
+        }
+
+        startXRef = parseInt(str, 10);
+
+        if (isNaN(startXRef)) {
+          startXRef = 0;
+        }
+      }
+    }
+
+    return (0, _util.shadow)(this, 'startXRef', startXRef);
+  }
+
+  checkHeader() {
+    const stream = this.stream;
+    stream.reset();
+
+    if (!find(stream, '%PDF-', 1024)) {
+      return;
+    }
+
+    stream.moveStart();
+    const MAX_PDF_VERSION_LENGTH = 12;
+    let version = '',
+        ch;
+
+    while ((ch = stream.getByte()) > 0x20) {
+      if (version.length >= MAX_PDF_VERSION_LENGTH) {
+        break;
+      }
+
+      version += String.fromCharCode(ch);
+    }
+
+    if (!this.pdfFormatVersion) {
+      this.pdfFormatVersion = version.substring(5);
+    }
+  }
+
+  parseStartXRef() {
+    this.xref.setStartXRef(this.startXRef);
+  }
+
+  setup(recoveryMode) {
+    this.xref.parse(recoveryMode);
+    this.catalog = new _obj.Catalog(this.pdfManager, this.xref);
+  }
+
+  get numPages() {
+    const linearization = this.linearization;
+    const num = linearization ? linearization.numPages : this.catalog.numPages;
+    return (0, _util.shadow)(this, 'numPages', num);
+  }
+
+  get documentInfo() {
+    const DocumentInfoValidators = {
+      Title: _util.isString,
+      Author: _util.isString,
+      Subject: _util.isString,
+      Keywords: _util.isString,
+      Creator: _util.isString,
+      Producer: _util.isString,
+      CreationDate: _util.isString,
+      ModDate: _util.isString,
+      Trapped: _primitives.isName
+    };
+    const docInfo = {
+      PDFFormatVersion: this.pdfFormatVersion,
+      IsLinearized: !!this.linearization,
+      IsAcroFormPresent: !!this.acroForm,
+      IsXFAPresent: !!this.xfa
+    };
+    let infoDict;
+
+    try {
+      infoDict = this.xref.trailer.get('Info');
+    } catch (err) {
+      if (err instanceof _util.MissingDataException) {
+        throw err;
+      }
+
+      (0, _util.info)('The document information dictionary is invalid.');
+    }
+
+    if ((0, _primitives.isDict)(infoDict)) {
+      for (const key of infoDict.getKeys()) {
+        const value = infoDict.get(key);
+
+        if (DocumentInfoValidators[key]) {
+          if (DocumentInfoValidators[key](value)) {
+            docInfo[key] = typeof value !== 'string' ? value : (0, _util.stringToPDFString)(value);
+          } else {
+            (0, _util.info)(`Bad value in document info for "${key}".`);
+          }
+        } else if (typeof key === 'string') {
+          let customValue;
+
+          if ((0, _util.isString)(value)) {
+            customValue = (0, _util.stringToPDFString)(value);
+          } else if ((0, _primitives.isName)(value) || (0, _util.isNum)(value) || (0, _util.isBool)(value)) {
+            customValue = value;
+          } else {
+            (0, _util.info)(`Unsupported value in document info for (custom) "${key}".`);
+            continue;
+          }
+
+          if (!docInfo['Custom']) {
+            docInfo['Custom'] = Object.create(null);
+          }
+
+          docInfo['Custom'][key] = customValue;
+        }
+      }
+    }
+
+    return (0, _util.shadow)(this, 'documentInfo', docInfo);
+  }
+
+  get fingerprint() {
+    let hash;
+    const idArray = this.xref.trailer.get('ID');
+
+    if (Array.isArray(idArray) && idArray[0] && (0, _util.isString)(idArray[0]) && idArray[0] !== EMPTY_FINGERPRINT) {
+      hash = (0, _util.stringToBytes)(idArray[0]);
+    } else {
+      if (this.stream.ensureRange) {
+        this.stream.ensureRange(0, Math.min(FINGERPRINT_FIRST_BYTES, this.stream.end));
+      }
+
+      hash = (0, _crypto.calculateMD5)(this.stream.bytes.subarray(0, FINGERPRINT_FIRST_BYTES), 0, FINGERPRINT_FIRST_BYTES);
+    }
+
+    let fingerprint = '';
+
+    for (const hashPart of hash) {
+      const hex = hashPart.toString(16);
+      fingerprint += hex.length === 1 ? '0' + hex : hex;
+    }
+
+    return (0, _util.shadow)(this, 'fingerprint', fingerprint);
+  }
+
+  _getLinearizationPage(pageIndex) {
+    const {
+      catalog,
+      linearization
+    } = this;
+    (0, _util.assert)(linearization && linearization.pageFirst === pageIndex);
+    const ref = new _primitives.Ref(linearization.objectNumberFirst, 0);
+    return this.xref.fetchAsync(ref).then(obj => {
+      if ((0, _primitives.isDict)(obj, 'Page') || (0, _primitives.isDict)(obj) && !obj.has('Type') && obj.has('Contents')) {
+        if (ref && !catalog.pageKidsCountCache.has(ref)) {
+          catalog.pageKidsCountCache.put(ref, 1);
+        }
+
+        return [obj, ref];
+      }
+
+      throw new _util.FormatError('The Linearization dictionary doesn\'t point ' + 'to a valid Page dictionary.');
+    }).catch(reason => {
+      (0, _util.info)(reason);
+      return catalog.getPageDict(pageIndex);
+    });
+  }
+
+  getPage(pageIndex) {
+    if (this._pagePromises[pageIndex] !== undefined) {
+      return this._pagePromises[pageIndex];
+    }
+
+    const {
+      catalog,
+      linearization
+    } = this;
+    const promise = linearization && linearization.pageFirst === pageIndex ? this._getLinearizationPage(pageIndex) : catalog.getPageDict(pageIndex);
+    return this._pagePromises[pageIndex] = promise.then(([pageDict, ref]) => {
+      return new Page({
+        pdfManager: this.pdfManager,
+        xref: this.xref,
+        pageIndex,
+        pageDict,
+        ref,
+        fontCache: catalog.fontCache,
+        builtInCMapCache: catalog.builtInCMapCache,
+        pdfFunctionFactory: this.pdfFunctionFactory
+      });
+    });
+  }
+
+  checkFirstPage() {
+    return this.getPage(0).catch(reason => {
+      if (reason instanceof _util.XRefEntryException) {
+        this._pagePromises.length = 0;
+        this.cleanup();
+        throw new _util.XRefParseException();
+      }
+    });
+  }
+
+  cleanup() {
+    return this.catalog.cleanup();
+  }
+
+}
 
 exports.PDFDocument = PDFDocument;
 
 /***/ }),
 /* 11 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
@@ -8498,33 +8505,34 @@ var XRef = function XRefClosure() {
 
       if (xrefEntry === null) {
         return this.cache[num] = null;
       }
 
       if (xrefEntry.uncompressed) {
         xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption);
       } else {
-        xrefEntry = this.fetchCompressed(xrefEntry, suppressEncryption);
+        xrefEntry = this.fetchCompressed(ref, xrefEntry, suppressEncryption);
       }
 
       if ((0, _primitives.isDict)(xrefEntry)) {
         xrefEntry.objId = ref.toString();
       } else if ((0, _primitives.isStream)(xrefEntry)) {
         xrefEntry.dict.objId = ref.toString();
       }
 
       return xrefEntry;
     },
-    fetchUncompressed: function XRef_fetchUncompressed(ref, xrefEntry, suppressEncryption) {
+
+    fetchUncompressed(ref, xrefEntry, suppressEncryption = false) {
       var gen = ref.gen;
       var num = ref.num;
 
       if (xrefEntry.gen !== gen) {
-        throw new _util.FormatError('inconsistent generation in XRef');
+        throw new _util.XRefEntryException(`Inconsistent generation in XRef: ${ref}`);
       }
 
       var stream = this.stream.makeSubStream(xrefEntry.offset + this.stream.start);
       var parser = new _parser.Parser(new _parser.Lexer(stream), true, this);
       var obj1 = parser.getObj();
       var obj2 = parser.getObj();
       var obj3 = parser.getObj();
 
@@ -8532,44 +8540,45 @@ var XRef = function XRefClosure() {
         obj1 = parseInt(obj1, 10);
       }
 
       if (!Number.isInteger(obj2)) {
         obj2 = parseInt(obj2, 10);
       }
 
       if (obj1 !== num || obj2 !== gen || !(0, _primitives.isCmd)(obj3)) {
-        throw new _util.FormatError('bad XRef entry');
+        throw new _util.XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`);
       }
 
       if (obj3.cmd !== 'obj') {
         if (obj3.cmd.indexOf('obj') === 0) {
           num = parseInt(obj3.cmd.substring(3), 10);
 
           if (!Number.isNaN(num)) {
             return num;
           }
         }
 
-        throw new _util.FormatError('bad XRef entry');
+        throw new _util.XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`);
       }
 
       if (this.encrypt && !suppressEncryption) {
         xrefEntry = parser.getObj(this.encrypt.createCipherTransform(num, gen));
       } else {
         xrefEntry = parser.getObj();
       }
 
       if (!(0, _primitives.isStream)(xrefEntry)) {
         this.cache[num] = xrefEntry;
       }
 
       return xrefEntry;
     },
-    fetchCompressed: function XRef_fetchCompressed(xrefEntry, suppressEncryption) {
+
+    fetchCompressed(ref, xrefEntry, suppressEncryption = false) {
       var tableOffset = xrefEntry.offset;
       var stream = this.fetch(new _primitives.Ref(tableOffset, 0));
 
       if (!(0, _primitives.isStream)(stream)) {
         throw new _util.FormatError('bad ObjStm stream');
       }
 
       var first = stream.dict.get('First');
@@ -8614,17 +8623,17 @@ var XRef = function XRefClosure() {
         if (entry && entry.offset === tableOffset && entry.gen === i) {
           this.cache[num] = entries[i];
         }
       }
 
       xrefEntry = entries[xrefEntry.gen];
 
       if (xrefEntry === undefined) {
-        throw new _util.FormatError('bad XRef entry for compressed object');
+        throw new _util.XRefEntryException(`Bad (compressed) XRef entry: ${ref}`);
       }
 
       return xrefEntry;
     },
 
     async fetchIfRefAsync(obj, suppressEncryption) {
       if (!(0, _primitives.isRef)(obj)) {
         return obj;
@@ -9235,23 +9244,21 @@ exports.Dict = Dict;
 var Ref = function RefClosure() {
   function Ref(num, gen) {
     this.num = num;
     this.gen = gen;
   }
 
   Ref.prototype = {
     toString: function Ref_toString() {
-      var str = this.num + 'R';
-
       if (this.gen !== 0) {
-        str += this.gen;
-      }
-
-      return str;
+        return `${this.num}R${this.gen}`;
+      }
+
+      return `${this.num}R`;
     }
   };
   return Ref;
 }();
 
 exports.Ref = Ref;
 
 var RefSet = function RefSetClosure() {
@@ -21972,23 +21979,27 @@ class AnnotationBorderStyle {
     this.width = 1;
     this.style = _util.AnnotationBorderStyleType.SOLID;
     this.dashArray = [3];
     this.horizontalCornerRadius = 0;
     this.verticalCornerRadius = 0;
   }
 
   setWidth(width) {
+    if ((0, _primitives.isName)(width)) {
+      width = parseFloat(width.name);
+    }
+
     if (Number.isInteger(width)) {
       this.width = width;
     }
   }
 
   setStyle(style) {
-    if (!style) {
+    if (!(0, _primitives.isName)(style)) {
       return;
     }
 
     switch (style.name) {
       case 'S':
         this.style = _util.AnnotationBorderStyleType.SOLID;
         break;
 
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -51,16 +51,18 @@
 .textLayer .highlight.middle {
   border-radius: 0px;
 }
 
 .textLayer .highlight.selected {
   background-color: rgb(0, 100, 0);
 }
 
+.textLayer ::-moz-selection { background: rgb(0,0,255); }
+
 .textLayer ::selection { background: rgb(0,0,255); }
 
 .textLayer .endOfContent {
   display: block;
   position: absolute;
   left: 0px;
   top: 100%;
   right: 0px;
@@ -1670,16 +1672,17 @@ html[dir='rtl'] .outlineItemToggler::bef
   color: hsla(0,0%,100%,.8);
   font-style: italic;
   cursor: default;
 }
 
 /* TODO: file FF bug to support ::-moz-selection:window-inactive
    so we can override the opaque grey background when the window is inactive;
    see https://bugzilla.mozilla.org/show_bug.cgi?id=706209 */
+::-moz-selection { background: rgba(0,0,255,0.3); }
 ::selection { background: rgba(0,0,255,0.3); }
 
 #errorWrapper {
   background: none repeat scroll 0 0 #FF5555;
   color: white;
   left: 0;
   position: absolute;
   right: 0;
--- 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.1.132
+  release: version 2.1.145
 
   # 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/dom/base/nsAttrValue.h
+++ b/dom/base/nsAttrValue.h
@@ -17,23 +17,23 @@
 #include "nscore.h"
 #include "nsString.h"
 #include "nsStringBuffer.h"
 #include "nsColor.h"
 #include "nsCaseTreatment.h"
 #include "nsMargin.h"
 #include "nsCOMPtr.h"
 #include "nsStringFwd.h"
-#include "SVGAttrValueWrapper.h"
 #include "nsTArrayForwardDeclare.h"
 #include "nsAtom.h"
+#include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/AtomArray.h"
+#include "mozilla/EnumTypeTraits.h"
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/dom/BindingDeclarations.h"
-#include "mozilla/EnumTypeTraits.h"
+#include "mozilla/SVGAttrValueWrapper.h"
 
 class nsIDocument;
 class nsIURI;
 class nsStyledElement;
 struct MiscContainer;
 
 namespace mozilla {
 class DeclarationBlock;
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -103,30 +103,30 @@
 #include "mozilla/dom/SVGImageElement.h"
 #include "mozilla/dom/SVGMatrix.h"
 #include "mozilla/dom/TextMetrics.h"
 #include "mozilla/dom/SVGMatrix.h"
 #include "mozilla/FloatingPoint.h"
 #include "nsGlobalWindow.h"
 #include "GLContext.h"
 #include "GLContextProvider.h"
-#include "SVGContentUtils.h"
 #include "nsIScreenManager.h"
 #include "nsFilterInstance.h"
 #include "nsSVGLength2.h"
 #include "nsDeviceContext.h"
 #include "nsFontMetrics.h"
 #include "Units.h"
 #include "CanvasUtils.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
+#include "mozilla/ServoCSSParser.h"
 #include "mozilla/ServoStyleSet.h"
+#include "mozilla/SVGContentUtils.h"
 #include "mozilla/layers/CanvasClient.h"
 #include "mozilla/layers/WebRenderUserData.h"
 #include "mozilla/layers/WebRenderCanvasRenderer.h"
-#include "mozilla/ServoCSSParser.h"
 
 #undef free  // apparently defined by some windows header, clashing with a
              // free() method in SkTypes.h
 #include "SkiaGLGlue.h"
 #ifdef USE_SKIA
 #include "SurfaceTypes.h"
 #include "GLBlitHelper.h"
 #include "ScopedGLHelpers.h"
--- a/dom/smil/SMILAnimationController.cpp
+++ b/dom/smil/SMILAnimationController.cpp
@@ -324,17 +324,17 @@ void SMILAnimationController::DoSample(b
   }
 
   // STEP 3: (i)  Sample the timed elements AND
   //         (ii) Create a table of compositors
   //
   // (i) Here we sample the timed elements (fetched from the
   // SVGAnimationElements) which determine from the active time if the
   // element is active and what its simple time etc. is. This information is
-  // then passed to its time client (nsSMILAnimationFunction).
+  // then passed to its time client (SMILAnimationFunction).
   //
   // (ii) During the same loop we also build up a table that contains one
   // compositor for each animated attribute and which maps animated elements to
   // the corresponding compositor for their target attribute.
   //
   // Note that this compositor table needs to be allocated on the heap so we can
   // store it until the next sample. This lets us find out which elements were
   // animated in sample 'n-1' but not in sample 'n' (and hence need to have
@@ -565,17 +565,17 @@ void SMILAnimationController::DoMileston
     SVGAnimationElement* aElement, nsSMILCompositorTable* aCompositorTable,
     bool& aStyleFlushNeeded) {
   // Add a compositor to the hash table if there's not already one there
   nsSMILTargetIdentifier key;
   if (!GetTargetIdentifierForAnimation(aElement, key))
     // Something's wrong/missing about animation's target; skip this animation
     return;
 
-  nsSMILAnimationFunction& func = aElement->AnimationFunction();
+  SMILAnimationFunction& func = aElement->AnimationFunction();
 
   // Only add active animation functions. If there are no active animations
   // targeting an attribute, no compositor will be created and any previously
   // applied animations will be cleared.
   if (func.IsActiveOrFrozen()) {
     // Look up the compositor for our target, & add our animation function
     // to its list of animation functions.
     nsSMILCompositor* result = aCompositorTable->PutEntry(key);
rename from dom/smil/nsSMILAnimationFunction.cpp
rename to dom/smil/SMILAnimationFunction.cpp
--- a/dom/smil/nsSMILAnimationFunction.cpp
+++ b/dom/smil/SMILAnimationFunction.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
-#include "nsSMILAnimationFunction.h"
+#include "SMILAnimationFunction.h"
 
 #include "mozilla/dom/SVGAnimationElement.h"
 #include "mozilla/Move.h"
 #include "nsISMILAttr.h"
 #include "SMILCSSValueType.h"
 #include "nsSMILParserUtils.h"
 #include "SMILNullType.h"
 #include "nsSMILTimedElement.h"
@@ -21,62 +21,63 @@
 #include "nsContentUtils.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include <math.h>
 #include <algorithm>
 
 using namespace mozilla::dom;
 
+namespace mozilla {
+
 //----------------------------------------------------------------------
 // Static members
 
-nsAttrValue::EnumTable nsSMILAnimationFunction::sAccumulateTable[] = {
+nsAttrValue::EnumTable SMILAnimationFunction::sAccumulateTable[] = {
     {"none", false}, {"sum", true}, {nullptr, 0}};
 
-nsAttrValue::EnumTable nsSMILAnimationFunction::sAdditiveTable[] = {
+nsAttrValue::EnumTable SMILAnimationFunction::sAdditiveTable[] = {
     {"replace", false}, {"sum", true}, {nullptr, 0}};
 
-nsAttrValue::EnumTable nsSMILAnimationFunction::sCalcModeTable[] = {
+nsAttrValue::EnumTable SMILAnimationFunction::sCalcModeTable[] = {
     {"linear", CALC_LINEAR},
     {"discrete", CALC_DISCRETE},
     {"paced", CALC_PACED},
     {"spline", CALC_SPLINE},
     {nullptr, 0}};
 
 // Any negative number should be fine as a sentinel here,
 // because valid distances are non-negative.
 #define COMPUTE_DISTANCE_ERROR (-1)
 
 //----------------------------------------------------------------------
 // Constructors etc.
 
-nsSMILAnimationFunction::nsSMILAnimationFunction()
+SMILAnimationFunction::SMILAnimationFunction()
     : mSampleTime(-1),
       mRepeatIteration(0),
       mBeginTime(INT64_MIN),
       mAnimationElement(nullptr),
       mErrorFlags(0),
       mIsActive(false),
       mIsFrozen(false),
       mLastValue(false),
       mHasChanged(true),
       mValueNeedsReparsingEverySample(false),
       mPrevSampleWasSingleValueAnimation(false),
       mWasSkippedInPrevSample(false) {}
 
-void nsSMILAnimationFunction::SetAnimationElement(
+void SMILAnimationFunction::SetAnimationElement(
     SVGAnimationElement* aAnimationElement) {
   mAnimationElement = aAnimationElement;
 }
 
-bool nsSMILAnimationFunction::SetAttr(nsAtom* aAttribute,
-                                      const nsAString& aValue,
-                                      nsAttrValue& aResult,
-                                      nsresult* aParseResult) {
+bool SMILAnimationFunction::SetAttr(nsAtom* aAttribute, const nsAString& aValue,
+                                    nsAttrValue& aResult,
+                                    nsresult* aParseResult) {
   bool foundMatch = true;
   nsresult parseResult = NS_OK;
 
   // The attributes 'by', 'from', 'to', and 'values' may be parsed differently
   // depending on the element & attribute we're animating.  So instead of
   // parsing them now we re-parse them at every sample.
   if (aAttribute == nsGkAtoms::by || aAttribute == nsGkAtoms::from ||
       aAttribute == nsGkAtoms::to || aAttribute == nsGkAtoms::values) {
@@ -101,17 +102,17 @@ bool nsSMILAnimationFunction::SetAttr(ns
 
   if (foundMatch && aParseResult) {
     *aParseResult = parseResult;
   }
 
   return foundMatch;
 }
 
-bool nsSMILAnimationFunction::UnsetAttr(nsAtom* aAttribute) {
+bool SMILAnimationFunction::UnsetAttr(nsAtom* aAttribute) {
   bool foundMatch = true;
 
   if (aAttribute == nsGkAtoms::by || aAttribute == nsGkAtoms::from ||
       aAttribute == nsGkAtoms::to || aAttribute == nsGkAtoms::values) {
     mHasChanged = true;
   } else if (aAttribute == nsGkAtoms::accumulate) {
     UnsetAccumulate();
   } else if (aAttribute == nsGkAtoms::additive) {
@@ -124,19 +125,19 @@ bool nsSMILAnimationFunction::UnsetAttr(
     UnsetKeySplines();
   } else {
     foundMatch = false;
   }
 
   return foundMatch;
 }
 
-void nsSMILAnimationFunction::SampleAt(nsSMILTime aSampleTime,
-                                       const nsSMILTimeValue& aSimpleDuration,
-                                       uint32_t aRepeatIteration) {
+void SMILAnimationFunction::SampleAt(nsSMILTime aSampleTime,
+                                     const nsSMILTimeValue& aSimpleDuration,
+                                     uint32_t aRepeatIteration) {
   // * Update mHasChanged ("Might this sample be different from prev one?")
   // Were we previously sampling a fill="freeze" final val? (We're not anymore.)
   mHasChanged |= mLastValue;
 
   // Are we sampling at a new point in simple duration? And does that matter?
   mHasChanged |=
       (mSampleTime != aSampleTime || mSimpleDuration != aSimpleDuration) &&
       !IsValueFixedForSimpleDuration();
@@ -147,40 +148,40 @@ void nsSMILAnimationFunction::SampleAt(n
   }
 
   mSampleTime = aSampleTime;
   mSimpleDuration = aSimpleDuration;
   mRepeatIteration = aRepeatIteration;
   mLastValue = false;
 }
 
-void nsSMILAnimationFunction::SampleLastValue(uint32_t aRepeatIteration) {
+void SMILAnimationFunction::SampleLastValue(uint32_t aRepeatIteration) {
   if (mHasChanged || !mLastValue || mRepeatIteration != aRepeatIteration) {
     mHasChanged = true;
   }
 
   mRepeatIteration = aRepeatIteration;
   mLastValue = true;
 }
 
-void nsSMILAnimationFunction::Activate(nsSMILTime aBeginTime) {
+void SMILAnimationFunction::Activate(nsSMILTime aBeginTime) {
   mBeginTime = aBeginTime;
   mIsActive = true;
   mIsFrozen = false;
   mHasChanged = true;
 }
 
-void nsSMILAnimationFunction::Inactivate(bool aIsFrozen) {
+void SMILAnimationFunction::Inactivate(bool aIsFrozen) {
   mIsActive = false;
   mIsFrozen = aIsFrozen;
   mHasChanged = true;
 }
 
-void nsSMILAnimationFunction::ComposeResult(const nsISMILAttr& aSMILAttr,
-                                            nsSMILValue& aResult) {
+void SMILAnimationFunction::ComposeResult(const nsISMILAttr& aSMILAttr,
+                                          nsSMILValue& aResult) {
   mHasChanged = false;
   mPrevSampleWasSingleValueAnimation = false;
   mWasSkippedInPrevSample = false;
 
   // Skip animations that are inactive or in error
   if (!IsActiveOrFrozen() || mErrorFlags != 0) return;
 
   // Get the animation values
@@ -232,18 +233,18 @@ void nsSMILAnimationFunction::ComposeRes
   }
 
   // If additive animation isn't required or isn't supported, set the value.
   if (!isAdditive || NS_FAILED(aResult.SandwichAdd(result))) {
     aResult = std::move(result);
   }
 }
 
-int8_t nsSMILAnimationFunction::CompareTo(
-    const nsSMILAnimationFunction* aOther) const {
+int8_t SMILAnimationFunction::CompareTo(
+    const SMILAnimationFunction* aOther) const {
   NS_ENSURE_TRUE(aOther, 0);
 
   NS_ASSERTION(aOther != this, "Trying to compare to self");
 
   // Inactive animations sort first
   if (!IsActiveOrFrozen() && aOther->IsActiveOrFrozen()) return -1;
 
   if (IsActiveOrFrozen() && !aOther->IsActiveOrFrozen()) return 1;
@@ -267,43 +268,43 @@ int8_t nsSMILAnimationFunction::CompareT
              "Two animations cannot have the same animation content element!");
 
   return (nsContentUtils::PositionIsBefore(mAnimationElement,
                                            aOther->mAnimationElement))
              ? -1
              : 1;
 }
 
-bool nsSMILAnimationFunction::WillReplace() const {
+bool SMILAnimationFunction::WillReplace() const {
   /*
    * In IsAdditive() we don't consider to-animation to be additive as it is
    * a special case that is dealt with differently in the compositing method.
    * Here, however, we return FALSE for to-animation (i.e. it will NOT replace
    * the underlying value) as it builds on the underlying value.
    */
   return !mErrorFlags && !(IsAdditive() || IsToAnimation());
 }
 
-bool nsSMILAnimationFunction::HasChanged() const {
+bool SMILAnimationFunction::HasChanged() const {
   return mHasChanged || mValueNeedsReparsingEverySample;
 }
 
-bool nsSMILAnimationFunction::UpdateCachedTarget(
+bool SMILAnimationFunction::UpdateCachedTarget(
     const nsSMILTargetIdentifier& aNewTarget) {
   if (!mLastTarget.Equals(aNewTarget)) {
     mLastTarget = aNewTarget;
     return true;
   }
   return false;
 }
 
 //----------------------------------------------------------------------
 // Implementation helpers
 
-nsresult nsSMILAnimationFunction::InterpolateResult(
+nsresult SMILAnimationFunction::InterpolateResult(
     const nsSMILValueArray& aValues, nsSMILValue& aResult,
     nsSMILValue& aBaseValue) {
   // Sanity check animation values
   if ((!IsToAnimation() && aValues.Length() < 2) ||
       (IsToAnimation() && aValues.Length() != 1)) {
     NS_ERROR("Unexpected number of values");
     return NS_ERROR_FAILURE;
   }
@@ -447,17 +448,17 @@ nsresult nsSMILAnimationFunction::Interp
         }
       }
     }
     rv = NS_OK;
   }
   return rv;
 }
 
-nsresult nsSMILAnimationFunction::AccumulateResult(
+nsresult SMILAnimationFunction::AccumulateResult(
     const nsSMILValueArray& aValues, nsSMILValue& aResult) {
   if (!IsToAnimation() && GetAccumulate() && mRepeatIteration) {
     const nsSMILValue& lastValue = aValues[aValues.Length() - 1];
 
     // If the target attribute type doesn't support addition, Add will
     // fail and we leave aResult untouched.
     aResult.Add(lastValue, mRepeatIteration);
   }
@@ -470,17 +471,17 @@ nsresult nsSMILAnimationFunction::Accumu
  *  - determines which two elements of the values array we're in between
  *    (returned as aFrom and aTo)
  *  - determines where we are between them
  *    (returned as aIntervalProgress)
  *
  * Returns NS_OK, or NS_ERROR_FAILURE if our values don't support distance
  * computation.
  */
-nsresult nsSMILAnimationFunction::ComputePacedPosition(
+nsresult SMILAnimationFunction::ComputePacedPosition(
     const nsSMILValueArray& aValues, double aSimpleProgress,
     double& aIntervalProgress, const nsSMILValue*& aFrom,
     const nsSMILValue*& aTo) {
   NS_ASSERTION(0.0f <= aSimpleProgress && aSimpleProgress < 1.0f,
                "aSimpleProgress is out of bounds");
   NS_ASSERTION(GetCalcMode() == CALC_PACED,
                "Calling paced-specific function, but not in paced mode");
   MOZ_ASSERT(aValues.Length() >= 2, "Unexpected number of values");
@@ -563,17 +564,17 @@ nsresult nsSMILAnimationFunction::Comput
 }
 
 /*
  * Computes the total distance to be travelled by a paced animation.
  *
  * Returns the total distance, or returns COMPUTE_DISTANCE_ERROR if
  * our values don't support distance computation.
  */
-double nsSMILAnimationFunction::ComputePacedTotalDistance(
+double SMILAnimationFunction::ComputePacedTotalDistance(
     const nsSMILValueArray& aValues) const {
   NS_ASSERTION(GetCalcMode() == CALC_PACED,
                "Calling paced-specific function, but not in paced mode");
 
   double totalDistance = 0.0;
   for (uint32_t i = 0; i < aValues.Length() - 1; i++) {
     double tmpDist;
     nsresult rv = aValues[i].ComputeDistance(aValues[i + 1], tmpDist);
@@ -587,18 +588,18 @@ double nsSMILAnimationFunction::ComputeP
     tmpDist = std::max(tmpDist, 0.0);
 
     totalDistance += tmpDist;
   }
 
   return totalDistance;
 }
 
-double nsSMILAnimationFunction::ScaleSimpleProgress(double aProgress,
-                                                    nsSMILCalcMode aCalcMode) {
+double SMILAnimationFunction::ScaleSimpleProgress(double aProgress,
+                                                  nsSMILCalcMode aCalcMode) {
   if (!HasAttr(nsGkAtoms::keyTimes)) return aProgress;
 
   uint32_t numTimes = mKeyTimes.Length();
 
   if (numTimes < 2) return aProgress;
 
   uint32_t i = 0;
   for (; i < numTimes - 2 && aProgress >= mKeyTimes[i + 1]; ++i) {
@@ -623,38 +624,38 @@ double nsSMILAnimationFunction::ScaleSim
 
   double intervalLength = intervalEnd - intervalStart;
   if (intervalLength <= 0.0) return intervalStart;
 
   return (i + (aProgress - intervalStart) / intervalLength) /
          double(numTimes - 1);
 }
 
-double nsSMILAnimationFunction::ScaleIntervalProgress(double aProgress,
-                                                      uint32_t aIntervalIndex) {
+double SMILAnimationFunction::ScaleIntervalProgress(double aProgress,
+                                                    uint32_t aIntervalIndex) {
   if (GetCalcMode() != CALC_SPLINE) return aProgress;
 
   if (!HasAttr(nsGkAtoms::keySplines)) return aProgress;
 
   MOZ_ASSERT(aIntervalIndex < mKeySplines.Length(), "Invalid interval index");
 
   nsSMILKeySpline const& spline = mKeySplines[aIntervalIndex];
   return spline.GetSplineValue(aProgress);
 }
 
-bool nsSMILAnimationFunction::HasAttr(nsAtom* aAttName) const {
+bool SMILAnimationFunction::HasAttr(nsAtom* aAttName) const {
   return mAnimationElement->HasAttr(aAttName);
 }
 
-const nsAttrValue* nsSMILAnimationFunction::GetAttr(nsAtom* aAttName) const {
+const nsAttrValue* SMILAnimationFunction::GetAttr(nsAtom* aAttName) const {
   return mAnimationElement->GetParsedAttr(aAttName);
 }
 
-bool nsSMILAnimationFunction::GetAttr(nsAtom* aAttName,
-                                      nsAString& aResult) const {
+bool SMILAnimationFunction::GetAttr(nsAtom* aAttName,
+                                    nsAString& aResult) const {
   return mAnimationElement->GetAttr(aAttName, aResult);
 }
 
 /*
  * A utility function to make querying an attribute that corresponds to an
  * nsSMILValue a little neater.
  *
  * @param aAttName    The attribute name (in the global namespace).
@@ -664,20 +665,20 @@ bool nsSMILAnimationFunction::GetAttr(ns
  *                    If |aResult| contains dependencies on its context that
  *                    should prevent the result of the animation sandwich from
  *                    being cached and reused in future samples (as reported
  *                    by nsISMILAttr::ValueFromString), then this outparam
  *                    will be set to true. Otherwise it is left unmodified.
  *
  * Returns false if a parse error occurred, otherwise returns true.
  */
-bool nsSMILAnimationFunction::ParseAttr(nsAtom* aAttName,
-                                        const nsISMILAttr& aSMILAttr,
-                                        nsSMILValue& aResult,
-                                        bool& aPreventCachingOfSandwich) const {
+bool SMILAnimationFunction::ParseAttr(nsAtom* aAttName,
+                                      const nsISMILAttr& aSMILAttr,
+                                      nsSMILValue& aResult,
+                                      bool& aPreventCachingOfSandwich) const {
   nsAutoString attValue;
   if (GetAttr(aAttName, attValue)) {
     bool preventCachingOfSandwich = false;
     nsresult rv = aSMILAttr.ValueFromString(attValue, mAnimationElement,
                                             aResult, preventCachingOfSandwich);
     if (NS_FAILED(rv)) return false;
 
     if (preventCachingOfSandwich) {
@@ -696,18 +697,18 @@ bool nsSMILAnimationFunction::ParseAttr(
  * (3) if both by and to are specified only to will be used, by will be ignored
  * (4) if by is specified without from (by animation), forces additive behaviour
  * (5) if to is specified without from (to animation), special care needs to be
  *     taken when compositing animation as such animations are composited last.
  *
  * This helper method applies these rules to fill in the values list and to set
  * some internal state.
  */
-nsresult nsSMILAnimationFunction::GetValues(const nsISMILAttr& aSMILAttr,
-                                            nsSMILValueArray& aResult) {
+nsresult SMILAnimationFunction::GetValues(const nsISMILAttr& aSMILAttr,
+                                          nsSMILValueArray& aResult) {
   if (!mAnimationElement) return NS_ERROR_FAILURE;
 
   mValueNeedsReparsingEverySample = false;
   nsSMILValueArray result;
 
   // If "values" is set, use it
   if (HasAttr(nsGkAtoms::values)) {
     nsAutoString attValue;
@@ -732,63 +733,62 @@ nsresult nsSMILAnimationFunction::GetVal
         ParseAttr(nsGkAtoms::from, aSMILAttr, from, preventCachingOfSandwich);
     parseOk &=
         ParseAttr(nsGkAtoms::by, aSMILAttr, by, preventCachingOfSandwich);
 
     if (preventCachingOfSandwich) {
       mValueNeedsReparsingEverySample = true;
     }
 
-    if (!parseOk || !result.SetCapacity(2, mozilla::fallible)) {
+    if (!parseOk || !result.SetCapacity(2, fallible)) {
       return NS_ERROR_FAILURE;
     }
 
     // AppendElement() below must succeed, because SetCapacity() succeeded.
     if (!to.IsNull()) {
       if (!from.IsNull()) {
-        MOZ_ALWAYS_TRUE(result.AppendElement(from, mozilla::fallible));
-        MOZ_ALWAYS_TRUE(result.AppendElement(to, mozilla::fallible));
+        MOZ_ALWAYS_TRUE(result.AppendElement(from, fallible));
+        MOZ_ALWAYS_TRUE(result.AppendElement(to, fallible));
       } else {
-        MOZ_ALWAYS_TRUE(result.AppendElement(to, mozilla::fallible));
+        MOZ_ALWAYS_TRUE(result.AppendElement(to, fallible));
       }
     } else if (!by.IsNull()) {
       nsSMILValue effectiveFrom(by.mType);
       if (!from.IsNull()) effectiveFrom = from;
       // Set values to 'from; from + by'
-      MOZ_ALWAYS_TRUE(result.AppendElement(effectiveFrom, mozilla::fallible));
+      MOZ_ALWAYS_TRUE(result.AppendElement(effectiveFrom, fallible));
       nsSMILValue effectiveTo(effectiveFrom);
       if (!effectiveTo.IsNull() && NS_SUCCEEDED(effectiveTo.Add(by))) {
-        MOZ_ALWAYS_TRUE(result.AppendElement(effectiveTo, mozilla::fallible));
+        MOZ_ALWAYS_TRUE(result.AppendElement(effectiveTo, fallible));
       } else {
         // Using by-animation with non-additive type or bad base-value
         return NS_ERROR_FAILURE;
       }
     } else {
       // No values, no to, no by -- call it a day
       return NS_ERROR_FAILURE;
     }
   }
 
   result.SwapElements(aResult);
 
   return NS_OK;
 }
 
-void nsSMILAnimationFunction::CheckValueListDependentAttrs(
-    uint32_t aNumValues) {
+void SMILAnimationFunction::CheckValueListDependentAttrs(uint32_t aNumValues) {
   CheckKeyTimes(aNumValues);
   CheckKeySplines(aNumValues);
 }
 
 /**
  * Performs checks for the keyTimes attribute required by the SMIL spec but
  * which depend on other attributes and therefore needs to be updated as
  * dependent attributes are set.
  */
-void nsSMILAnimationFunction::CheckKeyTimes(uint32_t aNumValues) {
+void SMILAnimationFunction::CheckKeyTimes(uint32_t aNumValues) {
   if (!HasAttr(nsGkAtoms::keyTimes)) return;
 
   nsSMILCalcMode calcMode = GetCalcMode();
 
   // attribute is ignored for calcMode = paced
   if (calcMode == CALC_PACED) {
     SetKeyTimesErrorFlag(false);
     return;
@@ -820,17 +820,17 @@ void nsSMILAnimationFunction::CheckKeyTi
       mKeyTimes[numKeyTimes - 1] != 1.0) {
     SetKeyTimesErrorFlag(true);
     return;
   }
 
   SetKeyTimesErrorFlag(false);
 }
 
-void nsSMILAnimationFunction::CheckKeySplines(uint32_t aNumValues) {
+void SMILAnimationFunction::CheckKeySplines(uint32_t aNumValues) {
   // attribute is ignored if calc mode is not spline
   if (GetCalcMode() != CALC_SPLINE) {
     SetKeySplinesErrorFlag(false);
     return;
   }
 
   // calc mode is spline but the attribute is not set
   if (!HasAttr(nsGkAtoms::keySplines)) {
@@ -856,123 +856,125 @@ void nsSMILAnimationFunction::CheckKeySp
       (IsToAnimation() && splineSpecs != 1)) {
     SetKeySplinesErrorFlag(true);
     return;
   }
 
   SetKeySplinesErrorFlag(false);
 }
 
-bool nsSMILAnimationFunction::IsValueFixedForSimpleDuration() const {
+bool SMILAnimationFunction::IsValueFixedForSimpleDuration() const {
   return mSimpleDuration.IsIndefinite() ||
          (!mHasChanged && mPrevSampleWasSingleValueAnimation);
 }
 
 //----------------------------------------------------------------------
 // Property getters
 
-bool nsSMILAnimationFunction::GetAccumulate() const {
+bool SMILAnimationFunction::GetAccumulate() const {
   const nsAttrValue* value = GetAttr(nsGkAtoms::accumulate);
   if (!value) return false;
 
   return value->GetEnumValue();
 }
 
-bool nsSMILAnimationFunction::GetAdditive() const {
+bool SMILAnimationFunction::GetAdditive() const {
   const nsAttrValue* value = GetAttr(nsGkAtoms::additive);
   if (!value) return false;
 
   return value->GetEnumValue();
 }
 
-nsSMILAnimationFunction::nsSMILCalcMode nsSMILAnimationFunction::GetCalcMode()
+SMILAnimationFunction::nsSMILCalcMode SMILAnimationFunction::GetCalcMode()
     const {
   const nsAttrValue* value = GetAttr(nsGkAtoms::calcMode);
   if (!value) return CALC_LINEAR;
 
   return nsSMILCalcMode(value->GetEnumValue());
 }
 
 //----------------------------------------------------------------------
 // Property setters / un-setters:
 
-nsresult nsSMILAnimationFunction::SetAccumulate(const nsAString& aAccumulate,
-                                                nsAttrValue& aResult) {
+nsresult SMILAnimationFunction::SetAccumulate(const nsAString& aAccumulate,
+                                              nsAttrValue& aResult) {
   mHasChanged = true;
   bool parseResult =
       aResult.ParseEnumValue(aAccumulate, sAccumulateTable, true);
   SetAccumulateErrorFlag(!parseResult);
   return parseResult ? NS_OK : NS_ERROR_FAILURE;
 }
 
-void nsSMILAnimationFunction::UnsetAccumulate() {
+void SMILAnimationFunction::UnsetAccumulate() {
   SetAccumulateErrorFlag(false);
   mHasChanged = true;
 }
 
-nsresult nsSMILAnimationFunction::SetAdditive(const nsAString& aAdditive,
-                                              nsAttrValue& aResult) {
+nsresult SMILAnimationFunction::SetAdditive(const nsAString& aAdditive,
+                                            nsAttrValue& aResult) {
   mHasChanged = true;
   bool parseResult = aResult.ParseEnumValue(aAdditive, sAdditiveTable, true);
   SetAdditiveErrorFlag(!parseResult);
   return parseResult ? NS_OK : NS_ERROR_FAILURE;
 }
 
-void nsSMILAnimationFunction::UnsetAdditive() {
+void SMILAnimationFunction::UnsetAdditive() {
   SetAdditiveErrorFlag(false);
   mHasChanged = true;
 }
 
-nsresult nsSMILAnimationFunction::SetCalcMode(const nsAString& aCalcMode,
-                                              nsAttrValue& aResult) {
+nsresult SMILAnimationFunction::SetCalcMode(const nsAString& aCalcMode,
+                                            nsAttrValue& aResult) {
   mHasChanged = true;
   bool parseResult = aResult.ParseEnumValue(aCalcMode, sCalcModeTable, true);
   SetCalcModeErrorFlag(!parseResult);
   return parseResult ? NS_OK : NS_ERROR_FAILURE;
 }
 
-void nsSMILAnimationFunction::UnsetCalcMode() {
+void SMILAnimationFunction::UnsetCalcMode() {
   SetCalcModeErrorFlag(false);
   mHasChanged = true;
 }
 
-nsresult nsSMILAnimationFunction::SetKeySplines(const nsAString& aKeySplines,
-                                                nsAttrValue& aResult) {
+nsresult SMILAnimationFunction::SetKeySplines(const nsAString& aKeySplines,
+                                              nsAttrValue& aResult) {
   mKeySplines.Clear();
   aResult.SetTo(aKeySplines);
 
   mHasChanged = true;
 
   if (!nsSMILParserUtils::ParseKeySplines(aKeySplines, mKeySplines)) {
     mKeySplines.Clear();
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
-void nsSMILAnimationFunction::UnsetKeySplines() {
+void SMILAnimationFunction::UnsetKeySplines() {
   mKeySplines.Clear();
   SetKeySplinesErrorFlag(false);
   mHasChanged = true;
 }
 
-nsresult nsSMILAnimationFunction::SetKeyTimes(const nsAString& aKeyTimes,
-                                              nsAttrValue& aResult) {
+nsresult SMILAnimationFunction::SetKeyTimes(const nsAString& aKeyTimes,
+                                            nsAttrValue& aResult) {
   mKeyTimes.Clear();
   aResult.SetTo(aKeyTimes);
 
   mHasChanged = true;
 
   if (!nsSMILParserUtils::ParseSemicolonDelimitedProgressList(aKeyTimes, true,
                                                               mKeyTimes)) {
     mKeyTimes.Clear();
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
-void nsSMILAnimationFunction::UnsetKeyTimes() {
+void SMILAnimationFunction::UnsetKeyTimes() {
   mKeyTimes.Clear();
   SetKeyTimesErrorFlag(false);
   mHasChanged = true;
 }
+
+}  // namespace mozilla
rename from dom/smil/nsSMILAnimationFunction.h
rename to dom/smil/SMILAnimationFunction.h
--- a/dom/smil/nsSMILAnimationFunction.h
+++ b/dom/smil/SMILAnimationFunction.h
@@ -17,33 +17,32 @@
 #include "nsTArray.h"
 #include "nsAttrValue.h"
 #include "nsSMILTypes.h"
 
 namespace mozilla {
 namespace dom {
 class SVGAnimationElement;
 }  // namespace dom
-}  // namespace mozilla
 
 //----------------------------------------------------------------------
-// nsSMILAnimationFunction
+// SMILAnimationFunction
 //
 // The animation function calculates animation values. It it is provided with
 // time parameters (sample time, repeat iteration etc.) and it uses this to
 // build an appropriate animation value by performing interpolation and
 // addition operations.
 //
 // It is responsible for implementing the animation parameters of an animation
 // element (e.g. from, by, to, values, calcMode, additive, accumulate, keyTimes,
 // keySplines)
 //
-class nsSMILAnimationFunction {
+class SMILAnimationFunction {
  public:
-  nsSMILAnimationFunction();
+  SMILAnimationFunction();
 
   /*
    * Sets the owning animation element which this class uses to query attribute
    * values and compare document positions.
    */
   void SetAnimationElement(
       mozilla::dom::SVGAnimationElement* aAnimationElement);
 
@@ -133,17 +132,17 @@ class nsSMILAnimationFunction {
    * sandwich -- higher priority animations are applied on top of lower
    * priority animations.
    *
    * @return  -1 if this animation has lower priority or 1 if this animation has
    *          higher priority
    *
    * This method should never return any other value, including 0.
    */
-  int8_t CompareTo(const nsSMILAnimationFunction* aOther) const;
+  int8_t CompareTo(const SMILAnimationFunction* aOther) const;
 
   /*
    * The following methods are provided so that the compositor can optimize its
    * operations by only composing those animation that will affect the final
    * result.
    */
 
   /**
@@ -239,42 +238,42 @@ class nsSMILAnimationFunction {
   /**
    * Returns true if we need to recalculate the animation value on every sample.
    * (e.g. because it depends on context like the font-size)
    */
   bool ValueNeedsReparsingEverySample() const {
     return mValueNeedsReparsingEverySample;
   }
 
-  // Comparator utility class, used for sorting nsSMILAnimationFunctions
+  // Comparator utility class, used for sorting SMILAnimationFunctions
   class Comparator {
    public:
-    bool Equals(const nsSMILAnimationFunction* aElem1,
-                const nsSMILAnimationFunction* aElem2) const {
+    bool Equals(const SMILAnimationFunction* aElem1,
+                const SMILAnimationFunction* aElem2) const {
       return (aElem1->CompareTo(aElem2) == 0);
     }
-    bool LessThan(const nsSMILAnimationFunction* aElem1,
-                  const nsSMILAnimationFunction* aElem2) const {
+    bool LessThan(const SMILAnimationFunction* aElem1,
+                  const SMILAnimationFunction* aElem2) const {
       return (aElem1->CompareTo(aElem2) < 0);
     }
   };
 
  protected:
   // Typedefs
   typedef FallibleTArray<nsSMILValue> nsSMILValueArray;
 
   // Types
   enum nsSMILCalcMode : uint8_t {
     CALC_LINEAR,
     CALC_DISCRETE,
     CALC_PACED,
     CALC_SPLINE
   };
 
-  // Used for sorting nsSMILAnimationFunctions
+  // Used for sorting SMILAnimationFunctions
   nsSMILTime GetBeginTime() const { return mBeginTime; }
 
   // Property getters
   bool GetAccumulate() const;
   bool GetAdditive() const;
   virtual nsSMILCalcMode GetCalcMode() const;
 
   // Property setters
@@ -412,17 +411,17 @@ class nsSMILAnimationFunction {
   nsSMILTime mSampleTime;  // sample time within simple dur
   nsSMILTimeValue mSimpleDuration;
   uint32_t mRepeatIteration;
 
   nsSMILTime mBeginTime;  // document time
 
   // The owning animation element. This is used for sorting based on document
   // position and for fetching attribute values stored in the element.
-  // Raw pointer is OK here, because this nsSMILAnimationFunction can't outlive
+  // Raw pointer is OK here, because this SMILAnimationFunction can't outlive
   // its owning animation element.
   mozilla::dom::SVGAnimationElement* mAnimationElement;
 
   // Which attributes have been set but have had errors. This is not used for
   // all attributes but only those which have specified error behaviour
   // associated with them.
   uint16_t mErrorFlags;
 
@@ -436,9 +435,11 @@ class nsSMILAnimationFunction {
   bool mIsFrozen : 1;
   bool mLastValue : 1;
   bool mHasChanged : 1;
   bool mValueNeedsReparsingEverySample : 1;
   bool mPrevSampleWasSingleValueAnimation : 1;
   bool mWasSkippedInPrevSample : 1;
 };
 
+}  // namespace mozilla
+
 #endif  // NS_SMILANIMATIONFUNCTION_H_
rename from dom/smil/nsSMILSetAnimationFunction.cpp
rename to dom/smil/SMILSetAnimationFunction.cpp
--- a/dom/smil/nsSMILSetAnimationFunction.cpp
+++ b/dom/smil/SMILSetAnimationFunction.cpp
@@ -1,17 +1,19 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
-#include "nsSMILSetAnimationFunction.h"
+#include "SMILSetAnimationFunction.h"
 
-inline bool nsSMILSetAnimationFunction::IsDisallowedAttribute(
+namespace mozilla {
+
+inline bool SMILSetAnimationFunction::IsDisallowedAttribute(
     const nsAtom* aAttribute) const {
   //
   // A <set> element is similar to <animate> but lacks:
   //   AnimationValue.attrib(calcMode, values, keyTimes, keySplines, from, to,
   //                         by) -- BUT has 'to'
   //   AnimationAddition.attrib(additive, accumulate)
   //
   if (aAttribute == nsGkAtoms::calcMode || aAttribute == nsGkAtoms::values ||
@@ -20,60 +22,62 @@ inline bool nsSMILSetAnimationFunction::
       aAttribute == nsGkAtoms::by || aAttribute == nsGkAtoms::additive ||
       aAttribute == nsGkAtoms::accumulate) {
     return true;
   }
 
   return false;
 }
 
-bool nsSMILSetAnimationFunction::SetAttr(nsAtom* aAttribute,
-                                         const nsAString& aValue,
-                                         nsAttrValue& aResult,
-                                         nsresult* aParseResult) {
+bool SMILSetAnimationFunction::SetAttr(nsAtom* aAttribute,
+                                       const nsAString& aValue,
+                                       nsAttrValue& aResult,
+                                       nsresult* aParseResult) {
   if (IsDisallowedAttribute(aAttribute)) {
     aResult.SetTo(aValue);
     if (aParseResult) {
       // SMILANIM 4.2 says:
       //
       //   The additive and accumulate attributes are not allowed, and will be
       //   ignored if specified.
       //
       // So at least for those two attributes we shouldn't report an error even
       // if they're present. For now we'll also just silently ignore other
       // attribute types too.
       *aParseResult = NS_OK;
     }
     return true;
   }
 
-  return nsSMILAnimationFunction::SetAttr(aAttribute, aValue, aResult,
-                                          aParseResult);
+  return SMILAnimationFunction::SetAttr(aAttribute, aValue, aResult,
+                                        aParseResult);
 }
 
-bool nsSMILSetAnimationFunction::UnsetAttr(nsAtom* aAttribute) {
+bool SMILSetAnimationFunction::UnsetAttr(nsAtom* aAttribute) {
   if (IsDisallowedAttribute(aAttribute)) {
     return true;
   }
 
-  return nsSMILAnimationFunction::UnsetAttr(aAttribute);
+  return SMILAnimationFunction::UnsetAttr(aAttribute);
 }
 
-bool nsSMILSetAnimationFunction::HasAttr(nsAtom* aAttName) const {
+bool SMILSetAnimationFunction::HasAttr(nsAtom* aAttName) const {
   if (IsDisallowedAttribute(aAttName)) return false;
 
-  return nsSMILAnimationFunction::HasAttr(aAttName);
+  return SMILAnimationFunction::HasAttr(aAttName);
 }
 
-const nsAttrValue* nsSMILSetAnimationFunction::GetAttr(nsAtom* aAttName) const {
+const nsAttrValue* SMILSetAnimationFunction::GetAttr(nsAtom* aAttName) const {
   if (IsDisallowedAttribute(aAttName)) return nullptr;
 
-  return nsSMILAnimationFunction::GetAttr(aAttName);
+  return SMILAnimationFunction::GetAttr(aAttName);
 }
 
-bool nsSMILSetAnimationFunction::GetAttr(nsAtom* aAttName,
-                                         nsAString& aResult) const {
+bool SMILSetAnimationFunction::GetAttr(nsAtom* aAttName,
+                                       nsAString& aResult) const {
   if (IsDisallowedAttribute(aAttName)) return false;
 
-  return nsSMILAnimationFunction::GetAttr(aAttName, aResult);
+  return SMILAnimationFunction::GetAttr(aAttName, aResult);
 }
 
-bool nsSMILSetAnimationFunction::WillReplace() const { return true; }
+bool SMILSetAnimationFunction::WillReplace() const { return true; }
+
+}  // namespace mozilla
rename from dom/smil/nsSMILSetAnimationFunction.h
rename to dom/smil/SMILSetAnimationFunction.h
--- a/dom/smil/nsSMILSetAnimationFunction.h
+++ b/dom/smil/SMILSetAnimationFunction.h
@@ -3,25 +3,27 @@
 /* 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/. */
 
 #ifndef NS_SMILSETANIMATIONFUNCTION_H_
 #define NS_SMILSETANIMATIONFUNCTION_H_
 
 #include "mozilla/Attributes.h"
-#include "nsSMILAnimationFunction.h"
+#include "mozilla/SMILAnimationFunction.h"
+
+namespace mozilla {
 
 //----------------------------------------------------------------------
-// nsSMILSetAnimationFunction
+// SMILSetAnimationFunction
 //
-// Subclass of nsSMILAnimationFunction that limits the behaviour to that offered
+// Subclass of SMILAnimationFunction that limits the behaviour to that offered
 // by a <set> element.
 //
-class nsSMILSetAnimationFunction : public nsSMILAnimationFunction {
+class SMILSetAnimationFunction : public SMILAnimationFunction {
  public:
   /*
    * Sets animation-specific attributes (or marks them dirty, in the case
    * of from/to/by/values).
    *
    * @param aAttribute The attribute being set
    * @param aValue     The updated value of the attribute.
    * @param aResult    The nsAttrValue object that may be used for storing the
@@ -55,9 +57,11 @@ class nsSMILSetAnimationFunction : publi
   virtual bool HasAttr(nsAtom* aAttName) const override;
   virtual const nsAttrValue* GetAttr(nsAtom* aAttName) const override;
   virtual bool GetAttr(nsAtom* aAttName, nsAString& aResult) const override;
   virtual bool WillReplace() const override;
 
   bool IsDisallowedAttribute(const nsAtom* aAttribute) const;
 };
 
+}  // namespace mozilla
+
 #endif  // NS_SMILSETANIMATIONFUNCTION_H_
--- a/dom/smil/moz.build
+++ b/dom/smil/moz.build
@@ -6,68 +6,68 @@
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "SVG")
 
 MOCHITEST_MANIFESTS += ['test/mochitest.ini']
 
 EXPORTS += [
     'nsISMILAttr.h',
-    'nsSMILAnimationFunction.h',
     'nsSMILCompositorTable.h',
     'nsSMILCSSProperty.h',
     'nsSMILInstanceTime.h',
     'nsSMILInterval.h',
     'nsSMILKeySpline.h',
     'nsSMILMilestone.h',
     'nsSMILRepeatCount.h',
-    'nsSMILSetAnimationFunction.h',
     'nsSMILTargetIdentifier.h',
     'nsSMILTimeContainer.h',
     'nsSMILTimedElement.h',
     'nsSMILTimeValue.h',
     'nsSMILTimeValueSpec.h',
     'nsSMILTimeValueSpecParams.h',
     'nsSMILTypes.h',
     'nsSMILValue.h',
     'SMILCSSValueType.h',
     'SMILNullType.h',
     'SMILType.h',
 ]
 
 EXPORTS.mozilla += [
     'SMILAnimationController.h',
+    'SMILAnimationFunction.h',
+    'SMILSetAnimationFunction.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'TimeEvent.h',
 ]
 
 UNIFIED_SOURCES += [
-    'nsSMILAnimationFunction.cpp',
     'nsSMILCompositor.cpp',
     'nsSMILCSSProperty.cpp',
     'nsSMILInstanceTime.cpp',
     'nsSMILInterval.cpp',
     'nsSMILKeySpline.cpp',
     'nsSMILParserUtils.cpp',
     'nsSMILRepeatCount.cpp',
-    'nsSMILSetAnimationFunction.cpp',
     'nsSMILTimeContainer.cpp',
     'nsSMILTimedElement.cpp',
     'nsSMILTimeValue.cpp',
     'nsSMILTimeValueSpec.cpp',
     'nsSMILValue.cpp',
     'SMILAnimationController.cpp',
+    'SMILAnimationFunction.cpp',
     'SMILBoolType.cpp',
     'SMILCSSValueType.cpp',
     'SMILEnumType.cpp',
     'SMILFloatType.cpp',
     'SMILIntegerType.cpp',
     'SMILNullType.cpp',
+    'SMILSetAnimationFunction.cpp',
     'SMILStringType.cpp',
     'TimeEvent.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/dom/base',
     '/dom/svg',
     '/layout/base',
--- a/dom/smil/nsSMILCompositor.cpp
+++ b/dom/smil/nsSMILCompositor.cpp
@@ -29,17 +29,17 @@ bool nsSMILCompositor::KeyEquals(KeyType
 void nsSMILCompositor::Traverse(nsCycleCollectionTraversalCallback* aCallback) {
   if (!mKey.mElement) return;
 
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback, "Compositor mKey.mElement");
   aCallback->NoteXPCOMChild(mKey.mElement);
 }
 
 // Other methods
-void nsSMILCompositor::AddAnimationFunction(nsSMILAnimationFunction* aFunc) {
+void nsSMILCompositor::AddAnimationFunction(SMILAnimationFunction* aFunc) {
   if (aFunc) {
     mAnimationFunctions.AppendElement(aFunc);
   }
 }
 
 void nsSMILCompositor::ComposeAttribute(bool& aMightHavePendingStyleUpdates) {
   if (!mKey.mElement) return;
 
@@ -63,17 +63,17 @@ void nsSMILCompositor::ComposeAttribute(
     // that case if an animation function has *just* become inactive)
     smilAttr->ClearAnimValue();
     // Removing the animation effect may require a style update.
     aMightHavePendingStyleUpdates = true;
     return;
   }
 
   // SECOND: Sort the animationFunctions, to prepare for compositing.
-  nsSMILAnimationFunction::Comparator comparator;
+  SMILAnimationFunction::Comparator comparator;
   mAnimationFunctions.Sort(comparator);
 
   // THIRD: Step backwards through animation functions to find out
   // which ones we actually care about.
   uint32_t firstFuncToCompose = GetFirstFuncToAffectSandwich();
 
   // FOURTH: Get & cache base value
   nsSMILValue sandwichResultValue;
@@ -164,17 +164,17 @@ nsCSSPropertyID nsSMILCompositor::GetCSS
 
 bool nsSMILCompositor::MightNeedBaseStyle() const {
   if (GetCSSPropertyToAnimate() == eCSSProperty_UNKNOWN) {
     return false;
   }
 
   // We should return true if at least one animation function might build on
   // the base value.
-  for (const nsSMILAnimationFunction* func : mAnimationFunctions) {
+  for (const SMILAnimationFunction* func : mAnimationFunctions) {
     if (!func->WillReplace()) {
       return true;
     }
   }
 
   return false;
 }
 
@@ -188,17 +188,17 @@ uint32_t nsSMILCompositor::GetFirstFuncT
   // a primary frame. Before this process, we will construct frame when we
   // append an element to subtree. So we will not need to worry about pending
   // frame construction in this step.
   bool canThrottle = mKey.mAttributeName != nsGkAtoms::display &&
                      !mKey.mElement->GetPrimaryFrame();
 
   uint32_t i;
   for (i = mAnimationFunctions.Length(); i > 0; --i) {
-    nsSMILAnimationFunction* curAnimFunc = mAnimationFunctions[i - 1];
+    SMILAnimationFunction* curAnimFunc = mAnimationFunctions[i - 1];
     // In the following, the lack of short-circuit behavior of |= means that we
     // will ALWAYS run UpdateCachedTarget (even if mForceCompositing is true)
     // but only call HasChanged and WasSkippedInPrevSample if necessary.  This
     // is important since we need UpdateCachedTarget to run in order to detect
     // changes to the target in subsequent samples.
     mForceCompositing |= curAnimFunc->UpdateCachedTarget(mKey) ||
                          (curAnimFunc->HasChanged() && !canThrottle) ||
                          curAnimFunc->WasSkippedInPrevSample();
--- a/dom/smil/nsSMILCompositor.h
+++ b/dom/smil/nsSMILCompositor.h
@@ -6,17 +6,17 @@
 
 #ifndef NS_SMILCOMPOSITOR_H_
 #define NS_SMILCOMPOSITOR_H_
 
 #include "mozilla/Move.h"
 #include "mozilla/UniquePtr.h"
 #include "nsTHashtable.h"
 #include "nsString.h"
-#include "nsSMILAnimationFunction.h"
+#include "SMILAnimationFunction.h"
 #include "nsSMILTargetIdentifier.h"
 #include "nsSMILCompositorTable.h"
 #include "PLDHashTable.h"
 
 //----------------------------------------------------------------------
 // nsSMILCompositor
 //
 // Performs the composition of the animation sandwich by combining the results
@@ -41,17 +41,17 @@ class nsSMILCompositor : public PLDHashE
   // PLDHashEntryHdr methods
   KeyTypeRef GetKey() const { return mKey; }
   bool KeyEquals(KeyTypePointer aKey) const;
   static KeyTypePointer KeyToPointer(KeyTypeRef aKey) { return &aKey; }
   static PLDHashNumber HashKey(KeyTypePointer aKey);
   enum { ALLOW_MEMMOVE = false };
 
   // Adds the given animation function to this Compositor's list of functions
-  void AddAnimationFunction(nsSMILAnimationFunction* aFunc);
+  void AddAnimationFunction(mozilla::SMILAnimationFunction* aFunc);
 
   // Composes the attribute's current value with the list of animation
   // functions, and assigns the resulting value to this compositor's target
   // attribute. If a change is made that might produce style updates,
   // aMightHavePendingStyleUpdates is set to true. Otherwise it is not modified.
   void ComposeAttribute(bool& aMightHavePendingStyleUpdates);
 
   // Clears animation effects on my target attribute
@@ -99,17 +99,17 @@ class nsSMILCompositor : public PLDHashE
   // If the passed-in base value differs from our cached base value, this
   // method updates the cached value (and toggles the 'mForceCompositing' flag)
   void UpdateCachedBaseValue(const nsSMILValue& aBaseValue);
 
   // The hash key (tuple of element and attributeName)
   KeyType mKey;
 
   // Hash Value: List of animation functions that animate the specified attr
-  nsTArray<nsSMILAnimationFunction*> mAnimationFunctions;
+  nsTArray<mozilla::SMILAnimationFunction*> mAnimationFunctions;
 
   // Member data for detecting when we need to force-recompose
   // ---------------------------------------------------------
   // Flag for tracking whether we need to compose. Initialized to false, but
   // gets flipped to true if we detect that something has changed.
   bool mForceCompositing;
 
   // Cached base value, so we can detect & force-recompose when it changes
--- a/dom/smil/nsSMILParserUtils.cpp
+++ b/dom/smil/nsSMILParserUtils.cpp
@@ -1,26 +1,26 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "nsSMILParserUtils.h"
+#include "mozilla/SVGContentUtils.h"
 #include "mozilla/TextUtils.h"
 #include "nsSMILKeySpline.h"
 #include "nsISMILAttr.h"
 #include "nsSMILValue.h"
 #include "nsSMILTimeValue.h"
 #include "nsSMILTimeValueSpecParams.h"
 #include "nsSMILTypes.h"
 #include "nsSMILRepeatCount.h"
 #include "nsContentUtils.h"
 #include "nsCharSeparatedTokenizer.h"
-#include "SVGContentUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 //------------------------------------------------------------------------------
 // Helper functions and Constants
 
 namespace {
 
--- a/dom/smil/nsSMILTimedElement.cpp
+++ b/dom/smil/nsSMILTimedElement.cpp
@@ -7,17 +7,17 @@
 #include "mozilla/DebugOnly.h"
 
 #include "mozilla/ContentEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/dom/SVGAnimationElement.h"
 #include "mozilla/TaskCategory.h"
 #include "nsSMILTimedElement.h"
 #include "nsAttrValueInlines.h"
-#include "nsSMILAnimationFunction.h"
+#include "SMILAnimationFunction.h"
 #include "nsSMILTimeValue.h"
 #include "nsSMILTimeValueSpec.h"
 #include "nsSMILInstanceTime.h"
 #include "nsSMILParserUtils.h"
 #include "nsSMILTimeContainer.h"
 #include "nsGkAtoms.h"
 #include "nsReadableUtils.h"
 #include "nsMathUtils.h"
@@ -444,17 +444,17 @@ void nsSMILTimedElement::RemoveInstanceT
 
   InstanceTimeList& instances = aIsBegin ? mBeginInstances : mEndInstances;
   RemoveByCreator removeByCreator(aCreator);
   RemoveInstanceTimes(instances, removeByCreator);
 
   UpdateCurrentInterval();
 }
 
-void nsSMILTimedElement::SetTimeClient(nsSMILAnimationFunction* aClient) {
+void nsSMILTimedElement::SetTimeClient(SMILAnimationFunction* aClient) {
   //
   // No need to check for nullptr. A nullptr parameter simply means to remove
   // the previous client which we do by setting to nullptr anyway.
   //
 
   mClient = aClient;
 }
 
--- a/dom/smil/nsSMILTimedElement.h
+++ b/dom/smil/nsSMILTimedElement.h
@@ -17,36 +17,37 @@
 #include "nsSMILRepeatCount.h"
 #include "nsSMILTypes.h"
 #include "nsTArray.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "nsAutoPtr.h"
 #include "nsAttrValue.h"
 
-class nsSMILAnimationFunction;
 class nsSMILTimeContainer;
 class nsSMILTimeValue;
 class nsAtom;
 
 namespace mozilla {
+class SMILAnimationFunction;
 namespace dom {
 class SVGAnimationElement;
 }  // namespace dom
 }  // namespace mozilla
 
 //----------------------------------------------------------------------
 // nsSMILTimedElement
 
 class nsSMILTimedElement {
  public:
   nsSMILTimedElement();
   ~nsSMILTimedElement();
 
   typedef mozilla::dom::Element Element;
+  typedef mozilla::SMILAnimationFunction SMILAnimationFunction;
 
   /*
    * Sets the owning animation element which this class uses to convert between
    * container times and to register timebase elements.
    */
   void SetAnimationElement(mozilla::dom::SVGAnimationElement* aElement);
 
   /*
@@ -189,17 +190,17 @@ class nsSMILTimedElement {
    * In Schmitz's model it is possible to associate several time clients with
    * a timed element but for now we only allow one.
    *
    * @param aClient   The time client to associate. Any previous time client
    *                  will be disassociated and no longer sampled. Setting this
    *                  to nullptr will simply disassociate the previous client,
    * if any.
    */
-  void SetTimeClient(nsSMILAnimationFunction* aClient);
+  void SetTimeClient(SMILAnimationFunction* aClient);
 
   /**
    * Samples the object at the given container time. Timing intervals are
    * updated and if this element is active at the given time the associated time
    * client will be sampled with the appropriate simple time.
    *
    * @param aContainerTime The container time at which to sample.
    */
@@ -575,17 +576,17 @@ class nsSMILTimedElement {
   };
   nsSMILRestartMode mRestartMode;
   static const nsAttrValue::EnumTable sRestartModeTable[];
 
   InstanceTimeList mBeginInstances;
   InstanceTimeList mEndInstances;
   uint32_t mInstanceSerialIndex;
 
-  nsSMILAnimationFunction* mClient;
+  SMILAnimationFunction* mClient;
   mozilla::UniquePtr<nsSMILInterval> mCurrentInterval;
   IntervalList mOldIntervals;
   uint32_t mCurrentRepeatIteration;
   nsSMILMilestone mPrevRegisteredMilestone;
   static const nsSMILMilestone sMaxMilestone;
   static const uint8_t sMaxNumIntervals;
   static const uint8_t sMaxNumInstanceTimes;
 
--- a/dom/svg/SVGAnimateElement.cpp
+++ b/dom/svg/SVGAnimateElement.cpp
@@ -26,14 +26,14 @@ SVGAnimateElement::SVGAnimateElement(
 
 //----------------------------------------------------------------------
 // nsINode methods
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGAnimateElement)
 
 //----------------------------------------------------------------------
 
-nsSMILAnimationFunction& SVGAnimateElement::AnimationFunction() {
+SMILAnimationFunction& SVGAnimateElement::AnimationFunction() {
   return mAnimationFunction;
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/svg/SVGAnimateElement.h
+++ b/dom/svg/SVGAnimateElement.h
@@ -4,41 +4,41 @@
  * 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/. */
 
 #ifndef mozilla_dom_SVGAnimateElement_h
 #define mozilla_dom_SVGAnimateElement_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/SVGAnimationElement.h"
-#include "nsSMILAnimationFunction.h"
+#include "mozilla/SMILAnimationFunction.h"
 
 nsresult NS_NewSVGAnimateElement(
     nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
 
 namespace mozilla {
 namespace dom {
 
 class SVGAnimateElement final : public SVGAnimationElement {
  protected:
   explicit SVGAnimateElement(
       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
 
-  nsSMILAnimationFunction mAnimationFunction;
+  SMILAnimationFunction mAnimationFunction;
   friend nsresult(::NS_NewSVGAnimateElement(
       nsIContent** aResult,
       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aGivenProto) override;
 
  public:
   // nsINode
   virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
 
   // SVGAnimationElement
-  virtual nsSMILAnimationFunction& AnimationFunction() override;
+  virtual SMILAnimationFunction& AnimationFunction() override;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_SVGAnimateElement_h
--- a/dom/svg/SVGAnimateMotionElement.cpp
+++ b/dom/svg/SVGAnimateMotionElement.cpp
@@ -26,17 +26,17 @@ SVGAnimateMotionElement::SVGAnimateMotio
 
 //----------------------------------------------------------------------
 // nsINode methods
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGAnimateMotionElement)
 
 //----------------------------------------------------------------------
 
-nsSMILAnimationFunction& SVGAnimateMotionElement::AnimationFunction() {
+SMILAnimationFunction& SVGAnimateMotionElement::AnimationFunction() {
   return mAnimationFunction;
 }
 
 bool SVGAnimateMotionElement::GetTargetAttributeName(
     int32_t* aNamespaceID, nsAtom** aLocalName) const {
   // <animateMotion> doesn't take an attributeName, since it doesn't target an
   // 'attribute' per se.  We'll use a unique dummy attribute-name so that our
   // nsSMILTargetIdentifier logic (which requires a attribute name) still works.
--- a/dom/svg/SVGAnimateMotionElement.h
+++ b/dom/svg/SVGAnimateMotionElement.h
@@ -30,17 +30,17 @@ class SVGAnimateMotionElement final : pu
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aGivenProto) override;
 
  public:
   // nsINode specializations
   virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
 
   // SVGAnimationElement
-  virtual nsSMILAnimationFunction& AnimationFunction() override;
+  virtual SMILAnimationFunction& AnimationFunction() override;
   virtual bool GetTargetAttributeName(int32_t* aNamespaceID,
                                       nsAtom** aLocalName) const override;
 
   // SVGElement
   virtual nsStaticAtom* GetPathDataAttrName() const override {
     return nsGkAtoms::path;
   }
 
--- a/dom/svg/SVGAnimateTransformElement.cpp
+++ b/dom/svg/SVGAnimateTransformElement.cpp
@@ -46,14 +46,14 @@ bool SVGAnimateTransformElement::ParseAt
 
 //----------------------------------------------------------------------
 // nsINode methods
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGAnimateTransformElement)
 
 //----------------------------------------------------------------------
 
-nsSMILAnimationFunction& SVGAnimateTransformElement::AnimationFunction() {
+SMILAnimationFunction& SVGAnimateTransformElement::AnimationFunction() {
   return mAnimationFunction;
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/svg/SVGAnimateTransformElement.h
+++ b/dom/svg/SVGAnimateTransformElement.h
@@ -4,30 +4,30 @@
  * 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/. */
 
 #ifndef mozilla_dom_SVGAnimateTransformElement_h
 #define mozilla_dom_SVGAnimateTransformElement_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/SVGAnimationElement.h"
-#include "nsSMILAnimationFunction.h"
+#include "mozilla/SMILAnimationFunction.h"
 
 nsresult NS_NewSVGAnimateTransformElement(
     nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
 
 namespace mozilla {
 namespace dom {
 
 class SVGAnimateTransformElement final : public SVGAnimationElement {
  protected:
   explicit SVGAnimateTransformElement(
       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
 
-  nsSMILAnimationFunction mAnimationFunction;
+  SMILAnimationFunction mAnimationFunction;
   friend nsresult(::NS_NewSVGAnimateTransformElement(
       nsIContent** aResult,
       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aGivenProto) override;
 
  public:
@@ -36,15 +36,15 @@ class SVGAnimateTransformElement final :
 
   // Element specializations
   virtual bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
                               const nsAString& aValue,
                               nsIPrincipal* aMaybeScriptedPrincipal,
                               nsAttrValue& aResult) override;
 
   // SVGAnimationElement
-  virtual nsSMILAnimationFunction& AnimationFunction() override;
+  virtual SMILAnimationFunction& AnimationFunction() override;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_SVGAnimateTransformElement_h
--- a/dom/svg/SVGAnimationElement.cpp
+++ b/dom/svg/SVGAnimationElement.cpp
@@ -4,17 +4,17 @@
  * 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/. */
 
 #include "mozilla/dom/SVGAnimationElement.h"
 #include "mozilla/dom/SVGSVGElement.h"
 #include "mozilla/dom/ElementInlines.h"
 #include "nsSMILTimeContainer.h"
 #include "SMILAnimationController.h"
-#include "nsSMILAnimationFunction.h"
+#include "SMILAnimationFunction.h"
 #include "nsContentUtils.h"
 #include "nsIContentInlines.h"
 #include "nsIURI.h"
 #include "prtime.h"
 
 namespace mozilla {
 namespace dom {
 
--- a/dom/svg/SVGAnimationElement.h
+++ b/dom/svg/SVGAnimationElement.h
@@ -58,17 +58,17 @@ class SVGAnimationElement : public SVGAn
                                 nsIPrincipal* aSubjectPrincipal,
                                 bool aNotify) override;
 
   Element* GetTargetElementContent();
   virtual bool GetTargetAttributeName(int32_t* aNamespaceID,
                                       nsAtom** aLocalName) const;
   nsSMILTimedElement& TimedElement();
   nsSMILTimeContainer* GetTimeContainer();
-  virtual nsSMILAnimationFunction& AnimationFunction() = 0;
+  virtual SMILAnimationFunction& AnimationFunction() = 0;
 
   virtual bool IsEventAttributeNameInternal(nsAtom* aName) override;
 
   // Utility methods for within SVG
   void ActivateByHyperlink();
 
   // WebIDL
   SVGElement* GetTargetElement();
--- a/dom/svg/SVGElement.h
+++ b/dom/svg/SVGElement.h
@@ -8,27 +8,27 @@
 #define __NS_SVGELEMENT_H__
 
 /*
   SVGElement is the base class for all SVG content elements.
   It implements all the common DOM interfaces and handles attributes.
 */
 
 #include "mozilla/Attributes.h"
+#include "mozilla/SVGContentUtils.h"
 #include "mozilla/dom/DOMRect.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/gfx/MatrixFwd.h"
 #include "nsAutoPtr.h"
 #include "nsChangeHint.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsError.h"
 #include "nsISupportsImpl.h"
 #include "nsStyledElement.h"
-#include "SVGContentUtils.h"
 #include "nsSVGClass.h"
 #include "gfxMatrix.h"
 
 class nsSVGAngle;
 class nsSVGBoolean;
 class nsSVGEnum;
 class nsSVGInteger;
 class nsSVGIntegerPair;
--- a/dom/svg/SVGElementFactory.h
+++ b/dom/svg/SVGElementFactory.h
@@ -37,17 +37,17 @@ typedef nsresult (*SVGContentCreatorFunc
       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, \
       mozilla::dom::FromParser aFromParser);
 
 #define SVG_FROM_PARSER_TAG(_tag, _classname)               \
   nsresult NS_NewSVG##_classname##Element(                  \
       nsIContent** aResult,                                 \
       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, \
       mozilla::dom::FromParser aFromParser);
-#include "SVGTagList.h"
+#include "mozilla/SVGTagList.h"
 #undef SVG_TAG
 #undef SVG_FROM_PARSER_TAG
 
 nsresult NS_NewSVGUnknownElement(
     nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
     mozilla::dom::FromParser aFromParser);
 
 #endif /* mozilla_dom_SVGElementFactory_h */
--- a/dom/svg/SVGMotionSMILAnimationFunction.cpp
+++ b/dom/svg/SVGMotionSMILAnimationFunction.cpp
@@ -74,41 +74,41 @@ bool SVGMotionSMILAnimationFunction::Set
              aAttribute == nsGkAtoms::values) {
     aResult.SetTo(aValue);
     MarkStaleIfAttributeAffectsPath(aAttribute);
     if (aParseResult) {
       *aParseResult = NS_OK;
     }
   } else {
     // Defer to superclass method
-    return nsSMILAnimationFunction::SetAttr(aAttribute, aValue, aResult,
-                                            aParseResult);
+    return SMILAnimationFunction::SetAttr(aAttribute, aValue, aResult,
+                                          aParseResult);
   }
 
   return true;
 }
 
 bool SVGMotionSMILAnimationFunction::UnsetAttr(nsAtom* aAttribute) {
   if (aAttribute == nsGkAtoms::keyPoints) {
     UnsetKeyPoints();
   } else if (aAttribute == nsGkAtoms::rotate) {
     UnsetRotate();
   } else if (aAttribute == nsGkAtoms::path || aAttribute == nsGkAtoms::by ||
              aAttribute == nsGkAtoms::from || aAttribute == nsGkAtoms::to ||
              aAttribute == nsGkAtoms::values) {
     MarkStaleIfAttributeAffectsPath(aAttribute);
   } else {
     // Defer to superclass method
-    return nsSMILAnimationFunction::UnsetAttr(aAttribute);
+    return SMILAnimationFunction::UnsetAttr(aAttribute);
   }
 
   return true;
 }
 
-nsSMILAnimationFunction::nsSMILCalcMode
+SMILAnimationFunction::nsSMILCalcMode
 SVGMotionSMILAnimationFunction::GetCalcMode() const {
   const nsAttrValue* value = GetAttr(nsGkAtoms::calcMode);
   if (!value) {
     return CALC_PACED;  // animateMotion defaults to calcMode="paced"
   }
 
   return nsSMILCalcMode(value->GetEnumValue());
 }
@@ -159,17 +159,17 @@ void SVGMotionSMILAnimationFunction::Reb
     // Apply 'from' value (or a dummy 0,0 'from' value)
     if (HasAttr(nsGkAtoms::from)) {
       const nsAString& fromStr = GetAttr(nsGkAtoms::from)->GetStringValue();
       success = pathGenerator.MoveToAbsolute(fromStr);
       mPathVertices.AppendElement(0.0, fallible);
     } else {
       // Create dummy 'from' value at 0,0, if we're doing by-animation.
       // (NOTE: We don't add the dummy 0-point to our list for *to-animation*,
-      // because the nsSMILAnimationFunction logic for to-animation doesn't
+      // because the SMILAnimationFunction logic for to-animation doesn't
       // expect a dummy value. It only expects one value: the final 'to' value.)
       pathGenerator.MoveToOrigin();
       if (!HasAttr(nsGkAtoms::to)) {
         mPathVertices.AppendElement(0.0, fallible);
       }
       success = true;
     }
 
@@ -315,29 +315,29 @@ nsresult SVGMotionSMILAnimationFunction:
   }
 
   return NS_OK;
 }
 
 void SVGMotionSMILAnimationFunction::CheckValueListDependentAttrs(
     uint32_t aNumValues) {
   // Call superclass method.
-  nsSMILAnimationFunction::CheckValueListDependentAttrs(aNumValues);
+  SMILAnimationFunction::CheckValueListDependentAttrs(aNumValues);
 
   // Added behavior: Do checks specific to keyPoints.
   CheckKeyPoints();
 }
 
 bool SVGMotionSMILAnimationFunction::IsToAnimation() const {
   // Rely on inherited method, but not if we have an <mpath> child or a |path|
   // attribute, because they'll override any 'to' attr we might have.
   // NOTE: We can't rely on mPathSourceType, because it might not have been
   // set to a useful value yet (or it might be stale).
   return !GetFirstMPathChild(mAnimationElement) && !HasAttr(nsGkAtoms::path) &&
-         nsSMILAnimationFunction::IsToAnimation();
+         SMILAnimationFunction::IsToAnimation();
 }
 
 void SVGMotionSMILAnimationFunction::CheckKeyPoints() {
   if (!HasAttr(nsGkAtoms::keyPoints)) return;
 
   // attribute is ignored for calcMode="paced" (even if it's got errors)
   if (GetCalcMode() == CALC_PACED) {
     SetKeyPointsErrorFlag(false);
--- a/dom/svg/SVGMotionSMILAnimationFunction.h
+++ b/dom/svg/SVGMotionSMILAnimationFunction.h
@@ -4,17 +4,17 @@
  * 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/. */
 
 #ifndef MOZILLA_SVGMOTIONSMILANIMATIONFUNCTION_H_
 #define MOZILLA_SVGMOTIONSMILANIMATIONFUNCTION_H_
 
 #include "mozilla/gfx/2D.h"
 #include "mozilla/RefPtr.h"
-#include "nsSMILAnimationFunction.h"
+#include "mozilla/SMILAnimationFunction.h"
 #include "nsTArray.h"
 #include "SVGMotionSMILType.h"  // for RotateType
 
 class nsAttrValue;
 class nsAtom;
 class nsIContent;
 class nsISMILAttr;
 class nsSMILValue;
@@ -23,20 +23,20 @@ namespace mozilla {
 
 namespace dom {
 class SVGMPathElement;
 }  // namespace dom
 
 //----------------------------------------------------------------------
 // SVGMotionSMILAnimationFunction
 //
-// Subclass of nsSMILAnimationFunction to support a few extra features offered
+// Subclass of SMILAnimationFunction to support a few extra features offered
 // by the <animateMotion> element.
 //
-class SVGMotionSMILAnimationFunction final : public nsSMILAnimationFunction {
+class SVGMotionSMILAnimationFunction final : public SMILAnimationFunction {
   typedef mozilla::gfx::Path Path;
 
  public:
   SVGMotionSMILAnimationFunction();
   virtual bool SetAttr(nsAtom* aAttribute, const nsAString& aValue,
                        nsAttrValue& aResult,
                        nsresult* aParseResult = nullptr) override;
   virtual bool UnsetAttr(nsAtom* aAttribute) override;
--- a/dom/svg/SVGSetElement.cpp
+++ b/dom/svg/SVGSetElement.cpp
@@ -26,14 +26,14 @@ SVGSetElement::SVGSetElement(
 
 //----------------------------------------------------------------------
 // nsINode methods
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGSetElement)
 
 //----------------------------------------------------------------------
 
-nsSMILAnimationFunction& SVGSetElement::AnimationFunction() {
+SMILAnimationFunction& SVGSetElement::AnimationFunction() {
   return mAnimationFunction;
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/svg/SVGSetElement.h
+++ b/dom/svg/SVGSetElement.h
@@ -4,41 +4,41 @@
  * 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/. */
 
 #ifndef mozilla_dom_SVGSetElement_h
 #define mozilla_dom_SVGSetElement_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/SVGAnimationElement.h"
-#include "nsSMILSetAnimationFunction.h"
+#include "mozilla/SMILSetAnimationFunction.h"
 
 nsresult NS_NewSVGSetElement(
     nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
 
 namespace mozilla {
 namespace dom {
 
 class SVGSetElement final : public SVGAnimationElement {
  protected:
   explicit SVGSetElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
 
-  nsSMILSetAnimationFunction mAnimationFunction;
+  SMILSetAnimationFunction mAnimationFunction;
 
   friend nsresult(::NS_NewSVGSetElement(
       nsIContent** aResult,
       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aGivenProto) override;
 
  public:
   // nsINode
   virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
 
   // SVGAnimationElement
-  virtual nsSMILAnimationFunction& AnimationFunction() override;
+  virtual SMILAnimationFunction& AnimationFunction() override;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_SVGSetElement_h
--- a/dom/svg/SVGTests.h
+++ b/dom/svg/SVGTests.h
@@ -2,19 +2,19 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #ifndef mozilla_dom_SVGTests_h
 #define mozilla_dom_SVGTests_h
 
+#include "nsCOMPtr.h"
 #include "nsStringFwd.h"
-#include "SVGStringList.h"
-#include "nsCOMPtr.h"
+#include "mozilla/SVGStringList.h"
 
 class nsAttrValue;
 class nsAtom;
 class nsStaticAtom;
 
 namespace mozilla {
 class DOMSVGStringList;
 
--- a/dom/svg/moz.build
+++ b/dom/svg/moz.build
@@ -7,16 +7,19 @@
 with Files("**"):
     BUG_COMPONENT = ("Core", "SVG")
 
 MOCHITEST_MANIFESTS += ['test/mochitest.ini']
 
 EXPORTS += [
     'nsSVGClass.h',
     'nsSVGFeatures.h',
+]
+
+EXPORTS.mozilla += [
     'SVGAttrValueWrapper.h',
     'SVGContentUtils.h',
     'SVGPreserveAspectRatio.h',
     'SVGStringList.h',
     'SVGTagList.h',
 ]
 
 EXPORTS.mozilla.dom += [
--- a/js/src/gc/Cell.h
+++ b/js/src/gc/Cell.h
@@ -346,23 +346,19 @@ bool TenuredCell::isInsideZone(JS::Zone*
   return zone == arena()->zone;
 }
 
 /* static */ MOZ_ALWAYS_INLINE void TenuredCell::readBarrier(
     TenuredCell* thing) {
   MOZ_ASSERT(!CurrentThreadIsIonCompiling());
   MOZ_ASSERT(thing);
   MOZ_ASSERT(CurrentThreadCanAccessZone(thing->zoneFromAnyThread()));
-
-  // It would be good if barriers were never triggered during collection, but
-  // at the moment this can happen e.g. when rekeying tables containing
-  // read-barriered GC things after a moving GC.
-  //
-  // TODO: Fix this and assert we're not collecting if we're on the active
-  // thread.
+  // Barriers should not be triggered on main thread while collecting.
+  MOZ_ASSERT_IF(CurrentThreadCanAccessRuntime(thing->runtimeFromAnyThread()),
+                !JS::RuntimeHeapIsCollecting());
 
   JS::shadow::Zone* shadowZone = thing->shadowZoneFromAnyThread();
   if (shadowZone->needsIncrementalBarrier()) {
     // Barriers are only enabled on the main thread and are disabled while
     // collecting.
     MOZ_ASSERT(!RuntimeFromMainThreadIsHeapMajorCollecting(shadowZone));
     Cell* tmp = thing;
     TraceManuallyBarrieredGenericPointerEdge(shadowZone->barrierTracer(), &tmp,
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -331,33 +331,36 @@ bool Zone::canCollect() {
   }
 
   // Zones that will be or are currently used by other threads cannot be
   // collected.
   return !createdForHelperThread();
 }
 
 void Zone::notifyObservingDebuggers() {
+  MOZ_ASSERT(JS::RuntimeHeapIsCollecting(),
+             "This method should be called during GC.");
+
   JSRuntime* rt = runtimeFromMainThread();
   JSContext* cx = rt->mainContextFromOwnThread();
 
   for (RealmsInZoneIter realms(this); !realms.done(); realms.next()) {
     RootedGlobalObject global(cx, realms->unsafeUnbarrieredMaybeGlobal());
     if (!global) {
       continue;
     }
 
     GlobalObject::DebuggerVector* dbgs = global->getDebuggers();
     if (!dbgs) {
       continue;
     }
 
     for (GlobalObject::DebuggerVector::Range r = dbgs->all(); !r.empty();
          r.popFront()) {
-      if (!r.front()->debuggeeIsBeingCollected(rt->gc.majorGCCount())) {
+      if (!r.front().unbarrieredGet()->debuggeeIsBeingCollected(rt->gc.majorGCCount())) {
 #ifdef DEBUG
         fprintf(stderr,
                 "OOM while notifying observing Debuggers of a GC: The "
                 "onGarbageCollection\n"
                 "hook will not be fired for this GC for some Debuggers!\n");
 #endif
         return;
       }
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -3033,17 +3033,20 @@ void Debugger::updateObservesAsmJSOnDebu
   auto existingCallback = global.realm()->getAllocationMetadataBuilder();
   return existingCallback && existingCallback != &SavedStacks::metadataBuilder;
 }
 
 /* static */ bool Debugger::isObservedByDebuggerTrackingAllocations(
     const GlobalObject& debuggee) {
   if (auto* v = debuggee.getDebuggers()) {
     for (auto p = v->begin(); p != v->end(); p++) {
-      if ((*p)->trackingAllocationSites && (*p)->enabled) {
+      // Use unbarrieredGet() to prevent triggering read barrier while
+      // collecting, this is safe as long as dbg does not escape.
+      Debugger* dbg = p->unbarrieredGet();
+      if (dbg->trackingAllocationSites && dbg->enabled) {
         return true;
       }
     }
   }
 
   return false;
 }
 
@@ -3171,16 +3174,18 @@ void Debugger::traceCrossCompartmentEdge
  *      that may yet be called.
  *   2. Mark breakpoint handlers.
  *
  * This happens during the iterative part of the GC mark phase. This method
  * returns true if it has to mark anything; GC calls it repeatedly until it
  * returns false.
  */
 /* static */ bool Debugger::markIteratively(GCMarker* marker) {
+  MOZ_ASSERT(JS::RuntimeHeapIsCollecting(),
+             "This method should be called during GC.");
   bool markedAny = false;
 
   // Find all Debugger objects in danger of GC. This code is a little
   // convoluted since the easiest way to find them is via their debuggees.
   JSRuntime* rt = marker->runtime();
   for (RealmsIter r(rt); !r.done(); r.next()) {
     if (r->isDebuggee()) {
       GlobalObject* global = r->unsafeUnbarrieredMaybeGlobal();
@@ -3188,17 +3193,17 @@ void Debugger::traceCrossCompartmentEdge
         continue;
       }
 
       // Every debuggee has at least one debugger, so in this case
       // getDebuggers can't return nullptr.
       const GlobalObject::DebuggerVector* debuggers = global->getDebuggers();
       MOZ_ASSERT(debuggers);
       for (auto p = debuggers->begin(); p != debuggers->end(); p++) {
-        Debugger* dbg = *p;
+        Debugger* dbg = p->unbarrieredGet();
 
         // dbg is a Debugger with at least one debuggee. Check three things:
         //   - dbg is actually in a compartment that is being marked
         //   - it isn't already marked
         //   - it actually has hooks that might be called
         GCPtrNativeObject& dbgobj = dbg->toJSObjectRef();
         if (!dbgobj->zone()->isGCMarking()) {
           continue;
@@ -4199,16 +4204,31 @@ static T* findDebuggerInVector(Debugger*
     if (*p == dbg) {
       break;
     }
   }
   MOZ_ASSERT(p != vec->end());
   return p;
 }
 
+// a ReadBarriered version for findDebuggerInVector
+// TODO: Bug 1515934 - findDebuggerInVector<T> triggers read barriers.
+static ReadBarriered<Debugger*>*
+findDebuggerInVector(Debugger* dbg,
+                     Vector<ReadBarriered<Debugger*>, 0, js::SystemAllocPolicy>* vec) {
+  ReadBarriered<Debugger*>* p;
+  for (p = vec->begin(); p != vec->end(); p++) {
+    if (p->unbarrieredGet() == dbg) {
+      break;
+    }
+  }
+  MOZ_ASSERT(p != vec->end());
+  return p;
+}
+
 void Debugger::removeDebuggeeGlobal(FreeOp* fop, GlobalObject* global,
                                     WeakGlobalObjectSet::Enum* debugEnum) {
   // The caller might have found global by enumerating this->debuggees; if
   // so, use HashSet::Enum::removeFront rather than HashSet::remove below,
   // to avoid invalidating the live enumerator.
   MOZ_ASSERT(debuggees.has(global));
   MOZ_ASSERT(debuggeeZones.has(global->zone()));
   MOZ_ASSERT_IF(debugEnum, debugEnum->front().unbarrieredGet() == global);
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -2573,17 +2573,18 @@ void DebugEnvironments::checkHashTablesA
    * This is called at the end of StoreBuffer::mark() to check that our
    * postbarriers have worked and that no hashtable keys (or values) are left
    * pointing into the nursery.
    */
   proxiedEnvs.checkAfterMovingGC();
   for (MissingEnvironmentMap::Range r = missingEnvs.all(); !r.empty();
        r.popFront()) {
     CheckGCThingAfterMovingGC(r.front().key().scope());
-    CheckGCThingAfterMovingGC(r.front().value().get());
+    // Use unbarrieredGet() to prevent triggering read barrier while collecting.
+    CheckGCThingAfterMovingGC(r.front().value().unbarrieredGet());
   }
   for (LiveEnvironmentMap::Range r = liveEnvs.all(); !r.empty(); r.popFront()) {
     CheckGCThingAfterMovingGC(r.front().key());
     CheckGCThingAfterMovingGC(r.front().value().scope_.get());
   }
 }
 #endif
 
--- a/js/src/vm/Realm.cpp
+++ b/js/src/vm/Realm.cpp
@@ -791,17 +791,19 @@ void Realm::updateDebuggerObservesFlag(u
              flag == DebuggerObservesCoverage || flag == DebuggerObservesAsmJS);
 
   GlobalObject* global =
       zone()->runtimeFromMainThread()->gc.isForegroundSweeping()
           ? unsafeUnbarrieredMaybeGlobal()
           : maybeGlobal();
   const GlobalObject::DebuggerVector* v = global->getDebuggers();
   for (auto p = v->begin(); p != v->end(); p++) {
-    Debugger* dbg = *p;
+    // Use unbarrieredGet() to prevent triggering read barrier while collecting,
+    // this is safe as long as dbg does not escape.
+    Debugger* dbg = p->unbarrieredGet();
     if (flag == DebuggerObservesAllExecution
             ? dbg->observesAllExecution()
             : flag == DebuggerObservesCoverage
                   ? dbg->observesCoverage()
                   : flag == DebuggerObservesAsmJS && dbg->observesAsmJS()) {
       debugModeBits_ |= flag;
       return;
     }
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -1671,39 +1671,44 @@ bool SavedStacks::getLocation(JSContext*
     }
   }
 
   locationp.set(p->value());
   return true;
 }
 
 void SavedStacks::chooseSamplingProbability(Realm* realm) {
-  GlobalObject* global = realm->maybeGlobal();
+  // Use unbarriered version to prevent triggering read barrier while collecting,
+  // this is safe as long as global does not escape.
+  GlobalObject* global = realm->unsafeUnbarrieredMaybeGlobal();
   if (!global) {
     return;
   }
 
   GlobalObject::DebuggerVector* dbgs = global->getDebuggers();
   if (!dbgs || dbgs->empty()) {
     return;
   }
 
   mozilla::DebugOnly<ReadBarriered<Debugger*>*> begin = dbgs->begin();
   mozilla::DebugOnly<bool> foundAnyDebuggers = false;
 
   double probability = 0;
-  for (auto dbgp = dbgs->begin(); dbgp < dbgs->end(); dbgp++) {
+  for (auto p = dbgs->begin(); p < dbgs->end(); p++) {
     // The set of debuggers had better not change while we're iterating,
     // such that the vector gets reallocated.
     MOZ_ASSERT(dbgs->begin() == begin);
+    // Use unbarrieredGet() to prevent triggering read barrier while collecting,
+    // this is safe as long as dbgp does not escape.
+    Debugger* dbgp = p->unbarrieredGet();
 
-    if ((*dbgp)->trackingAllocationSites && (*dbgp)->enabled) {
+    if (dbgp->trackingAllocationSites && dbgp->enabled) {
       foundAnyDebuggers = true;
       probability =
-          std::max((*dbgp)->allocationSamplingProbability, probability);
+          std::max(dbgp->allocationSamplingProbability, probability);
     }
   }
   MOZ_ASSERT(foundAnyDebuggers);
 
   if (!bernoulliSeeded) {
     mozilla::Array<uint64_t, 2> seed;
     GenerateXorShift128PlusSeed(seed);
     bernoulli.setRandomState(seed[0], seed[1]);
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -2286,22 +2286,22 @@ void Zone::fixupInitialShapeTable() {
     if (IsForwarded(shape)) {
       shape = Forwarded(shape);
       e.mutableFront().shape.set(shape);
     }
     shape->updateBaseShapeAfterMovingGC();
 
     // If the prototype has moved we have to rekey the entry.
     InitialShapeEntry entry = e.front();
-    if (entry.proto.proto().isObject() &&
-        IsForwarded(entry.proto.proto().toObject())) {
-      entry.proto.setProto(
-          TaggedProto(Forwarded(entry.proto.proto().toObject())));
+    // Use unbarrieredGet() to prevent triggering read barrier while collecting.
+    const TaggedProto& proto = entry.proto.proto().unbarrieredGet();
+    if (proto.isObject() && IsForwarded(proto.toObject())) {
+      entry.proto.setProto(TaggedProto(Forwarded(proto.toObject())));
       using Lookup = InitialShapeEntry::Lookup;
-      Lookup relookup(shape->getObjectClass(), Lookup::ShapeProto(entry.proto),
+      Lookup relookup(shape->getObjectClass(), Lookup::ShapeProto(proto),
                       shape->numFixedSlots(), shape->getObjectFlags());
       e.rekeyFront(relookup, entry);
     }
   }
 }
 
 void AutoRooterGetterSetter::Inner::trace(JSTracer* trc) {
   if ((attrs & JSPROP_GETTER) && *pgetter) {
--- a/layout/svg/SVGImageContext.h
+++ b/layout/svg/SVGImageContext.h
@@ -4,17 +4,17 @@
  * 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/. */
 
 #ifndef MOZILLA_SVGCONTEXT_H_
 #define MOZILLA_SVGCONTEXT_H_
 
 #include "mozilla/Maybe.h"
 #include "mozilla/SVGContextPaint.h"
-#include "SVGPreserveAspectRatio.h"
+#include "mozilla/SVGPreserveAspectRatio.h"
 #include "Units.h"
 
 class nsIFrame;
 
 namespace mozilla {
 
 class ComputedStyle;
 
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -1184,27 +1184,41 @@ function handleCriticalWriteResult(wrote
  * @throws if patch has a size of 0
  * @constructor
  */
 function UpdatePatch(patch) {
   this._properties = {};
   for (var i = 0; i < patch.attributes.length; ++i) {
     var attr = patch.attributes.item(i);
     switch (attr.name) {
+      case "xmlns":
+        // Don't save the XML namespace.
+        break;
       case "selected":
         this.selected = attr.value == "true";
         break;
       case "size":
         if (0 == parseInt(attr.value)) {
           LOG("UpdatePatch:init - 0-sized patch!");
           throw Cr.NS_ERROR_ILLEGAL_VALUE;
         }
         // fall through
+      case "type":
+      case "URL":
+      case "finalURL":
+      case "state":
+      case "errorCode":
+        this[attr.name] = attr.value;
+        break;
       default:
         this[attr.name] = attr.value;
+        // Save custom attributes when serializing to the local xml file but
+        // don't use this method for the expected attributes which are already
+        // handled in serialize.
+        this.setProperty(attr.name, attr.value);
         break;
     }
   }
 }
 UpdatePatch.prototype = {
   /**
    * See nsIUpdateService.idl
    */
@@ -1255,26 +1269,32 @@ UpdatePatch.prototype = {
     if (name in this._properties)
       this._properties[name].present = false;
     else
       throw Cr.NS_ERROR_FAILURE;
   },
 
   /**
    * See nsIPropertyBag.idl
+   *
+   * Note: this only contains the nsIPropertyBag name / value pairs and not the
+   *       nsIUpdatePatch name / value pairs.
    */
   get enumerator() {
     return this.enumerate();
   },
 
   * enumerate() {
-    for (var p in this._properties) {
-      let prop = this.properties[p].data;
-      if (prop) {
-        yield prop;
+    for (let propName in this._properties) {
+      if (this._properties[propName].present) {
+        // The nsIPropertyBag enumerator returns a nsISimpleEnumerator whose
+        // elements are nsIProperty objects.
+        yield { name: propName,
+                value: this._properties[propName].data,
+                QueryInterface: ChromeUtils.generateQI([Ci.nsIProperty])};
       }
     }
   },
 
   /**
    * See nsIPropertyBag.idl
    * Note: returns null instead of throwing when the property doesn't exist to
    *       simplify code and to silence warnings in debug builds.
@@ -1356,17 +1376,18 @@ function Update(update) {
 
   // Set the installDate value with the current time. If the update has an
   // installDate attribute this will be replaced with that value if it doesn't
   // equal 0.
   this.installDate = (new Date()).getTime();
 
   for (let i = 0; i < update.attributes.length; ++i) {
     var attr = update.attributes.item(i);
-    if (attr.value == "undefined") {
+    if (attr.name == "xmlns" || attr.value == "undefined") {
+      // Don't save the XML namespace or undefined values.
       continue;
     } else if (attr.name == "detailsURL") {
       this._detailsURL = attr.value;
     } else if (attr.name == "installDate" && attr.value) {
       let val = parseInt(attr.value);
       if (val) {
         this.installDate = val;
       }
@@ -1572,26 +1593,32 @@ Update.prototype = {
     if (name in this._properties)
       this._properties[name].present = false;
     else
       throw Cr.NS_ERROR_FAILURE;
   },
 
   /**
    * See nsIPropertyBag.idl
+   *
+   * Note: this only contains the nsIPropertyBag name value / pairs and not the
+   *       nsIUpdate name / value pairs.
    */
   get enumerator() {
     return this.enumerate();
   },
 
   * enumerate() {
-    for (var p in this._properties) {
-      let prop = this.properties[p].data;
-      if (prop) {
-        yield prop;
+    for (let propName in this._properties) {
+      if (this._properties[propName].present) {
+        // The nsIPropertyBag enumerator returns a nsISimpleEnumerator whose
+        // elements are nsIProperty objects.
+        yield { name: propName,
+                value: this._properties[propName].data,
+                QueryInterface: ChromeUtils.generateQI([Ci.nsIProperty])};
       }
     }
   },
 
   /**
    * See nsIPropertyBag.idl
    * Note: returns null instead of throwing when the property doesn't exist to
    *       simplify code and to silence warnings in debug builds.
--- a/toolkit/mozapps/update/tests/browser/browser.ini
+++ b/toolkit/mozapps/update/tests/browser/browser.ini
@@ -6,17 +6,16 @@ support-files =
   testConstants.js
 
 [browser_TelemetryUpdatePing.js]
 [browser_updateAutoPrefUI.js]
 skip-if = os != 'win'
 reason = Tests that update config is properly written to file, which is a Windows-only feature
 [browser_updatesBackgroundWindow.js]
 [browser_updatesBackgroundWindowFailures.js]
-skip-if = verify
 [browser_updatesBasicPrompt.js]
 skip-if = asan
 reason = Bug 1168003
 [browser_updatesBasicPromptNoStaging.js]
 [browser_updatesCantApply.js]
 skip-if = os != 'win'
 [browser_updatesCompleteAndPartialPatchesWithBadCompleteSize.js]
 [browser_updatesCompleteAndPartialPatchesWithBadPartialSize.js]
--- a/toolkit/mozapps/update/tests/browser/browser_TelemetryUpdatePing.js
+++ b/toolkit/mozapps/update/tests/browser/browser_TelemetryUpdatePing.js
@@ -24,17 +24,17 @@ add_task(async function testUpdatePingRe
   await archiveChecker.promiseInit();
 
   // Trigger an "update" ping by downloading and applying an update.
   await runUpdateTest(updateParams, 1, [
     {
       notificationId: "update-available",
       button: "button",
       beforeClick() {
-        checkWhatsNewLink("update-available-whats-new");
+        checkWhatsNewLink(window, "update-available-whats-new");
       },
     },
     {
       notificationId: "update-restart",
       button: "secondarybutton",
       cleanup() {
         AppMenuNotifications.removeNotification(/.*/);
       },
--- a/toolkit/mozapps/update/tests/browser/browser_updatesBackgroundWindow.js
+++ b/toolkit/mozapps/update/tests/browser/browser_updatesBackgroundWindow.js
@@ -16,17 +16,17 @@ add_task(async function testUpdatesBackg
          "The doorhanger is not showing for the background window");
       is(PanelUI.menuButton.getAttribute("badge-status"), "update-available",
          "The badge is showing for the background window");
       let popupShownPromise = BrowserTestUtils.waitForEvent(PanelUI.notificationPanel, "popupshown");
       await BrowserTestUtils.closeWindow(extraWindow);
       await SimpleTest.promiseFocus(window);
       await popupShownPromise;
 
-      checkWhatsNewLink("update-available-whats-new");
+      checkWhatsNewLink(window, "update-available-whats-new");
       let buttonEl = getNotificationButton(window, "update-available", "button");
       buttonEl.click();
     },
     {
       notificationId: "update-restart",
       button: "secondarybutton",
       cleanup() {
         AppMenuNotifications.removeNotification(/.*/);
--- a/toolkit/mozapps/update/tests/browser/browser_updatesBackgroundWindowFailures.js
+++ b/toolkit/mozapps/update/tests/browser/browser_updatesBackgroundWindowFailures.js
@@ -1,30 +1,30 @@
 add_task(async function testBackgroundWindowFailures() {
   const maxBackgroundErrors = 5;
   SpecialPowers.pushPrefEnv({set: [
     [PREF_APP_UPDATE_BACKGROUNDMAXERRORS, maxBackgroundErrors],
-    [PREF_APP_UPDATE_DOWNLOADPROMPTMAXATTEMPTS, 2],
+    [PREF_APP_UPDATE_DOWNLOADPROMPT_MAXATTEMPTS, 2],
   ]});
 
   let updateParams = "badURL=1";
   let extraWindow = await BrowserTestUtils.openNewBrowserWindow();
   await SimpleTest.promiseFocus(extraWindow);
 
   function getBackgroundWindowHandler(destroyWindow) {
     return async function() {
       await BrowserTestUtils.waitForCondition(() => PanelUI.menuButton.hasAttribute("badge-status"),
                                               "Background window has a badge.");
 
       is(PanelUI.notificationPanel.state, "closed",
          "The doorhanger is not showing for the background window");
       is(PanelUI.menuButton.getAttribute("badge-status"), "update-available",
          "The badge is showing for the background window");
 
-      checkWhatsNewLink("update-available-whats-new");
+      checkWhatsNewLink(extraWindow, "update-available-whats-new");
       let buttonEl = getNotificationButton(extraWindow, "update-available", "button");
       buttonEl.click();
 
       if (destroyWindow) {
         await BrowserTestUtils.closeWindow(extraWindow);
         await SimpleTest.promiseFocus(window);
       }
     };
--- a/toolkit/mozapps/update/tests/browser/browser_updatesBasicPrompt.js
+++ b/toolkit/mozapps/update/tests/browser/browser_updatesBasicPrompt.js
@@ -7,17 +7,17 @@ add_task(async function testBasicPrompt(
   let updateParams = "promptWaitTime=0";
   gUseTestUpdater = true;
 
   await runUpdateTest(updateParams, 1, [
     {
       notificationId: "update-available",
       button: "button",
       beforeClick() {
-        checkWhatsNewLink("update-available-whats-new");
+        checkWhatsNewLink(window, "update-available-whats-new");
       },
     },
     {
       notificationId: "update-restart",
       button: "secondarybutton",
       cleanup() {
         AppMenuNotifications.removeNotification(/.*/);
       },
--- a/toolkit/mozapps/update/tests/browser/browser_updatesBasicPromptNoStaging.js
+++ b/toolkit/mozapps/update/tests/browser/browser_updatesBasicPromptNoStaging.js
@@ -6,17 +6,17 @@ add_task(async function testBasicPromptN
 
   let updateParams = "promptWaitTime=0";
 
   await runUpdateTest(updateParams, 1, [
     {
       notificationId: "update-available",
       button: "button",
       beforeClick() {
-        checkWhatsNewLink("update-available-whats-new");
+        checkWhatsNewLink(window, "update-available-whats-new");
       },
     },
     {
       notificationId: "update-restart",
       button: "secondarybutton",
       cleanup() {
         AppMenuNotifications.removeNotification(/.*/);
       },
--- a/toolkit/mozapps/update/tests/browser/browser_updatesCompleteAndPartialPatchesWithBadSizes.js
+++ b/toolkit/mozapps/update/tests/browser/browser_updatesCompleteAndPartialPatchesWithBadSizes.js
@@ -1,10 +1,12 @@
 add_task(async function testCompleteAndPartialPatchesWithBadSizes() {
-  SpecialPowers.pushPrefEnv({set: [[PREF_APP_UPDATE_DOWNLOADPROMPTMAXATTEMPTS, 2]]});
+  SpecialPowers.pushPrefEnv({set: [
+    [PREF_APP_UPDATE_DOWNLOADPROMPT_MAXATTEMPTS, 2],
+  ]});
   let updateParams = "invalidPartialSize=1&invalidCompleteSize=1";
 
   await runUpdateTest(updateParams, 1, [
     {
       // if we fail maxBackgroundErrors download attempts, then we want to
       // first show the user an update available prompt.
       notificationId: "update-available",
       button: "button",
@@ -15,17 +17,17 @@ add_task(async function testCompleteAndP
     },
     {
       // if we have only an invalid patch, then something's wrong and we don't
       // have an automatic way to fix it, so show the manual update
       // doorhanger.
       notificationId: "update-manual",
       button: "button",
       beforeClick() {
-        checkWhatsNewLink("update-manual-whats-new");
+        checkWhatsNewLink(window, "update-manual-whats-new");
       },
       async cleanup() {
         await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
         is(gBrowser.selectedBrowser.currentURI.spec,
            URL_MANUAL_UPDATE, "Landed on manual update page.");
         gBrowser.removeTab(gBrowser.selectedTab);
       },
     },
--- a/toolkit/mozapps/update/tests/browser/browser_updatesCompletePatchApplyFailure.js
+++ b/toolkit/mozapps/update/tests/browser/browser_updatesCompletePatchApplyFailure.js
@@ -6,17 +6,17 @@ add_task(async function testCompletePatc
   await runUpdateProcessingTest(updates, [
     {
       // if we have only an invalid patch, then something's wrong and we don't
       // have an automatic way to fix it, so show the manual update
       // doorhanger.
       notificationId: "update-manual",
       button: "button",
       beforeClick() {
-        checkWhatsNewLink("update-manual-whats-new");
+        checkWhatsNewLink(window, "update-manual-whats-new");
       },
       async cleanup() {
         await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
         is(gBrowser.selectedBrowser.currentURI.spec,
            URL_MANUAL_UPDATE, "Landed on manual update page.");
         gBrowser.removeTab(gBrowser.selectedTab);
       },
     },
--- a/toolkit/mozapps/update/tests/browser/browser_updatesCompletePatchWithBadCompleteSize.js
+++ b/toolkit/mozapps/update/tests/browser/browser_updatesCompletePatchWithBadCompleteSize.js
@@ -1,10 +1,12 @@
 add_task(async function testCompletePatchWithBadCompleteSize() {
-  SpecialPowers.pushPrefEnv({set: [[PREF_APP_UPDATE_DOWNLOADPROMPTMAXATTEMPTS, 2]]});
+  SpecialPowers.pushPrefEnv({set: [
+    [PREF_APP_UPDATE_DOWNLOADPROMPT_MAXATTEMPTS, 2],
+  ]});
 
   let updateParams = "completePatchOnly=1&invalidCompleteSize=1";
 
   await runUpdateTest(updateParams, 1, [
     {
       // if we fail maxBackgroundErrors download attempts, then we want to
       // first show the user an update available prompt.
       notificationId: "update-available",
@@ -16,17 +18,17 @@ add_task(async function testCompletePatc
     },
     {
       // if we have only an invalid patch, then something's wrong and we don't
       // have an automatic way to fix it, so show the manual update
       // doorhanger.
       notificationId: "update-manual",
       button: "button",
       beforeClick() {
-        checkWhatsNewLink("update-manual-whats-new");
+        checkWhatsNewLink(window, "update-manual-whats-new");
       },
       async cleanup() {
         await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
         is(gBrowser.selectedBrowser.currentURI.spec,
            URL_MANUAL_UPDATE, "Landed on manual update page.");
         gBrowser.removeTab(gBrowser.selectedTab);
       },
     },
--- a/toolkit/mozapps/update/tests/browser/browser_updatesDownloadFailures.js
+++ b/toolkit/mozapps/update/tests/browser/browser_updatesDownloadFailures.js
@@ -1,13 +1,13 @@
 add_task(async function testDownloadFailures() {
   const maxBackgroundErrors = 5;
   SpecialPowers.pushPrefEnv({set: [
     [PREF_APP_UPDATE_BACKGROUNDMAXERRORS, maxBackgroundErrors],
-    [PREF_APP_UPDATE_DOWNLOADPROMPTMAXATTEMPTS, 2],
+    [PREF_APP_UPDATE_DOWNLOADPROMPT_MAXATTEMPTS, 2],
   ]});
   let updateParams = "badURL=1";
 
   await runUpdateTest(updateParams, 1, [
     {
       // if we fail maxBackgroundErrors download attempts, then we want to
       // first show the user an update available prompt.
       notificationId: "update-available",
--- a/toolkit/mozapps/update/tests/browser/browser_updatesMalformedXml.js
+++ b/toolkit/mozapps/update/tests/browser/browser_updatesMalformedXml.js
@@ -10,17 +10,17 @@ add_task(async function testMalformedXml
 
   await runUpdateTest(updateParams, maxBackgroundErrors, [
     {
       // if we fail 10 check attempts, then we want to just show the user a manual update
       // workflow.
       notificationId: "update-manual",
       button: "button",
       beforeClick() {
-        checkWhatsNewLink("update-manual-whats-new", updateDetailsUrl);
+        checkWhatsNewLink(window, "update-manual-whats-new", updateDetailsUrl);
       },
       async cleanup() {
         await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
         is(gBrowser.selectedBrowser.currentURI.spec,
            URL_MANUAL_UPDATE, "Landed on manual update page.");
         gBrowser.removeTab(gBrowser.selectedTab);
       },
     },
--- a/toolkit/mozapps/update/tests/browser/browser_updatesPartialPatchApplyFailure.js
+++ b/toolkit/mozapps/update/tests/browser/browser_updatesPartialPatchApplyFailure.js
@@ -8,17 +8,17 @@ add_task(async function testPartialPatch
   await runUpdateProcessingTest(updates, [
     {
       // if we have only an invalid patch, then something's wrong and we don't
       // have an automatic way to fix it, so show the manual update
       // doorhanger.
       notificationId: "update-manual",
       button: "button",
       beforeClick() {
-        checkWhatsNewLink("update-manual-whats-new");
+        checkWhatsNewLink(window, "update-manual-whats-new");
       },
       async cleanup() {
         await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
         is(gBrowser.selectedBrowser.currentURI.spec,
            URL_MANUAL_UPDATE, "Landed on manual update page.");
         gBrowser.removeTab(gBrowser.selectedTab);
       },
     },
--- a/toolkit/mozapps/update/tests/browser/browser_updatesPartialPatchApplyFailureWithCompleteValidationFailure.js
+++ b/toolkit/mozapps/update/tests/browser/browser_updatesPartialPatchApplyFailureWithCompleteValidationFailure.js
@@ -1,12 +1,14 @@
 add_task(async function testPartialPatchApplyFailureWithCompleteValidationFailure() {
   // because of the way we're simulating failure, we have to just pretend we've already
   // retried.
-  SpecialPowers.pushPrefEnv({set: [[PREF_APP_UPDATE_DOWNLOADPROMPTMAXATTEMPTS, 0]]});
+  SpecialPowers.pushPrefEnv({set: [
+    [PREF_APP_UPDATE_DOWNLOADPROMPT_MAXATTEMPTS, 0],
+  ]});
 
   let patchProps = {type: "partial",
                     state: STATE_PENDING};
   let patches = getLocalPatchString(patchProps);
   patchProps = {size: "1234",
                 selected: "false"};
   patches += getLocalPatchString(patchProps);
   let updateProps = {isCompleteUpdate: "false"};
@@ -15,17 +17,17 @@ add_task(async function testPartialPatch
   await runUpdateProcessingTest(updates, [
     {
       // if we have only an invalid patch, then something's wrong and we don't
       // have an automatic way to fix it, so show the manual update
       // doorhanger.
       notificationId: "update-manual",
       button: "button",
       beforeClick() {
-        checkWhatsNewLink("update-manual-whats-new");
+        checkWhatsNewLink(window, "update-manual-whats-new");
       },
       async cleanup() {
         await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
         is(gBrowser.selectedBrowser.currentURI.spec,
            URL_MANUAL_UPDATE, "Landed on manual update page.");
         gBrowser.removeTab(gBrowser.selectedTab);
       },
     },
--- a/toolkit/mozapps/update/tests/browser/browser_updatesPartialPatchWithBadPartialSize.js
+++ b/toolkit/mozapps/update/tests/browser/browser_updatesPartialPatchWithBadPartialSize.js
@@ -1,10 +1,12 @@
 add_task(async function testPartialPatchWithBadPartialSize() {
-  SpecialPowers.pushPrefEnv({set: [[PREF_APP_UPDATE_DOWNLOADPROMPTMAXATTEMPTS, 2]]});
+  SpecialPowers.pushPrefEnv({set: [
+    [PREF_APP_UPDATE_DOWNLOADPROMPT_MAXATTEMPTS, 2],
+  ]});
   let updateParams = "partialPatchOnly=1&invalidPartialSize=1";
 
   await runUpdateTest(updateParams, 1, [
     {
       // if we fail maxBackgroundErrors download attempts, then we want to
       // first show the user an update available prompt.
       notificationId: "update-available",
       button: "button",
@@ -15,17 +17,17 @@ add_task(async function testPartialPatch
     },
     {
       // if we have only an invalid patch, then something's wrong and we don't
       // have an automatic way to fix it, so show the manual update
       // doorhanger.
       notificationId: "update-manual",
       button: "button",
       beforeClick() {
-        checkWhatsNewLink("update-manual-whats-new");
+        checkWhatsNewLink(window, "update-manual-whats-new");
       },
       async cleanup() {
         await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
         is(gBrowser.selectedBrowser.currentURI.spec,
            URL_MANUAL_UPDATE, "Landed on manual update page.");
         gBrowser.removeTab(gBrowser.selectedTab);
       },
     },
--- a/toolkit/mozapps/update/tests/browser/head.js
+++ b/toolkit/mozapps/update/tests/browser/head.js
@@ -278,41 +278,44 @@ function waitForEvent(topic, status = nu
       }
     },
   }, topic));
 }
 
 /**
  * Gets the specified button for the notification.
  *
- * @param  window
+ * @param  win
  *         The window to get the notification button for.
  * @param  notificationId
  *         The ID of the notification to get the button for.
  * @param  button
  *         The anonid of the button to get.
+ * @return The button element.
  */
 function getNotificationButton(win, notificationId, button) {
   let notification = win.document.getElementById(`appMenu-${notificationId}-notification`);
   is(notification.hidden, false, `${notificationId} notification is showing`);
   return win.document.getAnonymousElementByAttribute(notification, "anonid", button);
 }
 
 /**
  * Ensures that the "What's new" link with the provided ID is displayed and
  * matches the url parameter provided. If no URL is provided, it will instead
  * ensure that the link matches the default link URL.
  *
+ * @param  win
+ *         The window to get the "What's new" link for.
  * @param  id
  *         The ID of the "What's new" link element.
  * @param  url (optional)
  *         The URL to check against. If none is provided, a default will be used.
  */
-function checkWhatsNewLink(id, url) {
-  let whatsNewLink = document.getElementById(id);
+function checkWhatsNewLink(win, id, url) {
+  let whatsNewLink = win.document.getElementById(id);
   is(whatsNewLink.href,
      url || URL_HTTP_UPDATE_SJS + "?uiURL=DETAILS",
      "What's new link points to the test_details URL");
   is(whatsNewLink.hidden, false, "What's new link is not hidden.");
 }
 
 /**
  * For tests that use the test updater restores the backed up real updater if
--- a/toolkit/mozapps/update/tests/data/shared.js
+++ b/toolkit/mozapps/update/tests/data/shared.js
@@ -12,17 +12,17 @@ ChromeUtils.defineModuleGetter(this, "Up
 
 const PREF_APP_UPDATE_AUTO                       = "app.update.auto";
 const PREF_APP_UPDATE_BACKGROUNDERRORS           = "app.update.backgroundErrors";
 const PREF_APP_UPDATE_BACKGROUNDMAXERRORS        = "app.update.backgroundMaxErrors";
 const PREF_APP_UPDATE_CANCELATIONS               = "app.update.cancelations";
 const PREF_APP_UPDATE_CHANNEL                    = "app.update.channel";
 const PREF_APP_UPDATE_DOORHANGER                 = "app.update.doorhanger";
 const PREF_APP_UPDATE_DOWNLOADPROMPTATTEMPTS     = "app.update.download.attempts";
-const PREF_APP_UPDATE_DOWNLOADPROMPTMAXATTEMPTS  = "app.update.download.maxAttempts";
+const PREF_APP_UPDATE_DOWNLOADPROMPT_MAXATTEMPTS = "app.update.download.maxAttempts";
 const PREF_APP_UPDATE_DISABLEDFORTESTING         = "app.update.disabledForTesting";
 const PREF_APP_UPDATE_IDLETIME                   = "app.update.idletime";
 const PREF_APP_UPDATE_LOG                        = "app.update.log";
 const PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED        = "app.update.notifiedUnsupported";
 const PREF_APP_UPDATE_PROMPTWAITTIME             = "app.update.promptWaitTime";
 const PREF_APP_UPDATE_RETRYTIMEOUT               = "app.update.socket.retryTimeout";
 const PREF_APP_UPDATE_SERVICE_ENABLED            = "app.update.service.enabled";
 const PREF_APP_UPDATE_SILENT                     = "app.update.silent";
--- a/toolkit/mozapps/update/tests/data/sharedUpdateXML.js
+++ b/toolkit/mozapps/update/tests/data/sharedUpdateXML.js
@@ -157,16 +157,18 @@ function getRemotePatchString(aPatchProp
       if (gURLData) {
         return gURLData + FILE_SIMPLE_MAR;
       }
       return null;
     },
     set url(val) {
       this._url = val;
     },
+    custom1: null,
+    custom2: null,
     size: SIZE_SIMPLE_MAR,
   };
 
   for (let name in aPatchProps) {
     patchProps[name] = aPatchProps[name];
   }
 
   return getPatchString(patchProps) + "/>";
@@ -269,16 +271,18 @@ function getLocalUpdateString(aUpdatePro
  *         See patchProps below for possible object names.
  * @return The string representing a patch element for a local update xml file.
  */
 function getLocalPatchString(aPatchProps) {
   const patchProps = {
     type: "complete",
     url: gURLData + FILE_SIMPLE_MAR,
     size: SIZE_SIMPLE_MAR,
+    custom1: null,
+    custom2: null,
     selected: "true",
     state: STATE_SUCCEEDED,
   };
 
   for (let name in aPatchProps) {
     patchProps[name] = aPatchProps[name];
   }
 
@@ -330,13 +334,17 @@ function getUpdateString(aUpdateProps) {
  *         An object containing non default test values for an nsIUpdatePatch.
  *         See the patchProps property names below for possible object names.
  * @return The string representing a patch element for an update xml file.
  */
 function getPatchString(aPatchProps) {
   let type = "type=\"" + aPatchProps.type + "\" ";
   let url = "URL=\"" + aPatchProps.url + "\" ";
   let size = "size=\"" + aPatchProps.size + "\"";
+  let custom1 = aPatchProps.custom1 ? aPatchProps.custom1 + " " : "";
+  let custom2 = aPatchProps.custom2 ? aPatchProps.custom2 + " " : "";
   return "<patch " +
          type +
          url +
+         custom1 +
+         custom2 +
          size;
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js
@@ -11,17 +11,19 @@ function run_test() {
             "prior to bug 530872");
 
   setUpdateChannel("test_channel");
 
   let patchProps = {type: "partial",
                     url: "http://partial/",
                     size: "86",
                     selected: "true",
-                    state: STATE_PENDING};
+                    state: STATE_PENDING,
+                    custom1: "custom1_attr=\"custom1 patch value\"",
+                    custom2: "custom2_attr=\"custom2 patch value\""};
   let patches = getLocalPatchString(patchProps);
   let updateProps = {type: "major",
                      name: "New",
                      displayVersion: "version 4",
                      appVersion: "4.0",
                      buildID: "20070811053724",
                      detailsURL: "http://details1/",
                      serviceURL: "http://service1/",
@@ -37,17 +39,19 @@ function run_test() {
   let updates = getLocalUpdateString(updateProps, patches);
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
   writeStatusFile(STATE_SUCCEEDED);
 
   patchProps = {type: "complete",
                 url: "http://complete/",
                 size: "75",
                 selected: "true",
-                state: STATE_FAILED};
+                state: STATE_FAILED,
+                custom1: "custom3_attr=\"custom3 patch value\"",
+                custom2: "custom4_attr=\"custom4 patch value\""};
   patches = getLocalPatchString(patchProps);
   updateProps = {type: "minor",
                  name: "Existing",
                  appVersion: "3.0",
                  detailsURL: "http://details2/",
                  serviceURL: "http://service2/",
                  statusText: getString("patchApplyFailure"),
                  isCompleteUpdate: "true",
@@ -61,17 +65,17 @@ function run_test() {
 
   standardInit();
 
   Assert.ok(!gUpdateManager.activeUpdate,
             "the update manager activeUpdate attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(gUpdateManager.updateCount, 2,
                "the update manager updateCount attribute" + MSG_SHOULD_EQUAL);
 
-  debugDump("checking the activeUpdate properties");
+  debugDump("checking the first update properties");
   let update = gUpdateManager.getUpdateAt(0).QueryInterface(Ci.nsIWritablePropertyBag);
   Assert.equal(update.state, STATE_SUCCEEDED,
                "the update state attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(update.type, "major",
                "the update type attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(update.name, "New",
                "the update name attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(update.displayVersion, "version 4",
@@ -97,31 +101,82 @@ function run_test() {
                "the update promptWaitTime attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(update.previousAppVersion, "3.0",
                "the update previousAppVersion attribute" + MSG_SHOULD_EQUAL);
   // Custom attributes
   Assert.equal(update.getProperty("custom1_attr"), "custom1 value",
                "the update custom1_attr property" + MSG_SHOULD_EQUAL);
   Assert.equal(update.getProperty("custom2_attr"), "custom2 value",
                "the update custom2_attr property" + MSG_SHOULD_EQUAL);
+  // nsIPropertyBag enumerator
+  debugDump("checking the first update enumerator");
+  let e = update.enumerator;
+  Assert.ok(e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
+  let prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom1_attr",
+               "the first property name" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.value, "custom1 value",
+               "the first property value" + MSG_SHOULD_EQUAL);
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom2_attr",
+               "the second property name" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.value, "custom2 value",
+               "the second property value" + MSG_SHOULD_EQUAL);
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.equal(prop.name, "foregroundDownload",
+               "the third property name" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.value, "true",
+               "the third property value" + MSG_SHOULD_EQUAL);
+  Assert.ok(!e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
 
-  debugDump("checking the activeUpdate patch properties");
-  let patch = update.selectedPatch;
+  debugDump("checking the first update patch properties");
+  let patch = update.selectedPatch.QueryInterface(Ci.nsIWritablePropertyBag);
   Assert.equal(patch.type, "partial",
                "the update patch type attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.URL, "http://partial/",
                "the update patch URL attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.size, "86",
                "the update patch size attribute" + MSG_SHOULD_EQUAL);
   Assert.ok(!!patch.selected,
             "the update patch selected attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.state, STATE_SUCCEEDED,
                "the update patch state attribute" + MSG_SHOULD_EQUAL);
+  Assert.equal(patch.getProperty("custom1_attr"), "custom1 patch value",
+               "the update patch custom1_attr property" + MSG_SHOULD_EQUAL);
+  Assert.equal(patch.getProperty("custom2_attr"), "custom2 patch value",
+               "the update patch custom2_attr property" + MSG_SHOULD_EQUAL);
+  // nsIPropertyBag enumerator
+  debugDump("checking the first update patch enumerator");
+  e = patch.enumerator;
+  Assert.ok(e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom1_attr",
+               "the first property name" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.value, "custom1 patch value",
+               "the first property value" + MSG_SHOULD_EQUAL);
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom2_attr",
+               "the second property name" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.value, "custom2 patch value",
+               "the second property value" + MSG_SHOULD_EQUAL);
+  Assert.ok(!e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
 
-  debugDump("checking the first update properties");
+  debugDump("checking the second update properties");
   update = gUpdateManager.getUpdateAt(1).QueryInterface(Ci.nsIWritablePropertyBag);
   Assert.equal(update.state, STATE_FAILED,
                "the update state attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(update.name, "Existing",
                "the update name attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(update.type, "minor",
                "the update type attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(update.displayVersion, "3.0",
@@ -146,29 +201,80 @@ function run_test() {
                "the update promptWaitTime attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(update.previousAppVersion, null,
                "the update previousAppVersion attribute" + MSG_SHOULD_EQUAL);
   // Custom attributes
   Assert.equal(update.getProperty("custom3_attr"), "custom3 value",
                "the update custom3_attr property" + MSG_SHOULD_EQUAL);
   Assert.equal(update.getProperty("custom4_attr"), "custom4 value",
                "the update custom4_attr property" + MSG_SHOULD_EQUAL);
+  // nsIPropertyBag enumerator
+  debugDump("checking the second update enumerator");
+  e = update.enumerator;
+  Assert.ok(e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom3_attr",
+               "the first property name" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.value, "custom3 value",
+               "the first property value" + MSG_SHOULD_EQUAL);
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom4_attr",
+               "the second property name" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.value, "custom4 value",
+               "the second property value" + MSG_SHOULD_EQUAL);
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.equal(prop.name, "foregroundDownload",
+               "the third property name" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.value, "false",
+               "the third property value" + MSG_SHOULD_EQUAL);
+  Assert.ok(!e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
 
-  debugDump("checking the first update patch properties");
-  patch = update.selectedPatch;
+  debugDump("checking the second update patch properties");
+  patch = update.selectedPatch.QueryInterface(Ci.nsIWritablePropertyBag);
   Assert.equal(patch.type, "complete",
                "the update patch type attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.URL, "http://complete/",
                "the update patch URL attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.size, "75",
                "the update patch size attribute" + MSG_SHOULD_EQUAL);
   Assert.ok(!!patch.selected,
             "the update patch selected attribute" + MSG_SHOULD_EQUAL);
   Assert.equal(patch.state, STATE_FAILED,
                "the update patch state attribute" + MSG_SHOULD_EQUAL);
+  Assert.equal(patch.getProperty("custom3_attr"), "custom3 patch value",
+               "the update patch custom3_attr property" + MSG_SHOULD_EQUAL);
+  Assert.equal(patch.getProperty("custom4_attr"), "custom4 patch value",
+               "the update patch custom4_attr property" + MSG_SHOULD_EQUAL);
+  // nsIPropertyBag enumerator
+  debugDump("checking the second update patch enumerator");
+  e = patch.enumerator;
+  Assert.ok(e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom3_attr",
+               "the first property name" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.value, "custom3 patch value",
+               "the first property value" + MSG_SHOULD_EQUAL);
+  prop = e.getNext().QueryInterface(Ci.nsIProperty);
+  Assert.ok(!!prop,
+            "the enumerator.getNext()" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.name, "custom4_attr",
+               "the second property name" + MSG_SHOULD_EQUAL);
+  Assert.equal(prop.value, "custom4 patch value",
+               "the second property value" + MSG_SHOULD_EQUAL);
+  Assert.ok(!e.hasMoreElements(),
+            "the enumerator.hasMoreElements()" + MSG_SHOULD_EQUAL);
 
   // Cleaning up the active update along with reloading the update manager
   // in doTestFinish will prevent writing the update xml files during
   // shutdown.
   gUpdateManager.cleanupActiveUpdate();
   executeSoon(waitForUpdateXMLFiles);
 }