Merge inbound to mozilla-central a=merge r=merge
authorBrindusan Cristian <cbrindusan@mozilla.com>
Tue, 28 Nov 2017 11:50:57 +0200
changeset 448198 5b33b070378ae0806bed0b5e5e34de429a29e7db
parent 448168 cff54d05bcad74654249e2a2d4735b491bc452fd (current diff)
parent 448197 f763151e6c59fd0e18c69a918a36d2e6741d5b0e (diff)
child 448199 9c0b74605a0450a87916def6a85fb35b49b3cdb7
child 448210 f71820cbdcb0a7e3026bea22bdc03843214ad884
child 448325 eb30901ed24e317a89c5a62e5bd6bd126d7920aa
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone59.0a1
first release with
nightly linux32
5b33b070378a / 59.0a1 / 20171128100440 / files
nightly linux64
5b33b070378a / 59.0a1 / 20171128100440 / files
nightly mac
5b33b070378a / 59.0a1 / 20171128100440 / files
nightly win32
5b33b070378a / 59.0a1 / 20171128100440 / files
nightly win64
5b33b070378a / 59.0a1 / 20171128100440 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central a=merge r=merge
dom/base/nsDocument.cpp
dom/xbl/nsXBLService.cpp
layout/painting/nsDisplayList.cpp
netwerk/base/nsSocketTransport2.cpp
netwerk/base/nsSocketTransport2.h
netwerk/base/nsSocketTransportService2.cpp
--- a/browser/base/content/test/metaTags/browser_meta_tags.js
+++ b/browser/base/content/test/metaTags/browser_meta_tags.js
@@ -14,17 +14,17 @@ const URL = "https://example.com/browser
  * we have to wait for some time before checking that the page info was stored.
  */
 add_task(async function test_metadata() {
   const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
 
   // Wait until places has stored the page info
   const pageInfo = await waitForPageInfo(URL);
   is(pageInfo.description, "og:description", "got the correct description");
-  is(pageInfo.previewImageURL.href, "og:image:secure_url", "got the correct preview image");
+  is(pageInfo.previewImageURL.href, "https://test.com/og-image-secure-url.jpg", "got the correct preview image");
 
   await BrowserTestUtils.removeTab(tab);
   await PlacesTestUtils.clearHistory();
 });
 
 /**
  * This test is almost like the previous one except it opens a second tab to
  * make sure the extra tab does not cause the debounce logic to be skipped. If
@@ -35,14 +35,14 @@ add_task(async function multiple_tabs() 
 
   // Add a background tab to cause another page to load *without* putting the
   // desired URL in a background tab, which results in its timers being throttled.
   gBrowser.addTab();
 
   // Wait until places has stored the page info
   const pageInfo = await waitForPageInfo(URL);
   is(pageInfo.description, "og:description", "got the correct description");
-  is(pageInfo.previewImageURL.href, "og:image:secure_url", "got the correct preview image");
+  is(pageInfo.previewImageURL.href, "https://test.com/og-image-secure-url.jpg", "got the correct preview image");
 
   await BrowserTestUtils.removeTab(tab);
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
   await PlacesTestUtils.clearHistory();
 });
--- a/browser/base/content/test/metaTags/meta_tags.html
+++ b/browser/base/content/test/metaTags/meta_tags.html
@@ -2,26 +2,26 @@
 <html>
   <head>
     <meta charset="UTF-8" />
     <title>MetaTags</title>
     <meta property="twitter:description" content="twitter:description" />
     <meta property="og:description" content="og:description" />
     <meta name="description" content="description" />
     <meta name="unknown:tag" content="unknown:tag" />
-    <meta property="og:image" content="og:image" />
-    <meta property="twitter:image" content="twitter:image" />
-    <meta property="og:image:url" content="og:image:url" />
-    <meta name="thumbnail" content="thumbnail" />
+    <meta property="og:image" content="https://test.com/og-image.jpg" />
+    <meta property="twitter:image" content="https://test.com/twitter-image.jpg" />
+    <meta property="og:image:url" content="https://test.com/og-image-url" />
+    <meta name="thumbnail" content="https://test.com/thumbnail.jpg" />
   </head>
   <body>
     <script>
       function addMeta(tag) {
         const meta = document.createElement("meta");
-        meta.content = tag;
+        meta.content = "https://test.com/og-image-secure-url.jpg";
         meta.setAttribute("property", tag);
         document.head.appendChild(meta);
       }
 
       // Delay adding this "best" image tag to test that later tags are used.
       // Use a delay that is long enough for tests to check for wrong metadata.
       setTimeout(() => addMeta("og:image:secure_url"), 100);
     </script>
--- 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.0.120
+Current extension version is: 2.0.161
 
-Taken from upstream commit: e162df59
+Taken from upstream commit: b32d659d
--- a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
+++ b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
@@ -112,19 +112,18 @@ function getDOMWindow(aChannel) {
   var requestor = aChannel.notificationCallbacks ?
                   aChannel.notificationCallbacks :
                   aChannel.loadGroup.notificationCallbacks;
   var win = requestor.getInterface(Components.interfaces.nsIDOMWindow);
   return win;
 }
 
 function getLocalizedStrings(path) {
-  var stringBundle = Cc["@mozilla.org/intl/stringbundle;1"].
-      getService(Ci.nsIStringBundleService).
-      createBundle("chrome://pdf.js/locale/" + path);
+  var stringBundle =
+    Services.strings.createBundle("chrome://pdf.js/locale/" + path);
 
   var map = {};
   var enumerator = stringBundle.getSimpleEnumeration();
   while (enumerator.hasMoreElements()) {
     var string = enumerator.getNext().QueryInterface(Ci.nsIPropertyElement);
     var key = string.key, property = "textContent";
     var i = key.lastIndexOf(".");
     if (i >= 0) {
@@ -1013,21 +1012,20 @@ PdfStreamConverter.prototype = {
     // Keep the URL the same so the browser sees it as the same.
     channel.originalURI = aRequest.URI;
     channel.loadGroup = aRequest.loadGroup;
     channel.loadInfo.originAttributes = aRequest.loadInfo.originAttributes;
 
     // We can use the resource principal when data is fetched by the chrome,
     // e.g. useful for NoScript. Make make sure we reuse the origin attributes
     // from the request channel to keep isolation consistent.
-    var ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
-                .getService(Ci.nsIScriptSecurityManager);
     var uri = NetUtil.newURI(PDF_VIEWER_WEB_PAGE);
     var resourcePrincipal =
-      ssm.createCodebasePrincipal(uri, aRequest.loadInfo.originAttributes);
+      Services.scriptSecurityManager.createCodebasePrincipal(uri,
+        aRequest.loadInfo.originAttributes);
     aRequest.owner = resourcePrincipal;
 
     channel.asyncOpen2(proxy);
   },
 
   // nsIRequestObserver::onStopRequest
   onStopRequest(aRequest, aContext, aStatusCode) {
     if (!this.dataListener) {
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -80,34 +80,34 @@ return /******/ (function(modules) { // 
 /******/
 /******/ 	// Object.prototype.hasOwnProperty.call
 /******/ 	__w_pdfjs_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
 /******/
 /******/ 	// __webpack_public_path__
 /******/ 	__w_pdfjs_require__.p = "";
 /******/
 /******/ 	// Load entry module and return exports
-/******/ 	return __w_pdfjs_require__(__w_pdfjs_require__.s = 9);
+/******/ 	return __w_pdfjs_require__(__w_pdfjs_require__.s = 8);
 /******/ })
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.loadJpegStream = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isNodeJS = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.createBlob = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.StatTimer = exports.PasswordResponses = exports.PasswordException = exports.PageViewport = exports.NotImplementedException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.MessageHandler = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VERBOSITY_LEVELS = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined;
 
-__w_pdfjs_require__(10);
-
-var _streams_polyfill = __w_pdfjs_require__(11);
+__w_pdfjs_require__(9);
+
+var _streams_polyfill = __w_pdfjs_require__(10);
 
 var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
 const NativeImageDecoding = {
   NONE: 'none',
   DECODE: 'decode',
   DISPLAY: 'display'
 };
 var TextRenderingMode = {
@@ -1838,27 +1838,29 @@ Object.defineProperty(exports, "__esModu
   value: true
 });
 exports.build = exports.version = exports.setPDFNetworkStreamClass = exports.PDFPageProxy = exports.PDFDocumentProxy = exports.PDFWorker = exports.PDFDataRangeTransport = exports.LoopbackPort = exports.getDocument = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
 var _dom_utils = __w_pdfjs_require__(1);
 
-var _font_loader = __w_pdfjs_require__(14);
-
-var _canvas = __w_pdfjs_require__(15);
+var _font_loader = __w_pdfjs_require__(13);
+
+var _canvas = __w_pdfjs_require__(14);
 
 var _global_scope = __w_pdfjs_require__(2);
 
 var _global_scope2 = _interopRequireDefault(_global_scope);
 
-var _metadata = __w_pdfjs_require__(5);
-
-var _transport_stream = __w_pdfjs_require__(17);
+var _metadata = __w_pdfjs_require__(4);
+
+var _transport_stream = __w_pdfjs_require__(16);
+
+var _webgl = __w_pdfjs_require__(17);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 var DEFAULT_RANGE_CHUNK_SIZE = 65536;
 var isWorkerDisabled = false;
 var workerSrc;
 var isPostMessageTransfersDisabled = false;
 var pdfjsFilePath = null;
@@ -1938,38 +1940,35 @@ function getDocument(src) {
     return _fetchDocument(worker, params, rangeTransport, docId).then(function (workerId) {
       if (task.destroyed) {
         throw new Error('Loading aborted');
       }
       let networkStream;
       if (rangeTransport) {
         networkStream = new _transport_stream.PDFDataTransportStream(params, rangeTransport);
       } else if (!params.data) {
-        networkStream = new PDFNetworkStream({
-          source: params,
-          disableRange: (0, _dom_utils.getDefaultSetting)('disableRange')
-        });
+        networkStream = new PDFNetworkStream(params);
       }
       var messageHandler = new _util.MessageHandler(docId, workerId, worker.port);
       messageHandler.postMessageTransfers = worker.postMessageTransfers;
       var transport = new WorkerTransport(messageHandler, task, networkStream, CMapReaderFactory);
       task._transport = transport;
       messageHandler.send('Ready', null);
     });
   }).catch(task._capability.reject);
   return task;
 }
 function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
   if (worker.destroyed) {
     return Promise.reject(new Error('Worker was destroyed'));
   }
-  let apiVersion = '2.0.120';
+  let apiVersion = '2.0.161';
+  source.disableRange = (0, _dom_utils.getDefaultSetting)('disableRange');
   source.disableAutoFetch = (0, _dom_utils.getDefaultSetting)('disableAutoFetch');
   source.disableStream = (0, _dom_utils.getDefaultSetting)('disableStream');
-  source.chunkedViewerLoading = !!pdfDataRangeTransport;
   if (pdfDataRangeTransport) {
     source.length = pdfDataRangeTransport.length;
     source.initialData = pdfDataRangeTransport.initialData;
   }
   return worker.messageHandler.sendWithPromise('GetDocRequest', {
     docId,
     apiVersion,
     source: {
@@ -2087,17 +2086,17 @@ var PDFDocumentProxy = function PDFDocum
   }
   PDFDocumentProxy.prototype = {
     get numPages() {
       return this.pdfInfo.numPages;
     },
     get fingerprint() {
       return this.pdfInfo.fingerprint;
     },
-    getPage: function PDFDocumentProxy_getPage(pageNumber) {
+    getPage(pageNumber) {
       return this.transport.getPage(pageNumber);
     },
     getPageIndex: function PDFDocumentProxy_getPageIndex(ref) {
       return this.transport.getPageIndex(ref);
     },
     getDestinations: function PDFDocumentProxy_getDestinations() {
       return this.transport.getDestinations();
     },
@@ -2185,16 +2184,17 @@ var PDFPageProxy = function PDFPageProxy
       return this.annotationsPromise;
     },
     render: function PDFPageProxy_render(params) {
       var stats = this.stats;
       stats.time('Overall');
       this.pendingCleanup = false;
       var renderingIntent = params.intent === 'print' ? 'print' : 'display';
       var canvasFactory = params.canvasFactory || new _dom_utils.DOMCanvasFactory();
+      let webGLContext = new _webgl.WebGLContext({ enable: !(0, _dom_utils.getDefaultSetting)('disableWebGL') });
       if (!this.intentStates[renderingIntent]) {
         this.intentStates[renderingIntent] = Object.create(null);
       }
       var intentState = this.intentStates[renderingIntent];
       if (!intentState.displayReadyCapability) {
         intentState.receivingOperatorList = true;
         intentState.displayReadyCapability = (0, _util.createPromiseCapability)();
         intentState.operatorList = {
@@ -2221,17 +2221,17 @@ var PDFPageProxy = function PDFPageProxy
         if (error) {
           internalRenderTask.capability.reject(error);
         } else {
           internalRenderTask.capability.resolve();
         }
         stats.timeEnd('Rendering');
         stats.timeEnd('Overall');
       };
-      var internalRenderTask = new InternalRenderTask(complete, params, this.objs, this.commonObjs, intentState.operatorList, this.pageNumber, canvasFactory);
+      var internalRenderTask = new InternalRenderTask(complete, params, this.objs, this.commonObjs, intentState.operatorList, this.pageNumber, canvasFactory, webGLContext);
       internalRenderTask.useRequestAnimationFrame = renderingIntent !== 'print';
       if (!intentState.renderTasks) {
         intentState.renderTasks = [];
       }
       intentState.renderTasks.push(internalRenderTask);
       var renderTask = internalRenderTask.task;
       intentState.displayReadyCapability.promise.then(transparency => {
         if (this.pendingCleanup) {
@@ -2551,22 +2551,16 @@ var PDFWorker = function PDFWorkerClosur
               this._readyCapability.resolve();
               messageHandler.send('configure', { verbosity: (0, _util.getVerbosityLevel)() });
             } else {
               this._setupFakeWorker();
               messageHandler.destroy();
               worker.terminate();
             }
           });
-          messageHandler.on('console_log', function (data) {
-            console.log.apply(console, data);
-          });
-          messageHandler.on('console_error', function (data) {
-            console.error.apply(console, data);
-          });
           messageHandler.on('ready', data => {
             worker.removeEventListener('error', onWorkerError);
             if (this.destroyed) {
               terminateEarly();
               return;
             }
             try {
               sendTest();
@@ -2986,17 +2980,17 @@ var WorkerTransport = function WorkerTra
           return Promise.reject(new Error('Worker was destroyed'));
         }
         return this.CMapReaderFactory.fetch({ name: data.name });
       }, this);
     },
     getData: function WorkerTransport_getData() {
       return this.messageHandler.sendWithPromise('GetData', null);
     },
-    getPage: function WorkerTransport_getPage(pageNumber, capability) {
+    getPage(pageNumber) {
       if (!Number.isInteger(pageNumber) || pageNumber <= 0 || pageNumber > this.numPages) {
         return Promise.reject(new Error('Invalid page request'));
       }
       var pageIndex = pageNumber - 1;
       if (pageIndex in this.pagePromises) {
         return this.pagePromises[pageIndex];
       }
       var promise = this.messageHandler.sendWithPromise('GetPage', { pageIndex }).then(pageInfo => {
@@ -3140,25 +3134,26 @@ var RenderTask = function RenderTaskClos
     then: function RenderTask_then(onFulfilled, onRejected) {
       return this.promise.then.apply(this.promise, arguments);
     }
   };
   return RenderTask;
 }();
 var InternalRenderTask = function InternalRenderTaskClosure() {
   let canvasInRendering = new WeakMap();
-  function InternalRenderTask(callback, params, objs, commonObjs, operatorList, pageNumber, canvasFactory) {
+  function InternalRenderTask(callback, params, objs, commonObjs, operatorList, pageNumber, canvasFactory, webGLContext) {
     this.callback = callback;
     this.params = params;
     this.objs = objs;
     this.commonObjs = commonObjs;
     this.operatorListIdx = null;
     this.operatorList = operatorList;
     this.pageNumber = pageNumber;
     this.canvasFactory = canvasFactory;
+    this.webGLContext = webGLContext;
     this.running = false;
     this.graphicsReadyCallback = null;
     this.graphicsReady = false;
     this.useRequestAnimationFrame = false;
     this.cancelled = false;
     this.capability = (0, _util.createPromiseCapability)();
     this.task = new RenderTask(this);
     this._continueBound = this._continue.bind(this);
@@ -3178,17 +3173,17 @@ var InternalRenderTask = function Intern
         return;
       }
       if ((0, _dom_utils.getDefaultSetting)('pdfBug') && _global_scope2.default.StepperManager && _global_scope2.default.StepperManager.enabled) {
         this.stepper = _global_scope2.default.StepperManager.create(this.pageNumber - 1);
         this.stepper.init(this.operatorList);
         this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint();
       }
       var params = this.params;
-      this.gfx = new _canvas.CanvasGraphics(params.canvasContext, this.commonObjs, this.objs, this.canvasFactory, params.imageLayer);
+      this.gfx = new _canvas.CanvasGraphics(params.canvasContext, this.commonObjs, this.objs, this.canvasFactory, this.webGLContext, params.imageLayer);
       this.gfx.beginDrawing({
         transform: params.transform,
         viewport: params.viewport,
         transparency,
         background: params.background
       });
       this.operatorListIdx = 0;
       this.graphicsReady = true;
@@ -3253,18 +3248,18 @@ var InternalRenderTask = function Intern
         }
       }
     }
   };
   return InternalRenderTask;
 }();
 var version, build;
 {
-  exports.version = version = '2.0.120';
-  exports.build = build = 'e162df59';
+  exports.version = version = '2.0.161';
+  exports.build = build = 'b32d659d';
 }
 exports.getDocument = getDocument;
 exports.LoopbackPort = LoopbackPort;
 exports.PDFDataRangeTransport = PDFDataRangeTransport;
 exports.PDFWorker = PDFWorker;
 exports.PDFDocumentProxy = PDFDocumentProxy;
 exports.PDFPageProxy = PDFPageProxy;
 exports.setPDFNetworkStreamClass = setPDFNetworkStreamClass;
@@ -3276,383 +3271,16 @@ exports.build = build;
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
-exports.WebGLUtils = undefined;
-
-var _dom_utils = __w_pdfjs_require__(1);
-
-var _util = __w_pdfjs_require__(0);
-
-var WebGLUtils = function WebGLUtilsClosure() {
-  function loadShader(gl, code, shaderType) {
-    var shader = gl.createShader(shaderType);
-    gl.shaderSource(shader, code);
-    gl.compileShader(shader);
-    var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
-    if (!compiled) {
-      var errorMsg = gl.getShaderInfoLog(shader);
-      throw new Error('Error during shader compilation: ' + errorMsg);
-    }
-    return shader;
-  }
-  function createVertexShader(gl, code) {
-    return loadShader(gl, code, gl.VERTEX_SHADER);
-  }
-  function createFragmentShader(gl, code) {
-    return loadShader(gl, code, gl.FRAGMENT_SHADER);
-  }
-  function createProgram(gl, shaders) {
-    var program = gl.createProgram();
-    for (var i = 0, ii = shaders.length; i < ii; ++i) {
-      gl.attachShader(program, shaders[i]);
-    }
-    gl.linkProgram(program);
-    var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
-    if (!linked) {
-      var errorMsg = gl.getProgramInfoLog(program);
-      throw new Error('Error during program linking: ' + errorMsg);
-    }
-    return program;
-  }
-  function createTexture(gl, image, textureId) {
-    gl.activeTexture(textureId);
-    var texture = gl.createTexture();
-    gl.bindTexture(gl.TEXTURE_2D, texture);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
-    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
-    return texture;
-  }
-  var currentGL, currentCanvas;
-  function generateGL() {
-    if (currentGL) {
-      return;
-    }
-    currentCanvas = document.createElement('canvas');
-    currentGL = currentCanvas.getContext('webgl', { premultipliedalpha: false });
-  }
-  var smaskVertexShaderCode = '\
-  attribute vec2 a_position;                                    \
-  attribute vec2 a_texCoord;                                    \
-                                                                \
-  uniform vec2 u_resolution;                                    \
-                                                                \
-  varying vec2 v_texCoord;                                      \
-                                                                \
-  void main() {                                                 \
-    vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0;   \
-    gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);          \
-                                                                \
-    v_texCoord = a_texCoord;                                    \
-  }                                                             ';
-  var smaskFragmentShaderCode = '\
-  precision mediump float;                                      \
-                                                                \
-  uniform vec4 u_backdrop;                                      \
-  uniform int u_subtype;                                        \
-  uniform sampler2D u_image;                                    \
-  uniform sampler2D u_mask;                                     \
-                                                                \
-  varying vec2 v_texCoord;                                      \
-                                                                \
-  void main() {                                                 \
-    vec4 imageColor = texture2D(u_image, v_texCoord);           \
-    vec4 maskColor = texture2D(u_mask, v_texCoord);             \
-    if (u_backdrop.a > 0.0) {                                   \
-      maskColor.rgb = maskColor.rgb * maskColor.a +             \
-                      u_backdrop.rgb * (1.0 - maskColor.a);     \
-    }                                                           \
-    float lum;                                                  \
-    if (u_subtype == 0) {                                       \
-      lum = maskColor.a;                                        \
-    } else {                                                    \
-      lum = maskColor.r * 0.3 + maskColor.g * 0.59 +            \
-            maskColor.b * 0.11;                                 \
-    }                                                           \
-    imageColor.a *= lum;                                        \
-    imageColor.rgb *= imageColor.a;                             \
-    gl_FragColor = imageColor;                                  \
-  }                                                             ';
-  var smaskCache = null;
-  function initSmaskGL() {
-    var canvas, gl;
-    generateGL();
-    canvas = currentCanvas;
-    currentCanvas = null;
-    gl = currentGL;
-    currentGL = null;
-    var vertexShader = createVertexShader(gl, smaskVertexShaderCode);
-    var fragmentShader = createFragmentShader(gl, smaskFragmentShaderCode);
-    var program = createProgram(gl, [vertexShader, fragmentShader]);
-    gl.useProgram(program);
-    var cache = {};
-    cache.gl = gl;
-    cache.canvas = canvas;
-    cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
-    cache.positionLocation = gl.getAttribLocation(program, 'a_position');
-    cache.backdropLocation = gl.getUniformLocation(program, 'u_backdrop');
-    cache.subtypeLocation = gl.getUniformLocation(program, 'u_subtype');
-    var texCoordLocation = gl.getAttribLocation(program, 'a_texCoord');
-    var texLayerLocation = gl.getUniformLocation(program, 'u_image');
-    var texMaskLocation = gl.getUniformLocation(program, 'u_mask');
-    var texCoordBuffer = gl.createBuffer();
-    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
-    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0]), gl.STATIC_DRAW);
-    gl.enableVertexAttribArray(texCoordLocation);
-    gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
-    gl.uniform1i(texLayerLocation, 0);
-    gl.uniform1i(texMaskLocation, 1);
-    smaskCache = cache;
-  }
-  function composeSMask(layer, mask, properties) {
-    var width = layer.width,
-        height = layer.height;
-    if (!smaskCache) {
-      initSmaskGL();
-    }
-    var cache = smaskCache,
-        canvas = cache.canvas,
-        gl = cache.gl;
-    canvas.width = width;
-    canvas.height = height;
-    gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
-    gl.uniform2f(cache.resolutionLocation, width, height);
-    if (properties.backdrop) {
-      gl.uniform4f(cache.resolutionLocation, properties.backdrop[0], properties.backdrop[1], properties.backdrop[2], 1);
-    } else {
-      gl.uniform4f(cache.resolutionLocation, 0, 0, 0, 0);
-    }
-    gl.uniform1i(cache.subtypeLocation, properties.subtype === 'Luminosity' ? 1 : 0);
-    var texture = createTexture(gl, layer, gl.TEXTURE0);
-    var maskTexture = createTexture(gl, mask, gl.TEXTURE1);
-    var buffer = gl.createBuffer();
-    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
-    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, width, 0, 0, height, 0, height, width, 0, width, height]), gl.STATIC_DRAW);
-    gl.enableVertexAttribArray(cache.positionLocation);
-    gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
-    gl.clearColor(0, 0, 0, 0);
-    gl.enable(gl.BLEND);
-    gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
-    gl.clear(gl.COLOR_BUFFER_BIT);
-    gl.drawArrays(gl.TRIANGLES, 0, 6);
-    gl.flush();
-    gl.deleteTexture(texture);
-    gl.deleteTexture(maskTexture);
-    gl.deleteBuffer(buffer);
-    return canvas;
-  }
-  var figuresVertexShaderCode = '\
-  attribute vec2 a_position;                                    \
-  attribute vec3 a_color;                                       \
-                                                                \
-  uniform vec2 u_resolution;                                    \
-  uniform vec2 u_scale;                                         \
-  uniform vec2 u_offset;                                        \
-                                                                \
-  varying vec4 v_color;                                         \
-                                                                \
-  void main() {                                                 \
-    vec2 position = (a_position + u_offset) * u_scale;          \
-    vec2 clipSpace = (position / u_resolution) * 2.0 - 1.0;     \
-    gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);          \
-                                                                \
-    v_color = vec4(a_color / 255.0, 1.0);                       \
-  }                                                             ';
-  var figuresFragmentShaderCode = '\
-  precision mediump float;                                      \
-                                                                \
-  varying vec4 v_color;                                         \
-                                                                \
-  void main() {                                                 \
-    gl_FragColor = v_color;                                     \
-  }                                                             ';
-  var figuresCache = null;
-  function initFiguresGL() {
-    var canvas, gl;
-    generateGL();
-    canvas = currentCanvas;
-    currentCanvas = null;
-    gl = currentGL;
-    currentGL = null;
-    var vertexShader = createVertexShader(gl, figuresVertexShaderCode);
-    var fragmentShader = createFragmentShader(gl, figuresFragmentShaderCode);
-    var program = createProgram(gl, [vertexShader, fragmentShader]);
-    gl.useProgram(program);
-    var cache = {};
-    cache.gl = gl;
-    cache.canvas = canvas;
-    cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
-    cache.scaleLocation = gl.getUniformLocation(program, 'u_scale');
-    cache.offsetLocation = gl.getUniformLocation(program, 'u_offset');
-    cache.positionLocation = gl.getAttribLocation(program, 'a_position');
-    cache.colorLocation = gl.getAttribLocation(program, 'a_color');
-    figuresCache = cache;
-  }
-  function drawFigures(width, height, backgroundColor, figures, context) {
-    if (!figuresCache) {
-      initFiguresGL();
-    }
-    var cache = figuresCache,
-        canvas = cache.canvas,
-        gl = cache.gl;
-    canvas.width = width;
-    canvas.height = height;
-    gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
-    gl.uniform2f(cache.resolutionLocation, width, height);
-    var count = 0;
-    var i, ii, rows;
-    for (i = 0, ii = figures.length; i < ii; i++) {
-      switch (figures[i].type) {
-        case 'lattice':
-          rows = figures[i].coords.length / figures[i].verticesPerRow | 0;
-          count += (rows - 1) * (figures[i].verticesPerRow - 1) * 6;
-          break;
-        case 'triangles':
-          count += figures[i].coords.length;
-          break;
-      }
-    }
-    var coords = new Float32Array(count * 2);
-    var colors = new Uint8Array(count * 3);
-    var coordsMap = context.coords,
-        colorsMap = context.colors;
-    var pIndex = 0,
-        cIndex = 0;
-    for (i = 0, ii = figures.length; i < ii; i++) {
-      var figure = figures[i],
-          ps = figure.coords,
-          cs = figure.colors;
-      switch (figure.type) {
-        case 'lattice':
-          var cols = figure.verticesPerRow;
-          rows = ps.length / cols | 0;
-          for (var row = 1; row < rows; row++) {
-            var offset = row * cols + 1;
-            for (var col = 1; col < cols; col++, offset++) {
-              coords[pIndex] = coordsMap[ps[offset - cols - 1]];
-              coords[pIndex + 1] = coordsMap[ps[offset - cols - 1] + 1];
-              coords[pIndex + 2] = coordsMap[ps[offset - cols]];
-              coords[pIndex + 3] = coordsMap[ps[offset - cols] + 1];
-              coords[pIndex + 4] = coordsMap[ps[offset - 1]];
-              coords[pIndex + 5] = coordsMap[ps[offset - 1] + 1];
-              colors[cIndex] = colorsMap[cs[offset - cols - 1]];
-              colors[cIndex + 1] = colorsMap[cs[offset - cols - 1] + 1];
-              colors[cIndex + 2] = colorsMap[cs[offset - cols - 1] + 2];
-              colors[cIndex + 3] = colorsMap[cs[offset - cols]];
-              colors[cIndex + 4] = colorsMap[cs[offset - cols] + 1];
-              colors[cIndex + 5] = colorsMap[cs[offset - cols] + 2];
-              colors[cIndex + 6] = colorsMap[cs[offset - 1]];
-              colors[cIndex + 7] = colorsMap[cs[offset - 1] + 1];
-              colors[cIndex + 8] = colorsMap[cs[offset - 1] + 2];
-              coords[pIndex + 6] = coords[pIndex + 2];
-              coords[pIndex + 7] = coords[pIndex + 3];
-              coords[pIndex + 8] = coords[pIndex + 4];
-              coords[pIndex + 9] = coords[pIndex + 5];
-              coords[pIndex + 10] = coordsMap[ps[offset]];
-              coords[pIndex + 11] = coordsMap[ps[offset] + 1];
-              colors[cIndex + 9] = colors[cIndex + 3];
-              colors[cIndex + 10] = colors[cIndex + 4];
-              colors[cIndex + 11] = colors[cIndex + 5];
-              colors[cIndex + 12] = colors[cIndex + 6];
-              colors[cIndex + 13] = colors[cIndex + 7];
-              colors[cIndex + 14] = colors[cIndex + 8];
-              colors[cIndex + 15] = colorsMap[cs[offset]];
-              colors[cIndex + 16] = colorsMap[cs[offset] + 1];
-              colors[cIndex + 17] = colorsMap[cs[offset] + 2];
-              pIndex += 12;
-              cIndex += 18;
-            }
-          }
-          break;
-        case 'triangles':
-          for (var j = 0, jj = ps.length; j < jj; j++) {
-            coords[pIndex] = coordsMap[ps[j]];
-            coords[pIndex + 1] = coordsMap[ps[j] + 1];
-            colors[cIndex] = colorsMap[cs[j]];
-            colors[cIndex + 1] = colorsMap[cs[j] + 1];
-            colors[cIndex + 2] = colorsMap[cs[j] + 2];
-            pIndex += 2;
-            cIndex += 3;
-          }
-          break;
-      }
-    }
-    if (backgroundColor) {
-      gl.clearColor(backgroundColor[0] / 255, backgroundColor[1] / 255, backgroundColor[2] / 255, 1.0);
-    } else {
-      gl.clearColor(0, 0, 0, 0);
-    }
-    gl.clear(gl.COLOR_BUFFER_BIT);
-    var coordsBuffer = gl.createBuffer();
-    gl.bindBuffer(gl.ARRAY_BUFFER, coordsBuffer);
-    gl.bufferData(gl.ARRAY_BUFFER, coords, gl.STATIC_DRAW);
-    gl.enableVertexAttribArray(cache.positionLocation);
-    gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
-    var colorsBuffer = gl.createBuffer();
-    gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer);
-    gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
-    gl.enableVertexAttribArray(cache.colorLocation);
-    gl.vertexAttribPointer(cache.colorLocation, 3, gl.UNSIGNED_BYTE, false, 0, 0);
-    gl.uniform2f(cache.scaleLocation, context.scaleX, context.scaleY);
-    gl.uniform2f(cache.offsetLocation, context.offsetX, context.offsetY);
-    gl.drawArrays(gl.TRIANGLES, 0, count);
-    gl.flush();
-    gl.deleteBuffer(coordsBuffer);
-    gl.deleteBuffer(colorsBuffer);
-    return canvas;
-  }
-  function cleanup() {
-    if (smaskCache && smaskCache.canvas) {
-      smaskCache.canvas.width = 0;
-      smaskCache.canvas.height = 0;
-    }
-    if (figuresCache && figuresCache.canvas) {
-      figuresCache.canvas.width = 0;
-      figuresCache.canvas.height = 0;
-    }
-    smaskCache = null;
-    figuresCache = null;
-  }
-  return {
-    get isEnabled() {
-      if ((0, _dom_utils.getDefaultSetting)('disableWebGL')) {
-        return false;
-      }
-      var enabled = false;
-      try {
-        generateGL();
-        enabled = !!currentGL;
-      } catch (e) {}
-      return (0, _util.shadow)(this, 'isEnabled', enabled);
-    },
-    composeSMask,
-    drawFigures,
-    clear: cleanup
-  };
-}();
-exports.WebGLUtils = WebGLUtils;
-
-/***/ }),
-/* 5 */
-/***/ (function(module, exports, __w_pdfjs_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
 exports.Metadata = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
 var _dom_utils = __w_pdfjs_require__(1);
 
 class Metadata {
   constructor(data) {
@@ -3715,17 +3343,17 @@ class Metadata {
   }
   has(name) {
     return typeof this._metadata[name] !== 'undefined';
   }
 }
 exports.Metadata = Metadata;
 
 /***/ }),
-/* 6 */
+/* 5 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -4422,17 +4050,17 @@ class AnnotationLayer {
       }
     }
     parameters.div.removeAttribute('hidden');
   }
 }
 exports.AnnotationLayer = AnnotationLayer;
 
 /***/ }),
-/* 7 */
+/* 6 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -4960,17 +4588,17 @@ var renderTextLayer = function renderTex
     task._render(renderParameters.timeout);
     return task;
   }
   return renderTextLayer;
 }();
 exports.renderTextLayer = renderTextLayer;
 
 /***/ }),
-/* 8 */
+/* 7 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -4982,31 +4610,31 @@ var _dom_utils = __w_pdfjs_require__(1);
 
 var SVGGraphics = function () {
   throw new Error('Not implemented: SVGGraphics');
 };
 ;
 exports.SVGGraphics = SVGGraphics;
 
 /***/ }),
-/* 9 */
+/* 8 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.0.120';
-var pdfjsBuild = 'e162df59';
+var pdfjsVersion = '2.0.161';
+var pdfjsBuild = 'b32d659d';
 var pdfjsSharedUtil = __w_pdfjs_require__(0);
-var pdfjsDisplayGlobal = __w_pdfjs_require__(13);
+var pdfjsDisplayGlobal = __w_pdfjs_require__(12);
 var pdfjsDisplayAPI = __w_pdfjs_require__(3);
-var pdfjsDisplayTextLayer = __w_pdfjs_require__(7);
-var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(6);
+var pdfjsDisplayTextLayer = __w_pdfjs_require__(6);
+var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(5);
 var pdfjsDisplayDOMUtils = __w_pdfjs_require__(1);
-var pdfjsDisplaySVG = __w_pdfjs_require__(8);
+var pdfjsDisplaySVG = __w_pdfjs_require__(7);
 ;
 exports.PDFJS = pdfjsDisplayGlobal.PDFJS;
 exports.build = pdfjsDisplayAPI.build;
 exports.version = pdfjsDisplayAPI.version;
 exports.getDocument = pdfjsDisplayAPI.getDocument;
 exports.LoopbackPort = pdfjsDisplayAPI.LoopbackPort;
 exports.PDFDataRangeTransport = pdfjsDisplayAPI.PDFDataRangeTransport;
 exports.PDFWorker = pdfjsDisplayAPI.PDFWorker;
@@ -5028,26 +4656,26 @@ exports.removeNullCharacters = pdfjsShar
 exports.shadow = pdfjsSharedUtil.shadow;
 exports.createBlob = pdfjsSharedUtil.createBlob;
 exports.RenderingCancelledException = pdfjsDisplayDOMUtils.RenderingCancelledException;
 exports.getFilenameFromUrl = pdfjsDisplayDOMUtils.getFilenameFromUrl;
 exports.addLinkAttributes = pdfjsDisplayDOMUtils.addLinkAttributes;
 exports.StatTimer = pdfjsSharedUtil.StatTimer;
 
 /***/ }),
-/* 10 */
+/* 9 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 ;
 
 /***/ }),
-/* 11 */
+/* 10 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 let isReadableStreamSupported = false;
 if (typeof ReadableStream !== 'undefined') {
   try {
@@ -5057,21 +4685,21 @@ if (typeof ReadableStream !== 'undefined
       }
     });
     isReadableStreamSupported = true;
   } catch (e) {}
 }
 if (isReadableStreamSupported) {
   exports.ReadableStream = ReadableStream;
 } else {
-  exports.ReadableStream = __w_pdfjs_require__(12).ReadableStream;
+  exports.ReadableStream = __w_pdfjs_require__(11).ReadableStream;
 }
 
 /***/ }),
-/* 12 */
+/* 11 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 (function (e, a) {
   for (var i in a) e[i] = a[i];
 })(exports, function (modules) {
@@ -8077,54 +7705,54 @@ if (isReadableStreamSupported) {
   function streamBrandCheckException(name) {
     return new TypeError('TransformStream.prototype.' + name + ' can only be used on a TransformStream');
   }
 }, function (module, exports, __w_pdfjs_require__) {
   module.exports = __w_pdfjs_require__(5);
 }]));
 
 /***/ }),
-/* 13 */
+/* 12 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.PDFJS = exports.globalScope = undefined;
 
 var _dom_utils = __w_pdfjs_require__(1);
 
 var _util = __w_pdfjs_require__(0);
 
 var _api = __w_pdfjs_require__(3);
 
-var _annotation_layer = __w_pdfjs_require__(6);
+var _annotation_layer = __w_pdfjs_require__(5);
 
 var _global_scope = __w_pdfjs_require__(2);
 
 var _global_scope2 = _interopRequireDefault(_global_scope);
 
-var _metadata = __w_pdfjs_require__(5);
-
-var _text_layer = __w_pdfjs_require__(7);
-
-var _svg = __w_pdfjs_require__(8);
+var _metadata = __w_pdfjs_require__(4);
+
+var _text_layer = __w_pdfjs_require__(6);
+
+var _svg = __w_pdfjs_require__(7);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 if (!_global_scope2.default.PDFJS) {
   _global_scope2.default.PDFJS = {};
 }
 var PDFJS = _global_scope2.default.PDFJS;
 {
-  PDFJS.version = '2.0.120';
-  PDFJS.build = 'e162df59';
+  PDFJS.version = '2.0.161';
+  PDFJS.build = 'b32d659d';
 }
 PDFJS.pdfBug = false;
 if (PDFJS.verbosity !== undefined) {
   (0, _util.setVerbosityLevel)(PDFJS.verbosity);
 }
 delete PDFJS.verbosity;
 Object.defineProperty(PDFJS, 'verbosity', {
   get() {
@@ -8191,17 +7819,17 @@ PDFJS.isExternalLinkTargetSet = _dom_uti
 PDFJS.AnnotationLayer = _annotation_layer.AnnotationLayer;
 PDFJS.renderTextLayer = _text_layer.renderTextLayer;
 PDFJS.Metadata = _metadata.Metadata;
 PDFJS.SVGGraphics = _svg.SVGGraphics;
 exports.globalScope = _global_scope2.default;
 exports.PDFJS = PDFJS;
 
 /***/ }),
-/* 14 */
+/* 13 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -8316,32 +7944,30 @@ var FontFaceObject = function FontFaceOb
     }
   };
   return FontFaceObject;
 }();
 exports.FontFaceObject = FontFaceObject;
 exports.FontLoader = FontLoader;
 
 /***/ }),
-/* 15 */
+/* 14 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.CanvasGraphics = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
-var _pattern_helper = __w_pdfjs_require__(16);
-
-var _webgl = __w_pdfjs_require__(4);
+var _pattern_helper = __w_pdfjs_require__(15);
 
 var MIN_FONT_SIZE = 16;
 var MAX_FONT_SIZE = 100;
 var MAX_GROUP_SIZE = 4096;
 var MIN_WIDTH_FACTOR = 0.65;
 var COMPILE_TYPE3_GLYPHS = true;
 var MAX_SIZE_TO_COMPILE = 1000;
 var FULL_CHUNK_HEIGHT = 16;
@@ -8629,27 +8255,28 @@ var CanvasExtraState = function CanvasEx
       this.y = y;
     }
   };
   return CanvasExtraState;
 }();
 var CanvasGraphics = function CanvasGraphicsClosure() {
   var EXECUTION_TIME = 15;
   var EXECUTION_STEPS = 10;
-  function CanvasGraphics(canvasCtx, commonObjs, objs, canvasFactory, imageLayer) {
+  function CanvasGraphics(canvasCtx, commonObjs, objs, canvasFactory, webGLContext, imageLayer) {
     this.ctx = canvasCtx;
     this.current = new CanvasExtraState();
     this.stateStack = [];
     this.pendingClip = null;
     this.pendingEOFill = false;
     this.res = null;
     this.xobjs = null;
     this.commonObjs = commonObjs;
     this.objs = objs;
     this.canvasFactory = canvasFactory;
+    this.webGLContext = webGLContext;
     this.imageLayer = imageLayer;
     this.groupStack = [];
     this.processingType3 = null;
     this.baseTransform = null;
     this.baseTransformStack = [];
     this.groupLevel = 0;
     this.smaskStack = [];
     this.smaskCounter = 0;
@@ -8860,25 +8487,29 @@ var CanvasGraphics = function CanvasGrap
       var layerData = layerCtx.getImageData(0, row, width, chunkHeight);
       if (hasBackdrop) {
         composeSMaskBackdrop(maskData.data, r0, g0, b0);
       }
       composeFn(maskData.data, layerData.data, transferMap);
       maskCtx.putImageData(layerData, 0, row);
     }
   }
-  function composeSMask(ctx, smask, layerCtx) {
+  function composeSMask(ctx, smask, layerCtx, webGLContext) {
     var mask = smask.canvas;
     var maskCtx = smask.context;
     ctx.setTransform(smask.scaleX, 0, 0, smask.scaleY, smask.offsetX, smask.offsetY);
     var backdrop = smask.backdrop || null;
-    if (!smask.transferMap && _webgl.WebGLUtils.isEnabled) {
-      var composed = _webgl.WebGLUtils.composeSMask(layerCtx.canvas, mask, {
-        subtype: smask.subtype,
-        backdrop
+    if (!smask.transferMap && webGLContext.isEnabled) {
+      let composed = webGLContext.composeSMask({
+        layer: layerCtx.canvas,
+        mask,
+        properties: {
+          subtype: smask.subtype,
+          backdrop
+        }
       });
       ctx.setTransform(1, 0, 0, 1, 0, 0);
       ctx.drawImage(composed, smask.offsetX, smask.offsetY);
       return;
     }
     genericComposeSMask(maskCtx, layerCtx, mask.width, mask.height, smask.subtype, backdrop, smask.transferMap);
     ctx.drawImage(mask, 0, 0);
   }
@@ -8969,17 +8600,17 @@ var CanvasGraphics = function CanvasGrap
         this.ctx = this.compositeCtx;
         this.ctx.save();
         this.ctx.setTransform(1, 0, 0, 1, 0, 0);
         this.ctx.drawImage(this.transparentCanvas, 0, 0);
         this.ctx.restore();
         this.transparentCanvas = null;
       }
       this.cachedCanvases.clear();
-      _webgl.WebGLUtils.clear();
+      this.webGLContext.clear();
       if (this.imageLayer) {
         this.imageLayer.endLayout();
       }
     },
     setLineWidth: function CanvasGraphics_setLineWidth(width) {
       this.current.lineWidth = width;
       this.ctx.lineWidth = width;
     },
@@ -9077,17 +8708,17 @@ var CanvasGraphics = function CanvasGrap
       this.setGState([['BM', 'source-over'], ['ca', 1], ['CA', 1]]);
       this.groupStack.push(currentCtx);
       this.groupLevel++;
     },
     suspendSMaskGroup: function CanvasGraphics_endSMaskGroup() {
       var groupCtx = this.ctx;
       this.groupLevel--;
       this.ctx = this.groupStack.pop();
-      composeSMask(this.ctx, this.current.activeSMask, groupCtx);
+      composeSMask(this.ctx, this.current.activeSMask, groupCtx, this.webGLContext);
       this.ctx.restore();
       this.ctx.save();
       copyCtxState(groupCtx, this.ctx);
       this.current.resumeSMaskCtx = groupCtx;
       var deltaTransform = _util.Util.transform(this.current.activeSMask.startTransformInverse, groupCtx.mozCurrentTransform);
       this.ctx.transform.apply(this.ctx, deltaTransform);
       groupCtx.save();
       groupCtx.setTransform(1, 0, 0, 1, 0, 0);
@@ -9100,17 +8731,17 @@ var CanvasGraphics = function CanvasGrap
       this.ctx = groupCtx;
       this.groupStack.push(currentCtx);
       this.groupLevel++;
     },
     endSMaskGroup: function CanvasGraphics_endSMaskGroup() {
       var groupCtx = this.ctx;
       this.groupLevel--;
       this.ctx = this.groupStack.pop();
-      composeSMask(this.ctx, this.current.activeSMask, groupCtx);
+      composeSMask(this.ctx, this.current.activeSMask, groupCtx, this.webGLContext);
       this.ctx.restore();
       copyCtxState(groupCtx, this.ctx);
       var deltaTransform = _util.Util.transform(this.current.activeSMask.startTransformInverse, groupCtx.mozCurrentTransform);
       this.ctx.transform.apply(this.ctx, deltaTransform);
     },
     save: function CanvasGraphics_save() {
       this.ctx.save();
       var old = this.current;
@@ -10045,31 +9676,29 @@ var CanvasGraphics = function CanvasGrap
   for (var op in _util.OPS) {
     CanvasGraphics.prototype[_util.OPS[op]] = CanvasGraphics.prototype[op];
   }
   return CanvasGraphics;
 }();
 exports.CanvasGraphics = CanvasGraphics;
 
 /***/ }),
-/* 16 */
+/* 15 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.TilingPattern = exports.getShadingPatternFromIR = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
-var _webgl = __w_pdfjs_require__(4);
-
 var ShadingIRs = {};
 ShadingIRs.RadialAxial = {
   fromIR: function RadialAxial_fromIR(raw) {
     var type = raw[1];
     var colorStops = raw[2];
     var p0 = raw[3];
     var p1 = raw[4];
     var r0 = raw[5];
@@ -10199,17 +9828,17 @@ var createMeshCanvas = function createMe
         for (i = 0, ii = ps.length; i < ii; i += 3) {
           drawTriangle(data, context, ps[i], ps[i + 1], ps[i + 2], cs[i], cs[i + 1], cs[i + 2]);
         }
         break;
       default:
         throw new Error('illegal figure');
     }
   }
-  function createMeshCanvas(bounds, combinesScale, coords, colors, figures, backgroundColor, cachedCanvases) {
+  function createMeshCanvas(bounds, combinesScale, coords, colors, figures, backgroundColor, cachedCanvases, webGLContext) {
     var EXPECTED_SCALE = 1.1;
     var MAX_PATTERN_SIZE = 3000;
     var BORDER_SIZE = 2;
     var offsetX = Math.floor(bounds[0]);
     var offsetY = Math.floor(bounds[1]);
     var boundsWidth = Math.ceil(bounds[2]) - offsetX;
     var boundsHeight = Math.ceil(bounds[3]) - offsetY;
     var width = Math.min(Math.ceil(Math.abs(boundsWidth * combinesScale[0] * EXPECTED_SCALE)), MAX_PATTERN_SIZE);
@@ -10222,18 +9851,24 @@ var createMeshCanvas = function createMe
       offsetX: -offsetX,
       offsetY: -offsetY,
       scaleX: 1 / scaleX,
       scaleY: 1 / scaleY
     };
     var paddedWidth = width + BORDER_SIZE * 2;
     var paddedHeight = height + BORDER_SIZE * 2;
     var canvas, tmpCanvas, i, ii;
-    if (_webgl.WebGLUtils.isEnabled) {
-      canvas = _webgl.WebGLUtils.drawFigures(width, height, backgroundColor, figures, context);
+    if (webGLContext.isEnabled) {
+      canvas = webGLContext.drawFigures({
+        width,
+        height,
+        backgroundColor,
+        figures,
+        context
+      });
       tmpCanvas = cachedCanvases.getCanvas('mesh', paddedWidth, paddedHeight, false);
       tmpCanvas.context.drawImage(canvas, BORDER_SIZE, BORDER_SIZE);
       canvas = tmpCanvas.canvas;
     } else {
       tmpCanvas = cachedCanvases.getCanvas('mesh', paddedWidth, paddedHeight, false);
       var tmpCtx = tmpCanvas.context;
       var data = tmpCtx.createImageData(width, height);
       if (backgroundColor) {
@@ -10277,17 +9912,17 @@ ShadingIRs.Mesh = {
           scale = _util.Util.singularValueDecompose2dScale(ctx.mozCurrentTransform);
         } else {
           scale = _util.Util.singularValueDecompose2dScale(owner.baseTransform);
           if (matrix) {
             var matrixScale = _util.Util.singularValueDecompose2dScale(matrix);
             scale = [scale[0] * matrixScale[0], scale[1] * matrixScale[1]];
           }
         }
-        var temporaryPatternCanvas = createMeshCanvas(bounds, scale, coords, colors, figures, shadingFill ? null : background, owner.cachedCanvases);
+        var temporaryPatternCanvas = createMeshCanvas(bounds, scale, coords, colors, figures, shadingFill ? null : background, owner.cachedCanvases, owner.webGLContext);
         if (!shadingFill) {
           ctx.setTransform.apply(ctx, owner.baseTransform);
           if (matrix) {
             ctx.transform.apply(ctx, matrix);
           }
         }
         ctx.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY);
         ctx.scale(temporaryPatternCanvas.scaleX, temporaryPatternCanvas.scaleY);
@@ -10423,17 +10058,17 @@ var TilingPattern = function TilingPatte
     }
   };
   return TilingPattern;
 }();
 exports.getShadingPatternFromIR = getShadingPatternFromIR;
 exports.TilingPattern = TilingPattern;
 
 /***/ }),
-/* 17 */
+/* 16 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -10658,11 +10293,394 @@ var PDFDataTransportStream = function PD
       this._requests = [];
       this._stream._removeRangeReader(this);
     }
   };
   return PDFDataTransportStream;
 }();
 exports.PDFDataTransportStream = PDFDataTransportStream;
 
+/***/ }),
+/* 17 */
+/***/ (function(module, exports, __w_pdfjs_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.WebGLContext = undefined;
+
+var _util = __w_pdfjs_require__(0);
+
+class WebGLContext {
+  constructor({
+    enable = false
+  }) {
+    this._enabled = enable === true;
+  }
+  get isEnabled() {
+    let enabled = this._enabled;
+    if (enabled) {
+      enabled = WebGLUtils.tryInitGL();
+    }
+    return (0, _util.shadow)(this, 'isEnabled', enabled);
+  }
+  composeSMask({ layer, mask, properties }) {
+    return WebGLUtils.composeSMask(layer, mask, properties);
+  }
+  drawFigures({ width, height, backgroundColor, figures, context }) {
+    return WebGLUtils.drawFigures(width, height, backgroundColor, figures, context);
+  }
+  clear() {
+    WebGLUtils.cleanup();
+  }
+}
+var WebGLUtils = function WebGLUtilsClosure() {
+  function loadShader(gl, code, shaderType) {
+    var shader = gl.createShader(shaderType);
+    gl.shaderSource(shader, code);
+    gl.compileShader(shader);
+    var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
+    if (!compiled) {
+      var errorMsg = gl.getShaderInfoLog(shader);
+      throw new Error('Error during shader compilation: ' + errorMsg);
+    }
+    return shader;
+  }
+  function createVertexShader(gl, code) {
+    return loadShader(gl, code, gl.VERTEX_SHADER);
+  }
+  function createFragmentShader(gl, code) {
+    return loadShader(gl, code, gl.FRAGMENT_SHADER);
+  }
+  function createProgram(gl, shaders) {
+    var program = gl.createProgram();
+    for (var i = 0, ii = shaders.length; i < ii; ++i) {
+      gl.attachShader(program, shaders[i]);
+    }
+    gl.linkProgram(program);
+    var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
+    if (!linked) {
+      var errorMsg = gl.getProgramInfoLog(program);
+      throw new Error('Error during program linking: ' + errorMsg);
+    }
+    return program;
+  }
+  function createTexture(gl, image, textureId) {
+    gl.activeTexture(textureId);
+    var texture = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, texture);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
+    return texture;
+  }
+  var currentGL, currentCanvas;
+  function generateGL() {
+    if (currentGL) {
+      return;
+    }
+    currentCanvas = document.createElement('canvas');
+    currentGL = currentCanvas.getContext('webgl', { premultipliedalpha: false });
+  }
+  var smaskVertexShaderCode = '\
+  attribute vec2 a_position;                                    \
+  attribute vec2 a_texCoord;                                    \
+                                                                \
+  uniform vec2 u_resolution;                                    \
+                                                                \
+  varying vec2 v_texCoord;                                      \
+                                                                \
+  void main() {                                                 \
+    vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0;   \
+    gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);          \
+                                                                \
+    v_texCoord = a_texCoord;                                    \
+  }                                                             ';
+  var smaskFragmentShaderCode = '\
+  precision mediump float;                                      \
+                                                                \
+  uniform vec4 u_backdrop;                                      \
+  uniform int u_subtype;                                        \
+  uniform sampler2D u_image;                                    \
+  uniform sampler2D u_mask;                                     \
+                                                                \
+  varying vec2 v_texCoord;                                      \
+                                                                \
+  void main() {                                                 \
+    vec4 imageColor = texture2D(u_image, v_texCoord);           \
+    vec4 maskColor = texture2D(u_mask, v_texCoord);             \
+    if (u_backdrop.a > 0.0) {                                   \
+      maskColor.rgb = maskColor.rgb * maskColor.a +             \
+                      u_backdrop.rgb * (1.0 - maskColor.a);     \
+    }                                                           \
+    float lum;                                                  \
+    if (u_subtype == 0) {                                       \
+      lum = maskColor.a;                                        \
+    } else {                                                    \
+      lum = maskColor.r * 0.3 + maskColor.g * 0.59 +            \
+            maskColor.b * 0.11;                                 \
+    }                                                           \
+    imageColor.a *= lum;                                        \
+    imageColor.rgb *= imageColor.a;                             \
+    gl_FragColor = imageColor;                                  \
+  }                                                             ';
+  var smaskCache = null;
+  function initSmaskGL() {
+    var canvas, gl;
+    generateGL();
+    canvas = currentCanvas;
+    currentCanvas = null;
+    gl = currentGL;
+    currentGL = null;
+    var vertexShader = createVertexShader(gl, smaskVertexShaderCode);
+    var fragmentShader = createFragmentShader(gl, smaskFragmentShaderCode);
+    var program = createProgram(gl, [vertexShader, fragmentShader]);
+    gl.useProgram(program);
+    var cache = {};
+    cache.gl = gl;
+    cache.canvas = canvas;
+    cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
+    cache.positionLocation = gl.getAttribLocation(program, 'a_position');
+    cache.backdropLocation = gl.getUniformLocation(program, 'u_backdrop');
+    cache.subtypeLocation = gl.getUniformLocation(program, 'u_subtype');
+    var texCoordLocation = gl.getAttribLocation(program, 'a_texCoord');
+    var texLayerLocation = gl.getUniformLocation(program, 'u_image');
+    var texMaskLocation = gl.getUniformLocation(program, 'u_mask');
+    var texCoordBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0]), gl.STATIC_DRAW);
+    gl.enableVertexAttribArray(texCoordLocation);
+    gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
+    gl.uniform1i(texLayerLocation, 0);
+    gl.uniform1i(texMaskLocation, 1);
+    smaskCache = cache;
+  }
+  function composeSMask(layer, mask, properties) {
+    var width = layer.width,
+        height = layer.height;
+    if (!smaskCache) {
+      initSmaskGL();
+    }
+    var cache = smaskCache,
+        canvas = cache.canvas,
+        gl = cache.gl;
+    canvas.width = width;
+    canvas.height = height;
+    gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+    gl.uniform2f(cache.resolutionLocation, width, height);
+    if (properties.backdrop) {
+      gl.uniform4f(cache.resolutionLocation, properties.backdrop[0], properties.backdrop[1], properties.backdrop[2], 1);
+    } else {
+      gl.uniform4f(cache.resolutionLocation, 0, 0, 0, 0);
+    }
+    gl.uniform1i(cache.subtypeLocation, properties.subtype === 'Luminosity' ? 1 : 0);
+    var texture = createTexture(gl, layer, gl.TEXTURE0);
+    var maskTexture = createTexture(gl, mask, gl.TEXTURE1);
+    var buffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, width, 0, 0, height, 0, height, width, 0, width, height]), gl.STATIC_DRAW);
+    gl.enableVertexAttribArray(cache.positionLocation);
+    gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
+    gl.clearColor(0, 0, 0, 0);
+    gl.enable(gl.BLEND);
+    gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
+    gl.clear(gl.COLOR_BUFFER_BIT);
+    gl.drawArrays(gl.TRIANGLES, 0, 6);
+    gl.flush();
+    gl.deleteTexture(texture);
+    gl.deleteTexture(maskTexture);
+    gl.deleteBuffer(buffer);
+    return canvas;
+  }
+  var figuresVertexShaderCode = '\
+  attribute vec2 a_position;                                    \
+  attribute vec3 a_color;                                       \
+                                                                \
+  uniform vec2 u_resolution;                                    \
+  uniform vec2 u_scale;                                         \
+  uniform vec2 u_offset;                                        \
+                                                                \
+  varying vec4 v_color;                                         \
+                                                                \
+  void main() {                                                 \
+    vec2 position = (a_position + u_offset) * u_scale;          \
+    vec2 clipSpace = (position / u_resolution) * 2.0 - 1.0;     \
+    gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);          \
+                                                                \
+    v_color = vec4(a_color / 255.0, 1.0);                       \
+  }                                                             ';
+  var figuresFragmentShaderCode = '\
+  precision mediump float;                                      \
+                                                                \
+  varying vec4 v_color;                                         \
+                                                                \
+  void main() {                                                 \
+    gl_FragColor = v_color;                                     \
+  }                                                             ';
+  var figuresCache = null;
+  function initFiguresGL() {
+    var canvas, gl;
+    generateGL();
+    canvas = currentCanvas;
+    currentCanvas = null;
+    gl = currentGL;
+    currentGL = null;
+    var vertexShader = createVertexShader(gl, figuresVertexShaderCode);
+    var fragmentShader = createFragmentShader(gl, figuresFragmentShaderCode);
+    var program = createProgram(gl, [vertexShader, fragmentShader]);
+    gl.useProgram(program);
+    var cache = {};
+    cache.gl = gl;
+    cache.canvas = canvas;
+    cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
+    cache.scaleLocation = gl.getUniformLocation(program, 'u_scale');
+    cache.offsetLocation = gl.getUniformLocation(program, 'u_offset');
+    cache.positionLocation = gl.getAttribLocation(program, 'a_position');
+    cache.colorLocation = gl.getAttribLocation(program, 'a_color');
+    figuresCache = cache;
+  }
+  function drawFigures(width, height, backgroundColor, figures, context) {
+    if (!figuresCache) {
+      initFiguresGL();
+    }
+    var cache = figuresCache,
+        canvas = cache.canvas,
+        gl = cache.gl;
+    canvas.width = width;
+    canvas.height = height;
+    gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+    gl.uniform2f(cache.resolutionLocation, width, height);
+    var count = 0;
+    var i, ii, rows;
+    for (i = 0, ii = figures.length; i < ii; i++) {
+      switch (figures[i].type) {
+        case 'lattice':
+          rows = figures[i].coords.length / figures[i].verticesPerRow | 0;
+          count += (rows - 1) * (figures[i].verticesPerRow - 1) * 6;
+          break;
+        case 'triangles':
+          count += figures[i].coords.length;
+          break;
+      }
+    }
+    var coords = new Float32Array(count * 2);
+    var colors = new Uint8Array(count * 3);
+    var coordsMap = context.coords,
+        colorsMap = context.colors;
+    var pIndex = 0,
+        cIndex = 0;
+    for (i = 0, ii = figures.length; i < ii; i++) {
+      var figure = figures[i],
+          ps = figure.coords,
+          cs = figure.colors;
+      switch (figure.type) {
+        case 'lattice':
+          var cols = figure.verticesPerRow;
+          rows = ps.length / cols | 0;
+          for (var row = 1; row < rows; row++) {
+            var offset = row * cols + 1;
+            for (var col = 1; col < cols; col++, offset++) {
+              coords[pIndex] = coordsMap[ps[offset - cols - 1]];
+              coords[pIndex + 1] = coordsMap[ps[offset - cols - 1] + 1];
+              coords[pIndex + 2] = coordsMap[ps[offset - cols]];
+              coords[pIndex + 3] = coordsMap[ps[offset - cols] + 1];
+              coords[pIndex + 4] = coordsMap[ps[offset - 1]];
+              coords[pIndex + 5] = coordsMap[ps[offset - 1] + 1];
+              colors[cIndex] = colorsMap[cs[offset - cols - 1]];
+              colors[cIndex + 1] = colorsMap[cs[offset - cols - 1] + 1];
+              colors[cIndex + 2] = colorsMap[cs[offset - cols - 1] + 2];
+              colors[cIndex + 3] = colorsMap[cs[offset - cols]];
+              colors[cIndex + 4] = colorsMap[cs[offset - cols] + 1];
+              colors[cIndex + 5] = colorsMap[cs[offset - cols] + 2];
+              colors[cIndex + 6] = colorsMap[cs[offset - 1]];
+              colors[cIndex + 7] = colorsMap[cs[offset - 1] + 1];
+              colors[cIndex + 8] = colorsMap[cs[offset - 1] + 2];
+              coords[pIndex + 6] = coords[pIndex + 2];
+              coords[pIndex + 7] = coords[pIndex + 3];
+              coords[pIndex + 8] = coords[pIndex + 4];
+              coords[pIndex + 9] = coords[pIndex + 5];
+              coords[pIndex + 10] = coordsMap[ps[offset]];
+              coords[pIndex + 11] = coordsMap[ps[offset] + 1];
+              colors[cIndex + 9] = colors[cIndex + 3];
+              colors[cIndex + 10] = colors[cIndex + 4];
+              colors[cIndex + 11] = colors[cIndex + 5];
+              colors[cIndex + 12] = colors[cIndex + 6];
+              colors[cIndex + 13] = colors[cIndex + 7];
+              colors[cIndex + 14] = colors[cIndex + 8];
+              colors[cIndex + 15] = colorsMap[cs[offset]];
+              colors[cIndex + 16] = colorsMap[cs[offset] + 1];
+              colors[cIndex + 17] = colorsMap[cs[offset] + 2];
+              pIndex += 12;
+              cIndex += 18;
+            }
+          }
+          break;
+        case 'triangles':
+          for (var j = 0, jj = ps.length; j < jj; j++) {
+            coords[pIndex] = coordsMap[ps[j]];
+            coords[pIndex + 1] = coordsMap[ps[j] + 1];
+            colors[cIndex] = colorsMap[cs[j]];
+            colors[cIndex + 1] = colorsMap[cs[j] + 1];
+            colors[cIndex + 2] = colorsMap[cs[j] + 2];
+            pIndex += 2;
+            cIndex += 3;
+          }
+          break;
+      }
+    }
+    if (backgroundColor) {
+      gl.clearColor(backgroundColor[0] / 255, backgroundColor[1] / 255, backgroundColor[2] / 255, 1.0);
+    } else {
+      gl.clearColor(0, 0, 0, 0);
+    }
+    gl.clear(gl.COLOR_BUFFER_BIT);
+    var coordsBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, coordsBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, coords, gl.STATIC_DRAW);
+    gl.enableVertexAttribArray(cache.positionLocation);
+    gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
+    var colorsBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
+    gl.enableVertexAttribArray(cache.colorLocation);
+    gl.vertexAttribPointer(cache.colorLocation, 3, gl.UNSIGNED_BYTE, false, 0, 0);
+    gl.uniform2f(cache.scaleLocation, context.scaleX, context.scaleY);
+    gl.uniform2f(cache.offsetLocation, context.offsetX, context.offsetY);
+    gl.drawArrays(gl.TRIANGLES, 0, count);
+    gl.flush();
+    gl.deleteBuffer(coordsBuffer);
+    gl.deleteBuffer(colorsBuffer);
+    return canvas;
+  }
+  return {
+    tryInitGL() {
+      try {
+        generateGL();
+        return !!currentGL;
+      } catch (ex) {}
+      return false;
+    },
+    composeSMask,
+    drawFigures,
+    cleanup() {
+      if (smaskCache && smaskCache.canvas) {
+        smaskCache.canvas.width = 0;
+        smaskCache.canvas.height = 0;
+      }
+      if (figuresCache && figuresCache.canvas) {
+        figuresCache.canvas.width = 0;
+        figuresCache.canvas.height = 0;
+      }
+      smaskCache = null;
+      figuresCache = null;
+    }
+  };
+}();
+exports.WebGLContext = WebGLContext;
+
 /***/ })
 /******/ ]);
 });
\ No newline at end of file
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -80,34 +80,34 @@ return /******/ (function(modules) { // 
 /******/
 /******/ 	// Object.prototype.hasOwnProperty.call
 /******/ 	__w_pdfjs_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
 /******/
 /******/ 	// __webpack_public_path__
 /******/ 	__w_pdfjs_require__.p = "";
 /******/
 /******/ 	// Load entry module and return exports
-/******/ 	return __w_pdfjs_require__(__w_pdfjs_require__.s = 17);
+/******/ 	return __w_pdfjs_require__(__w_pdfjs_require__.s = 18);
 /******/ })
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.loadJpegStream = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isNodeJS = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.createBlob = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.StatTimer = exports.PasswordResponses = exports.PasswordException = exports.PageViewport = exports.NotImplementedException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.MessageHandler = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VERBOSITY_LEVELS = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined;
 
-__w_pdfjs_require__(19);
-
-var _streams_polyfill = __w_pdfjs_require__(20);
+__w_pdfjs_require__(20);
+
+var _streams_polyfill = __w_pdfjs_require__(21);
 
 var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
 const NativeImageDecoding = {
   NONE: 'none',
   DECODE: 'decode',
   DISPLAY: 'display'
 };
 var TextRenderingMode = {
@@ -1686,26 +1686,22 @@ exports.isStream = isStream;
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
-exports.LZWStream = exports.StringStream = exports.StreamsSequenceStream = exports.Stream = exports.RunLengthStream = exports.PredictorStream = exports.NullStream = exports.JpxStream = exports.JpegStream = exports.FlateStream = exports.DecodeStream = exports.DecryptStream = exports.AsciiHexStream = exports.Ascii85Stream = undefined;
+exports.LZWStream = exports.StringStream = exports.StreamsSequenceStream = exports.Stream = exports.RunLengthStream = exports.PredictorStream = exports.NullStream = exports.FlateStream = exports.DecodeStream = exports.DecryptStream = exports.AsciiHexStream = exports.Ascii85Stream = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
 var _primitives = __w_pdfjs_require__(1);
 
-var _jpg = __w_pdfjs_require__(24);
-
-var _jpx = __w_pdfjs_require__(10);
-
 var Stream = function StreamClosure() {
   function Stream(arrayBuffer, start, length, dict) {
     this.bytes = arrayBuffer instanceof Uint8Array ? arrayBuffer : new Uint8Array(arrayBuffer);
     this.start = start || 0;
     this.pos = this.start;
     this.end = start + length || this.bytes.length;
     this.dict = dict;
   }
@@ -2356,136 +2352,16 @@ var PredictorStream = function Predictor
         break;
       default:
         throw new _util.FormatError(`Unsupported predictor: ${predictor}`);
     }
     this.bufferLength += rowBytes;
   };
   return PredictorStream;
 }();
-var JpegStream = function JpegStreamClosure() {
-  function JpegStream(stream, maybeLength, dict, params) {
-    var ch;
-    while ((ch = stream.getByte()) !== -1) {
-      if (ch === 0xFF) {
-        stream.skip(-1);
-        break;
-      }
-    }
-    this.stream = stream;
-    this.maybeLength = maybeLength;
-    this.dict = dict;
-    this.params = params;
-    DecodeStream.call(this, maybeLength);
-  }
-  JpegStream.prototype = Object.create(DecodeStream.prototype);
-  Object.defineProperty(JpegStream.prototype, 'bytes', {
-    get: function JpegStream_bytes() {
-      return (0, _util.shadow)(this, 'bytes', this.stream.getBytes(this.maybeLength));
-    },
-    configurable: true
-  });
-  JpegStream.prototype.ensureBuffer = function JpegStream_ensureBuffer(req) {
-    if (this.bufferLength) {
-      return;
-    }
-    var jpegImage = new _jpg.JpegImage();
-    var decodeArr = this.dict.getArray('Decode', 'D');
-    if (this.forceRGB && Array.isArray(decodeArr)) {
-      var bitsPerComponent = this.dict.get('BitsPerComponent') || 8;
-      var decodeArrLength = decodeArr.length;
-      var transform = new Int32Array(decodeArrLength);
-      var transformNeeded = false;
-      var maxValue = (1 << bitsPerComponent) - 1;
-      for (var i = 0; i < decodeArrLength; i += 2) {
-        transform[i] = (decodeArr[i + 1] - decodeArr[i]) * 256 | 0;
-        transform[i + 1] = decodeArr[i] * maxValue | 0;
-        if (transform[i] !== 256 || transform[i + 1] !== 0) {
-          transformNeeded = true;
-        }
-      }
-      if (transformNeeded) {
-        jpegImage.decodeTransform = transform;
-      }
-    }
-    if ((0, _primitives.isDict)(this.params)) {
-      var colorTransform = this.params.get('ColorTransform');
-      if (Number.isInteger(colorTransform)) {
-        jpegImage.colorTransform = colorTransform;
-      }
-    }
-    jpegImage.parse(this.bytes);
-    var data = jpegImage.getData(this.drawWidth, this.drawHeight, this.forceRGB);
-    this.buffer = data;
-    this.bufferLength = data.length;
-    this.eof = true;
-  };
-  JpegStream.prototype.getBytes = function JpegStream_getBytes(length) {
-    this.ensureBuffer();
-    return this.buffer;
-  };
-  JpegStream.prototype.getIR = function JpegStream_getIR(forceDataSchema) {
-    return (0, _util.createObjectURL)(this.bytes, 'image/jpeg', forceDataSchema);
-  };
-  return JpegStream;
-}();
-var JpxStream = function JpxStreamClosure() {
-  function JpxStream(stream, maybeLength, dict, params) {
-    this.stream = stream;
-    this.maybeLength = maybeLength;
-    this.dict = dict;
-    this.params = params;
-    DecodeStream.call(this, maybeLength);
-  }
-  JpxStream.prototype = Object.create(DecodeStream.prototype);
-  Object.defineProperty(JpxStream.prototype, 'bytes', {
-    get: function JpxStream_bytes() {
-      return (0, _util.shadow)(this, 'bytes', this.stream.getBytes(this.maybeLength));
-    },
-    configurable: true
-  });
-  JpxStream.prototype.ensureBuffer = function JpxStream_ensureBuffer(req) {
-    if (this.bufferLength) {
-      return;
-    }
-    var jpxImage = new _jpx.JpxImage();
-    jpxImage.parse(this.bytes);
-    var width = jpxImage.width;
-    var height = jpxImage.height;
-    var componentsCount = jpxImage.componentsCount;
-    var tileCount = jpxImage.tiles.length;
-    if (tileCount === 1) {
-      this.buffer = jpxImage.tiles[0].items;
-    } else {
-      var data = new Uint8ClampedArray(width * height * componentsCount);
-      for (var k = 0; k < tileCount; k++) {
-        var tileComponents = jpxImage.tiles[k];
-        var tileWidth = tileComponents.width;
-        var tileHeight = tileComponents.height;
-        var tileLeft = tileComponents.left;
-        var tileTop = tileComponents.top;
-        var src = tileComponents.items;
-        var srcPosition = 0;
-        var dataPosition = (width * tileTop + tileLeft) * componentsCount;
-        var imgRowSize = width * componentsCount;
-        var tileRowSize = tileWidth * componentsCount;
-        for (var j = 0; j < tileHeight; j++) {
-          var rowBytes = src.subarray(srcPosition, srcPosition + tileRowSize);
-          data.set(rowBytes, dataPosition);
-          srcPosition += tileRowSize;
-          dataPosition += imgRowSize;
-        }
-      }
-      this.buffer = data;
-    }
-    this.bufferLength = this.buffer.length;
-    this.eof = true;
-  };
-  return JpxStream;
-}();
 var DecryptStream = function DecryptStreamClosure() {
   function DecryptStream(str, maybeLength, decrypt) {
     this.str = str;
     this.dict = str.dict;
     this.decrypt = decrypt;
     this.nextChunk = null;
     this.initialized = false;
     DecodeStream.call(this, maybeLength);
@@ -2795,18 +2671,16 @@ var NullStream = function NullStreamClos
   NullStream.prototype = Stream.prototype;
   return NullStream;
 }();
 exports.Ascii85Stream = Ascii85Stream;
 exports.AsciiHexStream = AsciiHexStream;
 exports.DecryptStream = DecryptStream;
 exports.DecodeStream = DecodeStream;
 exports.FlateStream = FlateStream;
-exports.JpegStream = JpegStream;
-exports.JpxStream = JpxStream;
 exports.NullStream = NullStream;
 exports.PredictorStream = PredictorStream;
 exports.RunLengthStream = RunLengthStream;
 exports.Stream = Stream;
 exports.StreamsSequenceStream = StreamsSequenceStream;
 exports.StringStream = StringStream;
 exports.LZWStream = LZWStream;
 
@@ -3795,16 +3669,20 @@ var _stream = __w_pdfjs_require__(2);
 var _util = __w_pdfjs_require__(0);
 
 var _primitives = __w_pdfjs_require__(1);
 
 var _ccitt_stream = __w_pdfjs_require__(25);
 
 var _jbig2_stream = __w_pdfjs_require__(27);
 
+var _jpeg_stream = __w_pdfjs_require__(6);
+
+var _jpx_stream = __w_pdfjs_require__(30);
+
 var MAX_LENGTH_TO_CACHE = 1000;
 var Parser = function ParserClosure() {
   function Parser(lexer, allowStreams, xref, recoveryMode) {
     this.lexer = lexer;
     this.allowStreams = allowStreams;
     this.xref = xref;
     this.recoveryMode = recoveryMode || false;
     this.imageCache = Object.create(null);
@@ -4274,21 +4152,21 @@ var Parser = function ParserClosure() {
               earlyChange = params.get('EarlyChange');
             }
             return new _stream.PredictorStream(new _stream.LZWStream(stream, maybeLength, earlyChange), maybeLength, params);
           }
           return new _stream.LZWStream(stream, maybeLength, earlyChange);
         }
         if (name === 'DCTDecode' || name === 'DCT') {
           xrefStreamStats[_util.StreamType.DCT] = true;
-          return new _stream.JpegStream(stream, maybeLength, stream.dict, params);
+          return new _jpeg_stream.JpegStream(stream, maybeLength, stream.dict, params);
         }
         if (name === 'JPXDecode' || name === 'JPX') {
           xrefStreamStats[_util.StreamType.JPX] = true;
-          return new _stream.JpxStream(stream, maybeLength, stream.dict, params);
+          return new _jpx_stream.JpxStream(stream, maybeLength, stream.dict, params);
         }
         if (name === 'ASCII85Decode' || name === 'A85') {
           xrefStreamStats[_util.StreamType.A85] = true;
           return new _stream.Ascii85Stream(stream, maybeLength);
         }
         if (name === 'ASCIIHexDecode' || name === 'AHx') {
           xrefStreamStats[_util.StreamType.AHX] = true;
           return new _stream.AsciiHexStream(stream, maybeLength);
@@ -4753,16 +4631,105 @@ exports.Parser = Parser;
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
+exports.JpegStream = undefined;
+
+var _util = __w_pdfjs_require__(0);
+
+var _stream = __w_pdfjs_require__(2);
+
+var _primitives = __w_pdfjs_require__(1);
+
+var _jpg = __w_pdfjs_require__(29);
+
+let JpegStream = function JpegStreamClosure() {
+  function JpegStream(stream, maybeLength, dict, params) {
+    let ch;
+    while ((ch = stream.getByte()) !== -1) {
+      if (ch === 0xFF) {
+        stream.skip(-1);
+        break;
+      }
+    }
+    this.stream = stream;
+    this.maybeLength = maybeLength;
+    this.dict = dict;
+    this.params = params;
+    _stream.DecodeStream.call(this, maybeLength);
+  }
+  JpegStream.prototype = Object.create(_stream.DecodeStream.prototype);
+  Object.defineProperty(JpegStream.prototype, 'bytes', {
+    get: function JpegStream_bytes() {
+      return (0, _util.shadow)(this, 'bytes', this.stream.getBytes(this.maybeLength));
+    },
+    configurable: true
+  });
+  JpegStream.prototype.ensureBuffer = function (requested) {};
+  JpegStream.prototype.readBlock = function () {
+    if (this.eof) {
+      return;
+    }
+    let jpegImage = new _jpg.JpegImage();
+    let decodeArr = this.dict.getArray('Decode', 'D');
+    if (this.forceRGB && Array.isArray(decodeArr)) {
+      let bitsPerComponent = this.dict.get('BitsPerComponent') || 8;
+      let decodeArrLength = decodeArr.length;
+      let transform = new Int32Array(decodeArrLength);
+      let transformNeeded = false;
+      let maxValue = (1 << bitsPerComponent) - 1;
+      for (let i = 0; i < decodeArrLength; i += 2) {
+        transform[i] = (decodeArr[i + 1] - decodeArr[i]) * 256 | 0;
+        transform[i + 1] = decodeArr[i] * maxValue | 0;
+        if (transform[i] !== 256 || transform[i + 1] !== 0) {
+          transformNeeded = true;
+        }
+      }
+      if (transformNeeded) {
+        jpegImage.decodeTransform = transform;
+      }
+    }
+    if ((0, _primitives.isDict)(this.params)) {
+      let colorTransform = this.params.get('ColorTransform');
+      if (Number.isInteger(colorTransform)) {
+        jpegImage.colorTransform = colorTransform;
+      }
+    }
+    jpegImage.parse(this.bytes);
+    let data = jpegImage.getData(this.drawWidth, this.drawHeight, this.forceRGB);
+    this.buffer = data;
+    this.bufferLength = data.length;
+    this.eof = true;
+  };
+  JpegStream.prototype.getBytes = function (length) {
+    this.readBlock();
+    return this.buffer;
+  };
+  JpegStream.prototype.getIR = function (forceDataSchema = false) {
+    return (0, _util.createObjectURL)(this.bytes, 'image/jpeg', forceDataSchema);
+  };
+  return JpegStream;
+}();
+exports.JpegStream = JpegStream;
+
+/***/ }),
+/* 7 */
+/***/ (function(module, exports, __w_pdfjs_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
 exports.OperatorList = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
 var QueueOptimizer = function QueueOptimizerClosure() {
   function addState(parentState, pattern, checkFn, iterateFn, processFn) {
     var state = parentState;
     for (var i = 0, ii = pattern.length - 1; i < ii; i++) {
@@ -5272,17 +5239,17 @@ var OperatorList = function OperatorList
       this.optimizer.reset();
     }
   };
   return OperatorList;
 }();
 exports.OperatorList = OperatorList;
 
 /***/ }),
-/* 7 */
+/* 8 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 var getLookupTableFactory = __w_pdfjs_require__(0).getLookupTableFactory;
 var getGlyphsUnicode = getLookupTableFactory(function (t) {
  t['A'] = 0x0041;
  t['AE'] = 0x00C6;
  t['AEacute'] = 0x01FC;
  t['AEmacron'] = 0x01E2;
@@ -9808,17 +9775,17 @@ var getDingbatsGlyphsUnicode = getLookup
  t['a95'] = 0x2774;
  t['a96'] = 0x2775;
  t['.notdef'] = 0x0000;
 });
 exports.getGlyphsUnicode = getGlyphsUnicode;
 exports.getDingbatsGlyphsUnicode = getDingbatsGlyphsUnicode;
 
 /***/ }),
-/* 8 */
+/* 9 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -10276,36 +10243,36 @@ var ChunkedStreamManager = function Chun
     }
   };
   return ChunkedStreamManager;
 }();
 exports.ChunkedStream = ChunkedStream;
 exports.ChunkedStreamManager = ChunkedStreamManager;
 
 /***/ }),
-/* 9 */
+/* 10 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.FileSpec = exports.XRef = exports.ObjectLoader = exports.Catalog = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
 var _primitives = __w_pdfjs_require__(1);
 
 var _parser = __w_pdfjs_require__(5);
 
-var _chunked_stream = __w_pdfjs_require__(8);
-
-var _crypto = __w_pdfjs_require__(12);
+var _chunked_stream = __w_pdfjs_require__(9);
+
+var _crypto = __w_pdfjs_require__(13);
 
 var _colorspace = __w_pdfjs_require__(3);
 
 var Catalog = function CatalogClosure() {
   function Catalog(pdfManager, xref, pageFactory) {
     this.pdfManager = pdfManager;
     this.xref = xref;
     this.catDict = xref.getCatalogObj();
@@ -11785,17 +11752,357 @@ let ObjectLoader = function () {
   return ObjectLoader;
 }();
 exports.Catalog = Catalog;
 exports.ObjectLoader = ObjectLoader;
 exports.XRef = XRef;
 exports.FileSpec = FileSpec;
 
 /***/ }),
-/* 10 */
+/* 11 */
+/***/ (function(module, exports, __w_pdfjs_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+var ArithmeticDecoder = function ArithmeticDecoderClosure() {
+  var QeTable = [{
+    qe: 0x5601,
+    nmps: 1,
+    nlps: 1,
+    switchFlag: 1
+  }, {
+    qe: 0x3401,
+    nmps: 2,
+    nlps: 6,
+    switchFlag: 0
+  }, {
+    qe: 0x1801,
+    nmps: 3,
+    nlps: 9,
+    switchFlag: 0
+  }, {
+    qe: 0x0AC1,
+    nmps: 4,
+    nlps: 12,
+    switchFlag: 0
+  }, {
+    qe: 0x0521,
+    nmps: 5,
+    nlps: 29,
+    switchFlag: 0
+  }, {
+    qe: 0x0221,
+    nmps: 38,
+    nlps: 33,
+    switchFlag: 0
+  }, {
+    qe: 0x5601,
+    nmps: 7,
+    nlps: 6,
+    switchFlag: 1
+  }, {
+    qe: 0x5401,
+    nmps: 8,
+    nlps: 14,
+    switchFlag: 0
+  }, {
+    qe: 0x4801,
+    nmps: 9,
+    nlps: 14,
+    switchFlag: 0
+  }, {
+    qe: 0x3801,
+    nmps: 10,
+    nlps: 14,
+    switchFlag: 0
+  }, {
+    qe: 0x3001,
+    nmps: 11,
+    nlps: 17,
+    switchFlag: 0
+  }, {
+    qe: 0x2401,
+    nmps: 12,
+    nlps: 18,
+    switchFlag: 0
+  }, {
+    qe: 0x1C01,
+    nmps: 13,
+    nlps: 20,
+    switchFlag: 0
+  }, {
+    qe: 0x1601,
+    nmps: 29,
+    nlps: 21,
+    switchFlag: 0
+  }, {
+    qe: 0x5601,
+    nmps: 15,
+    nlps: 14,
+    switchFlag: 1
+  }, {
+    qe: 0x5401,
+    nmps: 16,
+    nlps: 14,
+    switchFlag: 0
+  }, {
+    qe: 0x5101,
+    nmps: 17,
+    nlps: 15,
+    switchFlag: 0
+  }, {
+    qe: 0x4801,
+    nmps: 18,
+    nlps: 16,
+    switchFlag: 0
+  }, {
+    qe: 0x3801,
+    nmps: 19,
+    nlps: 17,
+    switchFlag: 0
+  }, {
+    qe: 0x3401,
+    nmps: 20,
+    nlps: 18,
+    switchFlag: 0
+  }, {
+    qe: 0x3001,
+    nmps: 21,
+    nlps: 19,
+    switchFlag: 0
+  }, {
+    qe: 0x2801,
+    nmps: 22,
+    nlps: 19,
+    switchFlag: 0
+  }, {
+    qe: 0x2401,
+    nmps: 23,
+    nlps: 20,
+    switchFlag: 0
+  }, {
+    qe: 0x2201,
+    nmps: 24,
+    nlps: 21,
+    switchFlag: 0
+  }, {
+    qe: 0x1C01,
+    nmps: 25,
+    nlps: 22,
+    switchFlag: 0
+  }, {
+    qe: 0x1801,
+    nmps: 26,
+    nlps: 23,
+    switchFlag: 0
+  }, {
+    qe: 0x1601,
+    nmps: 27,
+    nlps: 24,
+    switchFlag: 0
+  }, {
+    qe: 0x1401,
+    nmps: 28,
+    nlps: 25,
+    switchFlag: 0
+  }, {
+    qe: 0x1201,
+    nmps: 29,
+    nlps: 26,
+    switchFlag: 0
+  }, {
+    qe: 0x1101,
+    nmps: 30,
+    nlps: 27,
+    switchFlag: 0
+  }, {
+    qe: 0x0AC1,
+    nmps: 31,
+    nlps: 28,
+    switchFlag: 0
+  }, {
+    qe: 0x09C1,
+    nmps: 32,
+    nlps: 29,
+    switchFlag: 0
+  }, {
+    qe: 0x08A1,
+    nmps: 33,
+    nlps: 30,
+    switchFlag: 0
+  }, {
+    qe: 0x0521,
+    nmps: 34,
+    nlps: 31,
+    switchFlag: 0
+  }, {
+    qe: 0x0441,
+    nmps: 35,
+    nlps: 32,
+    switchFlag: 0
+  }, {
+    qe: 0x02A1,
+    nmps: 36,
+    nlps: 33,
+    switchFlag: 0
+  }, {
+    qe: 0x0221,
+    nmps: 37,
+    nlps: 34,
+    switchFlag: 0
+  }, {
+    qe: 0x0141,
+    nmps: 38,
+    nlps: 35,
+    switchFlag: 0
+  }, {
+    qe: 0x0111,
+    nmps: 39,
+    nlps: 36,
+    switchFlag: 0
+  }, {
+    qe: 0x0085,
+    nmps: 40,
+    nlps: 37,
+    switchFlag: 0
+  }, {
+    qe: 0x0049,
+    nmps: 41,
+    nlps: 38,
+    switchFlag: 0
+  }, {
+    qe: 0x0025,
+    nmps: 42,
+    nlps: 39,
+    switchFlag: 0
+  }, {
+    qe: 0x0015,
+    nmps: 43,
+    nlps: 40,
+    switchFlag: 0
+  }, {
+    qe: 0x0009,
+    nmps: 44,
+    nlps: 41,
+    switchFlag: 0
+  }, {
+    qe: 0x0005,
+    nmps: 45,
+    nlps: 42,
+    switchFlag: 0
+  }, {
+    qe: 0x0001,
+    nmps: 45,
+    nlps: 43,
+    switchFlag: 0
+  }, {
+    qe: 0x5601,
+    nmps: 46,
+    nlps: 46,
+    switchFlag: 0
+  }];
+  function ArithmeticDecoder(data, start, end) {
+    this.data = data;
+    this.bp = start;
+    this.dataEnd = end;
+    this.chigh = data[start];
+    this.clow = 0;
+    this.byteIn();
+    this.chigh = this.chigh << 7 & 0xFFFF | this.clow >> 9 & 0x7F;
+    this.clow = this.clow << 7 & 0xFFFF;
+    this.ct -= 7;
+    this.a = 0x8000;
+  }
+  ArithmeticDecoder.prototype = {
+    byteIn: function ArithmeticDecoder_byteIn() {
+      var data = this.data;
+      var bp = this.bp;
+      if (data[bp] === 0xFF) {
+        var b1 = data[bp + 1];
+        if (b1 > 0x8F) {
+          this.clow += 0xFF00;
+          this.ct = 8;
+        } else {
+          bp++;
+          this.clow += data[bp] << 9;
+          this.ct = 7;
+          this.bp = bp;
+        }
+      } else {
+        bp++;
+        this.clow += bp < this.dataEnd ? data[bp] << 8 : 0xFF00;
+        this.ct = 8;
+        this.bp = bp;
+      }
+      if (this.clow > 0xFFFF) {
+        this.chigh += this.clow >> 16;
+        this.clow &= 0xFFFF;
+      }
+    },
+    readBit: function ArithmeticDecoder_readBit(contexts, pos) {
+      var cx_index = contexts[pos] >> 1,
+          cx_mps = contexts[pos] & 1;
+      var qeTableIcx = QeTable[cx_index];
+      var qeIcx = qeTableIcx.qe;
+      var d;
+      var a = this.a - qeIcx;
+      if (this.chigh < qeIcx) {
+        if (a < qeIcx) {
+          a = qeIcx;
+          d = cx_mps;
+          cx_index = qeTableIcx.nmps;
+        } else {
+          a = qeIcx;
+          d = 1 ^ cx_mps;
+          if (qeTableIcx.switchFlag === 1) {
+            cx_mps = d;
+          }
+          cx_index = qeTableIcx.nlps;
+        }
+      } else {
+        this.chigh -= qeIcx;
+        if ((a & 0x8000) !== 0) {
+          this.a = a;
+          return cx_mps;
+        }
+        if (a < qeIcx) {
+          d = 1 ^ cx_mps;
+          if (qeTableIcx.switchFlag === 1) {
+            cx_mps = d;
+          }
+          cx_index = qeTableIcx.nlps;
+        } else {
+          d = cx_mps;
+          cx_index = qeTableIcx.nmps;
+        }
+      }
+      do {
+        if (this.ct === 0) {
+          this.byteIn();
+        }
+        a <<= 1;
+        this.chigh = this.chigh << 1 & 0xFFFF | this.clow >> 15 & 1;
+        this.clow = this.clow << 1 & 0xFFFF;
+        this.ct--;
+      } while ((a & 0x8000) === 0);
+      this.a = a;
+      contexts[pos] = cx_index << 1 | cx_mps;
+      return d;
+    }
+  };
+  return ArithmeticDecoder;
+}();
+exports.ArithmeticDecoder = ArithmeticDecoder;
+
+/***/ }),
+/* 12 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -13712,357 +14019,17 @@ var JpxImage = function JpxImageClosure(
     };
     return ReversibleTransform;
   }();
   return JpxImage;
 }();
 exports.JpxImage = JpxImage;
 
 /***/ }),
-/* 11 */
-/***/ (function(module, exports, __w_pdfjs_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-var ArithmeticDecoder = function ArithmeticDecoderClosure() {
-  var QeTable = [{
-    qe: 0x5601,
-    nmps: 1,
-    nlps: 1,
-    switchFlag: 1
-  }, {
-    qe: 0x3401,
-    nmps: 2,
-    nlps: 6,
-    switchFlag: 0
-  }, {
-    qe: 0x1801,
-    nmps: 3,
-    nlps: 9,
-    switchFlag: 0
-  }, {
-    qe: 0x0AC1,
-    nmps: 4,
-    nlps: 12,
-    switchFlag: 0
-  }, {
-    qe: 0x0521,
-    nmps: 5,
-    nlps: 29,
-    switchFlag: 0
-  }, {
-    qe: 0x0221,
-    nmps: 38,
-    nlps: 33,
-    switchFlag: 0
-  }, {
-    qe: 0x5601,
-    nmps: 7,
-    nlps: 6,
-    switchFlag: 1
-  }, {
-    qe: 0x5401,
-    nmps: 8,
-    nlps: 14,
-    switchFlag: 0
-  }, {
-    qe: 0x4801,
-    nmps: 9,
-    nlps: 14,
-    switchFlag: 0
-  }, {
-    qe: 0x3801,
-    nmps: 10,
-    nlps: 14,
-    switchFlag: 0
-  }, {
-    qe: 0x3001,
-    nmps: 11,
-    nlps: 17,
-    switchFlag: 0
-  }, {
-    qe: 0x2401,
-    nmps: 12,
-    nlps: 18,
-    switchFlag: 0
-  }, {
-    qe: 0x1C01,
-    nmps: 13,
-    nlps: 20,
-    switchFlag: 0
-  }, {
-    qe: 0x1601,
-    nmps: 29,
-    nlps: 21,
-    switchFlag: 0
-  }, {
-    qe: 0x5601,
-    nmps: 15,
-    nlps: 14,
-    switchFlag: 1
-  }, {
-    qe: 0x5401,
-    nmps: 16,
-    nlps: 14,
-    switchFlag: 0
-  }, {
-    qe: 0x5101,
-    nmps: 17,
-    nlps: 15,
-    switchFlag: 0
-  }, {
-    qe: 0x4801,
-    nmps: 18,
-    nlps: 16,
-    switchFlag: 0
-  }, {
-    qe: 0x3801,
-    nmps: 19,
-    nlps: 17,
-    switchFlag: 0
-  }, {
-    qe: 0x3401,
-    nmps: 20,
-    nlps: 18,
-    switchFlag: 0
-  }, {
-    qe: 0x3001,
-    nmps: 21,
-    nlps: 19,
-    switchFlag: 0
-  }, {
-    qe: 0x2801,
-    nmps: 22,
-    nlps: 19,
-    switchFlag: 0
-  }, {
-    qe: 0x2401,
-    nmps: 23,
-    nlps: 20,
-    switchFlag: 0
-  }, {
-    qe: 0x2201,
-    nmps: 24,
-    nlps: 21,
-    switchFlag: 0
-  }, {
-    qe: 0x1C01,
-    nmps: 25,
-    nlps: 22,
-    switchFlag: 0
-  }, {
-    qe: 0x1801,
-    nmps: 26,
-    nlps: 23,
-    switchFlag: 0
-  }, {
-    qe: 0x1601,
-    nmps: 27,
-    nlps: 24,
-    switchFlag: 0
-  }, {
-    qe: 0x1401,
-    nmps: 28,
-    nlps: 25,
-    switchFlag: 0
-  }, {
-    qe: 0x1201,
-    nmps: 29,
-    nlps: 26,
-    switchFlag: 0
-  }, {
-    qe: 0x1101,
-    nmps: 30,
-    nlps: 27,
-    switchFlag: 0
-  }, {
-    qe: 0x0AC1,
-    nmps: 31,
-    nlps: 28,
-    switchFlag: 0
-  }, {
-    qe: 0x09C1,
-    nmps: 32,
-    nlps: 29,
-    switchFlag: 0
-  }, {
-    qe: 0x08A1,
-    nmps: 33,
-    nlps: 30,
-    switchFlag: 0
-  }, {
-    qe: 0x0521,
-    nmps: 34,
-    nlps: 31,
-    switchFlag: 0
-  }, {
-    qe: 0x0441,
-    nmps: 35,
-    nlps: 32,
-    switchFlag: 0
-  }, {
-    qe: 0x02A1,
-    nmps: 36,
-    nlps: 33,
-    switchFlag: 0
-  }, {
-    qe: 0x0221,
-    nmps: 37,
-    nlps: 34,
-    switchFlag: 0
-  }, {
-    qe: 0x0141,
-    nmps: 38,
-    nlps: 35,
-    switchFlag: 0
-  }, {
-    qe: 0x0111,
-    nmps: 39,
-    nlps: 36,
-    switchFlag: 0
-  }, {
-    qe: 0x0085,
-    nmps: 40,
-    nlps: 37,
-    switchFlag: 0
-  }, {
-    qe: 0x0049,
-    nmps: 41,
-    nlps: 38,
-    switchFlag: 0
-  }, {
-    qe: 0x0025,
-    nmps: 42,
-    nlps: 39,
-    switchFlag: 0
-  }, {
-    qe: 0x0015,
-    nmps: 43,
-    nlps: 40,
-    switchFlag: 0
-  }, {
-    qe: 0x0009,
-    nmps: 44,
-    nlps: 41,
-    switchFlag: 0
-  }, {
-    qe: 0x0005,
-    nmps: 45,
-    nlps: 42,
-    switchFlag: 0
-  }, {
-    qe: 0x0001,
-    nmps: 45,
-    nlps: 43,
-    switchFlag: 0
-  }, {
-    qe: 0x5601,
-    nmps: 46,
-    nlps: 46,
-    switchFlag: 0
-  }];
-  function ArithmeticDecoder(data, start, end) {
-    this.data = data;
-    this.bp = start;
-    this.dataEnd = end;
-    this.chigh = data[start];
-    this.clow = 0;
-    this.byteIn();
-    this.chigh = this.chigh << 7 & 0xFFFF | this.clow >> 9 & 0x7F;
-    this.clow = this.clow << 7 & 0xFFFF;
-    this.ct -= 7;
-    this.a = 0x8000;
-  }
-  ArithmeticDecoder.prototype = {
-    byteIn: function ArithmeticDecoder_byteIn() {
-      var data = this.data;
-      var bp = this.bp;
-      if (data[bp] === 0xFF) {
-        var b1 = data[bp + 1];
-        if (b1 > 0x8F) {
-          this.clow += 0xFF00;
-          this.ct = 8;
-        } else {
-          bp++;
-          this.clow += data[bp] << 9;
-          this.ct = 7;
-          this.bp = bp;
-        }
-      } else {
-        bp++;
-        this.clow += bp < this.dataEnd ? data[bp] << 8 : 0xFF00;
-        this.ct = 8;
-        this.bp = bp;
-      }
-      if (this.clow > 0xFFFF) {
-        this.chigh += this.clow >> 16;
-        this.clow &= 0xFFFF;
-      }
-    },
-    readBit: function ArithmeticDecoder_readBit(contexts, pos) {
-      var cx_index = contexts[pos] >> 1,
-          cx_mps = contexts[pos] & 1;
-      var qeTableIcx = QeTable[cx_index];
-      var qeIcx = qeTableIcx.qe;
-      var d;
-      var a = this.a - qeIcx;
-      if (this.chigh < qeIcx) {
-        if (a < qeIcx) {
-          a = qeIcx;
-          d = cx_mps;
-          cx_index = qeTableIcx.nmps;
-        } else {
-          a = qeIcx;
-          d = 1 ^ cx_mps;
-          if (qeTableIcx.switchFlag === 1) {
-            cx_mps = d;
-          }
-          cx_index = qeTableIcx.nlps;
-        }
-      } else {
-        this.chigh -= qeIcx;
-        if ((a & 0x8000) !== 0) {
-          this.a = a;
-          return cx_mps;
-        }
-        if (a < qeIcx) {
-          d = 1 ^ cx_mps;
-          if (qeTableIcx.switchFlag === 1) {
-            cx_mps = d;
-          }
-          cx_index = qeTableIcx.nlps;
-        } else {
-          d = cx_mps;
-          cx_index = qeTableIcx.nmps;
-        }
-      }
-      do {
-        if (this.ct === 0) {
-          this.byteIn();
-        }
-        a <<= 1;
-        this.chigh = this.chigh << 1 & 0xFFFF | this.clow >> 15 & 1;
-        this.clow = this.clow << 1 & 0xFFFF;
-        this.ct--;
-      } while ((a & 0x8000) === 0);
-      this.a = a;
-      contexts[pos] = cx_index << 1 | cx_mps;
-      return d;
-    }
-  };
-  return ArithmeticDecoder;
-}();
-exports.ArithmeticDecoder = ArithmeticDecoder;
-
-/***/ }),
-/* 12 */
+/* 13 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -15646,30 +15613,30 @@ exports.CipherTransformFactory = CipherT
 exports.PDF17 = PDF17;
 exports.PDF20 = PDF20;
 exports.calculateMD5 = calculateMD5;
 exports.calculateSHA256 = calculateSHA256;
 exports.calculateSHA384 = calculateSHA384;
 exports.calculateSHA512 = calculateSHA512;
 
 /***/ }),
-/* 13 */
+/* 14 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.CFFCompiler = exports.CFFPrivateDict = exports.CFFTopDict = exports.CFFCharset = exports.CFFIndex = exports.CFFStrings = exports.CFFHeader = exports.CFF = exports.CFFParser = exports.CFFStandardStrings = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
-var _charsets = __w_pdfjs_require__(33);
+var _charsets = __w_pdfjs_require__(35);
 
 var _encodings = __w_pdfjs_require__(4);
 
 var MAX_SUBR_NESTING = 10;
 var CFFStandardStrings = ['.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl', 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', 'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', '001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 'Semibold'];
 var CFFParser = function CFFParserClosure() {
   var CharstringValidationData = [null, {
     id: 'hstem',
@@ -17066,17 +17033,17 @@ exports.CFFHeader = CFFHeader;
 exports.CFFStrings = CFFStrings;
 exports.CFFIndex = CFFIndex;
 exports.CFFCharset = CFFCharset;
 exports.CFFTopDict = CFFTopDict;
 exports.CFFPrivateDict = CFFPrivateDict;
 exports.CFFCompiler = CFFCompiler;
 
 /***/ }),
-/* 14 */
+/* 15 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -17717,17 +17684,17 @@ var getSupplementalGlyphMapForArialBlack
 exports.getStdFontMap = getStdFontMap;
 exports.getNonStdFontMap = getNonStdFontMap;
 exports.getSerifFonts = getSerifFonts;
 exports.getSymbolsFonts = getSymbolsFonts;
 exports.getGlyphMapForStandardFonts = getGlyphMapForStandardFonts;
 exports.getSupplementalGlyphMapForArialBlack = getSupplementalGlyphMapForArialBlack;
 
 /***/ }),
-/* 15 */
+/* 16 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 var getLookupTableFactory = __w_pdfjs_require__(0).getLookupTableFactory;
 var getSpecialPUASymbols = getLookupTableFactory(function (t) {
  t[63721] = 0x00A9;
  t[63193] = 0x00A9;
  t[63720] = 0x00AE;
  t[63194] = 0x00AE;
@@ -19694,32 +19661,32 @@ function reverseIfRtl(chars) {
 }
 exports.mapSpecialUnicodeValues = mapSpecialUnicodeValues;
 exports.reverseIfRtl = reverseIfRtl;
 exports.getUnicodeRangeFor = getUnicodeRangeFor;
 exports.getNormalizedUnicodes = getNormalizedUnicodes;
 exports.getUnicodeForGlyph = getUnicodeForGlyph;
 
 /***/ }),
-/* 16 */
+/* 17 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.PostScriptCompiler = exports.PostScriptEvaluator = exports.PDFFunctionFactory = exports.isPDFFunction = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
 var _primitives = __w_pdfjs_require__(1);
 
-var _ps_parser = __w_pdfjs_require__(39);
+var _ps_parser = __w_pdfjs_require__(41);
 
 let IsEvalSupportedCached = {
   get value() {
     return (0, _util.shadow)(this, 'value', (0, _util.isEvalSupported)());
   }
 };
 class PDFFunctionFactory {
   constructor({ xref, isEvalSupported = true }) {
@@ -20750,42 +20717,42 @@ var PostScriptCompiler = function PostSc
   return PostScriptCompiler;
 }();
 exports.isPDFFunction = isPDFFunction;
 exports.PDFFunctionFactory = PDFFunctionFactory;
 exports.PostScriptEvaluator = PostScriptEvaluator;
 exports.PostScriptCompiler = PostScriptCompiler;
 
 /***/ }),
-/* 17 */
-/***/ (function(module, exports, __w_pdfjs_require__) {
-
-"use strict";
-
-
-var pdfjsVersion = '2.0.120';
-var pdfjsBuild = 'e162df59';
-var pdfjsCoreWorker = __w_pdfjs_require__(18);
+/* 18 */
+/***/ (function(module, exports, __w_pdfjs_require__) {
+
+"use strict";
+
+
+var pdfjsVersion = '2.0.161';
+var pdfjsBuild = 'b32d659d';
+var pdfjsCoreWorker = __w_pdfjs_require__(19);
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
-/* 18 */
+/* 19 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.WorkerMessageHandler = exports.WorkerTask = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
-var _pdf_manager = __w_pdfjs_require__(22);
+var _pdf_manager = __w_pdfjs_require__(23);
 
 var _primitives = __w_pdfjs_require__(1);
 
 var WorkerTask = function WorkerTaskClosure() {
   function WorkerTask(name) {
     this.name = name;
     this.terminated = false;
     this._capability = (0, _util.createPromiseCapability)();
@@ -20952,17 +20919,17 @@ var WorkerMessageHandler = {
     });
   },
   createDocumentHandler(docParams, port) {
     var pdfManager;
     var terminated = false;
     var cancelXHRs = null;
     var WorkerTasks = [];
     let apiVersion = docParams.apiVersion;
-    let workerVersion = '2.0.120';
+    let workerVersion = '2.0.161';
     if (apiVersion !== null && 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';
     var handler = new _util.MessageHandler(workerHandlerName, docId, port);
     handler.postMessageTransfers = docParams.postMessageTransfers;
@@ -21341,26 +21308,26 @@ function isMessagePort(maybePort) {
 }
 if (typeof window === 'undefined' && !(0, _util.isNodeJS)() && typeof self !== 'undefined' && isMessagePort(self)) {
   WorkerMessageHandler.initializeFromPort(self);
 }
 exports.WorkerTask = WorkerTask;
 exports.WorkerMessageHandler = WorkerMessageHandler;
 
 /***/ }),
-/* 19 */
+/* 20 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 ;
 
 /***/ }),
-/* 20 */
+/* 21 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 let isReadableStreamSupported = false;
 if (typeof ReadableStream !== 'undefined') {
   try {
@@ -21370,21 +21337,21 @@ if (typeof ReadableStream !== 'undefined
       }
     });
     isReadableStreamSupported = true;
   } catch (e) {}
 }
 if (isReadableStreamSupported) {
   exports.ReadableStream = ReadableStream;
 } else {
-  exports.ReadableStream = __w_pdfjs_require__(21).ReadableStream;
-}
-
-/***/ }),
-/* 21 */
+  exports.ReadableStream = __w_pdfjs_require__(22).ReadableStream;
+}
+
+/***/ }),
+/* 22 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 (function (e, a) {
   for (var i in a) e[i] = a[i];
 })(exports, function (modules) {
@@ -24390,32 +24357,32 @@ if (isReadableStreamSupported) {
   function streamBrandCheckException(name) {
     return new TypeError('TransformStream.prototype.' + name + ' can only be used on a TransformStream');
   }
 }, function (module, exports, __w_pdfjs_require__) {
   module.exports = __w_pdfjs_require__(5);
 }]));
 
 /***/ }),
-/* 22 */
+/* 23 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.NetworkPdfManager = exports.LocalPdfManager = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
-var _chunked_stream = __w_pdfjs_require__(8);
-
-var _document = __w_pdfjs_require__(23);
+var _chunked_stream = __w_pdfjs_require__(9);
+
+var _document = __w_pdfjs_require__(24);
 
 var _stream = __w_pdfjs_require__(2);
 
 var BasePdfManager = function BasePdfManagerClosure() {
   function BasePdfManager() {
     throw new Error('Cannot initialize BaseManagerManager');
   }
   BasePdfManager.prototype = {
@@ -24574,46 +24541,46 @@ var NetworkPdfManager = function Network
     }
   });
   return NetworkPdfManager;
 }();
 exports.LocalPdfManager = LocalPdfManager;
 exports.NetworkPdfManager = NetworkPdfManager;
 
 /***/ }),
-/* 23 */
+/* 24 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.PDFDocument = exports.Page = undefined;
 
-var _obj = __w_pdfjs_require__(9);
+var _obj = __w_pdfjs_require__(10);
 
 var _primitives = __w_pdfjs_require__(1);
 
 var _util = __w_pdfjs_require__(0);
 
 var _stream = __w_pdfjs_require__(2);
 
-var _annotation = __w_pdfjs_require__(29);
-
-var _crypto = __w_pdfjs_require__(12);
+var _annotation = __w_pdfjs_require__(31);
+
+var _crypto = __w_pdfjs_require__(13);
 
 var _parser = __w_pdfjs_require__(5);
 
-var _operator_list = __w_pdfjs_require__(6);
-
-var _evaluator = __w_pdfjs_require__(30);
-
-var _function = __w_pdfjs_require__(16);
+var _operator_list = __w_pdfjs_require__(7);
+
+var _evaluator = __w_pdfjs_require__(32);
+
+var _function = __w_pdfjs_require__(17);
 
 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({ pdfManager, xref, pageIndex, pageDict, ref, fontCache, builtInCMapCache, pdfFunctionFactory }) {
@@ -25097,932 +25064,16 @@ var PDFDocument = function PDFDocumentCl
     }
   };
   return PDFDocument;
 }();
 exports.Page = Page;
 exports.PDFDocument = PDFDocument;
 
 /***/ }),
-/* 24 */
-/***/ (function(module, exports, __w_pdfjs_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports.JpegImage = undefined;
-
-var _util = __w_pdfjs_require__(0);
-
-let JpegError = function JpegErrorClosure() {
-  function JpegError(msg) {
-    this.message = 'JPEG error: ' + msg;
-  }
-  JpegError.prototype = new Error();
-  JpegError.prototype.name = 'JpegError';
-  JpegError.constructor = JpegError;
-  return JpegError;
-}();
-var JpegImage = function JpegImageClosure() {
-  var dctZigZag = new Uint8Array([0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63]);
-  var dctCos1 = 4017;
-  var dctSin1 = 799;
-  var dctCos3 = 3406;
-  var dctSin3 = 2276;
-  var dctCos6 = 1567;
-  var dctSin6 = 3784;
-  var dctSqrt2 = 5793;
-  var dctSqrt1d2 = 2896;
-  function JpegImage() {
-    this.decodeTransform = null;
-    this.colorTransform = -1;
-  }
-  function buildHuffmanTable(codeLengths, values) {
-    var k = 0,
-        code = [],
-        i,
-        j,
-        length = 16;
-    while (length > 0 && !codeLengths[length - 1]) {
-      length--;
-    }
-    code.push({
-      children: [],
-      index: 0
-    });
-    var p = code[0],
-        q;
-    for (i = 0; i < length; i++) {
-      for (j = 0; j < codeLengths[i]; j++) {
-        p = code.pop();
-        p.children[p.index] = values[k];
-        while (p.index > 0) {
-          p = code.pop();
-        }
-        p.index++;
-        code.push(p);
-        while (code.length <= i) {
-          code.push(q = {
-            children: [],
-            index: 0
-          });
-          p.children[p.index] = q.children;
-          p = q;
-        }
-        k++;
-      }
-      if (i + 1 < length) {
-        code.push(q = {
-          children: [],
-          index: 0
-        });
-        p.children[p.index] = q.children;
-        p = q;
-      }
-    }
-    return code[0].children;
-  }
-  function getBlockBufferOffset(component, row, col) {
-    return 64 * ((component.blocksPerLine + 1) * row + col);
-  }
-  function decodeScan(data, offset, frame, components, resetInterval, spectralStart, spectralEnd, successivePrev, successive) {
-    var mcusPerLine = frame.mcusPerLine;
-    var progressive = frame.progressive;
-    var startOffset = offset,
-        bitsData = 0,
-        bitsCount = 0;
-    function readBit() {
-      if (bitsCount > 0) {
-        bitsCount--;
-        return bitsData >> bitsCount & 1;
-      }
-      bitsData = data[offset++];
-      if (bitsData === 0xFF) {
-        var nextByte = data[offset++];
-        if (nextByte) {
-          throw new JpegError(`unexpected marker ${(bitsData << 8 | nextByte).toString(16)}`);
-        }
-      }
-      bitsCount = 7;
-      return bitsData >>> 7;
-    }
-    function decodeHuffman(tree) {
-      var node = tree;
-      while (true) {
-        node = node[readBit()];
-        if (typeof node === 'number') {
-          return node;
-        }
-        if (typeof node !== 'object') {
-          throw new JpegError('invalid huffman sequence');
-        }
-      }
-    }
-    function receive(length) {
-      var n = 0;
-      while (length > 0) {
-        n = n << 1 | readBit();
-        length--;
-      }
-      return n;
-    }
-    function receiveAndExtend(length) {
-      if (length === 1) {
-        return readBit() === 1 ? 1 : -1;
-      }
-      var n = receive(length);
-      if (n >= 1 << length - 1) {
-        return n;
-      }
-      return n + (-1 << length) + 1;
-    }
-    function decodeBaseline(component, offset) {
-      var t = decodeHuffman(component.huffmanTableDC);
-      var diff = t === 0 ? 0 : receiveAndExtend(t);
-      component.blockData[offset] = component.pred += diff;
-      var k = 1;
-      while (k < 64) {
-        var rs = decodeHuffman(component.huffmanTableAC);
-        var s = rs & 15,
-            r = rs >> 4;
-        if (s === 0) {
-          if (r < 15) {
-            break;
-          }
-          k += 16;
-          continue;
-        }
-        k += r;
-        var z = dctZigZag[k];
-        component.blockData[offset + z] = receiveAndExtend(s);
-        k++;
-      }
-    }
-    function decodeDCFirst(component, offset) {
-      var t = decodeHuffman(component.huffmanTableDC);
-      var diff = t === 0 ? 0 : receiveAndExtend(t) << successive;
-      component.blockData[offset] = component.pred += diff;
-    }
-    function decodeDCSuccessive(component, offset) {
-      component.blockData[offset] |= readBit() << successive;
-    }
-    var eobrun = 0;
-    function decodeACFirst(component, offset) {
-      if (eobrun > 0) {
-        eobrun--;
-        return;
-      }
-      var k = spectralStart,
-          e = spectralEnd;
-      while (k <= e) {
-        var rs = decodeHuffman(component.huffmanTableAC);
-        var s = rs & 15,
-            r = rs >> 4;
-        if (s === 0) {
-          if (r < 15) {
-            eobrun = receive(r) + (1 << r) - 1;
-            break;
-          }
-          k += 16;
-          continue;
-        }
-        k += r;
-        var z = dctZigZag[k];
-        component.blockData[offset + z] = receiveAndExtend(s) * (1 << successive);
-        k++;
-      }
-    }
-    var successiveACState = 0,
-        successiveACNextValue;
-    function decodeACSuccessive(component, offset) {
-      var k = spectralStart;
-      var e = spectralEnd;
-      var r = 0;
-      var s;
-      var rs;
-      while (k <= e) {
-        var z = dctZigZag[k];
-        switch (successiveACState) {
-          case 0:
-            rs = decodeHuffman(component.huffmanTableAC);
-            s = rs & 15;
-            r = rs >> 4;
-            if (s === 0) {
-              if (r < 15) {
-                eobrun = receive(r) + (1 << r);
-                successiveACState = 4;
-              } else {
-                r = 16;
-                successiveACState = 1;
-              }
-            } else {
-              if (s !== 1) {
-                throw new JpegError('invalid ACn encoding');
-              }
-              successiveACNextValue = receiveAndExtend(s);
-              successiveACState = r ? 2 : 3;
-            }
-            continue;
-          case 1:
-          case 2:
-            if (component.blockData[offset + z]) {
-              component.blockData[offset + z] += readBit() << successive;
-            } else {
-              r--;
-              if (r === 0) {
-                successiveACState = successiveACState === 2 ? 3 : 0;
-              }
-            }
-            break;
-          case 3:
-            if (component.blockData[offset + z]) {
-              component.blockData[offset + z] += readBit() << successive;
-            } else {
-              component.blockData[offset + z] = successiveACNextValue << successive;
-              successiveACState = 0;
-            }
-            break;
-          case 4:
-            if (component.blockData[offset + z]) {
-              component.blockData[offset + z] += readBit() << successive;
-            }
-            break;
-        }
-        k++;
-      }
-      if (successiveACState === 4) {
-        eobrun--;
-        if (eobrun === 0) {
-          successiveACState = 0;
-        }
-      }
-    }
-    function decodeMcu(component, decode, mcu, row, col) {
-      var mcuRow = mcu / mcusPerLine | 0;
-      var mcuCol = mcu % mcusPerLine;
-      var blockRow = mcuRow * component.v + row;
-      var blockCol = mcuCol * component.h + col;
-      var offset = getBlockBufferOffset(component, blockRow, blockCol);
-      decode(component, offset);
-    }
-    function decodeBlock(component, decode, mcu) {
-      var blockRow = mcu / component.blocksPerLine | 0;
-      var blockCol = mcu % component.blocksPerLine;
-      var offset = getBlockBufferOffset(component, blockRow, blockCol);
-      decode(component, offset);
-    }
-    var componentsLength = components.length;
-    var component, i, j, k, n;
-    var decodeFn;
-    if (progressive) {
-      if (spectralStart === 0) {
-        decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive;
-      } else {
-        decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive;
-      }
-    } else {
-      decodeFn = decodeBaseline;
-    }
-    var mcu = 0,
-        fileMarker;
-    var mcuExpected;
-    if (componentsLength === 1) {
-      mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn;
-    } else {
-      mcuExpected = mcusPerLine * frame.mcusPerColumn;
-    }
-    var h, v;
-    while (mcu < mcuExpected) {
-      var mcuToRead = resetInterval ? Math.min(mcuExpected - mcu, resetInterval) : mcuExpected;
-      for (i = 0; i < componentsLength; i++) {
-        components[i].pred = 0;
-      }
-      eobrun = 0;
-      if (componentsLength === 1) {
-        component = components[0];
-        for (n = 0; n < mcuToRead; n++) {
-          decodeBlock(component, decodeFn, mcu);
-          mcu++;
-        }
-      } else {
-        for (n = 0; n < mcuToRead; n++) {
-          for (i = 0; i < componentsLength; i++) {
-            component = components[i];
-            h = component.h;
-            v = component.v;
-            for (j = 0; j < v; j++) {
-              for (k = 0; k < h; k++) {
-                decodeMcu(component, decodeFn, mcu, j, k);
-              }
-            }
-          }
-          mcu++;
-        }
-      }
-      bitsCount = 0;
-      fileMarker = findNextFileMarker(data, offset);
-      if (fileMarker && fileMarker.invalid) {
-        (0, _util.warn)('decodeScan - unexpected MCU data, next marker is: ' + fileMarker.invalid);
-        offset = fileMarker.offset;
-      }
-      var marker = fileMarker && fileMarker.marker;
-      if (!marker || marker <= 0xFF00) {
-        throw new JpegError('marker was not found');
-      }
-      if (marker >= 0xFFD0 && marker <= 0xFFD7) {
-        offset += 2;
-      } else {
-        break;
-      }
-    }
-    fileMarker = findNextFileMarker(data, offset);
-    if (fileMarker && fileMarker.invalid) {
-      (0, _util.warn)('decodeScan - unexpected Scan data, next marker is: ' + fileMarker.invalid);
-      offset = fileMarker.offset;
-    }
-    return offset - startOffset;
-  }
-  function quantizeAndInverse(component, blockBufferOffset, p) {
-    var qt = component.quantizationTable,
-        blockData = component.blockData;
-    var v0, v1, v2, v3, v4, v5, v6, v7;
-    var p0, p1, p2, p3, p4, p5, p6, p7;
-    var t;
-    if (!qt) {
-      throw new JpegError('missing required Quantization Table.');
-    }
-    for (var row = 0; row < 64; row += 8) {
-      p0 = blockData[blockBufferOffset + row];
-      p1 = blockData[blockBufferOffset + row + 1];
-      p2 = blockData[blockBufferOffset + row + 2];
-      p3 = blockData[blockBufferOffset + row + 3];
-      p4 = blockData[blockBufferOffset + row + 4];
-      p5 = blockData[blockBufferOffset + row + 5];
-      p6 = blockData[blockBufferOffset + row + 6];
-      p7 = blockData[blockBufferOffset + row + 7];
-      p0 *= qt[row];
-      if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
-        t = dctSqrt2 * p0 + 512 >> 10;
-        p[row] = t;
-        p[row + 1] = t;
-        p[row + 2] = t;
-        p[row + 3] = t;
-        p[row + 4] = t;
-        p[row + 5] = t;
-        p[row + 6] = t;
-        p[row + 7] = t;
-        continue;
-      }
-      p1 *= qt[row + 1];
-      p2 *= qt[row + 2];
-      p3 *= qt[row + 3];
-      p4 *= qt[row + 4];
-      p5 *= qt[row + 5];
-      p6 *= qt[row + 6];
-      p7 *= qt[row + 7];
-      v0 = dctSqrt2 * p0 + 128 >> 8;
-      v1 = dctSqrt2 * p4 + 128 >> 8;
-      v2 = p2;
-      v3 = p6;
-      v4 = dctSqrt1d2 * (p1 - p7) + 128 >> 8;
-      v7 = dctSqrt1d2 * (p1 + p7) + 128 >> 8;
-      v5 = p3 << 4;
-      v6 = p5 << 4;
-      v0 = v0 + v1 + 1 >> 1;
-      v1 = v0 - v1;
-      t = v2 * dctSin6 + v3 * dctCos6 + 128 >> 8;
-      v2 = v2 * dctCos6 - v3 * dctSin6 + 128 >> 8;
-      v3 = t;
-      v4 = v4 + v6 + 1 >> 1;
-      v6 = v4 - v6;
-      v7 = v7 + v5 + 1 >> 1;
-      v5 = v7 - v5;
-      v0 = v0 + v3 + 1 >> 1;
-      v3 = v0 - v3;
-      v1 = v1 + v2 + 1 >> 1;
-      v2 = v1 - v2;
-      t = v4 * dctSin3 + v7 * dctCos3 + 2048 >> 12;
-      v4 = v4 * dctCos3 - v7 * dctSin3 + 2048 >> 12;
-      v7 = t;
-      t = v5 * dctSin1 + v6 * dctCos1 + 2048 >> 12;
-      v5 = v5 * dctCos1 - v6 * dctSin1 + 2048 >> 12;
-      v6 = t;
-      p[row] = v0 + v7;
-      p[row + 7] = v0 - v7;
-      p[row + 1] = v1 + v6;
-      p[row + 6] = v1 - v6;
-      p[row + 2] = v2 + v5;
-      p[row + 5] = v2 - v5;
-      p[row + 3] = v3 + v4;
-      p[row + 4] = v3 - v4;
-    }
-    for (var col = 0; col < 8; ++col) {
-      p0 = p[col];
-      p1 = p[col + 8];
-      p2 = p[col + 16];
-      p3 = p[col + 24];
-      p4 = p[col + 32];
-      p5 = p[col + 40];
-      p6 = p[col + 48];
-      p7 = p[col + 56];
-      if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
-        t = dctSqrt2 * p0 + 8192 >> 14;
-        t = t < -2040 ? 0 : t >= 2024 ? 255 : t + 2056 >> 4;
-        blockData[blockBufferOffset + col] = t;
-        blockData[blockBufferOffset + col + 8] = t;
-        blockData[blockBufferOffset + col + 16] = t;
-        blockData[blockBufferOffset + col + 24] = t;
-        blockData[blockBufferOffset + col + 32] = t;
-        blockData[blockBufferOffset + col + 40] = t;
-        blockData[blockBufferOffset + col + 48] = t;
-        blockData[blockBufferOffset + col + 56] = t;
-        continue;
-      }
-      v0 = dctSqrt2 * p0 + 2048 >> 12;
-      v1 = dctSqrt2 * p4 + 2048 >> 12;
-      v2 = p2;
-      v3 = p6;
-      v4 = dctSqrt1d2 * (p1 - p7) + 2048 >> 12;
-      v7 = dctSqrt1d2 * (p1 + p7) + 2048 >> 12;
-      v5 = p3;
-      v6 = p5;
-      v0 = (v0 + v1 + 1 >> 1) + 4112;
-      v1 = v0 - v1;
-      t = v2 * dctSin6 + v3 * dctCos6 + 2048 >> 12;
-      v2 = v2 * dctCos6 - v3 * dctSin6 + 2048 >> 12;
-      v3 = t;
-      v4 = v4 + v6 + 1 >> 1;
-      v6 = v4 - v6;
-      v7 = v7 + v5 + 1 >> 1;
-      v5 = v7 - v5;
-      v0 = v0 + v3 + 1 >> 1;
-      v3 = v0 - v3;
-      v1 = v1 + v2 + 1 >> 1;
-      v2 = v1 - v2;
-      t = v4 * dctSin3 + v7 * dctCos3 + 2048 >> 12;
-      v4 = v4 * dctCos3 - v7 * dctSin3 + 2048 >> 12;
-      v7 = t;
-      t = v5 * dctSin1 + v6 * dctCos1 + 2048 >> 12;
-      v5 = v5 * dctCos1 - v6 * dctSin1 + 2048 >> 12;
-      v6 = t;
-      p0 = v0 + v7;
-      p7 = v0 - v7;
-      p1 = v1 + v6;
-      p6 = v1 - v6;
-      p2 = v2 + v5;
-      p5 = v2 - v5;
-      p3 = v3 + v4;
-      p4 = v3 - v4;
-      p0 = p0 < 16 ? 0 : p0 >= 4080 ? 255 : p0 >> 4;
-      p1 = p1 < 16 ? 0 : p1 >= 4080 ? 255 : p1 >> 4;
-      p2 = p2 < 16 ? 0 : p2 >= 4080 ? 255 : p2 >> 4;
-      p3 = p3 < 16 ? 0 : p3 >= 4080 ? 255 : p3 >> 4;
-      p4 = p4 < 16 ? 0 : p4 >= 4080 ? 255 : p4 >> 4;
-      p5 = p5 < 16 ? 0 : p5 >= 4080 ? 255 : p5 >> 4;
-      p6 = p6 < 16 ? 0 : p6 >= 4080 ? 255 : p6 >> 4;
-      p7 = p7 < 16 ? 0 : p7 >= 4080 ? 255 : p7 >> 4;
-      blockData[blockBufferOffset + col] = p0;
-      blockData[blockBufferOffset + col + 8] = p1;
-      blockData[blockBufferOffset + col + 16] = p2;
-      blockData[blockBufferOffset + col + 24] = p3;
-      blockData[blockBufferOffset + col + 32] = p4;
-      blockData[blockBufferOffset + col + 40] = p5;
-      blockData[blockBufferOffset + col + 48] = p6;
-      blockData[blockBufferOffset + col + 56] = p7;
-    }
-  }
-  function buildComponentData(frame, component) {
-    var blocksPerLine = component.blocksPerLine;
-    var blocksPerColumn = component.blocksPerColumn;
-    var computationBuffer = new Int16Array(64);
-    for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {
-      for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {
-        var offset = getBlockBufferOffset(component, blockRow, blockCol);
-        quantizeAndInverse(component, offset, computationBuffer);
-      }
-    }
-    return component.blockData;
-  }
-  function findNextFileMarker(data, currentPos, startPos) {
-    function peekUint16(pos) {
-      return data[pos] << 8 | data[pos + 1];
-    }
-    var maxPos = data.length - 1;
-    var newPos = startPos < currentPos ? startPos : currentPos;
-    if (currentPos >= maxPos) {
-      return null;
-    }
-    var currentMarker = peekUint16(currentPos);
-    if (currentMarker >= 0xFFC0 && currentMarker <= 0xFFFE) {
-      return {
-        invalid: null,
-        marker: currentMarker,
-        offset: currentPos
-      };
-    }
-    var newMarker = peekUint16(newPos);
-    while (!(newMarker >= 0xFFC0 && newMarker <= 0xFFFE)) {
-      if (++newPos >= maxPos) {
-        return null;
-      }
-      newMarker = peekUint16(newPos);
-    }
-    return {
-      invalid: currentMarker.toString(16),
-      marker: newMarker,
-      offset: newPos
-    };
-  }
-  JpegImage.prototype = {
-    parse: function parse(data) {
-      function readUint16() {
-        var value = data[offset] << 8 | data[offset + 1];
-        offset += 2;
-        return value;
-      }
-      function readDataBlock() {
-        var length = readUint16();
-        var endOffset = offset + length - 2;
-        var fileMarker = findNextFileMarker(data, endOffset, offset);
-        if (fileMarker && fileMarker.invalid) {
-          (0, _util.warn)('readDataBlock - incorrect length, next marker is: ' + fileMarker.invalid);
-          endOffset = fileMarker.offset;
-        }
-        var array = data.subarray(offset, endOffset);
-        offset += array.length;
-        return array;
-      }
-      function prepareComponents(frame) {
-        var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / frame.maxH);
-        var mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV);
-        for (var i = 0; i < frame.components.length; i++) {
-          component = frame.components[i];
-          var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) * component.h / frame.maxH);
-          var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines / 8) * component.v / frame.maxV);
-          var blocksPerLineForMcu = mcusPerLine * component.h;
-          var blocksPerColumnForMcu = mcusPerColumn * component.v;
-          var blocksBufferSize = 64 * blocksPerColumnForMcu * (blocksPerLineForMcu + 1);
-          component.blockData = new Int16Array(blocksBufferSize);
-          component.blocksPerLine = blocksPerLine;
-          component.blocksPerColumn = blocksPerColumn;
-        }
-        frame.mcusPerLine = mcusPerLine;
-        frame.mcusPerColumn = mcusPerColumn;
-      }
-      var offset = 0;
-      var jfif = null;
-      var adobe = null;
-      var frame, resetInterval;
-      var quantizationTables = [];
-      var huffmanTablesAC = [],
-          huffmanTablesDC = [];
-      var fileMarker = readUint16();
-      if (fileMarker !== 0xFFD8) {
-        throw new JpegError('SOI not found');
-      }
-      fileMarker = readUint16();
-      while (fileMarker !== 0xFFD9) {
-        var i, j, l;
-        switch (fileMarker) {
-          case 0xFFE0:
-          case 0xFFE1:
-          case 0xFFE2:
-          case 0xFFE3:
-          case 0xFFE4:
-          case 0xFFE5:
-          case 0xFFE6:
-          case 0xFFE7:
-          case 0xFFE8:
-          case 0xFFE9:
-          case 0xFFEA:
-          case 0xFFEB:
-          case 0xFFEC:
-          case 0xFFED:
-          case 0xFFEE:
-          case 0xFFEF:
-          case 0xFFFE:
-            var appData = readDataBlock();
-            if (fileMarker === 0xFFE0) {
-              if (appData[0] === 0x4A && appData[1] === 0x46 && appData[2] === 0x49 && appData[3] === 0x46 && appData[4] === 0) {
-                jfif = {
-                  version: {
-                    major: appData[5],
-                    minor: appData[6]
-                  },
-                  densityUnits: appData[7],
-                  xDensity: appData[8] << 8 | appData[9],
-                  yDensity: appData[10] << 8 | appData[11],
-                  thumbWidth: appData[12],
-                  thumbHeight: appData[13],
-                  thumbData: appData.subarray(14, 14 + 3 * appData[12] * appData[13])
-                };
-              }
-            }
-            if (fileMarker === 0xFFEE) {
-              if (appData[0] === 0x41 && appData[1] === 0x64 && appData[2] === 0x6F && appData[3] === 0x62 && appData[4] === 0x65) {
-                adobe = {
-                  version: appData[5] << 8 | appData[6],
-                  flags0: appData[7] << 8 | appData[8],
-                  flags1: appData[9] << 8 | appData[10],
-                  transformCode: appData[11]
-                };
-              }
-            }
-            break;
-          case 0xFFDB:
-            var quantizationTablesLength = readUint16();
-            var quantizationTablesEnd = quantizationTablesLength + offset - 2;
-            var z;
-            while (offset < quantizationTablesEnd) {
-              var quantizationTableSpec = data[offset++];
-              var tableData = new Uint16Array(64);
-              if (quantizationTableSpec >> 4 === 0) {
-                for (j = 0; j < 64; j++) {
-                  z = dctZigZag[j];
-                  tableData[z] = data[offset++];
-                }
-              } else if (quantizationTableSpec >> 4 === 1) {
-                for (j = 0; j < 64; j++) {
-                  z = dctZigZag[j];
-                  tableData[z] = readUint16();
-                }
-              } else {
-                throw new JpegError('DQT - invalid table spec');
-              }
-              quantizationTables[quantizationTableSpec & 15] = tableData;
-            }
-            break;
-          case 0xFFC0:
-          case 0xFFC1:
-          case 0xFFC2:
-            if (frame) {
-              throw new JpegError('Only single frame JPEGs supported');
-            }
-            readUint16();
-            frame = {};
-            frame.extended = fileMarker === 0xFFC1;
-            frame.progressive = fileMarker === 0xFFC2;
-            frame.precision = data[offset++];
-            frame.scanLines = readUint16();
-            frame.samplesPerLine = readUint16();
-            frame.components = [];
-            frame.componentIds = {};
-            var componentsCount = data[offset++],
-                componentId;
-            var maxH = 0,
-                maxV = 0;
-            for (i = 0; i < componentsCount; i++) {
-              componentId = data[offset];
-              var h = data[offset + 1] >> 4;
-              var v = data[offset + 1] & 15;
-              if (maxH < h) {
-                maxH = h;
-              }
-              if (maxV < v) {
-                maxV = v;
-              }
-              var qId = data[offset + 2];
-              l = frame.components.push({
-                h,
-                v,
-                quantizationId: qId,
-                quantizationTable: null
-              });
-              frame.componentIds[componentId] = l - 1;
-              offset += 3;
-            }
-            frame.maxH = maxH;
-            frame.maxV = maxV;
-            prepareComponents(frame);
-            break;
-          case 0xFFC4:
-            var huffmanLength = readUint16();
-            for (i = 2; i < huffmanLength;) {
-              var huffmanTableSpec = data[offset++];
-              var codeLengths = new Uint8Array(16);
-              var codeLengthSum = 0;
-              for (j = 0; j < 16; j++, offset++) {
-                codeLengthSum += codeLengths[j] = data[offset];
-              }
-              var huffmanValues = new Uint8Array(codeLengthSum);
-              for (j = 0; j < codeLengthSum; j++, offset++) {
-                huffmanValues[j] = data[offset];
-              }
-              i += 17 + codeLengthSum;
-              (huffmanTableSpec >> 4 === 0 ? huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] = buildHuffmanTable(codeLengths, huffmanValues);
-            }
-            break;
-          case 0xFFDD:
-            readUint16();
-            resetInterval = readUint16();
-            break;
-          case 0xFFDA:
-            readUint16();
-            var selectorsCount = data[offset++];
-            var components = [],
-                component;
-            for (i = 0; i < selectorsCount; i++) {
-              var componentIndex = frame.componentIds[data[offset++]];
-              component = frame.components[componentIndex];
-              var tableSpec = data[offset++];
-              component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4];
-              component.huffmanTableAC = huffmanTablesAC[tableSpec & 15];
-              components.push(component);
-            }
-            var spectralStart = data[offset++];
-            var spectralEnd = data[offset++];
-            var successiveApproximation = data[offset++];
-            var processed = decodeScan(data, offset, frame, components, resetInterval, spectralStart, spectralEnd, successiveApproximation >> 4, successiveApproximation & 15);
-            offset += processed;
-            break;
-          case 0xFFFF:
-            if (data[offset] !== 0xFF) {
-              offset--;
-            }
-            break;
-          default:
-            if (data[offset - 3] === 0xFF && data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) {
-              offset -= 3;
-              break;
-            }
-            throw new JpegError('unknown marker ' + fileMarker.toString(16));
-        }
-        fileMarker = readUint16();
-      }
-      this.width = frame.samplesPerLine;
-      this.height = frame.scanLines;
-      this.jfif = jfif;
-      this.adobe = adobe;
-      this.components = [];
-      for (i = 0; i < frame.components.length; i++) {
-        component = frame.components[i];
-        var quantizationTable = quantizationTables[component.quantizationId];
-        if (quantizationTable) {
-          component.quantizationTable = quantizationTable;
-        }
-        this.components.push({
-          output: buildComponentData(frame, component),
-          scaleX: component.h / frame.maxH,
-          scaleY: component.v / frame.maxV,
-          blocksPerLine: component.blocksPerLine,
-          blocksPerColumn: component.blocksPerColumn
-        });
-      }
-      this.numComponents = this.components.length;
-    },
-    _getLinearizedBlockData: function getLinearizedBlockData(width, height) {
-      var scaleX = this.width / width,
-          scaleY = this.height / height;
-      var component, componentScaleX, componentScaleY, blocksPerScanline;
-      var x, y, i, j, k;
-      var index;
-      var offset = 0;
-      var output;
-      var numComponents = this.components.length;
-      var dataLength = width * height * numComponents;
-      var data = new Uint8ClampedArray(dataLength);
-      var xScaleBlockOffset = new Uint32Array(width);
-      var mask3LSB = 0xfffffff8;
-      for (i = 0; i < numComponents; i++) {
-        component = this.components[i];
-        componentScaleX = component.scaleX * scaleX;
-        componentScaleY = component.scaleY * scaleY;
-        offset = i;
-        output = component.output;
-        blocksPerScanline = component.blocksPerLine + 1 << 3;
-        for (x = 0; x < width; x++) {
-          j = 0 | x * componentScaleX;
-          xScaleBlockOffset[x] = (j & mask3LSB) << 3 | j & 7;
-        }
-        for (y = 0; y < height; y++) {
-          j = 0 | y * componentScaleY;
-          index = blocksPerScanline * (j & mask3LSB) | (j & 7) << 3;
-          for (x = 0; x < width; x++) {
-            data[offset] = output[index + xScaleBlockOffset[x]];
-            offset += numComponents;
-          }
-        }
-      }
-      var transform = this.decodeTransform;
-      if (transform) {
-        for (i = 0; i < dataLength;) {
-          for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) {
-            data[i] = (data[i] * transform[k] >> 8) + transform[k + 1];
-          }
-        }
-      }
-      return data;
-    },
-    _isColorConversionNeeded() {
-      if (this.adobe) {
-        return !!this.adobe.transformCode;
-      }
-      if (this.numComponents === 3) {
-        if (this.colorTransform === 0) {
-          return false;
-        }
-        return true;
-      }
-      if (this.colorTransform === 1) {
-        return true;
-      }
-      return false;
-    },
-    _convertYccToRgb: function convertYccToRgb(data) {
-      var Y, Cb, Cr;
-      for (var i = 0, length = data.length; i < length; i += 3) {
-        Y = data[i];
-        Cb = data[i + 1];
-        Cr = data[i + 2];
-        data[i] = Y - 179.456 + 1.402 * Cr;
-        data[i + 1] = Y + 135.459 - 0.344 * Cb - 0.714 * Cr;
-        data[i + 2] = Y - 226.816 + 1.772 * Cb;
-      }
-      return data;
-    },
-    _convertYcckToRgb: function convertYcckToRgb(data) {
-      var Y, Cb, Cr, k;
-      var offset = 0;
-      for (var i = 0, length = data.length; i < length; i += 4) {
-        Y = data[i];
-        Cb = data[i + 1];
-        Cr = data[i + 2];
-        k = data[i + 3];
-        data[offset++] = -122.67195406894 + Cb * (-6.60635669420364e-5 * Cb + 0.000437130475926232 * Cr - 5.4080610064599e-5 * Y + 0.00048449797120281 * k - 0.154362151871126) + Cr * (-0.000957964378445773 * Cr + 0.000817076911346625 * Y - 0.00477271405408747 * k + 1.53380253221734) + Y * (0.000961250184130688 * Y - 0.00266257332283933 * k + 0.48357088451265) + k * (-0.000336197177618394 * k + 0.484791561490776);
-        data[offset++] = 107.268039397724 + Cb * (2.19927104525741e-5 * Cb - 0.000640992018297945 * Cr + 0.000659397001245577 * Y + 0.000426105652938837 * k - 0.176491792462875) + Cr * (-0.000778269941513683 * Cr + 0.00130872261408275 * Y + 0.000770482631801132 * k - 0.151051492775562) + Y * (0.00126935368114843 * Y - 0.00265090189010898 * k + 0.25802910206845) + k * (-0.000318913117588328 * k - 0.213742400323665);
-        data[offset++] = -20.810012546947 + Cb * (-0.000570115196973677 * Cb - 2.63409051004589e-5 * Cr + 0.0020741088115012 * Y - 0.00288260236853442 * k + 0.814272968359295) + Cr * (-1.53496057440975e-5 * Cr - 0.000132689043961446 * Y + 0.000560833691242812 * k - 0.195152027534049) + Y * (0.00174418132927582 * Y - 0.00255243321439347 * k + 0.116935020465145) + k * (-0.000343531996510555 * k + 0.24165260232407);
-      }
-      return data;
-    },
-    _convertYcckToCmyk: function convertYcckToCmyk(data) {
-      var Y, Cb, Cr;
-      for (var i = 0, length = data.length; i < length; i += 4) {
-        Y = data[i];
-        Cb = data[i + 1];
-        Cr = data[i + 2];
-        data[i] = 434.456 - Y - 1.402 * Cr;
-        data[i + 1] = 119.541 - Y + 0.344 * Cb + 0.714 * Cr;
-        data[i + 2] = 481.816 - Y - 1.772 * Cb;
-      }
-      return data;
-    },
-    _convertCmykToRgb: function convertCmykToRgb(data) {
-      var c, m, y, k;
-      var offset = 0;
-      var scale = 1 / 255;
-      for (var i = 0, length = data.length; i < length; i += 4) {
-        c = data[i] * scale;
-        m = data[i + 1] * scale;
-        y = data[i + 2] * scale;
-        k = data[i + 3] * scale;
-        data[offset++] = 255 + c * (-4.387332384609988 * c + 54.48615194189176 * m + 18.82290502165302 * y + 212.25662451639585 * k - 285.2331026137004) + m * (1.7149763477362134 * m - 5.6096736904047315 * y - 17.873870861415444 * k - 5.497006427196366) + y * (-2.5217340131683033 * y - 21.248923337353073 * k + 17.5119270841813) - k * (21.86122147463605 * k + 189.48180835922747);
-        data[offset++] = 255 + c * (8.841041422036149 * c + 60.118027045597366 * m + 6.871425592049007 * y + 31.159100130055922 * k - 79.2970844816548) + m * (-15.310361306967817 * m + 17.575251261109482 * y + 131.35250912493976 * k - 190.9453302588951) + y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) - k * (20.737325471181034 * k + 187.80453709719578);
-        data[offset++] = 255 + c * (0.8842522430003296 * c + 8.078677503112928 * m + 30.89978309703729 * y - 0.23883238689178934 * k - 14.183576799673286) + m * (10.49593273432072 * m + 63.02378494754052 * y + 50.606957656360734 * k - 112.23884253719248) + y * (0.03296041114873217 * y + 115.60384449646641 * k - 193.58209356861505) - k * (22.33816807309886 * k + 180.12613974708367);
-      }
-      return data;
-    },
-    getData: function getData(width, height, forceRGBoutput) {
-      if (this.numComponents > 4) {
-        throw new JpegError('Unsupported color mode');
-      }
-      var data = this._getLinearizedBlockData(width, height);
-      if (this.numComponents === 1 && forceRGBoutput) {
-        var dataLength = data.length;
-        var rgbData = new Uint8ClampedArray(dataLength * 3);
-        var offset = 0;
-        for (var i = 0; i < dataLength; i++) {
-          var grayColor = data[i];
-          rgbData[offset++] = grayColor;
-          rgbData[offset++] = grayColor;
-          rgbData[offset++] = grayColor;
-        }
-        return rgbData;
-      } else if (this.numComponents === 3 && this._isColorConversionNeeded()) {
-        return this._convertYccToRgb(data);
-      } else if (this.numComponents === 4) {
-        if (this._isColorConversionNeeded()) {
-          if (forceRGBoutput) {
-            return this._convertYcckToRgb(data);
-          }
-          return this._convertYcckToCmyk(data);
-        } else if (forceRGBoutput) {
-          return this._convertCmykToRgb(data);
-        }
-      }
-      return data;
-    }
-  };
-  return JpegImage;
-}();
-exports.JpegImage = JpegImage;
-
-/***/ }),
 /* 25 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
@@ -26624,56 +25675,57 @@ exports.Jbig2Stream = undefined;
 var _primitives = __w_pdfjs_require__(1);
 
 var _stream = __w_pdfjs_require__(2);
 
 var _jbig = __w_pdfjs_require__(28);
 
 var _util = __w_pdfjs_require__(0);
 
-var Jbig2Stream = function Jbig2StreamClosure() {
+let Jbig2Stream = function Jbig2StreamClosure() {
   function Jbig2Stream(stream, maybeLength, dict, params) {
     this.stream = stream;
     this.maybeLength = maybeLength;
     this.dict = dict;
     this.params = params;
     _stream.DecodeStream.call(this, maybeLength);
   }
   Jbig2Stream.prototype = Object.create(_stream.DecodeStream.prototype);
   Object.defineProperty(Jbig2Stream.prototype, 'bytes', {
     get() {
       return (0, _util.shadow)(this, 'bytes', this.stream.getBytes(this.maybeLength));
     },
     configurable: true
   });
-  Jbig2Stream.prototype.ensureBuffer = function (req) {
-    if (this.bufferLength) {
-      return;
-    }
-    var jbig2Image = new _jbig.Jbig2Image();
-    var chunks = [];
+  Jbig2Stream.prototype.ensureBuffer = function (requested) {};
+  Jbig2Stream.prototype.readBlock = function () {
+    if (this.eof) {
+      return;
+    }
+    let jbig2Image = new _jbig.Jbig2Image();
+    let chunks = [];
     if ((0, _primitives.isDict)(this.params)) {
-      var globalsStream = this.params.get('JBIG2Globals');
+      let globalsStream = this.params.get('JBIG2Globals');
       if ((0, _primitives.isStream)(globalsStream)) {
-        var globals = globalsStream.getBytes();
+        let globals = globalsStream.getBytes();
         chunks.push({
           data: globals,
           start: 0,
           end: globals.length
         });
       }
     }
     chunks.push({
       data: this.bytes,
       start: 0,
       end: this.bytes.length
     });
-    var data = jbig2Image.parseChunks(chunks);
-    var dataLength = data.length;
-    for (var i = 0; i < dataLength; i++) {
+    let data = jbig2Image.parseChunks(chunks);
+    let dataLength = data.length;
+    for (let i = 0; i < dataLength; i++) {
       data[i] ^= 0xFF;
     }
     this.buffer = data;
     this.bufferLength = dataLength;
     this.eof = true;
   };
   return Jbig2Stream;
 }();
@@ -27925,27 +26977,1018 @@ exports.Jbig2Image = Jbig2Image;
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
+exports.JpegImage = undefined;
+
+var _util = __w_pdfjs_require__(0);
+
+let JpegError = function JpegErrorClosure() {
+  function JpegError(msg) {
+    this.message = 'JPEG error: ' + msg;
+  }
+  JpegError.prototype = new Error();
+  JpegError.prototype.name = 'JpegError';
+  JpegError.constructor = JpegError;
+  return JpegError;
+}();
+var JpegImage = function JpegImageClosure() {
+  var dctZigZag = new Uint8Array([0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63]);
+  var dctCos1 = 4017;
+  var dctSin1 = 799;
+  var dctCos3 = 3406;
+  var dctSin3 = 2276;
+  var dctCos6 = 1567;
+  var dctSin6 = 3784;
+  var dctSqrt2 = 5793;
+  var dctSqrt1d2 = 2896;
+  function JpegImage() {
+    this.decodeTransform = null;
+    this.colorTransform = -1;
+  }
+  function buildHuffmanTable(codeLengths, values) {
+    var k = 0,
+        code = [],
+        i,
+        j,
+        length = 16;
+    while (length > 0 && !codeLengths[length - 1]) {
+      length--;
+    }
+    code.push({
+      children: [],
+      index: 0
+    });
+    var p = code[0],
+        q;
+    for (i = 0; i < length; i++) {
+      for (j = 0; j < codeLengths[i]; j++) {
+        p = code.pop();
+        p.children[p.index] = values[k];
+        while (p.index > 0) {
+          p = code.pop();
+        }
+        p.index++;
+        code.push(p);
+        while (code.length <= i) {
+          code.push(q = {
+            children: [],
+            index: 0
+          });
+          p.children[p.index] = q.children;
+          p = q;
+        }
+        k++;
+      }
+      if (i + 1 < length) {
+        code.push(q = {
+          children: [],
+          index: 0
+        });
+        p.children[p.index] = q.children;
+        p = q;
+      }
+    }
+    return code[0].children;
+  }
+  function getBlockBufferOffset(component, row, col) {
+    return 64 * ((component.blocksPerLine + 1) * row + col);
+  }
+  function decodeScan(data, offset, frame, components, resetInterval, spectralStart, spectralEnd, successivePrev, successive) {
+    var mcusPerLine = frame.mcusPerLine;
+    var progressive = frame.progressive;
+    var startOffset = offset,
+        bitsData = 0,
+        bitsCount = 0;
+    function readBit() {
+      if (bitsCount > 0) {
+        bitsCount--;
+        return bitsData >> bitsCount & 1;
+      }
+      bitsData = data[offset++];
+      if (bitsData === 0xFF) {
+        var nextByte = data[offset++];
+        if (nextByte) {
+          throw new JpegError(`unexpected marker ${(bitsData << 8 | nextByte).toString(16)}`);
+        }
+      }
+      bitsCount = 7;
+      return bitsData >>> 7;
+    }
+    function decodeHuffman(tree) {
+      var node = tree;
+      while (true) {
+        node = node[readBit()];
+        if (typeof node === 'number') {
+          return node;
+        }
+        if (typeof node !== 'object') {
+          throw new JpegError('invalid huffman sequence');
+        }
+      }
+    }
+    function receive(length) {
+      var n = 0;
+      while (length > 0) {
+        n = n << 1 | readBit();
+        length--;
+      }
+      return n;
+    }
+    function receiveAndExtend(length) {
+      if (length === 1) {
+        return readBit() === 1 ? 1 : -1;
+      }
+      var n = receive(length);
+      if (n >= 1 << length - 1) {
+        return n;
+      }
+      return n + (-1 << length) + 1;
+    }
+    function decodeBaseline(component, offset) {
+      var t = decodeHuffman(component.huffmanTableDC);
+      var diff = t === 0 ? 0 : receiveAndExtend(t);
+      component.blockData[offset] = component.pred += diff;
+      var k = 1;
+      while (k < 64) {
+        var rs = decodeHuffman(component.huffmanTableAC);
+        var s = rs & 15,
+            r = rs >> 4;
+        if (s === 0) {
+          if (r < 15) {
+            break;
+          }
+          k += 16;
+          continue;
+        }
+        k += r;
+        var z = dctZigZag[k];
+        component.blockData[offset + z] = receiveAndExtend(s);
+        k++;
+      }
+    }
+    function decodeDCFirst(component, offset) {
+      var t = decodeHuffman(component.huffmanTableDC);
+      var diff = t === 0 ? 0 : receiveAndExtend(t) << successive;
+      component.blockData[offset] = component.pred += diff;
+    }
+    function decodeDCSuccessive(component, offset) {
+      component.blockData[offset] |= readBit() << successive;
+    }
+    var eobrun = 0;
+    function decodeACFirst(component, offset) {
+      if (eobrun > 0) {
+        eobrun--;
+        return;
+      }
+      var k = spectralStart,
+          e = spectralEnd;
+      while (k <= e) {
+        var rs = decodeHuffman(component.huffmanTableAC);
+        var s = rs & 15,
+            r = rs >> 4;
+        if (s === 0) {
+          if (r < 15) {
+            eobrun = receive(r) + (1 << r) - 1;
+            break;
+          }
+          k += 16;
+          continue;
+        }
+        k += r;
+        var z = dctZigZag[k];
+        component.blockData[offset + z] = receiveAndExtend(s) * (1 << successive);
+        k++;
+      }
+    }
+    var successiveACState = 0,
+        successiveACNextValue;
+    function decodeACSuccessive(component, offset) {
+      var k = spectralStart;
+      var e = spectralEnd;
+      var r = 0;
+      var s;
+      var rs;
+      while (k <= e) {
+        var z = dctZigZag[k];
+        switch (successiveACState) {
+          case 0:
+            rs = decodeHuffman(component.huffmanTableAC);
+            s = rs & 15;
+            r = rs >> 4;
+            if (s === 0) {
+              if (r < 15) {
+                eobrun = receive(r) + (1 << r);
+                successiveACState = 4;
+              } else {
+                r = 16;
+                successiveACState = 1;
+              }
+            } else {
+              if (s !== 1) {
+                throw new JpegError('invalid ACn encoding');
+              }
+              successiveACNextValue = receiveAndExtend(s);
+              successiveACState = r ? 2 : 3;
+            }
+            continue;
+          case 1:
+          case 2:
+            if (component.blockData[offset + z]) {
+              component.blockData[offset + z] += readBit() << successive;
+            } else {
+              r--;
+              if (r === 0) {
+                successiveACState = successiveACState === 2 ? 3 : 0;
+              }
+            }
+            break;
+          case 3:
+            if (component.blockData[offset + z]) {
+              component.blockData[offset + z] += readBit() << successive;
+            } else {
+              component.blockData[offset + z] = successiveACNextValue << successive;
+              successiveACState = 0;
+            }
+            break;
+          case 4:
+            if (component.blockData[offset + z]) {
+              component.blockData[offset + z] += readBit() << successive;
+            }
+            break;
+        }
+        k++;
+      }
+      if (successiveACState === 4) {
+        eobrun--;
+        if (eobrun === 0) {
+          successiveACState = 0;
+        }
+      }
+    }
+    function decodeMcu(component, decode, mcu, row, col) {
+      var mcuRow = mcu / mcusPerLine | 0;
+      var mcuCol = mcu % mcusPerLine;
+      var blockRow = mcuRow * component.v + row;
+      var blockCol = mcuCol * component.h + col;
+      var offset = getBlockBufferOffset(component, blockRow, blockCol);
+      decode(component, offset);
+    }
+    function decodeBlock(component, decode, mcu) {
+      var blockRow = mcu / component.blocksPerLine | 0;
+      var blockCol = mcu % component.blocksPerLine;
+      var offset = getBlockBufferOffset(component, blockRow, blockCol);
+      decode(component, offset);
+    }
+    var componentsLength = components.length;
+    var component, i, j, k, n;
+    var decodeFn;
+    if (progressive) {
+      if (spectralStart === 0) {
+        decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive;
+      } else {
+        decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive;
+      }
+    } else {
+      decodeFn = decodeBaseline;
+    }
+    var mcu = 0,
+        fileMarker;
+    var mcuExpected;
+    if (componentsLength === 1) {
+      mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn;
+    } else {
+      mcuExpected = mcusPerLine * frame.mcusPerColumn;
+    }
+    var h, v;
+    while (mcu < mcuExpected) {
+      var mcuToRead = resetInterval ? Math.min(mcuExpected - mcu, resetInterval) : mcuExpected;
+      for (i = 0; i < componentsLength; i++) {
+        components[i].pred = 0;
+      }
+      eobrun = 0;
+      if (componentsLength === 1) {
+        component = components[0];
+        for (n = 0; n < mcuToRead; n++) {
+          decodeBlock(component, decodeFn, mcu);
+          mcu++;
+        }
+      } else {
+        for (n = 0; n < mcuToRead; n++) {
+          for (i = 0; i < componentsLength; i++) {
+            component = components[i];
+            h = component.h;
+            v = component.v;
+            for (j = 0; j < v; j++) {
+              for (k = 0; k < h; k++) {
+                decodeMcu(component, decodeFn, mcu, j, k);
+              }
+            }
+          }
+          mcu++;
+        }
+      }
+      bitsCount = 0;
+      fileMarker = findNextFileMarker(data, offset);
+      if (fileMarker && fileMarker.invalid) {
+        (0, _util.warn)('decodeScan - unexpected MCU data, next marker is: ' + fileMarker.invalid);
+        offset = fileMarker.offset;
+      }
+      var marker = fileMarker && fileMarker.marker;
+      if (!marker || marker <= 0xFF00) {
+        throw new JpegError('marker was not found');
+      }
+      if (marker >= 0xFFD0 && marker <= 0xFFD7) {
+        offset += 2;
+      } else {
+        break;
+      }
+    }
+    fileMarker = findNextFileMarker(data, offset);
+    if (fileMarker && fileMarker.invalid) {
+      (0, _util.warn)('decodeScan - unexpected Scan data, next marker is: ' + fileMarker.invalid);
+      offset = fileMarker.offset;
+    }
+    return offset - startOffset;
+  }
+  function quantizeAndInverse(component, blockBufferOffset, p) {
+    var qt = component.quantizationTable,
+        blockData = component.blockData;
+    var v0, v1, v2, v3, v4, v5, v6, v7;
+    var p0, p1, p2, p3, p4, p5, p6, p7;
+    var t;
+    if (!qt) {
+      throw new JpegError('missing required Quantization Table.');
+    }
+    for (var row = 0; row < 64; row += 8) {
+      p0 = blockData[blockBufferOffset + row];
+      p1 = blockData[blockBufferOffset + row + 1];
+      p2 = blockData[blockBufferOffset + row + 2];
+      p3 = blockData[blockBufferOffset + row + 3];
+      p4 = blockData[blockBufferOffset + row + 4];
+      p5 = blockData[blockBufferOffset + row + 5];
+      p6 = blockData[blockBufferOffset + row + 6];
+      p7 = blockData[blockBufferOffset + row + 7];
+      p0 *= qt[row];
+      if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
+        t = dctSqrt2 * p0 + 512 >> 10;
+        p[row] = t;
+        p[row + 1] = t;
+        p[row + 2] = t;
+        p[row + 3] = t;
+        p[row + 4] = t;
+        p[row + 5] = t;
+        p[row + 6] = t;
+        p[row + 7] = t;
+        continue;
+      }
+      p1 *= qt[row + 1];
+      p2 *= qt[row + 2];
+      p3 *= qt[row + 3];
+      p4 *= qt[row + 4];
+      p5 *= qt[row + 5];
+      p6 *= qt[row + 6];
+      p7 *= qt[row + 7];
+      v0 = dctSqrt2 * p0 + 128 >> 8;
+      v1 = dctSqrt2 * p4 + 128 >> 8;
+      v2 = p2;
+      v3 = p6;
+      v4 = dctSqrt1d2 * (p1 - p7) + 128 >> 8;
+      v7 = dctSqrt1d2 * (p1 + p7) + 128 >> 8;
+      v5 = p3 << 4;
+      v6 = p5 << 4;
+      v0 = v0 + v1 + 1 >> 1;
+      v1 = v0 - v1;
+      t = v2 * dctSin6 + v3 * dctCos6 + 128 >> 8;
+      v2 = v2 * dctCos6 - v3 * dctSin6 + 128 >> 8;
+      v3 = t;
+      v4 = v4 + v6 + 1 >> 1;
+      v6 = v4 - v6;
+      v7 = v7 + v5 + 1 >> 1;
+      v5 = v7 - v5;
+      v0 = v0 + v3 + 1 >> 1;
+      v3 = v0 - v3;
+      v1 = v1 + v2 + 1 >> 1;
+      v2 = v1 - v2;
+      t = v4 * dctSin3 + v7 * dctCos3 + 2048 >> 12;
+      v4 = v4 * dctCos3 - v7 * dctSin3 + 2048 >> 12;
+      v7 = t;
+      t = v5 * dctSin1 + v6 * dctCos1 + 2048 >> 12;
+      v5 = v5 * dctCos1 - v6 * dctSin1 + 2048 >> 12;
+      v6 = t;
+      p[row] = v0 + v7;
+      p[row + 7] = v0 - v7;
+      p[row + 1] = v1 + v6;
+      p[row + 6] = v1 - v6;
+      p[row + 2] = v2 + v5;
+      p[row + 5] = v2 - v5;
+      p[row + 3] = v3 + v4;
+      p[row + 4] = v3 - v4;
+    }
+    for (var col = 0; col < 8; ++col) {
+      p0 = p[col];
+      p1 = p[col + 8];
+      p2 = p[col + 16];
+      p3 = p[col + 24];
+      p4 = p[col + 32];
+      p5 = p[col + 40];
+      p6 = p[col + 48];
+      p7 = p[col + 56];
+      if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
+        t = dctSqrt2 * p0 + 8192 >> 14;
+        t = t < -2040 ? 0 : t >= 2024 ? 255 : t + 2056 >> 4;
+        blockData[blockBufferOffset + col] = t;
+        blockData[blockBufferOffset + col + 8] = t;
+        blockData[blockBufferOffset + col + 16] = t;
+        blockData[blockBufferOffset + col + 24] = t;
+        blockData[blockBufferOffset + col + 32] = t;
+        blockData[blockBufferOffset + col + 40] = t;
+        blockData[blockBufferOffset + col + 48] = t;
+        blockData[blockBufferOffset + col + 56] = t;
+        continue;
+      }
+      v0 = dctSqrt2 * p0 + 2048 >> 12;
+      v1 = dctSqrt2 * p4 + 2048 >> 12;
+      v2 = p2;
+      v3 = p6;
+      v4 = dctSqrt1d2 * (p1 - p7) + 2048 >> 12;
+      v7 = dctSqrt1d2 * (p1 + p7) + 2048 >> 12;
+      v5 = p3;
+      v6 = p5;
+      v0 = (v0 + v1 + 1 >> 1) + 4112;
+      v1 = v0 - v1;
+      t = v2 * dctSin6 + v3 * dctCos6 + 2048 >> 12;
+      v2 = v2 * dctCos6 - v3 * dctSin6 + 2048 >> 12;
+      v3 = t;
+      v4 = v4 + v6 + 1 >> 1;
+      v6 = v4 - v6;
+      v7 = v7 + v5 + 1 >> 1;
+      v5 = v7 - v5;
+      v0 = v0 + v3 + 1 >> 1;
+      v3 = v0 - v3;
+      v1 = v1 + v2 + 1 >> 1;
+      v2 = v1 - v2;
+      t = v4 * dctSin3 + v7 * dctCos3 + 2048 >> 12;
+      v4 = v4 * dctCos3 - v7 * dctSin3 + 2048 >> 12;
+      v7 = t;
+      t = v5 * dctSin1 + v6 * dctCos1 + 2048 >> 12;
+      v5 = v5 * dctCos1 - v6 * dctSin1 + 2048 >> 12;
+      v6 = t;
+      p0 = v0 + v7;
+      p7 = v0 - v7;
+      p1 = v1 + v6;
+      p6 = v1 - v6;
+      p2 = v2 + v5;
+      p5 = v2 - v5;
+      p3 = v3 + v4;
+      p4 = v3 - v4;
+      p0 = p0 < 16 ? 0 : p0 >= 4080 ? 255 : p0 >> 4;
+      p1 = p1 < 16 ? 0 : p1 >= 4080 ? 255 : p1 >> 4;
+      p2 = p2 < 16 ? 0 : p2 >= 4080 ? 255 : p2 >> 4;
+      p3 = p3 < 16 ? 0 : p3 >= 4080 ? 255 : p3 >> 4;
+      p4 = p4 < 16 ? 0 : p4 >= 4080 ? 255 : p4 >> 4;
+      p5 = p5 < 16 ? 0 : p5 >= 4080 ? 255 : p5 >> 4;
+      p6 = p6 < 16 ? 0 : p6 >= 4080 ? 255 : p6 >> 4;
+      p7 = p7 < 16 ? 0 : p7 >= 4080 ? 255 : p7 >> 4;
+      blockData[blockBufferOffset + col] = p0;
+      blockData[blockBufferOffset + col + 8] = p1;
+      blockData[blockBufferOffset + col + 16] = p2;
+      blockData[blockBufferOffset + col + 24] = p3;
+      blockData[blockBufferOffset + col + 32] = p4;
+      blockData[blockBufferOffset + col + 40] = p5;
+      blockData[blockBufferOffset + col + 48] = p6;
+      blockData[blockBufferOffset + col + 56] = p7;
+    }
+  }
+  function buildComponentData(frame, component) {
+    var blocksPerLine = component.blocksPerLine;
+    var blocksPerColumn = component.blocksPerColumn;
+    var computationBuffer = new Int16Array(64);
+    for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {
+      for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {
+        var offset = getBlockBufferOffset(component, blockRow, blockCol);
+        quantizeAndInverse(component, offset, computationBuffer);
+      }
+    }
+    return component.blockData;
+  }
+  function findNextFileMarker(data, currentPos, startPos) {
+    function peekUint16(pos) {
+      return data[pos] << 8 | data[pos + 1];
+    }
+    var maxPos = data.length - 1;
+    var newPos = startPos < currentPos ? startPos : currentPos;
+    if (currentPos >= maxPos) {
+      return null;
+    }
+    var currentMarker = peekUint16(currentPos);
+    if (currentMarker >= 0xFFC0 && currentMarker <= 0xFFFE) {
+      return {
+        invalid: null,
+        marker: currentMarker,
+        offset: currentPos
+      };
+    }
+    var newMarker = peekUint16(newPos);
+    while (!(newMarker >= 0xFFC0 && newMarker <= 0xFFFE)) {
+      if (++newPos >= maxPos) {
+        return null;
+      }
+      newMarker = peekUint16(newPos);
+    }
+    return {
+      invalid: currentMarker.toString(16),
+      marker: newMarker,
+      offset: newPos
+    };
+  }
+  JpegImage.prototype = {
+    parse: function parse(data) {
+      function readUint16() {
+        var value = data[offset] << 8 | data[offset + 1];
+        offset += 2;
+        return value;
+      }
+      function readDataBlock() {
+        var length = readUint16();
+        var endOffset = offset + length - 2;
+        var fileMarker = findNextFileMarker(data, endOffset, offset);
+        if (fileMarker && fileMarker.invalid) {
+          (0, _util.warn)('readDataBlock - incorrect length, next marker is: ' + fileMarker.invalid);
+          endOffset = fileMarker.offset;
+        }
+        var array = data.subarray(offset, endOffset);
+        offset += array.length;
+        return array;
+      }
+      function prepareComponents(frame) {
+        var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / frame.maxH);
+        var mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV);
+        for (var i = 0; i < frame.components.length; i++) {
+          component = frame.components[i];
+          var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) * component.h / frame.maxH);
+          var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines / 8) * component.v / frame.maxV);
+          var blocksPerLineForMcu = mcusPerLine * component.h;
+          var blocksPerColumnForMcu = mcusPerColumn * component.v;
+          var blocksBufferSize = 64 * blocksPerColumnForMcu * (blocksPerLineForMcu + 1);
+          component.blockData = new Int16Array(blocksBufferSize);
+          component.blocksPerLine = blocksPerLine;
+          component.blocksPerColumn = blocksPerColumn;
+        }
+        frame.mcusPerLine = mcusPerLine;
+        frame.mcusPerColumn = mcusPerColumn;
+      }
+      var offset = 0;
+      var jfif = null;
+      var adobe = null;
+      var frame, resetInterval;
+      var quantizationTables = [];
+      var huffmanTablesAC = [],
+          huffmanTablesDC = [];
+      var fileMarker = readUint16();
+      if (fileMarker !== 0xFFD8) {
+        throw new JpegError('SOI not found');
+      }
+      fileMarker = readUint16();
+      while (fileMarker !== 0xFFD9) {
+        var i, j, l;
+        switch (fileMarker) {
+          case 0xFFE0:
+          case 0xFFE1:
+          case 0xFFE2:
+          case 0xFFE3:
+          case 0xFFE4:
+          case 0xFFE5:
+          case 0xFFE6:
+          case 0xFFE7:
+          case 0xFFE8:
+          case 0xFFE9:
+          case 0xFFEA:
+          case 0xFFEB:
+          case 0xFFEC:
+          case 0xFFED:
+          case 0xFFEE:
+          case 0xFFEF:
+          case 0xFFFE:
+            var appData = readDataBlock();
+            if (fileMarker === 0xFFE0) {
+              if (appData[0] === 0x4A && appData[1] === 0x46 && appData[2] === 0x49 && appData[3] === 0x46 && appData[4] === 0) {
+                jfif = {
+                  version: {
+                    major: appData[5],
+                    minor: appData[6]
+                  },
+                  densityUnits: appData[7],
+                  xDensity: appData[8] << 8 | appData[9],
+                  yDensity: appData[10] << 8 | appData[11],
+                  thumbWidth: appData[12],
+                  thumbHeight: appData[13],
+                  thumbData: appData.subarray(14, 14 + 3 * appData[12] * appData[13])
+                };
+              }
+            }
+            if (fileMarker === 0xFFEE) {
+              if (appData[0] === 0x41 && appData[1] === 0x64 && appData[2] === 0x6F && appData[3] === 0x62 && appData[4] === 0x65) {
+                adobe = {
+                  version: appData[5] << 8 | appData[6],
+                  flags0: appData[7] << 8 | appData[8],
+                  flags1: appData[9] << 8 | appData[10],
+                  transformCode: appData[11]
+                };
+              }
+            }
+            break;
+          case 0xFFDB:
+            var quantizationTablesLength = readUint16();
+            var quantizationTablesEnd = quantizationTablesLength + offset - 2;
+            var z;
+            while (offset < quantizationTablesEnd) {
+              var quantizationTableSpec = data[offset++];
+              var tableData = new Uint16Array(64);
+              if (quantizationTableSpec >> 4 === 0) {
+                for (j = 0; j < 64; j++) {
+                  z = dctZigZag[j];
+                  tableData[z] = data[offset++];
+                }
+              } else if (quantizationTableSpec >> 4 === 1) {
+                for (j = 0; j < 64; j++) {
+                  z = dctZigZag[j];
+                  tableData[z] = readUint16();
+                }
+              } else {
+                throw new JpegError('DQT - invalid table spec');
+              }
+              quantizationTables[quantizationTableSpec & 15] = tableData;
+            }
+            break;
+          case 0xFFC0:
+          case 0xFFC1:
+          case 0xFFC2:
+            if (frame) {
+              throw new JpegError('Only single frame JPEGs supported');
+            }
+            readUint16();
+            frame = {};
+            frame.extended = fileMarker === 0xFFC1;
+            frame.progressive = fileMarker === 0xFFC2;
+            frame.precision = data[offset++];
+            frame.scanLines = readUint16();
+            frame.samplesPerLine = readUint16();
+            frame.components = [];
+            frame.componentIds = {};
+            var componentsCount = data[offset++],
+                componentId;
+            var maxH = 0,
+                maxV = 0;
+            for (i = 0; i < componentsCount; i++) {
+              componentId = data[offset];
+              var h = data[offset + 1] >> 4;
+              var v = data[offset + 1] & 15;
+              if (maxH < h) {
+                maxH = h;
+              }
+              if (maxV < v) {
+                maxV = v;
+              }
+              var qId = data[offset + 2];
+              l = frame.components.push({
+                h,
+                v,
+                quantizationId: qId,
+                quantizationTable: null
+              });
+              frame.componentIds[componentId] = l - 1;
+              offset += 3;
+            }
+            frame.maxH = maxH;
+            frame.maxV = maxV;
+            prepareComponents(frame);
+            break;
+          case 0xFFC4:
+            var huffmanLength = readUint16();
+            for (i = 2; i < huffmanLength;) {
+              var huffmanTableSpec = data[offset++];
+              var codeLengths = new Uint8Array(16);
+              var codeLengthSum = 0;
+              for (j = 0; j < 16; j++, offset++) {
+                codeLengthSum += codeLengths[j] = data[offset];
+              }
+              var huffmanValues = new Uint8Array(codeLengthSum);
+              for (j = 0; j < codeLengthSum; j++, offset++) {
+                huffmanValues[j] = data[offset];
+              }
+              i += 17 + codeLengthSum;
+              (huffmanTableSpec >> 4 === 0 ? huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] = buildHuffmanTable(codeLengths, huffmanValues);
+            }
+            break;
+          case 0xFFDD:
+            readUint16();
+            resetInterval = readUint16();
+            break;
+          case 0xFFDA:
+            readUint16();
+            var selectorsCount = data[offset++];
+            var components = [],
+                component;
+            for (i = 0; i < selectorsCount; i++) {
+              var componentIndex = frame.componentIds[data[offset++]];
+              component = frame.components[componentIndex];
+              var tableSpec = data[offset++];
+              component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4];
+              component.huffmanTableAC = huffmanTablesAC[tableSpec & 15];
+              components.push(component);
+            }
+            var spectralStart = data[offset++];
+            var spectralEnd = data[offset++];
+            var successiveApproximation = data[offset++];
+            var processed = decodeScan(data, offset, frame, components, resetInterval, spectralStart, spectralEnd, successiveApproximation >> 4, successiveApproximation & 15);
+            offset += processed;
+            break;
+          case 0xFFFF:
+            if (data[offset] !== 0xFF) {
+              offset--;
+            }
+            break;
+          default:
+            if (data[offset - 3] === 0xFF && data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) {
+              offset -= 3;
+              break;
+            }
+            throw new JpegError('unknown marker ' + fileMarker.toString(16));
+        }
+        fileMarker = readUint16();
+      }
+      this.width = frame.samplesPerLine;
+      this.height = frame.scanLines;
+      this.jfif = jfif;
+      this.adobe = adobe;
+      this.components = [];
+      for (i = 0; i < frame.components.length; i++) {
+        component = frame.components[i];
+        var quantizationTable = quantizationTables[component.quantizationId];
+        if (quantizationTable) {
+          component.quantizationTable = quantizationTable;
+        }
+        this.components.push({
+          output: buildComponentData(frame, component),
+          scaleX: component.h / frame.maxH,
+          scaleY: component.v / frame.maxV,
+          blocksPerLine: component.blocksPerLine,
+          blocksPerColumn: component.blocksPerColumn
+        });
+      }
+      this.numComponents = this.components.length;
+    },
+    _getLinearizedBlockData: function getLinearizedBlockData(width, height) {
+      var scaleX = this.width / width,
+          scaleY = this.height / height;
+      var component, componentScaleX, componentScaleY, blocksPerScanline;
+      var x, y, i, j, k;
+      var index;
+      var offset = 0;
+      var output;
+      var numComponents = this.components.length;
+      var dataLength = width * height * numComponents;
+      var data = new Uint8ClampedArray(dataLength);
+      var xScaleBlockOffset = new Uint32Array(width);
+      var mask3LSB = 0xfffffff8;
+      for (i = 0; i < numComponents; i++) {
+        component = this.components[i];
+        componentScaleX = component.scaleX * scaleX;
+        componentScaleY = component.scaleY * scaleY;
+        offset = i;
+        output = component.output;
+        blocksPerScanline = component.blocksPerLine + 1 << 3;
+        for (x = 0; x < width; x++) {
+          j = 0 | x * componentScaleX;
+          xScaleBlockOffset[x] = (j & mask3LSB) << 3 | j & 7;
+        }
+        for (y = 0; y < height; y++) {
+          j = 0 | y * componentScaleY;
+          index = blocksPerScanline * (j & mask3LSB) | (j & 7) << 3;
+          for (x = 0; x < width; x++) {
+            data[offset] = output[index + xScaleBlockOffset[x]];
+            offset += numComponents;
+          }
+        }
+      }
+      var transform = this.decodeTransform;
+      if (transform) {
+        for (i = 0; i < dataLength;) {
+          for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) {
+            data[i] = (data[i] * transform[k] >> 8) + transform[k + 1];
+          }
+        }
+      }
+      return data;
+    },
+    _isColorConversionNeeded() {
+      if (this.adobe) {
+        return !!this.adobe.transformCode;
+      }
+      if (this.numComponents === 3) {
+        if (this.colorTransform === 0) {
+          return false;
+        }
+        return true;
+      }
+      if (this.colorTransform === 1) {
+        return true;
+      }
+      return false;
+    },
+    _convertYccToRgb: function convertYccToRgb(data) {
+      var Y, Cb, Cr;
+      for (var i = 0, length = data.length; i < length; i += 3) {
+        Y = data[i];
+        Cb = data[i + 1];
+        Cr = data[i + 2];
+        data[i] = Y - 179.456 + 1.402 * Cr;
+        data[i + 1] = Y + 135.459 - 0.344 * Cb - 0.714 * Cr;
+        data[i + 2] = Y - 226.816 + 1.772 * Cb;
+      }
+      return data;
+    },
+    _convertYcckToRgb: function convertYcckToRgb(data) {
+      var Y, Cb, Cr, k;
+      var offset = 0;
+      for (var i = 0, length = data.length; i < length; i += 4) {
+        Y = data[i];
+        Cb = data[i + 1];
+        Cr = data[i + 2];
+        k = data[i + 3];
+        data[offset++] = -122.67195406894 + Cb * (-6.60635669420364e-5 * Cb + 0.000437130475926232 * Cr - 5.4080610064599e-5 * Y + 0.00048449797120281 * k - 0.154362151871126) + Cr * (-0.000957964378445773 * Cr + 0.000817076911346625 * Y - 0.00477271405408747 * k + 1.53380253221734) + Y * (0.000961250184130688 * Y - 0.00266257332283933 * k + 0.48357088451265) + k * (-0.000336197177618394 * k + 0.484791561490776);
+        data[offset++] = 107.268039397724 + Cb * (2.19927104525741e-5 * Cb - 0.000640992018297945 * Cr + 0.000659397001245577 * Y + 0.000426105652938837 * k - 0.176491792462875) + Cr * (-0.000778269941513683 * Cr + 0.00130872261408275 * Y + 0.000770482631801132 * k - 0.151051492775562) + Y * (0.00126935368114843 * Y - 0.00265090189010898 * k + 0.25802910206845) + k * (-0.000318913117588328 * k - 0.213742400323665);
+        data[offset++] = -20.810012546947 + Cb * (-0.000570115196973677 * Cb - 2.63409051004589e-5 * Cr + 0.0020741088115012 * Y - 0.00288260236853442 * k + 0.814272968359295) + Cr * (-1.53496057440975e-5 * Cr - 0.000132689043961446 * Y + 0.000560833691242812 * k - 0.195152027534049) + Y * (0.00174418132927582 * Y - 0.00255243321439347 * k + 0.116935020465145) + k * (-0.000343531996510555 * k + 0.24165260232407);
+      }
+      return data;
+    },
+    _convertYcckToCmyk: function convertYcckToCmyk(data) {
+      var Y, Cb, Cr;
+      for (var i = 0, length = data.length; i < length; i += 4) {
+        Y = data[i];
+        Cb = data[i + 1];
+        Cr = data[i + 2];
+        data[i] = 434.456 - Y - 1.402 * Cr;
+        data[i + 1] = 119.541 - Y + 0.344 * Cb + 0.714 * Cr;
+        data[i + 2] = 481.816 - Y - 1.772 * Cb;
+      }
+      return data;
+    },
+    _convertCmykToRgb: function convertCmykToRgb(data) {
+      var c, m, y, k;
+      var offset = 0;
+      var scale = 1 / 255;
+      for (var i = 0, length = data.length; i < length; i += 4) {
+        c = data[i] * scale;
+        m = data[i + 1] * scale;
+        y = data[i + 2] * scale;
+        k = data[i + 3] * scale;
+        data[offset++] = 255 + c * (-4.387332384609988 * c + 54.48615194189176 * m + 18.82290502165302 * y + 212.25662451639585 * k - 285.2331026137004) + m * (1.7149763477362134 * m - 5.6096736904047315 * y - 17.873870861415444 * k - 5.497006427196366) + y * (-2.5217340131683033 * y - 21.248923337353073 * k + 17.5119270841813) - k * (21.86122147463605 * k + 189.48180835922747);
+        data[offset++] = 255 + c * (8.841041422036149 * c + 60.118027045597366 * m + 6.871425592049007 * y + 31.159100130055922 * k - 79.2970844816548) + m * (-15.310361306967817 * m + 17.575251261109482 * y + 131.35250912493976 * k - 190.9453302588951) + y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) - k * (20.737325471181034 * k + 187.80453709719578);
+        data[offset++] = 255 + c * (0.8842522430003296 * c + 8.078677503112928 * m + 30.89978309703729 * y - 0.23883238689178934 * k - 14.183576799673286) + m * (10.49593273432072 * m + 63.02378494754052 * y + 50.606957656360734 * k - 112.23884253719248) + y * (0.03296041114873217 * y + 115.60384449646641 * k - 193.58209356861505) - k * (22.33816807309886 * k + 180.12613974708367);
+      }
+      return data;
+    },
+    getData: function getData(width, height, forceRGBoutput) {
+      if (this.numComponents > 4) {
+        throw new JpegError('Unsupported color mode');
+      }
+      var data = this._getLinearizedBlockData(width, height);
+      if (this.numComponents === 1 && forceRGBoutput) {
+        var dataLength = data.length;
+        var rgbData = new Uint8ClampedArray(dataLength * 3);
+        var offset = 0;
+        for (var i = 0; i < dataLength; i++) {
+          var grayColor = data[i];
+          rgbData[offset++] = grayColor;
+          rgbData[offset++] = grayColor;
+          rgbData[offset++] = grayColor;
+        }
+        return rgbData;
+      } else if (this.numComponents === 3 && this._isColorConversionNeeded()) {
+        return this._convertYccToRgb(data);
+      } else if (this.numComponents === 4) {
+        if (this._isColorConversionNeeded()) {
+          if (forceRGBoutput) {
+            return this._convertYcckToRgb(data);
+          }
+          return this._convertYcckToCmyk(data);
+        } else if (forceRGBoutput) {
+          return this._convertCmykToRgb(data);
+        }
+      }
+      return data;
+    }
+  };
+  return JpegImage;
+}();
+exports.JpegImage = JpegImage;
+
+/***/ }),
+/* 30 */
+/***/ (function(module, exports, __w_pdfjs_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.JpxStream = undefined;
+
+var _stream = __w_pdfjs_require__(2);
+
+var _jpx = __w_pdfjs_require__(12);
+
+var _util = __w_pdfjs_require__(0);
+
+let JpxStream = function JpxStreamClosure() {
+  function JpxStream(stream, maybeLength, dict, params) {
+    this.stream = stream;
+    this.maybeLength = maybeLength;
+    this.dict = dict;
+    this.params = params;
+    _stream.DecodeStream.call(this, maybeLength);
+  }
+  JpxStream.prototype = Object.create(_stream.DecodeStream.prototype);
+  Object.defineProperty(JpxStream.prototype, 'bytes', {
+    get: function JpxStream_bytes() {
+      return (0, _util.shadow)(this, 'bytes', this.stream.getBytes(this.maybeLength));
+    },
+    configurable: true
+  });
+  JpxStream.prototype.ensureBuffer = function (requested) {};
+  JpxStream.prototype.readBlock = function () {
+    if (this.eof) {
+      return;
+    }
+    let jpxImage = new _jpx.JpxImage();
+    jpxImage.parse(this.bytes);
+    let width = jpxImage.width;
+    let height = jpxImage.height;
+    let componentsCount = jpxImage.componentsCount;
+    let tileCount = jpxImage.tiles.length;
+    if (tileCount === 1) {
+      this.buffer = jpxImage.tiles[0].items;
+    } else {
+      let data = new Uint8ClampedArray(width * height * componentsCount);
+      for (let k = 0; k < tileCount; k++) {
+        let tileComponents = jpxImage.tiles[k];
+        let tileWidth = tileComponents.width;
+        let tileHeight = tileComponents.height;
+        let tileLeft = tileComponents.left;
+        let tileTop = tileComponents.top;
+        let src = tileComponents.items;
+        let srcPosition = 0;
+        let dataPosition = (width * tileTop + tileLeft) * componentsCount;
+        let imgRowSize = width * componentsCount;
+        let tileRowSize = tileWidth * componentsCount;
+        for (let j = 0; j < tileHeight; j++) {
+          let rowBytes = src.subarray(srcPosition, srcPosition + tileRowSize);
+          data.set(rowBytes, dataPosition);
+          srcPosition += tileRowSize;
+          dataPosition += imgRowSize;
+        }
+      }
+      this.buffer = data;
+    }
+    this.bufferLength = this.buffer.length;
+    this.eof = true;
+  };
+  return JpxStream;
+}();
+exports.JpxStream = JpxStream;
+
+/***/ }),
+/* 31 */
+/***/ (function(module, exports, __w_pdfjs_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
 exports.AnnotationFactory = exports.AnnotationBorderStyle = exports.Annotation = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
-var _obj = __w_pdfjs_require__(9);
+var _obj = __w_pdfjs_require__(10);
 
 var _primitives = __w_pdfjs_require__(1);
 
 var _colorspace = __w_pdfjs_require__(3);
 
-var _operator_list = __w_pdfjs_require__(6);
+var _operator_list = __w_pdfjs_require__(7);
 
 var _stream = __w_pdfjs_require__(2);
 
 class AnnotationFactory {
   static create(xref, ref, pdfManager, idFactory) {
     let dict = xref.fetchIfRef(ref);
     if (!(0, _primitives.isDict)(dict)) {
       return;
@@ -28405,17 +28448,17 @@ class ChoiceWidgetAnnotation extends Wid
     let options = _util.Util.getInheritableProperty(params.dict, 'Opt');
     if (Array.isArray(options)) {
       let xref = params.xref;
       for (let i = 0, ii = options.length; i < ii; i++) {
         let option = xref.fetchIfRef(options[i]);
         let isOptionArray = Array.isArray(option);
         this.data.options[i] = {
           exportValue: isOptionArray ? xref.fetchIfRef(option[0]) : option,
-          displayValue: isOptionArray ? xref.fetchIfRef(option[1]) : option
+          displayValue: (0, _util.stringToPDFString)(isOptionArray ? xref.fetchIfRef(option[1]) : option)
         };
       }
     }
     if (!Array.isArray(this.data.fieldValue)) {
       this.data.fieldValue = [this.data.fieldValue];
     }
     this.data.combo = this.hasFieldFlag(_util.AnnotationFieldFlag.COMBO);
     this.data.multiSelect = this.hasFieldFlag(_util.AnnotationFieldFlag.MULTISELECT);
@@ -28565,62 +28608,64 @@ class FileAttachmentAnnotation extends A
     this._preparePopup(parameters.dict);
   }
 }
 exports.Annotation = Annotation;
 exports.AnnotationBorderStyle = AnnotationBorderStyle;
 exports.AnnotationFactory = AnnotationFactory;
 
 /***/ }),
-/* 30 */
+/* 32 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.PartialEvaluator = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
-var _cmap = __w_pdfjs_require__(31);
+var _cmap = __w_pdfjs_require__(33);
 
 var _stream = __w_pdfjs_require__(2);
 
 var _primitives = __w_pdfjs_require__(1);
 
-var _fonts = __w_pdfjs_require__(32);
+var _fonts = __w_pdfjs_require__(34);
 
 var _encodings = __w_pdfjs_require__(4);
 
-var _unicode = __w_pdfjs_require__(15);
-
-var _standard_fonts = __w_pdfjs_require__(14);
-
-var _pattern = __w_pdfjs_require__(36);
+var _unicode = __w_pdfjs_require__(16);
+
+var _standard_fonts = __w_pdfjs_require__(15);
+
+var _pattern = __w_pdfjs_require__(38);
 
 var _parser = __w_pdfjs_require__(5);
 
-var _bidi = __w_pdfjs_require__(37);
+var _bidi = __w_pdfjs_require__(39);
 
 var _colorspace = __w_pdfjs_require__(3);
 
-var _glyphlist = __w_pdfjs_require__(7);
-
-var _metrics = __w_pdfjs_require__(38);
-
-var _function = __w_pdfjs_require__(16);
-
-var _murmurhash = __w_pdfjs_require__(40);
-
-var _operator_list = __w_pdfjs_require__(6);
-
-var _image = __w_pdfjs_require__(41);
+var _glyphlist = __w_pdfjs_require__(8);
+
+var _metrics = __w_pdfjs_require__(40);
+
+var _function = __w_pdfjs_require__(17);
+
+var _jpeg_stream = __w_pdfjs_require__(6);
+
+var _murmurhash = __w_pdfjs_require__(42);
+
+var _operator_list = __w_pdfjs_require__(7);
+
+var _image = __w_pdfjs_require__(43);
 
 var PartialEvaluator = function PartialEvaluatorClosure() {
   const DefaultPartialEvaluatorOptions = {
     forceDataSchema: false,
     maxImageSize: -1,
     disableFontFace: false,
     nativeImageDecoderSupport: _util.NativeImageDecoding.DECODE,
     ignoreErrors: false,
@@ -28630,17 +28675,17 @@ var PartialEvaluator = function PartialE
     this.xref = xref;
     this.resources = resources;
     this.handler = handler;
     this.forceDataSchema = forceDataSchema;
     this.pdfFunctionFactory = pdfFunctionFactory;
   }
   NativeImageDecoder.prototype = {
     canDecode(image) {
-      return image instanceof _stream.JpegStream && NativeImageDecoder.isDecodable(image, this.xref, this.resources, this.pdfFunctionFactory);
+      return image instanceof _jpeg_stream.JpegStream && NativeImageDecoder.isDecodable(image, this.xref, this.resources, this.pdfFunctionFactory);
     },
     decode(image) {
       var dict = image.dict;
       var colorSpace = dict.get('ColorSpace', 'CS');
       colorSpace = _colorspace.ColorSpace.parse(colorSpace, this.xref, this.resources, this.pdfFunctionFactory);
       var numComps = colorSpace.numComps;
       var decodePromise = this.handler.sendWithPromise('JpegDecode', [image.getIR(this.forceDataSchema), numComps]);
       return decodePromise.then(function (message) {
@@ -28895,44 +28940,44 @@ var PartialEvaluator = function PartialE
             args
           };
         }
         return;
       }
       var softMask = dict.get('SMask', 'SM') || false;
       var mask = dict.get('Mask') || false;
       var SMALL_IMAGE_DIMENSIONS = 200;
-      if (inline && !softMask && !mask && !(image instanceof _stream.JpegStream) && w + h < SMALL_IMAGE_DIMENSIONS) {
+      if (inline && !softMask && !mask && !(image instanceof _jpeg_stream.JpegStream) && w + h < SMALL_IMAGE_DIMENSIONS) {
         let imageObj = new _image.PDFImage({
           xref: this.xref,
           res: resources,
           image,
           pdfFunctionFactory: this.pdfFunctionFactory
         });
         imgData = imageObj.createImageData(true);
         operatorList.addOp(_util.OPS.paintInlineImageXObject, [imgData]);
         return;
       }
       var nativeImageDecoderSupport = this.options.nativeImageDecoderSupport;
       var objId = 'img_' + this.idFactory.createObjId();
       operatorList.addDependency(objId);
       args = [objId, w, h];
-      if (nativeImageDecoderSupport !== _util.NativeImageDecoding.NONE && !softMask && !mask && image instanceof _stream.JpegStream && NativeImageDecoder.isSupported(image, this.xref, resources, this.pdfFunctionFactory)) {
+      if (nativeImageDecoderSupport !== _util.NativeImageDecoding.NONE && !softMask && !mask && image instanceof _jpeg_stream.JpegStream && NativeImageDecoder.isSupported(image, this.xref, resources, this.pdfFunctionFactory)) {
         operatorList.addOp(_util.OPS.paintJpegXObject, args);
         this.handler.send('obj', [objId, this.pageIndex, 'JpegStream', image.getIR(this.options.forceDataSchema)]);
         if (cacheKey) {
           imageCache[cacheKey] = {
             fn: _util.OPS.paintJpegXObject,
             args
           };
         }
         return;
       }
       var nativeImageDecoder = null;
-      if (nativeImageDecoderSupport === _util.NativeImageDecoding.DECODE && (image instanceof _stream.JpegStream || mask instanceof _stream.JpegStream || softMask instanceof _stream.JpegStream)) {
+      if (nativeImageDecoderSupport === _util.NativeImageDecoding.DECODE && (image instanceof _jpeg_stream.JpegStream || mask instanceof _jpeg_stream.JpegStream || softMask instanceof _jpeg_stream.JpegStream)) {
         nativeImageDecoder = new NativeImageDecoder({
           xref: this.xref,
           resources,
           handler: this.handler,
           forceDataSchema: this.options.forceDataSchema,
           pdfFunctionFactory: this.pdfFunctionFactory
         });
       }
@@ -31223,17 +31268,17 @@ var EvaluatorPreprocessor = function Eva
       }
     }
   };
   return EvaluatorPreprocessor;
 }();
 exports.PartialEvaluator = PartialEvaluator;
 
 /***/ }),
-/* 31 */
+/* 33 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -31938,44 +31983,44 @@ var CMapFactory = function CMapFactoryCl
     }
   };
 }();
 exports.CMap = CMap;
 exports.IdentityCMap = IdentityCMap;
 exports.CMapFactory = CMapFactory;
 
 /***/ }),
-/* 32 */
+/* 34 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.getFontType = exports.ProblematicCharRanges = exports.IdentityToUnicodeMap = exports.ToUnicodeMap = exports.FontFlags = exports.Font = exports.ErrorFont = exports.PRIVATE_USE_OFFSET_END = exports.PRIVATE_USE_OFFSET_START = exports.SEAC_ANALYSIS_ENABLED = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
-var _cff_parser = __w_pdfjs_require__(13);
-
-var _glyphlist = __w_pdfjs_require__(7);
+var _cff_parser = __w_pdfjs_require__(14);
+
+var _glyphlist = __w_pdfjs_require__(8);
 
 var _encodings = __w_pdfjs_require__(4);
 
-var _standard_fonts = __w_pdfjs_require__(14);
-
-var _unicode = __w_pdfjs_require__(15);
-
-var _font_renderer = __w_pdfjs_require__(34);
+var _standard_fonts = __w_pdfjs_require__(15);
+
+var _unicode = __w_pdfjs_require__(16);
+
+var _font_renderer = __w_pdfjs_require__(36);
 
 var _stream = __w_pdfjs_require__(2);
 
-var _type1_parser = __w_pdfjs_require__(35);
+var _type1_parser = __w_pdfjs_require__(37);
 
 var PRIVATE_USE_OFFSET_START = 0xE000;
 var PRIVATE_USE_OFFSET_END = 0xF8FF;
 var SKIP_PRIVATE_USE_RANGE_F000_TO_F01F = false;
 var PDF_GLYPH_SPACE_UNITS = 1000;
 var SEAC_ANALYSIS_ENABLED = false;
 var FontFlags = {
   FixedPitch: 1,
@@ -34411,49 +34456,49 @@ exports.ErrorFont = ErrorFont;
 exports.Font = Font;
 exports.FontFlags = FontFlags;
 exports.ToUnicodeMap = ToUnicodeMap;
 exports.IdentityToUnicodeMap = IdentityToUnicodeMap;
 exports.ProblematicCharRanges = ProblematicCharRanges;
 exports.getFontType = getFontType;
 
 /***/ }),
-/* 33 */
+/* 35 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 var ISOAdobeCharset = ['.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl', 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', 'yacute', 'ydieresis', 'zcaron'];
 var ExpertCharset = ['.notdef', 'space', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', 'onequarter', 'onehalf', 'threequarters', 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall'];
 var ExpertSubsetCharset = ['.notdef', 'space', 'dollaroldstyle', 'dollarsuperior', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior', 'hyphensuperior', 'colonmonetary', 'onefitted', 'rupiah', 'centoldstyle', 'figuredash', 'hypheninferior', 'onequarter', 'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior'];
 exports.ISOAdobeCharset = ISOAdobeCharset;
 exports.ExpertCharset = ExpertCharset;
 exports.ExpertSubsetCharset = ExpertSubsetCharset;
 
 /***/ }),
-/* 34 */
+/* 36 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.FontRendererFactory = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
-var _cff_parser = __w_pdfjs_require__(13);
-
-var _glyphlist = __w_pdfjs_require__(7);
+var _cff_parser = __w_pdfjs_require__(14);
+
+var _glyphlist = __w_pdfjs_require__(8);
 
 var _encodings = __w_pdfjs_require__(4);
 
 var _stream = __w_pdfjs_require__(2);
 
 var FontRendererFactory = function FontRendererFactoryClosure() {
   function getLong(data, offset) {
     return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
@@ -35168,17 +35213,17 @@ var FontRendererFactory = function FontR
       }
       return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap);
     }
   };
 }();
 exports.FontRendererFactory = FontRendererFactory;
 
 /***/ }),
-/* 35 */
+/* 37 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -35731,17 +35776,17 @@ var Type1Parser = function Type1ParserCl
       }
     }
   };
   return Type1Parser;
 }();
 exports.Type1Parser = Type1Parser;
 
 /***/ }),
-/* 36 */
+/* 38 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -36521,17 +36566,17 @@ function getTilingPatternIR(operatorList
     throw new _util.FormatError(`Invalid getTilingPatternIR /BBox array: [${bbox}].`);
   }
   return ['TilingPattern', args, operatorList, matrix, bbox, xstep, ystep, paintType, tilingType];
 }
 exports.Pattern = Pattern;
 exports.getTilingPatternIR = getTilingPatternIR;
 
 /***/ }),
-/* 37 */
+/* 39 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -36766,17 +36811,17 @@ function bidi(str, startLevel, vertical)
       chars[i] = '';
     }
   }
   return createBidiText(chars.join(''), isLTR);
 }
 exports.bidi = bidi;
 
 /***/ }),
-/* 38 */
+/* 40 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -39720,17 +39765,17 @@ var getMetrics = (0, _util.getLookupTabl
     t['a189'] = 927;
     t['a190'] = 970;
     t['a191'] = 918;
   });
 });
 exports.getMetrics = getMetrics;
 
 /***/ }),
-/* 39 */
+/* 41 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -39924,17 +39969,17 @@ var PostScriptLexer = function PostScrip
     }
   };
   return PostScriptLexer;
 }();
 exports.PostScriptLexer = PostScriptLexer;
 exports.PostScriptParser = PostScriptParser;
 
 /***/ }),
-/* 40 */
+/* 42 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
@@ -40042,36 +40087,38 @@ var MurmurHash3_64 = function MurmurHash
       return str;
     }
   };
   return MurmurHash3_64;
 }();
 exports.MurmurHash3_64 = MurmurHash3_64;
 
 /***/ }),
-/* 41 */
+/* 43 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.PDFImage = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
-var _stream = __w_pdfjs_require__(2);
-
 var _primitives = __w_pdfjs_require__(1);
 
 var _colorspace = __w_pdfjs_require__(3);
 
-var _jpx = __w_pdfjs_require__(10);
+var _stream = __w_pdfjs_require__(2);
+
+var _jpeg_stream = __w_pdfjs_require__(6);
+
+var _jpx = __w_pdfjs_require__(12);
 
 var PDFImage = function PDFImageClosure() {
   function handleImageData(image, nativeDecoder) {
     if (nativeDecoder && nativeDecoder.canDecode(image)) {
       return nativeDecoder.decode(image);
     }
     return Promise.resolve(image);
   }
@@ -40472,17 +40519,17 @@ var PDFImage = function PDFImageClosure(
             (0, _util.assert)(kind === _util.ImageKind.GRAYSCALE_1BPP);
             var buffer = imgData.data;
             for (var i = 0, ii = buffer.length; i < ii; i++) {
               buffer[i] ^= 0xff;
             }
           }
           return imgData;
         }
-        if (this.image instanceof _stream.JpegStream && !this.smask && !this.mask && (this.colorSpace.name === 'DeviceGray' || this.colorSpace.name === 'DeviceRGB' || this.colorSpace.name === 'DeviceCMYK')) {
+        if (this.image instanceof _jpeg_stream.JpegStream && !this.smask && !this.mask && (this.colorSpace.name === 'DeviceGray' || this.colorSpace.name === 'DeviceRGB' || this.colorSpace.name === 'DeviceCMYK')) {
           imgData.kind = _util.ImageKind.RGB_24BPP;
           imgData.data = this.getImageBytes(originalHeight * rowBytes, drawWidth, drawHeight, true);
           return imgData;
         }
       }
       imgArray = this.getImageBytes(originalHeight * rowBytes);
       var actualHeight = 0 | imgArray.length / rowBytes * drawHeight / originalHeight;
       var comps = this.getComponents(imgArray);
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -927,16 +927,18 @@ let PDFViewerApplication = {
   baseUrl: '',
   externalServices: DefaultExternalServices,
   _boundEvents: {},
   initialize(appConfig) {
     this.preferences = this.externalServices.createPreferences();
     configure(_pdfjsLib.PDFJS);
     this.appConfig = appConfig;
     return this._readPreferences().then(() => {
+      return this._parseHashParameters();
+    }).then(() => {
       return this._initializeL10n();
     }).then(() => {
       return this._initializeViewerComponents();
     }).then(() => {
       this.bindEvents();
       this.bindWindowEvents();
       let appContainer = appConfig.appContainer || document.documentElement;
       this.l10n.translate(appContainer).then(() => {
@@ -998,24 +1000,79 @@ let PDFViewerApplication = {
     }), preferences.get('disablePageMode').then(function resolved(value) {
       viewerPrefs['disablePageMode'] = value;
     }), preferences.get('disablePageLabels').then(function resolved(value) {
       viewerPrefs['disablePageLabels'] = value;
     }), preferences.get('enablePrintAutoRotate').then(function resolved(value) {
       viewerPrefs['enablePrintAutoRotate'] = value;
     })]).catch(function (reason) {});
   },
+  _parseHashParameters() {
+    let { appConfig, viewerPrefs } = this;
+    let waitOn = [];
+    if (viewerPrefs['pdfBugEnabled']) {
+      let hash = document.location.hash.substring(1);
+      let hashParams = (0, _ui_utils.parseQueryString)(hash);
+      if ('disableworker' in hashParams) {
+        _pdfjsLib.PDFJS.disableWorker = hashParams['disableworker'] === 'true';
+      }
+      if ('disablerange' in hashParams) {
+        _pdfjsLib.PDFJS.disableRange = hashParams['disablerange'] === 'true';
+      }
+      if ('disablestream' in hashParams) {
+        _pdfjsLib.PDFJS.disableStream = hashParams['disablestream'] === 'true';
+      }
+      if ('disableautofetch' in hashParams) {
+        _pdfjsLib.PDFJS.disableAutoFetch = hashParams['disableautofetch'] === 'true';
+      }
+      if ('disablefontface' in hashParams) {
+        _pdfjsLib.PDFJS.disableFontFace = hashParams['disablefontface'] === 'true';
+      }
+      if ('disablehistory' in hashParams) {
+        _pdfjsLib.PDFJS.disableHistory = hashParams['disablehistory'] === 'true';
+      }
+      if ('webgl' in hashParams) {
+        _pdfjsLib.PDFJS.disableWebGL = hashParams['webgl'] !== 'true';
+      }
+      if ('useonlycsszoom' in hashParams) {
+        _pdfjsLib.PDFJS.useOnlyCssZoom = hashParams['useonlycsszoom'] === 'true';
+      }
+      if ('verbosity' in hashParams) {
+        _pdfjsLib.PDFJS.verbosity = hashParams['verbosity'] | 0;
+      }
+      if ('textlayer' in hashParams) {
+        switch (hashParams['textlayer']) {
+          case 'off':
+            _pdfjsLib.PDFJS.disableTextLayer = true;
+            break;
+          case 'visible':
+          case 'shadow':
+          case 'hover':
+            let viewer = appConfig.viewerContainer;
+            viewer.classList.add('textLayer-' + hashParams['textlayer']);
+            break;
+        }
+      }
+      if ('pdfbug' in hashParams) {
+        _pdfjsLib.PDFJS.pdfBug = true;
+        let pdfBug = hashParams['pdfbug'];
+        let enabled = pdfBug.split(',');
+        waitOn.push(loadAndEnablePDFBug(enabled));
+      }
+    }
+    return Promise.all(waitOn);
+  },
   _initializeL10n() {
     this.l10n = this.externalServices.createL10n();
     return this.l10n.getDirection().then(dir => {
       document.getElementsByTagName('html')[0].dir = dir;
     });
   },
   _initializeViewerComponents() {
-    let appConfig = this.appConfig;
+    let { appConfig, viewerPrefs } = this;
     return new Promise((resolve, reject) => {
       this.overlayManager = new _overlay_manager.OverlayManager();
       let eventBus = appConfig.eventBus || (0, _dom_events.getGlobalEventBus)();
       this.eventBus = eventBus;
       let pdfRenderingQueue = new _pdf_rendering_queue.PDFRenderingQueue();
       pdfRenderingQueue.onIdle = this.cleanup.bind(this);
       this.pdfRenderingQueue = pdfRenderingQueue;
       let pdfLinkService = new _pdf_link_service.PDFLinkService({ eventBus });
@@ -1026,21 +1083,21 @@ let PDFViewerApplication = {
       let viewer = appConfig.viewerContainer;
       this.pdfViewer = new _pdf_viewer.PDFViewer({
         container,
         viewer,
         eventBus,
         renderingQueue: pdfRenderingQueue,
         linkService: pdfLinkService,
         downloadManager,
-        renderer: this.viewerPrefs['renderer'],
+        renderer: viewerPrefs['renderer'],
         l10n: this.l10n,
-        enhanceTextSelection: this.viewerPrefs['enhanceTextSelection'],
-        renderInteractiveForms: this.viewerPrefs['renderInteractiveForms'],
-        enablePrintAutoRotate: this.viewerPrefs['enablePrintAutoRotate']
+        enhanceTextSelection: viewerPrefs['enhanceTextSelection'],
+        renderInteractiveForms: viewerPrefs['renderInteractiveForms'],
+        enablePrintAutoRotate: viewerPrefs['enablePrintAutoRotate']
       });
       pdfRenderingQueue.setViewer(this.pdfViewer);
       pdfLinkService.setViewer(this.pdfViewer);
       let thumbnailContainer = appConfig.sidebar.thumbnailView;
       this.pdfThumbnailViewer = new _pdf_thumbnail_viewer.PDFThumbnailViewer({
         container: thumbnailContainer,
         renderingQueue: pdfRenderingQueue,
         linkService: pdfLinkService,
@@ -1132,19 +1189,16 @@ let PDFViewerApplication = {
       newScale = Math.floor(newScale * 10) / 10;
       newScale = Math.max(_ui_utils.MIN_SCALE, newScale);
     } while (--ticks > 0 && newScale > _ui_utils.MIN_SCALE);
     this.pdfViewer.currentScaleValue = newScale;
   },
   get pagesCount() {
     return this.pdfDocument ? this.pdfDocument.numPages : 0;
   },
-  get pageRotation() {
-    return this.pdfViewer.pagesRotation;
-  },
   set page(val) {
     this.pdfViewer.currentPageNumber = val;
   },
   get page() {
     return this.pdfViewer.currentPageNumber;
   },
   get printing() {
     return !!this.printService;
@@ -1294,16 +1348,19 @@ let PDFViewerApplication = {
     };
     loadingTask.onProgress = ({ loaded, total }) => {
       this.progress(loaded / total);
     };
     loadingTask.onUnsupportedFeature = this.fallback.bind(this);
     return loadingTask.promise.then(pdfDocument => {
       this.load(pdfDocument);
     }, exception => {
+      if (loadingTask !== this.pdfLoadingTask) {
+        return;
+      }
       let message = exception && exception.message;
       let loadingErrorMessage;
       if (exception instanceof _pdfjsLib.InvalidPDFException) {
         loadingErrorMessage = this.l10n.get('invalid_file_error', null, 'Invalid or corrupted PDF file.');
       } else if (exception instanceof _pdfjsLib.MissingPDFException) {
         loadingErrorMessage = this.l10n.get('missing_file_error', null, 'Missing PDF file.');
       } else if (exception instanceof _pdfjsLib.UnexpectedResponseException) {
         loadingErrorMessage = this.l10n.get('unexpected_response_error', null, 'Unexpected server response.');
@@ -1793,69 +1850,18 @@ function loadAndEnablePDFBug(enabledTabs
     };
     (document.getElementsByTagName('head')[0] || document.body).appendChild(script);
   });
 }
 function webViewerInitialized() {
   let appConfig = PDFViewerApplication.appConfig;
   let file;
   file = window.location.href.split('#')[0];
-  let waitForBeforeOpening = [];
   appConfig.toolbar.openFile.setAttribute('hidden', 'true');
   appConfig.secondaryToolbar.openFileButton.setAttribute('hidden', 'true');
-  if (PDFViewerApplication.viewerPrefs['pdfBugEnabled']) {
-    let hash = document.location.hash.substring(1);
-    let hashParams = (0, _ui_utils.parseQueryString)(hash);
-    if ('disableworker' in hashParams) {
-      _pdfjsLib.PDFJS.disableWorker = hashParams['disableworker'] === 'true';
-    }
-    if ('disablerange' in hashParams) {
-      _pdfjsLib.PDFJS.disableRange = hashParams['disablerange'] === 'true';
-    }
-    if ('disablestream' in hashParams) {
-      _pdfjsLib.PDFJS.disableStream = hashParams['disablestream'] === 'true';
-    }
-    if ('disableautofetch' in hashParams) {
-      _pdfjsLib.PDFJS.disableAutoFetch = hashParams['disableautofetch'] === 'true';
-    }
-    if ('disablefontface' in hashParams) {
-      _pdfjsLib.PDFJS.disableFontFace = hashParams['disablefontface'] === 'true';
-    }
-    if ('disablehistory' in hashParams) {
-      _pdfjsLib.PDFJS.disableHistory = hashParams['disablehistory'] === 'true';
-    }
-    if ('webgl' in hashParams) {
-      _pdfjsLib.PDFJS.disableWebGL = hashParams['webgl'] !== 'true';
-    }
-    if ('useonlycsszoom' in hashParams) {
-      _pdfjsLib.PDFJS.useOnlyCssZoom = hashParams['useonlycsszoom'] === 'true';
-    }
-    if ('verbosity' in hashParams) {
-      _pdfjsLib.PDFJS.verbosity = hashParams['verbosity'] | 0;
-    }
-    if ('textlayer' in hashParams) {
-      switch (hashParams['textlayer']) {
-        case 'off':
-          _pdfjsLib.PDFJS.disableTextLayer = true;
-          break;
-        case 'visible':
-        case 'shadow':
-        case 'hover':
-          let viewer = appConfig.viewerContainer;
-          viewer.classList.add('textLayer-' + hashParams['textlayer']);
-          break;
-      }
-    }
-    if ('pdfbug' in hashParams) {
-      _pdfjsLib.PDFJS.pdfBug = true;
-      let pdfBug = hashParams['pdfbug'];
-      let enabled = pdfBug.split(',');
-      waitForBeforeOpening.push(loadAndEnablePDFBug(enabled));
-    }
-  }
   if (!PDFViewerApplication.supportsDocumentFonts) {
     _pdfjsLib.PDFJS.disableFontFace = true;
     PDFViewerApplication.l10n.get('web_fonts_disabled', null, 'Web fonts are disabled: unable to use embedded PDF fonts.').then(msg => {
       console.warn(msg);
     });
   }
   if (!PDFViewerApplication.supportsPrinting) {
     appConfig.toolbar.print.classList.add('hidden');
@@ -1871,20 +1877,20 @@ function webViewerInitialized() {
   appConfig.mainContainer.addEventListener('transitionend', function (evt) {
     if (evt.target === this) {
       PDFViewerApplication.eventBus.dispatch('resize', { source: this });
     }
   }, true);
   appConfig.sidebar.toggleButton.addEventListener('click', function () {
     PDFViewerApplication.pdfSidebar.toggle();
   });
-  Promise.all(waitForBeforeOpening).then(function () {
+  Promise.resolve().then(function () {
     webViewerOpenFileViaURL(file);
   }).catch(function (reason) {
-    PDFViewerApplication.l10n.get('loading_error', null, 'An error occurred while opening.').then(msg => {
+    PDFViewerApplication.l10n.get('loading_error', null, 'An error occurred while loading the PDF.').then(msg => {
       PDFViewerApplication.error(msg, reason);
     });
   });
 }
 let webViewerOpenFileViaURL;
 {
   webViewerOpenFileViaURL = function webViewerOpenFileViaURL(file) {
     PDFViewerApplication.setTitleUsingUrl(file);
--- a/browser/modules/ContentMetaHandler.jsm
+++ b/browser/modules/ContentMetaHandler.jsm
@@ -6,16 +6,18 @@
 const {utils: Cu, interfaces: Ci, classes: Cc} = Components;
 Cu.importGlobalProperties(["URL"]);
 Cu.import("resource://gre/modules/Services.jsm");
 
 // Debounce time in milliseconds - this should be long enough to account for
 // sync script tags that could appear between desired meta tags
 const TIMEOUT_DELAY = 1000;
 
+const ACCEPTED_PROTOCOLS = ["http:", "https:"];
+
 // Possible description tags, listed in order from least favourable to most favourable
 const DESCRIPTION_RULES = [
   "twitter:description",
   "description",
   "og:description"
 ];
 
 // Possible image tags, listed in order from least favourable to most favourable
@@ -40,16 +42,38 @@ const PREVIEW_IMAGE_RULES = [
  *
  * @returns {Boolean} true if the incoming meta tag is better than the current
  *                    best meta tag of that same kind, false otherwise
  */
 function shouldExtractMetadata(aRules, aTag, aEntry) {
   return aRules.indexOf(aTag) > aEntry.currMaxScore;
 }
 
+/*
+ * Ensure that the preview image URL is safe and valid before storing
+ *
+ * @param {URL} aURL
+ *          A URL object that needs to be checked for valid principal and protocol
+ *
+ * @returns {Boolean} true if the preview URL is safe and can be stored, false otherwise
+ */
+function checkLoadURIStr(aURL) {
+  if (!ACCEPTED_PROTOCOLS.includes(aURL.protocol)) {
+    return false;
+  }
+  try {
+    let ssm = Services.scriptSecurityManager;
+    let principal = ssm.createNullPrincipal({});
+    ssm.checkLoadURIStrWithPrincipal(principal, aURL.href, ssm.DISALLOW_INHERIT_PRINCIPAL);
+  } catch (e) {
+    return false;
+  }
+  return true;
+}
+
 this.EXPORTED_SYMBOLS = [ "ContentMetaHandler" ];
 
 /*
  * This listens to DOMMetaAdded events and collects relevant metadata about the
  * meta tag received. Then, it sends the metadata gathered from the meta tags
  * and the url of the page as it's payload to be inserted into moz_places.
  */
 
@@ -83,28 +107,36 @@ this.ContentMetaHandler = {
     let tag = name || prop;
 
     const entry = metaTags.get(url) || {
       description: {value: null, currMaxScore: -1},
       image: {value: null, currMaxScore: -1},
       timeout: null
     };
 
+    // Malformed meta tag - do not store it
+    const content = metaTag.getAttributeNS(null, "content");
+    if (!content) {
+      return;
+    }
+
     if (shouldExtractMetadata(DESCRIPTION_RULES, tag, entry.description)) {
       // Extract the description
-      const value = metaTag.getAttributeNS(null, "content");
-      if (value) {
-        entry.description.value = value;
-        entry.description.currMaxScore = DESCRIPTION_RULES.indexOf(tag);
-      }
+      entry.description.value = content;
+      entry.description.currMaxScore = DESCRIPTION_RULES.indexOf(tag);
     } else if (shouldExtractMetadata(PREVIEW_IMAGE_RULES, tag, entry.image)) {
       // Extract the preview image
-      const value = metaTag.getAttributeNS(null, "content");
-      if (value) {
-        entry.image.value = new URL(value, url).href;
+      let value;
+      try {
+        value = new URL(content, url);
+      } catch (e) {
+        return;
+      }
+      if (value && checkLoadURIStr(value)) {
+        entry.image.value = value.href;
         entry.image.currMaxScore = PREVIEW_IMAGE_RULES.indexOf(tag);
       }
     } else {
       // We don't care about other meta tags
       return;
     }
 
     if (!metaTags.has(url)) {
--- a/config/external/nspr/pr/moz.build
+++ b/config/external/nspr/pr/moz.build
@@ -80,16 +80,18 @@ elif CONFIG['OS_TARGET'] == 'WINNT':
         XP_PC=True,
         WIN32=True,
         # For historical reasons we use the WIN95 NSPR target instead of
         # WINNT.
         WIN95=True,
         WINNT=False,
         _PR_GLOBAL_THREADS_ONLY=True,
     )
+    if not CONFIG['DEBUG']:
+      DEFINES['DO_NOT_WAIT_FOR_CONNECT_OVERLAPPED_OPERATIONS'] = True
     if CONFIG['CPU_ARCH'] == 'x86_64':
         DEFINES['_AMD64_'] = True
     else:
         DEFINES['_X86_'] = True
 else:
     error('Not a supported OS_TARGET for NSPR in moz.build: "%s". Use --with-system-nspr' % CONFIG['OS_TARGET'])
 
 
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -72,16 +72,17 @@ CustomElementConstructor::Construct(cons
   if (!cx) {
     MOZ_ASSERT(aRv.Failed());
     return nullptr;
   }
 
   JS::Rooted<JSObject*> result(cx);
   JS::Rooted<JS::Value> constructor(cx, JS::ObjectValue(*mCallback));
   if (!JS::Construct(cx, constructor, JS::HandleValueArray::empty(), &result)) {
+    aRv.NoteJSContextException(cx);
     return nullptr;
   }
 
   RefPtr<Element> element;
   if (NS_FAILED(UNWRAP_OBJECT(Element, &result, element))) {
     return nullptr;
   }
 
@@ -152,33 +153,35 @@ CustomElementData::Unlink()
 //-----------------------------------------------------
 // CustomElementRegistry
 
 namespace {
 
 class MOZ_RAII AutoConstructionStackEntry final
 {
 public:
-  AutoConstructionStackEntry(nsTArray<RefPtr<nsGenericHTMLElement>>& aStack,
-                             nsGenericHTMLElement* aElement)
+  AutoConstructionStackEntry(nsTArray<RefPtr<Element>>& aStack,
+                             Element* aElement)
     : mStack(aStack)
   {
+    MOZ_ASSERT(aElement->IsHTMLElement() || aElement->IsXULElement());
+
     mIndex = mStack.Length();
     mStack.AppendElement(aElement);
   }
 
   ~AutoConstructionStackEntry()
   {
     MOZ_ASSERT(mIndex == mStack.Length() - 1,
                "Removed element should be the last element");
     mStack.RemoveElementAt(mIndex);
   }
 
 private:
-  nsTArray<RefPtr<nsGenericHTMLElement>>& mStack;
+  nsTArray<RefPtr<Element>>& mStack;
   uint32_t mIndex;
 };
 
 } // namespace anonymous
 
 // Only needed for refcounted objects.
 NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementRegistry)
 
@@ -911,18 +914,17 @@ CustomElementRegistry::Upgrade(Element* 
 
   // Step 4.
   if (aElement->IsInComposedDoc()) {
     nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eConnected, aElement,
       nullptr, nullptr, aDefinition);
   }
 
   // Step 5.
-  AutoConstructionStackEntry acs(aDefinition->mConstructionStack,
-                                 nsGenericHTMLElement::FromContent(aElement));
+  AutoConstructionStackEntry acs(aDefinition->mConstructionStack, aElement);
 
   // Step 6 and step 7.
   DoUpgrade(aElement, aDefinition->mConstructor, aRv);
   if (aRv.Failed()) {
     data->mState = CustomElementData::State::eFailed;
     // Empty element's custom element reaction queue.
     data->mReactionQueue.Clear();
     return;
--- a/dom/base/CustomElementRegistry.h
+++ b/dom/base/CustomElementRegistry.h
@@ -169,17 +169,17 @@ struct CustomElementDefinition
 
   // The prototype to use for new custom elements of this type.
   JS::Heap<JSObject *> mPrototype;
 
   // The lifecycle callbacks to call for this custom element.
   UniquePtr<mozilla::dom::LifecycleCallbacks> mCallbacks;
 
   // A construction stack. Use nullptr to represent an "already constructed marker".
-  nsTArray<RefPtr<nsGenericHTMLElement>> mConstructionStack;
+  nsTArray<RefPtr<Element>> mConstructionStack;
 
   // The document custom element order.
   uint32_t mDocOrder;
 
   bool IsCustomBuiltIn()
   {
     return mType != mLocalName;
   }
--- a/dom/base/nsContentCreatorFunctions.h
+++ b/dom/base/nsContentCreatorFunctions.h
@@ -54,17 +54,18 @@ CreateHTMLElement(uint32_t aNodeType,
 
 nsresult
 NS_NewMathMLElement(mozilla::dom::Element** aResult,
                     already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
 
 #ifdef MOZ_XUL
 nsresult
 NS_NewXULElement(mozilla::dom::Element** aResult,
-                 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
+                 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
+                 mozilla::dom::FromParser aFromParser);
 
 void
 NS_TrustedNewXULElement(nsIContent** aResult,
                         already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
 #endif
 
 nsresult
 NS_NewSVGElement(mozilla::dom::Element** aResult,
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -221,16 +221,17 @@
 #include "mozilla/BloomFilter.h"
 #include "TabChild.h"
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/TabGroup.h"
 #include "nsIWebNavigationInfo.h"
 #include "nsPluginHost.h"
 #include "mozilla/HangAnnotations.h"
 #include "mozilla/Encoding.h"
+#include "nsXULElement.h"
 
 #include "nsIBidiKeyboard.h"
 
 #if defined(XP_WIN)
 // Undefine LoadImage to prevent naming conflict with Windows.
 #undef LoadImage
 #endif
 
@@ -10062,25 +10063,205 @@ nsContentUtils::TryToUpgradeElement(Elem
   } else {
     // Add an unresolved custom element that is a candidate for
     // upgrade when a custom element is connected to the document.
     // We will make sure it's shadow-including tree order in bug 1326028.
     nsContentUtils::RegisterUnresolvedElement(aElement, typeAtom);
   }
 }
 
+static void
+DoCustomElementCreate(Element** aElement, nsIDocument* aDoc, NodeInfo* aNodeInfo,
+                      CustomElementConstructor* aConstructor, ErrorResult& aRv)
+{
+  RefPtr<Element> element =
+    aConstructor->Construct("Custom Element Create", aRv);
+  if (aRv.Failed()) {
+    return;
+  }
+
+  if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
+    if (!element || !element->IsHTMLElement()) {
+      aRv.ThrowTypeError<MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE>(NS_LITERAL_STRING("HTMLElement"));
+      return;
+    }
+  } else {
+    if (!element || !element->IsXULElement()) {
+      aRv.ThrowTypeError<MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE>(NS_LITERAL_STRING("XULElement"));
+      return;
+    }
+  }
+
+  nsAtom* localName = aNodeInfo->NameAtom();
+
+  if (aDoc != element->OwnerDoc() || element->GetParentNode() ||
+      element->HasChildren() || element->GetAttrCount() ||
+      element->NodeInfo()->NameAtom() != localName) {
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return;
+  }
+
+  element.forget(aElement);
+}
+
+/* static */ nsresult
+nsContentUtils::NewXULOrHTMLElement(Element** aResult, mozilla::dom::NodeInfo* aNodeInfo,
+                                    FromParser aFromParser, const nsAString* aIs,
+                                    mozilla::dom::CustomElementDefinition* aDefinition)
+{
+  RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
+  MOZ_ASSERT(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) ||
+             nodeInfo->NamespaceEquals(kNameSpaceID_XUL),
+             "Can only create XUL or XHTML elements.");
+
+  nsAtom *name = nodeInfo->NameAtom();
+  RefPtr<nsAtom> tagAtom = nodeInfo->NameAtom();
+  RefPtr<nsAtom> typeAtom = aIs ? NS_Atomize(*aIs) : tagAtom;
+
+  int32_t tag = eHTMLTag_unknown;
+  bool isCustomElementName = false;
+  if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
+    tag = nsHTMLTags::CaseSensitiveAtomTagToId(name);
+    isCustomElementName = (tag == eHTMLTag_userdefined &&
+                           nsContentUtils::IsCustomElementName(name));
+  } else {
+    isCustomElementName = nsContentUtils::IsCustomElementName(name);
+  }
+  bool isCustomElement = isCustomElementName || aIs;
+  MOZ_ASSERT_IF(aDefinition, isCustomElement);
+
+  // https://dom.spec.whatwg.org/#concept-create-element
+  // We only handle the "synchronous custom elements flag is set" now.
+  // For the unset case (e.g. cloning a node), see bug 1319342 for that.
+  // Step 4.
+  CustomElementDefinition* definition = aDefinition;
+  if (CustomElementRegistry::IsCustomElementEnabled() && isCustomElement &&
+      !definition) {
+    definition =
+      nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(),
+                                                    nodeInfo->LocalName(),
+                                                    nodeInfo->NamespaceID(),
+                                                    typeAtom);
+  }
+
+  // It might be a problem that parser synchronously calls constructor, so filed
+  // bug 1378079 to figure out what we should do for parser case.
+  if (definition) {
+    /*
+      * Synchronous custom elements flag is determined by 3 places in spec,
+      * 1) create an element for a token, the flag is determined by
+      *    "will execute script" which is not originally created
+      *    for the HTML fragment parsing algorithm.
+      * 2) createElement and createElementNS, the flag is the same as
+      *    NOT_FROM_PARSER.
+      * 3) clone a node, our implementation will not go into this function.
+      * For the unset case which is non-synchronous only applied for
+      * inner/outerHTML.
+      */
+    bool synchronousCustomElements = aFromParser != dom::FROM_PARSER_FRAGMENT ||
+                                     aFromParser == dom::NOT_FROM_PARSER;
+    // Per discussion in https://github.com/w3c/webcomponents/issues/635,
+    // use entry global in those places that are called from JS APIs and use the
+    // node document's global object if it is called from parser.
+    nsIGlobalObject* global;
+    if (aFromParser == dom::NOT_FROM_PARSER) {
+      global = GetEntryGlobal();
+    } else {
+      global = nodeInfo->GetDocument()->GetScopeObject();
+    }
+    if (!global) {
+      // In browser chrome code, one may have access to a document which doesn't
+      // have scope object anymore.
+      return NS_ERROR_FAILURE;
+    }
+
+    AutoEntryScript aes(global, "create custom elements");
+    JSContext* cx = aes.cx();
+    ErrorResult rv;
+
+    // Step 5.
+    if (definition->IsCustomBuiltIn()) {
+      // SetupCustomElement() should be called with an element that don't have
+      // CustomElementData setup, if not we will hit the assertion in
+      // SetCustomElementData().
+      // Built-in element
+      MOZ_ASSERT(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML),
+                 "Custom built-in XUL elements are not supported yet.");
+      *aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
+      (*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
+      if (synchronousCustomElements) {
+        CustomElementRegistry::Upgrade(*aResult, definition, rv);
+        if (rv.MaybeSetPendingException(cx)) {
+          aes.ReportException();
+        }
+      } else {
+        nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
+      }
+
+      return NS_OK;
+    }
+
+    // Step 6.1.
+    if (synchronousCustomElements) {
+      DoCustomElementCreate(aResult, nodeInfo->GetDocument(), nodeInfo,
+                            definition->mConstructor, rv);
+      if (rv.MaybeSetPendingException(cx)) {
+        if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
+          NS_IF_ADDREF(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget(), aFromParser));
+        } else {
+          NS_IF_ADDREF(*aResult = new nsXULElement(nodeInfo.forget()));
+        }
+      }
+      return NS_OK;
+    }
+
+    // Step 6.2.
+    if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
+      NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
+    } else {
+      NS_IF_ADDREF(*aResult = new nsXULElement(nodeInfo.forget()));
+    }
+    (*aResult)->SetCustomElementData(new CustomElementData(definition->mType));
+    nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
+    return NS_OK;
+  }
+
+  if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
+    // Per the Custom Element specification, unknown tags that are valid custom
+    // element names should be HTMLElement instead of HTMLUnknownElement.
+    if (isCustomElementName) {
+      NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
+    } else {
+      *aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
+    }
+  } else {
+    NS_IF_ADDREF(*aResult = new nsXULElement(nodeInfo.forget()));
+  }
+
+  if (!*aResult) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  if (CustomElementRegistry::IsCustomElementEnabled() && isCustomElement) {
+    (*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
+  }
+
+  return NS_OK;
+}
+
 /* static */ CustomElementDefinition*
 nsContentUtils::LookupCustomElementDefinition(nsIDocument* aDoc,
                                               const nsAString& aLocalName,
                                               uint32_t aNameSpaceID,
                                               nsAtom* aTypeAtom)
 {
   MOZ_ASSERT(aDoc);
 
-  if (aNameSpaceID != kNameSpaceID_XHTML ||
+  if ((aNameSpaceID != kNameSpaceID_XUL &&
+       aNameSpaceID != kNameSpaceID_XHTML) ||
       !aDoc->GetDocShell()) {
     return nullptr;
   }
 
   nsCOMPtr<nsPIDOMWindowInner> window(aDoc->GetInnerWindow());
   if (!window) {
     return nullptr;
   }
@@ -10171,17 +10352,18 @@ nsContentUtils::EnqueueLifecycleCallback
 /* static */ void
 nsContentUtils::GetCustomPrototype(nsIDocument* aDoc,
                                    int32_t aNamespaceID,
                                    nsAtom* aAtom,
                                    JS::MutableHandle<JSObject*> aPrototype)
 {
   MOZ_ASSERT(aDoc);
 
-  if (aNamespaceID != kNameSpaceID_XHTML ||
+  if ((aNamespaceID != kNameSpaceID_XHTML &&
+       aNamespaceID != kNameSpaceID_XUL) ||
       !aDoc->GetDocShell()) {
     return;
   }
 
   nsCOMPtr<nsPIDOMWindowInner> window(aDoc->GetInnerWindow());
   if (!window) {
     return;
   }
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -15,16 +15,17 @@
 
 #if defined(SOLARIS)
 #include <ieeefp.h>
 #endif
 
 #include "js/TypeDecls.h"
 #include "js/Value.h"
 #include "js/RootingAPI.h"
+#include "mozilla/dom/FromParser.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/TaskCategory.h"
 #include "mozilla/TimeStamp.h"
 #include "nsContentListDeclarations.h"
 #include "nsMathUtils.h"
 #include "nsTArrayForwardDeclare.h"
@@ -3024,16 +3025,24 @@ public:
 
   /**
    * Try to upgrade an element.
    * https://html.spec.whatwg.org/multipage/custom-elements.html#concept-try-upgrade
    */
   static void TryToUpgradeElement(Element* aElement);
 
   /**
+   * Creates a new XUL or XHTML element applying any appropriate custom element
+   * definition.
+   */
+  static nsresult NewXULOrHTMLElement(Element** aResult, mozilla::dom::NodeInfo* aNodeInfo,
+                                      mozilla::dom::FromParser aFromParser, const nsAString* aIs,
+                                      mozilla::dom::CustomElementDefinition* aDefinition);
+
+  /**
    * Looking up a custom element definition.
    * https://html.spec.whatwg.org/#look-up-a-custom-element-definition
    */
   static mozilla::dom::CustomElementDefinition*
     LookupCustomElementDefinition(nsIDocument* aDoc,
                                   const nsAString& aLocalName,
                                   uint32_t aNameSpaceID,
                                   nsAtom* aTypeAtom);
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -6392,17 +6392,17 @@ nsDocument::CustomElementConstructor(JSC
   }
 
   RefPtr<Element> element;
 
   // We integrate with construction stack and do prototype swizzling here, so
   // that old upgrade behavior could also share the new upgrade steps.
   // And this old upgrade will be remove at some point (when everything is
   // switched to latest custom element spec).
-  nsTArray<RefPtr<nsGenericHTMLElement>>& constructionStack =
+  nsTArray<RefPtr<Element>>& constructionStack =
     definition->mConstructionStack;
   if (constructionStack.Length()) {
     element = constructionStack.LastElement();
     NS_ENSURE_TRUE(element != ALEADY_CONSTRUCTED_MARKER, false);
 
     // Do prototype swizzling if dom reflector exists.
     JS::Rooted<JSObject*> reflector(aCx, element->GetWrapper());
     if (reflector) {
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -1357,19 +1357,21 @@ nsGlobalWindowInner::FreeInnerObjects()
   mHasVREvents = false;
   mHasVRDisplayActivateEvents = false;
   mVRDisplays.Clear();
 
   // This breaks a cycle between the window and the ClientSource object.
   mClientSource.reset();
 
   if (mTabChild) {
-    while (mBeforeUnloadListenerCount-- > 0) {
+    // Remove any remaining listeners, and reset mBeforeUnloadListenerCount.
+    for (int i = 0; i < mBeforeUnloadListenerCount; ++i) {
       mTabChild->BeforeUnloadRemoved();
     }
+    mBeforeUnloadListenerCount = 0;
   }
 }
 
 //*****************************************************************************
 // nsGlobalWindowInner::nsISupports
 //*****************************************************************************
 
 // QueryInterface implementation for nsGlobalWindowInner
--- a/dom/base/nsNameSpaceManager.cpp
+++ b/dom/base/nsNameSpaceManager.cpp
@@ -178,17 +178,17 @@ NS_NewElement(Element** aResult,
 {
   RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
   int32_t ns = ni->NamespaceID();
   if (ns == kNameSpaceID_XHTML) {
     return NS_NewHTMLElement(aResult, ni.forget(), aFromParser, aIs);
   }
 #ifdef MOZ_XUL
   if (ns == kNameSpaceID_XUL) {
-    return NS_NewXULElement(aResult, ni.forget());
+    return NS_NewXULElement(aResult, ni.forget(), aFromParser);
   }
 #endif
   if (ns == kNameSpaceID_MathML) {
     // If the mathml.disabled pref. is true, convert all MathML nodes into
     // disabled MathML nodes by swapping the namespace.
     if (ni->NodeInfoManager()->MathMLEnabled()) {
       return NS_NewMathMLElement(aResult, ni.forget());
     }
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -453,17 +453,17 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
   if (aClone) {
     nsresult rv = aNode->Clone(nodeInfo, getter_AddRefs(clone), aDeep);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       aError.Throw(rv);
       return nullptr;
     }
 
     if (CustomElementRegistry::IsCustomElementEnabled() &&
-        clone->IsHTMLElement()) {
+        (clone->IsHTMLElement() || clone->IsXULElement())) {
       // The cloned node may be a custom element that may require
       // enqueing upgrade reaction.
       Element* cloneElem = clone->AsElement();
       RefPtr<nsAtom> tagAtom = nodeInfo->NameAtom();
       CustomElementData* data = elem->GetCustomElementData();
 
       // Check if node may be custom element by type extension.
       // ex. <button is="x-button">
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -41,27 +41,29 @@
 #include "mozilla/dom/CustomElementRegistry.h"
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/ElementBinding.h"
 #include "mozilla/dom/HTMLObjectElement.h"
 #include "mozilla/dom/HTMLObjectElementBinding.h"
 #include "mozilla/dom/HTMLEmbedElement.h"
 #include "mozilla/dom/HTMLElementBinding.h"
 #include "mozilla/dom/HTMLEmbedElementBinding.h"
+#include "mozilla/dom/XULElementBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ResolveSystemBinding.h"
 #include "mozilla/dom/WebIDLGlobalNameHash.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "mozilla/dom/XrayExpandoClass.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "nsDOMClassInfo.h"
 #include "ipc/ErrorIPCUtils.h"
 #include "mozilla/UseCounter.h"
 #include "mozilla/dom/DocGroup.h"
+#include "nsXULElement.h"
 
 namespace mozilla {
 namespace dom {
 
 using namespace workers;
 
 // Forward declare GetConstructorObject methods.
 #define HTML_TAG(_tag, _classname, _interfacename)                             \
@@ -3543,33 +3545,38 @@ GetCustomElementReactionsStack(JS::Handl
   if (!docGroup) {
     return nullptr;
   }
 
   return docGroup->CustomElementReactionsStack();
 }
 
 // https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor
-already_AddRefed<nsGenericHTMLElement>
-CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
-                  JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv)
+already_AddRefed<Element>
+CreateXULOrHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
+                       JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv)
 {
   // Step 1.
   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsIDocument* doc = window->GetExtantDoc();
   if (!doc) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
+  int32_t ns = doc->GetDefaultNamespaceID();
+  if (ns != kNameSpaceID_XUL) {
+    ns = kNameSpaceID_XHTML;
+  }
+
   RefPtr<mozilla::dom::CustomElementRegistry> registry(window->CustomElements());
   if (!registry) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   // Step 2 is in the code output by CGClassConstructor.
   // Step 3.
@@ -3592,31 +3599,44 @@ CreateHTMLElement(const GlobalObject& aG
   // And the actual callee might be in different compartment, so enter its
   // compartment before getting the standard constructor object to compare to,
   // so we get it from the same global as callee itself.
   JSAutoCompartment ac(cx, callee);
   int32_t tag = eHTMLTag_userdefined;
   if (!definition->IsCustomBuiltIn()) {
     // Step 4.
     // If the definition is for an autonomous custom element, the active
-    // function should be HTMLElement.
-    JS::Rooted<JSObject*> constructor(cx, HTMLElementBinding::GetConstructorObject(cx));
+    // function should be HTMLElement or XULElement
+    JS::Rooted<JSObject*> constructor(cx);
+    if (ns == kNameSpaceID_XUL) {
+      constructor = XULElementBinding::GetConstructorObject(cx);
+    } else {
+      constructor = HTMLElementBinding::GetConstructorObject(cx);
+    }
+
     if (!constructor) {
       aRv.NoteJSContextException(cx);
       return nullptr;
     }
 
     if (callee != constructor) {
       aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
       return nullptr;
     }
   } else {
     // Step 5.
     // If the definition is for a customized built-in element, the localName
     // should be defined in the specification.
+
+    // Customized built-in elements are not supported for XUL yet.
+    if (ns == kNameSpaceID_XUL) {
+      aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+      return nullptr;
+    }
+
     tag = nsHTMLTags::CaseSensitiveAtomTagToId(definition->mLocalName);
     if (tag == eHTMLTag_userdefined) {
       aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
       return nullptr;
     }
 
     MOZ_ASSERT(tag <= NS_HTML_TAG_MAX, "tag is out of bounds");
 
@@ -3638,47 +3658,51 @@ CreateHTMLElement(const GlobalObject& aG
       aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
       return nullptr;
     }
   }
 
   RefPtr<mozilla::dom::NodeInfo> nodeInfo =
     doc->NodeInfoManager()->GetNodeInfo(definition->mLocalName,
                                         nullptr,
-                                        kNameSpaceID_XHTML,
+                                        ns,
                                         nsIDOMNode::ELEMENT_NODE);
   if (!nodeInfo) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   // Step 6 and Step 7 are in the code output by CGClassConstructor.
   // Step 8.
-  nsTArray<RefPtr<nsGenericHTMLElement>>& constructionStack =
+  nsTArray<RefPtr<Element>>& constructionStack =
     definition->mConstructionStack;
   if (constructionStack.IsEmpty()) {
-    RefPtr<nsGenericHTMLElement> newElement;
-    if (tag == eHTMLTag_userdefined) {
-      // Autonomous custom element.
-      newElement = NS_NewHTMLElement(nodeInfo.forget());
+    RefPtr<Element> newElement;
+    if (ns == kNameSpaceID_XUL) {
+      newElement = new nsXULElement(nodeInfo.forget());
     } else {
-      // Customized built-in element.
-      newElement = CreateHTMLElement(tag, nodeInfo.forget(), NOT_FROM_PARSER);
+      if (tag == eHTMLTag_userdefined) {
+        // Autonomous custom element.
+        newElement = NS_NewHTMLElement(nodeInfo.forget());
+      } else {
+        // Customized built-in element.
+        newElement = CreateHTMLElement(tag, nodeInfo.forget(), NOT_FROM_PARSER);
+      }
     }
 
     newElement->SetCustomElementData(
       new CustomElementData(definition->mType, CustomElementData::State::eCustom));
 
     newElement->SetCustomElementDefinition(definition);
 
     return newElement.forget();
   }
 
   // Step 9.
-  RefPtr<nsGenericHTMLElement>& element = constructionStack.LastElement();
+  RefPtr<Element>& element = constructionStack.LastElement();
 
   // Step 10.
   if (element == ALEADY_CONSTRUCTED_MARKER) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
   // Step 11.
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3386,21 +3386,21 @@ GetDesiredProto(JSContext* aCx, const JS
 
 // Get the CustomElementReactionsStack for the docgroup of the global
 // of the underlying object of aObj.  This can be null if aObj can't
 // be CheckUnwrapped, or if the global of the result has no docgroup
 // (e.g. because it's not a Window global).
 CustomElementReactionsStack*
 GetCustomElementReactionsStack(JS::Handle<JSObject*> aObj);
 // This function is expected to be called from the constructor function for an
-// HTML element interface; the global/callargs need to be whatever was passed to
-// that constructor function.
-already_AddRefed<nsGenericHTMLElement>
-CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
-                  JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv);
+// HTML or XUL element interface; the global/callargs need to be whatever was
+// passed to that constructor function.
+already_AddRefed<Element>
+CreateXULOrHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
+                       JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv);
 
 void
 SetDocumentAndPageUseCounter(JSObject* aObject, UseCounter aUseCounter);
 
 // Warnings
 void
 DeprecationWarning(JSContext* aCx, JSObject* aObject,
                    nsIDocument::DeprecatedOperations aOperation);
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1902,21 +1902,21 @@ class CGClassConstructor(CGAbstractStati
             ctorName=ctorName,
             htmlConstructorSanityCheck=htmlConstructorSanityCheck,
             htmlConstructorFallback=htmlConstructorFallback)
 
         if  self._ctor.isHTMLConstructor():
             signatures = self._ctor.signatures()
             assert len(signatures) == 1
             # Given that HTMLConstructor takes no args, we can just codegen a
-            # call to CreateHTMLElement() in BindingUtils which reuses the
+            # call to CreateXULOrHTMLElement() in BindingUtils which reuses the
             # factory thing in HTMLContentSink. Then we don't have to implement
             # Constructor on all the HTML elements.
             callGenerator = CGPerSignatureCall(signatures[0][0], signatures[0][1],
-                                               "CreateHTMLElement", True,
+                                               "CreateXULOrHTMLElement", True,
                                                self.descriptor, self._ctor,
                                                isConstructor=True)
         else:
             name = self._ctor.identifier.name
             nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
             callGenerator = CGMethodCall(nativeName, True, self.descriptor,
                                          self._ctor, isConstructor=True,
                                          constructorName=ctorName)
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -1737,16 +1737,63 @@ EventStateManager::FillInEventFromGestur
   // the old event, adjusted for the fact that the widget might be
   // different
   aEvent->mRefPoint =
     mGestureDownPoint - aEvent->mWidget->WidgetToScreenOffset();
   aEvent->mModifiers = mGestureModifiers;
   aEvent->buttons = mGestureDownButtons;
 }
 
+void
+EventStateManager::MaybeFirePointerCancel(WidgetInputEvent* aEvent)
+{
+  nsCOMPtr<nsIPresShell> shell = mPresContext->GetPresShell();
+  AutoWeakFrame targetFrame = mCurrentTarget;
+
+  if (!PointerEventHandler::IsPointerEventEnabled() || !shell ||
+      !targetFrame) {
+    return;
+  }
+
+  nsCOMPtr<nsIContent> content;
+  targetFrame->GetContentForEvent(aEvent, getter_AddRefs(content));
+  if (!content) {
+    return;
+  }
+
+  nsEventStatus status = nsEventStatus_eIgnore;
+
+  if (WidgetMouseEvent* aMouseEvent = aEvent->AsMouseEvent()) {
+    WidgetPointerEvent event(*aMouseEvent);
+    PointerEventHandler::InitPointerEventFromMouse(&event,
+                                                   aMouseEvent,
+                                                   ePointerCancel);
+
+    event.convertToPointer = false;
+    shell->HandleEventWithTarget(&event, targetFrame, content, &status);
+  } else if (WidgetTouchEvent* aTouchEvent = aEvent->AsTouchEvent()) {
+    WidgetPointerEvent event(aTouchEvent->IsTrusted(), ePointerCancel,
+                             aTouchEvent->mWidget);
+
+    PointerEventHandler::InitPointerEventFromTouch(&event,
+                                                   aTouchEvent,
+                                                   aTouchEvent->mTouches[0],
+                                                   true);
+
+    event.convertToPointer = false;
+    shell->HandleEventWithTarget(&event, targetFrame, content, &status);
+  } else {
+    MOZ_ASSERT(false);
+  }
+
+  // HandleEventWithTarget clears out mCurrentTarget, which may be used in the
+  // caller GenerateDragGesture. We have to restore mCurrentTarget.
+  mCurrentTarget = targetFrame;
+}
+
 //
 // GenerateDragGesture
 //
 // If we're in the TRACKING state of the d&d gesture tracker, check the current position
 // of the mouse in relation to the old one. If we've moved a sufficient amount from
 // the mouse down, then fire off a drag gesture event.
 void
 EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
@@ -1888,16 +1935,17 @@ EventStateManager::GenerateDragGesture(n
                                          nullptr);
       }
 
       if (status != nsEventStatus_eConsumeNoDefault) {
         bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer,
                                               targetContent, selection);
         if (dragStarted) {
           sActiveESM = nullptr;
+          MaybeFirePointerCancel(aEvent);
           aEvent->StopPropagation();
         }
       }
 
       // Reset mCurretTargetContent to what it was
       mCurrentTargetContent = targetBeforeEvent;
     }
 
@@ -3254,20 +3302,22 @@ EventStateManager::PostHandleEvent(nsPre
   case ePointerCancel:
   case ePointerUp: {
     WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
     MOZ_ASSERT(pointerEvent);
     // Implicitly releasing capture for given pointer. ePointerLostCapture
     // should be send after ePointerUp or ePointerCancel.
     PointerEventHandler::ImplicitlyReleasePointerCapture(pointerEvent);
 
-    if (pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
-      // After UP/Cancel Touch pointers become invalid so we can remove relevant
-      // helper from Table Mouse/Pen pointers are valid all the time (not only
-      // between down/up)
+    if (pointerEvent->mMessage == ePointerCancel ||
+        pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
+      // After pointercancel, pointer becomes invalid so we can remove relevant
+      // helper from table. Regarding pointerup with non-hoverable device, the
+      // pointer also becomes invalid. Hoverable (mouse/pen) pointers are valid
+      // all the time (not only between down/up).
       GenerateMouseEnterExit(pointerEvent);
       mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId);
     }
     break;
   }
   case eMouseUp:
     {
       ClearGlobalActiveContent(this);
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -907,16 +907,22 @@ protected:
 
   friend class mozilla::dom::TabParent;
   void BeginTrackingRemoteDragGesture(nsIContent* aContent);
   void StopTrackingDragGesture();
   void GenerateDragGesture(nsPresContext* aPresContext,
                            WidgetInputEvent* aEvent);
 
   /**
+   * When starting a dnd session, UA must fire a pointercancel event and stop
+   * firing the subsequent pointer events.
+   */
+  void MaybeFirePointerCancel(WidgetInputEvent* aEvent);
+
+  /**
    * Determine which node the drag should be targeted at.
    * This is either the node clicked when there is a selection, or, for HTML,
    * the element with a draggable property set to true.
    *
    * aSelectionTarget - target to check for selection
    * aDataTransfer - data transfer object that will contain the data to drag
    * aSelection - [out] set to the selection to be dragged
    * aTargetNode - [out] the draggable node, or null if there isn't one
--- a/dom/events/PointerEventHandler.cpp
+++ b/dom/events/PointerEventHandler.cpp
@@ -372,16 +372,71 @@ PointerEventHandler::PostHandlePointerEv
   if (!pointerInfo->mActiveState) {
     return;
   }
   aMouseOrTouchEvent->PreventDefault(false);
   pointerInfo->mPreventMouseEventByContent = true;
 }
 
 /* static */ void
+PointerEventHandler::InitPointerEventFromMouse(
+                       WidgetPointerEvent* aPointerEvent,
+                       WidgetMouseEvent* aMouseEvent,
+                       EventMessage aMessage)
+{
+  MOZ_ASSERT(aPointerEvent);
+  MOZ_ASSERT(aMouseEvent);
+  aPointerEvent->pointerId = aMouseEvent->pointerId;
+  aPointerEvent->inputSource = aMouseEvent->inputSource;
+  aPointerEvent->mMessage = aMessage;
+  aPointerEvent->button = aMouseEvent->mMessage == eMouseMove ?
+                            WidgetMouseEvent::eNoButton : aMouseEvent->button;
+
+  aPointerEvent->buttons = aMouseEvent->buttons;
+  aPointerEvent->pressure = aPointerEvent->buttons ?
+                              aMouseEvent->pressure ?
+                                aMouseEvent->pressure : 0.5f :
+                              0.0f;
+}
+
+/* static */ void
+PointerEventHandler::InitPointerEventFromTouch(
+                       WidgetPointerEvent* aPointerEvent,
+                       WidgetTouchEvent* aTouchEvent,
+                       mozilla::dom::Touch* aTouch,
+                       bool aIsPrimary)
+{
+  MOZ_ASSERT(aPointerEvent);
+  MOZ_ASSERT(aTouchEvent);
+
+  int16_t button = aTouchEvent->mMessage == eTouchMove ?
+                     WidgetMouseEvent::eNoButton :
+                     WidgetMouseEvent::eLeftButton;
+
+  int16_t buttons = aTouchEvent->mMessage == eTouchEnd ?
+                      WidgetMouseEvent::eNoButtonFlag :
+                      WidgetMouseEvent::eLeftButtonFlag;
+
+  aPointerEvent->mIsPrimary = aIsPrimary;
+  aPointerEvent->pointerId = aTouch->Identifier();
+  aPointerEvent->mRefPoint = aTouch->mRefPoint;
+  aPointerEvent->mModifiers = aTouchEvent->mModifiers;
+  aPointerEvent->mWidth = aTouch->RadiusX(CallerType::System);
+  aPointerEvent->mHeight = aTouch->RadiusY(CallerType::System);
+  aPointerEvent->tiltX = aTouch->tiltX;
+  aPointerEvent->tiltY = aTouch->tiltY;
+  aPointerEvent->mTime = aTouchEvent->mTime;
+  aPointerEvent->mTimeStamp = aTouchEvent->mTimeStamp;
+  aPointerEvent->mFlags = aTouchEvent->mFlags;
+  aPointerEvent->button = button;
+  aPointerEvent->buttons = buttons;
+  aPointerEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
+}
+
+/* static */ void
 PointerEventHandler::DispatchPointerFromMouseOrTouch(
                        PresShell* aShell,
                        nsIFrame* aFrame,
                        WidgetGUIEvent* aEvent,
                        bool aDontRetargetEvents,
                        nsEventStatus* aStatus,
                        nsIContent** aTargetContent)
 {
@@ -413,44 +468,33 @@ PointerEventHandler::DispatchPointerFrom
         mouseEvent->buttons & ~nsContentUtils::GetButtonsFlagForButton(button) ?
         ePointerMove : ePointerDown;
       break;
     default:
       return;
     }
 
     WidgetPointerEvent event(*mouseEvent);
-    event.pointerId = mouseEvent->pointerId;
-    event.inputSource = mouseEvent->inputSource;
-    event.mMessage = pointerMessage;
-    event.button = button;
-    event.buttons = mouseEvent->buttons;
-    event.pressure = event.buttons ?
-                     mouseEvent->pressure ? mouseEvent->pressure : 0.5f :
-                     0.0f;
+    InitPointerEventFromMouse(&event, mouseEvent, pointerMessage);
     event.convertToPointer = mouseEvent->convertToPointer = false;
     PreHandlePointerEventsPreventDefault(&event, aEvent);
     RefPtr<PresShell> shell(aShell);
     shell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
                        aTargetContent);
     PostHandlePointerEventsPreventDefault(&event, aEvent);
   } else if (aEvent->mClass == eTouchEventClass) {
     WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
-    int16_t button = WidgetMouseEvent::eLeftButton;
-    int16_t buttons = WidgetMouseEvent::eLeftButtonFlag;
     // loop over all touches and dispatch pointer events on each touch
     // copy the event
     switch (touchEvent->mMessage) {
     case eTouchMove:
       pointerMessage = ePointerMove;
-      button = WidgetMouseEvent::eNoButton;
       break;
     case eTouchEnd:
       pointerMessage = ePointerUp;
-      buttons = WidgetMouseEvent::eNoButtonFlag;
       break;
     case eTouchStart:
       pointerMessage = ePointerDown;
       break;
     case eTouchCancel:
     case eTouchPointerCancel:
       pointerMessage = ePointerCancel;
       break;
@@ -462,30 +506,18 @@ PointerEventHandler::DispatchPointerFrom
     for (uint32_t i = 0; i < touchEvent->mTouches.Length(); ++i) {
       Touch* touch = touchEvent->mTouches[i];
       if (!TouchManager::ShouldConvertTouchToPointer(touch, touchEvent)) {
         continue;
       }
 
       WidgetPointerEvent event(touchEvent->IsTrusted(), pointerMessage,
                                touchEvent->mWidget);
-      event.mIsPrimary = i == 0;
-      event.pointerId = touch->Identifier();
-      event.mRefPoint = touch->mRefPoint;
-      event.mModifiers = touchEvent->mModifiers;
-      event.mWidth = touch->RadiusX(CallerType::System);
-      event.mHeight = touch->RadiusY(CallerType::System);
-      event.tiltX = touch->tiltX;
-      event.tiltY = touch->tiltY;
-      event.mTime = touchEvent->mTime;
-      event.mTimeStamp = touchEvent->mTimeStamp;
-      event.mFlags = touchEvent->mFlags;
-      event.button = button;
-      event.buttons = buttons;
-      event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
+
+      InitPointerEventFromTouch(&event, touchEvent, touch, i == 0);
       event.convertToPointer = touch->convertToPointer = false;
       PreHandlePointerEventsPreventDefault(&event, aEvent);
       shell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
                          aTargetContent);
       PostHandlePointerEventsPreventDefault(&event, aEvent);
     }
   }
 }
--- a/dom/events/PointerEventHandler.h
+++ b/dom/events/PointerEventHandler.h
@@ -138,16 +138,25 @@ public:
 
   static void DispatchPointerFromMouseOrTouch(PresShell* aShell,
                                               nsIFrame* aFrame,
                                               WidgetGUIEvent* aEvent,
                                               bool aDontRetargetEvents,
                                               nsEventStatus* aStatus,
                                               nsIContent** aTargetContent);
 
+  static void InitPointerEventFromMouse(WidgetPointerEvent* aPointerEvent,
+                                        WidgetMouseEvent* aMouseEvent,
+                                        EventMessage aMessage);
+
+  static void InitPointerEventFromTouch(WidgetPointerEvent* aPointerEvent,
+                                        WidgetTouchEvent* aTouchEvent,
+                                        mozilla::dom::Touch* aTouch,
+                                        bool aIsPrimary);
+
 private:
   // GetPointerType returns pointer type like mouse, pen or touch for pointer
   // event with pointerId. The return value must be one of
   // nsIDOMMouseEvent::MOZ_SOURCE_*
   static uint16_t GetPointerType(uint32_t aPointerId);
 
   // GetPointerPrimaryState returns state of attribute isPrimary for pointer
   // event with pointerId
--- a/dom/html/nsHTMLContentSink.cpp
+++ b/dom/html/nsHTMLContentSink.cpp
@@ -219,167 +219,27 @@ public:
     nsIContent *Add(nsIContent *child);
   };
 
   Node* mStack;
   int32_t mStackSize;
   int32_t mStackPos;
 };
 
-static void
-DoCustomElementCreate(Element** aElement, nsIDocument* aDoc, nsAtom* aLocalName,
-                      CustomElementConstructor* aConstructor, ErrorResult& aRv)
-{
-  RefPtr<Element> element =
-    aConstructor->Construct("Custom Element Create", aRv);
-  if (aRv.Failed()) {
-    return;
-  }
-
-  if (!element || !element->IsHTMLElement()) {
-    aRv.ThrowTypeError<MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE>(NS_LITERAL_STRING("HTMLElement"));
-    return;
-  }
-
-  if (aDoc != element->OwnerDoc() || element->GetParentNode() ||
-      element->HasChildren() || element->GetAttrCount() ||
-      element->NodeInfo()->NameAtom() != aLocalName) {
-    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-    return;
-  }
-
-  element.forget(aElement);
-}
-
 nsresult
 NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                   FromParser aFromParser, const nsAString* aIs,
                   mozilla::dom::CustomElementDefinition* aDefinition)
 {
-  *aResult = nullptr;
-
   RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
 
-  nsAtom *name = nodeInfo->NameAtom();
-  RefPtr<nsAtom> tagAtom = nodeInfo->NameAtom();
-  RefPtr<nsAtom> typeAtom = aIs ? NS_Atomize(*aIs) : tagAtom;
-
   NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML),
-               "Trying to HTML elements that don't have the XHTML namespace");
-
-  int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(name);
-  bool isCustomElementName = (tag == eHTMLTag_userdefined &&
-                              nsContentUtils::IsCustomElementName(name));
-  bool isCustomElement = isCustomElementName || aIs;
-  MOZ_ASSERT_IF(aDefinition, isCustomElement);
-
-  // https://dom.spec.whatwg.org/#concept-create-element
-  // We only handle the "synchronous custom elements flag is set" now.
-  // For the unset case (e.g. cloning a node), see bug 1319342 for that.
-  // Step 4.
-  CustomElementDefinition* definition = aDefinition;
-  if (CustomElementRegistry::IsCustomElementEnabled() && isCustomElement &&
-      !definition) {
-    definition =
-      nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(),
-                                                    nodeInfo->LocalName(),
-                                                    nodeInfo->NamespaceID(),
-                                                    typeAtom);
-  }
-
-  // It might be a problem that parser synchronously calls constructor, so filed
-  // bug 1378079 to figure out what we should do for parser case.
-  if (definition) {
-    /*
-     * Synchronous custom elements flag is determined by 3 places in spec,
-     * 1) create an element for a token, the flag is determined by
-     *    "will execute script" which is not originally created
-     *    for the HTML fragment parsing algorithm.
-     * 2) createElement and createElementNS, the flag is the same as
-     *    NOT_FROM_PARSER.
-     * 3) clone a node, our implementation will not go into this function.
-     * For the unset case which is non-synchronous only applied for
-     * inner/outerHTML.
-     */
-    bool synchronousCustomElements = aFromParser != dom::FROM_PARSER_FRAGMENT ||
-                                     aFromParser == dom::NOT_FROM_PARSER;
-    // Per discussion in https://github.com/w3c/webcomponents/issues/635,
-    // use entry global in those places that are called from JS APIs and use the
-    // node document's global object if it is called from parser.
-    nsIGlobalObject* global;
-    if (aFromParser == dom::NOT_FROM_PARSER) {
-      global = GetEntryGlobal();
-    } else {
-      global = nodeInfo->GetDocument()->GetScopeObject();
-    }
-    if (!global) {
-      // In browser chrome code, one may have access to a document which doesn't
-      // have scope object anymore.
-      return NS_ERROR_FAILURE;
-    }
+               "Trying to create HTML elements that don't have the XHTML namespace");
 
-    AutoEntryScript aes(global, "create custom elements");
-    JSContext* cx = aes.cx();
-    ErrorResult rv;
-
-    // Step 5.
-    if (definition->IsCustomBuiltIn()) {
-      // SetupCustomElement() should be called with an element that don't have
-      // CustomElementData setup, if not we will hit the assertion in
-      // SetCustomElementData().
-      // Built-in element
-      *aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
-      (*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
-      if (synchronousCustomElements) {
-        CustomElementRegistry::Upgrade(*aResult, definition, rv);
-        if (rv.MaybeSetPendingException(cx)) {
-          aes.ReportException();
-        }
-      } else {
-        nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
-      }
-
-      return NS_OK;
-    }
-
-    // Step 6.1.
-    if (synchronousCustomElements) {
-      DoCustomElementCreate(aResult, nodeInfo->GetDocument(),
-                            nodeInfo->NameAtom(),
-                            definition->mConstructor, rv);
-      if (rv.MaybeSetPendingException(cx)) {
-        NS_IF_ADDREF(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget(), aFromParser));
-      }
-      return NS_OK;
-    }
-
-    // Step 6.2.
-    NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
-    (*aResult)->SetCustomElementData(new CustomElementData(definition->mType));
-    nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
-    return NS_OK;
-  }
-
-  // Per the Custom Element specification, unknown tags that are valid custom
-  // element names should be HTMLElement instead of HTMLUnknownElement.
-  if (isCustomElementName) {
-    NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
-  } else {
-    *aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
-  }
-
-  if (!*aResult) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  if (CustomElementRegistry::IsCustomElementEnabled() && isCustomElement) {
-    (*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
-  }
-
-  return NS_OK;
+  return nsContentUtils::NewXULOrHTMLElement(aResult, nodeInfo, aFromParser, aIs, aDefinition);
 }
 
 already_AddRefed<nsGenericHTMLElement>
 CreateHTMLElement(uint32_t aNodeType,
                   already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                   FromParser aFromParser)
 {
   NS_ASSERTION(aNodeType <= NS_HTML_TAG_MAX ||
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -25,21 +25,19 @@ extern mozilla::LazyLogModule gMediaStre
 #define LOG(type, msg) MOZ_LOG(gMediaStreamGraphLog, type, msg)
 
 namespace mozilla {
 
 GraphDriver::GraphDriver(MediaStreamGraphImpl* aGraphImpl)
   : mIterationStart(0),
     mIterationEnd(0),
     mGraphImpl(aGraphImpl),
-    mWaitState(WAITSTATE_RUNNING),
     mCurrentTimeStamp(TimeStamp::Now()),
     mPreviousDriver(nullptr),
-    mNextDriver(nullptr),
-    mScheduled(false)
+    mNextDriver(nullptr)
 { }
 
 void GraphDriver::SetGraphTime(GraphDriver* aPreviousDriver,
                                GraphTime aLastSwitchNextIterationStart,
                                GraphTime aLastSwitchNextIterationEnd)
 {
   GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
   // We set mIterationEnd here, because the first thing a driver do when it
@@ -116,22 +114,16 @@ void GraphDriver::SetNextDriver(GraphDri
 }
 
 void GraphDriver::SetPreviousDriver(GraphDriver* aPreviousDriver)
 {
   GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
   mPreviousDriver = aPreviousDriver;
 }
 
-bool GraphDriver::Scheduled()
-{
-  GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
-  return mScheduled;
-}
-
 ThreadedDriver::ThreadedDriver(MediaStreamGraphImpl* aGraphImpl)
   : GraphDriver(aGraphImpl)
 { }
 
 class MediaStreamGraphShutdownThreadRunnable : public Runnable {
 public:
   explicit MediaStreamGraphShutdownThreadRunnable(
     already_AddRefed<nsIThread> aThread)
@@ -211,18 +203,17 @@ ThreadedDriver::Start()
   LOG(LogLevel::Debug,
       ("Starting thread for a SystemClockDriver  %p", mGraphImpl));
   Unused << NS_WARN_IF(mThread);
   if (!mThread) { // Ensure we haven't already started it
     nsCOMPtr<nsIRunnable> event = new MediaStreamGraphInitThreadRunnable(this);
     // Note: mThread may be null during event->Run() if we pass to NewNamedThread!  See AudioInitTask
     nsresult rv = NS_NewNamedThread("MediaStreamGrph", getter_AddRefs(mThread));
     if (NS_SUCCEEDED(rv)) {
-      rv = mThread->EventTarget()->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
-      mScheduled = NS_SUCCEEDED(rv);
+      mThread->EventTarget()->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
     }
   }
 }
 
 void
 ThreadedDriver::Revive()
 {
   // Note: only called on MainThread, without monitor
@@ -258,16 +249,17 @@ ThreadedDriver::Shutdown()
     mThread = nullptr;
   }
 }
 
 SystemClockDriver::SystemClockDriver(MediaStreamGraphImpl* aGraphImpl)
   : ThreadedDriver(aGraphImpl),
     mInitialTimeStamp(TimeStamp::Now()),
     mLastTimeStamp(TimeStamp::Now()),
+    mWaitState(WAITSTATE_RUNNING),
     mIsFallback(false)
 {}
 
 SystemClockDriver::~SystemClockDriver()
 { }
 
 void
 SystemClockDriver::MarkAsFallback()
@@ -279,18 +271,17 @@ bool
 SystemClockDriver::IsFallback()
 {
   return mIsFallback;
 }
 
 void
 ThreadedDriver::RunThread()
 {
-  bool stillProcessing = true;
-  while (stillProcessing) {
+  while (true) {
     mIterationStart = IterationEnd();
     mIterationEnd += GetIntervalForIteration();
 
     GraphTime stateComputedTime = StateComputedTime();
     if (stateComputedTime < mIterationEnd) {
       LOG(LogLevel::Warning, ("Media graph global underrun detected"));
       mIterationEnd = stateComputedTime;
     }
@@ -319,20 +310,26 @@ ThreadedDriver::RunThread()
     }
     LOG(LogLevel::Verbose,
         ("interval[%ld; %ld] state[%ld; %ld]",
          (long)mIterationStart,
          (long)mIterationEnd,
          (long)stateComputedTime,
          (long)nextStateComputedTime));
 
-    stillProcessing = mGraphImpl->OneIteration(nextStateComputedTime);
+    bool stillProcessing = mGraphImpl->OneIteration(nextStateComputedTime);
 
+    if (!stillProcessing) {
+      // Enter shutdown mode. The stable-state handler will detect this
+      // and complete shutdown if the graph does not get restarted.
+      mGraphImpl->SignalMainThreadCleanup();
+      return;
+    }
     MonitorAutoLock lock(GraphImpl()->GetMonitor());
-    if (NextDriver() && stillProcessing) {
+    if (NextDriver()) {
       LOG(LogLevel::Debug, ("Switching to AudioCallbackDriver"));
       RemoveCallback();
       NextDriver()->SetGraphTime(this, mIterationStart, mIterationEnd);
       mGraphImpl->SetCurrentDriver(NextDriver());
       NextDriver()->Start();
       return;
     }
   }
@@ -535,16 +532,17 @@ AudioCallbackDriver::AudioCallbackDriver
   , mSampleRate(0)
   , mInputChannels(1)
   , mIterationDurationMS(MEDIA_GRAPH_TARGET_PERIOD_MS)
   , mStarted(false)
   , mAudioInput(nullptr)
   , mAddedMixer(false)
   , mInCallback(false)
   , mMicrophoneActive(false)
+  , mShouldFallbackIfError(false)
   , mFromFallback(false)
 {
   LOG(LogLevel::Debug, ("AudioCallbackDriver ctor for graph %p", aGraphImpl));
 #if defined(XP_WIN)
   if (XRE_IsContentProcess()) {
     audio::AudioNotificationReceiver::Register(this);
   }
 #endif
@@ -721,25 +719,16 @@ AudioCallbackDriver::Init()
     LOG(LogLevel::Warning, ("AudioCallbackDriver couldn't start stream."));
     return false;
   }
 
   LOG(LogLevel::Debug, ("AudioCallbackDriver started."));
   return true;
 }
 
-
-void
-AudioCallbackDriver::Destroy()
-{
-  LOG(LogLevel::Debug, ("AudioCallbackDriver destroyed."));
-  mAudioInput = nullptr;
-  mAudioStream.reset();
-}
-
 void
 AudioCallbackDriver::Start()
 {
   if (mPreviousDriver) {
     if (mPreviousDriver->AsAudioCallbackDriver()) {
       LOG(LogLevel::Debug, ("Releasing audio driver off main thread."));
       RefPtr<AsyncCubebTask> releaseEvent =
         new AsyncCubebTask(mPreviousDriver->AsAudioCallbackDriver(),
@@ -755,32 +744,31 @@ AudioCallbackDriver::Start()
     }
   }
 
   LOG(LogLevel::Debug,
       ("Starting new audio driver off main thread, "
        "to ensure it runs after previous shutdown."));
   RefPtr<AsyncCubebTask> initEvent =
     new AsyncCubebTask(AsAudioCallbackDriver(), AsyncCubebOperation::INIT);
-  nsresult rv = initEvent->Dispatch();
-  mScheduled = NS_SUCCEEDED(rv);
+  initEvent->Dispatch();
 }
 
 bool
 AudioCallbackDriver::StartStream()
 {
+  mShouldFallbackIfError = true;
   if (cubeb_stream_start(mAudioStream) != CUBEB_OK) {
     NS_WARNING("Could not start cubeb stream for MSG.");
     return false;
   }
 
   {
     MonitorAutoLock mon(mGraphImpl->GetMonitor());
     mStarted = true;
-    mWaitState = WAITSTATE_RUNNING;
   }
   return true;
 }
 
 void
 AudioCallbackDriver::Stop()
 {
   if (cubeb_stream_stop(mAudioStream) != CUBEB_OK) {
@@ -1004,68 +992,61 @@ AudioCallbackDriver::DataCallback(const 
   // Callback any observers for the AEC speaker data.  Note that one
   // (maybe) of these will be full-duplex, the others will get their input
   // data off separate cubeb callbacks.  Take care with how stuff is
   // removed/added to this list and TSAN issues, but input and output will
   // use separate callback methods.
   mGraphImpl->NotifyOutputData(aOutputBuffer, static_cast<size_t>(aFrames),
                                mSampleRate, mOutputChannels);
 
+  if (!stillProcessing) {
+    // About to hand over control of the graph.  Do not start a new driver if
+    // StateCallback() receives an error for this stream while the main thread
+    // or another driver has control of the graph.
+    mShouldFallbackIfError = false;
+    // Enter shutdown mode. The stable-state handler will detect this
+    // and complete shutdown if the graph does not get restarted.
+    mGraphImpl->SignalMainThreadCleanup();
+    return aFrames - 1;
+  }
+
   bool switching = false;
   {
     MonitorAutoLock mon(mGraphImpl->GetMonitor());
     switching = !!NextDriver();
   }
 
-  if (switching && stillProcessing) {
+  if (switching) {
+    mShouldFallbackIfError = false;
     // If the audio stream has not been started by the previous driver or
     // the graph itself, keep it alive.
     MonitorAutoLock mon(mGraphImpl->GetMonitor());
     if (!IsStarted()) {
       return aFrames;
     }
     LOG(LogLevel::Debug, ("Switching to system driver."));
     RemoveCallback();
     NextDriver()->SetGraphTime(this, mIterationStart, mIterationEnd);
     mGraphImpl->SetCurrentDriver(NextDriver());
     NextDriver()->Start();
     // Returning less than aFrames starts the draining and eventually stops the
     // audio thread. This function will never get called again.
     return aFrames - 1;
   }
 
-  if (!stillProcessing) {
-    LOG(LogLevel::Debug,
-        ("Stopping audio thread for MediaStreamGraph %p", this));
-    return aFrames - 1;
-  }
   return aFrames;
 }
 
 void
 AudioCallbackDriver::StateCallback(cubeb_state aState)
 {
   LOG(LogLevel::Debug, ("AudioCallbackDriver State: %d", aState));
 
-  if (aState == CUBEB_STATE_ERROR) {
-    if (!mAudioStream) {
-      // If we don't have an audio stream here, this means that the stream
-      // initialization has failed. A fallback on a SystemCallDriver will happen at
-      // the callsite of `cubeb_stream_init`.
-      return;
-    }
-
+  if (aState == CUBEB_STATE_ERROR && mShouldFallbackIfError) {
     MonitorAutoLock lock(GraphImpl()->GetMonitor());
-
-    if (NextDriver() && NextDriver()->Scheduled()) {
-      // We are switching to another driver that has already been scheduled
-      // to be initialized and started. There's nothing for us to do here.
-      return;
-    }
-
     // Fall back to a driver using a normal thread. If needed,
     // the graph will try to re-open an audio stream later.
     SystemClockDriver* nextDriver = new SystemClockDriver(GraphImpl());
     SetNextDriver(nextDriver);
     RemoveCallback();
     nextDriver->MarkAsFallback();
     nextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
     // We're not using SwitchAtNextIteration here, because there
--- a/dom/media/GraphDriver.h
+++ b/dom/media/GraphDriver.h
@@ -114,17 +114,16 @@ public:
   explicit GraphDriver(MediaStreamGraphImpl* aGraphImpl);
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GraphDriver);
   /* For real-time graphs, this waits until it's time to process more data. For
    * offline graphs, this is a no-op. */
   virtual void WaitForNextIteration() = 0;
   /* Wakes up the graph if it is waiting. */
   virtual void WakeUp() = 0;
-  virtual void Destroy() {}
   /* Start the graph, init the driver, start the thread. */
   virtual void Start() = 0;
   /* Revive this driver, as more messages just arrived. */
   virtual void Revive() = 0;
   /* Remove Mixer callbacks when switching */
   virtual void RemoveCallback() = 0;
   /* Shutdown GraphDriver (synchronously) */
   virtual void Shutdown() = 0;
@@ -141,19 +140,16 @@ public:
 
   // Those are simply or setting the associated pointer, but assert that the
   // lock is held.
   GraphDriver* NextDriver();
   GraphDriver* PreviousDriver();
   void SetNextDriver(GraphDriver* aNextDriver);
   void SetPreviousDriver(GraphDriver* aPreviousDriver);
 
-  /* Return whether we have been scheduled to start. */
-  bool Scheduled();
-
   /**
    * If we are running a real time graph, get the current time stamp to schedule
    * video frames. This has to be reimplemented by real time drivers.
    */
   virtual TimeStamp GetCurrentTimeStamp() {
     return mCurrentTimeStamp;
   }
 
@@ -213,32 +209,16 @@ protected:
   // Time of the end of this graph iteration. This must be accessed while having
   // the monitor.
   GraphTime mIterationEnd;
   // The MediaStreamGraphImpl that owns this driver. This has a lifetime longer
   // than the driver, and will never be null. Hence, it can be accesed without
   // monitor.
   MediaStreamGraphImpl* mGraphImpl;
 
-  // This enum specifies the wait state of the driver.
-  enum WaitState {
-    // RunThread() is running normally
-    WAITSTATE_RUNNING,
-    // RunThread() is paused waiting for its next iteration, which will
-    // happen soon
-    WAITSTATE_WAITING_FOR_NEXT_ITERATION,
-    // RunThread() is paused indefinitely waiting for something to change
-    WAITSTATE_WAITING_INDEFINITELY,
-    // Something has signaled RunThread() to wake up immediately,
-    // but it hasn't done so yet
-    WAITSTATE_WAKING_UP
-  };
-  // This must be access with the monitor.
-  WaitState mWaitState;
-
   // This is used on the main thread (during initialization), and the graph
   // thread. No monitor needed because we know the graph thread does not run
   // during the initialization.
   TimeStamp mCurrentTimeStamp;
   // This is non-null only when this driver has recently switched from an other
   // driver, and has not cleaned it up yet (for example because the audio stream
   // is currently calling the callback during initialization).
   //
@@ -247,19 +227,16 @@ protected:
   // check whether we're changing driver (in Switching()), from the graph
   // thread.
   // This must be accessed using the {Set,Get}PreviousDriver methods.
   RefPtr<GraphDriver> mPreviousDriver;
   // This is non-null only when this driver is going to switch to an other
   // driver at the end of this iteration.
   // This must be accessed using the {Set,Get}NextDriver methods.
   RefPtr<GraphDriver> mNextDriver;
-  // This is initially false, but set to true as soon the driver has been
-  // scheduled to start through GraphDriver::Start().
-  bool mScheduled;
   virtual ~GraphDriver()
   { }
 };
 
 class MediaStreamGraphInitThreadRunnable;
 
 /**
  * This class is a driver that manages its own thread.
@@ -312,16 +289,33 @@ public:
     return this;
   }
 
 private:
   // Those are only modified (after initialization) on the graph thread. The
   // graph thread does not run during the initialization.
   TimeStamp mInitialTimeStamp;
   TimeStamp mLastTimeStamp;
+
+  // This enum specifies the wait state of the driver.
+  enum WaitState {
+    // RunThread() is running normally
+    WAITSTATE_RUNNING,
+    // RunThread() is paused waiting for its next iteration, which will
+    // happen soon
+    WAITSTATE_WAITING_FOR_NEXT_ITERATION,
+    // RunThread() is paused indefinitely waiting for something to change
+    WAITSTATE_WAITING_INDEFINITELY,
+    // Something has signaled RunThread() to wake up immediately,
+    // but it hasn't done so yet
+    WAITSTATE_WAKING_UP
+  };
+  // This must be access with the monitor.
+  WaitState mWaitState;
+
   // This is true if this SystemClockDriver runs the graph because we could not
   // open an audio stream.
   bool mIsFallback;
 };
 
 /**
  * An OfflineClockDriver runs the graph as fast as possible, without waiting
  * between iteration.
@@ -384,17 +378,16 @@ class AudioCallbackDriver : public Graph
 #if defined(XP_WIN)
                             , public audio::DeviceChangeListener
 #endif
 {
 public:
   explicit AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl);
   virtual ~AudioCallbackDriver();
 
-  void Destroy() override;
   void Start() override;
   void Revive() override;
   void RemoveCallback() override;
   void WaitForNextIteration() override;
   void WakeUp() override;
   void Shutdown() override;
 #if defined(XP_WIN)
   void ResetDefaultDevice() override;
@@ -553,16 +546,24 @@ private:
 
   /* This is atomic and is set by the audio callback thread. It can be read by
    * any thread safely. */
   Atomic<bool> mInCallback;
   /**
    * True if microphone is being used by this process. This is synchronized by
    * the graph's monitor. */
   Atomic<bool> mMicrophoneActive;
+  /* Indication of whether a fallback SystemClockDriver should be started if
+   * StateCallback() receives an error.  No mutex need be held during access.
+   * The transition to true happens before cubeb_stream_start() is called.
+   * After transitioning to false on the last DataCallback(), the stream is
+   * not accessed from another thread until the graph thread either signals
+   * main thread cleanup or dispatches an event to switch to another
+   * driver. */
+  bool mShouldFallbackIfError;
   /* True if this driver was created from a driver created because of a previous
    * AudioCallbackDriver failure. */
   bool mFromFallback;
 };
 
 class AsyncCubebTask : public Runnable
 {
 public:
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -1212,21 +1212,23 @@ MediaStreamGraphImpl::PrepareUpdatesToMa
         stream->GraphTimeToStreamTime(mProcessedTime);
       update->mNextMainThreadFinished = stream->mNotifiedFinished;
     }
     if (!mPendingUpdateRunnables.IsEmpty()) {
       mUpdateRunnables.AppendElements(Move(mPendingUpdateRunnables));
     }
   }
 
-  // Don't send the message to the main thread if it's not going to have
-  // any work to do.
-  if (aFinalUpdate ||
-      !mUpdateRunnables.IsEmpty() ||
-      !mStreamUpdates.IsEmpty()) {
+  // If this is the final update, then a stable state event will soon be
+  // posted just before this thread finishes, and so there is no need to also
+  // post here.
+  if (!aFinalUpdate &&
+      // Don't send the message to the main thread if it's not going to have
+      // any work to do.
+      !(mUpdateRunnables.IsEmpty() && mStreamUpdates.IsEmpty())) {
     EnsureStableStateEventPosted();
   }
 }
 
 GraphTime
 MediaStreamGraphImpl::RoundUpToNextAudioBlock(GraphTime aTime)
 {
   StreamTime ticks = aTime;
@@ -1455,22 +1457,17 @@ MediaStreamGraphImpl::UpdateMainThreadSt
 {
   MOZ_ASSERT(OnGraphThread());
   MonitorAutoLock lock(mMonitor);
   bool finalUpdate = mForceShutDown ||
     (mProcessedTime >= mEndTime && AllFinishedStreamsNotified()) ||
     (IsEmpty() && mBackMessageQueue.IsEmpty());
   PrepareUpdatesToMainThreadState(finalUpdate);
   if (finalUpdate) {
-    // Enter shutdown mode. The stable-state handler will detect this
-    // and complete shutdown. Destroy any streams immediately.
-    LOG(LogLevel::Debug,
-        ("MediaStreamGraph %p waiting for main thread cleanup", this));
-    // We'll shut down this graph object if it does not get restarted.
-    LifecycleStateRef() = LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP;
+    // Enter shutdown mode when this iteration is completed.
     // No need to Destroy streams here. The main-thread owner of each
     // stream is responsible for calling Destroy on them.
     return false;
   }
 
   CurrentDriver()->WaitForNextIteration();
 
   SwapMessageQueues();
@@ -1894,16 +1891,29 @@ MediaStreamGraphImpl::EnsureStableStateE
   if (mPostedRunInStableStateEvent)
     return;
   mPostedRunInStableStateEvent = true;
   nsCOMPtr<nsIRunnable> event = new MediaStreamGraphStableStateRunnable(this, true);
   mAbstractMainThread->Dispatch(event.forget());
 }
 
 void
+MediaStreamGraphImpl::SignalMainThreadCleanup()
+{
+  MOZ_ASSERT(mDriver->OnThread());
+
+  MonitorAutoLock lock(mMonitor);
+  LOG(LogLevel::Debug,
+      ("MediaStreamGraph %p waiting for main thread cleanup", this));
+  LifecycleStateRef() =
+    MediaStreamGraphImpl::LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP;
+  EnsureStableStateEventPosted();
+}
+
+void
 MediaStreamGraphImpl::AppendMessage(UniquePtr<ControlMessage> aMessage)
 {
   MOZ_ASSERT(NS_IsMainThread(), "main thread only");
   MOZ_ASSERT(!aMessage->GetStream() ||
              !aMessage->GetStream()->IsDestroyed(),
              "Stream already destroyed");
 
   if (mDetectedNotRunning &&
--- a/dom/media/MediaStreamGraphImpl.h
+++ b/dom/media/MediaStreamGraphImpl.h
@@ -193,16 +193,24 @@ public:
    */
   bool UpdateMainThreadState();
 
   /**
    * Returns true if this MediaStreamGraph should keep running
    */
   bool OneIteration(GraphTime aStateEnd);
 
+  /**
+   * Called from the driver, when the graph thread is about to stop, to tell
+   * the main thread to attempt to begin cleanup.  The main thread may either
+   * shutdown or revive the graph depending on whether it receives new
+   * messages.
+   */
+  void SignalMainThreadCleanup();
+
   bool Running() const
   {
     return LifecycleStateRef() == LIFECYCLE_RUNNING;
   }
 
   /* This is the end of the current iteration, that is, the current time of the
    * graph. */
   GraphTime IterationEnd() const;
@@ -719,18 +727,19 @@ public:
     // Graph threads have shut down but we're waiting for remaining streams
     // to be destroyed. Only happens during application shutdown and on
     // completed non-realtime graphs, since normally we'd only shut down a
     // realtime graph when it has no streams.
     LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION
   };
 
   /**
-   * Modified on the main and graph thread (in UpdateMainThreadState() when
-   * we're about to shutdown) in mMonitor. mMonitor must be held when accessed.
+   * Modified only in mMonitor.  Transitions to
+   * LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP occur on the graph thread at
+   * the end of an iteration.  All other transitions occur on the main thread.
    */
   LifecycleState mLifecycleState;
   LifecycleState& LifecycleStateRef()
   {
 #if DEBUG
     if (!mDetectedNotRunning) {
       mMonitor.AssertCurrentThreadOwns();
     }
--- a/dom/media/platforms/wmf/WMFUtils.cpp
+++ b/dom/media/platforms/wmf/WMFUtils.cpp
@@ -40,17 +40,17 @@ HNsToFrames(int64_t aHNs, uint32_t aRate
   i *= aRate;
   i /= HNS_PER_S;
   NS_ENSURE_TRUE(i.isValid(), E_FAIL);
   *aOutFrames = i.value();
   return S_OK;
 }
 
 HRESULT
-GetDefaultStride(IMFMediaType *aType, uint32_t aWidth, uint32_t* aOutStride)
+GetDefaultStride(IMFMediaType* aType, uint32_t aWidth, uint32_t* aOutStride)
 {
   // Try to get the default stride from the media type.
   HRESULT hr = aType->GetUINT32(MF_MT_DEFAULT_STRIDE, aOutStride);
   if (SUCCEEDED(hr)) {
     return S_OK;
   }
 
   // Stride attribute not set, calculate it.
@@ -61,16 +61,32 @@ GetDefaultStride(IMFMediaType *aType, ui
 
   hr = wmf::MFGetStrideForBitmapInfoHeader(
     subtype.Data1, aWidth, (LONG*)(aOutStride));
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   return hr;
 }
 
+YUVColorSpace
+GetYUVColorSpace(IMFMediaType* aType)
+{
+  UINT32 yuvColorMatrix;
+  HRESULT hr = aType->GetUINT32(MF_MT_YUV_MATRIX, &yuvColorMatrix);
+  NS_ENSURE_TRUE(SUCCEEDED(hr), YUVColorSpace::BT601);
+
+  switch (yuvColorMatrix) {
+    case MFVideoTransferMatrix_BT709:
+      return YUVColorSpace::BT709;
+    case MFVideoTransferMatrix_BT601:
+    default:
+      return YUVColorSpace::BT601;
+  }
+}
+
 int32_t
 MFOffsetToInt32(const MFOffset& aOffset)
 {
   return int32_t(aOffset.value + (aOffset.fract / 65536.0f));
 }
 
 TimeUnit
 GetSampleDuration(IMFSample* aSample)
--- a/dom/media/platforms/wmf/WMFUtils.h
+++ b/dom/media/platforms/wmf/WMFUtils.h
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 WMFUtils_h
 #define WMFUtils_h
 
+#include "ImageTypes.h"
 #include "TimeUnits.h"
 #include "VideoUtils.h"
 #include "WMF.h"
 #include "mozilla/gfx/Rect.h"
 #include "nsString.h"
 
 // Various utilities shared by WMF backend files.
 
@@ -35,16 +36,18 @@ HNsToUsecs(int64_t hNanoSecs)
   return hNanoSecs / 10;
 }
 
 HRESULT HNsToFrames(int64_t aHNs, uint32_t aRate, int64_t* aOutFrames);
 
 HRESULT
 GetDefaultStride(IMFMediaType* aType, uint32_t aWidth, uint32_t* aOutStride);
 
+YUVColorSpace GetYUVColorSpace(IMFMediaType* aType);
+
 int32_t MFOffsetToInt32(const MFOffset& aOffset);
 
 // Gets the sub-region of the video frame that should be displayed.
 // See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb530115(v=vs.85).aspx
 HRESULT
 GetPictureRegion(IMFMediaType* aMediaType, gfx::IntRect& aOutPictureRegion);
 
 // Returns the duration of a IMFSample in TimeUnit.
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
@@ -167,16 +167,17 @@ WMFVideoMFTManager::WMFVideoMFTManager(
   const VideoInfo& aConfig,
   layers::KnowsCompositor* aKnowsCompositor,
   layers::ImageContainer* aImageContainer,
   float aFramerate,
   bool aDXVAEnabled)
   : mVideoInfo(aConfig)
   , mImageSize(aConfig.mImage)
   , mVideoStride(0)
+  , mYUVColorSpace(YUVColorSpace::BT601)
   , mImageContainer(aImageContainer)
   , mKnowsCompositor(aKnowsCompositor)
   , mDXVAEnabled(aDXVAEnabled)
   , mAMDVP9InUse(false)
   , mFramerate(aFramerate)
   // mVideoStride, mVideoWidth, mVideoHeight, mUseHwAccel are initialized in
   // Init().
 {
@@ -751,16 +752,17 @@ WMFVideoMFTManager::InitInternal()
   if (mDXVA2Manager) {
     hr = mDXVA2Manager->ConfigureForSize(mVideoInfo.ImageRect().width,
                                          mVideoInfo.ImageRect().height);
     NS_ENSURE_TRUE(SUCCEEDED(hr),
                    MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                                RESULT_DETAIL("Fail to configure image size for "
                                              "DXVA2Manager.")));
   } else {
+    mYUVColorSpace = GetYUVColorSpace(outputType);
     GetDefaultStride(outputType, mVideoInfo.ImageRect().width, &mVideoStride);
   }
   LOG("WMFVideoMFTManager frame geometry stride=%u picture=(%d, %d, %d, %d) "
       "display=(%d,%d)",
       mVideoStride,
       mVideoInfo.ImageRect().x,
       mVideoInfo.ImageRect().y,
       mVideoInfo.ImageRect().width,
@@ -1000,16 +1002,19 @@ WMFVideoMFTManager::CreateBasicVideoFram
   // V plane (Cr)
   b.mPlanes[2].mData = data + y_size;
   b.mPlanes[2].mStride = halfStride;
   b.mPlanes[2].mHeight = halfHeight;
   b.mPlanes[2].mWidth = halfWidth;
   b.mPlanes[2].mOffset = 0;
   b.mPlanes[2].mSkip = 0;
 
+  // YuvColorSpace
+  b.mYUVColorSpace = mYUVColorSpace;
+
   TimeUnit pts = GetSampleTime(aSample);
   NS_ENSURE_TRUE(pts.IsValid(), E_FAIL);
   TimeUnit duration = GetSampleDuration(aSample);
   NS_ENSURE_TRUE(duration.IsValid(), E_FAIL);
   gfx::IntRect pictureRegion =
     mVideoInfo.ScaledImageRect(videoWidth, videoHeight);
 
   LayersBackend backend = GetCompositorBackendType(mKnowsCompositor);
@@ -1131,16 +1136,17 @@ WMFVideoMFTManager::Output(int64_t aStre
                                           nullptr);
       NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
       if (!mUseHwAccel) {
         // The stride may have changed, recheck for it.
         RefPtr<IMFMediaType> outputType;
         hr = mDecoder->GetOutputMediaType(outputType);
         NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
+        mYUVColorSpace = GetYUVColorSpace(outputType);
         hr = GetDefaultStride(outputType, mVideoInfo.ImageRect().width,
                               &mVideoStride);
         NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
       }
       // Catch infinite loops, but some decoders perform at least 2 stream
       // changes on consecutive calls, so be permissive.
       // 100 is arbitrarily > 2.
       NS_ENSURE_TRUE(typeChangeCount < 100, MF_E_TRANSFORM_STREAM_CHANGE);
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.h
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.h
@@ -84,16 +84,17 @@ private:
   bool CanUseDXVA(IMFMediaType* aType, float aFramerate);
 
   already_AddRefed<MFTDecoder> LoadAMDVP9Decoder();
 
   // Video frame geometry.
   const VideoInfo mVideoInfo;
   const gfx::IntSize mImageSize;
   uint32_t mVideoStride;
+  YUVColorSpace mYUVColorSpace;
 
   RefPtr<layers::ImageContainer> mImageContainer;
   RefPtr<layers::KnowsCompositor> mKnowsCompositor;
   nsAutoPtr<DXVA2Manager> mDXVA2Manager;
 
   media::TimeUnit mLastDuration;
   media::TimeUnit mLastTime;
   bool mDraining = false;
--- a/dom/tests/mochitest/general/test_resizeby.html
+++ b/dom/tests/mochitest/general/test_resizeby.html
@@ -4,34 +4,30 @@
   <title>Test for Bug 1369627</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
 
 
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
-<body onload="loadedResolve()">
+<body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1369627">Mozilla Bug 1369627</a>
 <p id="display"></p>
 <div id="content">
   <button id="clicky">clicky</button>
 </div>
 <pre id="test">
 </pre>
 
 <script>
-
   /** Test for Bug 1369627 **/
+  add_task(async function resizeby() {
+    await SimpleTest.promiseFocus();
 
-  let loadedResolve;
-  let loaded = new Promise(resolve => { loadedResolve = resolve });
-
-  add_task(async function resizeby() {
-    await loaded;
     let clicky = document.querySelector("#clicky");
 
     let popupPromise = new Promise(resolve => {
       let linkclick = () => {
         clicky.removeEventListener('click', linkclick);
         let popup = window.open("about:blank", "_blank", "width=500,height=500");
         is(popup.innerHeight, 500);
         is(popup.innerWidth, 500);
--- a/dom/tests/mochitest/webcomponents/chrome.ini
+++ b/dom/tests/mochitest/webcomponents/chrome.ini
@@ -5,9 +5,10 @@ support-files =
 [test_custom_element_htmlconstructor_chrome.html]
 skip-if = os == 'android' # bug 1323645
 support-files =
   htmlconstructor_autonomous_tests.js
   htmlconstructor_builtin_tests.js
 [test_custom_element_upgrade_chrome.html]
 support-files =
   test_upgrade_page.html
-  upgrade_tests.js
\ No newline at end of file
+  upgrade_tests.js
+[test_xul_custom_element.xul]
--- a/dom/tests/mochitest/webcomponents/mochitest.ini
+++ b/dom/tests/mochitest/webcomponents/mochitest.ini
@@ -15,16 +15,18 @@ skip-if = os == 'android' # bug 1323645
 support-files =
   htmlconstructor_autonomous_tests.js
   htmlconstructor_builtin_tests.js
 [test_custom_element_in_shadow.html]
 [test_custom_element_register_invalid_callbacks.html]
 [test_custom_element_throw_on_dynamic_markup_insertion.html]
 [test_custom_element_get.html]
 [test_custom_element_when_defined.html]
+[test_custom_element_uncatchable_exception.html]
+skip-if = !debug # TestFunctions only applied in debug builds
 [test_custom_element_upgrade.html]
 support-files =
   test_upgrade_page.html
   upgrade_tests.js
 [test_custom_element_lifecycle.html]
 [test_custom_element_stack.html]
 [test_nested_content_element.html]
 [test_dest_insertion_points.html]
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/webcomponents/test_custom_element_uncatchable_exception.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1407669
+-->
+<head>
+  <title>Test custom elements runtime exception</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1407669">Bug 1407669</a>
+<script type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, function() {
+  window.onerror = function (e) {
+    ok(false, "How did we get here!?");
+  }
+
+  class Foo extends HTMLElement {
+    constructor() {
+      super()
+      TestFunctions.throwUncatchableException();
+    }
+  }
+
+  customElements.define("test-custom-element", Foo);
+  let element = document.createElement("test-custom-element");
+  is(element instanceof HTMLUnknownElement, true, "It should be a HTMLUnknownElement when uncatchable exception throws in constructor");
+  ok(true, "Uncatchable exception should not report");
+  SimpleTest.finish();
+});
+
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/webcomponents/test_xul_custom_element.xul
@@ -0,0 +1,68 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+
+<window title="XUL Custom Elements"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="runTest();">
+  <title>XUL Custom Elements</title>
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <script type="application/javascript">
+  <![CDATA[
+    SimpleTest.waitForExplicitFinish();
+
+    class TestCustomElement extends XULElement {
+      constructor() {
+        super();
+      }
+
+      connectedCallback() {
+        this.textContent = "foo";
+      }
+    }
+
+    customElements.define("test-custom-element", TestCustomElement);
+
+    function runTest() {
+      const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+      let element = document.createElementNS(XUL_NS, "test-custom-element");
+      document.querySelector("#content").appendChild(element);
+      is(element.textContent, "foo", "Should have set the textContent");
+      ok(element instanceof TestCustomElement, "Should be an instance of TestCustomElement");
+
+      let element2 = element.cloneNode(false);
+      is(element2.textContent, "", "Shouldn't have cloned the textContent");
+      document.querySelector("#content").appendChild(element2);
+      is(element2.textContent, "foo", "Should have set the textContent");
+      ok(element2 instanceof TestCustomElement, "Should be an instance of TestCustomElement");
+
+      let element3 = new TestCustomElement();
+      is(element3.localName, "test-custom-element", "Should see the right tag");
+      is(element3.textContent, "", "Shouldn't have been inserted yet");
+      is(element3.namespaceURI, XUL_NS, "Should have set the right namespace");
+      document.querySelector("#content").appendChild(element3);
+      is(element3.textContent, "foo", "Should have set the textContent");
+      ok(element3 instanceof TestCustomElement, "Should be an instance of TestCustomElement");
+
+      let element4 = document.getElementById("element4");
+      is(element4.textContent, "foo",
+         "Parser should have instantiated the custom element.");
+      ok(element4 instanceof TestCustomElement, "Should be an instance of TestCustomElement");
+
+      SimpleTest.finish();
+    }
+  ]]>
+  </script>
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+    <p id="display"></p>
+    <div id="content" style="display: none">
+      <test-custom-element id="element4" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
+    </div>
+    <pre id="test"></pre>
+  </body>
+</window>
--- a/dom/webidl/XULElement.webidl
+++ b/dom/webidl/XULElement.webidl
@@ -3,17 +3,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/.
  */
 
 interface XULControllers;
 interface MozRDFCompositeDataSource;
 interface MozRDFResource;
 
-[Func="IsChromeOrXBL"]
+[HTMLConstructor, Func="IsChromeOrXBL"]
 interface XULElement : Element {
   // Layout properties
   [SetterThrows]
   attribute DOMString align;
   [SetterThrows]
   attribute DOMString dir;
   [SetterThrows]
   attribute DOMString flex;
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -595,17 +595,19 @@ private:
   // run we have not yet done our load so don't know things like our final
   // principal and whatnot.
 
   virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
     aWorkerPrivate->AssertIsOnWorkerThread();
 
-    aWorkerPrivate->EnsureClientSource();
+    if (NS_WARN_IF(!aWorkerPrivate->EnsureClientSource())) {
+      return false;
+    }
 
     ErrorResult rv;
     scriptloader::LoadMainScript(aWorkerPrivate, mScriptURL, WorkerScript, rv);
     rv.WouldReportJSException();
     // Explicitly ignore NS_BINDING_ABORTED on rv.  Or more precisely, still
     // return false and don't SetWorkerScriptExecutedSuccessfully() in that
     // case, but don't throw anything on aCx.  The idea is to not dispatch error
     // events if our load is canceled with that error code.
@@ -667,17 +669,19 @@ private:
 
     WorkerDebuggerGlobalScope* globalScope =
       aWorkerPrivate->CreateDebuggerGlobalScope(aCx);
     if (!globalScope) {
       NS_WARNING("Failed to make global!");
       return false;
     }
 
-    aWorkerPrivate->EnsureClientSource();
+    if (NS_WARN_IF(!aWorkerPrivate->EnsureClientSource())) {
+      return false;
+    }
 
     JS::Rooted<JSObject*> global(aCx, globalScope->GetWrapper());
 
     ErrorResult rv;
     JSAutoCompartment ac(aCx, global);
     scriptloader::LoadMainScript(aWorkerPrivate, mScriptURL,
                                  DebuggerScript, rv);
     rv.WouldReportJSException();
@@ -5290,23 +5294,23 @@ WorkerPrivate::ControlEventTarget()
 }
 
 nsISerialEventTarget*
 WorkerPrivate::HybridEventTarget()
 {
   return mWorkerHybridEventTarget;
 }
 
-void
+bool
 WorkerPrivate::EnsureClientSource()
 {
   AssertIsOnWorkerThread();
 
   if (mClientSource) {
-    return;
+    return true;
   }
 
   ClientType type;
   switch(Type()) {
     case WorkerTypeDedicated:
       type = ClientType::Worker;
       break;
     case WorkerTypeShared:
@@ -5316,19 +5320,25 @@ WorkerPrivate::EnsureClientSource()
       type = ClientType::Serviceworker;
       break;
     default:
       MOZ_CRASH("unknown worker type!");
   }
 
   mClientSource = ClientManager::CreateSource(type, mWorkerHybridEventTarget,
                                               GetPrincipalInfo());
+  if (!mClientSource) {
+    return false;
+  }
+
   if (mFrozen) {
     mClientSource->Freeze();
   }
+
+  return true;
 }
 
 const ClientInfo&
 WorkerPrivate::GetClientInfo() const
 {
   AssertIsOnWorkerThread();
   MOZ_DIAGNOSTIC_ASSERT(mClientSource);
   return mClientSource->Info();
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -1492,17 +1492,17 @@ public:
   // Get an event target that will attempt to dispatch a normal WorkerRunnable,
   // but if that fails will then fall back to a control runnable.
   nsISerialEventTarget*
   HybridEventTarget();
 
   void
   DumpCrashInformation(nsACString& aString);
 
-  void
+  bool
   EnsureClientSource();
 
   const ClientInfo&
   GetClientInfo() const;
 
   void
   ExecutionReady();
 
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -1067,16 +1067,21 @@ nsXBLService::FetchBindingDocument(nsICo
   if (IsChromeOrResourceURI(aDocumentURI))
     aForceSyncLoad = true;
 
   // Create document and contentsink and set them up.
   nsCOMPtr<nsIDocument> doc;
   rv = NS_NewXMLDocument(getter_AddRefs(doc));
   NS_ENSURE_SUCCESS(rv, rv);
 
+  // XBL documents must allow XUL and XBL elements in them but the usual check
+  // only checks if the document is loaded in the system principal which is
+  // sometimes not the case.
+  doc->ForceEnableXULXBL();
+
   // Set the style backend type before loading the XBL document. Assume
   // gecko if there's no bound document.
   doc->SetStyleBackendType(aBoundDocument ? aBoundDocument->GetStyleBackendType()
                                           : StyleBackendType::Gecko);
 
   nsCOMPtr<nsIXMLContentSink> xblSink;
   rv = NS_NewXBLContentSink(getter_AddRefs(xblSink), doc, aDocumentURI, nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/xml/XMLDocument.cpp
+++ b/dom/xml/XMLDocument.cpp
@@ -231,16 +231,22 @@ NS_NewXBLDocument(nsIDOMDocument** aInst
                                   NS_LITERAL_STRING("http://www.mozilla.org/xbl"),
                                   NS_LITERAL_STRING("bindings"), nullptr,
                                   aDocumentURI, aBaseURI, aPrincipal, false,
                                   nullptr, DocumentFlavorLegacyGuess,
                                   aStyleBackend);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIDocument> idoc = do_QueryInterface(*aInstancePtrResult);
+
+  // XBL documents must allow XUL and XBL elements in them but the usual check
+  // only checks if the document is loaded in the system principal which is
+  // sometimes not the case.
+  idoc->ForceEnableXULXBL();
+
   nsDocument* doc = static_cast<nsDocument*>(idoc.get());
   doc->SetLoadedAsInteractiveData(true);
   doc->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);
 
   return NS_OK;
 }
 
 namespace mozilla {
--- a/dom/xul/moz.build
+++ b/dom/xul/moz.build
@@ -15,16 +15,17 @@ if CONFIG['MOZ_XUL']:
     DIRS += ['templates']
 
     XPIDL_SOURCES += [
         'nsIXULOverlayProvider.idl',
     ]
 
     EXPORTS += [
         'nsIXULDocument.h',
+        'nsXULElement.h',
     ]
 
     UNIFIED_SOURCES += [
         'nsXULCommandDispatcher.cpp',
         'nsXULContentSink.cpp',
         'nsXULElement.cpp',
         'nsXULPopupListener.cpp',
         'nsXULPrototypeCache.cpp',
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -181,18 +181,22 @@ nsXULElement::MaybeUpdatePrivateLifetime
 }
 
 /* static */
 already_AddRefed<nsXULElement>
 nsXULElement::Create(nsXULPrototypeElement* aPrototype, mozilla::dom::NodeInfo *aNodeInfo,
                      bool aIsScriptable, bool aIsRoot)
 {
     RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
-    RefPtr<nsXULElement> element = new nsXULElement(ni.forget());
-    if (element) {
+    nsCOMPtr<Element> baseElement;
+    NS_NewXULElement(getter_AddRefs(baseElement), ni.forget(), dom::FROM_PARSER_NETWORK);
+
+    if (baseElement) {
+        nsXULElement* element = FromContent(baseElement);
+
         if (aPrototype->mHasIdAttribute) {
             element->SetHasID();
         }
         if (aPrototype->mHasClassAttribute) {
             element->SetMayHaveClass();
         }
         if (aPrototype->mHasStyleAttribute) {
             element->SetMayHaveStyle();
@@ -211,19 +215,21 @@ nsXULElement::Create(nsXULPrototypeEleme
 
         if (aIsRoot && aPrototype->mNodeInfo->Equals(nsGkAtoms::window)) {
             for (uint32_t i = 0; i < aPrototype->mNumAttributes; ++i) {
                 if (aPrototype->mAttributes[i].mName.Equals(nsGkAtoms::windowtype)) {
                     element->MaybeUpdatePrivateLifetime();
                 }
             }
         }
+
+        return baseElement.forget().downcast<nsXULElement>();
     }
 
-    return element.forget();
+    return nullptr;
 }
 
 nsresult
 nsXULElement::Create(nsXULPrototypeElement* aPrototype,
                      nsIDocument* aDocument,
                      bool aIsScriptable,
                      bool aIsRoot,
                      Element** aResult)
@@ -250,30 +256,32 @@ nsXULElement::Create(nsXULPrototypeEleme
     RefPtr<nsXULElement> element = Create(aPrototype, nodeInfo,
                                             aIsScriptable, aIsRoot);
     element.forget(aResult);
 
     return NS_OK;
 }
 
 nsresult
-NS_NewXULElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
+NS_NewXULElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
+                 FromParser aFromParser)
 {
-    RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
-
-    NS_PRECONDITION(ni, "need nodeinfo for non-proto Create");
-
-    nsIDocument* doc = ni->GetDocument();
+    RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
+
+    NS_PRECONDITION(nodeInfo, "need nodeinfo for non-proto Create");
+
+    NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XUL),
+                 "Trying to create XUL elements that don't have the XUL namespace");
+
+    nsIDocument* doc = nodeInfo->GetDocument();
     if (doc && !doc->AllowXULXBL()) {
         return NS_ERROR_NOT_AVAILABLE;
     }
 
-    NS_ADDREF(*aResult = new nsXULElement(ni.forget()));
-
-    return NS_OK;
+    return nsContentUtils::NewXULOrHTMLElement(aResult, nodeInfo, aFromParser, nullptr, nullptr);
 }
 
 void
 NS_TrustedNewXULElement(nsIContent** aResult,
                         already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
 {
     RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
     NS_PRECONDITION(ni, "need nodeinfo for non-proto Create");
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -35,16 +35,17 @@
 #include "nsFrameLoader.h" // Needed because we return an
                            // already_AddRefed<nsFrameLoader> where bindings
                            // want an already_AddRefed<nsIFrameLoader> and hence
                            // bindings need to know that the former can cast to
                            // the latter.
 #include "mozilla/dom/DOMRect.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/DOMString.h"
+#include "mozilla/dom/FromParser.h"
 
 class nsIDocument;
 class nsXULPrototypeDocument;
 
 class nsIObjectInputStream;
 class nsIObjectOutputStream;
 class nsIOffThreadScriptReceiver;
 class nsXULPrototypeNode;
@@ -794,17 +795,18 @@ protected:
       nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
       return slots ? slots->mControllers.get() : nullptr;
     }
 
     void UnregisterAccessKey(const nsAString& aOldValue);
     bool BoolAttrIsTrue(nsAtom* aName) const;
 
     friend nsresult
-    NS_NewXULElement(mozilla::dom::Element** aResult, mozilla::dom::NodeInfo *aNodeInfo);
+    NS_NewXULElement(mozilla::dom::Element** aResult, mozilla::dom::NodeInfo *aNodeInfo,
+                     mozilla::dom::FromParser aFromParser, const nsAString* aIs);
     friend void
     NS_TrustedNewXULElement(nsIContent** aResult, mozilla::dom::NodeInfo *aNodeInfo);
 
     static already_AddRefed<nsXULElement>
     Create(nsXULPrototypeElement* aPrototype, mozilla::dom::NodeInfo *aNodeInfo,
            bool aIsScriptable, bool aIsRoot);
 
     bool IsReadWriteTextElement() const
--- a/gfx/vr/gfxVROpenVR.cpp
+++ b/gfx/vr/gfxVROpenVR.cpp
@@ -592,16 +592,17 @@ VRControllerOpenVR::VibrateHaptic(::vr::
 void
 VRControllerOpenVR::StopVibrateHaptic()
 {
   mIsVibrateStopped = true;
 }
 
 VRSystemManagerOpenVR::VRSystemManagerOpenVR()
   : mVRSystem(nullptr)
+  , mIsWindowsMR(false)
 {
 }
 
 /*static*/ already_AddRefed<VRSystemManagerOpenVR>
 VRSystemManagerOpenVR::Create()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -693,16 +694,19 @@ VRSystemManagerOpenVR::HandleInput()
 {
   // mVRSystem is available after VRDisplay is created
   // at GetHMDs().
   if (!mVRSystem) {
     return;
   }
 
   RefPtr<impl::VRControllerOpenVR> controller;
+  // Compare with Edge, we have a wrong implementation for the vertical axis value.
+  // In order to not affect the current VR content, we add a workaround for yAxis.
+  const float yAxisInvert = (mIsWindowsMR) ? -1.0f : 1.0f;
   ::vr::VRControllerState_t state;
   ::vr::TrackedDevicePose_t poses[::vr::k_unMaxTrackedDeviceCount];
   mVRSystem->GetDeviceToAbsoluteTrackingPose(::vr::TrackingUniverseSeated, 0.0f,
                                              poses, ::vr::k_unMaxTrackedDeviceCount);
   // Process OpenVR controller state
   for (uint32_t i = 0; i < mOpenVRController.Length(); ++i) {
     uint32_t axisIdx = 0;
     uint32_t buttonIdx = 0;
@@ -732,34 +736,47 @@ VRSystemManagerOpenVR::HandleInput()
       for (uint32_t j = 0; j < ::vr::k_unControllerStateAxisCount; ++j) {
         const uint32_t axisType = mVRSystem->GetInt32TrackedDeviceProperty(
                                    trackedIndex,
                                    static_cast<::vr::TrackedDeviceProperty>(
                                    ::vr::Prop_Axis0Type_Int32 + j));
         switch (axisType) {
           case ::vr::EVRControllerAxisType::k_eControllerAxis_Joystick:
           case ::vr::EVRControllerAxisType::k_eControllerAxis_TrackPad:
+            if (mIsWindowsMR) {
+              // Adjust the input mapping for Windows MR which has
+              // different order.
+              axisIdx = (axisIdx == 0) ? 2 : 0;
+              buttonIdx = (buttonIdx == 0) ? 4 : 0;
+            }
+
             HandleAxisMove(i, axisIdx,
                            state.rAxis[j].x);
             ++axisIdx;
             HandleAxisMove(i, axisIdx,
-                           state.rAxis[j].y);
+                           state.rAxis[j].y * yAxisInvert);
             ++axisIdx;
             HandleButtonPress(i, buttonIdx,
                               ::vr::ButtonMaskFromId(
                                  static_cast<::vr::EVRButtonId>(::vr::k_EButton_Axis0 + j)),
                                  state.ulButtonPressed, state.ulButtonTouched);
             ++buttonIdx;
+
+            if (mIsWindowsMR) {
+              axisIdx = (axisIdx == 4) ? 2 : 4;
+              buttonIdx = (buttonIdx == 5) ? 1 : 2;
+            }
             break;
           case vr::EVRControllerAxisType::k_eControllerAxis_Trigger:
             if (j <= 2) {
               HandleTriggerPress(i, buttonIdx, triggerIdx, state.rAxis[j].x);
               ++buttonIdx;
               ++triggerIdx;
             } else {
+              // For SteamVR Knuckles.
               HandleTriggerPress(i, buttonIdx, triggerIdx, state.rAxis[j].x);
               ++buttonIdx;
               ++triggerIdx;
               HandleTriggerPress(i, buttonIdx, triggerIdx, state.rAxis[j].y);
               ++buttonIdx;
               ++triggerIdx;
             }
             break;
@@ -786,16 +803,21 @@ VRSystemManagerOpenVR::HandleInput()
       }
       if (supportedButtons &
           BTN_MASK_FROM_ID(k_EButton_ApplicationMenu)) {
         HandleButtonPress(i, buttonIdx,
                           BTN_MASK_FROM_ID(k_EButton_ApplicationMenu),
                           state.ulButtonPressed, state.ulButtonTouched);
         ++buttonIdx;
       }
+      if (mIsWindowsMR) {
+        // button 4 in Windows MR has already been assigned
+        // to k_eControllerAxis_TrackPad.
+        ++buttonIdx;
+      }
       if (supportedButtons &
           BTN_MASK_FROM_ID(k_EButton_DPad_Left)) {
         HandleButtonPress(i, buttonIdx,
                           BTN_MASK_FROM_ID(k_EButton_DPad_Left),
                           state.ulButtonPressed, state.ulButtonTouched);
         ++buttonIdx;
       }
       if (supportedButtons &
@@ -1155,27 +1177,42 @@ void
 VRSystemManagerOpenVR::GetControllerDeviceId(::vr::ETrackedDeviceClass aDeviceType,
                                              ::vr::TrackedDeviceIndex_t aDeviceIndex, nsCString& aId)
 {
   switch (aDeviceType) {
     case ::vr::TrackedDeviceClass_Controller:
     {
       ::vr::ETrackedPropertyError err;
       uint32_t requiredBufferLen;
+      bool founded = false;
       char charBuf[128];
       requiredBufferLen = mVRSystem->GetStringTrackedDeviceProperty(aDeviceIndex,
                           ::vr::Prop_RenderModelName_String, charBuf, 128, &err);
       if (requiredBufferLen > 128) {
         MOZ_CRASH("Larger than the buffer size.");
       }
       MOZ_ASSERT(requiredBufferLen && err == ::vr::TrackedProp_Success);
       nsCString deviceId(charBuf);
       if (deviceId.Find("knuckles") != kNotFound) {
         aId.AssignLiteral("OpenVR Knuckles");
-      } else {
+        founded = true;
+      }
+      requiredBufferLen = mVRSystem->GetStringTrackedDeviceProperty(aDeviceIndex,
+        ::vr::Prop_SerialNumber_String, charBuf, 128, &err);
+      if (requiredBufferLen > 128) {
+        MOZ_CRASH("Larger than the buffer size.");
+      }
+      MOZ_ASSERT(requiredBufferLen && err == ::vr::TrackedProp_Success);
+      deviceId.Assign(charBuf);
+      if (deviceId.Find("MRSOURCE") != kNotFound) {
+        aId.AssignLiteral("Spatial Controller (Spatial Interaction Source) ");
+        mIsWindowsMR = true;
+        founded = true;
+      }
+      if (!founded) {
         aId.AssignLiteral("OpenVR Gamepad");
       }
       break;
     }
     case ::vr::TrackedDeviceClass_GenericTracker:
     {
       aId.AssignLiteral("OpenVR Tracker");
       break;
--- a/gfx/vr/gfxVROpenVR.h
+++ b/gfx/vr/gfxVROpenVR.h
@@ -164,15 +164,16 @@ private:
   void GetControllerDeviceId(::vr::ETrackedDeviceClass aDeviceType,
                              ::vr::TrackedDeviceIndex_t aDeviceIndex,
                              nsCString& aId);
 
   // there can only be one
   RefPtr<impl::VRDisplayOpenVR> mOpenVRHMD;
   nsTArray<RefPtr<impl::VRControllerOpenVR>> mOpenVRController;
   ::vr::IVRSystem *mVRSystem;
+  bool mIsWindowsMR;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 
 #endif /* GFX_VR_OPENVR_H */
--- a/js/rust/build.rs
+++ b/js/rust/build.rs
@@ -158,16 +158,17 @@ const WHITELIST_TYPES: &'static [&'stati
     "js::Class",
     "JS::CompartmentOptions",
     "JS::ContextOptions",
     "js::DOMCallbacks",
     "js::DOMProxyShadowsResult",
     "js::ESClass",
     "JS::ForOfIterator",
     "JS::Handle",
+    "JS::HandleFunction",
     "JS::HandleId",
     "JS::HandleObject",
     "JS::HandleString",
     "JS::HandleValue",
     "JS::HandleValueArray",
     "JS::IsAcceptableThis",
     "JSAutoCompartment",
     "JSAutoStructuredCloneBuffer",
@@ -221,16 +222,17 @@ const WHITELIST_TYPES: &'static [&'stati
     "JS::RootedObject",
     "JS::RootingContext",
     "JS::RootKind",
     "js::Scalar::Type",
     "JS::ServoSizes",
     "js::shadow::Object",
     "js::shadow::ObjectGroup",
     "JS::SourceBufferHolder",
+    "js::StackFormat",
     "JSStructuredCloneCallbacks",
     "JS::Symbol",
     "JS::SymbolCode",
     "JS::TraceKind",
     "JS::TransferableOwnership",
     "JS::Value",
     "JS::WarningReporter",
     "JS::shadow::Zone",
@@ -249,24 +251,27 @@ const WHITELIST_VARS: &'static [&'static
     "JS::NullHandleValue",
     "JS::TrueHandleValue",
     "JS::UndefinedHandleValue",
 ];
 
 /// Functions we want to generate bindings to.
 const WHITELIST_FUNCTIONS: &'static [&'static str] = &[
     "INTERNED_STRING_TO_JSID",
+    "ExceptionStackOrNull",
     "JS_AddExtraGCRootsTracer",
     "JS_AddInterruptCallback",
     "JS::AddPromiseReactions",
     "js::AddRawValueRoot",
     "JS_AlreadyHasOwnPropertyById",
     "JS_AtomizeAndPinString",
     "js::AssertSameCompartment",
+    "JS::BuildStackString",
     "JS::Call",
+    "JS_CallFunctionName",
     "JS_CallFunctionValue",
     "JS::CallOriginalPromiseThen",
     "JS::CallOriginalPromiseResolve",
     "JS::CallOriginalPromiseReject",
     "JS::CompileFunction",
     "JS::Construct",
     "JS::ContextOptionsRef",
     "JS_CopyPropertiesFrom",
@@ -283,16 +288,17 @@ const WHITELIST_FUNCTIONS: &'static [&'s
     "js::GetFunctionNativeReserved",
     "JS_GetFunctionPrototype",
     "js::GetGlobalForObjectCrossCompartment",
     "JS_GetIteratorPrototype",
     "js::GetObjectProto",
     "JS_GetObjectPrototype",
     "JS_GetObjectRuntime",
     "JS_GetOwnPropertyDescriptorById",
+    "JS::GetPromiseResult",
     "JS::GetPromiseState",
     "JS_GetPropertyDescriptorById",
     "js::GetPropertyKeys",
     "JS_GetPrototype",
     "JS_GetRuntime",
     "js::GetStaticPrototype",
     "JS_HasOwnPropertyById",
     "JS_HasProperty",
@@ -317,16 +323,17 @@ const WHITELIST_FUNCTIONS: &'static [&'s
     "JS::DisableIncrementalGC",
     "js::Dump.*",
     "JS_EncodeStringToUTF8",
     "JS_EndRequest",
     "JS_EnterCompartment",
     "JS_EnumerateStandardClasses",
     "JS_ErrorFromException",
     "JS_FireOnNewGlobalObject",
+    "JS_free",
     "JS_GC",
     "JS_GetArrayBufferData",
     "JS_GetArrayBufferViewType",
     "JS_GetFloat32ArrayData",
     "JS_GetFloat64ArrayData",
     "JS_GetFunctionObject",
     "JS_GetGCParameter",
     "JS_GetInt16ArrayData",
@@ -381,21 +388,23 @@ const WHITELIST_FUNCTIONS: &'static [&'s
     "JS_NewUint8Array",
     "JS_NewUint8ClampedArray",
     "js::ObjectClassName",
     "JS_ObjectIsDate",
     "JS_ParseJSON",
     "JS_ReadBytes",
     "JS_ReadStructuredClone",
     "JS_ReadUint32Pair",
+    "JS_RemoveExtraGCRootsTracer",
     "js::RemoveRawValueRoot",
     "JS_ReportErrorASCII",
     "JS_ReportErrorNumberUTF8",
     "JS_RequestInterruptCallback",
     "JS_ResolveStandardClass",
+    "js::RunJobs",
     "JS_SameValue",
     "js::SetDOMCallbacks",
     "js::SetDOMProxyInformation",
     "JS::SetEnqueuePromiseJobCallback",
     "js::SetFunctionNativeReserved",
     "JS_SetGCCallback",
     "JS::SetGCSliceCallback",
     "JS_SetGCParameter",
@@ -403,24 +412,26 @@ const WHITELIST_FUNCTIONS: &'static [&'s
     "JS::SetGetIncumbentGlobalCallback",
     "JS_SetGlobalJitCompilerOption",
     "JS_SetImmutablePrototype",
     "JS_SetNativeStackQuota",
     "JS_SetOffthreadIonCompilationEnabled",
     "JS_SetParallelParsingEnabled",
     "JS_SetPendingException",
     "js::SetPreserveWrapperCallback",
+    "JS::SetPromiseRejectionTrackerCallback",
     "JS_SetPrototype",
     "js::SetWindowProxy",
     "js::SetWindowProxyClass",
     "JS_SetProperty",
     "JS_SetReservedSlot",
     "JS_SetWrapObjectCallbacks",
     "JS_ShutDown",
     "JS_SplicePrototype",
+    "js::StopDrainingJobQueue",
     "JS_StrictPropertyStub",
     "JS_StringEqualsAscii",
     "JS_StringHasLatin1Chars",
     "JS_WrapObject",
     "JS_WrapValue",
     "JS_WriteBytes",
     "JS_WriteStructuredClone",
     "JS_WriteUint32Pair",
@@ -444,16 +455,18 @@ const WHITELIST_FUNCTIONS: &'static [&'s
     "js::UnwrapFloat64Array",
     "js::UnwrapInt16Array",
     "js::UnwrapInt32Array",
     "js::UnwrapInt8Array",
     "js::UnwrapUint16Array",
     "js::UnwrapUint32Array",
     "js::UnwrapUint8Array",
     "js::UnwrapUint8ClampedArray",
+    "js::UseInternalJobQueues",
+    "JS_ValueToFunction",
 ];
 
 /// Types that should be treated as an opaque blob of bytes whenever they show
 /// up within a whitelisted type.
 ///
 /// These are types which are too tricky for bindgen to handle, and/or use C++
 /// features that don't have an equivalent in rust, such as partial template
 /// specialization.
--- a/js/rust/src/conversions.rs
+++ b/js/rust/src/conversions.rs
@@ -97,16 +97,27 @@ pub trait ToJSValConvertible {
 pub enum ConversionResult<T> {
     /// Everything went fine.
     Success(T),
     /// Conversion failed, without a pending exception.
     Failure(Cow<'static, str>),
 }
 
 impl<T> ConversionResult<T> {
+    /// Map a function over the `Success` value.
+    pub fn map<F, U>(self, mut f: F) -> ConversionResult<U>
+    where
+        F: FnMut(T) -> U
+    {
+        match self {
+            ConversionResult::Success(t) => ConversionResult::Success(f(t)),
+            ConversionResult::Failure(e) => ConversionResult::Failure(e),
+        }
+    }
+
     /// Returns Some(value) if it is `ConversionResult::Success`.
     pub fn get_success_value(&self) -> Option<&T> {
         match *self {
             ConversionResult::Success(ref v) => Some(v),
             _ => None,
         }
     }
 }
@@ -132,16 +143,63 @@ pub enum ConversionBehavior {
     /// Wrap into the integer's range.
     Default,
     /// Throw an exception.
     EnforceRange,
     /// Clamp into the integer's range.
     Clamp,
 }
 
+/// Use `T` with `ConversionBehavior::Default` but without requiring any
+/// `Config` associated type.
+pub struct Default<T>(pub T);
+
+impl<T> FromJSValConvertible for Default<T>
+where
+    T: FromJSValConvertible<Config = ConversionBehavior>
+{
+    type Config = ();
+    unsafe fn from_jsval(cx: *mut JSContext, val: JS::HandleValue, _: ())
+                         -> Result<ConversionResult<Self>, ()> {
+        T::from_jsval(cx, val, ConversionBehavior::Default).map(|conv| conv.map(Default))
+    }
+}
+
+/// Use `T` with `ConversionBehavior::EnforceRange` but without requiring any
+/// `Config` associated type.
+pub struct EnforceRange<T>(pub T);
+
+impl<T> FromJSValConvertible for EnforceRange<T>
+    where
+    T: FromJSValConvertible<Config = ConversionBehavior>
+{
+    type Config = ();
+    unsafe fn from_jsval(cx: *mut JSContext, val: JS::HandleValue, _: ())
+                         -> Result<ConversionResult<Self>, ()> {
+        T::from_jsval(cx, val, ConversionBehavior::EnforceRange)
+            .map(|conv| conv.map(EnforceRange))
+    }
+}
+
+/// Use `T` with `ConversionBehavior::Clamp` but without requiring any `Config`
+/// associated type.
+pub struct Clamp<T>(pub T);
+
+impl<T> FromJSValConvertible for Clamp<T>
+    where
+    T: FromJSValConvertible<Config = ConversionBehavior>
+{
+    type Config = ();
+    unsafe fn from_jsval(cx: *mut JSContext, val: JS::HandleValue, _: ())
+                         -> Result<ConversionResult<Self>, ()> {
+        T::from_jsval(cx, val, ConversionBehavior::Clamp)
+            .map(|conv| conv.map(Clamp))
+    }
+}
+
 /// Try to cast the number to a smaller type, but
 /// if it doesn't fit, it will return an error.
 unsafe fn enforce_range<D>(cx: *mut JSContext, d: f64) -> Result<ConversionResult<D>, ()>
     where D: Bounded + As<f64>,
           f64: As<D>
 {
     if d.is_infinite() {
         throw_type_error(cx, "value out of range in an EnforceRange argument");
@@ -672,8 +730,60 @@ impl ToJSValConvertible for NonZero<*mut
 // https://heycam.github.io/webidl/#es-object
 impl ToJSValConvertible for Heap<*mut JSObject> {
     #[inline]
     unsafe fn to_jsval(&self, cx: *mut JSContext, rval: JS::MutableHandleValue) {
         rval.set(ObjectOrNullValue(self.get()));
         maybe_wrap_object_or_null_value(cx, rval);
     }
 }
+
+// JSFunction
+
+impl ToJSValConvertible for *mut JSFunction {
+    #[inline]
+    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: JS::MutableHandleValue) {
+        rval.set(ObjectOrNullValue(*self as *mut JSObject));
+        maybe_wrap_object_or_null_value(cx, rval);
+    }
+}
+
+#[cfg(feature = "nonzero")]
+impl ToJSValConvertible for NonZero<*mut JSFunction> {
+    #[inline]
+    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: JS::MutableHandleValue) {
+        use rust::maybe_wrap_object_value;
+        rval.set(ObjectValue(self.get() as *mut JSObject));
+        maybe_wrap_object_value(cx, rval);
+    }
+}
+
+impl ToJSValConvertible for Heap<*mut JSFunction> {
+    #[inline]
+    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: JS::MutableHandleValue) {
+        rval.set(ObjectOrNullValue(self.get() as *mut JSObject));
+        maybe_wrap_object_or_null_value(cx, rval);
+    }
+}
+
+impl ToJSValConvertible for JS::Handle<*mut JSFunction> {
+    #[inline]
+    unsafe fn to_jsval(&self, cx: *mut JSContext, rval: JS::MutableHandleValue) {
+        rval.set(ObjectOrNullValue(self.get() as *mut JSObject));
+        maybe_wrap_object_or_null_value(cx, rval);
+    }
+}
+
+impl FromJSValConvertible for *mut JSFunction {
+    type Config = ();
+
+    unsafe fn from_jsval(cx: *mut JSContext,
+                         val: JS::HandleValue,
+                         _: ())
+                         -> Result<ConversionResult<Self>, ()> {
+        let func = JS_ValueToFunction(cx, val);
+        if func.is_null() {
+            Ok(ConversionResult::Failure("value is not a function".into()))
+        } else {
+            Ok(ConversionResult::Success(func))
+        }
+    }
+}
--- a/js/rust/src/rust.rs
+++ b/js/rust/src/rust.rs
@@ -79,17 +79,21 @@ impl Runtime {
         let cx = CONTEXT.with(|context| {
             context.get()
         });
         assert!(!cx.is_null());
         cx
     }
 
     /// Creates a new `JSContext`.
-    pub fn new() -> Result<Runtime, ()> {
+    ///
+    /// * `use_internal_job_queue`: If `true`, then SpiderMonkey's internal
+    /// micro-task job queue is used. If `false`, then it is up to you to
+    /// implement micro-tasks yourself.
+    pub fn new(use_internal_job_queue: bool) -> Result<Runtime, ()> {
         if SHUT_DOWN.load(Ordering::SeqCst) {
             return Err(());
         }
 
         OUTSTANDING_RUNTIMES.fetch_add(1, Ordering::SeqCst);
 
         unsafe {
             #[derive(Debug)]
@@ -172,16 +176,20 @@ impl Runtime {
             (*opts).set_ion_(true);
             (*opts).set_nativeRegExp_(true);
 
             CONTEXT.with(|context| {
                 assert!(context.get().is_null());
                 context.set(js_context);
             });
 
+            if use_internal_job_queue {
+                assert!(js::UseInternalJobQueues(js_context, false));
+            }
+
             JS::InitSelfHostedCode(js_context);
 
             JS::SetWarningReporter(js_context, Some(report_warning));
 
             JS_BeginRequest(js_context);
 
             Ok(Runtime {
                 cx: js_context,
@@ -1093,8 +1101,131 @@ pub unsafe fn maybe_wrap_object_or_null_
 #[inline]
 pub unsafe fn maybe_wrap_value(cx: *mut JSContext, rval: JS::MutableHandleValue) {
     if rval.is_string() {
         assert!(JS_WrapValue(cx, rval));
     } else if rval.is_object() {
         maybe_wrap_object_value(cx, rval);
     }
 }
+
+/// Equivalents of the JS_FN* macros.
+impl JSFunctionSpec {
+    pub fn js_fs(name: *const ::std::os::raw::c_char,
+                 func: JSNative,
+                 nargs: u16,
+                 flags: u16) -> JSFunctionSpec {
+        JSFunctionSpec {
+            name: name,
+            call: JSNativeWrapper {
+                op: func,
+                info: ptr::null(),
+            },
+            nargs: nargs,
+            flags: flags,
+            selfHostedName: 0 as *const _,
+        }
+    }
+
+    pub fn js_fn(name: *const ::std::os::raw::c_char,
+                 func: JSNative,
+                 nargs: u16,
+                 flags: u16) -> JSFunctionSpec {
+        JSFunctionSpec {
+            name: name,
+            call: JSNativeWrapper {
+                op: func,
+                info: ptr::null(),
+            },
+            nargs: nargs,
+            flags: flags,
+            selfHostedName: 0 as *const _,
+        }
+    }
+
+    pub const NULL: JSFunctionSpec = JSFunctionSpec {
+        name: 0 as *const _,
+        call: JSNativeWrapper {
+            op: None,
+            info: 0 as *const _,
+        },
+        nargs: 0,
+        flags: 0,
+        selfHostedName: 0 as *const _,
+    };
+}
+
+/// Equivalents of the JS_PS* macros.
+impl JSPropertySpec {
+    pub fn getter(name: *const ::std::os::raw::c_char, flags: u8, func: JSNative)
+                        -> JSPropertySpec {
+        debug_assert_eq!(flags & !(JSPROP_ENUMERATE | JSPROP_PERMANENT), 0);
+        JSPropertySpec {
+            name: name,
+            flags: flags,
+            __bindgen_anon_1: JSPropertySpec__bindgen_ty_1 {
+                accessors: JSPropertySpec__bindgen_ty_1__bindgen_ty_1 {
+                    getter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1 {
+                        native: JSNativeWrapper {
+                            op: func,
+                            info: ptr::null(),
+                        },
+                    },
+                    setter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2 {
+                        native: JSNativeWrapper {
+                            op: None,
+                            info: ptr::null(),
+                        },
+                    }
+                }
+            }
+        }
+    }
+
+    pub fn getter_setter(name: *const ::std::os::raw::c_char,
+                         flags: u8,
+                         g_f: JSNative,
+                         s_f: JSNative)
+                         -> JSPropertySpec {
+        debug_assert_eq!(flags & !(JSPROP_ENUMERATE | JSPROP_PERMANENT), 0);
+        JSPropertySpec {
+            name: name,
+            flags: flags,
+            __bindgen_anon_1: JSPropertySpec__bindgen_ty_1 {
+                accessors: JSPropertySpec__bindgen_ty_1__bindgen_ty_1 {
+                    getter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1 {
+                        native: JSNativeWrapper {
+                            op: g_f,
+                            info: ptr::null(),
+                        },
+                    },
+                    setter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2 {
+                        native: JSNativeWrapper {
+                            op: s_f,
+                            info: ptr::null(),
+                        },
+                    }
+                }
+            }
+        }
+    }
+
+    pub const NULL: JSPropertySpec = JSPropertySpec {
+        name: 0 as *const _,
+        flags: 0,
+        __bindgen_anon_1: JSPropertySpec__bindgen_ty_1{
+            accessors: JSPropertySpec__bindgen_ty_1__bindgen_ty_1 {
+                getter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1 {
+                    native: JSNativeWrapper {
+                        op: None,
+                        info: 0 as *const _,
+                    },
+                },
+                setter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2 {
+                    native: JSNativeWrapper {
+                        op: None,
+                        info: 0 as *const _,
+                    },
+                }
+            }
+        }
+    };
+}
--- a/js/rust/tests/callback.rs
+++ b/js/rust/tests/callback.rs
@@ -20,17 +20,17 @@ use js::jsval::UndefinedValue;
 use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
 
 use std::ffi::CStr;
 use std::ptr;
 use std::str;
 
 #[test]
 fn callback() {
-    let runtime = Runtime::new().unwrap();
+    let runtime = Runtime::new(false).unwrap();
     let context = runtime.cx();
     let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
     let c_option = CompartmentOptions::default();
 
     unsafe {
         let global = JS_NewGlobalObject(context, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(), h_option, &c_option);
         rooted!(in(context) let global_root = global);
         let global = global_root.handle();
--- a/js/rust/tests/enumerate.rs
+++ b/js/rust/tests/enumerate.rs
@@ -16,17 +16,17 @@ use js::jsapi::root::JS::OnNewGlobalHook
 use js::jsval::UndefinedValue;
 use js::rust::IdVector;
 use js::rust::Runtime;
 use js::rust::SIMPLE_GLOBAL_CLASS;
 use std::ptr;
 
 #[test]
 fn enumerate() {
-    let rt = Runtime::new().unwrap();
+    let rt = Runtime::new(false).unwrap();
     let cx = rt.cx();
 
     unsafe {
         rooted!(in(cx) let global =
             JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
                                OnNewGlobalHookOption::FireOnNewGlobalHook,
                                &CompartmentOptions::default())
         );
--- a/js/rust/tests/evaluate.rs
+++ b/js/rust/tests/evaluate.rs
@@ -10,17 +10,17 @@ use js::jsapi::root::JS_NewGlobalObject;
 use js::jsapi::root::JS::OnNewGlobalHookOption;
 use js::jsval::UndefinedValue;
 use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
 
 use std::ptr;
 
 #[test]
 fn evaluate() {
-    let rt = Runtime::new().unwrap();
+    let rt = Runtime::new(false).unwrap();
     let cx = rt.cx();
 
     unsafe {
 
         rooted!(in(cx) let global =
             JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
                                OnNewGlobalHookOption::FireOnNewGlobalHook,
                                &CompartmentOptions::default())
--- a/js/rust/tests/panic.rs
+++ b/js/rust/tests/panic.rs
@@ -10,17 +10,17 @@ use js::jsval::UndefinedValue;
 use js::panic::wrap_panic;
 use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
 use std::ptr;
 use std::str;
 
 #[test]
 #[should_panic]
 fn panic() {
-    let runtime = Runtime::new().unwrap();
+    let runtime = Runtime::new(false).unwrap();
     let context = runtime.cx();
     let h_option = JS::OnNewGlobalHookOption::FireOnNewGlobalHook;
     let c_option = JS::CompartmentOptions::default();
 
     unsafe {
         let global = JS_NewGlobalObject(context, &SIMPLE_GLOBAL_CLASS,
                                         ptr::null_mut(), h_option, &c_option);
         rooted!(in(context) let global_root = global);
--- a/js/rust/tests/rooting.rs
+++ b/js/rust/tests/rooting.rs
@@ -12,17 +12,17 @@ extern crate libc;
 
 use js::jsapi::*;
 use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS, define_methods};
 use std::ptr;
 
 #[test]
 fn rooting() {
     unsafe {
-        let runtime = Runtime::new().unwrap();
+        let runtime = Runtime::new(false).unwrap();
         JS_SetGCZeal(runtime.cx(), 2, 1);
 
         let cx = runtime.cx();
         let h_option = JS::OnNewGlobalHookOption::FireOnNewGlobalHook;
         let c_option = JS::CompartmentOptions::default();
 
         rooted!(in(cx) let global = JS_NewGlobalObject(cx,
                                                        &SIMPLE_GLOBAL_CLASS,
--- a/js/rust/tests/runtime.rs
+++ b/js/rust/tests/runtime.rs
@@ -8,32 +8,32 @@ extern crate libc;
 
 use js::jsapi::*;
 use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
 use std::ptr;
 
 #[test]
 fn runtime() {
     unsafe {
-        let runtime = Runtime::new().unwrap();
+        let runtime = Runtime::new(false).unwrap();
 
         let cx = runtime.cx();
         let h_option = JS::OnNewGlobalHookOption::FireOnNewGlobalHook;
         let c_option = JS::CompartmentOptions::default();
 
         rooted!(in(cx) let global = JS_NewGlobalObject(cx,
                                                        &SIMPLE_GLOBAL_CLASS,
                                                        ptr::null_mut(),
                                                        h_option,
                                                        &c_option));
         let _ac = js::ac::AutoCompartment::with_obj(cx, global.get());
         rooted!(in(cx) let _object = JS_NewObject(cx, &CLASS as *const _));
     }
 
-    assert!(Runtime::new().is_err());
+    assert!(Runtime::new(false).is_err());
 }
 
 unsafe extern fn finalize(_fop: *mut JSFreeOp, _object: *mut JSObject) {
     assert!(!Runtime::get().is_null());
 }
 
 static CLASS_OPS: JSClassOps = JSClassOps {
     addProperty: None,
--- a/js/rust/tests/stack_limit.rs
+++ b/js/rust/tests/stack_limit.rs
@@ -10,17 +10,17 @@ use js::jsapi::root::JS_NewGlobalObject;
 use js::jsapi::root::JS::OnNewGlobalHookOption;
 use js::jsval::UndefinedValue;
 use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
 
 use std::ptr;
 
 #[test]
 fn stack_limit() {
-    let rt = Runtime::new().unwrap();
+    let rt = Runtime::new(false).unwrap();
     let cx = rt.cx();
 
     unsafe {
         let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
         let c_option = CompartmentOptions::default();
         let global = JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS,
                                         ptr::null_mut(), h_option, &c_option);
         rooted!(in(cx) let global_root = global);
--- a/js/rust/tests/typedarray.rs
+++ b/js/rust/tests/typedarray.rs
@@ -9,17 +9,17 @@ use js::jsapi::*;
 use js::jsval::UndefinedValue;
 use js::rust::Runtime as Runtime_;
 use js::rust::SIMPLE_GLOBAL_CLASS;
 use js::typedarray::{CreateWith, Uint32Array};
 use std::ptr;
 
 #[test]
 fn typedarray() {
-    let rt = Runtime_::new().unwrap();
+    let rt = Runtime_::new(false).unwrap();
     let cx = rt.cx();
 
     unsafe {
         rooted!(in(cx) let global =
             JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
                                JS::OnNewGlobalHookOption::FireOnNewGlobalHook,
                                &JS::CompartmentOptions::default())
         );
@@ -67,17 +67,17 @@ fn typedarray() {
         typedarray!(in(cx) let view: ArrayBufferView = rval.get());
         assert_eq!(view.unwrap().get_array_type(), js::jsapi::js::Scalar::Type::Uint32);
     }
 }
 
 #[test]
 #[should_panic]
 fn typedarray_update_panic() {
-    let rt = Runtime_::new().unwrap();
+    let rt = Runtime_::new(false).unwrap();
     let cx = rt.cx();
 
     unsafe {
         rooted!(in(cx) let global =
             JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
                                JS::OnNewGlobalHookOption::FireOnNewGlobalHook,
                                &JS::CompartmentOptions::default())
         );
--- a/js/rust/tests/vec_conversion.rs
+++ b/js/rust/tests/vec_conversion.rs
@@ -25,17 +25,17 @@ fn assert_is_array(cx: *mut js::jsapi::r
     assert!(unsafe {
         js::jsapi::root::JS_IsArrayObject(cx, val, &mut is_array as *mut _)
     });
     assert!(is_array);
 }
 
 #[test]
 fn vec_conversion() {
-    let rt = Runtime::new().unwrap();
+    let rt = Runtime::new(false).unwrap();
     let cx = rt.cx();
 
     let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
     let c_option = CompartmentOptions::default();
 
     unsafe {
         let global = JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS,
                                         ptr::null_mut(), h_option, &c_option);
--- a/js/src/builtin/Date.js
+++ b/js/src/builtin/Date.js
@@ -47,26 +47,23 @@ var dateTimeFormatCache = new Record();
  */
 function GetCachedFormat(format, required, defaults) {
     assert(format === "dateTimeFormat" ||
            format === "dateFormat" ||
            format === "timeFormat",
            "unexpected format key: please update the comment by " +
            "dateTimeFormatCache");
 
-    var runtimeDefaultLocale = RuntimeDefaultLocale();
-    var icuDefaultTimeZone = intl_defaultTimeZone();
-
     var formatters;
-    if (dateTimeFormatCache.runtimeDefaultLocale !== runtimeDefaultLocale ||
-        dateTimeFormatCache.icuDefaultTimeZone !== icuDefaultTimeZone)
+    if (!IsRuntimeDefaultLocale(dateTimeFormatCache.runtimeDefaultLocale) ||
+        !intl_isDefaultTimeZone(dateTimeFormatCache.icuDefaultTimeZone))
     {
         formatters = dateTimeFormatCache.formatters = new Record();
-        dateTimeFormatCache.runtimeDefaultLocale = runtimeDefaultLocale;
-        dateTimeFormatCache.icuDefaultTimeZone = icuDefaultTimeZone;
+        dateTimeFormatCache.runtimeDefaultLocale = RuntimeDefaultLocale();
+        dateTimeFormatCache.icuDefaultTimeZone = intl_defaultTimeZone();
     } else {
         formatters = dateTimeFormatCache.formatters;
     }
 
     var fmt = formatters[format];
     if (fmt === undefined) {
         var options = ToDateTimeOptions(undefined, required, defaults);
         fmt = formatters[format] = intl_DateTimeFormat(undefined, options);
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -947,38 +947,48 @@ class ScopedICUObject
 
 // Starting with ICU 59, UChar defaults to char16_t.
 static_assert(mozilla::IsSame<UChar, char16_t>::value,
               "We don't support redefining UChar to a different type");
 
 // The inline capacity we use for the char16_t Vectors.
 static const size_t INITIAL_CHAR_BUFFER_SIZE = 32;
 
+template <typename ICUStringFunction, size_t InlineCapacity>
+static int32_t
+Call(JSContext* cx, const ICUStringFunction& strFn, Vector<char16_t, InlineCapacity>& chars)
+{
+    MOZ_ASSERT(chars.length() == 0);
+    MOZ_ALWAYS_TRUE(chars.resize(InlineCapacity));
+
+    UErrorCode status = U_ZERO_ERROR;
+    int32_t size = strFn(chars.begin(), InlineCapacity, &status);
+    if (status == U_BUFFER_OVERFLOW_ERROR) {
+        MOZ_ASSERT(size >= 0);
+        if (!chars.resize(size_t(size)))
+            return -1;
+        status = U_ZERO_ERROR;
+        strFn(chars.begin(), size, &status);
+    }
+    if (U_FAILURE(status)) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
+        return -1;
+    }
+    MOZ_ASSERT(size >= 0);
+    return size;
+}
+
 template <typename ICUStringFunction>
 static JSString*
 Call(JSContext* cx, const ICUStringFunction& strFn)
 {
     Vector<char16_t, INITIAL_CHAR_BUFFER_SIZE> chars(cx);
-    MOZ_ALWAYS_TRUE(chars.resize(INITIAL_CHAR_BUFFER_SIZE));
-
-    UErrorCode status = U_ZERO_ERROR;
-    int32_t size = strFn(chars.begin(), INITIAL_CHAR_BUFFER_SIZE, &status);
-    if (status == U_BUFFER_OVERFLOW_ERROR) {
-        MOZ_ASSERT(size >= 0);
-        if (!chars.resize(size_t(size)))
-            return nullptr;
-        status = U_ZERO_ERROR;
-        strFn(chars.begin(), size, &status);
-    }
-    if (U_FAILURE(status)) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
+    int32_t size = Call(cx, strFn, chars);
+    if (size < 0)
         return nullptr;
-    }
-
-    MOZ_ASSERT(size >= 0);
     return NewStringCopyN<CanGC>(cx, chars.begin(), size_t(size));
 }
 
 
 /******************** Collator ********************/
 
 const ClassOps CollatorObject::classOps_ = {
     nullptr, /* addProperty */
@@ -3105,16 +3115,58 @@ js::intl_defaultTimeZoneOffset(JSContext
         return false;
     }
 
     args.rval().setInt32(offset);
     return true;
 }
 
 bool
+js::intl_isDefaultTimeZone(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 1);
+    MOZ_ASSERT(args[0].isString() || args[0].isUndefined());
+
+    // |undefined| is the default value when the Intl runtime caches haven't
+    // yet been initialized. Handle it the same way as a cache miss.
+    if (args[0].isUndefined()) {
+        args.rval().setBoolean(false);
+        return true;
+    }
+
+    // The current default might be stale, because JS::ResetTimeZone() doesn't
+    // immediately update ICU's default time zone. So perform an update if
+    // needed.
+    js::ResyncICUDefaultTimeZone();
+
+    Vector<char16_t, INITIAL_CHAR_BUFFER_SIZE> chars(cx);
+    int32_t size = Call(cx, ucal_getDefaultTimeZone, chars);
+    if (size < 0)
+        return false;
+
+    JSLinearString* str = args[0].toString()->ensureLinear(cx);
+    if (!str)
+        return false;
+
+    bool equals;
+    if (str->length() == size_t(size)) {
+        JS::AutoCheckCannotGC nogc;
+        equals = str->hasLatin1Chars()
+                 ? EqualChars(str->latin1Chars(nogc), chars.begin(), str->length())
+                 : EqualChars(str->twoByteChars(nogc), chars.begin(), str->length());
+    } else {
+        equals = false;
+    }
+
+    args.rval().setBoolean(equals);
+    return true;
+}
+
+bool
 js::intl_patternForSkeleton(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 2);
     MOZ_ASSERT(args[0].isString());
     MOZ_ASSERT(args[1].isString());
 
     JSAutoByteString locale(cx, args[0].toString());
--- a/js/src/builtin/Intl.h
+++ b/js/src/builtin/Intl.h
@@ -473,16 +473,25 @@ intl_defaultTimeZone(JSContext* cx, unsi
  * Return the raw offset from GMT in milliseconds for the default time zone.
  *
  * Usage: defaultTimeZoneOffset = intl_defaultTimeZoneOffset()
  */
 extern MOZ_MUST_USE bool
 intl_defaultTimeZoneOffset(JSContext* cx, unsigned argc, Value* vp);
 
 /**
+ * Return true if the given string is the default time zone as returned by
+ * intl_defaultTimeZone(). Otherwise return false.
+ *
+ * Usage: isIcuDefaultTimeZone = intl_isDefaultTimeZone(icuDefaultTimeZone)
+ */
+extern MOZ_MUST_USE bool
+intl_isDefaultTimeZone(JSContext* cx, unsigned argc, Value* vp);
+
+/**
  * Return a pattern in the date-time format pattern language of Unicode
  * Technical Standard 35, Unicode Locale Data Markup Language, for the
  * best-fit date-time format pattern corresponding to skeleton for the
  * given locale.
  *
  * Usage: pattern = intl_patternForSkeleton(locale, skeleton)
  */
 extern MOZ_MUST_USE bool
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -652,23 +652,23 @@ function DefaultLocaleIgnoringAvailableL
 
 
 /**
  * Returns the BCP 47 language tag for the host environment's current locale.
  *
  * Spec: ECMAScript Internationalization API Specification, 6.2.4.
  */
 function DefaultLocale() {
-    const runtimeDefaultLocale = RuntimeDefaultLocale();
-    if (runtimeDefaultLocale === localeCache.runtimeDefaultLocale)
+    if (IsRuntimeDefaultLocale(localeCache.runtimeDefaultLocale))
         return localeCache.defaultLocale;
 
     // If we didn't have a cache hit, compute the candidate default locale.
     // Then use it as the actual default locale if ICU supports that locale
     // (perhaps via fallback).  Otherwise use the last-ditch locale.
+    var runtimeDefaultLocale = RuntimeDefaultLocale();
     var candidate = DefaultLocaleIgnoringAvailableLocales();
     var locale;
     if (BestAvailableLocaleIgnoringDefault(callFunction(collatorInternalProperties.availableLocales,
                                                         collatorInternalProperties),
                                            candidate) &&
         BestAvailableLocaleIgnoringDefault(callFunction(numberFormatInternalProperties.availableLocales,
                                                         numberFormatInternalProperties),
                                            candidate) &&
@@ -756,21 +756,21 @@ function CanonicalizeTimeZoneName(timeZo
 /**
  * 6.4.3 DefaultTimeZone ()
  *
  * Returns the IANA time zone name for the host environment's current time zone.
  *
  * ES2017 Intl draft rev 4a23f407336d382ed5e3471200c690c9b020b5f3
  */
 function DefaultTimeZone() {
-    const icuDefaultTimeZone = intl_defaultTimeZone();
-    if (timeZoneCache.icuDefaultTimeZone === icuDefaultTimeZone)
+    if (intl_isDefaultTimeZone(timeZoneCache.icuDefaultTimeZone))
         return timeZoneCache.defaultTimeZone;
 
     // Verify that the current ICU time zone is a valid ECMA-402 time zone.
+    var icuDefaultTimeZone = intl_defaultTimeZone();
     var timeZone = intl_IsValidTimeZoneName(icuDefaultTimeZone);
     if (timeZone === null) {
         // Before defaulting to "UTC", try to represent the default time zone
         // using the Etc/GMT + offset format. This format only accepts full
         // hour offsets.
         const msPerHour = 60 * 60 * 1000;
         var offset = intl_defaultTimeZoneOffset();
         assert(offset === (offset | 0),
--- a/js/src/builtin/Number.js
+++ b/js/src/builtin/Number.js
@@ -23,18 +23,20 @@ function Number_toLocaleString() {
     var locales = arguments.length > 0 ? arguments[0] : undefined;
     var options = arguments.length > 1 ? arguments[1] : undefined;
 
     // Step 4.
     var numberFormat;
     if (locales === undefined && options === undefined) {
         // This cache only optimizes for the old ES5 toLocaleString without
         // locales and options.
-        if (numberFormatCache.numberFormat === undefined)
+        if (!IsRuntimeDefaultLocale(numberFormatCache.runtimeDefaultLocale)) {
             numberFormatCache.numberFormat = intl_NumberFormat(locales, options);
+            numberFormatCache.runtimeDefaultLocale = RuntimeDefaultLocale();
+        }
         numberFormat = numberFormatCache.numberFormat;
     } else {
         numberFormat = intl_NumberFormat(locales, options);
     }
 
     // Step 5.
     return intl_FormatNumber(numberFormat, x, /* formatToParts = */ false);
 }
--- a/js/src/builtin/String.js
+++ b/js/src/builtin/String.js
@@ -485,18 +485,16 @@ function String_codePointAt(pos) {
     var second = callFunction(std_String_charCodeAt, S, position + 1);
     if (second < 0xDC00 || second > 0xDFFF)
         return first;
 
     // Step 12.
     return (first - 0xD800) * 0x400 + (second - 0xDC00) + 0x10000;
 }
 
-var collatorCache = new Record();
-
 /* ES6 20121122 draft 15.5.4.21. */
 function String_repeat(count) {
     // Steps 1-3.
     RequireObjectCoercible(this);
     var S = ToString(this);
 
     // Steps 4-5.
     var n = ToInteger(count);
@@ -567,16 +565,18 @@ function StringIteratorNext() {
     UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + charCount);
 
     // Communicate |first|'s possible range to the compiler.
     result.value = callFunction(std_String_fromCodePoint, null, first & 0x1fffff);
 
     return result;
 }
 
+var collatorCache = new Record();
+
 /**
  * Compare this String against that String, using the locale and collation
  * options provided.
  *
  * Spec: ECMAScript Internationalization API Specification, 13.1.1.
  */
 function String_localeCompare(that) {
     // Steps 1-3.
@@ -588,18 +588,20 @@ function String_localeCompare(that) {
     var locales = arguments.length > 1 ? arguments[1] : undefined;
     var options = arguments.length > 2 ? arguments[2] : undefined;
 
     // Step 6.
     var collator;
     if (locales === undefined && options === undefined) {
         // This cache only optimizes for the old ES5 localeCompare without
         // locales and options.
-        if (collatorCache.collator === undefined)
+        if (!IsRuntimeDefaultLocale(collatorCache.runtimeDefaultLocale)) {
             collatorCache.collator = intl_Collator(locales, options);
+            collatorCache.runtimeDefaultLocale = RuntimeDefaultLocale();
+        }
         collator = collatorCache.collator;
     } else {
         collator = intl_Collator(locales, options);
     }
 
     // Step 7.
     return intl_CompareStrings(collator, S, That);
 }
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1281,17 +1281,16 @@ JSContext::JSContext(JSRuntime* runtime,
     arenas_(nullptr),
     enterCompartmentDepth_(0),
     jitActivation(nullptr),
     activation_(nullptr),
     profilingActivation_(nullptr),
     nativeStackBase(GetNativeStackBase()),
     entryMonitor(nullptr),
     noExecuteDebuggerTop(nullptr),
-    handlingSegFault(false),
     activityCallback(nullptr),
     activityCallbackArg(nullptr),
     requestDepth(0),
 #ifdef DEBUG
     checkRequestDepth(0),
     inUnsafeCallWithABI(false),
     hasAutoUnsafeCallWithABI(false),
 #endif
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -409,19 +409,16 @@ struct JSContext : public JS::RootingCon
      * Stack of debuggers that currently disallow debuggee execution.
      *
      * When we check for NX we are inside the debuggee compartment, and thus a
      * stack of Debuggers that have prevented execution need to be tracked to
      * enter the correct Debugger compartment to report the error.
      */
     js::ThreadLocalData<js::EnterDebuggeeNoExecute*> noExecuteDebuggerTop;
 
-    // Set when handling a segfault in the wasm signal handler.
-    bool handlingSegFault;
-
     js::ThreadLocalData<js::ActivityCallback> activityCallback;
     js::ThreadLocalData<void*>                activityCallbackArg;
     void triggerActivityCallback(bool active);
 
     /* The request depth for this thread. */
     js::ThreadLocalData<unsigned> requestDepth;
 
 #ifdef DEBUG
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1786,31 +1786,71 @@ js::ReportIncompatibleSelfHostedMethod(J
 /**
  * Returns the default locale as a well-formed, but not necessarily canonicalized,
  * BCP-47 language tag.
  */
 static bool
 intrinsic_RuntimeDefaultLocale(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 0);
 
     const char* locale = cx->runtime()->getDefaultLocale();
     if (!locale) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEFAULT_LOCALE_ERROR);
         return false;
     }
 
     JSString* jslocale = JS_NewStringCopyZ(cx, locale);
     if (!jslocale)
         return false;
 
     args.rval().setString(jslocale);
     return true;
 }
 
+static bool
+intrinsic_IsRuntimeDefaultLocale(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 1);
+    MOZ_ASSERT(args[0].isString() || args[0].isUndefined());
+
+    // |undefined| is the default value when the Intl runtime caches haven't
+    // yet been initialized. Handle it the same way as a cache miss.
+    if (args[0].isUndefined()) {
+        args.rval().setBoolean(false);
+        return true;
+    }
+
+    const char* locale = cx->runtime()->getDefaultLocale();
+    if (!locale) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEFAULT_LOCALE_ERROR);
+        return false;
+    }
+
+    JSLinearString* str = args[0].toString()->ensureLinear(cx);
+    if (!str)
+        return false;
+
+    bool equals;
+    if (str->length() == strlen(locale)) {
+        JS::AutoCheckCannotGC nogc;
+        const Latin1Char* latin1Locale = reinterpret_cast<const Latin1Char*>(locale);
+        equals = str->hasLatin1Chars()
+                 ? EqualChars(str->latin1Chars(nogc), latin1Locale, str->length())
+                 : EqualChars(str->twoByteChars(nogc), latin1Locale, str->length());
+    } else {
+        equals = false;
+    }
+
+    args.rval().setBoolean(equals);
+    return true;
+}
+
 using GetOrCreateIntlConstructor = JSFunction* (*)(JSContext*, Handle<GlobalObject*>);
 
 template <GetOrCreateIntlConstructor getOrCreateIntlConstructor>
 static bool
 intrinsic_GetBuiltinIntlConstructor(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 0);
@@ -2227,16 +2267,17 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("OwnPropertyKeys",         intrinsic_OwnPropertyKeys,         1,0),
     JS_FN("MakeDefaultConstructor",  intrinsic_MakeDefaultConstructor,  2,0),
     JS_FN("_ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1,0),
     JS_FN("_NameForTypedArray",      intrinsic_NameForTypedArray, 1,0),
     JS_FN("DecompileArg",            intrinsic_DecompileArg,            2,0),
     JS_INLINABLE_FN("_FinishBoundFunctionInit", intrinsic_FinishBoundFunctionInit, 3,0,
                     IntrinsicFinishBoundFunctionInit),
     JS_FN("RuntimeDefaultLocale",    intrinsic_RuntimeDefaultLocale,    0,0),
+    JS_FN("IsRuntimeDefaultLocale",  intrinsic_IsRuntimeDefaultLocale,  1,0),
     JS_FN("AddContentTelemetry",     intrinsic_AddContentTelemetry,     2,0),
     JS_FN("_DefineDataProperty",     intrinsic_DefineDataProperty,      4,0),
     JS_FN("_DefineProperty",         intrinsic_DefineProperty,          6,0),
 
     JS_INLINABLE_FN("_IsConstructing", intrinsic_IsConstructing,        0,0,
                     IntrinsicIsConstructing),
     JS_INLINABLE_FN("SubstringKernel", intrinsic_SubstringKernel,       3,0,
                     IntrinsicSubstringKernel),
@@ -2430,16 +2471,17 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("intl_Collator", intl_Collator, 2,0),
     JS_FN("intl_Collator_availableLocales", intl_Collator_availableLocales, 0,0),
     JS_FN("intl_CompareStrings", intl_CompareStrings, 3,0),
     JS_FN("intl_DateTimeFormat", intl_DateTimeFormat, 2,0),
     JS_FN("intl_DateTimeFormat_availableLocales", intl_DateTimeFormat_availableLocales, 0,0),
     JS_FN("intl_defaultCalendar", intl_defaultCalendar, 1,0),
     JS_FN("intl_defaultTimeZone", intl_defaultTimeZone, 0,0),
     JS_FN("intl_defaultTimeZoneOffset", intl_defaultTimeZoneOffset, 0,0),
+    JS_FN("intl_isDefaultTimeZone", intl_isDefaultTimeZone, 1,0),
     JS_FN("intl_FormatDateTime", intl_FormatDateTime, 2,0),
     JS_FN("intl_FormatNumber", intl_FormatNumber, 2,0),
     JS_FN("intl_GetCalendarInfo", intl_GetCalendarInfo, 1,0),
     JS_FN("intl_GetLocaleInfo", intl_GetLocaleInfo, 1,0),
     JS_FN("intl_ComputeDisplayNames", intl_ComputeDisplayNames, 3,0),
     JS_FN("intl_isUpperCaseFirst", intl_isUpperCaseFirst, 1,0),
     JS_FN("intl_IsValidTimeZoneName", intl_IsValidTimeZoneName, 1,0),
     JS_FN("intl_NumberFormat", intl_NumberFormat, 2,0),
--- a/js/src/wasm/WasmSignalHandlers.cpp
+++ b/js/src/wasm/WasmSignalHandlers.cpp
@@ -16,16 +16,17 @@
  * limitations under the License.
  */
 
 #include "wasm/WasmSignalHandlers.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/ScopeExit.h"
+#include "mozilla/ThreadLocal.h"
 
 #include "jit/AtomicOperations.h"
 #include "jit/Disassembler.h"
 #include "vm/Runtime.h"
 #include "wasm/WasmBuiltins.h"
 #include "wasm/WasmInstance.h"
 
 using namespace js;
@@ -43,32 +44,30 @@ extern "C" MFBT_API bool IsSignalHandlin
 # endif
 #endif
 
 // Crashing inside the signal handler can cause the handler to be recursively
 // invoked, eventually blowing the stack without actually showing a crash
 // report dialog via Breakpad. To guard against this we watch for such
 // recursion and fall through to the next handler immediately rather than
 // trying to handle it.
-class AutoSetHandlingSegFault
-{
-    JSContext* cx;
+
+static MOZ_THREAD_LOCAL(bool) sAlreadyInSignalHandler;
 
-  public:
-    explicit AutoSetHandlingSegFault(JSContext* cx)
-      : cx(cx)
+struct AutoSignalHandler
+{
+    explicit AutoSignalHandler()
     {
-        MOZ_ASSERT(!cx->handlingSegFault);
-        cx->handlingSegFault = true;
+        MOZ_ASSERT(!sAlreadyInSignalHandler.get());
+        sAlreadyInSignalHandler.set(true);
     }
 
-    ~AutoSetHandlingSegFault()
-    {
-        MOZ_ASSERT(cx->handlingSegFault);
-        cx->handlingSegFault = false;
+    ~AutoSignalHandler() {
+        MOZ_ASSERT(sAlreadyInSignalHandler.get());
+        sAlreadyInSignalHandler.set(false);
     }
 };
 
 #if defined(XP_WIN)
 # define XMM_sig(p,i) ((p)->Xmm##i)
 # define EIP_sig(p) ((p)->Eip)
 # define EBP_sig(p) ((p)->Ebp)
 # define ESP_sig(p) ((p)->Esp)
@@ -963,22 +962,16 @@ IsHeapAccessAddress(const Instance &inst
 {
     size_t accessLimit = instance.memoryMappedSize();
 
     return instance.metadata().usesMemory() &&
            faultingAddress >= instance.memoryBase() &&
            faultingAddress < instance.memoryBase() + accessLimit;
 }
 
-MOZ_COLD static bool
-IsActiveContext(JSContext* cx)
-{
-    return cx == cx->runtime()->activeContext();
-}
-
 #if defined(XP_WIN)
 
 static bool
 HandleFault(PEXCEPTION_POINTERS exception)
 {
     EXCEPTION_RECORD* record = exception->ExceptionRecord;
     CONTEXT* context = exception->ContextRecord;
 
@@ -986,30 +979,23 @@ HandleFault(PEXCEPTION_POINTERS exceptio
         return false;
 
     uint8_t** ppc = ContextToPC(context);
     uint8_t* pc = *ppc;
 
     if (record->NumberParameters < 2)
         return false;
 
-    // Don't allow recursive handling of signals, see AutoSetHandlingSegFault.
-    JSContext* cx = TlsContext.get();
-    if (!cx || cx->handlingSegFault || !IsActiveContext(cx))
-        return false;
-    AutoSetHandlingSegFault handling(cx);
-
-    if (!cx->activation() || !cx->activation()->isJit())
-        return false;
-    JitActivation* activation = cx->activation()->asJit();
-
     const CodeSegment* codeSegment = LookupCodeSegment(pc);
     if (!codeSegment)
         return false;
 
+    JitActivation* activation = TlsContext.get()->activation()->asJit();
+    MOZ_ASSERT(activation);
+
     const Instance* instance = LookupFaultingInstance(*codeSegment, pc, ContextToFP(context));
     if (!instance) {
         // On Windows, it is possible for InterruptRunningJitCode to execute
         // between a faulting heap access and the handling of the fault due
         // to InterruptRunningJitCode's use of SuspendThread. When this happens,
         // after ResumeThread, the exception handler is called with pc equal to
         // CodeSegment.interrupt, which is logically wrong. The Right Thing would
         // be for the OS to make fault-handling atomic (so that CONTEXT.pc was
@@ -1023,16 +1009,18 @@ HandleFault(PEXCEPTION_POINTERS exceptio
 
     uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(record->ExceptionInformation[1]);
 
     // This check isn't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
     if (!IsHeapAccessAddress(*instance, faultingAddress))
         return false;
 
+    MOZ_ASSERT(activation->compartment() == instance->compartment());
+
     // Similar to the non-atomic situation above, on Windows, an OOB fault at a
     // PC can trigger *after* an async interrupt observed that PC and attempted
     // to redirect to the async stub. In this unique case, isWasmInterrupted() is
     // already true when the OOB handler is called. Since the point of the async
     // interrupt is to get out of an iloop and the OOB trap will do just that,
     // we can simply clear the interrupt. (The update to CONTEXT.pc made by
     // HandleMemoryAccess will clobber the interrupt's previous update.)
     if (activation->isWasmInterrupted()) {
@@ -1042,16 +1030,21 @@ HandleFault(PEXCEPTION_POINTERS exceptio
 
     HandleMemoryAccess(context, pc, faultingAddress, codeSegment, *instance, activation, ppc);
     return true;
 }
 
 static LONG WINAPI
 WasmFaultHandler(LPEXCEPTION_POINTERS exception)
 {
+    // Before anything else, prevent handler recursion.
+    if (sAlreadyInSignalHandler.get())
+        return EXCEPTION_CONTINUE_SEARCH;
+    AutoSignalHandler ash;
+
     if (HandleFault(exception))
         return EXCEPTION_CONTINUE_EXECUTION;
 
     // No need to worry about calling other handlers, the OS does this for us.
     return EXCEPTION_CONTINUE_SEARCH;
 }
 
 #elif defined(XP_DARWIN)
@@ -1079,21 +1072,16 @@ struct ExceptionRequest
 {
     Request__mach_exception_raise_t body;
     mach_msg_trailer_t trailer;
 };
 
 static bool
 HandleMachException(JSContext* cx, const ExceptionRequest& request)
 {
-    // Don't allow recursive handling of signals, see AutoSetHandlingSegFault.
-    if (cx->handlingSegFault || !IsActiveContext(cx))
-        return false;
-    AutoSetHandlingSegFault handling(cx);
-
     // Get the port of the JSContext's thread from the message.
     mach_port_t cxThread = request.body.thread.name;
 
     // Read out the JSRuntime thread's register state.
     EMULATOR_CONTEXT context;
 # if defined(__x86_64__)
     unsigned int thread_state_count = x86_THREAD_STATE64_COUNT;
     unsigned int float_state_count = x86_FLOAT_STATE64_COUNT;
@@ -1127,35 +1115,34 @@ HandleMachException(JSContext* cx, const
 
     if (request.body.exception != EXC_BAD_ACCESS || request.body.codeCnt != 2)
         return false;
 
     // The faulting thread is suspended so we can access cx fields that can
     // normally only be accessed by the cx's active thread.
     AutoNoteSingleThreadedRegion anstr;
 
-    if (!cx->activation() || !cx->activation()->isJit())
-        return false;
-    JitActivation* activation = cx->activation()->asJit();
-
     const CodeSegment* codeSegment = LookupCodeSegment(pc);
     if (!codeSegment)
         return false;
 
     const Instance* instance = LookupFaultingInstance(*codeSegment, pc, ContextToFP(&context));
     if (!instance)
         return false;
 
     uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(request.body.code[1]);
 
     // This check isn't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
     if (!IsHeapAccessAddress(*instance, faultingAddress))
         return false;
 
+    JitActivation* activation = cx->activation()->asJit();
+    MOZ_ASSERT(activation->compartment() == instance->compartment());
+
     HandleMemoryAccess(&context, pc, faultingAddress, codeSegment, *instance, activation, ppc);
 
     // Update the thread state with the new pc and register values.
     kret = thread_set_state(cxThread, float_state, (thread_state_t)&context.float_, float_state_count);
     if (kret != KERN_SUCCESS)
         return false;
     kret = thread_set_state(cxThread, thread_state, (thread_state_t)&context.thread, thread_state_count);
     if (kret != KERN_SUCCESS)
@@ -1309,49 +1296,32 @@ MachExceptionHandler::install(JSContext*
 
     installed_ = true;
     onFailure.release();
     return true;
 }
 
 #else  // If not Windows or Mac, assume Unix
 
-enum class Signal {
-    SegFault,
-    BusError
-};
-
 // Be very cautious and default to not handling; we don't want to accidentally
 // silence real crashes from real bugs.
-template<Signal signal>
 static bool
 HandleFault(int signum, siginfo_t* info, void* ctx)
 {
-    // The signals we're expecting come from access violations, accessing
-    // mprotected memory. If the signal originates anywhere else, don't try
-    // to handle it.
-    if (signal == Signal::SegFault)
-        MOZ_RELEASE_ASSERT(signum == SIGSEGV);
-    else
-        MOZ_RELEASE_ASSERT(signum == SIGBUS);
+    // Before anything else, prevent handler recursion.
+    if (sAlreadyInSignalHandler.get())
+        return false;
+    AutoSignalHandler ash;
+
+    MOZ_RELEASE_ASSERT(signum == SIGSEGV || signum == SIGBUS);
 
     CONTEXT* context = (CONTEXT*)ctx;
     uint8_t** ppc = ContextToPC(context);
     uint8_t* pc = *ppc;
 
-    // Don't allow recursive handling of signals, see AutoSetHandlingSegFault.
-    JSContext* cx = TlsContext.get();
-    if (!cx || cx->handlingSegFault || !IsActiveContext(cx))
-        return false;
-    AutoSetHandlingSegFault handling(cx);
-
-    if (!cx->activation() || !cx->activation()->isJit())
-        return false;
-    JitActivation* activation = cx->activation()->asJit();
-
     const CodeSegment* segment = LookupCodeSegment(pc);
     if (!segment)
         return false;
 
     const Instance* instance = LookupFaultingInstance(*segment, pc, ContextToFP(context));
     if (!instance)
         return false;
 
@@ -1371,18 +1341,21 @@ HandleFault(int signum, siginfo_t* info,
 #else
         return false;
 #endif
     } else {
         if (!IsHeapAccessAddress(*instance, faultingAddress))
             return false;
     }
 
+    JitActivation* activation = TlsContext.get()->activation()->asJit();
+    MOZ_ASSERT(activation->compartment() == instance->compartment());
+
 #ifdef JS_CODEGEN_ARM
-    if (signal == Signal::BusError) {
+    if (signum == SIGBUS) {
         // TODO: We may see a bus error for something that is an unaligned access that
         // partly overlaps the end of the heap.  In this case, it is an out-of-bounds
         // error and we should signal that properly, but to do so we must inspect
         // the operand of the failed access.
         activation->startWasmInterrupt(ToRegisterState(context));
         *ppc = segment->unalignedAccessCode();
         return true;
     }
@@ -1390,21 +1363,20 @@ HandleFault(int signum, siginfo_t* info,
 
     HandleMemoryAccess(context, pc, faultingAddress, segment, *instance, activation, ppc);
     return true;
 }
 
 static struct sigaction sPrevSEGVHandler;
 static struct sigaction sPrevSIGBUSHandler;
 
-template<Signal signal>
 static void
 WasmFaultHandler(int signum, siginfo_t* info, void* context)
 {
-    if (HandleFault<signal>(signum, info, context))
+    if (HandleFault(signum, info, context))
         return;
 
     struct sigaction* previousSignal = signum == SIGSEGV
                                        ? &sPrevSEGVHandler
                                        : &sPrevSIGBUSHandler;
 
     // This signal is not for any asm.js code we expect, so we need to forward
     // the signal to the next handler. If there is no next handler (SIG_IGN or
@@ -1624,26 +1596,26 @@ ProcessHasSignalHandlers()
 # else
     // SA_NODEFER allows us to reenter the signal handler if we crash while
     // handling the signal, and fall through to the Breakpad handler by testing
     // handlingSegFault.
 
     // Allow handling OOB with signals on all architectures
     struct sigaction faultHandler;
     faultHandler.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
-    faultHandler.sa_sigaction = WasmFaultHandler<Signal::SegFault>;
+    faultHandler.sa_sigaction = WasmFaultHandler;
     sigemptyset(&faultHandler.sa_mask);
     if (sigaction(SIGSEGV, &faultHandler, &sPrevSEGVHandler))
         MOZ_CRASH("unable to install segv handler");
 
 #  if defined(JS_CODEGEN_ARM)
     // On Arm Handle Unaligned Accesses
     struct sigaction busHandler;
     busHandler.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
-    busHandler.sa_sigaction = WasmFaultHandler<Signal::BusError>;
+    busHandler.sa_sigaction = WasmFaultHandler;
     sigemptyset(&busHandler.sa_mask);
     if (sigaction(SIGBUS, &busHandler, &sPrevSIGBUSHandler))
         MOZ_CRASH("unable to install sigbus handler");
 #  endif
 # endif
 
     sHaveSignalHandlers = true;
     return true;
new file mode 100644
--- /dev/null
+++ b/layout/painting/crashtests/1418722-1.html
@@ -0,0 +1,17 @@
+<html class="reftest-wait">
+<body>
+  <div style="width:200px; height:200px; perspective:1000px">
+    <div style="width:200px; height:200px; transform:translateZ(2px); background-color:green" id="transformed"></div>
+  </div>
+  <div style="width: 200px; height:200px; background-color:red" id="helper"></div>
+</body>
+<script>
+  function doTest() {
+    var element = document.getElementById("transformed");
+    element.parentNode.removeChild(element);
+    document.getElementById("helper").style.backgroundColor = "blue";
+    document.documentElement.className = "";
+  }
+  window.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</html>
--- a/layout/painting/crashtests/crashtests.list
+++ b/layout/painting/crashtests/crashtests.list
@@ -1,5 +1,6 @@
 load 1402183-1.html
 skip-if(!(stylo||styloVsGecko)||Android) load 1407470-1.html
 load 1413073-1.html
 load 1413073-2.html
 load 1405881-1.html
+load 1418722-1.html
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -9032,16 +9032,18 @@ nsDisplayPerspective::nsDisplayPerspecti
                                            nsDisplayList* aList)
   : nsDisplayItem(aBuilder, aPerspectiveFrame)
   , mList(aBuilder, aPerspectiveFrame, aList)
   , mTransformFrame(aTransformFrame)
   , mIndex(aBuilder->AllocatePerspectiveItemIndex())
 {
   MOZ_ASSERT(mList.GetChildren()->Count() == 1);
   MOZ_ASSERT(mList.GetChildren()->GetTop()->GetType() == DisplayItemType::TYPE_TRANSFORM);
+
+  mTransformFrame->AddDisplayItem(this);
 }
 
 already_AddRefed<Layer>
 nsDisplayPerspective::BuildLayer(nsDisplayListBuilder *aBuilder,
                                  LayerManager *aManager,
                                  const ContainerLayerParameters& aContainerParameters)
 {
   float appUnitsPerPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -2058,17 +2058,17 @@ public:
    * @return the nsIFrame that provides the style data, and should
    * be checked when deciding if this display item can be reused.
    */
   virtual nsIFrame* FrameForInvalidation() const
   {
     return mFrame;
   }
 
-  bool HasDeletedFrame() const { return !mFrame; }
+  virtual bool HasDeletedFrame() const { return !mFrame; }
 
   virtual nsIFrame* StyleFrame() const { return mFrame; }
 
   /**
    * Compute the used z-index of our frame; returns zero for elements to which
    * z-index does not apply, and for z-index:auto.
    * @note This can be overridden, @see nsDisplayWrapList::SetOverrideZIndex.
    */
@@ -6157,16 +6157,22 @@ class nsDisplayPerspective : public nsDi
   typedef mozilla::gfx::Point3D Point3D;
 
 public:
   NS_DISPLAY_DECL_NAME("nsDisplayPerspective", TYPE_PERSPECTIVE)
 
   nsDisplayPerspective(nsDisplayListBuilder* aBuilder, nsIFrame* aTransformFrame,
                        nsIFrame* aPerspectiveFrame,
                        nsDisplayList* aList);
+  ~nsDisplayPerspective()
+  {
+    if (mTransformFrame) {
+      mTransformFrame->RemoveDisplayItem(this);
+    }
+  }
 
   virtual uint32_t GetPerFrameKey() const override {
     return (mIndex << TYPE_BITS) | nsDisplayItem::GetPerFrameKey();
   }
 
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override
   {
@@ -6263,16 +6269,26 @@ public:
   }
 
   virtual void Destroy(nsDisplayListBuilder* aBuilder) override
   {
     mList.GetChildren()->DeleteAll(aBuilder);
     nsDisplayItem::Destroy(aBuilder);
   }
 
+  virtual bool HasDeletedFrame() const override { return !mTransformFrame || nsDisplayItem::HasDeletedFrame(); }
+
+  virtual void RemoveFrame(nsIFrame* aFrame) override
+  {
+    if (aFrame == mTransformFrame) {
+      mTransformFrame = nullptr;
+    }
+    nsDisplayItem::RemoveFrame(aFrame);
+  }
+
 private:
   nsDisplayWrapList mList;
   nsIFrame* mTransformFrame;
   uint32_t mIndex;
 };
 
 /**
  * This class adds basic support for limiting the rendering (in the inline axis
--- a/layout/xul/nsDocElementBoxFrame.cpp
+++ b/layout/xul/nsDocElementBoxFrame.cpp
@@ -16,16 +16,17 @@
 #include "nsStackLayout.h"
 #include "nsIAnonymousContentCreator.h"
 #include "mozilla/dom/NodeInfo.h"
 #include "nsIServiceManager.h"
 #include "nsNodeInfoManager.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentUtils.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/FromParser.h"
 
 //#define DEBUG_REFLOW
 
 using namespace mozilla::dom;
 
 class nsDocElementBoxFrame final : public nsBoxFrame
                                  , public nsIAnonymousContentCreator
 {
@@ -93,29 +94,30 @@ nsDocElementBoxFrame::CreateAnonymousCon
   // create the top-secret popupgroup node. shhhhh!
   RefPtr<NodeInfo> nodeInfo;
   nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::popupgroup,
                                           nullptr, kNameSpaceID_XUL,
                                           nsIDOMNode::ELEMENT_NODE);
   NS_E