Merge m-c to graphics
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 31 Jan 2017 09:04:18 -0500
changeset 388826 c3133d426341b4e1b679af25f1489ecadd03b03f
parent 388825 12c5788aa7a0c13030cd0af79baeafeaf0b46ccd (current diff)
parent 378367 adab5d5d0372d1a26685d6fbc59cdfc977ad76c6 (diff)
child 388827 004bac21b3b9421828d1307b83d238632a4b1abb
push id7198
push userjlorenzo@mozilla.com
push dateTue, 18 Apr 2017 12:07:49 +0000
treeherdermozilla-beta@d57aa49c3948 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to graphics MozReview-Commit-ID: 7PVyxahE0p6
browser/components/extensions/test/browser/browser-common.ini
browser/components/preferences/in-content/sync.xul
browser/extensions/shield-recipe-client/data/EventEmitter.js
browser/themes/shared/fxa/sync-illustration.svg
config/rules.mk
devtools/client/inspector/components/box-model.js
dom/base/TimeoutHandler.cpp
dom/base/TimeoutHandler.h
dom/ipc/TabChild.cpp
gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
js/src/jit/BaselineCacheIRCompiler.cpp
layout/reftests/bugs/reftest.list
layout/reftests/canvas/reftest.list
layout/reftests/css-blending/reftest.list
layout/reftests/css-gradients/reftest.list
layout/reftests/flexbox/reftest.list
layout/reftests/ogg-video/reftest.list
layout/reftests/position-sticky/reftest.list
layout/reftests/svg/reftest.list
layout/reftests/text-overflow/reftest.list
layout/reftests/transform-3d/reftest.list
layout/reftests/webm-video/reftest.list
layout/reftests/writing-mode/reftest.list
mobile/android/thirdparty/com/keepsafe/switchboard/AsyncConfigLoader.java
mobile/android/thirdparty/com/keepsafe/switchboard/DeviceUuidFactory.java
mobile/android/thirdparty/com/keepsafe/switchboard/Preferences.java
mobile/android/thirdparty/com/keepsafe/switchboard/Switch.java
mobile/android/thirdparty/com/keepsafe/switchboard/SwitchBoard.java
modules/libpref/init/all.js
python/mozbuild/mozbuild/test/backend/data/sdk-files/bar.ico
python/mozbuild/mozbuild/test/backend/data/sdk-files/foo.ico
python/mozbuild/mozbuild/test/backend/data/sdk-files/moz.build
python/mozbuild/mozbuild/test/backend/data/sdk-files/sub/quux.png
python/mozbuild/mozbuild/test/frontend/data/sdk-files/bar.ico
python/mozbuild/mozbuild/test/frontend/data/sdk-files/baz.png
python/mozbuild/mozbuild/test/frontend/data/sdk-files/foo.xpm
python/mozbuild/mozbuild/test/frontend/data/sdk-files/moz.build
python/mozbuild/mozbuild/test/frontend/data/sdk-files/quux.icns
security/moz.build
services/sync/tests/unit/fake_login_manager.js
taskcluster/ci/build/linux.yml
toolkit/library/moz.build
tools/profiler/core/GeckoSampler.cpp
tools/profiler/core/GeckoSampler.h
--- a/.eslintignore
+++ b/.eslintignore
@@ -63,17 +63,18 @@ browser/base/content/test/general/file_c
 browser/base/content/test/urlbar/file_blank_but_not_blank.html
 browser/base/content/newtab/**
 browser/components/downloads/**
 browser/components/privatebrowsing/**
 browser/components/sessionstore/**
 browser/components/tabview/**
 # generated files in cld2
 browser/components/translation/cld2/cld-worker.js
-browser/extensions/pdfjs/content/**
+browser/extensions/pdfjs/content/build**
+browser/extensions/pdfjs/content/web**
 # generated or library files in pocket
 browser/extensions/pocket/content/panels/js/tmpl.js
 browser/extensions/pocket/content/panels/js/vendor/**
 browser/locales/**
 # imported from chromium
 browser/extensions/mortar/**
 
 # devtools/ exclusions
@@ -176,17 +177,16 @@ mobile/android/components/Snippets.js
 mobile/android/modules/HomeProvider.jsm
 
 # services/ exclusions
 
 # Uses `#filter substitution`
 services/sync/modules/constants.js
 
 # Third party services
-services/sync/tps/extensions/mozmill/resource/stdlib/json2.js
 services/common/kinto-http-client.js
 services/common/kinto-offline-client.js
 services/sync/tps/extensions/mozmill
 
 # toolkit/ exclusions
 
 # Not part of the default build
 toolkit/components/help/**
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,16 +1,17 @@
 "use strict";
 
 module.exports = {
   // When adding items to this file please check for effects on sub-directories.
   "plugins": [
     "mozilla"
   ],
   "rules": {
+    "mozilla/avoid-removeChild": "error",
     "mozilla/import-globals": "warn",
     "mozilla/no-import-into-var-and-global": "error",
     "mozilla/no-useless-parameters": "error",
     "mozilla/no-useless-removeEventListener": "error",
 
     // No (!foo in bar) or (!object instanceof Class)
     "no-unsafe-negation": "error",
   },
--- a/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js
+++ b/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js
@@ -112,18 +112,17 @@ function* testContainer1(browser, accDoc
       { GROUPING: [ ] } // ARIA owned, t1_group
     ]
   };
   testAccessibleTree(acc, tree);
 
   /* ================ Remove element ======================================== */
   onReorder = waitForEvent(EVENT_REORDER, id);
   yield ContentTask.spawn(browser, {}, () =>
-    content.document.getElementById('t1_span').parentNode.removeChild(
-      content.document.getElementById('t1_span')));
+    content.document.getElementById('t1_span').remove());
   yield onReorder;
 
   // subdiv should go away
   tree = {
     SECTION: [
       { CHECKBUTTON: [ ] }, // explicit, t1_checkbox
       { RADIOBUTTON: [ ] }, // explicit, t1_child3
       { PUSHBUTTON: [ ] }, // ARIA owned, t1_button
--- a/accessible/tests/browser/e10s/browser_treeupdate_imagemap.js
+++ b/accessible/tests/browser/e10s/browser_treeupdate_imagemap.js
@@ -114,17 +114,17 @@ function* testContainer(browser) {
     } ]
   };
   testAccessibleTree(acc, tree);
 
   /* ================= Remove map =========================================== */
   onReorder = waitForEvent(EVENT_REORDER, id);
   yield ContentTask.spawn(browser, {}, () => {
     let mapNode = content.document.getElementById('map');
-    mapNode.parentNode.removeChild(mapNode);
+    mapNode.remove();
   });
   yield onReorder;
 
   tree = {
     SECTION: [
       { GRAPHIC: [ ] }
     ]
   };
--- a/accessible/tests/mochitest/attributes/test_obj_css.html
+++ b/accessible/tests/mochitest/attributes/test_obj_css.html
@@ -23,17 +23,17 @@
       this.accessible = getAccessible(aID);
 
       this.eventSeq = [
         new invokerChecker(EVENT_HIDE, this.accessible)
       ];
 
       this.invoke = function removeElm_invoke()
       {
-        this.node.parentNode.removeChild(this.node);
+        this.node.remove();
       }
 
       this.check = function removeElm_check()
       {
         testAbsentCSSAttrs(this.accessible);
       }
 
       this.getID = function removeElm_getID()
--- a/accessible/tests/mochitest/attributes/test_obj_group.html
+++ b/accessible/tests/mochitest/attributes/test_obj_group.html
@@ -197,17 +197,17 @@
       testGroupAttrs("t1_li2", 2, 3);
       testGroupAttrs("t1_li3", 3, 3);
 
       // Test that group position information updates after deleting node.
       testGroupAttrs("tree4_ti1", 1, 2, 1);
       testGroupAttrs("tree4_ti2", 2, 2, 1);
       var tree4element = document.getElementById("tree4_ti1");
       var tree4acc = getAccessible("tree4");
-      tree4element.parentNode.removeChild(tree4element);
+      tree4element.remove();
       waitForEvent(EVENT_REORDER, tree4acc, function() {
         testGroupAttrs("tree4_ti2", 1, 1, 1);
         SimpleTest.finish();
       });
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
--- a/accessible/tests/mochitest/events/test_coalescence.html
+++ b/accessible/tests/mochitest/events/test_coalescence.html
@@ -69,17 +69,17 @@
       }
 
       // Implementation details
 
       this.invokeAction = function coalescenceBase_invokeAction(aNode, aAction)
       {
         switch (aAction) {
           case kRemoveElm:
-            aNode.parentNode.removeChild(aNode);
+            aNode.remove();
             break;
 
           case kHideElm:
             aNode.style.display = "none";
             break;
 
           case kAddElm:
             if (aNode == this.parentNode)
@@ -323,18 +323,18 @@
         new invokerChecker(EVENT_REORDER, getNode(aParentId).parentNode),
         new unexpectedInvokerChecker(EVENT_HIDE, getAccessible(aChild1Id)),
         new unexpectedInvokerChecker(EVENT_HIDE, getAccessible(aChild2Id)),
         new unexpectedInvokerChecker(EVENT_REORDER, getAccessible(aParentId))
       ];
 
       this.invoke = function removeGrandChildrenNHideParent_invoke()
       {
-        this.child1.parentNode.removeChild(this.child1);
-        this.child2.parentNode.removeChild(this.child2);
+        this.child1.remove();
+        this.child2.remove();
         this.parent.hidden = true;
       }
 
       this.getID = function removeGrandChildrenNHideParent_getID() {
         return "remove grand children of different parents and then hide their grand parent";
       }
     }
 
--- a/accessible/tests/mochitest/events/test_mutation.html
+++ b/accessible/tests/mochitest/events/test_mutation.html
@@ -197,17 +197,17 @@
       var eventTypes = aEventTypes || kHideEvents;
       var doNotExpectEvents = (aEventTypes == kNoEvents);
 
       this.__proto__ = new mutateA11yTree(aNodeOrID, eventTypes,
                                           doNotExpectEvents);
 
       this.invoke = function removeFromDOM_invoke()
       {
-        this.DOMNode.parentNode.removeChild(this.DOMNode);
+        this.DOMNode.remove();
       }
 
       this.getID = function removeFromDOM_getID()
       {
         return prettyName(aNodeOrID) + " remove from DOM.";
       }
 
       if (aTargetsFunc && (eventTypes & kHideEvent))
@@ -382,22 +382,22 @@
       this.txt = null;
       this.eventSeq = [
         new invokerChecker(EVENT_HIDE, function() { return this.txt; }.bind(this))
       ];
 
       this.invoke = function hideNDestroyDoc_invoke()
       {
         this.txt = getAccessible('c5').firstChild.firstChild;
-        this.txt.DOMNode.parentNode.removeChild(this.txt.DOMNode);
+        this.txt.DOMNode.remove();
       }
 
       this.check = function hideNDestroyDoc_check()
       {
-        getNode('c5').parentNode.removeChild(getNode('c5'));
+        getNode('c5').remove();
       }
 
       this.getID = function hideNDestroyDoc_getID()
       {
         return "remove text node and destroy a document on hide event";
       }
     }
 
@@ -415,17 +415,17 @@
         this.target = l1.firstChild;
         var l2 = doc.lastChild;
         l1.DOMNode.removeChild(l1.DOMNode.firstChild);
         l2.DOMNode.removeChild(l2.DOMNode.firstChild);
       }
 
       this.check = function hideHideNDestroyDoc_check()
       {
-        getNode('c6').parentNode.removeChild(getNode('c6'));
+        getNode('c6').remove();
       }
 
       this.getID = function hideHideNDestroyDoc_getID()
       {
         return "remove text nodes (2 events in the queue) and destroy a document on first hide event";
       }
     }
 
--- a/accessible/tests/mochitest/pivot.js
+++ b/accessible/tests/mochitest/pivot.js
@@ -471,17 +471,17 @@ function removeVCPositionChecker(aDocAcc
  *                    set to it.
  */
 function removeVCPositionInvoker(aDocAcc, aPosNode)
 {
   this.accessible = getAccessible(aPosNode);
   this.invoke = function removeVCPositionInvoker_invoke()
   {
     aDocAcc.virtualCursor.position = this.accessible;
-    aPosNode.parentNode.removeChild(aPosNode);
+    aPosNode.remove();
   };
 
   this.getID = function removeVCPositionInvoker_getID()
   {
     return "Bring virtual cursor to accessible, and remove its DOM node.";
   };
 
   this.eventSeq = [
@@ -518,17 +518,17 @@ function removeVCRootChecker(aPivot)
  *                       pivot. Should have more than one child.
  */
 function removeVCRootInvoker(aRootNode)
 {
   this.pivot = gAccService.createAccessiblePivot(getAccessible(aRootNode));
   this.invoke = function removeVCRootInvoker_invoke()
   {
     this.pivot.position = this.pivot.root.firstChild;
-    aRootNode.parentNode.removeChild(aRootNode);
+    aRootNode.remove();
   };
 
   this.getID = function removeVCRootInvoker_getID()
   {
     return "Remove root of pivot from tree.";
   };
 
   this.eventSeq = [
--- a/accessible/tests/mochitest/treeupdate/test_ariaowns.html
+++ b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
@@ -218,17 +218,17 @@
         new invokerChecker(EVENT_HIDE, getNode, "t1_checkbox"),
         new invokerChecker(EVENT_SHOW, getNode, "t1_checkbox"),
         new invokerChecker(EVENT_REORDER, getNode("t1_container"))
       ];
 
       this.invoke = function removeEl_invoke()
       {
         // remove a container of t1_subdiv
-        getNode("t1_span").parentNode.removeChild(getNode("t1_span"));
+        getNode("t1_span").remove();
       }
 
       this.finalCheck = function removeEl_finalCheck()
       {
         // subdiv should go away
         var tree =
           { SECTION: [
               { CHECKBUTTON: [ ] }, // explicit, t1_checkbox
@@ -518,17 +518,17 @@
       this.eventSeq = [
         new invokerChecker(EVENT_HIDE, getAccessible(aParent))
       ];
 
       this.invoke = function setARIAOwnsOnElToRemove_invoke()
       {
         getNode(aChild).setAttribute("aria-owns", "no_id");
         getNode(aParent).removeChild(getNode(aChild));
-        getNode(aParent).parentNode.removeChild(getNode(aParent));
+        getNode(aParent).remove();
       }
 
       this.getID = function setARIAOwnsOnElToRemove_getID()
       {
         return `set ARIA owns on an element, and then remove it, and then remove its parent`;
       }
     }
 
--- a/accessible/tests/mochitest/treeupdate/test_imagemap.html
+++ b/accessible/tests/mochitest/treeupdate/test_imagemap.html
@@ -268,17 +268,17 @@
         new invokerChecker(EVENT_HIDE, getImageMap, this),
         new invokerChecker(EVENT_SHOW, this.imgNode),
         new invokerChecker(EVENT_REORDER, this.container)
       ];
 
       this.invoke = function removeMap_invoke()
       {
         this.imageMap = getAccessible(aImageMapID);
-        this.mapNode.parentNode.removeChild(this.mapNode);
+        this.mapNode.remove();
       }
 
       this.finalCheck = function removeMap_finalCheck()
       {
         var accTree =
           { SECTION: [
             { GRAPHIC: [ ] }
           ] };
--- a/accessible/tests/mochitest/treeupdate/test_shutdown.xul
+++ b/accessible/tests/mochitest/treeupdate/test_shutdown.xul
@@ -50,17 +50,17 @@
       this.eventSeq = [
         new invokerChecker(EVENT_REORDER, document)
       ];
 
       this.invoke = function invoke()
       {
         this.lastItem = getAccessible(aID).lastChild;
         this.lastCell = this.lastItem.lastChild;
-        getNode(aID).parentNode.removeChild(getNode(aID));
+        getNode(aID).remove();
       };
 
       this.check = function check(aEvent)
       {
         testIsDefunct(this.tree, aID);
         testIsDefunct(this.lastItem, "last item of " + aID);
         if (this.lastCell) {
           testIsDefunct(this.lastCell, "last item cell of " + aID);
--- a/addon-sdk/source/lib/sdk/addon/window.js
+++ b/addon-sdk/source/lib/sdk/addon/window.js
@@ -56,10 +56,10 @@ eventTarget.addEventListener("DOMContent
 }, {once: true});
 
 exports.ready = promise;
 exports.window = window;
 
 // Still close window on unload to claim memory back early.
 unload(function() {
   window.close()
-  frame.parentNode.removeChild(frame);
+  frame.remove();
 });
--- a/addon-sdk/source/lib/sdk/context-menu.js
+++ b/addon-sdk/source/lib/sdk/context-menu.js
@@ -961,24 +961,24 @@ var MenuWrapper = Class({
   onXULRemoved: function onXULRemoved(parent) {
     if (parent == this.contextMenu) {
       let toplevel = this.topLevelItems;
 
       // If there are no more items then remove the separator
       if (toplevel.length == 0) {
         let separator = this.separator;
         if (separator)
-          separator.parentNode.removeChild(separator);
+          separator.remove();
       }
     }
     else if (parent == this.overflowPopup) {
       // If there are no more items then remove the overflow menu and separator
       if (parent.childNodes.length == 0) {
         let separator = this.separator;
-        separator.parentNode.removeChild(separator);
+        separator.remove();
         this.contextMenu.removeChild(parent.parentNode);
       }
     }
   },
 
   // Recurses through all the items owned by this module and sets their hidden
   // state
   updateItemVisibilities: function updateItemVisibilities(event) {
--- a/addon-sdk/source/lib/sdk/frame/hidden-frame.js
+++ b/addon-sdk/source/lib/sdk/frame/hidden-frame.js
@@ -103,13 +103,13 @@ function removeHiddenFrame(frame) {
     throw Error("The object to be removed must be a HiddenFrame.");
 
   if (!cache.has(frame)) return;
 
   // Remove from cache before calling in order to avoid loop
   cache.delete(frame);
   emit(frame, "unload")
   let element = frame.element
-  if (element) element.parentNode.removeChild(element)
+  if (element) element.remove()
 }
 exports.remove = removeHiddenFrame;
 
 unload(() => fromIterator(cache).forEach(removeHiddenFrame));
--- a/addon-sdk/source/lib/sdk/panel/utils.js
+++ b/addon-sdk/source/lib/sdk/panel/utils.js
@@ -362,17 +362,17 @@ function attach(panel, document) {
   if (container !== panel.parentNode) {
     detach(panel);
     document.getElementById("mainPopupSet").appendChild(panel);
   }
 }
 exports.attach = attach;
 
 function detach(panel) {
-  if (panel.parentNode) panel.parentNode.removeChild(panel);
+  if (panel.parentNode) panel.remove();
 }
 exports.detach = detach;
 
 function dispose(panel) {
   panel.backgroundFrame.remove();
   panel.backgroundFrame = null;
   events.off("document-element-inserted", panel.onContentChange);
   panel.onContentChange = null;
--- a/addon-sdk/source/lib/sdk/ui/sidebar/view.js
+++ b/addon-sdk/source/lib/sdk/ui/sidebar/view.js
@@ -39,17 +39,17 @@ function create(window, details) {
 
   document.getElementById('viewSidebarMenu').appendChild(menuitem);
 
   return menuitem;
 }
 exports.create = create;
 
 function dispose(menuitem) {
-  menuitem.parentNode.removeChild(menuitem);
+  menuitem.remove();
 }
 exports.dispose = dispose;
 
 function updateTitle(sidebar, title) {
   let button = buttons.get(sidebar);
 
   for (let window of windows(null, { includePrivate: true })) {
   	let { document } = window;
--- a/addon-sdk/source/test/addons/e10s-content/lib/test-content-script.js
+++ b/addon-sdk/source/test/addons/e10s-content/lib/test-content-script.js
@@ -49,17 +49,17 @@ function createProxyTest(html, callback)
         rawWindow: rawWindow,
         createWorker: function (contentScript) {
           return createWorker(assert, xrayWindow, contentScript, helper.done);
         },
         done: function () {
           if (isDone)
             return;
           isDone = true;
-          element.parentNode.removeChild(element);
+          element.remove();
           done();
         }
       };
       callback(helper, assert);
     }
   };
 }
 
--- a/addon-sdk/source/test/addons/unsafe-content-script/main.js
+++ b/addon-sdk/source/test/addons/unsafe-content-script/main.js
@@ -46,17 +46,17 @@ exports.testMembranelessMode = function(
           window.wrappedJSObject.assert = assert;
           window.wrappedJSObject.runTest();
           done();
         }
     });
 
     worker.port.on("done", () => {
       // cleanup
-      element.parentNode.removeChild(element);
+      element.remove();
       worker.destroy();
       loader.unload();
 
       done();
     });
 
     worker.port.on("assert", function (data) {
       assert.ok(data.assertion, data.msg);
--- a/addon-sdk/source/test/test-content-script.js
+++ b/addon-sdk/source/test/test-content-script.js
@@ -49,17 +49,17 @@ function createProxyTest(html, callback)
         rawWindow: rawWindow,
         createWorker: function (contentScript) {
           return createWorker(assert, xrayWindow, contentScript, helper.done);
         },
         done: function () {
           if (isDone)
             return;
           isDone = true;
-          element.parentNode.removeChild(element);
+          element.remove();
           done();
         }
       };
       callback(helper, assert);
     }
   };
 }
 
--- a/addon-sdk/source/test/test-context-menu.js
+++ b/addon-sdk/source/test/test-context-menu.js
@@ -2626,17 +2626,17 @@ exports.testItemNoLabel = function (asse
   }
   catch (e) {
     assert.ok(true, "Should have seen exception");
   }
 
   test.done();
 }
 
-
+/* bug 1302854 - disabled this subtest as it is intermittent
 // Tests that items can have an empty data property
 exports.testItemNoData = function (assert, done) {
   let test = new TestHelper(assert, done);
   let loader = test.newLoader();
 
   function checkData(data) {
     assert.equal(data, undefined, "Data should be undefined");
   }
@@ -2681,16 +2681,17 @@ exports.testItemNoData = function (asser
 
             test.done();
           });
         });
       });
     });
   });
 }
+*/
 
 
 exports.testItemNoAccessKey = function (assert, done) {
   let test = new TestHelper(assert, done);
   let loader = test.newLoader();
 
   let item1 = new loader.cm.Item({ label: "item 1" });
   let item2 = new loader.cm.Item({ label: "item 2", accesskey: null });
--- a/addon-sdk/source/test/test-page-mod.js
+++ b/addon-sdk/source/test/test-page-mod.js
@@ -1054,17 +1054,17 @@ exports.testAttachToTabsOnly = function(
   function openBrowserIframe() {
     assert.pass('Open iframe in browser window');
     let window = require('sdk/deprecated/window-utils').activeBrowserWindow;
     let document = window.document;
     let iframe = document.createElement('iframe');
     iframe.setAttribute('type', 'content');
     iframe.setAttribute('src', 'data:text/html;charset=utf-8,foobar');
     iframe.addEventListener('DOMContentLoaded', function() {
-      iframe.parentNode.removeChild(iframe);
+      iframe.remove();
       openTabWithIframes();
     }, {once: true});
     document.documentElement.appendChild(iframe);
   }
 
   // Only these three documents will be accepted by the page-mod
   function openTabWithIframes() {
     assert.pass('Open iframes in a tab');
--- a/b2g/components/SafeMode.jsm
+++ b/b2g/components/SafeMode.jsm
@@ -99,17 +99,17 @@ this.SafeMode = {
               return;
             }
 
             contentBrowser.removeEventListener("mozbrowserlocationchange", handleEvent, true);
             notifyContentStart();
             break;
           case "mozContentEvent":
             content.removeEventListener("mozContentEvent", handleEvent, true);
-            contentBrowser.parentNode.removeChild(contentBrowser);
+            contentBrowser.remove();
 
             if (e.detail == "safemode-yes")  {
               // Really starting in safe mode, let's disable add-ons first.
               // TODO: disable add-ons
               aResolve();
             } else {
               aResolve();
             }
--- a/b2g/config/mozconfigs/linux32_gecko/nightly
+++ b/b2g/config/mozconfigs/linux32_gecko/nightly
@@ -1,12 +1,11 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 MOZ_AUTOMATION_UPDATE_PACKAGING=0
-MOZ_AUTOMATION_SDK=0
 . "$topsrcdir/b2g/config/mozconfigs/common"
 . "$topsrcdir/build/unix/mozconfig.linux32"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-signmar
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
--- a/b2g/config/mozconfigs/linux64_gecko/nightly
+++ b/b2g/config/mozconfigs/linux64_gecko/nightly
@@ -1,12 +1,11 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 MOZ_AUTOMATION_UPDATE_PACKAGING=0
-MOZ_AUTOMATION_SDK=0
 . "$topsrcdir/b2g/config/mozconfigs/common"
 . "$topsrcdir/build/unix/mozconfig.linux"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-signmar
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
--- a/b2g/config/mozconfigs/macosx64_gecko/nightly
+++ b/b2g/config/mozconfigs/macosx64_gecko/nightly
@@ -1,11 +1,10 @@
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 MOZ_AUTOMATION_UPDATE_PACKAGING=0
-MOZ_AUTOMATION_SDK=0
 . "$topsrcdir/b2g/config/mozconfigs/common"
 
 # Use sccache
 no_sccache=
 
 . $topsrcdir/build/macosx/mozconfig.common
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
--- a/b2g/config/mozconfigs/win32_gecko/nightly
+++ b/b2g/config/mozconfigs/win32_gecko/nightly
@@ -1,12 +1,11 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 MOZ_AUTOMATION_UPDATE_PACKAGING=0
-MOZ_AUTOMATION_SDK=0
 . "$topsrcdir/b2g/config/mozconfigs/common"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-jemalloc
 ac_add_options --enable-signmar
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
--- a/b2g/dev/config/mozconfigs/linux64/mulet
+++ b/b2g/dev/config/mozconfigs/linux64/mulet
@@ -1,10 +1,9 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 MOZ_AUTOMATION_UPDATE_PACKAGING=0
-MOZ_AUTOMATION_SDK=0
 . "$topsrcdir/browser/config/mozconfigs/linux64/nightly"
 
 ac_add_options --enable-application=b2g/dev
 
 # Include Firefox OS fonts.
 MOZTTDIR=$topsrcdir/moz-tt
--- a/b2g/dev/config/mozconfigs/linux64/mulet-hazards
+++ b/b2g/dev/config/mozconfigs/linux64/mulet-hazards
@@ -1,12 +1,11 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 MOZ_AUTOMATION_UPDATE_PACKAGING=0
-MOZ_AUTOMATION_SDK=0
 . "$topsrcdir/browser/config/mozconfigs/linux64/nightly"
 
 ac_add_options --enable-application=b2g/dev
 ac_add_options --with-compiler-wrapper=$TOOLTOOL_DIR/sixgill/usr/libexec/sixgill/scripts/wrap_gcc/basecc
 ac_add_options --without-ccache
 ac_add_options --disable-warnings-as-errors
 
 # Include Firefox OS fonts.
--- a/b2g/dev/config/mozconfigs/linux64/mulet_dbg
+++ b/b2g/dev/config/mozconfigs/linux64/mulet_dbg
@@ -1,12 +1,11 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 MOZ_AUTOMATION_UPDATE_PACKAGING=0
-MOZ_AUTOMATION_SDK=0
 . "$topsrcdir/browser/config/mozconfigs/linux64/nightly"
 
 ac_add_options --enable-application=b2g/dev
 ac_add_options --enable-debug
 MOZ_DEMANGLE_SYMBOLS=1
 MOZ_DEBUG=1
 MOZ_DEBUG_SYMBOLS=1
 
--- a/b2g/dev/config/mozconfigs/macosx64/mulet
+++ b/b2g/dev/config/mozconfigs/macosx64/mulet
@@ -1,13 +1,12 @@
 MOZ_AUTOMATION_BUILD_SYMBOLS=0
 MOZ_AUTOMATION_PACKAGE_TESTS=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 MOZ_AUTOMATION_UPDATE_PACKAGING=0
-MOZ_AUTOMATION_SDK=0
 . $topsrcdir/build/macosx/mozconfig.common
 
 ac_add_options --enable-application=b2g/dev
 ac_add_options --disable-install-strip
 ac_add_options --enable-signmar
 ac_add_options --enable-profiling
 ac_add_options --enable-instruments
 ac_add_options --enable-dtrace
--- a/b2g/dev/config/mozconfigs/win32/mulet
+++ b/b2g/dev/config/mozconfigs/win32/mulet
@@ -1,13 +1,12 @@
 MOZ_AUTOMATION_BUILD_SYMBOLS=0
 MOZ_AUTOMATION_L10N_CHECK=0
 MOZ_AUTOMATION_PACKAGE_TESTS=0
 MOZ_AUTOMATION_INSTALLER=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 MOZ_AUTOMATION_UPDATE_PACKAGING=0
-MOZ_AUTOMATION_SDK=0
 . "$topsrcdir/browser/config/mozconfigs/win32/nightly"
 
 ac_add_options --enable-application=b2g/dev
 
 # Include Firefox OS fonts.
 MOZTTDIR=$topsrcdir/moz-tt
--- a/b2g/graphene/config/horizon-mozconfigs/common
+++ b/b2g/graphene/config/horizon-mozconfigs/common
@@ -1,17 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # Disable the l10n-check target, which isn't relevant to b2g builds at all.
 # This needs to be set prior to the next include for it to take effect.
 MOZ_AUTOMATION_PACKAGE_TESTS=0
 MOZ_AUTOMATION_L10N_CHECK=0
-MOZ_AUTOMATION_SDK=0
 
 . "$topsrcdir/build/mozconfig.common"
 
 # Normally, we'd set this unconditionally, but this file is also used
 # for local builds and there is no other mozconfig in this tree that
 # is included on device builds.
 if test -d $topsrcdir/../gcc/bin; then
     HOST_CC="$topsrcdir/../gcc/bin/gcc"
--- a/b2g/graphene/config/mozconfigs/common
+++ b/b2g/graphene/config/mozconfigs/common
@@ -1,17 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # Disable the l10n-check target, which isn't relevant to b2g builds at all.
 # This needs to be set prior to the next include for it to take effect.
 MOZ_AUTOMATION_PACKAGE_TESTS=0
 MOZ_AUTOMATION_L10N_CHECK=0
-MOZ_AUTOMATION_SDK=0
 
 . "$topsrcdir/build/mozconfig.common"
 
 # Normally, we'd set this unconditionally, but this file is also used
 # for local builds and there is no other mozconfig in this tree that
 # is included on device builds.
 if test -d $topsrcdir/../gcc/bin; then
     HOST_CC="$topsrcdir/../gcc/bin/gcc"
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1010,16 +1010,18 @@ pref("security.sandbox.content.level", 1
 //
 // So the purpose of this setting is to allow nightly users to disable the
 // sandbox while we fix their problems. This way, they won't have to wait for
 // another nightly release which disables seccomp-bpf again.
 //
 // This setting may not be required anymore once we decide to permanently
 // enable the content sandbox.
 pref("security.sandbox.content.level", 2);
+pref("security.sandbox.content.write_path_whitelist", "");
+pref("security.sandbox.content.syscall_whitelist", "");
 #endif
 
 #if defined(XP_MACOSX) || defined(XP_WIN)
 #if defined(MOZ_SANDBOX) && defined(MOZ_CONTENT_SANDBOX)
 // ID (a UUID when set by gecko) that is used to form the name of a
 // sandbox-writable temporary directory to be used by content processes
 // when a temporary writable file is required in a level 1 sandbox.
 pref("security.sandbox.content.tempDirSuffix", "");
--- a/browser/base/content/aboutNetError.xhtml
+++ b/browser/base/content/aboutNetError.xhtml
@@ -227,17 +227,17 @@
         }
 
         if (err == "weakCryptoUsed") {
           document.body.className = "certerror";
         }
 
         // remove undisplayed errors to avoid bug 39098
         var errContainer = document.getElementById("errorContainer");
-        errContainer.parentNode.removeChild(errContainer);
+        errContainer.remove();
 
         var className = getCSSClass();
         if (className && className != "expertBadCert") {
           // Associate a CSS class with the root of the page, if one was passed in,
           // to allow custom styling.
           // Not "expertBadCert" though, don't want to deal with the favicon
           document.documentElement.className = className;
 
--- a/browser/base/content/blockedSite.xhtml
+++ b/browser/base/content/blockedSite.xhtml
@@ -92,50 +92,50 @@
           default:
             return;
         }
 
         var el;
 
         if (error !== "malware") {
           el = document.getElementById("errorTitleText_malware");
-          el.parentNode.removeChild(el);
+          el.remove();
           el = document.getElementById("errorShortDescText_malware");
-          el.parentNode.removeChild(el);
+          el.remove();
           el = document.getElementById("errorLongDescText_malware");
-          el.parentNode.removeChild(el);
+          el.remove();
         }
 
         if (error !== "phishing") {
           el = document.getElementById("errorTitleText_phishing");
-          el.parentNode.removeChild(el);
+          el.remove();
           el = document.getElementById("errorShortDescText_phishing");
-          el.parentNode.removeChild(el);
+          el.remove();
           el = document.getElementById("errorLongDescText_phishing");
-          el.parentNode.removeChild(el);
+          el.remove();
         }
 
         if (error !== "unwanted") {
           el = document.getElementById("errorTitleText_unwanted");
-          el.parentNode.removeChild(el);
+          el.remove();
           el = document.getElementById("errorShortDescText_unwanted");
-          el.parentNode.removeChild(el);
+          el.remove();
           el = document.getElementById("errorLongDescText_unwanted");
-          el.parentNode.removeChild(el);
+          el.remove();
         }
 
         // Set sitename
         document.getElementById(error + "_sitename").textContent = getHostString();
         document.title = document.getElementById("errorTitleText_" + error)
                                  .innerHTML;
 
         if (!getOverride()) {
           var btn = document.getElementById("ignoreWarningButton");
           if (btn) {
-            btn.parentNode.removeChild(btn);
+            btn.remove();
           }
         }
 
         // Inform the test harness that we're done loading the page
         var event = new CustomEvent("AboutBlockedLoaded", {bubbles:true});
         document.dispatchEvent(event);
       }
     ]]></script>
--- a/browser/base/content/browser-gestureSupport.js
+++ b/browser/base/content/browser-gestureSupport.js
@@ -913,17 +913,17 @@ var gHistorySwipeAnimation = {
   /**
    * Removes the boxes.
    */
   _removeBoxes: function HSA__removeBoxes() {
     this._curBox = null;
     this._prevBox = null;
     this._nextBox = null;
     if (this._container)
-      this._container.parentNode.removeChild(this._container);
+      this._container.remove();
     this._container = null;
     this._boxWidth = -1;
     this._boxHeight = -1;
   },
 
   /**
    * Creates an element with a given identifier and tag name.
    *
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -653,17 +653,17 @@ var gPopupBlockerObserver = {
       aEvent.target.anchorNode.removeAttribute("open");
 
     this.isPopupHidingTick = true;
     setTimeout(() => this.isPopupHidingTick = false, 0);
 
     let item = aEvent.target.lastChild;
     while (item && item.getAttribute("observes") != "blockedPopupsSeparator") {
       let next = item.previousSibling;
-      item.parentNode.removeChild(item);
+      item.remove();
       item = next;
     }
   },
 
   showBlockedPopup(aEvent) {
     var target = aEvent.target;
     var popupReportIndex = target.getAttribute("popupReportIndex");
     let browser = target.popupReportBrowser;
@@ -2537,17 +2537,17 @@ function UpdateUrlbarSearchSplitterState
       splitter.setAttribute("resizebefore", "flex");
       splitter.setAttribute("resizeafter", "flex");
       splitter.setAttribute("skipintoolbarset", "true");
       splitter.setAttribute("overflows", "false");
       splitter.className = "chromeclass-toolbar-additional";
     }
     urlbar.parentNode.insertBefore(splitter, ibefore);
   } else if (splitter)
-    splitter.parentNode.removeChild(splitter);
+    splitter.remove();
 }
 
 function UpdatePageProxyState() {
   if (gURLBar && gURLBar.value != gLastValidURLStr)
     SetPageProxyState("invalid");
 }
 
 /**
--- a/browser/base/content/newtab/sites.js
+++ b/browser/base/content/newtab/sites.js
@@ -331,17 +331,17 @@ Site.prototype = {
     Services.telemetry.getHistogramById("NEWTAB_PAGE_SITE_CLICKED")
                       .add(aIndex);
   },
 
   _toggleLegalText: function(buttonClass, explanationTextClass) {
     let button = this._querySelector(buttonClass);
     if (button.hasAttribute("active")) {
       let explain = this._querySelector(explanationTextClass);
-      explain.parentNode.removeChild(explain);
+      explain.remove();
 
       button.removeAttribute("active");
     }
     else {
       let explain = document.createElementNS(HTML_NAMESPACE, "div");
       explain.className = explanationTextClass.slice(1); // Slice off the first character, '.'
       this.node.appendChild(explain);
 
--- a/browser/base/content/newtab/updater.js
+++ b/browser/base/content/newtab/updater.js
@@ -133,17 +133,17 @@ var gUpdater = {
         return;
 
       batch.push(new Promise(resolve => {
         // Fade out the to-be-removed site.
         gTransformation.hideSite(aSite, function () {
           let node = aSite.node;
 
           // Remove the site from the DOM.
-          node.parentNode.removeChild(node);
+          node.remove();
           resolve();
         });
       }));
     });
 
     Promise.all(batch).then(aCallback);
   },
 
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1701,18 +1701,19 @@
                 throw new Error("Cannot set an opener on a browser which should be remote!");
               }
               if (!isRemote && aBrowser.contentWindow.opener != aOptions.opener) {
                 throw new Error("Cannot change opener on an already non-remote browser!");
               }
             }
 
             // Abort if we're not going to change anything
+            let currentRemoteType = aBrowser.getAttribute("remoteType");
             if (isRemote == aShouldBeRemote && !aOptions.newFrameloader && !aOptions.freshProcess &&
-                (!isRemote || aBrowser.getAttribute("remoteType") == aOptions.remoteType) &&
+                (!isRemote || currentRemoteType == aOptions.remoteType) &&
                 !aBrowser.frameLoader.isFreshProcess) {
               return false;
             }
 
             let tab = this.getTabForBrowser(aBrowser);
             let evt = document.createEvent("Events");
             evt.initEvent("BeforeTabRemotenessChange", true, false);
             tab.dispatchEvent(evt);
@@ -1749,18 +1750,22 @@
               aBrowser.setAttribute("remote", "true");
               aBrowser.setAttribute("remoteType", aOptions.remoteType);
             } else {
               aBrowser.setAttribute("remote", "false");
               aBrowser.removeAttribute("remoteType");
             }
 
             // NB: This works with the hack in the browser constructor that
-            // turns this normal property into a field.
-            aBrowser.relatedBrowser = relatedBrowser;
+            // turns this normal property into a field. When switching remote
+            // type copying related browser would stop the switch and the
+            // previously related browser will no longer be relevant.
+            if (!aShouldBeRemote || currentRemoteType == aOptions.remoteType) {
+              aBrowser.relatedBrowser = relatedBrowser;
+            }
 
             if (aOptions.opener) {
               // Set the opener window on the browser, such that when the frame
               // loader is created the opener is set correctly.
               aBrowser.presetOpenerWindow(aOptions.opener);
             }
 
             // Set the freshProcess attribute so that the frameloader knows to
@@ -2760,17 +2765,17 @@
             // we alert the switcher in order to show a spinner instead.
             if (this._switcher) {
               this._switcher.onTabRemoved(aTab);
             }
 
             // This will unload the document. An unload handler could remove
             // dependant tabs, so it's important that the tabbrowser is now in
             // a consistent state (tab removed, tab positions updated, etc.).
-            browser.parentNode.removeChild(browser);
+            browser.remove();
 
             // Release the browser in case something is erroneously holding a
             // reference to the tab after its removal.
             this._tabForBrowser.delete(aTab.linkedBrowser);
             aTab.linkedBrowser = null;
 
             // As the browser is removed, the removal of a dependent document can
             // cause the whole window to close. So at this point, it's possible
--- a/browser/base/content/test/general/browser_accesskeys.js
+++ b/browser/base/content/test/general/browser_accesskeys.js
@@ -40,17 +40,17 @@ add_task(function *() {
 
   focusedId = yield performAccessKey("y");
   is(focusedId, "tab2button", "button accesskey in tab2");
 
   // Press the accesskey for the chrome element while the content document is focused.
   focusedId = yield performAccessKeyForChrome("z");
   is(focusedId, "chromebutton", "chromebutton accesskey");
 
-  newButton.parentNode.removeChild(newButton);
+  newButton.remove();
 
   gBrowser.removeTab(tab1);
   gBrowser.removeTab(tab2);
 });
 
 function childHandleFocus() {
   content.document.body.firstChild.addEventListener("focus", function focused(event) {
     let focusedElement = content.document.activeElement;
--- a/browser/base/content/test/plugins/browser_CTP_nonplugins.js
+++ b/browser/base/content/test/plugins/browser_CTP_nonplugins.js
@@ -29,30 +29,30 @@ add_task(function* () {
 
   // Test that the click-to-play notification is not shown for non-plugin object elements
   let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
   ok(popupNotification, "Test 1, Should have a click-to-play notification");
 
   let pluginRemovedPromise = waitForEvent(gBrowser.selectedBrowser, "PluginRemoved", null, true, true);
   yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
     let plugin = content.document.getElementById("secondtestA");
-    plugin.parentNode.removeChild(plugin);
+    plugin.remove();
     plugin = content.document.getElementById("secondtestB");
-    plugin.parentNode.removeChild(plugin);
+    plugin.remove();
 
     let image = content.document.createElement("object");
     image.type = "image/png";
     image.data = "moz.png";
     content.document.body.appendChild(image);
   });
   yield pluginRemovedPromise;
 
   popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
   ok(popupNotification, "Test 2, Should have a click-to-play notification");
 
   yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
     let plugin = content.document.getElementById("test");
-    plugin.parentNode.removeChild(plugin);
+    plugin.remove();
   });
 
   popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
   ok(popupNotification, "Test 3, Should still have a click-to-play notification");
 });
--- a/browser/base/content/test/popupNotifications/browser_popupNotification_2.js
+++ b/browser/base/content/test/popupNotifications/browser_popupNotification_2.js
@@ -161,17 +161,17 @@ var tests = [
       EventUtils.synthesizeMouse(button, 4, 4, {});
     },
     onShown(popup) {
       checkPopup(popup, this.notifyObj);
       dismissNotification(popup);
     },
     onHidden(popup) {
       this.notification.remove();
-      this.box.parentNode.removeChild(this.box);
+      this.box.remove();
     }
   },
   // Test that popupnotifications without popups have anchor icons shown
   { id: "Test#7",
     *run() {
       let notifyObj = new BasicNotification(this.id);
       notifyObj.anchorID = "geo-notification-icon";
       notifyObj.addOptions({neverShow: true});
--- a/browser/base/content/test/tabs/browser.ini
+++ b/browser/base/content/test/tabs/browser.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 support-files =
   dummy_page.html
 
+[browser_allow_process_switches_despite_related_browser.js]
 [browser_tabSpinnerProbe.js]
 skip-if = !e10s # Tab spinner is e10s only.
 [browser_tabSwitchPrintPreview.js]
 skip-if = os == 'mac'
 [browser_navigatePinnedTab.js]
 [browser_opened_file_tab_navigated_to_web.js]
 [browser_reload_deleted_file.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabs/browser_allow_process_switches_despite_related_browser.js
@@ -0,0 +1,32 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+
+const DUMMY_FILE = "dummy_page.html";
+
+// Test for bug 1328829.
+add_task(function* () {
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser,
+                                                        "data:text/html,Hi");
+  registerCleanupFunction(function* () {
+    yield BrowserTestUtils.removeTab(tab);
+  });
+
+  let promiseTab =
+    BrowserTestUtils.waitForNewTab(gBrowser, "view-source:data:text/html,Hi");
+  BrowserViewSource(tab.linkedBrowser);
+  let viewSourceTab = yield promiseTab;
+  registerCleanupFunction(function* () {
+    yield BrowserTestUtils.removeTab(viewSourceTab);
+  });
+
+
+  let dummyPage = getChromeDir(getResolvedURI(gTestPath));
+  dummyPage.append(DUMMY_FILE);
+  const uriString = Services.io.newFileURI(dummyPage).spec;
+
+  let viewSourceBrowser = viewSourceTab.linkedBrowser;
+  viewSourceBrowser.loadURI(uriString);
+  let href = yield BrowserTestUtils.browserLoaded(viewSourceBrowser);
+  is(href, uriString,
+    "Check file:// URI loads in a browser that was previously for view-source");
+});
--- a/browser/build.mk
+++ b/browser/build.mk
@@ -9,19 +9,16 @@ package:
 	@$(MAKE) -C browser/installer
 
 package-compare:
 	@$(MAKE) -C browser/installer package-compare
 
 stage-package:
 	@$(MAKE) -C browser/installer stage-package
 
-sdk:
-	@$(MAKE) -C browser/installer make-sdk
-
 install::
 	@$(MAKE) -C browser/installer install
 
 clean::
 	@$(MAKE) -C browser/installer clean
 
 distclean::
 	@$(MAKE) -C browser/installer distclean
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/ext-devtools-inspectedWindow.js
@@ -0,0 +1,64 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+/* global getDevToolsTargetForContext */
+
+Cu.import("resource://gre/modules/ExtensionUtils.jsm");
+
+const {
+  SpreadArgs,
+} = ExtensionUtils;
+
+extensions.registerSchemaAPI("devtools.inspectedWindow", "devtools_parent", context => {
+  const {
+    WebExtensionInspectedWindowFront,
+  } = require("devtools/shared/fronts/webextension-inspected-window");
+
+  // Lazily retrieve and store an inspectedWindow actor front per child context.
+  let waitForInspectedWindowFront;
+  async function getInspectedWindowFront() {
+    // If there is not yet a front instance, then a lazily cloned target for the context is
+    // retrieved using the DevtoolsParentContextsManager helper (which is an asynchronous operation,
+    // because the first time that the target has been cloned, it is not ready to be used to create
+    // the front instance until it is connected to the remote debugger successfully).
+    const clonedTarget = await getDevToolsTargetForContext(context);
+    return new WebExtensionInspectedWindowFront(clonedTarget.client, clonedTarget.form);
+  }
+
+  // TODO(rpl): retrive a more detailed callerInfo object, like the filename and
+  // lineNumber of the actual extension called, in the child process.
+  const callerInfo = {
+    addonId: context.extension.id,
+    url: context.extension.baseURI.spec,
+  };
+
+  return {
+    devtools: {
+      inspectedWindow: {
+        async eval(expression, options) {
+          if (!waitForInspectedWindowFront) {
+            waitForInspectedWindowFront = getInspectedWindowFront();
+          }
+
+          const front = await waitForInspectedWindowFront;
+          return front.eval(callerInfo, expression, options || {}).then(evalResult => {
+            // TODO(rpl): check for additional undocumented behaviors on chrome
+            // (e.g. if we should also print error to the console or set lastError?).
+            return new SpreadArgs([evalResult.value, evalResult.exceptionInfo]);
+          });
+        },
+        async reload(options) {
+          const {ignoreCache, userAgent, injectedScript} = options || {};
+
+          if (!waitForInspectedWindowFront) {
+            waitForInspectedWindowFront = getInspectedWindowFront();
+          }
+
+          const front = await waitForInspectedWindowFront;
+          front.reload(callerInfo, {ignoreCache, userAgent, injectedScript});
+        },
+      },
+    },
+  };
+});
--- a/browser/components/extensions/ext-theme.js
+++ b/browser/components/extensions/ext-theme.js
@@ -1,15 +1,19 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
                                   "resource://gre/modules/Preferences.jsm");
 
+let themeExtensions = new WeakSet();
+
 /* eslint-disable mozilla/balanced-listeners */
 extensions.on("manifest_theme", (type, directive, extension, manifest) => {
   let enabled = Preferences.get("extensions.webextensions.themes.enabled");
 
   if (!enabled || !manifest || !manifest.theme) {
     return;
   }
   // Apply theme only if themes are enabled.
@@ -45,18 +49,21 @@ extensions.on("manifest_theme", (type, d
         lwtStyles.headerURL = val;
       }
     }
   }
 
   if (lwtStyles.headerURL &&
       lwtStyles.accentcolor &&
       lwtStyles.textcolor) {
+    themeExtensions.add(extension);
     Services.obs.notifyObservers(null,
       "lightweight-theme-styling-update",
       JSON.stringify(lwtStyles));
   }
 });
 
 extensions.on("shutdown", (type, extension) => {
-  Services.obs.notifyObservers(null, "lightweight-theme-styling-update", null);
+  if (themeExtensions.has(extension)) {
+    Services.obs.notifyObservers(null, "lightweight-theme-styling-update", null);
+  }
 });
 /* eslint-enable mozilla/balanced-listeners */
--- a/browser/components/extensions/extensions-browser.manifest
+++ b/browser/components/extensions/extensions-browser.manifest
@@ -1,16 +1,17 @@
 # scripts
 category webextension-scripts bookmarks chrome://browser/content/ext-bookmarks.js
 category webextension-scripts browserAction chrome://browser/content/ext-browserAction.js
 category webextension-scripts browsingData chrome://browser/content/ext-browsingData.js
 category webextension-scripts commands chrome://browser/content/ext-commands.js
 category webextension-scripts contextMenus chrome://browser/content/ext-contextMenus.js
 category webextension-scripts desktop-runtime chrome://browser/content/ext-desktop-runtime.js
 category webextension-scripts devtools chrome://browser/content/ext-devtools.js
+category webextension-scripts devtools-inspectedWindow chrome://browser/content/ext-devtools-inspectedWindow.js
 category webextension-scripts history chrome://browser/content/ext-history.js
 category webextension-scripts omnibox chrome://browser/content/ext-omnibox.js
 category webextension-scripts pageAction chrome://browser/content/ext-pageAction.js
 category webextension-scripts sessions chrome://browser/content/ext-sessions.js
 category webextension-scripts tabs chrome://browser/content/ext-tabs.js
 category webextension-scripts theme chrome://browser/content/ext-theme.js
 category webextension-scripts url-overrides chrome://browser/content/ext-url-overrides.js
 category webextension-scripts utils chrome://browser/content/ext-utils.js
--- a/browser/components/extensions/jar.mn
+++ b/browser/components/extensions/jar.mn
@@ -14,16 +14,17 @@ browser.jar:
     content/browser/extension.svg
     content/browser/ext-bookmarks.js
     content/browser/ext-browserAction.js
     content/browser/ext-browsingData.js
     content/browser/ext-commands.js
     content/browser/ext-contextMenus.js
     content/browser/ext-desktop-runtime.js
     content/browser/ext-devtools.js
+    content/browser/ext-devtools-inspectedWindow.js
     content/browser/ext-history.js
     content/browser/ext-omnibox.js
     content/browser/ext-pageAction.js
     content/browser/ext-sessions.js
     content/browser/ext-tabs.js
     content/browser/ext-theme.js
     content/browser/ext-url-overrides.js
     content/browser/ext-utils.js
--- a/browser/components/extensions/schemas/devtools_inspected_window.json
+++ b/browser/components/extensions/schemas/devtools_inspected_window.json
@@ -88,17 +88,16 @@
       "tabId": {
         "description": "The ID of the tab being inspected. This ID may be used with chrome.tabs.* API.",
         "type": "integer"
       }
     },
     "functions": [
       {
         "name": "eval",
-        "unsupported": true,
         "type": "function",
         "description": "Evaluates a JavaScript expression in the context of the main frame of the inspected page. The expression must evaluate to a JSON-compliant object, otherwise an exception is thrown. The eval function can report either a DevTools-side error or a JavaScript exception that occurs during evaluation. In either case, the <code>result</code> parameter of the callback is <code>undefined</code>. In the case of a DevTools-side error, the <code>isException</code> parameter is non-null and has <code>isError</code> set to true and <code>code</code> set to an error code. In the case of a JavaScript error, <code>isException</code> is set to true and <code>value</code> is set to the string value of thrown object.",
         "async": "callback",
         "parameters": [
           {
             "name": "expression",
             "type": "string",
             "description": "An expression to evaluate."
@@ -174,17 +173,16 @@
                 }
               }
             ]
           }
         ]
       },
       {
         "name": "reload",
-        "unsupported": true,
         "type": "function",
         "description": "Reloads the inspected page.",
         "parameters": [
           {
             "type": "object",
             "name": "reloadOptions",
             "optional": true,
             "properties": {
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -12,16 +12,17 @@ support-files =
   file_popup_api_injection_b.html
   file_iframe_document.html
   file_iframe_document.sjs
   file_bypass_cache.sjs
   file_language_fr_en.html
   file_language_ja.html
   file_language_tlh.html
   file_dummy.html
+  file_inspectedwindow_reload_target.sjs
   file_serviceWorker.html
   serviceWorker.js
   searchSuggestionEngine.xml
   searchSuggestionEngine.sjs
   ../../../../../toolkit/components/extensions/test/mochitest/head_webrequest.js
 
 [browser_ext_browserAction_context.js]
 [browser_ext_browserAction_disabled.js]
@@ -45,16 +46,17 @@ support-files =
 [browser_ext_contextMenus_chrome.js]
 [browser_ext_contextMenus_icons.js]
 [browser_ext_contextMenus_onclick.js]
 [browser_ext_contextMenus_radioGroups.js]
 [browser_ext_contextMenus_uninstall.js]
 [browser_ext_contextMenus_urlPatterns.js]
 [browser_ext_currentWindow.js]
 [browser_ext_devtools_inspectedWindow.js]
+[browser_ext_devtools_inspectedWindow_reload.js]
 [browser_ext_devtools_page.js]
 [browser_ext_getViews.js]
 [browser_ext_incognito_views.js]
 [browser_ext_incognito_popup.js]
 [browser_ext_lastError.js]
 [browser_ext_omnibox.js]
 [browser_ext_optionsPage_privileges.js]
 [browser_ext_pageAction_context.js]
--- a/browser/components/extensions/test/browser/browser_ext_devtools_inspectedWindow.js
+++ b/browser/components/extensions/test/browser/browser_ext_devtools_inspectedWindow.js
@@ -10,16 +10,22 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 /**
  * this test file ensures that:
  *
  * - the devtools page gets only a subset of the runtime API namespace.
  * - devtools.inspectedWindow.tabId is the same tabId that we can retrieve
  *   in the background page using the tabs API namespace.
  * - devtools API is available in the devtools page sub-frames when a valid
  *   extension URL has been loaded.
+ * - devtools.inspectedWindow.eval:
+ *   - returns a serialized version of the evaluation result.
+ *   - returns the expected error object when the return value serialization raises a
+ *     "TypeError: cyclic object value" exception.
+ *   - returns the expected exception when an exception has been raised from the evaluated
+ *     javascript code.
  */
 add_task(function* test_devtools_inspectedWindow_tabId() {
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/");
 
   async function background() {
     browser.test.assertEq(undefined, browser.devtools,
                           "No devtools APIs should be available in the background page");
 
@@ -103,8 +109,130 @@ add_task(function* test_devtools_inspect
   yield gDevTools.closeToolbox(target);
 
   yield target.destroy();
 
   yield extension.unload();
 
   yield BrowserTestUtils.removeTab(tab);
 });
+
+add_task(function* test_devtools_inspectedWindow_eval() {
+  const TEST_TARGET_URL = "http://mochi.test:8888/";
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_TARGET_URL);
+
+  function devtools_page() {
+    browser.test.onMessage.addListener(async (msg, ...args) => {
+      if (msg !== "inspectedWindow-eval-request") {
+        browser.test.fail(`Unexpected test message received: ${msg}`);
+        return;
+      }
+
+      try {
+        const [evalResult, errorResult] = await browser.devtools.inspectedWindow.eval(...args);
+        browser.test.sendMessage("inspectedWindow-eval-result", {
+          evalResult,
+          errorResult,
+        });
+      } catch (err) {
+        browser.test.sendMessage("inspectedWindow-eval-result");
+        browser.test.fail(`Error: ${err} :: ${err.stack}`);
+      }
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      devtools_page: "devtools_page.html",
+    },
+    files: {
+      "devtools_page.html": `<!DOCTYPE html>
+      <html>
+       <head>
+         <meta charset="utf-8">
+         <script text="text/javascript" src="devtools_page.js"></script>
+       </head>
+       <body>
+       </body>
+      </html>`,
+      "devtools_page.js": devtools_page,
+    },
+  });
+
+  yield extension.startup();
+
+  let target = devtools.TargetFactory.forTab(tab);
+
+  yield gDevTools.showToolbox(target, "webconsole");
+  info("developer toolbox opened");
+
+  const evalTestCases = [
+    // Successful evaluation results.
+    {
+      args: ["window.location.href"],
+      expectedResults: {evalResult: TEST_TARGET_URL, errorResult: undefined},
+    },
+
+    // Error evaluation results.
+    {
+      args: ["window"],
+      expectedResults: {
+        evalResult: undefined,
+        errorResult: {
+          isError: true,
+          code: "E_PROTOCOLERROR",
+          description: "Inspector protocol error: %s",
+          details: [
+            "TypeError: cyclic object value",
+          ],
+        },
+      },
+    },
+
+    // Exception evaluation results.
+    {
+      args: ["throw new Error('fake eval exception');"],
+      expectedResults: {
+        evalResult: undefined,
+        errorResult: {
+          isException: true,
+          value: /Error: fake eval exception\n.*moz-extension:\/\//,
+        },
+      },
+
+    },
+  ];
+
+  for (let testCase of evalTestCases) {
+    info(`test inspectedWindow.eval with ${JSON.stringify(testCase)}`);
+
+    const {args, expectedResults} = testCase;
+
+    extension.sendMessage(`inspectedWindow-eval-request`, ...args);
+
+    const {evalResult, errorResult} = yield extension.awaitMessage(`inspectedWindow-eval-result`);
+
+    Assert.deepEqual(evalResult, expectedResults.evalResult, "Got the expected eval result");
+
+    if (errorResult) {
+      for (const errorPropName of Object.keys(expectedResults.errorResult)) {
+        const expected = expectedResults.errorResult[errorPropName];
+        const actual = errorResult[errorPropName];
+
+        if (expected instanceof RegExp) {
+          ok(expected.test(actual),
+             `Got exceptionInfo.${errorPropName} value ${actual} matches ${expected}`);
+        } else {
+          Assert.deepEqual(actual, expected,
+                           `Got the expected exceptionInfo.${errorPropName} value`);
+        }
+      }
+    }
+  }
+
+  yield gDevTools.closeToolbox(target);
+
+  yield target.destroy();
+
+  yield extension.unload();
+
+  yield BrowserTestUtils.removeTab(tab);
+});
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_devtools_inspectedWindow_reload.js
@@ -0,0 +1,336 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+// Like most of the mochitest-browser devtools test,
+// on debug test slave, it takes about 50s to run the test.
+requestLongerTimeout(4);
+
+XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
+                                  "resource://devtools/client/framework/gDevTools.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "devtools",
+                                  "resource://devtools/shared/Loader.jsm");
+
+// Small helper which provides the common steps to the following reload test cases.
+function* runReloadTestCase({urlParams, background, devtoolsPage, testCase}) {
+  const BASE = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/";
+  const TEST_TARGET_URL = `${BASE}file_inspectedwindow_reload_target.sjs?${urlParams}`;
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_TARGET_URL);
+
+  let extension = ExtensionTestUtils.loadExtension({
+    background,
+    manifest: {
+      devtools_page: "devtools_page.html",
+      permissions: ["webNavigation", "<all_urls>"],
+    },
+    files: {
+      "devtools_page.html": `<!DOCTYPE html>
+      <html>
+       <head>
+         <meta charset="utf-8">
+         <script type="text/javascript" src="devtools_page.js"></script>
+       </head>
+       <body>
+       </body>
+      </html>`,
+      "devtools_page.js": devtoolsPage,
+    },
+  });
+
+  yield extension.startup();
+
+  let target = devtools.TargetFactory.forTab(tab);
+
+  yield gDevTools.showToolbox(target, "webconsole");
+  info("developer toolbox opened");
+
+  // Wait the test extension to be ready.
+  yield extension.awaitMessage("devtools_inspected_window_reload.ready");
+
+  info("devtools page ready");
+
+  // Run the test case.
+  yield testCase(extension);
+
+  yield gDevTools.closeToolbox(target);
+
+  yield target.destroy();
+
+  yield BrowserTestUtils.removeTab(tab);
+
+  yield extension.unload();
+}
+
+add_task(function* test_devtools_inspectedWindow_reload_ignore_cache() {
+  function background() {
+    // Wait until the devtools page is ready to run the test.
+    browser.runtime.onMessage.addListener(async (msg) => {
+      if (msg !== "devtools_page.ready") {
+        browser.test.fail(`Unexpected message received: ${msg}`);
+        return;
+      }
+
+      const tabs = await browser.tabs.query({active: true});
+      const activeTabId = tabs[0].id;
+      let reloads = 0;
+
+      browser.webNavigation.onCompleted.addListener(async (details) => {
+        if (details.tabId == activeTabId && details.frameId == 0) {
+          reloads++;
+
+          // This test expects two `devtools.inspectedWindow.reload` calls:
+          // the first one without any options and the second one with
+          // `ignoreCache=true`.
+          let expectedContent;
+          let enabled;
+
+          switch (reloads) {
+            case 1:
+              enabled = false;
+              expectedContent = "empty cache headers";
+              break;
+            case 2:
+              enabled = true;
+              expectedContent = "no-cache:no-cache";
+              break;
+          }
+
+          if (!expectedContent) {
+            browser.test.fail(`Unexpected number of tab reloads: ${reloads}`);
+          } else {
+            try {
+              const code = `document.body.textContent`;
+              const [text] = await browser.tabs.executeScript(activeTabId, {code});
+
+              browser.test.assertEq(text, expectedContent,
+                                    `Got the expected cache headers with ignoreCache=${enabled}`);
+            } catch (err) {
+              browser.test.fail(`Error: ${err.message} - ${err.stack}`);
+            }
+          }
+
+          browser.test.sendMessage("devtools_inspectedWindow_reload_checkIgnoreCache.done");
+        }
+      });
+
+      browser.test.sendMessage("devtools_inspected_window_reload.ready");
+    });
+  }
+
+  async function devtoolsPage() {
+    browser.test.onMessage.addListener(msg => {
+      switch (msg) {
+        case "no-ignore-cache":
+          browser.devtools.inspectedWindow.reload();
+          break;
+        case "ignore-cache":
+          browser.devtools.inspectedWindow.reload({ignoreCache: true});
+          break;
+        default:
+          browser.test.fail(`Unexpected test message received: ${msg}`);
+      }
+    });
+
+    browser.runtime.sendMessage("devtools_page.ready");
+  }
+
+  yield runReloadTestCase({
+    urlParams: "test=cache",
+    background, devtoolsPage,
+    testCase: function* (extension) {
+      for (const testMessage of ["no-ignore-cache", "ignore-cache"]) {
+        extension.sendMessage(testMessage);
+        yield extension.awaitMessage("devtools_inspectedWindow_reload_checkIgnoreCache.done");
+      }
+    },
+  });
+});
+
+add_task(function* test_devtools_inspectedWindow_reload_custom_user_agent() {
+  function background() {
+    browser.runtime.onMessage.addListener(async (msg) => {
+      if (msg !== "devtools_page.ready") {
+        browser.test.fail(`Unexpected message received: ${msg}`);
+        return;
+      }
+
+      const tabs = await browser.tabs.query({active: true});
+      const activeTabId = tabs[0].id;
+      let reloads = 0;
+
+      browser.webNavigation.onCompleted.addListener(async (details) => {
+        if (details.tabId == activeTabId && details.frameId == 0) {
+          reloads++;
+
+          let expectedContent;
+          let enabled;
+
+          switch (reloads) {
+            case 1:
+              enabled = false;
+              expectedContent = window.navigator.userAgent;
+              break;
+            case 2:
+              enabled = true;
+              expectedContent = "CustomizedUserAgent";
+              break;
+          }
+
+          if (!expectedContent) {
+            browser.test.fail(`Unexpected number of tab reloads: ${reloads}`);
+          } else {
+            const code = `document.body.textContent`;
+            try {
+              const [text] = await browser.tabs.executeScript(activeTabId, {code});
+              browser.test.assertEq(expectedContent, text,
+                                      `Got the expected userAgent with userAgent=${enabled}`);
+            } catch (err) {
+              browser.test.fail(`Error: ${err.message} - ${err.stack}`);
+            }
+          }
+
+          browser.test.sendMessage("devtools_inspectedWindow_reload_checkUserAgent.done");
+        }
+      });
+
+      browser.test.sendMessage("devtools_inspected_window_reload.ready");
+    });
+  }
+
+  function devtoolsPage() {
+    browser.test.onMessage.addListener(msg => {
+      switch (msg) {
+        case "no-custom-user-agent":
+          browser.devtools.inspectedWindow.reload({});
+          break;
+        case "custom-user-agent":
+          browser.devtools.inspectedWindow.reload({userAgent: "CustomizedUserAgent"});
+          break;
+        default:
+          browser.test.fail(`Unexpected test message received: ${msg}`);
+      }
+    });
+
+    browser.runtime.sendMessage("devtools_page.ready");
+  }
+
+  yield runReloadTestCase({
+    urlParams: "test=user-agent",
+    background, devtoolsPage,
+    testCase: function* (extension) {
+      extension.sendMessage("no-custom-user-agent");
+
+      yield extension.awaitMessage("devtools_inspectedWindow_reload_checkUserAgent.done");
+
+      extension.sendMessage("custom-user-agent");
+
+      yield extension.awaitMessage("devtools_inspectedWindow_reload_checkUserAgent.done");
+    },
+  });
+});
+
+add_task(function* test_devtools_inspectedWindow_reload_injected_script() {
+  function background() {
+    function getIframesTextContent() {
+      let docs = [];
+      for (let iframe, doc = document; doc; doc = iframe && iframe.contentDocument) {
+        docs.push(doc);
+        iframe = doc.querySelector("iframe");
+      }
+
+      return docs.map(doc => doc.querySelector("pre").textContent);
+    }
+
+    browser.runtime.onMessage.addListener(async (msg) => {
+      if (msg !== "devtools_page.ready") {
+        browser.test.fail(`Unexpected message received: ${msg}`);
+        return;
+      }
+
+      const tabs = await browser.tabs.query({active: true});
+      const activeTabId = tabs[0].id;
+      let reloads = 0;
+
+      browser.webNavigation.onCompleted.addListener(async (details) => {
+        if (details.tabId == activeTabId && details.frameId == 0) {
+          reloads++;
+
+          let expectedContent;
+          let enabled;
+
+          switch (reloads) {
+            case 1:
+              enabled = false;
+              expectedContent = "injected script NOT executed";
+              break;
+            case 2:
+              enabled = true;
+              expectedContent = "injected script executed first";
+              break;
+            default:
+              browser.test.fail(`Unexpected number of tab reloads: ${reloads}`);
+          }
+
+          if (!expectedContent) {
+            browser.test.fail(`Unexpected number of tab reloads: ${reloads}`);
+          } else {
+            let expectedResults = (new Array(4)).fill(expectedContent);
+            let code = `(${getIframesTextContent})()`;
+
+            try {
+              let [results] = await browser.tabs.executeScript(activeTabId, {code});
+
+              browser.test.assertEq(JSON.stringify(expectedResults), JSON.stringify(results),
+                                    `Got the expected result with injectScript=${enabled}`);
+            } catch (err) {
+              browser.test.fail(`Error: ${err.message} - ${err.stack}`);
+            }
+          }
+
+          browser.test.sendMessage(`devtools_inspectedWindow_reload_injectedScript.done`);
+        }
+      });
+
+      browser.test.sendMessage("devtools_inspected_window_reload.ready");
+    });
+  }
+
+  function devtoolsPage() {
+    function injectedScript() {
+      if (!window.pageScriptExecutedFirst) {
+        window.addEventListener("DOMContentLoaded", function listener() {
+          document.querySelector("pre").textContent = "injected script executed first";
+        }, {once: true});
+      }
+    }
+
+    browser.test.onMessage.addListener(msg => {
+      switch (msg) {
+        case "no-injected-script":
+          browser.devtools.inspectedWindow.reload({});
+          break;
+        case "injected-script":
+          browser.devtools.inspectedWindow.reload({injectedScript: `new ${injectedScript}`});
+          break;
+        default:
+          browser.test.fail(`Unexpected test message received: ${msg}`);
+      }
+    });
+
+    browser.runtime.sendMessage("devtools_page.ready");
+  }
+
+  yield runReloadTestCase({
+    urlParams: "test=injected-script&frames=3",
+    background, devtoolsPage,
+    testCase: function* (extension) {
+      extension.sendMessage("no-injected-script");
+
+      yield extension.awaitMessage("devtools_inspectedWindow_reload_injectedScript.done");
+
+      extension.sendMessage("injected-script");
+
+      yield extension.awaitMessage("devtools_inspectedWindow_reload_injectedScript.done");
+    },
+  });
+});
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/file_inspectedwindow_reload_target.sjs
@@ -0,0 +1,74 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80 ft=javascript: */
+"use strict";
+
+Components.utils.importGlobalProperties(["URLSearchParams"]);
+
+function handleRequest(request, response) {
+  let params = new URLSearchParams(request.queryString);
+
+  switch(params.get("test")) {
+    case "cache":
+      handleCacheTestRequest(request, response);
+      break;
+
+    case "user-agent":
+      handleUserAgentTestRequest(request, response);
+      break;
+
+    case "injected-script":
+      handleInjectedScriptTestRequest(request, response, params);
+      break;
+  }
+}
+
+function handleCacheTestRequest(request, response) {
+  response.setHeader("Content-Type", "text/plain; charset=UTF-8", false);
+
+  if (request.hasHeader("pragma") && request.hasHeader("cache-control")) {
+    response.write(`${request.getHeader("pragma")}:${request.getHeader("cache-control")}`);
+  } else {
+    response.write("empty cache headers");
+  }
+}
+
+function handleUserAgentTestRequest(request, response) {
+  response.setHeader("Content-Type", "text/plain; charset=UTF-8", false);
+
+  if (request.hasHeader("user-agent")) {
+    response.write(request.getHeader("user-agent"));
+  } else {
+    response.write("no user agent header");
+  }
+}
+
+function handleInjectedScriptTestRequest(request, response, params) {
+  response.setHeader("Content-Type", "text/html; charset=UTF-8", false);
+
+  let content = "";
+  const frames = parseInt(params.get("frames"));
+  if (frames > 0) {
+    // Output an iframe in seamless mode, so that there is an higher chance that in case
+    // of test failures we get a screenshot where the nested iframes are all visible.
+    content = `<iframe seamless src="?test=injected-script&frames=${frames - 1}"></iframe>`;
+  }
+
+  response.write(`<!DOCTYPE html>
+    <html>
+      <head>
+       <meta charset="utf-8">
+       <style>
+         iframe { width: 100%; height: ${frames * 150}px; }
+       </style>
+      </head>
+      <body>
+       <h1>IFRAME ${frames}</h1>
+       <pre>injected script NOT executed</pre>
+       <script type="text/javascript">
+         window.pageScriptExecutedFirst = true;
+       </script>
+       ${content}
+      </body>
+    </html>
+  `);
+}
\ No newline at end of file
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -281,17 +281,17 @@ PlacesViewBase.prototype = {
 
   _removeChild: function PVB__removeChild(aChild) {
     // If document.popupNode pointed to this child, null it out,
     // otherwise controller's command-updating may rely on the removed
     // item still being "selected".
     if (document.popupNode == aChild)
       document.popupNode = null;
 
-    aChild.parentNode.removeChild(aChild);
+    aChild.remove();
   },
 
   _setEmptyPopupStatus:
   function PVB__setEmptyPopupStatus(aPopup, aEmpty) {
     if (!aPopup._emptyMenuitem) {
       let label = PlacesUIUtils.getString("bookmarksMenuEmptyFolder");
       aPopup._emptyMenuitem = document.createElement("menuitem");
       aPopup._emptyMenuitem.setAttribute("label", label);
--- a/browser/components/preferences/SiteDataManager.jsm
+++ b/browser/components/preferences/SiteDataManager.jsm
@@ -3,16 +3,18 @@
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "OfflineAppCacheHelper",
                                   "resource:///modules/offlineAppCache.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
+                                  "resource://gre/modules/ContextualIdentityService.jsm");
 
 this.EXPORTED_SYMBOLS = [
   "SiteDataManager"
 ];
 
 this.SiteDataManager = {
 
   _qms: Services.qms,
@@ -24,16 +26,17 @@ this.SiteDataManager = {
   // A Map of sites using the persistent-storage API (have requested persistent-storage permission)
   // Key is site's origin.
   // Value is one object holding:
   //   - perm: persistent-storage permision; instance of nsIPermission
   //   - status: the permission granted/rejected status
   //   - quotaUsage: the usage of indexedDB and localStorage.
   //   - appCacheList: an array of app cache; instances of nsIApplicationCache
   //   - diskCacheList: an array. Each element is object holding metadata of http cache:
+  //       - uri: the uri of that http cache
   //       - dataSize: that http cache size
   //       - idEnhance: the id extension of that http cache
   _sites: new Map(),
 
   _updateQuotaPromise: null,
 
   _updateDiskCachePromise: null,
 
@@ -48,17 +51,17 @@ this.SiteDataManager = {
     let perm = null;
     let status = null;
     let e = Services.perms.enumerator;
     while (e.hasMoreElements()) {
       perm = e.getNext();
       status = Services.perms.testExactPermissionFromPrincipal(perm.principal, "persistent-storage");
       if (status === Ci.nsIPermissionManager.ALLOW_ACTION ||
           status === Ci.nsIPermissionManager.DENY_ACTION) {
-        this._sites.set(perm.principal.origin, {
+        this._sites.set(perm.principal.URI.spec, {
           perm,
           status,
           quotaUsage: 0,
           appCacheList: [],
           diskCacheList: []
         });
       }
     }
@@ -120,16 +123,17 @@ this.SiteDataManager = {
     this._updateDiskCachePromise = new Promise(resolve => {
       if (this._sites.size) {
         let sites = this._sites;
         let visitor = {
           onCacheEntryInfo(uri, idEnhance, dataSize) {
             for (let site of sites.values()) {
               if (site.perm.matchesURI(uri, true)) {
                 site.diskCacheList.push({
+                  uri,
                   dataSize,
                   idEnhance
                 });
                 break;
               }
             }
           },
           onCacheEntryVisitCompleted() {
@@ -156,35 +160,16 @@ this.SiteDataManager = {
                         usage += cache.dataSize;
                       }
                       usage += site.quotaUsage;
                     }
                     return usage;
                   });
   },
 
-  _removePermission(site) {
-    Services.perms.removePermission(site.perm);
-  },
-
-  _removeQuotaUsage(site) {
-    this._qms.clearStoragesForPrincipal(site.perm.principal, null, true);
-  },
-
-  removeAll() {
-    for (let site of this._sites.values()) {
-      this._removePermission(site);
-      this._removeQuotaUsage(site);
-    }
-    Services.cache2.clear();
-    Services.cookies.removeAll();
-    OfflineAppCacheHelper.clear();
-    this.updateSites();
-  },
-
   getSites() {
     return Promise.all([this._updateQuotaPromise, this._updateDiskCachePromise])
                   .then(() => {
                     let list = [];
                     for (let [origin, site] of this._sites) {
                       let cache = null;
                       let usage = site.quotaUsage;
                       for (cache of site.appCacheList) {
@@ -196,10 +181,75 @@ this.SiteDataManager = {
                       list.push({
                         usage,
                         status: site.status,
                         uri: NetUtil.newURI(origin)
                       });
                     }
                     return list;
                   });
+  },
+
+  _removePermission(site) {
+    Services.perms.removePermission(site.perm);
+  },
+
+  _removeQuotaUsage(site) {
+    this._qms.clearStoragesForPrincipal(site.perm.principal, null, true);
+  },
+
+  _removeDiskCache(site) {
+    for (let cache of site.diskCacheList) {
+      this._diskCache.asyncDoomURI(cache.uri, cache.idEnhance, null);
+    }
+  },
+
+  _removeAppCache(site) {
+    for (let cache of site.appCacheList) {
+      cache.discard();
+    }
+  },
+
+  _removeCookie(site) {
+    let host = site.perm.principal.URI.host;
+    let e = Services.cookies.getCookiesFromHost(host, {});
+    while (e.hasMoreElements()) {
+      let cookie = e.getNext();
+      if (cookie instanceof Components.interfaces.nsICookie) {
+        if (this.isPrivateCookie(cookie)) {
+          continue;
+        }
+        Services.cookies.remove(
+          cookie.host, cookie.name, cookie.path, false, cookie.originAttributes);
+      }
+    }
+  },
+
+  remove(uris) {
+    for (let uri of uris) {
+      let site = this._sites.get(uri.spec);
+      if (site) {
+        this._removePermission(site);
+        this._removeQuotaUsage(site);
+        this._removeDiskCache(site);
+        this._removeAppCache(site);
+        this._removeCookie(site);
+      }
+    }
+    this.updateSites();
+  },
+
+  removeAll() {
+    for (let site of this._sites.values()) {
+      this._removePermission(site);
+      this._removeQuotaUsage(site);
+    }
+    Services.cache2.clear();
+    Services.cookies.removeAll();
+    OfflineAppCacheHelper.clear();
+    this.updateSites();
+  },
+
+  isPrivateCookie(cookie) {
+    let { userContextId } = cookie.originAttributes;
+    return userContextId && !ContextualIdentityService.getIdentityFromId(userContextId).public;
   }
 };
--- a/browser/components/preferences/cookies.js
+++ b/browser/components/preferences/cookies.js
@@ -5,16 +5,18 @@
 
 const nsICookie = Components.interfaces.nsICookie;
 
 Components.utils.import("resource://gre/modules/AppConstants.jsm");
 Components.utils.import("resource://gre/modules/PluralForm.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm")
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "SiteDataManager",
+                                  "resource:///modules/SiteDataManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
                                   "resource://gre/modules/ContextualIdentityService.jsm");
 
 var gCookiesWindow = {
   _cm               : Components.classes["@mozilla.org/cookiemanager;1"]
                                 .getService(Components.interfaces.nsICookieManager),
   _hosts            : {},
   _hostOrder        : [],
@@ -71,31 +73,22 @@ var gCookiesWindow = {
   _cookieEquals(aCookieA, aCookieB, aStrippedHost) {
     return aCookieA.rawHost == aStrippedHost &&
            aCookieA.name == aCookieB.name &&
            aCookieA.path == aCookieB.path &&
            ChromeUtils.isOriginAttributesEqual(aCookieA.originAttributes,
                                                aCookieB.originAttributes);
   },
 
-  _isPrivateCookie(aCookie) {
-      let { userContextId } = aCookie.originAttributes;
-      if (!userContextId) {
-        // Default identity is public.
-        return false;
-      }
-      return !ContextualIdentityService.getIdentityFromId(userContextId).public;
-  },
-
   observe(aCookie, aTopic, aData) {
     if (aTopic != "cookie-changed")
       return;
 
     if (aCookie instanceof Components.interfaces.nsICookie) {
-      if (this._isPrivateCookie(aCookie)) {
+      if (SiteDataManager.isPrivateCookie(aCookie)) {
         return;
       }
 
       var strippedHost = this._makeStrippedHost(aCookie.host);
       if (aData == "changed")
         this._handleCookieChanged(aCookie, strippedHost);
       else if (aData == "added")
         this._handleCookieAdded(aCookie, strippedHost);
@@ -479,17 +472,17 @@ var gCookiesWindow = {
   _loadCookies() {
     var e = this._cm.enumerator;
     var hostCount = { value: 0 };
     this._hosts = {};
     this._hostOrder = [];
     while (e.hasMoreElements()) {
       var cookie = e.getNext();
       if (cookie && cookie instanceof Components.interfaces.nsICookie) {
-        if (this._isPrivateCookie(cookie)) {
+        if (SiteDataManager.isPrivateCookie(cookie)) {
           continue;
         }
 
         var strippedHost = this._makeStrippedHost(cookie.host);
         this._addCookie(strippedHost, cookie, hostCount);
       } else
         break;
     }
--- a/browser/components/preferences/in-content/search.js
+++ b/browser/components/preferences/in-content/search.js
@@ -392,19 +392,19 @@ EngineStore.prototype = {
     }
 
     let engineName = aEngine.name;
     let index = this._engines.findIndex(element => element.name == engineName);
 
     if (index == -1)
       throw new Error("invalid engine?");
 
-    this._engines.splice(index, 1);
+    let removedEngine = this._engines.splice(index, 1)[0];
 
-    if (this._defaultEngines.some(this._isSameEngine, this._engines[index]))
+    if (this._defaultEngines.some(this._isSameEngine, removedEngine))
       gSearchPane.showRestoreDefaults(true);
     gSearchPane.buildDefaultEngineDropDown();
     return index;
   },
 
   restoreDefaultEngines() {
     var added = 0;
 
old mode 100644
new mode 100755
--- a/browser/components/preferences/in-content/tests/browser_advanced_siteData.js
+++ b/browser/components/preferences/in-content/tests/browser_advanced_siteData.js
@@ -110,16 +110,22 @@ const mockSiteDataManager = {
 };
 
 function addPersistentStoragePerm(origin) {
   let uri = NetUtil.newURI(origin);
   let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
   Services.perms.addFromPrincipal(principal, "persistent-storage", Ci.nsIPermissionManager.ALLOW_ACTION);
 }
 
+function removePersistentStoragePerm(origin) {
+  let uri = NetUtil.newURI(origin);
+  let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
+  Services.perms.removeFromPrincipal(principal, "persistent-storage");
+}
+
 function getPersistentStoragePermStatus(origin) {
   let uri = NetUtil.newURI(origin);
   let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
   return Services.perms.testExactPermissionFromPrincipal(principal, "persistent-storage");
 }
 
 function getQuotaUsage(origin) {
   return new Promise(resolve => {
@@ -139,16 +145,43 @@ function getCacheUsage() {
         Components.interfaces.nsICacheStorageConsumptionObserver,
         Components.interfaces.nsISupportsWeakReference
       ]),
     };
     Services.cache2.asyncGetDiskConsumption(obs);
   });
 }
 
+function openSettingsDialog() {
+  let doc = gBrowser.selectedBrowser.contentDocument;
+  let settingsBtn = doc.getElementById("siteDataSettings");
+  let dialogOverlay = doc.getElementById("dialogOverlay");
+  let dialogLoadPromise = promiseLoadSubDialog("chrome://browser/content/preferences/siteDataSettings.xul");
+  let dialogInitPromise = TestUtils.topicObserved("sitedata-settings-init", () => true);
+  let fullyLoadPromise = Promise.all([ dialogLoadPromise, dialogInitPromise ]).then(() => {
+    is(dialogOverlay.style.visibility, "visible", "The Settings dialog should be visible");
+  });
+  settingsBtn.doCommand();
+  return fullyLoadPromise;
+}
+
+function promiseSettingsDialogClose() {
+  return new Promise(resolve => {
+    let doc = gBrowser.selectedBrowser.contentDocument;
+    let dialogOverlay = doc.getElementById("dialogOverlay");
+    let win = content.gSubDialog._frame.contentWindow;
+    win.addEventListener("unload", function unload() {
+      if (win.document.documentURI === "chrome://browser/content/preferences/siteDataSettings.xul") {
+        isnot(dialogOverlay.style.visibility, "visible", "The Settings dialog should be hidden");
+        resolve();
+      }
+    }, { once: true });
+  });
+}
+
 function promiseSitesUpdated() {
   return TestUtils.topicObserved("sitedatamanager:sites-updated", () => true);
 }
 
 function promiseCookiesCleared() {
   return TestUtils.topicObserved("cookie-changed", (subj, data) => {
     return data === "cleared";
   });
@@ -232,26 +265,19 @@ add_task(function* () {
 
 add_task(function* () {
   yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
 
   mockSiteDataManager.register();
   let updatePromise = promiseSitesUpdated();
   yield openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
   yield updatePromise;
+  yield openSettingsDialog();
 
-  // Open the siteDataSettings subdialog
   let doc = gBrowser.selectedBrowser.contentDocument;
-  let settingsBtn = doc.getElementById("siteDataSettings");
-  let dialogOverlay = doc.getElementById("dialogOverlay");
-  let dialogPromise = promiseLoadSubDialog("chrome://browser/content/preferences/siteDataSettings.xul");
-  settingsBtn.doCommand();
-  yield dialogPromise;
-  is(dialogOverlay.style.visibility, "visible", "The dialog should be visible");
-
   let dialogFrame = doc.getElementById("dialogFrame");
   let frameDoc = dialogFrame.contentDocument;
   let hostCol = frameDoc.getElementById("hostCol");
   let usageCol = frameDoc.getElementById("usageCol");
   let statusCol = frameDoc.getElementById("statusCol");
   let sitesList = frameDoc.getElementById("sitesList");
   let mockSites = mockSiteDataManager.sites;
 
@@ -330,26 +356,19 @@ add_task(function* () {
 
 add_task(function* () {
   yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
 
   mockSiteDataManager.register();
   let updatePromise = promiseSitesUpdated();
   yield openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
   yield updatePromise;
+  yield openSettingsDialog();
 
-  // Open the siteDataSettings subdialog
   let doc = gBrowser.selectedBrowser.contentDocument;
-  let settingsBtn = doc.getElementById("siteDataSettings");
-  let dialogOverlay = doc.getElementById("dialogOverlay");
-  let dialogPromise = promiseLoadSubDialog("chrome://browser/content/preferences/siteDataSettings.xul");
-  settingsBtn.doCommand();
-  yield dialogPromise;
-  is(dialogOverlay.style.visibility, "visible", "The dialog should be visible");
-
   let frameDoc = doc.getElementById("dialogFrame").contentDocument;
   let searchBox = frameDoc.getElementById("searchBox");
   let mockOrigins = Array.from(mockSiteDataManager.sites.keys());
 
   searchBox.value = "xyz";
   searchBox.doCommand();
   assertSitesListed(mockOrigins.filter(o => o.includes("xyz")));
 
@@ -369,8 +388,207 @@ add_task(function* () {
     let totalSitesNumber = sitesList.getElementsByTagName("richlistitem").length;
     is(totalSitesNumber, origins.length, "Should list the right sites number");
     origins.forEach(origin => {
       let site = sitesList.querySelector(`richlistitem[data-origin="${origin}"]`);
       ok(site instanceof XULElement, `Should list the site of ${origin}`);
     });
   }
 });
+
+// Test selecting and removing all sites one by one
+add_task(function* () {
+  yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
+  let fakeOrigins = [
+    "https://news.foo.com/",
+    "https://mails.bar.com/",
+    "https://videos.xyz.com/",
+    "https://books.foo.com/",
+    "https://account.bar.com/",
+    "https://shopping.xyz.com/"
+  ];
+  fakeOrigins.forEach(origin => addPersistentStoragePerm(origin));
+
+  let updatePromise = promiseSitesUpdated();
+  yield openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
+  yield updatePromise;
+  yield openSettingsDialog();
+
+  let doc = gBrowser.selectedBrowser.contentDocument;
+  let frameDoc = null;
+  let saveBtn = null;
+  let cancelBtn = null;
+  let settingsDialogClosePromise = null;
+
+  // Test the initial state
+  assertAllSitesListed();
+
+  // Test the "Cancel" button
+  settingsDialogClosePromise = promiseSettingsDialogClose();
+  frameDoc = doc.getElementById("dialogFrame").contentDocument;
+  cancelBtn = frameDoc.getElementById("cancel");
+  removeAllSitesOneByOne();
+  assertAllSitesNotListed();
+  cancelBtn.doCommand();
+  yield settingsDialogClosePromise;
+  yield openSettingsDialog();
+  assertAllSitesListed();
+
+  // Test the "Save Changes" button but cancelling save
+  let cancelPromise = promiseAlertDialogOpen("cancel");
+  settingsDialogClosePromise = promiseSettingsDialogClose();
+  frameDoc = doc.getElementById("dialogFrame").contentDocument;
+  saveBtn = frameDoc.getElementById("save");
+  removeAllSitesOneByOne();
+  assertAllSitesNotListed();
+  saveBtn.doCommand();
+  yield cancelPromise;
+  yield settingsDialogClosePromise;
+  yield openSettingsDialog();
+  assertAllSitesListed();
+
+  // Test the "Save Changes" button and accepting save
+  let acceptPromise = promiseAlertDialogOpen("accept");
+  settingsDialogClosePromise = promiseSettingsDialogClose();
+  updatePromise = promiseSitesUpdated();
+  frameDoc = doc.getElementById("dialogFrame").contentDocument;
+  saveBtn = frameDoc.getElementById("save");
+  removeAllSitesOneByOne();
+  assertAllSitesNotListed();
+  saveBtn.doCommand();
+  yield acceptPromise;
+  yield settingsDialogClosePromise;
+  yield updatePromise;
+  yield openSettingsDialog();
+  assertAllSitesNotListed();
+
+  // Always clean up the fake origins
+  fakeOrigins.forEach(origin => removePersistentStoragePerm(origin));
+  yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+
+  function removeAllSitesOneByOne() {
+    frameDoc = doc.getElementById("dialogFrame").contentDocument;
+    let removeBtn = frameDoc.getElementById("removeSelected");
+    let sitesList = frameDoc.getElementById("sitesList");
+    let sites = sitesList.getElementsByTagName("richlistitem");
+    for (let i = sites.length - 1; i >= 0; --i) {
+      sites[i].click();
+      removeBtn.doCommand();
+    }
+  }
+
+  function assertAllSitesListed() {
+    frameDoc = doc.getElementById("dialogFrame").contentDocument;
+    let removeBtn = frameDoc.getElementById("removeSelected");
+    let sitesList = frameDoc.getElementById("sitesList");
+    let sites = sitesList.getElementsByTagName("richlistitem");
+    is(sites.length, fakeOrigins.length, "Should list all sites");
+    is(removeBtn.disabled, false, "Should enable the removeSelected button");
+  }
+
+  function assertAllSitesNotListed() {
+    frameDoc = doc.getElementById("dialogFrame").contentDocument;
+    let removeBtn = frameDoc.getElementById("removeSelected");
+    let sitesList = frameDoc.getElementById("sitesList");
+    let sites = sitesList.getElementsByTagName("richlistitem");
+    is(sites.length, 0, "Should not list all sites");
+    is(removeBtn.disabled, true, "Should disable the removeSelected button");
+  }
+});
+
+// Test selecting and removing partial sites
+add_task(function* () {
+  yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
+  let fakeOrigins = [
+    "https://news.foo.com/",
+    "https://mails.bar.com/",
+    "https://videos.xyz.com/",
+    "https://books.foo.com/",
+    "https://account.bar.com/",
+    "https://shopping.xyz.com/"
+  ];
+  fakeOrigins.forEach(origin => addPersistentStoragePerm(origin));
+
+  let updatePromise = promiseSitesUpdated();
+  yield openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
+  yield updatePromise;
+  yield openSettingsDialog();
+
+  const removeDialogURL = "chrome://browser/content/preferences/siteDataRemoveSelected.xul";
+  let doc = gBrowser.selectedBrowser.contentDocument;
+  let frameDoc = null;
+  let saveBtn = null;
+  let cancelBtn = null;
+  let removeDialogOpenPromise = null;
+  let settingsDialogClosePromise = null;
+
+  // Test the initial state
+  assertSitesListed(fakeOrigins);
+
+  // Test the "Cancel" button
+  settingsDialogClosePromise = promiseSettingsDialogClose();
+  frameDoc = doc.getElementById("dialogFrame").contentDocument;
+  cancelBtn = frameDoc.getElementById("cancel");
+  removeSelectedSite(fakeOrigins.slice(0, 4));
+  assertSitesListed(fakeOrigins.slice(4));
+  cancelBtn.doCommand();
+  yield settingsDialogClosePromise;
+  yield openSettingsDialog();
+  assertSitesListed(fakeOrigins);
+
+  // Test the "Save Changes" button but canceling save
+  removeDialogOpenPromise = promiseWindowDialogOpen("cancel", removeDialogURL);
+  settingsDialogClosePromise = promiseSettingsDialogClose();
+  frameDoc = doc.getElementById("dialogFrame").contentDocument;
+  saveBtn = frameDoc.getElementById("save");
+  removeSelectedSite(fakeOrigins.slice(0, 4));
+  assertSitesListed(fakeOrigins.slice(4));
+  saveBtn.doCommand();
+  yield removeDialogOpenPromise;
+  yield settingsDialogClosePromise;
+  yield openSettingsDialog();
+  assertSitesListed(fakeOrigins);
+
+  // Test the "Save Changes" button and accepting save
+  removeDialogOpenPromise = promiseWindowDialogOpen("accept", removeDialogURL);
+  settingsDialogClosePromise = promiseSettingsDialogClose();
+  frameDoc = doc.getElementById("dialogFrame").contentDocument;
+  saveBtn = frameDoc.getElementById("save");
+  removeSelectedSite(fakeOrigins.slice(0, 4));
+  assertSitesListed(fakeOrigins.slice(4));
+  saveBtn.doCommand();
+  yield removeDialogOpenPromise;
+  yield settingsDialogClosePromise;
+  yield openSettingsDialog();
+  assertSitesListed(fakeOrigins.slice(4));
+
+  // Always clean up the fake origins
+  fakeOrigins.forEach(origin => removePersistentStoragePerm(origin));
+  yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+
+  function removeSelectedSite(origins) {
+    frameDoc = doc.getElementById("dialogFrame").contentDocument;
+    let removeBtn = frameDoc.getElementById("removeSelected");
+    let sitesList = frameDoc.getElementById("sitesList");
+    origins.forEach(origin => {
+      let site = sitesList.querySelector(`richlistitem[data-origin="${origin}"]`);
+      if (site) {
+        site.click();
+        removeBtn.doCommand();
+      } else {
+        ok(false, `Should not select and remove inexisted site of ${origin}`);
+      }
+    });
+  }
+
+  function assertSitesListed(origins) {
+    frameDoc = doc.getElementById("dialogFrame").contentDocument;
+    let removeBtn = frameDoc.getElementById("removeSelected");
+    let sitesList = frameDoc.getElementById("sitesList");
+    let totalSitesNumber = sitesList.getElementsByTagName("richlistitem").length;
+    is(totalSitesNumber, origins.length, "Should list the right sites number");
+    origins.forEach(origin => {
+      let site = sitesList.querySelector(`richlistitem[data-origin="${origin}"]`);
+      ok(!!site, `Should list the site of ${origin}`);
+    });
+    is(removeBtn.disabled, false, "Should enable the removeSelected button");
+  }
+});
--- a/browser/components/preferences/in-content/tests/head.js
+++ b/browser/components/preferences/in-content/tests/head.js
@@ -156,24 +156,28 @@ function waitForCondition(aConditionFn, 
     function tryAgain() {
       setTimeout(tryNow, aCheckInterval);
     }
     let tries = 0;
     tryAgain();
   });
 }
 
-function promiseAlertDialogOpen(buttonAction) {
+function promiseWindowDialogOpen(buttonAction, url) {
   return new Promise(resolve => {
     Services.ww.registerNotification(function onOpen(subj, topic, data) {
       if (topic == "domwindowopened" && subj instanceof Ci.nsIDOMWindow) {
-        subj.addEventListener("load", function() {
-          if (subj.document.documentURI == "chrome://global/content/commonDialog.xul") {
+        subj.addEventListener("load", function onLoad() {
+          if (subj.document.documentURI == url) {
             Services.ww.unregisterNotification(onOpen);
             let doc = subj.document.documentElement;
             doc.getButton(buttonAction).click();
             resolve();
           }
         }, {once: true});
       }
     });
   });
 }
+
+function promiseAlertDialogOpen(buttonAction) {
+  return promiseWindowDialogOpen(buttonAction, "chrome://global/content/commonDialog.xul");
+}
--- a/browser/components/preferences/jar.mn
+++ b/browser/components/preferences/jar.mn
@@ -25,11 +25,13 @@ browser.jar:
     content/browser/preferences/permissions.js
     content/browser/preferences/sanitize.xul
     content/browser/preferences/sanitize.js
     content/browser/preferences/selectBookmark.xul
     content/browser/preferences/selectBookmark.js
     content/browser/preferences/siteDataSettings.xul
     content/browser/preferences/siteDataSettings.js
     content/browser/preferences/siteDataSettings.css
+*   content/browser/preferences/siteDataRemoveSelected.xul
+    content/browser/preferences/siteDataRemoveSelected.js
     content/browser/preferences/siteListItem.xml
     content/browser/preferences/translation.xul
     content/browser/preferences/translation.js
--- a/browser/components/preferences/moz.build
+++ b/browser/components/preferences/moz.build
@@ -14,13 +14,13 @@ for var in ('MOZ_APP_NAME', 'MOZ_MACBUND
     DEFINES[var] = CONFIG[var]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3', 'cocoa'):
     DEFINES['HAVE_SHELL_SERVICE'] = 1
 
 JAR_MANIFESTS += ['jar.mn']
 
 EXTRA_JS_MODULES += [
-    'SiteDataManager.jsm',
+    'SiteDataManager.jsm'
 ]
 
 with Files('**'):
     BUG_COMPONENT = ('Firefox', 'Preferences')
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/siteDataRemoveSelected.js
@@ -0,0 +1,197 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
+/* 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/. */
+const { utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+"use strict";
+
+let gSiteDataRemoveSelected = {
+
+  _tree: null,
+
+  init() {
+    // Organize items for the tree from the argument
+    let hostsTable = window.arguments[0].hostsTable;
+    let visibleItems = [];
+    let itemsTable = new Map();
+    for (let [ baseDomain, hosts ] of hostsTable) {
+      // In the beginning, only display base domains in the topmost level.
+      visibleItems.push({
+        level: 0,
+        opened: false,
+        host: baseDomain
+      });
+      // Other hosts are in the second level.
+      let items = hosts.map(host => {
+        return { host, level: 1 };
+      });
+      items.sort(sortByHost);
+      itemsTable.set(baseDomain, items);
+    }
+    visibleItems.sort(sortByHost);
+    this._view.itemsTable = itemsTable;
+    this._view.visibleItems = visibleItems;
+    this._tree = document.getElementById("sitesTree");
+    this._tree.view = this._view;
+
+    function sortByHost(a, b) {
+      let aHost = a.host.toLowerCase();
+      let bHost = b.host.toLowerCase();
+      return aHost.localeCompare(bHost);
+    }
+  },
+
+  ondialogaccept() {
+    window.arguments[0].allowed = true;
+  },
+
+  ondialogcancel() {
+    window.arguments[0].allowed = false;
+  },
+
+  _view: {
+    _selection: null,
+
+    itemsTable: null,
+
+    visibleItems: null,
+
+    get rowCount() {
+      return this.visibleItems.length;
+    },
+
+    getCellText(index, column) {
+      let item = this.visibleItems[index];
+      return item ? item.host : "";
+    },
+
+    isContainer(index) {
+      let item = this.visibleItems[index];
+      if (item && item.level === 0) {
+        return true;
+      }
+      return false;
+    },
+
+    isContainerEmpty() {
+      return false;
+    },
+
+    isContainerOpen(index) {
+      let item = this.visibleItems[index];
+      if (item && item.level === 0) {
+        return item.opened;
+      }
+      return false;
+    },
+
+    getLevel(index) {
+      let item = this.visibleItems[index];
+      return item ? item.level : 0;
+    },
+
+    hasNextSibling(index, afterIndex) {
+      let item = this.visibleItems[index];
+      if (item) {
+        let thisLV = this.getLevel(index);
+        for (let i = afterIndex + 1; i < this.rowCount; ++i) {
+          let nextLV = this.getLevel(i);
+          if (nextLV == thisLV) {
+            return true;
+          }
+          if (nextLV < thisLV) {
+            break;
+          }
+        }
+      }
+      return false;
+    },
+
+    getParentIndex(index) {
+      if (!this.isContainer(index)) {
+        for (let i = index - 1; i >= 0; --i) {
+          if (this.isContainer(i)) {
+            return i;
+          }
+        }
+      }
+      return -1;
+    },
+
+    toggleOpenState(index) {
+      let item = this.visibleItems[index];
+      if (!this.isContainer(index)) {
+        return;
+      }
+
+      if (item.opened) {
+        item.opened = false;
+
+        let deleteCount = 0;
+        for (let i = index + 1; i < this.visibleItems.length; ++i) {
+          if (!this.isContainer(i)) {
+            ++deleteCount;
+          } else {
+            break;
+          }
+        }
+
+        if (deleteCount) {
+          this.visibleItems.splice(index + 1, deleteCount);
+          this.treeBox.rowCountChanged(index + 1, -deleteCount);
+        }
+      } else {
+        item.opened = true;
+
+        let childItems = this.itemsTable.get(item.host);
+        for (let i = 0; i < childItems.length; ++i) {
+          this.visibleItems.splice(index + i + 1, 0, childItems[i]);
+        }
+        this.treeBox.rowCountChanged(index + 1, childItems.length);
+      }
+      this.treeBox.invalidateRow(index);
+    },
+
+    get selection() {
+      return this._selection;
+    },
+    set selection(v) {
+      this._selection = v;
+      return v;
+    },
+    setTree(treeBox) {
+      this.treeBox = treeBox;
+    },
+    isSeparator(index) {
+      return false;
+    },
+    isSorted(index) {
+      return false;
+    },
+    canDrop() {
+      return false;
+    },
+    drop() {},
+    getRowProperties() {},
+    getCellProperties() {},
+    getColumnProperties() {},
+    hasPreviousSibling(index) {},
+    getImageSrc() {},
+    getProgressMode() {},
+    getCellValue() {},
+    cycleHeader() {},
+    selectionChanged() {},
+    cycleCell() {},
+    isEditable() {},
+    isSelectable() {},
+    setCellValue() {},
+    setCellText() {},
+    performAction() {},
+    performActionOnRow() {},
+    performActionOnCell() {}
+  }
+};
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/siteDataRemoveSelected.xul
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+
+<!-- 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/. -->
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/content/preferences/siteDataSettings.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/preferences/in-content/siteDataSettings.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://browser/locale/preferences/siteDataSettings.dtd" >
+
+<dialog id="SiteDataRemoveSelectedDialog"
+        windowtype="Browser:SiteDataRemoveSelected"
+        width="500"
+        title="&removingDialog.title;"
+        onload="gSiteDataRemoveSelected.init();"
+        ondialogaccept="gSiteDataRemoveSelected.ondialogaccept(); return true;"
+        ondialogcancel="gSiteDataRemoveSelected.ondialogcancel(); return true;"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script src="chrome://browser/content/preferences/siteDataRemoveSelected.js"/>
+
+  <stringbundle id="bundlePreferences"
+                src="chrome://browser/locale/preferences/preferences.properties"/>
+
+  <vbox id="contentContainer">
+    <hbox flex="1">
+      <vbox>
+        <image class="question-icon"/>
+      </vbox>
+      <vbox flex="1">
+        <!-- Only show this label on OS X because of no dialog title -->
+        <label id="removing-label"
+#ifndef XP_MACOSX
+               hidden="true"
+#endif
+        >&removingDialog.title;</label>
+        <separator class="thin"/>
+        <description id="removing-description">&removingDialog.description;</description>
+      </vbox>
+    </hbox>
+
+    <separator />
+
+    <vbox flex="1">
+      <label>&siteTree.label;</label>
+      <separator class="thin"/>
+      <tree id="sitesTree" flex="1" seltype="single" hidecolumnpicker="true">
+        <treecols>
+          <treecol primary="true" flex="1" hideheader="true"/>
+        </treecols>
+        <treechildren />
+      </tree>
+    </vbox>
+  </vbox>
+
+</dialog>
--- a/browser/components/preferences/siteDataSettings.css
+++ b/browser/components/preferences/siteDataSettings.css
@@ -1,19 +1,11 @@
 /* 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/. */
 
-#searchBoxContainer {
-  -moz-box-align: center;
-}
-
-#sitesList {
-  min-height: 20em;
-}
-
 #sitesList > richlistitem {
   -moz-binding: url("chrome://browser/content/preferences/siteListItem.xml#siteListItem");
 }
 
-.item-box {
-  padding: 5px 8px;
+#SiteDataRemoveSelectedDialog {
+  -moz-binding: url("chrome://global/content/bindings/dialog.xml#dialog");
 }
--- a/browser/components/preferences/siteDataSettings.js
+++ b/browser/components/preferences/siteDataSettings.js
@@ -15,16 +15,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 "use strict";
 
 let gSiteDataSettings = {
 
   // Array of meatdata of sites. Each array element is object holding:
   // - uri: uri of site; instance of nsIURI
   // - status: persistent-storage permission status
   // - usage: disk usage which site uses
+  // - userAction: "remove" or "update-permission"; the action user wants to take.
+  //               If not specified, means no action to take
   _sites: null,
 
   _list: null,
   _searchBox: null,
 
   init() {
     function setEventListener(id, eventType, callback) {
       document.getElementById(id)
@@ -33,22 +35,33 @@ let gSiteDataSettings = {
 
     this._list = document.getElementById("sitesList");
     this._searchBox = document.getElementById("searchBox");
     SiteDataManager.getSites().then(sites => {
       this._sites = sites;
       let sortCol = document.getElementById("hostCol");
       this._sortSites(this._sites, sortCol);
       this._buildSitesList(this._sites);
+      this._updateButtonsState();
+      Services.obs.notifyObservers(null, "sitedata-settings-init", null);
     });
 
     setEventListener("hostCol", "click", this.onClickTreeCol);
     setEventListener("usageCol", "click", this.onClickTreeCol);
     setEventListener("statusCol", "click", this.onClickTreeCol);
     setEventListener("searchBox", "command", this.onCommandSearch);
+    setEventListener("cancel", "command", this.close);
+    setEventListener("save", "command", this.saveChanges);
+    setEventListener("removeSelected", "command", this.removeSelected);
+  },
+
+  _updateButtonsState() {
+    let items = this._list.getElementsByTagName("richlistitem");
+    let removeBtn = document.getElementById("removeSelected");
+    removeBtn.disabled = !(items.length > 0);
   },
 
   /**
    * @param sites {Array}
    * @param col {XULElement} the <treecol> being sorted on
    */
   _sortSites(sites, col) {
     let isCurrentSortCol = col.getAttribute("data-isCurrentSortCol")
@@ -105,16 +118,20 @@ let gSiteDataSettings = {
     let prefStrBundle = document.getElementById("bundlePreferences");
     let keyword = this._searchBox.value.toLowerCase().trim();
     for (let data of sites) {
       let host = data.uri.host;
       if (keyword && !host.includes(keyword)) {
         continue;
       }
 
+      if (data.userAction === "remove") {
+        continue;
+      }
+
       let statusStrId = data.status === Ci.nsIPermissionManager.ALLOW_ACTION ? "important" : "default";
       let size = DownloadUtils.convertByteUnits(data.usage);
       let item = document.createElement("richlistitem");
       item.setAttribute("data-origin", data.uri.spec);
       item.setAttribute("host", host);
       item.setAttribute("status", prefStrBundle.getString(statusStrId));
       item.setAttribute("usage", prefStrBundle.getFormattedString("siteUsage", size));
       this._list.appendChild(item);
@@ -123,10 +140,100 @@ let gSiteDataSettings = {
 
   onClickTreeCol(e) {
     this._sortSites(this._sites, e.target);
     this._buildSitesList(this._sites);
   },
 
   onCommandSearch() {
     this._buildSitesList(this._sites);
+  },
+
+  removeSelected() {
+    let selected = this._list.selectedItem;
+    if (selected) {
+      let origin = selected.getAttribute("data-origin");
+      for (let site of this._sites) {
+        if (site.uri.spec === origin) {
+          site.userAction = "remove";
+          break;
+        }
+      }
+      this._list.removeChild(selected);
+      this._updateButtonsState();
+    }
+  },
+
+  saveChanges() {
+    let allowed = true;
+
+    // Confirm user really wants to remove site data starts
+    let removals = [];
+    this._sites = this._sites.filter(site => {
+      if (site.userAction === "remove") {
+        removals.push(site.uri);
+        return false;
+      }
+      return true;
+    });
+
+    if (removals.length > 0) {
+      if (this._sites.length == 0) {
+        // User selects all sites so equivalent to clearing all data
+        let flags =
+          Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0 +
+          Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1 +
+          Services.prompt.BUTTON_POS_0_DEFAULT;
+        let prefStrBundle = document.getElementById("bundlePreferences");
+        let title = prefStrBundle.getString("clearSiteDataPromptTitle");
+        let text = prefStrBundle.getString("clearSiteDataPromptText");
+        let btn0Label = prefStrBundle.getString("clearSiteDataNow");
+        let result = Services.prompt.confirmEx(window, title, text, flags, btn0Label, null, null, null, {});
+        allowed = result == 0;
+        if (allowed) {
+          SiteDataManager.removeAll();
+        }
+      } else {
+        // User only removes partial sites.
+        // We will remove cookies based on base domain, say, user selects "news.foo.com" to remove.
+        // The cookies under "music.foo.com" will be removed together.
+        // We have to prmopt user about this action.
+        let hostsTable = new Map();
+        // Group removed sites by base domain
+        for (let uri of removals) {
+          let baseDomain = Services.eTLD.getBaseDomain(uri);
+          let hosts = hostsTable.get(baseDomain);
+          if (!hosts) {
+            hosts = [];
+            hostsTable.set(baseDomain, hosts);
+          }
+          hosts.push(uri.host);
+        }
+        // Pick out sites with the same base domain as removed sites
+        for (let site of this._sites) {
+          let baseDomain = Services.eTLD.getBaseDomain(site.uri);
+          let hosts = hostsTable.get(baseDomain);
+          if (hosts) {
+            hosts.push(site.uri.host);
+          }
+        }
+
+        let args = {
+          hostsTable,
+          allowed: false
+        };
+        let features = "centerscreen,chrome,modal,resizable=no";
+        window.openDialog("chrome://browser/content/preferences/siteDataRemoveSelected.xul", "", features, args);
+        allowed = args.allowed;
+        if (allowed) {
+          SiteDataManager.remove(removals);
+        }
+      }
+    }
+    // Confirm user really wants to remove site data ends
+
+    this.close();
+  },
+
+  close() {
+    window.close();
   }
 };
--- a/browser/components/preferences/siteDataSettings.xul
+++ b/browser/components/preferences/siteDataSettings.xul
@@ -2,16 +2,17 @@
 
 <!-- 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/. -->
 
 <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/preferences/siteDataSettings.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/preferences/in-content/siteDataSettings.css" type="text/css"?>
 
 <!DOCTYPE dialog SYSTEM "chrome://browser/locale/preferences/siteDataSettings.dtd" >
 
 <window id="SiteDataSettingsDialog" windowtype="Browser:SiteDataSettings"
         class="windowDialog" title="&window.title;"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         style="width: 45em;"
         onload="gSiteDataSettings.init();"
@@ -36,9 +37,20 @@
       <listheader>
         <treecol flex="4" width="50" label="&hostCol.label;" id="hostCol"/>
         <treecol flex="2" width="50" label="&statusCol.label;" id="statusCol"/>
         <treecol flex="1" width="50" label="&usageCol.label;" id="usageCol"/>
       </listheader>
     </richlistbox>
   </vbox>
 
+  <hbox align="start">
+    <button id="removeSelected" label="&removeSelected.label;" accesskey="&removeSelected.accesskey;"/>
+  </hbox>
+
+  <vbox align="end">
+    <hbox>
+        <button id="cancel" label="&cancel.label;" accesskey="&cancel.accesskey;"/>
+        <button id="save" label="&save.label;" accesskey="&save.accesskey;"/>
+    </hbox>
+  </vbox>
+
 </window>
--- a/browser/components/sessionstore/test/browser_500328.js
+++ b/browser/components/sessionstore/test/browser_500328.js
@@ -47,17 +47,17 @@ function checkState(tab) {
           "/^a$/", "second popstate object.");
       }).then(function() {
         // Make sure that the new-elem node is present in the document.  If it's
         // not, then this history entry has a different doc identifier than the
         // previous entry, which is bad.
         let doc = contentWindow.document;
         let newElem = doc.getElementById("new-elem");
         ok(newElem, "doc should contain new-elem.");
-        newElem.parentNode.removeChild(newElem);
+        newElem.remove();
         ok(!doc.getElementById("new-elem"), "new-elem should be removed.");
 
         tab.linkedBrowser.removeEventListener("popstate", arguments.callee, true);
         gBrowser.removeTab(tab);
         finish();
       });
     }
   });
--- a/browser/config/mozconfigs/linux32/beta
+++ b/browser/config/mozconfigs/linux32/beta
@@ -1,9 +1,8 @@
-MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
   MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/browser/config/mozconfigs/linux32/common-opt"
 
 ac_add_options --enable-official-branding
--- a/browser/config/mozconfigs/linux32/release
+++ b/browser/config/mozconfigs/linux32/release
@@ -1,11 +1,10 @@
 # This make file should be identical to the beta mozconfig, apart from the
 # safeguard below
-MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
 
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
   MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/browser/config/mozconfigs/linux32/common-opt"
 
--- a/browser/config/mozconfigs/linux64/beta
+++ b/browser/config/mozconfigs/linux64/beta
@@ -1,9 +1,8 @@
-MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
   MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/browser/config/mozconfigs/linux64/common-opt"
 
 ac_add_options --enable-official-branding
--- a/browser/config/mozconfigs/linux64/release
+++ b/browser/config/mozconfigs/linux64/release
@@ -1,11 +1,10 @@
 # This make file should be identical to the beta mozconfig, apart from the
 # safeguard below
-MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
 
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
   MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/browser/config/mozconfigs/linux64/common-opt"
 
--- a/browser/config/mozconfigs/macosx-universal/beta
+++ b/browser/config/mozconfigs/macosx-universal/beta
@@ -1,10 +1,8 @@
-MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
-
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
   MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/browser/config/mozconfigs/macosx-universal/common-opt"
 
 ac_add_options --enable-official-branding
--- a/browser/config/mozconfigs/macosx-universal/release
+++ b/browser/config/mozconfigs/macosx-universal/release
@@ -1,11 +1,10 @@
 # This make file should be identical to the beta mozconfig, apart from the
 # safeguard below
-MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
 
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
   MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/browser/config/mozconfigs/macosx-universal/common-opt"
 
--- a/browser/config/mozconfigs/macosx64/beta
+++ b/browser/config/mozconfigs/macosx64/beta
@@ -1,10 +1,8 @@
-MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
-
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
   MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/browser/config/mozconfigs/macosx64/common-opt"
 
 ac_add_options --enable-official-branding
--- a/browser/config/mozconfigs/macosx64/release
+++ b/browser/config/mozconfigs/macosx64/release
@@ -1,11 +1,10 @@
 # This make file should be identical to the beta mozconfig, apart from the
 # safeguard below
-MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
 
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
   MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/browser/config/mozconfigs/macosx64/common-opt"
 
--- a/browser/config/mozconfigs/whitelist
+++ b/browser/config/mozconfigs/whitelist
@@ -73,17 +73,16 @@ for platform in all_platforms:
         'ac_add_options --enable-update-channel=release',
         'ac_add_options --enable-official-branding',
         'mk_add_options MOZ_MAKE_FLAGS="-j4"',
         'export BUILDING_RELEASE=1',
         'if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then',
         'MOZ_AUTOMATION_UPLOAD_SYMBOLS=1',
         'MOZ_AUTOMATION_UPDATE_PACKAGING=1',
         'fi',
-        'MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}',
     ]
 whitelist['release']['win32'] += ['mk_add_options MOZ_PGO=1']
 whitelist['release']['win64'] += ['mk_add_options MOZ_PGO=1']
 
 whitelist['release']['linux32'] += [
     'export MOZILLA_OFFICIAL=1',
     'export MOZ_TELEMETRY_REPORTING=1',
     'mk_add_options MOZ_PGO=1',
--- a/browser/config/mozconfigs/win32/beta
+++ b/browser/config/mozconfigs/win32/beta
@@ -1,10 +1,8 @@
-MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
-
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
   MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win32/common-opt"
 
--- a/browser/config/mozconfigs/win32/release
+++ b/browser/config/mozconfigs/win32/release
@@ -1,11 +1,10 @@
 # This make file should be identical to the beta mozconfig, apart from the
 # safeguard below
-MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
 
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
   MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win32/common-opt"
--- a/browser/config/mozconfigs/win64/beta
+++ b/browser/config/mozconfigs/win64/beta
@@ -1,10 +1,8 @@
-MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
-
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
   MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-opt"
--- a/browser/config/mozconfigs/win64/release
+++ b/browser/config/mozconfigs/win64/release
@@ -1,11 +1,10 @@
 # This make file should be identical to the beta mozconfig, apart from the
 # safeguard below
-MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
 
 if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
   MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,3 +1,3 @@
 This is the pdf.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 1.7.227
+Current extension version is: 1.7.235
--- a/browser/extensions/pdfjs/content/PdfJs.jsm
+++ b/browser/extensions/pdfjs/content/PdfJs.jsm
@@ -10,52 +10,52 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 /* globals Components, Services, XPCOMUtils, PdfjsChromeUtils,
            PdfjsContentUtils, PdfStreamConverter */
 
-'use strict';
+"use strict";
 
-var EXPORTED_SYMBOLS = ['PdfJs'];
+var EXPORTED_SYMBOLS = ["PdfJs"];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cm = Components.manager;
 const Cu = Components.utils;
 
-const PREF_PREFIX = 'pdfjs';
-const PREF_DISABLED = PREF_PREFIX + '.disabled';
-const PREF_MIGRATION_VERSION = PREF_PREFIX + '.migrationVersion';
-const PREF_PREVIOUS_ACTION = PREF_PREFIX + '.previousHandler.preferredAction';
+const PREF_PREFIX = "pdfjs";
+const PREF_DISABLED = PREF_PREFIX + ".disabled";
+const PREF_MIGRATION_VERSION = PREF_PREFIX + ".migrationVersion";
+const PREF_PREVIOUS_ACTION = PREF_PREFIX + ".previousHandler.preferredAction";
 const PREF_PREVIOUS_ASK = PREF_PREFIX +
-                          '.previousHandler.alwaysAskBeforeHandling';
-const PREF_DISABLED_PLUGIN_TYPES = 'plugin.disable_full_page_plugin_for_types';
-const TOPIC_PDFJS_HANDLER_CHANGED = 'pdfjs:handlerChanged';
-const TOPIC_PLUGINS_LIST_UPDATED = 'plugins-list-updated';
-const TOPIC_PLUGIN_INFO_UPDATED = 'plugin-info-updated';
-const PDF_CONTENT_TYPE = 'application/pdf';
+                          ".previousHandler.alwaysAskBeforeHandling";
+const PREF_DISABLED_PLUGIN_TYPES = "plugin.disable_full_page_plugin_for_types";
+const TOPIC_PDFJS_HANDLER_CHANGED = "pdfjs:handlerChanged";
+const TOPIC_PLUGINS_LIST_UPDATED = "plugins-list-updated";
+const TOPIC_PLUGIN_INFO_UPDATED = "plugin-info-updated";
+const PDF_CONTENT_TYPE = "application/pdf";
 
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
 
 var Svc = {};
-XPCOMUtils.defineLazyServiceGetter(Svc, 'mime',
-                                   '@mozilla.org/mime;1',
-                                   'nsIMIMEService');
-XPCOMUtils.defineLazyServiceGetter(Svc, 'pluginHost',
-                                   '@mozilla.org/plugin/host;1',
-                                   'nsIPluginHost');
-XPCOMUtils.defineLazyModuleGetter(this, 'PdfjsChromeUtils',
-                                  'resource://pdf.js/PdfjsChromeUtils.jsm');
-XPCOMUtils.defineLazyModuleGetter(this, 'PdfjsContentUtils',
-                                  'resource://pdf.js/PdfjsContentUtils.jsm');
+XPCOMUtils.defineLazyServiceGetter(Svc, "mime",
+                                   "@mozilla.org/mime;1",
+                                   "nsIMIMEService");
+XPCOMUtils.defineLazyServiceGetter(Svc, "pluginHost",
+                                   "@mozilla.org/plugin/host;1",
+                                   "nsIPluginHost");
+XPCOMUtils.defineLazyModuleGetter(this, "PdfjsChromeUtils",
+                                  "resource://pdf.js/PdfjsChromeUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PdfjsContentUtils",
+                                  "resource://pdf.js/PdfjsContentUtils.jsm");
 
 function getBoolPref(aPref, aDefaultValue) {
   try {
     return Services.prefs.getBoolPref(aPref);
   } catch (ex) {
     return aDefaultValue;
   }
 }
@@ -93,28 +93,28 @@ function initializeDefaultPreferences() 
   "externalLinkTarget": 0,
   "enhanceTextSelection": false,
   "renderer": "canvas",
   "renderInteractiveForms": false,
   "disablePageLabels": false
 }
 
 
-  var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.');
+  var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + ".");
   var defaultValue;
   for (var key in DEFAULT_PREFERENCES) {
     defaultValue = DEFAULT_PREFERENCES[key];
     switch (typeof defaultValue) {
-      case 'boolean':
+      case "boolean":
         defaultBranch.setBoolPref(key, defaultValue);
         break;
-      case 'number':
+      case "number":
         defaultBranch.setIntPref(key, defaultValue);
         break;
-      case 'string':
+      case "string":
         defaultBranch.setCharPref(key, defaultValue);
         break;
     }
   }
 }
 
 // Register/unregister a constructor as a factory.
 function Factory() {}
@@ -150,18 +150,18 @@ Factory.prototype = {
 var PdfJs = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
   _registered: false,
   _initialized: false,
 
   init: function init(remote) {
     if (Services.appinfo.processType !==
         Services.appinfo.PROCESS_TYPE_DEFAULT) {
-      throw new Error('PdfJs.init should only get called ' +
-                      'in the parent process.');
+      throw new Error("PdfJs.init should only get called " +
+                      "in the parent process.");
     }
     PdfjsChromeUtils.init();
     if (!remote) {
       PdfjsContentUtils.init();
     }
     this.initPrefs();
     this.updateRegistration();
   },
@@ -214,70 +214,70 @@ var PdfJs = {
       return;
     }
     // Make pdf.js the default pdf viewer on the first migration.
     if (currentVersion < 1) {
       this._becomeHandler();
     }
     if (currentVersion < 2) {
       // cleaning up of unused database preference (see #3994)
-      Services.prefs.clearUserPref(PREF_PREFIX + '.database');
+      Services.prefs.clearUserPref(PREF_PREFIX + ".database");
     }
     Services.prefs.setIntPref(PREF_MIGRATION_VERSION, VERSION);
   },
 
   _becomeHandler: function _becomeHandler() {
-    let handlerInfo = Svc.mime.getFromTypeAndExtension(PDF_CONTENT_TYPE, 'pdf');
+    let handlerInfo = Svc.mime.getFromTypeAndExtension(PDF_CONTENT_TYPE, "pdf");
     let prefs = Services.prefs;
     if (handlerInfo.preferredAction !== Ci.nsIHandlerInfo.handleInternally &&
         handlerInfo.preferredAction !== false) {
       // Store the previous settings of preferredAction and
       // alwaysAskBeforeHandling in case we need to revert them in a hotfix that
       // would turn pdf.js off.
       prefs.setIntPref(PREF_PREVIOUS_ACTION, handlerInfo.preferredAction);
       prefs.setBoolPref(PREF_PREVIOUS_ASK, handlerInfo.alwaysAskBeforeHandling);
     }
 
-    let handlerService = Cc['@mozilla.org/uriloader/handler-service;1'].
+    let handlerService = Cc["@mozilla.org/uriloader/handler-service;1"].
                          getService(Ci.nsIHandlerService);
 
     // Change and save mime handler settings.
     handlerInfo.alwaysAskBeforeHandling = false;
     handlerInfo.preferredAction = Ci.nsIHandlerInfo.handleInternally;
     handlerService.store(handlerInfo);
 
     // Also disable any plugins for pdfs.
-    var stringTypes = '';
+    var stringTypes = "";
     var types = [];
     if (prefs.prefHasUserValue(PREF_DISABLED_PLUGIN_TYPES)) {
       stringTypes = prefs.getCharPref(PREF_DISABLED_PLUGIN_TYPES);
     }
-    if (stringTypes !== '') {
-      types = stringTypes.split(',');
+    if (stringTypes !== "") {
+      types = stringTypes.split(",");
     }
 
     if (types.indexOf(PDF_CONTENT_TYPE) === -1) {
       types.push(PDF_CONTENT_TYPE);
     }
-    prefs.setCharPref(PREF_DISABLED_PLUGIN_TYPES, types.join(','));
+    prefs.setCharPref(PREF_DISABLED_PLUGIN_TYPES, types.join(","));
 
     // Update the category manager in case the plugins are already loaded.
-    let categoryManager = Cc['@mozilla.org/categorymanager;1'];
+    let categoryManager = Cc["@mozilla.org/categorymanager;1"];
     categoryManager.getService(Ci.nsICategoryManager).
-                    deleteCategoryEntry('Gecko-Content-Viewers',
+                    deleteCategoryEntry("Gecko-Content-Viewers",
                                         PDF_CONTENT_TYPE,
                                         false);
   },
 
   // nsIObserver
   observe: function observe(aSubject, aTopic, aData) {
     this.updateRegistration();
     if (Services.appinfo.processType ===
         Services.appinfo.PROCESS_TYPE_DEFAULT) {
-      let jsm = 'resource://pdf.js/PdfjsChromeUtils.jsm';
+      let jsm = "resource://pdf.js/PdfjsChromeUtils.jsm";
       let PdfjsChromeUtils = Components.utils.import(jsm, {}).PdfjsChromeUtils;
       PdfjsChromeUtils.notifyChildOfSettingsChange();
     }
   },
 
   /**
    * pdf.js is only enabled if it is both selected as the pdf viewer and if the
    * global switch enabling it is true.
@@ -292,26 +292,26 @@ var PdfJs = {
     // Check if the 'application/pdf' preview handler is configured properly.
     if (!isDefaultHandler()) {
       return false;
     }
 
     // Check if we have disabled plugin handling of 'application/pdf' in prefs
     if (Services.prefs.prefHasUserValue(PREF_DISABLED_PLUGIN_TYPES)) {
       let disabledPluginTypes =
-        Services.prefs.getCharPref(PREF_DISABLED_PLUGIN_TYPES).split(',');
+        Services.prefs.getCharPref(PREF_DISABLED_PLUGIN_TYPES).split(",");
       if (disabledPluginTypes.indexOf(PDF_CONTENT_TYPE) >= 0) {
         return true;
       }
     }
 
     // Check if there is an enabled pdf plugin.
     // Note: this check is performed last because getPluginTags() triggers
     // costly plugin list initialization (bug 881575)
-    let tags = Cc['@mozilla.org/plugin/host;1'].
+    let tags = Cc["@mozilla.org/plugin/host;1"].
                   getService(Ci.nsIPluginHost).
                   getPluginTags();
     let enabledPluginFound = tags.some(function(tag) {
       if (tag.disabled) {
         return false;
       }
       let mimeTypes = tag.getMimeTypes();
       return mimeTypes.some(function(mimeType) {
@@ -323,26 +323,26 @@ var PdfJs = {
     return !enabledPluginFound;
   },
 
   _ensureRegistered: function _ensureRegistered() {
     if (this._registered) {
       return;
     }
     this._pdfStreamConverterFactory = new Factory();
-    Cu.import('resource://pdf.js/PdfStreamConverter.jsm');
+    Cu.import("resource://pdf.js/PdfStreamConverter.jsm");
     this._pdfStreamConverterFactory.register(PdfStreamConverter);
 
     this._registered = true;
   },
 
   _ensureUnregistered: function _ensureUnregistered() {
     if (!this._registered) {
       return;
     }
     this._pdfStreamConverterFactory.unregister();
-    Cu.unload('resource://pdf.js/PdfStreamConverter.jsm');
+    Cu.unload("resource://pdf.js/PdfStreamConverter.jsm");
     delete this._pdfStreamConverterFactory;
 
     this._registered = false;
   }
 };
 
--- a/browser/extensions/pdfjs/content/PdfJsNetwork.jsm
+++ b/browser/extensions/pdfjs/content/PdfJsNetwork.jsm
@@ -9,35 +9,35 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 /* globals Components, Services */
 
-'use strict';
+"use strict";
 
-Components.utils.import('resource://gre/modules/Services.jsm');
+Components.utils.import("resource://gre/modules/Services.jsm");
 
-var EXPORTED_SYMBOLS = ['NetworkManager'];
+var EXPORTED_SYMBOLS = ["NetworkManager"];
 
 function log(aMsg) {
-  var msg = 'PdfJsNetwork.jsm: ' + (aMsg.join ? aMsg.join('') : aMsg);
+  var msg = "PdfJsNetwork.jsm: " + (aMsg.join ? aMsg.join("") : aMsg);
   Services.console.logStringMessage(msg);
 }
 
 var NetworkManager = (function NetworkManagerClosure() {
 
   const OK_RESPONSE = 200;
   const PARTIAL_CONTENT_RESPONSE = 206;
 
   function getArrayBuffer(xhr) {
     var data = xhr.response;
-    if (typeof data !== 'string') {
+    if (typeof data !== "string") {
       return data;
     }
     var length = data.length;
     var array = new Uint8Array(length);
     for (var i = 0; i < length; i++) {
       array[i] = data.charCodeAt(i) & 0xFF;
     }
     return array.buffer;
@@ -77,40 +77,40 @@ var NetworkManager = (function NetworkMa
 
     request(args) {
       var xhr = this.getXhr();
       var xhrId = this.currXhrId++;
       var pendingRequest = this.pendingRequests[xhrId] = {
         xhr,
       };
 
-      xhr.open('GET', this.url);
+      xhr.open("GET", this.url);
       xhr.withCredentials = this.withCredentials;
       for (var property in this.httpHeaders) {
         var value = this.httpHeaders[property];
-        if (typeof value === 'undefined') {
+        if (typeof value === "undefined") {
           continue;
         }
         xhr.setRequestHeader(property, value);
       }
-      if (this.isHttp && 'begin' in args && 'end' in args) {
-        var rangeStr = args.begin + '-' + (args.end - 1);
-        xhr.setRequestHeader('Range', 'bytes=' + rangeStr);
+      if (this.isHttp && "begin" in args && "end" in args) {
+        var rangeStr = args.begin + "-" + (args.end - 1);
+        xhr.setRequestHeader("Range", "bytes=" + rangeStr);
         pendingRequest.expectedStatus = 206;
       } else {
         pendingRequest.expectedStatus = 200;
       }
 
       var useMozChunkedLoading = !!args.onProgressiveData;
       if (useMozChunkedLoading) {
-        xhr.responseType = 'moz-chunked-arraybuffer';
+        xhr.responseType = "moz-chunked-arraybuffer";
         pendingRequest.onProgressiveData = args.onProgressiveData;
         pendingRequest.mozChunked = true;
       } else {
-        xhr.responseType = 'arraybuffer';
+        xhr.responseType = "arraybuffer";
       }
 
       if (args.onError) {
         xhr.onerror = function(evt) {
           args.onError(xhr.status);
         };
       }
       xhr.onreadystatechange = this.onStateChange.bind(this, xhrId);
@@ -192,17 +192,17 @@ var NetworkManager = (function NetworkMa
         }
         return;
       }
 
       this.loadedRequests[xhrId] = true;
 
       var chunk = getArrayBuffer(xhr);
       if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
-        var rangeHeader = xhr.getResponseHeader('Content-Range');
+        var rangeHeader = xhr.getResponseHeader("Content-Range");
         var matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader);
         var begin = parseInt(matches[1], 10);
         pendingRequest.onDone({
           begin,
           chunk,
         });
       } else if (pendingRequest.onProgressiveData) {
         pendingRequest.onDone(null);
--- a/browser/extensions/pdfjs/content/PdfJsTelemetry.jsm
+++ b/browser/extensions/pdfjs/content/PdfJsTelemetry.jsm
@@ -10,61 +10,61 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 /* eslint max-len: ["error", 100] */
 /* globals Components, Services */
 
-'use strict';
+"use strict";
 
-this.EXPORTED_SYMBOLS = ['PdfJsTelemetry'];
+this.EXPORTED_SYMBOLS = ["PdfJsTelemetry"];
 
 const Cu = Components.utils;
-Cu.import('resource://gre/modules/Services.jsm');
+Cu.import("resource://gre/modules/Services.jsm");
 
 this.PdfJsTelemetry = {
   onViewerIsUsed() {
-    let histogram = Services.telemetry.getHistogramById('PDF_VIEWER_USED');
+    let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_USED");
     histogram.add(true);
   },
   onFallback() {
-    let histogram = Services.telemetry.getHistogramById('PDF_VIEWER_FALLBACK_SHOWN');
+    let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_FALLBACK_SHOWN");
     histogram.add(true);
   },
   onDocumentSize(size) {
-    let histogram = Services.telemetry.getHistogramById('PDF_VIEWER_DOCUMENT_SIZE_KB');
+    let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_DOCUMENT_SIZE_KB");
     histogram.add(size / 1024);
   },
   onDocumentVersion(versionId) {
-    let histogram = Services.telemetry.getHistogramById('PDF_VIEWER_DOCUMENT_VERSION');
+    let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_DOCUMENT_VERSION");
     histogram.add(versionId);
   },
   onDocumentGenerator(generatorId) {
-    let histogram = Services.telemetry.getHistogramById('PDF_VIEWER_DOCUMENT_GENERATOR');
+    let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_DOCUMENT_GENERATOR");
     histogram.add(generatorId);
   },
   onEmbed(isObject) {
-    let histogram = Services.telemetry.getHistogramById('PDF_VIEWER_EMBED');
+    let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_EMBED");
     histogram.add(isObject);
   },
   onFontType(fontTypeId) {
-    let histogram = Services.telemetry.getHistogramById('PDF_VIEWER_FONT_TYPES');
+    let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_FONT_TYPES");
     histogram.add(fontTypeId);
   },
   onForm(isAcroform) {
-    let histogram = Services.telemetry.getHistogramById('PDF_VIEWER_FORM');
+    let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_FORM");
     histogram.add(isAcroform);
   },
   onPrint() {
-    let histogram = Services.telemetry.getHistogramById('PDF_VIEWER_PRINT');
+    let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_PRINT");
     histogram.add(true);
   },
   onStreamType(streamTypeId) {
-    let histogram = Services.telemetry.getHistogramById('PDF_VIEWER_STREAM_TYPES');
+    let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_STREAM_TYPES");
     histogram.add(streamTypeId);
   },
   onTimeToView(ms) {
-    let histogram = Services.telemetry.getHistogramById('PDF_VIEWER_TIME_TO_VIEW_MS');
+    let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_TIME_TO_VIEW_MS");
     histogram.add(ms);
   }
 };
--- a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
+++ b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
@@ -10,64 +10,64 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 /* globals Components, Services, XPCOMUtils, NetUtil, PrivateBrowsingUtils,
            dump, NetworkManager, PdfJsTelemetry, PdfjsContentUtils */
 
-'use strict';
+"use strict";
 
-var EXPORTED_SYMBOLS = ['PdfStreamConverter'];
+var EXPORTED_SYMBOLS = ["PdfStreamConverter"];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 // True only if this is the version of pdf.js that is included with firefox.
-const MOZ_CENTRAL = JSON.parse('true');
-const PDFJS_EVENT_ID = 'pdf.js.message';
-const PDF_CONTENT_TYPE = 'application/pdf';
-const PREF_PREFIX = 'pdfjs';
-const PDF_VIEWER_WEB_PAGE = 'resource://pdf.js/web/viewer.html';
+const MOZ_CENTRAL = JSON.parse("true");
+const PDFJS_EVENT_ID = "pdf.js.message";
+const PDF_CONTENT_TYPE = "application/pdf";
+const PREF_PREFIX = "pdfjs";
+const PDF_VIEWER_WEB_PAGE = "resource://pdf.js/web/viewer.html";
 const MAX_NUMBER_OF_PREFS = 50;
 const MAX_STRING_PREF_LENGTH = 128;
 
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
-Cu.import('resource://gre/modules/NetUtil.jsm');
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, 'NetworkManager',
-  'resource://pdf.js/PdfJsNetwork.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, "NetworkManager",
+  "resource://pdf.js/PdfJsNetwork.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, 'PrivateBrowsingUtils',
-  'resource://gre/modules/PrivateBrowsingUtils.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
+  "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, 'PdfJsTelemetry',
-  'resource://pdf.js/PdfJsTelemetry.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, "PdfJsTelemetry",
+  "resource://pdf.js/PdfJsTelemetry.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, 'PdfjsContentUtils',
-  'resource://pdf.js/PdfjsContentUtils.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, "PdfjsContentUtils",
+  "resource://pdf.js/PdfjsContentUtils.jsm");
 
 var Svc = {};
-XPCOMUtils.defineLazyServiceGetter(Svc, 'mime',
-                                   '@mozilla.org/mime;1',
-                                   'nsIMIMEService');
+XPCOMUtils.defineLazyServiceGetter(Svc, "mime",
+                                   "@mozilla.org/mime;1",
+                                   "nsIMIMEService");
 
 function getContainingBrowser(domWindow) {
   return domWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                   .getInterface(Ci.nsIWebNavigation)
                   .QueryInterface(Ci.nsIDocShell)
                   .chromeEventHandler;
 }
 
 function getFindBar(domWindow) {
   if (PdfjsContentUtils.isRemote) {
-    throw new Error('FindBar is not accessible from the content process.');
+    throw new Error("FindBar is not accessible from the content process.");
   }
   try {
     var browser = getContainingBrowser(domWindow);
     var tabbrowser = browser.getTabBrowser();
     var tab = tabbrowser.getTabForBrowser(browser);
     return tabbrowser.getFindBar(tab);
   } catch (e) {
     // Suppress errors for PDF files opened in the bookmark sidebar, see
@@ -96,56 +96,56 @@ function getStringPref(pref, def) {
   try {
     return Services.prefs.getComplexValue(pref, Ci.nsISupportsString).data;
   } catch (ex) {
     return def;
   }
 }
 
 function log(aMsg) {
-  if (!getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false)) {
+  if (!getBoolPref(PREF_PREFIX + ".pdfBugEnabled", false)) {
     return;
   }
-  var msg = 'PdfStreamConverter.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
+  var msg = "PdfStreamConverter.js: " + (aMsg.join ? aMsg.join("") : aMsg);
   Services.console.logStringMessage(msg);
-  dump(msg + '\n');
+  dump(msg + "\n");
 }
 
 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'].
+  var stringBundle = Cc["@mozilla.org/intl/stringbundle;1"].
       getService(Ci.nsIStringBundleService).
-      createBundle('chrome://pdf.js/locale/' + path);
+      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('.');
+    var key = string.key, property = "textContent";
+    var i = key.lastIndexOf(".");
     if (i >= 0) {
       property = key.substring(i + 1);
       key = key.substring(0, i);
     }
     if (!(key in map)) {
       map[key] = {};
     }
     map[key][property] = string.value;
   }
   return map;
 }
 function getLocalizedString(strings, id, property) {
-  property = property || 'textContent';
+  property = property || "textContent";
   if (id in strings) {
     return strings[id][property];
   }
   return id;
 }
 
 // PDF data storage
 function PdfDataListener(length) {
@@ -228,73 +228,73 @@ class ChromeActions {
   download(data, sendResponse) {
     var self = this;
     var originalUrl = data.originalUrl;
     var blobUrl = data.blobUrl || originalUrl;
     // The data may not be downloaded so we need just retry getting the pdf with
     // the original url.
     var originalUri = NetUtil.newURI(originalUrl);
     var filename = data.filename;
-    if (typeof filename !== 'string' ||
+    if (typeof filename !== "string" ||
         (!/\.pdf$/i.test(filename) && !data.isAttachment)) {
-      filename = 'document.pdf';
+      filename = "document.pdf";
     }
     var blobUri = NetUtil.newURI(blobUrl);
     var extHelperAppSvc =
-          Cc['@mozilla.org/uriloader/external-helper-app-service;1'].
+          Cc["@mozilla.org/uriloader/external-helper-app-service;1"].
              getService(Ci.nsIExternalHelperAppService);
 
     var docIsPrivate = this.isInPrivateBrowsing();
     var netChannel = NetUtil.newChannel({
       uri: blobUri,
       loadUsingSystemPrincipal: true,
     });
-    if ('nsIPrivateBrowsingChannel' in Ci &&
+    if ("nsIPrivateBrowsingChannel" in Ci &&
         netChannel instanceof Ci.nsIPrivateBrowsingChannel) {
       netChannel.setPrivate(docIsPrivate);
     }
     NetUtil.asyncFetch(netChannel, function(aInputStream, aResult) {
       if (!Components.isSuccessCode(aResult)) {
         if (sendResponse) {
           sendResponse(true);
         }
         return;
       }
       // Create a nsIInputStreamChannel so we can set the url on the channel
       // so the filename will be correct.
-      var channel = Cc['@mozilla.org/network/input-stream-channel;1'].
+      var channel = Cc["@mozilla.org/network/input-stream-channel;1"].
                        createInstance(Ci.nsIInputStreamChannel);
       channel.QueryInterface(Ci.nsIChannel);
       try {
         // contentDisposition/contentDispositionFilename is readonly before FF18
         channel.contentDisposition = Ci.nsIChannel.DISPOSITION_ATTACHMENT;
         if (self.contentDispositionFilename && !data.isAttachment) {
           channel.contentDispositionFilename = self.contentDispositionFilename;
         } else {
           channel.contentDispositionFilename = filename;
         }
       } catch (e) {}
       channel.setURI(originalUri);
       channel.loadInfo = netChannel.loadInfo;
       channel.contentStream = aInputStream;
-      if ('nsIPrivateBrowsingChannel' in Ci &&
+      if ("nsIPrivateBrowsingChannel" in Ci &&
           channel instanceof Ci.nsIPrivateBrowsingChannel) {
         channel.setPrivate(docIsPrivate);
       }
 
       var listener = {
         extListener: null,
         onStartRequest(aRequest, aContext) {
           var loadContext = self.domWindow
                                 .QueryInterface(Ci.nsIInterfaceRequestor)
                                 .getInterface(Ci.nsIWebNavigation)
                                 .QueryInterface(Ci.nsILoadContext);
           this.extListener = extHelperAppSvc.doContent(
-            (data.isAttachment ? 'application/octet-stream' :
-                                 'application/pdf'),
+            (data.isAttachment ? "application/octet-stream" :
+                                 "application/pdf"),
             aRequest, loadContext, false);
           this.extListener.onStartRequest(aRequest, aContext);
         },
         onStopRequest(aRequest, aContext, aStatusCode) {
           if (this.extListener) {
             this.extListener.onStopRequest(aRequest, aContext, aStatusCode);
           }
           // Notify the content code we're done downloading.
@@ -308,92 +308,92 @@ class ChromeActions {
         }
       };
 
       channel.asyncOpen2(listener);
     });
   }
 
   getLocale() {
-    return getStringPref('general.useragent.locale', 'en-US');
+    return getStringPref("general.useragent.locale", "en-US");
   }
 
   getStrings(data) {
     try {
       // Lazy initialization of localizedStrings
-      if (!('localizedStrings' in this)) {
-        this.localizedStrings = getLocalizedStrings('viewer.properties');
+      if (!("localizedStrings" in this)) {
+        this.localizedStrings = getLocalizedStrings("viewer.properties");
       }
       var result = this.localizedStrings[data];
       return JSON.stringify(result || null);
     } catch (e) {
-      log('Unable to retrieve localized strings: ' + e);
-      return 'null';
+      log("Unable to retrieve localized strings: " + e);
+      return "null";
     }
   }
 
   supportsIntegratedFind() {
     // Integrated find is only supported when we're not in a frame
     if (this.domWindow.frameElement !== null) {
       return false;
     }
 
     // ... and we are in a child process
     if (PdfjsContentUtils.isRemote) {
       return true;
     }
 
     // ... or when the new find events code exists.
     var findBar = getFindBar(this.domWindow);
-    return !!findBar && ('updateControlState' in findBar);
+    return !!findBar && ("updateControlState" in findBar);
   }
 
   supportsDocumentFonts() {
-    var prefBrowser = getIntPref('browser.display.use_document_fonts', 1);
-    var prefGfx = getBoolPref('gfx.downloadable_fonts.enabled', true);
+    var prefBrowser = getIntPref("browser.display.use_document_fonts", 1);
+    var prefGfx = getBoolPref("gfx.downloadable_fonts.enabled", true);
     return (!!prefBrowser && prefGfx);
   }
 
   supportsDocumentColors() {
-    return getIntPref('browser.display.document_color_use', 0) !== 2;
+    return getIntPref("browser.display.document_color_use", 0) !== 2;
   }
 
   supportedMouseWheelZoomModifierKeys() {
     return {
-      ctrlKey: getIntPref('mousewheel.with_control.action', 3) === 3,
-      metaKey: getIntPref('mousewheel.with_meta.action', 1) === 3,
+      ctrlKey: getIntPref("mousewheel.with_control.action", 3) === 3,
+      metaKey: getIntPref("mousewheel.with_meta.action", 1) === 3,
     };
   }
 
   reportTelemetry(data) {
     var probeInfo = JSON.parse(data);
     switch (probeInfo.type) {
-      case 'documentInfo':
+      case "documentInfo":
         if (!this.telemetryState.documentInfo) {
           PdfJsTelemetry.onDocumentVersion(probeInfo.version | 0);
           PdfJsTelemetry.onDocumentGenerator(probeInfo.generator | 0);
           if (probeInfo.formType) {
-            PdfJsTelemetry.onForm(probeInfo.formType === 'acroform');
+            PdfJsTelemetry.onForm(probeInfo.formType === "acroform");
           }
           this.telemetryState.documentInfo = true;
         }
         break;
-      case 'pageInfo':
+      case "pageInfo":
         if (!this.telemetryState.firstPageInfo) {
           var duration = Date.now() - this.telemetryState.startAt;
           PdfJsTelemetry.onTimeToView(duration);
           this.telemetryState.firstPageInfo = true;
         }
         break;
-      case 'documentStats':
+      case "documentStats":
         // documentStats can be called several times for one documents.
         // if stream/font types are reported, trying not to submit the same
         // enumeration value multiple times.
         var documentStats = probeInfo.stats;
-        if (!documentStats || typeof documentStats !== 'object') {
+        if (!documentStats || typeof documentStats !== "object") {
           break;
         }
         var i, streamTypes = documentStats.streamTypes;
         if (Array.isArray(streamTypes)) {
           var STREAM_TYPE_ID_LIMIT = 20;
           for (i = 0; i < STREAM_TYPE_ID_LIMIT; i++) {
             if (streamTypes[i] &&
                 !this.telemetryState.streamTypesUsed[i]) {
@@ -409,145 +409,145 @@ class ChromeActions {
             if (fontTypes[i] &&
                 !this.telemetryState.fontTypesUsed[i]) {
               PdfJsTelemetry.onFontType(i);
               this.telemetryState.fontTypesUsed[i] = true;
             }
           }
         }
         break;
-      case 'print':
+      case "print":
         PdfJsTelemetry.onPrint();
         break;
     }
   }
 
   /**
    * @param {Object} args - Object with `featureId` and `url` properties.
    * @param {function} sendResponse - Callback function.
    */
   fallback(args, sendResponse) {
     var featureId = args.featureId;
 
     var domWindow = this.domWindow;
-    var strings = getLocalizedStrings('chrome.properties');
+    var strings = getLocalizedStrings("chrome.properties");
     var message;
-    if (featureId === 'forms') {
-      message = getLocalizedString(strings, 'unsupported_feature_forms');
+    if (featureId === "forms") {
+      message = getLocalizedString(strings, "unsupported_feature_forms");
     } else {
-      message = getLocalizedString(strings, 'unsupported_feature');
+      message = getLocalizedString(strings, "unsupported_feature");
     }
     PdfJsTelemetry.onFallback();
     PdfjsContentUtils.displayWarning(domWindow, message,
-      getLocalizedString(strings, 'open_with_different_viewer'),
-      getLocalizedString(strings, 'open_with_different_viewer', 'accessKey'));
+      getLocalizedString(strings, "open_with_different_viewer"),
+      getLocalizedString(strings, "open_with_different_viewer", "accessKey"));
 
     let winmm = domWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIDocShell)
                          .QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIContentFrameMessageManager);
 
-    winmm.addMessageListener('PDFJS:Child:fallbackDownload',
+    winmm.addMessageListener("PDFJS:Child:fallbackDownload",
       function fallbackDownload(msg) {
         let data = msg.data;
         sendResponse(data.download);
 
-        winmm.removeMessageListener('PDFJS:Child:fallbackDownload',
+        winmm.removeMessageListener("PDFJS:Child:fallbackDownload",
                                     fallbackDownload);
       });
   }
 
   updateFindControlState(data) {
     if (!this.supportsIntegratedFind()) {
       return;
     }
     // Verify what we're sending to the findbar.
     var result = data.result;
     var findPrevious = data.findPrevious;
     var findPreviousType = typeof findPrevious;
-    if ((typeof result !== 'number' || result < 0 || result > 3) ||
-        (findPreviousType !== 'undefined' && findPreviousType !== 'boolean')) {
+    if ((typeof result !== "number" || result < 0 || result > 3) ||
+        (findPreviousType !== "undefined" && findPreviousType !== "boolean")) {
       return;
     }
 
     var winmm = this.domWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                               .getInterface(Ci.nsIDocShell)
                               .QueryInterface(Ci.nsIInterfaceRequestor)
                               .getInterface(Ci.nsIContentFrameMessageManager);
 
-    winmm.sendAsyncMessage('PDFJS:Parent:updateControlState', data);
+    winmm.sendAsyncMessage("PDFJS:Parent:updateControlState", data);
   }
 
   setPreferences(prefs, sendResponse) {
-    var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.');
+    var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + ".");
     var numberOfPrefs = 0;
     var prefValue, prefName;
     for (var key in prefs) {
       if (++numberOfPrefs > MAX_NUMBER_OF_PREFS) {
-        log('setPreferences - Exceeded the maximum number of preferences ' +
-            'that is allowed to be set at once.');
+        log("setPreferences - Exceeded the maximum number of preferences " +
+            "that is allowed to be set at once.");
         break;
       } else if (!defaultBranch.getPrefType(key)) {
         continue;
       }
       prefValue = prefs[key];
-      prefName = (PREF_PREFIX + '.' + key);
+      prefName = (PREF_PREFIX + "." + key);
       switch (typeof prefValue) {
-        case 'boolean':
+        case "boolean":
           PdfjsContentUtils.setBoolPref(prefName, prefValue);
           break;
-        case 'number':
+        case "number":
           PdfjsContentUtils.setIntPref(prefName, prefValue);
           break;
-        case 'string':
+        case "string":
           if (prefValue.length > MAX_STRING_PREF_LENGTH) {
-            log('setPreferences - Exceeded the maximum allowed length ' +
-                'for a string preference.');
+            log("setPreferences - Exceeded the maximum allowed length " +
+                "for a string preference.");
           } else {
             PdfjsContentUtils.setStringPref(prefName, prefValue);
           }
           break;
       }
     }
     if (sendResponse) {
       sendResponse(true);
     }
   }
 
   getPreferences(prefs, sendResponse) {
-    var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.');
+    var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + ".");
     var currentPrefs = {}, numberOfPrefs = 0;
     var prefValue, prefName;
     for (var key in prefs) {
       if (++numberOfPrefs > MAX_NUMBER_OF_PREFS) {
-        log('getPreferences - Exceeded the maximum number of preferences ' +
-            'that is allowed to be fetched at once.');
+        log("getPreferences - Exceeded the maximum number of preferences " +
+            "that is allowed to be fetched at once.");
         break;
       } else if (!defaultBranch.getPrefType(key)) {
         continue;
       }
       prefValue = prefs[key];
-      prefName = (PREF_PREFIX + '.' + key);
+      prefName = (PREF_PREFIX + "." + key);
       switch (typeof prefValue) {
-        case 'boolean':
+        case "boolean":
           currentPrefs[key] = getBoolPref(prefName, prefValue);
           break;
-        case 'number':
+        case "number":
           currentPrefs[key] = getIntPref(prefName, prefValue);
           break;
-        case 'string':
+        case "string":
           currentPrefs[key] = getStringPref(prefName, prefValue);
           break;
       }
     }
+    let result = JSON.stringify(currentPrefs);
     if (sendResponse) {
-      sendResponse(JSON.stringify(currentPrefs));
-    } else {
-      return JSON.stringify(currentPrefs);
+      sendResponse(result);
     }
+    return result;
   }
 }
 
 /**
  * This is for range requests.
  */
 class RangedChromeActions extends ChromeActions {
   constructor(domWindow, contentDispositionFilename, originalRequest,
@@ -561,17 +561,17 @@ class RangedChromeActions extends Chrome
 
     this.pdfUrl = originalRequest.URI.spec;
     this.contentLength = originalRequest.contentLength;
 
     // Pass all the headers from the original request through
     var httpHeaderVisitor = {
       headers: {},
       visitHeader(aHeader, aValue) {
-        if (aHeader === 'Range') {
+        if (aHeader === "Range") {
           // When loading the PDF from cache, firefox seems to set the Range
           // request header to fetch only the unfetched portions of the file
           // (e.g. 'Range: bytes=1024-'). However, we want to set this header
           // manually to fetch the PDF in chunks.
           return;
         }
         this.headers[aHeader] = aValue;
       }
@@ -579,39 +579,39 @@ class RangedChromeActions extends Chrome
     if (originalRequest.visitRequestHeaders) {
       originalRequest.visitRequestHeaders(httpHeaderVisitor);
     }
 
     var self = this;
     var xhr_onreadystatechange = function xhr_onreadystatechange() {
       if (this.readyState === 1) { // LOADING
         var netChannel = this.channel;
-        if ('nsIPrivateBrowsingChannel' in Ci &&
+        if ("nsIPrivateBrowsingChannel" in Ci &&
             netChannel instanceof Ci.nsIPrivateBrowsingChannel) {
           var docIsPrivate = self.isInPrivateBrowsing();
           netChannel.setPrivate(docIsPrivate);
         }
       }
     };
     var getXhr = function getXhr() {
       const XMLHttpRequest = Components.Constructor(
-          '@mozilla.org/xmlextras/xmlhttprequest;1');
+          "@mozilla.org/xmlextras/xmlhttprequest;1");
       var xhr = new XMLHttpRequest();
-      xhr.addEventListener('readystatechange', xhr_onreadystatechange);
+      xhr.addEventListener("readystatechange", xhr_onreadystatechange);
       return xhr;
     };
 
     this.networkManager = new NetworkManager(this.pdfUrl, {
       httpHeaders: httpHeaderVisitor.headers,
       getXhr,
     });
 
     // If we are in range request mode, this means we manually issued xhr
     // requests, which we need to abort when we leave the page
-    domWindow.addEventListener('unload', function unload(e) {
+    domWindow.addEventListener("unload", function unload(e) {
       domWindow.removeEventListener(e.type, unload);
       self.abortLoading();
     });
   }
 
   initPassiveLoading() {
     var data;
     if (!this.streamingEnabled) {
@@ -619,35 +619,35 @@ class RangedChromeActions extends Chrome
       this.originalRequest = null;
       data = this.dataListener.readData();
       this.dataListener = null;
     } else {
       data = this.dataListener.readData();
 
       this.dataListener.onprogress = (loaded, total) => {
         this.domWindow.postMessage({
-          pdfjsLoadAction: 'progressiveRead',
+          pdfjsLoadAction: "progressiveRead",
           loaded,
           total,
           chunk: this.dataListener.readData(),
-        }, '*');
+        }, "*");
       };
       this.dataListener.oncomplete = () => {
         this.dataListener = null;
       };
     }
 
     this.domWindow.postMessage({
-      pdfjsLoadAction: 'supportsRangedLoading',
+      pdfjsLoadAction: "supportsRangedLoading",
       rangeEnabled: this.rangeEnabled,
       streamingEnabled: this.streamingEnabled,
       pdfUrl: this.pdfUrl,
       length: this.contentLength,
       data,
-    }, '*');
+    }, "*");
 
     return true;
   }
 
   requestDataRange(args) {
     if (!this.rangeEnabled) {
       return;
     }
@@ -656,26 +656,26 @@ class RangedChromeActions extends Chrome
     var end = args.end;
     var domWindow = this.domWindow;
     // TODO(mack): Support error handler. We're not currently not handling
     // errors from chrome code for non-range requests, so this doesn't
     // seem high-pri
     this.networkManager.requestRange(begin, end, {
       onDone: function RangedChromeActions_onDone(aArgs) {
         domWindow.postMessage({
-          pdfjsLoadAction: 'range',
+          pdfjsLoadAction: "range",
           begin: aArgs.begin,
           chunk: aArgs.chunk,
-        }, '*');
+        }, "*");
       },
       onProgress: function RangedChromeActions_onProgress(evt) {
         domWindow.postMessage({
-          pdfjsLoadAction: 'rangeProgress',
+          pdfjsLoadAction: "rangeProgress",
           loaded: evt.loaded,
-        }, '*');
+        }, "*");
       }
     });
   }
 
   abortLoading() {
     this.networkManager.abortAllRequests();
     if (this.originalRequest) {
       this.originalRequest.cancel(Cr.NS_BINDING_ABORTED);
@@ -698,28 +698,28 @@ class StandardChromeActions extends Chro
 
   initPassiveLoading() {
     if (!this.dataListener) {
       return false;
     }
 
     this.dataListener.onprogress = (loaded, total) => {
       this.domWindow.postMessage({
-        pdfjsLoadAction: 'progress',
+        pdfjsLoadAction: "progress",
         loaded,
         total,
-      }, '*');
+      }, "*");
     };
 
     this.dataListener.oncomplete = (data, errorCode) => {
       this.domWindow.postMessage({
-        pdfjsLoadAction: 'complete',
+        pdfjsLoadAction: "complete",
         data,
         errorCode,
-      }, '*');
+      }, "*");
 
       this.dataListener = null;
       this.originalRequest = null;
     };
 
     return true;
   }
 
@@ -744,33 +744,33 @@ class RequestListener {
   receive(event) {
     var message = event.target;
     var doc = message.ownerDocument;
     var action = event.detail.action;
     var data = event.detail.data;
     var sync = event.detail.sync;
     var actions = this.actions;
     if (!(action in actions)) {
-      log('Unknown action: ' + action);
+      log("Unknown action: " + action);
       return;
     }
     var response;
     if (sync) {
       response = actions[action].call(this.actions, data);
       event.detail.response = Cu.cloneInto(response, doc.defaultView);
     } else {
       if (!event.detail.responseExpected) {
         doc.documentElement.removeChild(message);
         response = null;
       } else {
         response = function sendResponse(aResponse) {
           try {
-            var listener = doc.createEvent('CustomEvent');
+            var listener = doc.createEvent("CustomEvent");
             let detail = Cu.cloneInto({ response: aResponse }, doc.defaultView);
-            listener.initCustomEvent('pdf.js.response', true, false, detail);
+            listener.initCustomEvent("pdf.js.response", true, false, detail);
             return message.dispatchEvent(listener);
           } catch (e) {
             // doc is no longer accessible because the requestor is already
             // gone. unloaded content cannot receive the response anyway.
             return false;
           }
         };
       }
@@ -792,54 +792,54 @@ class FindEventManager {
                               .getInterface(Ci.nsIContentFrameMessageManager);
   }
 
   bind() {
     var unload = function(e) {
       this.unbind();
       this.contentWindow.removeEventListener(e.type, unload);
     }.bind(this);
-    this.contentWindow.addEventListener('unload', unload);
+    this.contentWindow.addEventListener("unload", unload);
 
     // We cannot directly attach listeners to for the find events
     // since the FindBar is in the parent process. Instead we're
     // asking the PdfjsChromeUtils to do it for us and forward
     // all the find events to us.
-    this.winmm.sendAsyncMessage('PDFJS:Parent:addEventListener');
-    this.winmm.addMessageListener('PDFJS:Child:handleEvent', this);
+    this.winmm.sendAsyncMessage("PDFJS:Parent:addEventListener");
+    this.winmm.addMessageListener("PDFJS:Child:handleEvent", this);
   }
 
   receiveMessage(msg) {
     var detail = msg.data.detail;
     var type = msg.data.type;
     var contentWindow = this.contentWindow;
 
     detail = Cu.cloneInto(detail, contentWindow);
-    var forward = contentWindow.document.createEvent('CustomEvent');
+    var forward = contentWindow.document.createEvent("CustomEvent");
     forward.initCustomEvent(type, true, true, detail);
     contentWindow.dispatchEvent(forward);
   }
 
   unbind() {
-    this.winmm.sendAsyncMessage('PDFJS:Parent:removeEventListener');
+    this.winmm.sendAsyncMessage("PDFJS:Parent:removeEventListener");
   }
 }
 
 function PdfStreamConverter() {
 }
 
 PdfStreamConverter.prototype = {
 
   // properties required for XPCOM registration:
-  classID: Components.ID('{d0c5195d-e798-49d4-b1d3-9324328b2291}'),
-  classDescription: 'pdf.js Component',
-  contractID: '@mozilla.org/streamconv;1?from=application/pdf&to=*/*',
+  classID: Components.ID("{d0c5195d-e798-49d4-b1d3-9324328b2291}"),
+  classDescription: "pdf.js Component",
+  contractID: "@mozilla.org/streamconv;1?from=application/pdf&to=*/*",
 
-  classID2: Components.ID('{d0c5195d-e798-49d4-b1d3-9324328b2292}'),
-  contractID2: '@mozilla.org/streamconv;1?from=application/pdf&to=text/html',
+  classID2: Components.ID("{d0c5195d-e798-49d4-b1d3-9324328b2292}"),
+  contractID2: "@mozilla.org/streamconv;1?from=application/pdf&to=text/html",
 
   QueryInterface: XPCOMUtils.generateQI([
       Ci.nsISupports,
       Ci.nsIStreamConverter,
       Ci.nsIStreamListener,
       Ci.nsIRequestObserver
   ]),
 
@@ -889,69 +889,69 @@ PdfStreamConverter.prototype = {
     try {
       aRequest.QueryInterface(Ci.nsIHttpChannel);
       isHttpRequest = true;
     } catch (e) {}
 
     var rangeRequest = false;
     var streamRequest = false;
     if (isHttpRequest) {
-      var contentEncoding = 'identity';
+      var contentEncoding = "identity";
       try {
-        contentEncoding = aRequest.getResponseHeader('Content-Encoding');
+        contentEncoding = aRequest.getResponseHeader("Content-Encoding");
       } catch (e) {}
 
       var acceptRanges;
       try {
-        acceptRanges = aRequest.getResponseHeader('Accept-Ranges');
+        acceptRanges = aRequest.getResponseHeader("Accept-Ranges");
       } catch (e) {}
 
       var hash = aRequest.URI.ref;
-      var isPDFBugEnabled = getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false);
-      rangeRequest = contentEncoding === 'identity' &&
-                     acceptRanges === 'bytes' &&
+      var isPDFBugEnabled = getBoolPref(PREF_PREFIX + ".pdfBugEnabled", false);
+      rangeRequest = contentEncoding === "identity" &&
+                     acceptRanges === "bytes" &&
                      aRequest.contentLength >= 0 &&
-                     !getBoolPref(PREF_PREFIX + '.disableRange', false) &&
+                     !getBoolPref(PREF_PREFIX + ".disableRange", false) &&
                      (!isPDFBugEnabled ||
-                      hash.toLowerCase().indexOf('disablerange=true') < 0);
-      streamRequest = contentEncoding === 'identity' &&
+                      hash.toLowerCase().indexOf("disablerange=true") < 0);
+      streamRequest = contentEncoding === "identity" &&
                       aRequest.contentLength >= 0 &&
-                      !getBoolPref(PREF_PREFIX + '.disableStream', false) &&
+                      !getBoolPref(PREF_PREFIX + ".disableStream", false) &&
                       (!isPDFBugEnabled ||
-                       hash.toLowerCase().indexOf('disablestream=true') < 0);
+                       hash.toLowerCase().indexOf("disablestream=true") < 0);
     }
 
     aRequest.QueryInterface(Ci.nsIChannel);
 
     aRequest.QueryInterface(Ci.nsIWritablePropertyBag);
 
     var contentDispositionFilename;
     try {
       contentDispositionFilename = aRequest.contentDispositionFilename;
     } catch (e) {}
 
     // Change the content type so we don't get stuck in a loop.
-    aRequest.setProperty('contentType', aRequest.contentType);
-    aRequest.contentType = 'text/html';
+    aRequest.setProperty("contentType", aRequest.contentType);
+    aRequest.contentType = "text/html";
     if (isHttpRequest) {
       // We trust PDF viewer, using no CSP
-      aRequest.setResponseHeader('Content-Security-Policy', '', false);
-      aRequest.setResponseHeader('Content-Security-Policy-Report-Only', '',
+      aRequest.setResponseHeader("Content-Security-Policy", "", false);
+      aRequest.setResponseHeader("Content-Security-Policy-Report-Only", "",
                                  false);
       // The viewer does not need to handle HTTP Refresh header.
-      aRequest.setResponseHeader('Refresh', '', false);
+      aRequest.setResponseHeader("Refresh", "", false);
     }
 
     PdfJsTelemetry.onViewerIsUsed();
     PdfJsTelemetry.onDocumentSize(aRequest.contentLength);
 
     // Creating storage for PDF data
     var contentLength = aRequest.contentLength;
     this.dataListener = new PdfDataListener(contentLength);
-    this.binaryStream = Cc['@mozilla.org/binaryinputstream;1']
+    this.binaryStream = Cc["@mozilla.org/binaryinputstream;1"]
                         .createInstance(Ci.nsIBinaryInputStream);
 
     // Create a new channel that is viewer loaded as a resource.
     var channel = NetUtil.newChannel({
       uri: PDF_VIEWER_WEB_PAGE,
       loadUsingSystemPrincipal: true,
     });
 
@@ -988,32 +988,32 @@ PdfStreamConverter.prototype = {
         }, false, true);
         if (actions.supportsIntegratedFind()) {
           var findEventManager = new FindEventManager(domWindow);
           findEventManager.bind();
         }
         listener.onStopRequest(aRequest, aContext, statusCode);
 
         if (domWindow.frameElement) {
-          var isObjectEmbed = domWindow.frameElement.tagName !== 'IFRAME' ||
-            domWindow.frameElement.className === 'previewPluginContentFrame';
+          var isObjectEmbed = domWindow.frameElement.tagName !== "IFRAME" ||
+            domWindow.frameElement.className === "previewPluginContentFrame";
           PdfJsTelemetry.onEmbed(isObjectEmbed);
         }
       }
     };
 
     // 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']
+    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);
     aRequest.owner = resourcePrincipal;
 
     channel.asyncOpen2(proxy);
   },
--- a/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm
+++ b/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm
@@ -9,35 +9,35 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 /* globals Components, Services, XPCOMUtils */
 
-'use strict';
+"use strict";
 
-var EXPORTED_SYMBOLS = ['PdfjsChromeUtils'];
+var EXPORTED_SYMBOLS = ["PdfjsChromeUtils"];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 
-const PREF_PREFIX = 'pdfjs';
-const PDF_CONTENT_TYPE = 'application/pdf';
+const PREF_PREFIX = "pdfjs";
+const PDF_CONTENT_TYPE = "application/pdf";
 
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
 
 var Svc = {};
-XPCOMUtils.defineLazyServiceGetter(Svc, 'mime',
-                                   '@mozilla.org/mime;1',
-                                   'nsIMIMEService');
+XPCOMUtils.defineLazyServiceGetter(Svc, "mime",
+                                   "@mozilla.org/mime;1",
+                                   "nsIMIMEService");
 
 var DEFAULT_PREFERENCES =
 {
   "showPreviousViewOnLoad": true,
   "defaultZoomValue": "",
   "sidebarViewOnLoad": 0,
   "enableHandToolOnLoad": false,
   "enableWebGL": false,
@@ -66,56 +66,56 @@ var PdfjsChromeUtils = {
   /*
    * Public API
    */
 
   init() {
     this._browsers = new WeakSet();
     if (!this._ppmm) {
       // global parent process message manager (PPMM)
-      this._ppmm = Cc['@mozilla.org/parentprocessmessagemanager;1'].
+      this._ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"].
         getService(Ci.nsIMessageBroadcaster);
-      this._ppmm.addMessageListener('PDFJS:Parent:clearUserPref', this);
-      this._ppmm.addMessageListener('PDFJS:Parent:setIntPref', this);
-      this._ppmm.addMessageListener('PDFJS:Parent:setBoolPref', this);
-      this._ppmm.addMessageListener('PDFJS:Parent:setCharPref', this);
-      this._ppmm.addMessageListener('PDFJS:Parent:setStringPref', this);
-      this._ppmm.addMessageListener('PDFJS:Parent:isDefaultHandlerApp', this);
+      this._ppmm.addMessageListener("PDFJS:Parent:clearUserPref", this);
+      this._ppmm.addMessageListener("PDFJS:Parent:setIntPref", this);
+      this._ppmm.addMessageListener("PDFJS:Parent:setBoolPref", this);
+      this._ppmm.addMessageListener("PDFJS:Parent:setCharPref", this);
+      this._ppmm.addMessageListener("PDFJS:Parent:setStringPref", this);
+      this._ppmm.addMessageListener("PDFJS:Parent:isDefaultHandlerApp", this);
 
       // global dom message manager (MMg)
-      this._mmg = Cc['@mozilla.org/globalmessagemanager;1'].
+      this._mmg = Cc["@mozilla.org/globalmessagemanager;1"].
         getService(Ci.nsIMessageListenerManager);
-      this._mmg.addMessageListener('PDFJS:Parent:displayWarning', this);
+      this._mmg.addMessageListener("PDFJS:Parent:displayWarning", this);
 
-      this._mmg.addMessageListener('PDFJS:Parent:addEventListener', this);
-      this._mmg.addMessageListener('PDFJS:Parent:removeEventListener', this);
-      this._mmg.addMessageListener('PDFJS:Parent:updateControlState', this);
+      this._mmg.addMessageListener("PDFJS:Parent:addEventListener", this);
+      this._mmg.addMessageListener("PDFJS:Parent:removeEventListener", this);
+      this._mmg.addMessageListener("PDFJS:Parent:updateControlState", this);
 
       // observer to handle shutdown
-      Services.obs.addObserver(this, 'quit-application', false);
+      Services.obs.addObserver(this, "quit-application", false);
     }
   },
 
   uninit() {
     if (this._ppmm) {
-      this._ppmm.removeMessageListener('PDFJS:Parent:clearUserPref', this);
-      this._ppmm.removeMessageListener('PDFJS:Parent:setIntPref', this);
-      this._ppmm.removeMessageListener('PDFJS:Parent:setBoolPref', this);
-      this._ppmm.removeMessageListener('PDFJS:Parent:setCharPref', this);
-      this._ppmm.removeMessageListener('PDFJS:Parent:setStringPref', this);
-      this._ppmm.removeMessageListener('PDFJS:Parent:isDefaultHandlerApp',
+      this._ppmm.removeMessageListener("PDFJS:Parent:clearUserPref", this);
+      this._ppmm.removeMessageListener("PDFJS:Parent:setIntPref", this);
+      this._ppmm.removeMessageListener("PDFJS:Parent:setBoolPref", this);
+      this._ppmm.removeMessageListener("PDFJS:Parent:setCharPref", this);
+      this._ppmm.removeMessageListener("PDFJS:Parent:setStringPref", this);
+      this._ppmm.removeMessageListener("PDFJS:Parent:isDefaultHandlerApp",
                                        this);
 
-      this._mmg.removeMessageListener('PDFJS:Parent:displayWarning', this);
+      this._mmg.removeMessageListener("PDFJS:Parent:displayWarning", this);
 
-      this._mmg.removeMessageListener('PDFJS:Parent:addEventListener', this);
-      this._mmg.removeMessageListener('PDFJS:Parent:removeEventListener', this);
-      this._mmg.removeMessageListener('PDFJS:Parent:updateControlState', this);
+      this._mmg.removeMessageListener("PDFJS:Parent:addEventListener", this);
+      this._mmg.removeMessageListener("PDFJS:Parent:removeEventListener", this);
+      this._mmg.removeMessageListener("PDFJS:Parent:updateControlState", this);
 
-      Services.obs.removeObserver(this, 'quit-application');
+      Services.obs.removeObserver(this, "quit-application");
 
       this._mmg = null;
       this._ppmm = null;
     }
   },
 
   /*
    * Called by the main module when preference changes are picked up
@@ -126,61 +126,61 @@ var PdfjsChromeUtils = {
   notifyChildOfSettingsChange() {
     if (Services.appinfo.processType ===
         Services.appinfo.PROCESS_TYPE_DEFAULT && this._ppmm) {
       // XXX kinda bad, we want to get the parent process mm associated
       // with the content process. _ppmm is currently the global process
       // manager, which means this is going to fire to every child process
       // we have open. Unfortunately I can't find a way to get at that
       // process specific mm from js.
-      this._ppmm.broadcastAsyncMessage('PDFJS:Child:refreshSettings', {});
+      this._ppmm.broadcastAsyncMessage("PDFJS:Child:refreshSettings", {});
     }
   },
 
   /*
    * Events
    */
 
   observe(aSubject, aTopic, aData) {
-    if (aTopic === 'quit-application') {
+    if (aTopic === "quit-application") {
       this.uninit();
     }
   },
 
   receiveMessage(aMsg) {
     switch (aMsg.name) {
-      case 'PDFJS:Parent:clearUserPref':
+      case "PDFJS:Parent:clearUserPref":
         this._clearUserPref(aMsg.data.name);
         break;
-      case 'PDFJS:Parent:setIntPref':
+      case "PDFJS:Parent:setIntPref":
         this._setIntPref(aMsg.data.name, aMsg.data.value);
         break;
-      case 'PDFJS:Parent:setBoolPref':
+      case "PDFJS:Parent:setBoolPref":
         this._setBoolPref(aMsg.data.name, aMsg.data.value);
         break;
-      case 'PDFJS:Parent:setCharPref':
+      case "PDFJS:Parent:setCharPref":
         this._setCharPref(aMsg.data.name, aMsg.data.value);
         break;
-      case 'PDFJS:Parent:setStringPref':
+      case "PDFJS:Parent:setStringPref":
         this._setStringPref(aMsg.data.name, aMsg.data.value);
         break;
-      case 'PDFJS:Parent:isDefaultHandlerApp':
+      case "PDFJS:Parent:isDefaultHandlerApp":
         return this.isDefaultHandlerApp();
-      case 'PDFJS:Parent:displayWarning':
+      case "PDFJS:Parent:displayWarning":
         this._displayWarning(aMsg);
         break;
 
-
-      case 'PDFJS:Parent:updateControlState':
+      case "PDFJS:Parent:updateControlState":
         return this._updateControlState(aMsg);
-      case 'PDFJS:Parent:addEventListener':
+      case "PDFJS:Parent:addEventListener":
         return this._addEventListener(aMsg);
-      case 'PDFJS:Parent:removeEventListener':
+      case "PDFJS:Parent:removeEventListener":
         return this._removeEventListener(aMsg);
     }
+    return undefined;
   },
 
   /*
    * Internal
    */
 
   _findbarFromMessage(aMsg) {
     let browser = aMsg.target;
@@ -203,35 +203,35 @@ var PdfjsChromeUtils = {
       query: aEvent.detail.query,
       caseSensitive: aEvent.detail.caseSensitive,
       highlightAll: aEvent.detail.highlightAll,
       findPrevious: aEvent.detail.findPrevious
     };
 
     let browser = aEvent.currentTarget.browser;
     if (!this._browsers.has(browser)) {
-      throw new Error('FindEventManager was not bound ' +
-                      'for the current browser.');
+      throw new Error("FindEventManager was not bound " +
+                      "for the current browser.");
     }
     // Only forward the events if the current browser is a registered browser.
     let mm = browser.messageManager;
-    mm.sendAsyncMessage('PDFJS:Child:handleEvent', { type, detail, });
+    mm.sendAsyncMessage("PDFJS:Child:handleEvent", { type, detail, });
     aEvent.preventDefault();
   },
 
-  _types: ['find',
-           'findagain',
-           'findhighlightallchange',
-           'findcasesensitivitychange'],
+  _types: ["find",
+           "findagain",
+           "findhighlightallchange",
+           "findcasesensitivitychange"],
 
   _addEventListener(aMsg) {
     let browser = aMsg.target;
     if (this._browsers.has(browser)) {
-      throw new Error('FindEventManager was bound 2nd time ' +
-                      'without unbinding it first.');
+      throw new Error("FindEventManager was bound 2nd time " +
+                      "without unbinding it first.");
     }
 
     // Since this jsm is global, we need to store all the browsers
     // we have to forward the messages for.
     this._browsers.add(browser);
 
     // And we need to start listening to find events.
     for (var i = 0; i < this._types.length; i++) {
@@ -239,35 +239,35 @@ var PdfjsChromeUtils = {
       this._findbarFromMessage(aMsg)
           .addEventListener(type, this, true);
     }
   },
 
   _removeEventListener(aMsg) {
     let browser = aMsg.target;
     if (!this._browsers.has(browser)) {
-      throw new Error('FindEventManager was unbound without binding it first.');
+      throw new Error("FindEventManager was unbound without binding it first.");
     }
 
     this._browsers.delete(browser);
 
     // No reason to listen to find events any longer.
     for (var i = 0; i < this._types.length; i++) {
       var type = this._types[i];
       this._findbarFromMessage(aMsg)
           .removeEventListener(type, this, true);
     }
   },
 
   _ensurePreferenceAllowed(aPrefName) {
-    let unPrefixedName = aPrefName.split(PREF_PREFIX + '.');
-    if (unPrefixedName[0] !== '' ||
+    let unPrefixedName = aPrefName.split(PREF_PREFIX + ".");
+    if (unPrefixedName[0] !== "" ||
         this._allowedPrefNames.indexOf(unPrefixedName[1]) === -1) {
-      let msg = '"' + aPrefName + '" ' +
-                'can\'t be accessed from content. See PdfjsChromeUtils.';
+      let msg = "\"" + aPrefName + "\" " +
+                "can't be accessed from content. See PdfjsChromeUtils.";
       throw new Error(msg);
     }
   },
 
   _clearUserPref(aPrefName) {
     this._ensurePreferenceAllowed(aPrefName);
     Services.prefs.clearUserPref(aPrefName);
   },
@@ -284,29 +284,29 @@ var PdfjsChromeUtils = {
 
   _setCharPref(aPrefName, aPrefValue) {
     this._ensurePreferenceAllowed(aPrefName);
     Services.prefs.setCharPref(aPrefName, aPrefValue);
   },
 
   _setStringPref(aPrefName, aPrefValue) {
     this._ensurePreferenceAllowed(aPrefName);
-    let str = Cc['@mozilla.org/supports-string;1']
+    let str = Cc["@mozilla.org/supports-string;1"]
                 .createInstance(Ci.nsISupportsString);
     str.data = aPrefValue;
     Services.prefs.setComplexValue(aPrefName, Ci.nsISupportsString, str);
   },
 
   /*
    * Svc.mime doesn't have profile information in the child, so
    * we bounce this pdfjs enabled configuration check over to the
    * parent.
    */
   isDefaultHandlerApp() {
-    var handlerInfo = Svc.mime.getFromTypeAndExtension(PDF_CONTENT_TYPE, 'pdf');
+    var handlerInfo = Svc.mime.getFromTypeAndExtension(PDF_CONTENT_TYPE, "pdf");
     return (!handlerInfo.alwaysAskBeforeHandling &&
             handlerInfo.preferredAction === Ci.nsIHandlerInfo.handleInternally);
   },
 
   /*
    * Display a notification warning when the renderer isn't sure
    * a pdf displayed correctly.
    */
@@ -318,33 +318,33 @@ var PdfjsChromeUtils = {
     let notificationBox = tabbrowser.getNotificationBox(browser);
 
     // Flag so we don't send the message twice, since if the user clicks
     // "open with different viewer" both the button callback and
     // eventCallback will be called.
     let messageSent = false;
     function sendMessage(download) {
       let mm = browser.messageManager;
-      mm.sendAsyncMessage('PDFJS:Child:fallbackDownload', { download, });
+      mm.sendAsyncMessage("PDFJS:Child:fallbackDownload", { download, });
     }
     let buttons = [{
       label: data.label,
       accessKey: data.accessKey,
       callback() {
         messageSent = true;
         sendMessage(true);
       }
     }];
-    notificationBox.appendNotification(data.message, 'pdfjs-fallback', null,
+    notificationBox.appendNotification(data.message, "pdfjs-fallback", null,
                                        notificationBox.PRIORITY_INFO_LOW,
                                        buttons,
                                        function eventsCallback(eventType) {
       // Currently there is only one event "removed" but if there are any other
       // added in the future we still only care about removed at the moment.
-      if (eventType !== 'removed') {
+      if (eventType !== "removed") {
         return;
       }
       // Don't send a response again if we already responded when the button was
       // clicked.
       if (messageSent) {
         return;
       }
       sendMessage(false);
--- a/browser/extensions/pdfjs/content/PdfjsContentUtils.jsm
+++ b/browser/extensions/pdfjs/content/PdfjsContentUtils.jsm
@@ -9,27 +9,27 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 /* globals Components, Services, XPCOMUtils */
 
-'use strict';
+"use strict";
 
-var EXPORTED_SYMBOLS = ['PdfjsContentUtils'];
+var EXPORTED_SYMBOLS = ["PdfjsContentUtils"];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
 
 var PdfjsContentUtils = {
   _mm: null,
 
   /*
    * Public API
    */
 
@@ -37,113 +37,113 @@ var PdfjsContentUtils = {
     return (Services.appinfo.processType ===
             Services.appinfo.PROCESS_TYPE_CONTENT);
   },
 
   init() {
     // child *process* mm, or when loaded into the parent for in-content
     // support the psuedo child process mm 'child PPMM'.
     if (!this._mm) {
-      this._mm = Cc['@mozilla.org/childprocessmessagemanager;1'].
+      this._mm = Cc["@mozilla.org/childprocessmessagemanager;1"].
         getService(Ci.nsISyncMessageSender);
-      this._mm.addMessageListener('PDFJS:Child:refreshSettings', this);
-      Services.obs.addObserver(this, 'quit-application', false);
+      this._mm.addMessageListener("PDFJS:Child:refreshSettings", this);
+      Services.obs.addObserver(this, "quit-application", false);
     }
   },
 
   uninit() {
     if (this._mm) {
-      this._mm.removeMessageListener('PDFJS:Child:refreshSettings', this);
-      Services.obs.removeObserver(this, 'quit-application');
+      this._mm.removeMessageListener("PDFJS:Child:refreshSettings", this);
+      Services.obs.removeObserver(this, "quit-application");
     }
     this._mm = null;
   },
 
   /*
    * prefs utilities - the child does not have write access to prefs.
    * note, the pref names here are cross-checked against a list of
    * approved pdfjs prefs in chrome utils.
    */
 
   clearUserPref(aPrefName) {
-    this._mm.sendSyncMessage('PDFJS:Parent:clearUserPref', {
+    this._mm.sendSyncMessage("PDFJS:Parent:clearUserPref", {
       name: aPrefName
     });
   },
 
   setIntPref(aPrefName, aPrefValue) {
-    this._mm.sendSyncMessage('PDFJS:Parent:setIntPref', {
+    this._mm.sendSyncMessage("PDFJS:Parent:setIntPref", {
       name: aPrefName,
       value: aPrefValue
     });
   },
 
   setBoolPref(aPrefName, aPrefValue) {
-    this._mm.sendSyncMessage('PDFJS:Parent:setBoolPref', {
+    this._mm.sendSyncMessage("PDFJS:Parent:setBoolPref", {
       name: aPrefName,
       value: aPrefValue
     });
   },
 
   setCharPref(aPrefName, aPrefValue) {
-    this._mm.sendSyncMessage('PDFJS:Parent:setCharPref', {
+    this._mm.sendSyncMessage("PDFJS:Parent:setCharPref", {
       name: aPrefName,
       value: aPrefValue
     });
   },
 
   setStringPref(aPrefName, aPrefValue) {
-    this._mm.sendSyncMessage('PDFJS:Parent:setStringPref', {
+    this._mm.sendSyncMessage("PDFJS:Parent:setStringPref", {
       name: aPrefName,
       value: aPrefValue
     });
   },
 
   /*
    * Forwards default app query to the parent where we check various
    * handler app settings only available in the parent process.
    */
   isDefaultHandlerApp() {
-    return this._mm.sendSyncMessage('PDFJS:Parent:isDefaultHandlerApp')[0];
+    return this._mm.sendSyncMessage("PDFJS:Parent:isDefaultHandlerApp")[0];
   },
 
   /*
    * Request the display of a notification warning in the associated window
    * when the renderer isn't sure a pdf displayed correctly.
    */
   displayWarning(aWindow, aMessage, aLabel, aAccessKey) {
     // the child's dom frame mm associated with the window.
     let winmm = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIDocShell)
                        .QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIContentFrameMessageManager);
-    winmm.sendAsyncMessage('PDFJS:Parent:displayWarning', {
+    winmm.sendAsyncMessage("PDFJS:Parent:displayWarning", {
       message: aMessage,
       label: aLabel,
       accessKey: aAccessKey,
     });
   },
 
   /*
    * Events
    */
 
   observe(aSubject, aTopic, aData) {
-    if (aTopic === 'quit-application') {
+    if (aTopic === "quit-application") {
       this.uninit();
     }
   },
 
   receiveMessage(aMsg) {
     switch (aMsg.name) {
-      case 'PDFJS:Child:refreshSettings':
+      case "PDFJS:Child:refreshSettings":
         // Only react to this if we are remote.
         if (Services.appinfo.processType ===
             Services.appinfo.PROCESS_TYPE_CONTENT) {
-          let jsm = 'resource://pdf.js/PdfJs.jsm';
+          let jsm = "resource://pdf.js/PdfJs.jsm";
           let pdfjs = Components.utils.import(jsm, {}).PdfJs;
           pdfjs.updateRegistration();
         }
         break;
     }
   }
 };
 
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -18,18 +18,18 @@
   define('pdfjs-dist/build/pdf', ['exports'], factory);
  } else if (typeof exports !== 'undefined') {
   factory(exports);
  } else {
   factory(root['pdfjsDistBuildPdf'] = {});
  }
 }(this, function (exports) {
  'use strict';
- var pdfjsVersion = '1.7.227';
- var pdfjsBuild = 'e132fa97';
+ var pdfjsVersion = '1.7.235';
+ var pdfjsBuild = '3f320f0b';
  var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : null;
  var pdfjsLibs = {};
  (function pdfjsWrapper() {
   (function (root, factory) {
    factory(root.pdfjsSharedUtil = {});
   }(this, function (exports) {
    var globalScope = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this;
    var FONT_IDENTITY_MATRIX = [
@@ -4688,23 +4688,17 @@
        ctx.save();
        if (this.baseTransform) {
         ctx.setTransform.apply(ctx, this.baseTransform);
        }
        ctx.fillStyle = fillColor.getPattern(ctx, this);
        needRestore = true;
       }
       if (this.pendingEOFill) {
-       if (ctx.mozFillRule !== undefined) {
-        ctx.mozFillRule = 'evenodd';
-        ctx.fill();
-        ctx.mozFillRule = 'nonzero';
-       } else {
-        ctx.fill('evenodd');
-       }
+       ctx.fill('evenodd');
        this.pendingEOFill = false;
       } else {
        ctx.fill();
       }
       if (needRestore) {
        ctx.restore();
       }
       if (consumePath) {
@@ -5526,23 +5520,17 @@
      beginCompat: function CanvasGraphics_beginCompat() {
      },
      endCompat: function CanvasGraphics_endCompat() {
      },
      consumePath: function CanvasGraphics_consumePath() {
       var ctx = this.ctx;
       if (this.pendingClip) {
        if (this.pendingClip === EO_CLIP) {
-        if (ctx.mozFillRule !== undefined) {
-         ctx.mozFillRule = 'evenodd';
-         ctx.clip();
-         ctx.mozFillRule = 'nonzero';
-        } else {
-         ctx.clip('evenodd');
-        }
+        ctx.clip('evenodd');
        } else {
         ctx.clip();
        }
        this.pendingClip = null;
       }
       ctx.beginPath();
      },
      getSinglePixelWidth: function CanvasGraphics_getSinglePixelWidth(scale) {
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -18,18 +18,18 @@
   define('pdfjs-dist/build/pdf.worker', ['exports'], factory);
  } else if (typeof exports !== 'undefined') {
   factory(exports);
  } else {
   factory(root['pdfjsDistBuildPdfWorker'] = {});
  }
 }(this, function (exports) {
  'use strict';
- var pdfjsVersion = '1.7.227';
- var pdfjsBuild = 'e132fa97';
+ var pdfjsVersion = '1.7.235';
+ var pdfjsBuild = '3f320f0b';
  var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : null;
  var pdfjsLibs = {};
  (function pdfjsWrapper() {
   (function (root, factory) {
    factory(root.pdfjsCoreArithmeticDecoder = {});
   }(this, function (exports) {
    var ArithmeticDecoder = function ArithmeticDecoderClosure() {
     var QeTable = [
@@ -19515,16 +19515,17 @@
     return MurmurHash3_64;
    }();
    exports.MurmurHash3_64 = MurmurHash3_64;
   }));
   (function (root, factory) {
    factory(root.pdfjsCorePrimitives = {}, root.pdfjsSharedUtil);
   }(this, function (exports, sharedUtil) {
    var isArray = sharedUtil.isArray;
+   var EOF = {};
    var Name = function NameClosure() {
     function Name(name) {
      this.name = name;
     }
     Name.prototype = {};
     var nameCache = Object.create(null);
     Name.get = function Name_get(name) {
      var nameValue = nameCache[name];
@@ -19700,16 +19701,19 @@
       }
      },
      clear: function RefSetCache_clear() {
       this.dict = Object.create(null);
      }
     };
     return RefSetCache;
    }();
+   function isEOF(v) {
+    return v === EOF;
+   }
    function isName(v, name) {
     return v instanceof Name && (name === undefined || v.name === name);
    }
    function isCmd(v, cmd) {
     return v instanceof Cmd && (cmd === undefined || v.cmd === cmd);
    }
    function isDict(v, type) {
     return v instanceof Dict && (type === undefined || isName(v.get('Type'), type));
@@ -19718,22 +19722,24 @@
     return v instanceof Ref;
    }
    function isRefsEqual(v1, v2) {
     return v1.num === v2.num && v1.gen === v2.gen;
    }
    function isStream(v) {
     return typeof v === 'object' && v !== null && v.getBytes !== undefined;
    }
+   exports.EOF = EOF;
    exports.Cmd = Cmd;
    exports.Dict = Dict;
    exports.Name = Name;
    exports.Ref = Ref;
    exports.RefSet = RefSet;
    exports.RefSetCache = RefSetCache;
+   exports.isEOF = isEOF;
    exports.isCmd = isCmd;
    exports.isDict = isDict;
    exports.isName = isName;
    exports.isRef = isRef;
    exports.isRefsEqual = isRefsEqual;
    exports.isStream = isStream;
   }));
   (function (root, factory) {
@@ -22346,16 +22352,210 @@
    }
    exports.mapSpecialUnicodeValues = mapSpecialUnicodeValues;
    exports.reverseIfRtl = reverseIfRtl;
    exports.getUnicodeRangeFor = getUnicodeRangeFor;
    exports.getNormalizedUnicodes = getNormalizedUnicodes;
    exports.getUnicodeForGlyph = getUnicodeForGlyph;
   }));
   (function (root, factory) {
+   factory(root.pdfjsCorePsParser = {}, root.pdfjsSharedUtil, root.pdfjsCorePrimitives);
+  }(this, function (exports, sharedUtil, corePrimitives) {
+   var error = sharedUtil.error;
+   var isSpace = sharedUtil.isSpace;
+   var EOF = corePrimitives.EOF;
+   var PostScriptParser = function PostScriptParserClosure() {
+    function PostScriptParser(lexer) {
+     this.lexer = lexer;
+     this.operators = [];
+     this.token = null;
+     this.prev = null;
+    }
+    PostScriptParser.prototype = {
+     nextToken: function PostScriptParser_nextToken() {
+      this.prev = this.token;
+      this.token = this.lexer.getToken();
+     },
+     accept: function PostScriptParser_accept(type) {
+      if (this.token.type === type) {
+       this.nextToken();
+       return true;
+      }
+      return false;
+     },
+     expect: function PostScriptParser_expect(type) {
+      if (this.accept(type)) {
+       return true;
+      }
+      error('Unexpected symbol: found ' + this.token.type + ' expected ' + type + '.');
+     },
+     parse: function PostScriptParser_parse() {
+      this.nextToken();
+      this.expect(PostScriptTokenTypes.LBRACE);
+      this.parseBlock();
+      this.expect(PostScriptTokenTypes.RBRACE);
+      return this.operators;
+     },
+     parseBlock: function PostScriptParser_parseBlock() {
+      while (true) {
+       if (this.accept(PostScriptTokenTypes.NUMBER)) {
+        this.operators.push(this.prev.value);
+       } else if (this.accept(PostScriptTokenTypes.OPERATOR)) {
+        this.operators.push(this.prev.value);
+       } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
+        this.parseCondition();
+       } else {
+        return;
+       }
+      }
+     },
+     parseCondition: function PostScriptParser_parseCondition() {
+      var conditionLocation = this.operators.length;
+      this.operators.push(null, null);
+      this.parseBlock();
+      this.expect(PostScriptTokenTypes.RBRACE);
+      if (this.accept(PostScriptTokenTypes.IF)) {
+       this.operators[conditionLocation] = this.operators.length;
+       this.operators[conditionLocation + 1] = 'jz';
+      } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
+       var jumpLocation = this.operators.length;
+       this.operators.push(null, null);
+       var endOfTrue = this.operators.length;
+       this.parseBlock();
+       this.expect(PostScriptTokenTypes.RBRACE);
+       this.expect(PostScriptTokenTypes.IFELSE);
+       this.operators[jumpLocation] = this.operators.length;
+       this.operators[jumpLocation + 1] = 'j';
+       this.operators[conditionLocation] = endOfTrue;
+       this.operators[conditionLocation + 1] = 'jz';
+      } else {
+       error('PS Function: error parsing conditional.');
+      }
+     }
+    };
+    return PostScriptParser;
+   }();
+   var PostScriptTokenTypes = {
+    LBRACE: 0,
+    RBRACE: 1,
+    NUMBER: 2,
+    OPERATOR: 3,
+    IF: 4,
+    IFELSE: 5
+   };
+   var PostScriptToken = function PostScriptTokenClosure() {
+    function PostScriptToken(type, value) {
+     this.type = type;
+     this.value = value;
+    }
+    var opCache = Object.create(null);
+    PostScriptToken.getOperator = function PostScriptToken_getOperator(op) {
+     var opValue = opCache[op];
+     if (opValue) {
+      return opValue;
+     }
+     return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op);
+    };
+    PostScriptToken.LBRACE = new PostScriptToken(PostScriptTokenTypes.LBRACE, '{');
+    PostScriptToken.RBRACE = new PostScriptToken(PostScriptTokenTypes.RBRACE, '}');
+    PostScriptToken.IF = new PostScriptToken(PostScriptTokenTypes.IF, 'IF');
+    PostScriptToken.IFELSE = new PostScriptToken(PostScriptTokenTypes.IFELSE, 'IFELSE');
+    return PostScriptToken;
+   }();
+   var PostScriptLexer = function PostScriptLexerClosure() {
+    function PostScriptLexer(stream) {
+     this.stream = stream;
+     this.nextChar();
+     this.strBuf = [];
+    }
+    PostScriptLexer.prototype = {
+     nextChar: function PostScriptLexer_nextChar() {
+      return this.currentChar = this.stream.getByte();
+     },
+     getToken: function PostScriptLexer_getToken() {
+      var comment = false;
+      var ch = this.currentChar;
+      while (true) {
+       if (ch < 0) {
+        return EOF;
+       }
+       if (comment) {
+        if (ch === 0x0A || ch === 0x0D) {
+         comment = false;
+        }
+       } else if (ch === 0x25) {
+        comment = true;
+       } else if (!isSpace(ch)) {
+        break;
+       }
+       ch = this.nextChar();
+      }
+      switch (ch | 0) {
+      case 0x30:
+      case 0x31:
+      case 0x32:
+      case 0x33:
+      case 0x34:
+      case 0x35:
+      case 0x36:
+      case 0x37:
+      case 0x38:
+      case 0x39:
+      case 0x2B:
+      case 0x2D:
+      case 0x2E:
+       return new PostScriptToken(PostScriptTokenTypes.NUMBER, this.getNumber());
+      case 0x7B:
+       this.nextChar();
+       return PostScriptToken.LBRACE;
+      case 0x7D:
+       this.nextChar();
+       return PostScriptToken.RBRACE;
+      }
+      var strBuf = this.strBuf;
+      strBuf.length = 0;
+      strBuf[0] = String.fromCharCode(ch);
+      while ((ch = this.nextChar()) >= 0 && (ch >= 0x41 && ch <= 0x5A || ch >= 0x61 && ch <= 0x7A)) {
+       strBuf.push(String.fromCharCode(ch));
+      }
+      var str = strBuf.join('');
+      switch (str.toLowerCase()) {
+      case 'if':
+       return PostScriptToken.IF;
+      case 'ifelse':
+       return PostScriptToken.IFELSE;
+      default:
+       return PostScriptToken.getOperator(str);
+      }
+     },
+     getNumber: function PostScriptLexer_getNumber() {
+      var ch = this.currentChar;
+      var strBuf = this.strBuf;
+      strBuf.length = 0;
+      strBuf[0] = String.fromCharCode(ch);
+      while ((ch = this.nextChar()) >= 0) {
+       if (ch >= 0x30 && ch <= 0x39 || ch === 0x2D || ch === 0x2E) {
+        strBuf.push(String.fromCharCode(ch));
+       } else {
+        break;
+       }
+      }
+      var value = parseFloat(strBuf.join(''));
+      if (isNaN(value)) {
+       error('Invalid floating point number: ' + value);
+      }
+      return value;
+     }
+    };
+    return PostScriptLexer;
+   }();
+   exports.PostScriptLexer = PostScriptLexer;
+   exports.PostScriptParser = PostScriptParser;
+  }));
+  (function (root, factory) {
    factory(root.pdfjsCoreStream = {}, root.pdfjsSharedUtil, root.pdfjsCorePrimitives, root.pdfjsCoreJbig2, root.pdfjsCoreJpg, root.pdfjsCoreJpx);
   }(this, function (exports, sharedUtil, corePrimitives, coreJbig2, coreJpg, coreJpx) {
    var Util = sharedUtil.Util;
    var error = sharedUtil.error;
    var info = sharedUtil.info;
    var isInt = sharedUtil.isInt;
    var isArray = sharedUtil.isArray;
    var createObjectURL = sharedUtil.createObjectURL;
@@ -33590,50 +33790,1043 @@
       }
       return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap);
      }
     };
    }();
    exports.FontRendererFactory = FontRendererFactory;
   }));
   (function (root, factory) {
+   factory(root.pdfjsCoreFunction = {}, root.pdfjsSharedUtil, root.pdfjsCorePrimitives, root.pdfjsCorePsParser);
+  }(this, function (exports, sharedUtil, corePrimitives, corePsParser) {
+   var error = sharedUtil.error;
+   var info = sharedUtil.info;
+   var isArray = sharedUtil.isArray;
+   var isBool = sharedUtil.isBool;
+   var isDict = corePrimitives.isDict;
+   var isStream = corePrimitives.isStream;
+   var PostScriptLexer = corePsParser.PostScriptLexer;
+   var PostScriptParser = corePsParser.PostScriptParser;
+   var PDFFunction = function PDFFunctionClosure() {
+    var CONSTRUCT_SAMPLED = 0;
+    var CONSTRUCT_INTERPOLATED = 2;
+    var CONSTRUCT_STICHED = 3;
+    var CONSTRUCT_POSTSCRIPT = 4;
+    return {
+     getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps, str) {
+      var i, ii;
+      var length = 1;
+      for (i = 0, ii = size.length; i < ii; i++) {
+       length *= size[i];
+      }
+      length *= outputSize;
+      var array = new Array(length);
+      var codeSize = 0;
+      var codeBuf = 0;
+      var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1);
+      var strBytes = str.getBytes((length * bps + 7) / 8);
+      var strIdx = 0;
+      for (i = 0; i < length; i++) {
+       while (codeSize < bps) {
+        codeBuf <<= 8;
+        codeBuf |= strBytes[strIdx++];
+        codeSize += 8;
+       }
+       codeSize -= bps;
+       array[i] = (codeBuf >> codeSize) * sampleMul;
+       codeBuf &= (1 << codeSize) - 1;
+      }
+      return array;
+     },
+     getIR: function PDFFunction_getIR(xref, fn) {
+      var dict = fn.dict;
+      if (!dict) {
+       dict = fn;
+      }
+      var types = [
+       this.constructSampled,
+       null,
+       this.constructInterpolated,
+       this.constructStiched,
+       this.constructPostScript
+      ];
+      var typeNum = dict.get('FunctionType');
+      var typeFn = types[typeNum];
+      if (!typeFn) {
+       error('Unknown type of function');
+      }
+      return typeFn.call(this, fn, dict, xref);
+     },
+     fromIR: function PDFFunction_fromIR(IR) {
+      var type = IR[0];
+      switch (type) {
+      case CONSTRUCT_SAMPLED:
+       return this.constructSampledFromIR(IR);
+      case CONSTRUCT_INTERPOLATED:
+       return this.constructInterpolatedFromIR(IR);
+      case CONSTRUCT_STICHED:
+       return this.constructStichedFromIR(IR);
+      default:
+       return this.constructPostScriptFromIR(IR);
+      }
+     },
+     parse: function PDFFunction_parse(xref, fn) {
+      var IR = this.getIR(xref, fn);
+      return this.fromIR(IR);
+     },
+     parseArray: function PDFFunction_parseArray(xref, fnObj) {
+      if (!isArray(fnObj)) {
+       return this.parse(xref, fnObj);
+      }
+      var fnArray = [];
+      for (var j = 0, jj = fnObj.length; j < jj; j++) {
+       var obj = xref.fetchIfRef(fnObj[j]);
+       fnArray.push(PDFFunction.parse(xref, obj));
+      }
+      return function (src, srcOffset, dest, destOffset) {
+       for (var i = 0, ii = fnArray.length; i < ii; i++) {
+        fnArray[i](src, srcOffset, dest, destOffset + i);
+       }
+      };
+     },
+     constructSampled: function PDFFunction_constructSampled(str, dict) {
+      function toMultiArray(arr) {
+       var inputLength = arr.length;
+       var out = [];
+       var index = 0;
+       for (var i = 0; i < inputLength; i += 2) {
+        out[index] = [
+         arr[i],
+         arr[i + 1]
+        ];
+        ++index;
+       }
+       return out;
+      }
+      var domain = dict.getArray('Domain');
+      var range = dict.getArray('Range');
+      if (!domain || !range) {
+       error('No domain or range');
+      }
+      var inputSize = domain.length / 2;
+      var outputSize = range.length / 2;
+      domain = toMultiArray(domain);
+      range = toMultiArray(range);
+      var size = dict.get('Size');
+      var bps = dict.get('BitsPerSample');
+      var order = dict.get('Order') || 1;
+      if (order !== 1) {
+       info('No support for cubic spline interpolation: ' + order);
+      }
+      var encode = dict.getArray('Encode');
+      if (!encode) {
+       encode = [];
+       for (var i = 0; i < inputSize; ++i) {
+        encode.push(0);
+        encode.push(size[i] - 1);
+       }
+      }
+      encode = toMultiArray(encode);
+      var decode = dict.getArray('Decode');
+      if (!decode) {
+       decode = range;
+      } else {
+       decode = toMultiArray(decode);
+      }
+      var samples = this.getSampleArray(size, outputSize, bps, str);
+      return [
+       CONSTRUCT_SAMPLED,
+       inputSize,
+       domain,
+       encode,
+       decode,
+       samples,
+       size,
+       outputSize,
+       Math.pow(2, bps) - 1,
+       range
+      ];
+     },
+     constructSampledFromIR: function PDFFunction_constructSampledFromIR(IR) {
+      function interpolate(x, xmin, xmax, ymin, ymax) {
+       return ymin + (x - xmin) * ((ymax - ymin) / (xmax - xmin));
+      }
+      return function constructSampledFromIRResult(src, srcOffset, dest, destOffset) {
+       var m = IR[1];
+       var domain = IR[2];
+       var encode = IR[3];
+       var decode = IR[4];
+       var samples = IR[5];
+       var size = IR[6];
+       var n = IR[7];
+       var range = IR[9];
+       var cubeVertices = 1 << m;
+       var cubeN = new Float64Array(cubeVertices);
+       var cubeVertex = new Uint32Array(cubeVertices);
+       var i, j;
+       for (j = 0; j < cubeVertices; j++) {
+        cubeN[j] = 1;
+       }
+       var k = n, pos = 1;
+       for (i = 0; i < m; ++i) {
+        var domain_2i = domain[i][0];
+        var domain_2i_1 = domain[i][1];
+        var xi = Math.min(Math.max(src[srcOffset + i], domain_2i), domain_2i_1);
+        var e = interpolate(xi, domain_2i, domain_2i_1, encode[i][0], encode[i][1]);
+        var size_i = size[i];
+        e = Math.min(Math.max(e, 0), size_i - 1);
+        var e0 = e < size_i - 1 ? Math.floor(e) : e - 1;
+        var n0 = e0 + 1 - e;
+        var n1 = e - e0;
+        var offset0 = e0 * k;
+        var offset1 = offset0 + k;
+        for (j = 0; j < cubeVertices; j++) {
+         if (j & pos) {
+          cubeN[j] *= n1;
+          cubeVertex[j] += offset1;
+         } else {
+          cubeN[j] *= n0;
+          cubeVertex[j] += offset0;
+         }
+        }
+        k *= size_i;
+        pos <<= 1;
+       }
+       for (j = 0; j < n; ++j) {
+        var rj = 0;
+        for (i = 0; i < cubeVertices; i++) {
+         rj += samples[cubeVertex[i] + j] * cubeN[i];
+        }
+        rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);
+        dest[destOffset + j] = Math.min(Math.max(rj, range[j][0]), range[j][1]);
+       }
+      };
+     },
+     constructInterpolated: function PDFFunction_constructInterpolated(str, dict) {
+      var c0 = dict.getArray('C0') || [0];
+      var c1 = dict.getArray('C1') || [1];
+      var n = dict.get('N');
+      if (!isArray(c0) || !isArray(c1)) {
+       error('Illegal dictionary for interpolated function');
+      }
+      var length = c0.length;
+      var diff = [];
+      for (var i = 0; i < length; ++i) {
+       diff.push(c1[i] - c0[i]);
+      }
+      return [
+       CONSTRUCT_INTERPOLATED,
+       c0,
+       diff,
+       n
+      ];
+     },
+     constructInterpolatedFromIR: function PDFFunction_constructInterpolatedFromIR(IR) {
+      var c0 = IR[1];
+      var diff = IR[2];
+      var n = IR[3];
+      var length = diff.length;
+      return function constructInterpolatedFromIRResult(src, srcOffset, dest, destOffset) {
+       var x = n === 1 ? src[srcOffset] : Math.pow(src[srcOffset], n);
+       for (var j = 0; j < length; ++j) {
+        dest[destOffset + j] = c0[j] + x * diff[j];
+       }
+      };
+     },
+     constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
+      var domain = dict.getArray('Domain');
+      if (!domain) {
+       error('No domain');
+      }
+      var inputSize = domain.length / 2;
+      if (inputSize !== 1) {
+       error('Bad domain for stiched function');
+      }
+      var fnRefs = dict.get('Functions');
+      var fns = [];
+      for (var i = 0, ii = fnRefs.length; i < ii; ++i) {
+       fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i])));
+      }
+      var bounds = dict.getArray('Bounds');
+      var encode = dict.getArray('Encode');
+      return [
+       CONSTRUCT_STICHED,
+       domain,
+       bounds,
+       encode,
+       fns
+      ];
+     },
+     constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {
+      var domain = IR[1];
+      var bounds = IR[2];
+      var encode = IR[3];
+      var fnsIR = IR[4];
+      var fns = [];
+      var tmpBuf = new Float32Array(1);
+      for (var i = 0, ii = fnsIR.length; i < ii; i++) {
+       fns.push(PDFFunction.fromIR(fnsIR[i]));
+      }
+      return function constructStichedFromIRResult(src, srcOffset, dest, destOffset) {
+       var clip = function constructStichedFromIRClip(v, min, max) {
+        if (v > max) {
+         v = max;
+        } else if (v < min) {
+         v = min;
+        }
+        return v;
+       };
+       var v = clip(src[srcOffset], domain[0], domain[1]);
+       for (var i = 0, ii = bounds.length; i < ii; ++i) {
+        if (v < bounds[i]) {
+         break;
+        }
+       }
+       var dmin = domain[0];
+       if (i > 0) {
+        dmin = bounds[i - 1];
+       }
+       var dmax = domain[1];
+       if (i < bounds.length) {
+        dmax = bounds[i];
+       }
+       var rmin = encode[2 * i];
+       var rmax = encode[2 * i + 1];
+       tmpBuf[0] = dmin === dmax ? rmin : rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
+       fns[i](tmpBuf, 0, dest, destOffset);
+      };
+     },
+     constructPostScript: function PDFFunction_constructPostScript(fn, dict, xref) {
+      var domain = dict.getArray('Domain');
+      var range = dict.getArray('Range');
+      if (!domain) {
+       error('No domain.');
+      }
+      if (!range) {
+       error('No range.');
+      }
+      var lexer = new PostScriptLexer(fn);
+      var parser = new PostScriptParser(lexer);
+      var code = parser.parse();
+      return [
+       CONSTRUCT_POSTSCRIPT,
+       domain,
+       range,
+       code
+      ];
+     },
+     constructPostScriptFromIR: function PDFFunction_constructPostScriptFromIR(IR) {
+      var domain = IR[1];
+      var range = IR[2];
+      var code = IR[3];
+      var compiled = new PostScriptCompiler().compile(code, domain, range);
+      if (compiled) {
+       return new Function('src', 'srcOffset', 'dest', 'destOffset', compiled);
+      }
+      info('Unable to compile PS function');
+      var numOutputs = range.length >> 1;
+      var numInputs = domain.length >> 1;
+      var evaluator = new PostScriptEvaluator(code);
+      var cache = Object.create(null);
+      var MAX_CACHE_SIZE = 2048 * 4;
+      var cache_available = MAX_CACHE_SIZE;
+      var tmpBuf = new Float32Array(numInputs);
+      return function constructPostScriptFromIRResult(src, srcOffset, dest, destOffset) {
+       var i, value;
+       var key = '';
+       var input = tmpBuf;
+       for (i = 0; i < numInputs; i++) {
+        value = src[srcOffset + i];
+        input[i] = value;
+        key += value + '_';
+       }
+       var cachedValue = cache[key];
+       if (cachedValue !== undefined) {
+        dest.set(cachedValue, destOffset);
+        return;
+       }
+       var output = new Float32Array(numOutputs);
+       var stack = evaluator.execute(input);
+       var stackIndex = stack.length - numOutputs;
+       for (i = 0; i < numOutputs; i++) {
+        value = stack[stackIndex + i];
+        var bound = range[i * 2];
+        if (value < bound) {
+         value = bound;
+        } else {
+         bound = range[i * 2 + 1];
+         if (value > bound) {
+          value = bound;
+         }
+        }
+        output[i] = value;
+       }
+       if (cache_available > 0) {
+        cache_available--;
+        cache[key] = output;
+       }
+       dest.set(output, destOffset);
+      };
+     }
+    };
+   }();
+   function isPDFFunction(v) {
+    var fnDict;
+    if (typeof v !== 'object') {
+     return false;
+    } else if (isDict(v)) {
+     fnDict = v;
+    } else if (isStream(v)) {
+     fnDict = v.dict;
+    } else {
+     return false;
+    }
+    return fnDict.has('FunctionType');
+   }
+   var PostScriptStack = function PostScriptStackClosure() {
+    var MAX_STACK_SIZE = 100;
+    function PostScriptStack(initialStack) {
+     this.stack = !initialStack ? [] : Array.prototype.slice.call(initialStack, 0);
+    }
+    PostScriptStack.prototype = {
+     push: function PostScriptStack_push(value) {
+      if (this.stack.length >= MAX_STACK_SIZE) {
+       error('PostScript function stack overflow.');
+      }
+      this.stack.push(value);
+     },
+     pop: function PostScriptStack_pop() {
+      if (this.stack.length <= 0) {
+       error('PostScript function stack underflow.');
+      }
+      return this.stack.pop();
+     },
+     copy: function PostScriptStack_copy(n) {
+      if (this.stack.length + n >= MAX_STACK_SIZE) {
+       error('PostScript function stack overflow.');
+      }
+      var stack = this.stack;
+      for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) {
+       stack.push(stack[i]);
+      }
+     },
+     index: function PostScriptStack_index(n) {
+      this.push(this.stack[this.stack.length - n - 1]);
+     },
+     roll: function PostScriptStack_roll(n, p) {
+      var stack = this.stack;
+      var l = stack.length - n;
+      var r = stack.length - 1, c = l + (p - Math.floor(p / n) * n), i, j, t;
+      for (i = l, j = r; i < j; i++, j--) {
+       t = stack[i];
+       stack[i] = stack[j];
+       stack[j] = t;
+      }
+      for (i = l, j = c - 1; i < j; i++, j--) {
+       t = stack[i];
+       stack[i] = stack[j];
+       stack[j] = t;
+      }
+      for (i = c, j = r; i < j; i++, j--) {
+       t = stack[i];
+       stack[i] = stack[j];
+       stack[j] = t;
+      }
+     }
+    };
+    return PostScriptStack;
+   }();
+   var PostScriptEvaluator = function PostScriptEvaluatorClosure() {
+    function PostScriptEvaluator(operators) {
+     this.operators = operators;
+    }
+    PostScriptEvaluator.prototype = {
+     execute: function PostScriptEvaluator_execute(initialStack) {
+      var stack = new PostScriptStack(initialStack);
+      var counter = 0;
+      var operators = this.operators;
+      var length = operators.length;
+      var operator, a, b;
+      while (counter < length) {
+       operator = operators[counter++];
+       if (typeof operator === 'number') {
+        stack.push(operator);
+        continue;
+       }
+       switch (operator) {
+       case 'jz':
+        b = stack.pop();
+        a = stack.pop();
+        if (!a) {
+         counter = b;
+        }
+        break;
+       case 'j':
+        a = stack.pop();
+        counter = a;
+        break;
+       case 'abs':
+        a = stack.pop();
+        stack.push(Math.abs(a));
+        break;
+       case 'add':
+        b = stack.pop();
+        a = stack.pop();
+        stack.push(a + b);
+        break;
+       case 'and':
+        b = stack.pop();
+        a = stack.pop();
+        if (isBool(a) && isBool(b)) {
+         stack.push(a && b);
+        } else {
+         stack.push(a & b);
+        }
+        break;
+       case 'atan':
+        a = stack.pop();
+        stack.push(Math.atan(a));
+        break;
+       case 'bitshift':
+        b = stack.pop();
+        a = stack.pop();
+        if (a > 0) {
+         stack.push(a << b);
+        } else {
+         stack.push(a >> b);
+        }
+        break;
+       case 'ceiling':
+        a = stack.pop();
+        stack.push(Math.ceil(a));
+        break;
+       case 'copy':
+        a = stack.pop();
+        stack.copy(a);
+        break;
+       case 'cos':
+        a = stack.pop();
+        stack.push(Math.cos(a));
+        break;
+       case 'cvi':
+        a = stack.pop() | 0;
+        stack.push(a);
+        break;
+       case 'cvr':
+        break;
+       case 'div':
+        b = stack.pop();
+        a = stack.pop();
+        stack.push(a / b);
+        break;
+       case 'dup':
+        stack.copy(1);
+        break;
+       case 'eq':
+        b = stack.pop();
+        a = stack.pop();
+        stack.push(a === b);
+        break;
+       case 'exch':
+        stack.roll(2, 1);
+        break;
+       case 'exp':
+        b = stack.pop();
+        a = stack.pop();
+        stack.push(Math.pow(a, b));
+        break;
+       case 'false':
+        stack.push(false);
+        break;
+       case 'floor':
+        a = stack.pop();
+        stack.push(Math.floor(a));
+        break;
+       case 'ge':
+        b = stack.pop();
+        a = stack.pop();
+        stack.push(a >= b);
+        break;
+       case 'gt':
+        b = stack.pop();
+        a = stack.pop();
+        stack.push(a > b);
+        break;
+       case 'idiv':
+        b = stack.pop();
+        a = stack.pop();
+        stack.push(a / b | 0);
+        break;
+       case 'index':
+        a = stack.pop();
+        stack.index(a);
+        break;
+       case 'le':
+        b = stack.pop();
+        a = stack.pop();
+        stack.push(a <= b);
+        break;
+       case 'ln':
+        a = stack.pop();
+        stack.push(Math.log(a));
+        break;
+       case 'log':
+        a = stack.pop();
+        stack.push(Math.log(a) / Math.LN10);
+        break;
+       case 'lt':
+        b = stack.pop();
+        a = stack.pop();
+        stack.push(a < b);
+        break;
+       case 'mod':
+        b = stack.pop();
+        a = stack.pop();
+        stack.push(a % b);
+        break;
+       case 'mul':
+        b = stack.pop();
+        a = stack.pop();
+        stack.push(a * b);
+        break;
+       case 'ne':
+        b = stack.pop();
+        a = stack.pop();
+        stack.push(a !== b);
+        break;
+       case 'neg':
+        a = stack.pop();
+        stack.push(-a);
+        break;
+       case 'not':
+        a = stack.pop();
+        if (isBool(a)) {
+         stack.push(!a);
+        } else {
+         stack.push(~a);
+        }
+        break;
+       case 'or':
+        b = stack.pop();
+        a = stack.pop();
+        if (isBool(a) && isBool(b)) {
+         stack.push(a || b);
+        } else {
+         stack.push(a | b);
+        }
+        break;
+       case 'pop':
+        stack.pop();
+        break;
+       case 'roll':
+        b = stack.pop();
+        a = stack.pop();
+        stack.roll(a, b);
+        break;
+       case 'round':
+        a = stack.pop();
+        stack.push(Math.round(a));
+        break;
+       case 'sin':
+        a = stack.pop();
+        stack.push(Math.sin(a));
+        break;
+       case 'sqrt':
+        a = stack.pop();
+        stack.push(Math.sqrt(a));
+        break;
+       case 'sub':
+        b = stack.pop();
+        a = stack.pop();
+        stack.push(a - b);
+        break;
+       case 'true':
+        stack.push(true);
+        break;
+       case 'truncate':
+        a = stack.pop();
+        a = a < 0 ? Math.ceil(a) : Math.floor(a);
+        stack.push(a);
+        break;
+       case 'xor':
+        b = stack.pop();
+        a = stack.pop();
+        if (isBool(a) && isBool(b)) {
+         stack.push(a !== b);
+        } else {
+         stack.push(a ^ b);
+        }
+        break;
+       default:
+        error('Unknown operator ' + operator);
+        break;
+       }
+      }
+      return stack.stack;
+     }
+    };
+    return PostScriptEvaluator;
+   }();
+   var PostScriptCompiler = function PostScriptCompilerClosure() {
+    function AstNode(type) {
+     this.type = type;
+    }
+    AstNode.prototype.visit = function (visitor) {
+     throw new Error('abstract method');
+    };
+    function AstArgument(index, min, max) {
+     AstNode.call(this, 'args');
+     this.index = index;
+     this.min = min;
+     this.max = max;
+    }
+    AstArgument.prototype = Object.create(AstNode.prototype);
+    AstArgument.prototype.visit = function (visitor) {
+     visitor.visitArgument(this);
+    };
+    function AstLiteral(number) {
+     AstNode.call(this, 'literal');
+     this.number = number;
+     this.min = number;
+     this.max = number;
+    }
+    AstLiteral.prototype = Object.create(AstNode.prototype);
+    AstLiteral.prototype.visit = function (visitor) {
+     visitor.visitLiteral(this);
+    };
+    function AstBinaryOperation(op, arg1, arg2, min, max) {
+     AstNode.call(this, 'binary');
+     this.op = op;
+     this.arg1 = arg1;
+     this.arg2 = arg2;
+     this.min = min;
+     this.max = max;
+    }
+    AstBinaryOperation.prototype = Object.create(AstNode.prototype);
+    AstBinaryOperation.prototype.visit = function (visitor) {
+     visitor.visitBinaryOperation(this);
+    };
+    function AstMin(arg, max) {
+     AstNode.call(this, 'max');
+     this.arg = arg;
+     this.min = arg.min;
+     this.max = max;
+    }
+    AstMin.prototype = Object.create(AstNode.prototype);
+    AstMin.prototype.visit = function (visitor) {
+     visitor.visitMin(this);
+    };
+    function AstVariable(index, min, max) {
+     AstNode.call(this, 'var');
+     this.index = index;
+     this.min = min;
+     this.max = max;
+    }
+    AstVariable.prototype = Object.create(AstNode.prototype);
+    AstVariable.prototype.visit = function (visitor) {
+     visitor.visitVariable(this);
+    };
+    function AstVariableDefinition(variable, arg) {
+     AstNode.call(this, 'definition');
+     this.variable = variable;
+     this.arg = arg;
+    }
+    AstVariableDefinition.prototype = Object.create(AstNode.prototype);
+    AstVariableDefinition.prototype.visit = function (visitor) {
+     visitor.visitVariableDefinition(this);
+    };
+    function ExpressionBuilderVisitor() {
+     this.parts = [];
+    }
+    ExpressionBuilderVisitor.prototype = {
+     visitArgument: function (arg) {
+      this.parts.push('Math.max(', arg.min, ', Math.min(', arg.max, ', src[srcOffset + ', arg.index, ']))');
+     },
+     visitVariable: function (variable) {
+      this.parts.push('v', variable.index);
+     },
+     visitLiteral: function (literal) {
+      this.parts.push(literal.number);
+     },
+     visitBinaryOperation: function (operation) {
+      this.parts.push('(');
+      operation.arg1.visit(this);
+      this.parts.push(' ', operation.op, ' ');
+      operation.arg2.visit(this);
+      this.parts.push(')');
+     },
+     visitVariableDefinition: function (definition) {
+      this.parts.push('var ');
+      definition.variable.visit(this);
+      this.parts.push(' = ');
+      definition.arg.visit(this);
+      this.parts.push(';');
+     },
+     visitMin: function (max) {
+      this.parts.push('Math.min(');
+      max.arg.visit(this);
+      this.parts.push(', ', max.max, ')');
+     },
+     toString: function () {
+      return this.parts.join('');
+     }
+    };
+    function buildAddOperation(num1, num2) {
+     if (num2.type === 'literal' && num2.number === 0) {
+      return num1;
+     }
+     if (num1.type === 'literal' && num1.number === 0) {
+      return num2;
+     }
+     if (num2.type === 'literal' && num1.type === 'literal') {
+      return new AstLiteral(num1.number + num2.number);
+     }
+     return new AstBinaryOperation('+', num1, num2, num1.min + num2.min, num1.max + num2.max);
+    }
+    function buildMulOperation(num1, num2) {
+     if (num2.type === 'literal') {
+      if (num2.number === 0) {
+       return new AstLiteral(0);
+      } else if (num2.number === 1) {
+       return num1;
+      } else if (num1.type === 'literal') {
+       return new AstLiteral(num1.number * num2.number);
+      }
+     }
+     if (num1.type === 'literal') {
+      if (num1.number === 0) {
+       return new AstLiteral(0);
+      } else if (num1.number === 1) {
+       return num2;
+      }
+     }
+     var min = Math.min(num1.min * num2.min, num1.min * num2.max, num1.max * num2.min, num1.max * num2.max);
+     var max = Math.max(num1.min * num2.min, num1.min * num2.max, num1.max * num2.min, num1.max * num2.max);
+     return new AstBinaryOperation('*', num1, num2, min, max);
+    }
+    function buildSubOperation(num1, num2) {
+     if (num2.type === 'literal') {
+      if (num2.number === 0) {
+       return num1;
+      } else if (num1.type === 'literal') {
+       return new AstLiteral(num1.number - num2.number);
+      }
+     }
+     if (num2.type === 'binary' && num2.op === '-' && num1.type === 'literal' && num1.number === 1 && num2.arg1.type === 'literal' && num2.arg1.number === 1) {
+      return num2.arg2;
+     }
+     return new AstBinaryOperation('-', num1, num2, num1.min - num2.max, num1.max - num2.min);
+    }
+    function buildMinOperation(num1, max) {
+     if (num1.min >= max) {
+      return new AstLiteral(max);
+     } else if (num1.max <= max) {
+      return num1;
+     }
+     return new AstMin(num1, max);
+    }
+    function PostScriptCompiler() {
+    }
+    PostScriptCompiler.prototype = {
+     compile: function PostScriptCompiler_compile(code, domain, range) {
+      var stack = [];
+      var i, ii;
+      var instructions = [];
+      var inputSize = domain.length >> 1, outputSize = range.length >> 1;
+      var lastRegister = 0;
+      var n, j;
+      var num1, num2, ast1, ast2, tmpVar, item;
+      for (i = 0; i < inputSize; i++) {
+       stack.push(new AstArgument(i, domain[i * 2], domain[i * 2 + 1]));
+      }
+      for (i = 0, ii = code.length; i < ii; i++) {
+       item = code[i];
+       if (typeof item === 'number') {
+        stack.push(new AstLiteral(item));
+        continue;
+       }
+       switch (item) {
+       case 'add':
+        if (stack.length < 2) {
+         return null;
+        }
+        num2 = stack.pop();
+        num1 = stack.pop();
+        stack.push(buildAddOperation(num1, num2));
+        break;
+       case 'cvr':
+        if (stack.length < 1) {
+         return null;
+        }
+        break;
+       case 'mul':
+        if (stack.length < 2) {
+         return null;
+        }
+        num2 = stack.pop();
+        num1 = stack.pop();
+        stack.push(buildMulOperation(num1, num2));
+        break;
+       case 'sub':
+        if (stack.length < 2) {
+         return null;
+        }
+        num2 = stack.pop();
+        num1 = stack.pop();
+        stack.push(buildSubOperation(num1, num2));
+        break;
+       case 'exch':
+        if (stack.length < 2) {
+         return null;
+        }
+        ast1 = stack.pop();
+        ast2 = stack.pop();
+        stack.push(ast1, ast2);
+        break;
+       case 'pop':
+        if (stack.length < 1) {
+         return null;
+        }
+        stack.pop();
+        break;
+       case 'index':
+        if (stack.length < 1) {
+         return null;
+        }
+        num1 = stack.pop();
+        if (num1.type !== 'literal') {
+         return null;
+        }
+        n = num1.number;
+        if (n < 0 || (n | 0) !== n || stack.length < n) {
+         return null;
+        }
+        ast1 = stack[stack.length - n - 1];
+        if (ast1.type === 'literal' || ast1.type === 'var') {
+         stack.push(ast1);
+         break;
+        }
+        tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);
+        stack[stack.length - n - 1] = tmpVar;
+        stack.push(tmpVar);
+        instructions.push(new AstVariableDefinition(tmpVar, ast1));
+        break;
+       case 'dup':
+        if (stack.length < 1) {
+         return null;
+        }
+        if (typeof code[i + 1] === 'number' && code[i + 2] === 'gt' && code[i + 3] === i + 7 && code[i + 4] === 'jz' && code[i + 5] === 'pop' && code[i + 6] === code[i + 1]) {
+         num1 = stack.pop();
+         stack.push(buildMinOperation(num1, code[i + 1]));
+         i += 6;
+         break;
+        }
+        ast1 = stack[stack.length - 1];
+        if (ast1.type === 'literal' || ast1.type === 'var') {
+         stack.push(ast1);
+         break;
+        }
+        tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);
+        stack[stack.length - 1] = tmpVar;
+        stack.push(tmpVar);
+        instructions.push(new AstVariableDefinition(tmpVar, ast1));
+        break;
+       case 'roll':
+        if (stack.length < 2) {
+         return null;
+        }
+        num2 = stack.pop();
+        num1 = stack.pop();
+        if (num2.type !== 'literal' || num1.type !== 'literal') {
+         return null;
+        }
+        j = num2.number;
+        n = num1.number;
+        if (n <= 0 || (n | 0) !== n || (j | 0) !== j || stack.length < n) {
+         return null;
+        }
+        j = (j % n + n) % n;
+        if (j === 0) {
+         break;
+        }
+        Array.prototype.push.apply(stack, stack.splice(stack.length - n, n - j));
+        break;
+       default:
+        return null;
+       }
+      }
+      if (stack.length !== outputSize) {
+       return null;
+      }
+      var result = [];
+      instructions.forEach(function (instruction) {
+       var statementBuilder = new ExpressionBuilderVisitor();
+       instruction.visit(statementBuilder);
+       result.push(statementBuilder.toString());
+      });
+      stack.forEach(function (expr, i) {
+       var statementBuilder = new ExpressionBuilderVisitor();
+       expr.visit(statementBuilder);
+       var min = range[i * 2], max = range[i * 2 + 1];
+       var out = [statementBuilder.toString()];
+       if (min > expr.min) {
+        out.unshift('Math.max(', min, ', ');
+        out.push(')');
+       }
+       if (max < expr.max) {
+        out.unshift('Math.min(', max, ', ');
+        out.push(')');
+       }
+       out.unshift('dest[destOffset + ', i, '] = ');
+       out.push(';');
+       result.push(out.join(''));
+      });
+      return result.join('\n');
+     }
+    };
+    return PostScriptCompiler;
+   }();
+   exports.isPDFFunction = isPDFFunction;
+   exports.PDFFunction = PDFFunction;
+   exports.PostScriptEvaluator = PostScriptEvaluator;
+   exports.PostScriptCompiler = PostScriptCompiler;
+  }));
+  (function (root, factory) {
    factory(root.pdfjsCoreParser = {}, root.pdfjsSharedUtil, root.pdfjsCorePrimitives, root.pdfjsCoreStream);
   }(this, function (exports, sharedUtil, corePrimitives, coreStream) {
    var MissingDataException = sharedUtil.MissingDataException;
    var StreamType = sharedUtil.StreamType;
    var assert = sharedUtil.assert;
    var error = sharedUtil.error;
    var info = sharedUtil.info;
    var isArray = sharedUtil.isArray;
    var isInt = sharedUtil.isInt;
    var isNum = sharedUtil.isNum;
    var isString = sharedUtil.isString;
    var warn = sharedUtil.warn;
+   var EOF = corePrimitives.EOF;
    var Cmd = corePrimitives.Cmd;
    var Dict = corePrimitives.Dict;
    var Name = corePrimitives.Name;
    var Ref = corePrimitives.Ref;
+   var isEOF = corePrimitives.isEOF;
    var isCmd = corePrimitives.isCmd;
    var isDict = corePrimitives.isDict;
    var isName = corePrimitives.isName;
    var Ascii85Stream = coreStream.Ascii85Stream;
    var AsciiHexStream = coreStream.AsciiHexStream;
    var CCITTFaxStream = coreStream.CCITTFaxStream;
    var FlateStream = coreStream.FlateStream;
    var Jbig2Stream = coreStream.Jbig2Stream;
    var JpegStream = coreStream.JpegStream;
    var JpxStream = coreStream.JpxStream;
    var LZWStream = coreStream.LZWStream;
    var NullStream = coreStream.NullStream;
    var PredictorStream = coreStream.PredictorStream;
    var RunLengthStream = coreStream.RunLengthStream;
-   var EOF = {};
-   function isEOF(v) {
-    return v === EOF;
-   }
    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);
@@ -34794,21 +35987,19 @@
       objectNumberFirst: getInt('O'),
       endFirst: getInt('E'),
       numPages: getInt('N'),
       mainXRefEntriesOffset: getInt('T'),
       pageFirst: linDict.has('P') ? getInt('P', true) : 0
      };
     }
    };
-   exports.EOF = EOF;
    exports.Lexer = Lexer;
    exports.Linearization = Linearization;
    exports.Parser = Parser;
-   exports.isEOF = isEOF;
   }));
   (function (root, factory) {
    factory(root.pdfjsCoreType1Parser = {}, root.pdfjsSharedUtil, root.pdfjsCoreStream, root.pdfjsCoreEncodings);
   }(this, function (exports, sharedUtil, coreStream, coreEncodings) {
    var warn = sharedUtil.warn;
    var isSpace = sharedUtil.isSpace;
    var Stream = coreStream.Stream;
    var getEncoding = coreEncodings.getEncoding;
@@ -35350,22 +36541,22 @@
   }(this, function (exports, sharedUtil, corePrimitives, coreStream, coreParser) {
    var Util = sharedUtil.Util;
    var assert = sharedUtil.assert;
    var warn = sharedUtil.warn;
    var error = sharedUtil.error;
    var isInt = sharedUtil.isInt;
    var isString = sharedUtil.isString;
    var MissingDataException = sharedUtil.MissingDataException;
+   var isEOF = corePrimitives.isEOF;
    var isName = corePrimitives.isName;
    var isCmd = corePrimitives.isCmd;
    var isStream = corePrimitives.isStream;
    var StringStream = coreStream.StringStream;
    var Lexer = coreParser.Lexer;
-   var isEOF = coreParser.isEOF;
    var BUILT_IN_CMAPS = [
     'Adobe-GB1-UCS2',
     'Adobe-CNS1-UCS2',
     'Adobe-Japan1-UCS2',
     'Adobe-Korea1-UCS2',
     '78-EUC-H',
     '78-EUC-V',
     '78-H',
@@ -36239,16 +37430,1032 @@
      }
     };
    }();
    exports.CMap = CMap;
    exports.CMapFactory = CMapFactory;
    exports.IdentityCMap = IdentityCMap;
   }));
   (function (root, factory) {
+   factory(root.pdfjsCoreColorSpace = {}, root.pdfjsSharedUtil, root.pdfjsCorePrimitives, root.pdfjsCoreFunction);
+  }(this, function (exports, sharedUtil, corePrimitives, coreFunction) {
+   var error = sharedUtil.error;
+   var info = sharedUtil.info;
+   var isArray = sharedUtil.isArray;
+   var isString = sharedUtil.isString;
+   var shadow = sharedUtil.shadow;
+   var warn = sharedUtil.warn;
+   var isDict = corePrimitives.isDict;
+   var isName = corePrimitives.isName;
+   var isStream = corePrimitives.isStream;
+   var PDFFunction = coreFunction.PDFFunction;
+   var ColorSpace = function ColorSpaceClosure() {
+    function resizeRgbImage(src, bpc, w1, h1, w2, h2, alpha01, dest) {
+     var COMPONENTS = 3;
+     alpha01 = alpha01 !== 1 ? 0 : alpha01;
+     var xRatio = w1 / w2;
+     var yRatio = h1 / h2;
+     var i, j, py, newIndex = 0, oldIndex;
+     var xScaled = new Uint16Array(w2);
+     var w1Scanline = w1 * COMPONENTS;
+     for (i = 0; i < w2; i++) {
+      xScaled[i] = Math.floor(i * xRatio) * COMPONENTS;
+     }
+     for (i = 0; i < h2; i++) {
+      py = Math.floor(i * yRatio) * w1Scanline;
+      for (j = 0; j < w2; j++) {
+       oldIndex = py + xScaled[j];
+       dest[newIndex++] = src[oldIndex++];
+       dest[newIndex++] = src[oldIndex++];
+       dest[newIndex++] = src[oldIndex++];
+       newIndex += alpha01;
+      }
+     }
+    }
+    function ColorSpace() {
+     error('should not call ColorSpace constructor');
+    }
+    ColorSpace.prototype = {
+     getRgb: function ColorSpace_getRgb(src, srcOffset) {
+      var rgb = new Uint8Array(3);
+      this.getRgbItem(src, srcOffset, rgb, 0);
+      return rgb;
+     },
+     getRgbItem: function ColorSpace_getRgbItem(src, srcOffset, dest, destOffset) {
+      error('Should not call ColorSpace.getRgbItem');
+     },
+     getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
+      error('Should not call ColorSpace.getRgbBuffer');
+     },
+     getOutputLength: function ColorSpace_getOutputLength(inputLength, alpha01) {
+      error('Should not call ColorSpace.getOutputLength');
+     },
+     isPassthrough: function ColorSpace_isPassthrough(bits) {
+      return false;
+     },
+     fillRgb: function ColorSpace_fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight, bpc, comps, alpha01) {
+      var count = originalWidth * originalHeight;
+      var rgbBuf = null;
+      var numComponentColors = 1 << bpc;
+      var needsResizing = originalHeight !== height || originalWidth !== width;
+      var i, ii;
+      if (this.isPassthrough(bpc)) {
+       rgbBuf = comps;
+      } else if (this.numComps === 1 && count > numComponentColors && this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') {
+       var allColors = bpc <= 8 ? new Uint8Array(numComponentColors) : new Uint16Array(numComponentColors);
+       var key;
+       for (i = 0; i < numComponentColors; i++) {
+        allColors[i] = i;
+       }
+       var colorMap = new Uint8Array(numComponentColors * 3);
+       this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc, 0);
+       var destPos, rgbPos;
+       if (!needsResizing) {
+        destPos = 0;
+        for (i = 0; i < count; ++i) {
+         key = comps[i] * 3;
+         dest[destPos++] = colorMap[key];
+         dest[destPos++] = colorMap[key + 1];
+         dest[destPos++] = colorMap[key + 2];
+         destPos += alpha01;
+        }
+       } else {
+        rgbBuf = new Uint8Array(count * 3);
+        rgbPos = 0;
+        for (i = 0; i < count; ++i) {
+         key = comps[i] * 3;
+         rgbBuf[rgbPos++] = colorMap[key];
+         rgbBuf[rgbPos++] = colorMap[key + 1];
+         rgbBuf[rgbPos++] = colorMap[key + 2];
+        }
+       }
+      } else {
+       if (!needsResizing) {
+        this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc, alpha01);
+       } else {
+        rgbBuf = new Uint8Array(count * 3);
+        this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc, 0);
+       }
+      }
+      if (rgbBuf) {
+       if (needsResizing) {
+        resizeRgbImage(rgbBuf, bpc, originalWidth, originalHeight, width, height, alpha01, dest);
+       } else {
+        rgbPos = 0;
+        destPos = 0;
+        for (i = 0, ii = width * actualHeight; i < ii; i++) {
+         dest[destPos++] = rgbBuf[rgbPos++];
+         dest[destPos++] = rgbBuf[rgbPos++];
+         dest[destPos++] = rgbBuf[rgbPos++];
+         destPos += alpha01;
+        }
+       }
+      }
+     },
+     usesZeroToOneRange: true
+    };
+    ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
+     var IR = ColorSpace.parseToIR(cs, xref, res);
+     if (IR instanceof AlternateCS) {
+      return IR;
+     }
+     return ColorSpace.fromIR(IR);
+    };
+    ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
+     var name = isArray(IR) ? IR[0] : IR;
+     var whitePoint, blackPoint, gamma;
+     switch (name) {
+     case 'DeviceGrayCS':
+      return this.singletons.gray;
+     case 'DeviceRgbCS':
+      return this.singletons.rgb;
+     case 'DeviceCmykCS':
+      return this.singletons.cmyk;
+     case 'CalGrayCS':
+      whitePoint = IR[1];
+      blackPoint = IR[2];
+      gamma = IR[3];
+      return new CalGrayCS(whitePoint, blackPoint, gamma);
+     case 'CalRGBCS':
+      whitePoint = IR[1];
+      blackPoint = IR[2];
+      gamma = IR[3];
+      var matrix = IR[4];
+      return new CalRGBCS(whitePoint, blackPoint, gamma, matrix);
+     case 'PatternCS':
+      var basePatternCS = IR[1];
+      if (basePatternCS) {
+       basePatternCS = ColorSpace.fromIR(basePatternCS);
+      }
+      return new PatternCS(basePatternCS);
+     case 'IndexedCS':
+      var baseIndexedCS = IR[1];
+      var hiVal = IR[2];
+      var lookup = IR[3];
+      return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup);
+     case 'AlternateCS':
+      var numComps = IR[1];
+      var alt = IR[2];
+      var tintFnIR = IR[3];
+      return new AlternateCS(numComps, ColorSpace.fromIR(alt), PDFFunction.fromIR(tintFnIR));
+     case 'LabCS':
+      whitePoint = IR[1];
+      blackPoint = IR[2];
+      var range = IR[3];
+      return new LabCS(whitePoint, blackPoint, range);
+     default:
+      error('Unknown name ' + name);
+     }
+     return null;
+    };
+    ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) {
+     if (isName(cs)) {
+      var colorSpaces = res.get('ColorSpace');
+      if (isDict(colorSpaces)) {
+       var refcs = colorSpaces.get(cs.name);
+       if (refcs) {
+        cs = refcs;
+       }
+      }
+     }
+     cs = xref.fetchIfRef(cs);
+     if (isName(cs)) {
+      switch (cs.name) {
+      case 'DeviceGray':
+      case 'G':
+       return 'DeviceGrayCS';
+      case 'DeviceRGB':
+      case 'RGB':
+       return 'DeviceRgbCS';
+      case 'DeviceCMYK':
+      case 'CMYK':
+       return 'DeviceCmykCS';
+      case 'Pattern':
+       return [
+        'PatternCS',
+        null
+       ];
+      default:
+       error('unrecognized colorspace ' + cs.name);
+      }
+     } else if (isArray(cs)) {
+      var mode = xref.fetchIfRef(cs[0]).name;
+      var numComps, params, alt, whitePoint, blackPoint, gamma;
+      switch (mode) {
+      case 'DeviceGray':
+      case 'G':
+       return 'DeviceGrayCS';
+      case 'DeviceRGB':
+      case 'RGB':
+       return 'DeviceRgbCS';
+      case 'DeviceCMYK':
+      case 'CMYK':
+       return 'DeviceCmykCS';
+      case 'CalGray':
+       params = xref.fetchIfRef(cs[1]);
+       whitePoint = params.getArray('WhitePoint');
+       blackPoint = params.getArray('BlackPoint');
+       gamma = params.get('Gamma');
+       return [
+        'CalGrayCS',
+        whitePoint,
+        blackPoint,
+        gamma
+       ];
+      case 'CalRGB':
+       params = xref.fetchIfRef(cs[1]);
+       whitePoint = params.getArray('WhitePoint');
+       blackPoint = params.getArray('BlackPoint');
+       gamma = params.getArray('Gamma');
+       var matrix = params.getArray('Matrix');
+       return [
+        'CalRGBCS',
+        whitePoint,
+        blackPoint,
+        gamma,
+        matrix
+       ];
+      case 'ICCBased':
+       var stream = xref.fetchIfRef(cs[1]);
+       var dict = stream.dict;
+       numComps = dict.get('N');
+       alt = dict.get('Alternate');
+       if (alt) {
+        var altIR = ColorSpace.parseToIR(alt, xref, res);
+        var altCS = ColorSpace.fromIR(altIR);
+        if (altCS.numComps === numComps) {
+         return altIR;
+        }
+        warn('ICCBased color space: Ignoring incorrect /Alternate entry.');
+       }
+       if (numComps === 1) {
+        return 'DeviceGrayCS';
+       } else if (numComps === 3) {
+        return 'DeviceRgbCS';
+       } else if (numComps === 4) {
+        return 'DeviceCmykCS';
+       }
+       break;
+      case 'Pattern':
+       var basePatternCS = cs[1] || null;
+       if (basePatternCS) {
+        basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);
+       }
+       return [
+        'PatternCS',
+        basePatternCS
+       ];
+      case 'Indexed':
+      case 'I':
+       var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res);
+       var hiVal = xref.fetchIfRef(cs[2]) + 1;
+       var lookup = xref.fetchIfRef(cs[3]);
+       if (isStream(lookup)) {
+        lookup = lookup.getBytes();
+       }
+       return [
+        'IndexedCS',
+        baseIndexedCS,
+        hiVal,
+        lookup
+       ];
+      case 'Separation':
+      case 'DeviceN':
+       var name = xref.fetchIfRef(cs[1]);
+       numComps = isArray(name) ? name.length : 1;
+       alt = ColorSpace.parseToIR(cs[2], xref, res);
+       var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
+       return [
+        'AlternateCS',
+        numComps,
+        alt,
+        tintFnIR
+       ];
+      case 'Lab':
+       params = xref.fetchIfRef(cs[1]);
+       whitePoint = params.getArray('WhitePoint');
+       blackPoint = params.getArray('BlackPoint');
+       var range = params.getArray('Range');
+       return [
+        'LabCS',
+        whitePoint,
+        blackPoint,
+        range
+       ];
+      default:
+       error('unimplemented color space object "' + mode + '"');
+      }
+     } else {
+      error('unrecognized color space object: "' + cs + '"');
+     }
+     return null;
+    };
+    ColorSpace.isDefaultDecode = function ColorSpace_isDefaultDecode(decode, n) {
+     if (!isArray(decode)) {
+      return true;
+     }
+     if (n * 2 !== decode.length) {
+      warn('The decode map is not the correct length');
+      return true;
+     }
+     for (var i = 0, ii = decode.length; i < ii; i += 2) {
+      if (decode[i] !== 0 || decode[i + 1] !== 1) {
+       return false;
+      }
+     }
+     return true;
+    };
+    ColorSpace.singletons = {
+     get gray() {
+      return shadow(this, 'gray', new DeviceGrayCS());
+     },
+     get rgb() {
+      return shadow(this, 'rgb', new DeviceRgbCS());
+     },
+     get cmyk() {
+      return shadow(this, 'cmyk', new DeviceCmykCS());
+     }
+    };
+    return ColorSpace;
+   }();
+   var AlternateCS = function AlternateCSClosure() {
+    function AlternateCS(numComps, base, tintFn) {
+     this.name = 'Alternate';
+     this.numComps = numComps;
+     this.defaultColor = new Float32Array(numComps);
+     for (var i = 0; i < numComps; ++i) {
+      this.defaultColor[i] = 1;
+     }
+     this.base = base;
+     this.tintFn = tintFn;
+     this.tmpBuf = new Float32Array(base.numComps);
+    }
+    AlternateCS.prototype = {
+     getRgb: ColorSpace.prototype.getRgb,
+     getRgbItem: function AlternateCS_getRgbItem(src, srcOffset, dest, destOffset) {
+      var tmpBuf = this.tmpBuf;
+      this.tintFn(src, srcOffset, tmpBuf, 0);
+      this.base.getRgbItem(tmpBuf, 0, dest, destOffset);
+     },
+     getRgbBuffer: function AlternateCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
+      var tintFn = this.tintFn;
+      var base = this.base;
+      var scale = 1 / ((1 << bits) - 1);
+      var baseNumComps = base.numComps;
+      var usesZeroToOneRange = base.usesZeroToOneRange;
+      var isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) && alpha01 === 0;
+      var pos = isPassthrough ? destOffset : 0;
+      var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count);
+      var numComps = this.numComps;
+      var scaled = new Float32Array(numComps);
+      var tinted = new Float32Array(baseNumComps);
+      var i, j;
+      for (i = 0; i < count; i++) {
+       for (j = 0; j < numComps; j++) {
+        scaled[j] = src[srcOffset++] * scale;
+       }
+       tintFn(scaled, 0, tinted, 0);
+       if (usesZeroToOneRange) {
+        for (j = 0; j < baseNumComps; j++) {
+         baseBuf[pos++] = tinted[j] * 255;
+        }
+       } else {
+        base.getRgbItem(tinted, 0, baseBuf, pos);
+        pos += baseNumComps;
+       }
+      }
+      if (!isPassthrough) {
+       base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01);
+      }
+     },
+     getOutputLength: function AlternateCS_getOutputLength(inputLength, alpha01) {
+      return this.base.getOutputLength(inputLength * this.base.numComps / this.numComps, alpha01);
+     },
+     isPassthrough: ColorSpace.prototype.isPassthrough,
+     fillRgb: ColorSpace.prototype.fillRgb,
+     isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {
+      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+     },
+     usesZeroToOneRange: true
+    };
+    return AlternateCS;
+   }();
+   var PatternCS = function PatternCSClosure() {
+    function PatternCS(baseCS) {
+     this.name = 'Pattern';
+     this.base = baseCS;
+    }
+    PatternCS.prototype = {};
+    return PatternCS;
+   }();
+   var IndexedCS = function IndexedCSClosure() {
+    function IndexedCS(base, highVal, lookup) {
+     this.name = 'Indexed';
+     this.numComps = 1;
+     this.defaultColor = new Uint8Array(this.numComps);
+     this.base = base;
+     this.highVal = highVal;
+     var baseNumComps = base.numComps;
+     var length = baseNumComps * highVal;
+     if (isStream(lookup)) {
+      this.lookup = new Uint8Array(length);
+      var bytes = lookup.getBytes(length);
+      this.lookup.set(bytes);
+     } else if (isString(lookup)) {
+      this.lookup = new Uint8Array(length);
+      for (var i = 0; i < length; ++i) {
+       this.lookup[i] = lookup.charCodeAt(i);
+      }
+     } else if (lookup instanceof Uint8Array || lookup instanceof Array) {
+      this.lookup = lookup;
+     } else {
+      error('Unrecognized lookup table: ' + lookup);
+     }
+    }
+    IndexedCS.prototype = {
+     getRgb: ColorSpace.prototype.getRgb,
+     getRgbItem: function IndexedCS_getRgbItem(src, srcOffset, dest, destOffset) {
+      var numComps = this.base.numComps;
+      var start = src[srcOffset] * numComps;
+      this.base.getRgbItem(this.lookup, start, dest, destOffset);
+     },
+     getRgbBuffer: function IndexedCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
+      var base = this.base;
+      var numComps = base.numComps;
+      var outputDelta = base.getOutputLength(numComps, alpha01);
+      var lookup = this.lookup;
+      for (var i = 0; i < count; ++i) {
+       var lookupPos = src[srcOffset++] * numComps;
+       base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01);
+       destOffset += outputDelta;
+      }
+     },
+     getOutputLength: function IndexedCS_getOutputLength(inputLength, alpha01) {
+      return this.base.getOutputLength(inputLength * this.base.numComps, alpha01);
+     },
+     isPassthrough: ColorSpace.prototype.isPassthrough,
+     fillRgb: ColorSpace.prototype.fillRgb,
+     isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {
+      return true;
+     },
+     usesZeroToOneRange: true
+    };
+    return IndexedCS;
+   }();
+   var DeviceGrayCS = function DeviceGrayCSClosure() {
+    function DeviceGrayCS() {
+     this.name = 'DeviceGray';
+     this.numComps = 1;
+     this.defaultColor = new Float32Array(this.numComps);
+    }
+    DeviceGrayCS.prototype = {
+     getRgb: ColorSpace.prototype.getRgb,
+     getRgbItem: function DeviceGrayCS_getRgbItem(src, srcOffset, dest, destOffset) {
+      var c = src[srcOffset] * 255 | 0;
+      c = c < 0 ? 0 : c > 255 ? 255 : c;
+      dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c;
+     },
+     getRgbBuffer: function DeviceGrayCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
+      var scale = 255 / ((1 << bits) - 1);
+      var j = srcOffset, q = destOffset;
+      for (var i = 0; i < count; ++i) {
+       var c = scale * src[j++] | 0;
+       dest[q++] = c;
+       dest[q++] = c;
+       dest[q++] = c;
+       q += alpha01;
+      }
+     },
+     getOutputLength: function DeviceGrayCS_getOutputLength(inputLength, alpha01) {
+      return inputLength * (3 + alpha01);
+     },
+     isPassthrough: ColorSpace.prototype.isPassthrough,
+     fillRgb: ColorSpace.prototype.fillRgb,
+     isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
+      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+     },
+     usesZeroToOneRange: true
+    };
+    return DeviceGrayCS;
+   }();
+   var DeviceRgbCS = function DeviceRgbCSClosure() {
+    function DeviceRgbCS() {
+     this.name = 'DeviceRGB';
+     this.numComps = 3;
+     this.defaultColor = new Float32Array(this.numComps);
+    }
+    DeviceRgbCS.prototype = {
+     getRgb: ColorSpace.prototype.getRgb,
+     getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset, dest, destOffset) {
+      var r = src[srcOffset] * 255 | 0;
+      var g = src[srcOffset + 1] * 255 | 0;
+      var b = src[srcOffset + 2] * 255 | 0;
+      dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r;
+      dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g;
+      dest[destOffset + 2] = b < 0 ? 0 : b > 255 ? 255 : b;
+     },
+     getRgbBuffer: function DeviceRgbCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
+      if (bits === 8 && alpha01 === 0) {
+       dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset);
+       return;
+      }
+      var scale = 255 / ((1 << bits) - 1);
+      var j = srcOffset, q = destOffset;
+      for (var i = 0; i < count; ++i) {
+       dest[q++] = scale * src[j++] | 0;
+       dest[q++] = scale * src[j++] | 0;
+       dest[q++] = scale * src[j++] | 0;
+       q += alpha01;
+      }
+     },
+     getOutputLength: function DeviceRgbCS_getOutputLength(inputLength, alpha01) {
+      return inputLength * (3 + alpha01) / 3 | 0;
+     },
+     isPassthrough: function DeviceRgbCS_isPassthrough(bits) {
+      return bits === 8;
+     },
+     fillRgb: ColorSpace.prototype.fillRgb,
+     isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
+      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+     },
+     usesZeroToOneRange: true
+    };
+    return DeviceRgbCS;
+   }();
+   var DeviceCmykCS = function DeviceCmykCSClosure() {
+    function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
+     var c = src[srcOffset + 0] * srcScale;
+     var m = src[srcOffset + 1] * srcScale;
+     var y = src[srcOffset + 2] * srcScale;
+     var k = src[srcOffset + 3] * srcScale;
+     var r = 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) + 255 | 0;
+     var g = 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) + 255 | 0;
+     var b = 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) + 255 | 0;
+     dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r;
+     dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g;
+     dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b;
+    }
+    function DeviceCmykCS() {
+     this.name = 'DeviceCMYK';
+     this.numComps = 4;
+     this.defaultColor = new Float32Array(this.numComps);
+     this.defaultColor[3] = 1;
+    }
+    DeviceCmykCS.prototype = {
+     getRgb: ColorSpace.prototype.getRgb,
+     getRgbItem: function DeviceCmykCS_getRgbItem(src, srcOffset, dest, destOffset) {
+      convertToRgb(src, srcOffset, 1, dest, destOffset);
+     },
+     getRgbBuffer: function DeviceCmykCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
+      var scale = 1 / ((1 << bits) - 1);
+      for (var i = 0; i < count; i++) {
+       convertToRgb(src, srcOffset, scale, dest, destOffset);
+       srcOffset += 4;
+       destOffset += 3 + alpha01;
+      }
+     },
+     getOutputLength: function DeviceCmykCS_getOutputLength(inputLength, alpha01) {
+      return inputLength / 4 * (3 + alpha01) | 0;
+     },
+     isPassthrough: ColorSpace.prototype.isPassthrough,
+     fillRgb: ColorSpace.prototype.fillRgb,
+     isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {
+      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+     },
+     usesZeroToOneRange: true
+    };
+    return DeviceCmykCS;
+   }();
+   var CalGrayCS = function CalGrayCSClosure() {
+    function CalGrayCS(whitePoint, blackPoint, gamma) {
+     this.name = 'CalGray';
+     this.numComps = 1;
+     this.defaultColor = new Float32Array(this.numComps);
+     if (!whitePoint) {
+      error('WhitePoint missing - required for color space CalGray');
+     }
+     blackPoint = blackPoint || [
+      0,
+      0,
+      0
+     ];
+     gamma = gamma || 1;
+     this.XW = whitePoint[0];
+     this.YW = whitePoint[1];
+     this.ZW = whitePoint[2];
+     this.XB = blackPoint[0];
+     this.YB = blackPoint[1];
+     this.ZB = blackPoint[2];
+     this.G = gamma;
+     if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
+      error('Invalid WhitePoint components for ' + this.name + ', no fallback available');
+     }
+     if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
+      info('Invalid BlackPoint for ' + this.name + ', falling back to default');
+      this.XB = this.YB = this.ZB = 0;
+     }
+     if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) {
+      warn(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB + ', ZB: ' + this.ZB + ', only default values are supported.');
+     }
+     if (this.G < 1) {
+      info('Invalid Gamma: ' + this.G + ' for ' + this.name + ', falling back to default');
+      this.G = 1;
+     }
+    }
+    function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
+     var A = src[srcOffset] * scale;
+     var AG = Math.pow(A, cs.G);
+     var L = cs.YW * AG;
+     var val = Math.max(295.8 * Math.pow(L, 0.333333333333333333) - 40.8, 0) | 0;
+     dest[destOffset] = val;
+     dest[destOffset + 1] = val;
+     dest[destOffset + 2] = val;
+    }
+    CalGrayCS.prototype = {
+     getRgb: ColorSpace.prototype.getRgb,
+     getRgbItem: function CalGrayCS_getRgbItem(src, srcOffset, dest, destOffset) {
+      convertToRgb(this, src, srcOffset, dest, destOffset, 1);
+     },
+     getRgbBuffer: function CalGrayCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
+      var scale = 1 / ((1 << bits) - 1);
+      for (var i = 0; i < count; ++i) {
+       convertToRgb(this, src, srcOffset, dest, destOffset, scale);
+       srcOffset += 1;
+       destOffset += 3 + alpha01;
+      }
+     },
+     getOutputLength: function CalGrayCS_getOutputLength(inputLength, alpha01) {
+      return inputLength * (3 + alpha01);
+     },
+     isPassthrough: ColorSpace.prototype.isPassthrough,
+     fillRgb: ColorSpace.prototype.fillRgb,
+     isDefaultDecode: function CalGrayCS_isDefaultDecode(decodeMap) {
+      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+     },
+     usesZeroToOneRange: true
+    };
+    return CalGrayCS;
+   }();
+   var CalRGBCS = function CalRGBCSClosure() {
+    var BRADFORD_SCALE_MATRIX = new Float32Array([
+     0.8951,
+     0.2664,
+     -0.1614,
+     -0.7502,
+     1.7135,
+     0.0367,
+     0.0389,
+     -0.0685,
+     1.0296
+    ]);
+    var BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([
+     0.9869929,
+     -0.1470543,
+     0.1599627,
+     0.4323053,
+     0.5183603,
+     0.0492912,
+     -0.0085287,
+     0.0400428,
+     0.9684867
+    ]);
+    var SRGB_D65_XYZ_TO_RGB_MATRIX = new Float32Array([
+     3.2404542,
+     -1.5371385,
+     -0.4985314,
+     -0.9692660,
+     1.8760108,
+     0.0415560,
+     0.0556434,
+     -0.2040259,
+     1.0572252
+    ]);
+    var FLAT_WHITEPOINT_MATRIX = new Float32Array([
+     1,
+     1,
+     1
+    ]);
+    var tempNormalizeMatrix = new Float32Array(3);
+    var tempConvertMatrix1 = new Float32Array(3);
+    var tempConvertMatrix2 = new Float32Array(3);
+    var DECODE_L_CONSTANT = Math.pow((8 + 16) / 116, 3) / 8.0;
+    function CalRGBCS(whitePoint, blackPoint, gamma, matrix) {
+     this.name = 'CalRGB';
+     this.numComps = 3;
+     this.defaultColor = new Float32Array(this.numComps);
+     if (!whitePoint) {
+      error('WhitePoint missing - required for color space CalRGB');
+     }
+     blackPoint = blackPoint || new Float32Array(3);
+     gamma = gamma || new Float32Array([
+      1,
+      1,
+      1
+     ]);
+     matrix = matrix || new Float32Array([
+      1,
+      0,
+      0,
+      0,
+      1,
+      0,
+      0,
+      0,
+      1
+     ]);
+     var XW = whitePoint[0];
+     var YW = whitePoint[1];
+     var ZW = whitePoint[2];
+     this.whitePoint = whitePoint;
+     var XB = blackPoint[0];
+     var YB = blackPoint[1];
+     var ZB = blackPoint[2];
+     this.blackPoint = blackPoint;
+     this.GR = gamma[0];
+     this.GG = gamma[1];
+     this.GB = gamma[2];
+     this.MXA = matrix[0];
+     this.MYA = matrix[1];
+     this.MZA = matrix[2];
+     this.MXB = matrix[3];
+     this.MYB = matrix[4];
+     this.MZB = matrix[5];
+     this.MXC = matrix[6];
+     this.MYC = matrix[7];
+     this.MZC = matrix[8];
+     if (XW < 0 || ZW < 0 || YW !== 1) {
+      error('Invalid WhitePoint components for ' + this.name + ', no fallback available');
+     }
+     if (XB < 0 || YB < 0 || ZB < 0) {
+      info('Invalid BlackPoint for ' + this.name + ' [' + XB + ', ' + YB + ', ' + ZB + '], falling back to default');
+      this.blackPoint = new Float32Array(3);
+     }
+     if (this.GR < 0 || this.GG < 0 || this.GB < 0) {
+      info('Invalid Gamma [' + this.GR + ', ' + this.GG + ', ' + this.GB + '] for ' + this.name + ', falling back to default');
+      this.GR = this.GG = this.GB = 1;
+     }
+     if (this.MXA < 0 || this.MYA < 0 || this.MZA < 0 || this.MXB < 0 || this.MYB < 0 || this.MZB < 0 || this.MXC < 0 || this.MYC < 0 || this.MZC < 0) {
+      info('Invalid Matrix for ' + this.name + ' [' + this.MXA + ', ' + this.MYA + ', ' + this.MZA + this.MXB + ', ' + this.MYB + ', ' + this.MZB + this.MXC + ', ' + this.MYC + ', ' + this.MZC + '], falling back to default');
+      this.MXA = this.MYB = this.MZC = 1;
+      this.MXB = this.MYA = this.MZA = this.MXC = this.MYC = this.MZB = 0;
+     }
+    }
+    function matrixProduct(a, b, result) {
+     result[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+     result[1] = a[3] * b[0] + a[4] * b[1] + a[5] * b[2];
+     result[2] = a[6] * b[0] + a[7] * b[1] + a[8] * b[2];
+    }
+    function convertToFlat(sourceWhitePoint, LMS, result) {
+     result[0] = LMS[0] * 1 / sourceWhitePoint[0];
+     result[1] = LMS[1] * 1 / sourceWhitePoint[1];
+     result[2] = LMS[2] * 1 / sourceWhitePoint[2];
+    }
+    function convertToD65(sourceWhitePoint, LMS, result) {
+     var D65X = 0.95047;
+     var D65Y = 1;
+     var D65Z = 1.08883;
+     result[0] = LMS[0] * D65X / sourceWhitePoint[0];
+     result[1] = LMS[1] * D65Y / sourceWhitePoint[1];
+     result[2] = LMS[2] * D65Z / sourceWhitePoint[2];
+    }
+    function sRGBTransferFunction(color) {
+     if (color <= 0.0031308) {
+      return adjustToRange(0, 1, 12.92 * color);
+     }
+     return adjustToRange(0, 1, (1 + 0.055) * Math.pow(color, 1 / 2.4) - 0.055);
+    }
+    function adjustToRange(min, max, value) {
+     return Math.max(min, Math.min(max, value));
+    }
+    function decodeL(L) {
+     if (L < 0) {
+      return -decodeL(-L);
+     }
+     if (L > 8.0) {
+      return Math.pow((L + 16) / 116, 3);
+     }
+     return L * DECODE_L_CONSTANT;
+    }
+    function compensateBlackPoint(sourceBlackPoint, XYZ_Flat, result) {
+     if (sourceBlackPoint[0] === 0 && sourceBlackPoint[1] === 0 && sourceBlackPoint[2] === 0) {
+      result[0] = XYZ_Flat[0];
+      result[1] = XYZ_Flat[1];
+      result[2] = XYZ_Flat[2];
+      return;
+     }
+     var zeroDecodeL = decodeL(0);
+     var X_DST = zeroDecodeL;
+     var X_SRC = decodeL(sourceBlackPoint[0]);
+     var Y_DST = zeroDecodeL;
+     var Y_SRC = decodeL(sourceBlackPoint[1]);
+     var Z_DST = zeroDecodeL;
+     var Z_SRC = decodeL(sourceBlackPoint[2]);
+     var X_Scale = (1 - X_DST) / (1 - X_SRC);
+     var X_Offset = 1 - X_Scale;
+     var Y_Scale = (1 - Y_DST) / (1 - Y_SRC);
+     var Y_Offset = 1 - Y_Scale;
+     var Z_Scale = (1 - Z_DST) / (1 - Z_SRC);
+     var Z_Offset = 1 - Z_Scale;
+     result[0] = XYZ_Flat[0] * X_Scale + X_Offset;
+     result[1] = XYZ_Flat[1] * Y_Scale + Y_Offset;
+     result[2] = XYZ_Flat[2] * Z_Scale + Z_Offset;
+    }
+    function normalizeWhitePointToFlat(sourceWhitePoint, XYZ_In, result) {
+     if (sourceWhitePoint[0] === 1 && sourceWhitePoint[2] === 1) {
+      result[0] = XYZ_In[0];
+      result[1] = XYZ_In[1];
+      result[2] = XYZ_In[2];
+      return;
+     }
+     var LMS = result;
+     matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
+     var LMS_Flat = tempNormalizeMatrix;
+     convertToFlat(sourceWhitePoint, LMS, LMS_Flat);
+     matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_Flat, result);
+    }
+    function normalizeWhitePointToD65(sourceWhitePoint, XYZ_In, result) {
+     var LMS = result;
+     matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
+     var LMS_D65 = tempNormalizeMatrix;
+     convertToD65(sourceWhitePoint, LMS, LMS_D65);
+     matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_D65, result);
+    }
+    function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
+     var A = adjustToRange(0, 1, src[srcOffset] * scale);
+     var B = adjustToRange(0, 1, src[srcOffset + 1] * scale);
+     var C = adjustToRange(0, 1, src[srcOffset + 2] * scale);
+     var AGR = Math.pow(A, cs.GR);
+     var BGG = Math.pow(B, cs.GG);
+     var CGB = Math.pow(C, cs.GB);
+     var X = cs.MXA * AGR + cs.MXB * BGG + cs.MXC * CGB;
+     var Y = cs.MYA * AGR + cs.MYB * BGG + cs.MYC * CGB;
+     var Z = cs.MZA * AGR + cs.MZB * BGG + cs.MZC * CGB;
+     var XYZ = tempConvertMatrix1;
+     XYZ[0] = X;
+     XYZ[1] = Y;
+     XYZ[2] = Z;
+     var XYZ_Flat = tempConvertMatrix2;
+     normalizeWhitePointToFlat(cs.whitePoint, XYZ, XYZ_Flat);
+     var XYZ_Black = tempConvertMatrix1;
+     compensateBlackPoint(cs.blackPoint, XYZ_Flat, XYZ_Black);
+     var XYZ_D65 = tempConvertMatrix2;
+     normalizeWhitePointToD65(FLAT_WHITEPOINT_MATRIX, XYZ_Black, XYZ_D65);
+     var SRGB = tempConvertMatrix1;
+     matrixProduct(SRGB_D65_XYZ_TO_RGB_MATRIX, XYZ_D65, SRGB);
+     var sR = sRGBTransferFunction(SRGB[0]);
+     var sG = sRGBTransferFunction(SRGB[1]);
+     var sB = sRGBTransferFunction(SRGB[2]);
+     dest[destOffset] = Math.round(sR * 255);
+     dest[destOffset + 1] = Math.round(sG * 255);
+     dest[destOffset + 2] = Math.round(sB * 255);
+    }
+    CalRGBCS.prototype = {
+     getRgb: function CalRGBCS_getRgb(src, srcOffset) {
+      var rgb = new Uint8Array(3);
+      this.getRgbItem(src, srcOffset, rgb, 0);
+      return rgb;
+     },
+     getRgbItem: function CalRGBCS_getRgbItem(src, srcOffset, dest, destOffset) {
+      convertToRgb(this, src, srcOffset, dest, destOffset, 1);
+     },
+     getRgbBuffer: function CalRGBCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
+      var scale = 1 / ((1 << bits) - 1);
+      for (var i = 0; i < count; ++i) {
+       convertToRgb(this, src, srcOffset, dest, destOffset, scale);
+       srcOffset += 3;
+       destOffset += 3 + alpha01;
+      }
+     },
+     getOutputLength: function CalRGBCS_getOutputLength(inputLength, alpha01) {
+      return inputLength * (3 + alpha01) / 3 | 0;
+     },
+     isPassthrough: ColorSpace.prototype.isPassthrough,
+     fillRgb: ColorSpace.prototype.fillRgb,
+     isDefaultDecode: function CalRGBCS_isDefaultDecode(decodeMap) {
+      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+     },
+     usesZeroToOneRange: true
+    };
+    return CalRGBCS;
+   }();
+   var LabCS = function LabCSClosure() {
+    function LabCS(whitePoint, blackPoint, range) {
+     this.name = 'Lab';
+     this.numComps = 3;
+     this.defaultColor = new Float32Array(this.numComps);
+     if (!whitePoint) {
+      error('WhitePoint missing - required for color space Lab');
+     }
+     blackPoint = blackPoint || [
+      0,
+      0,
+      0
+     ];
+     range = range || [
+      -100,
+      100,
+      -100,
+      100
+     ];
+     this.XW = whitePoint[0];
+     this.YW = whitePoint[1];
+     this.ZW = whitePoint[2];
+     this.amin = range[0];
+     this.amax = range[1];
+     this.bmin = range[2];
+     this.bmax = range[3];
+     this.XB = blackPoint[0];
+     this.YB = blackPoint[1];
+     this.ZB = blackPoint[2];
+     if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
+      error('Invalid WhitePoint components, no fallback available');
+     }
+     if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
+      info('Invalid BlackPoint, falling back to default');
+      this.XB = this.YB = this.ZB = 0;
+     }
+     if (this.amin > this.amax || this.bmin > this.bmax) {
+      info('Invalid Range, falling back to defaults');
+      this.amin = -100;
+      this.amax = 100;
+      this.bmin = -100;
+      this.bmax = 100;
+     }
+    }
+    function fn_g(x) {
+     var result;
+     if (x >= 6 / 29) {
+      result = x * x * x;
+     } else {
+      result = 108 / 841 * (x - 4 / 29);
+     }
+     return result;
+    }
+    function decode(value, high1, low2, high2) {
+     return low2 + value * (high2 - low2) / high1;
+    }
+    function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) {
+     var Ls = src[srcOffset];
+     var as = src[srcOffset + 1];
+     var bs = src[srcOffset + 2];
+     if (maxVal !== false) {
+      Ls = decode(Ls, maxVal, 0, 100);
+      as = decode(as, maxVal, cs.amin, cs.amax);
+      bs = decode(bs, maxVal, cs.bmin, cs.bmax);
+     }
+     as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as;
+     bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.bmin : bs;
+     var M = (Ls + 16) / 116;
+     var L = M + as / 500;
+     var N = M - bs / 200;
+     var X = cs.XW * fn_g(L);
+     var Y = cs.YW * fn_g(M);
+     var Z = cs.ZW * fn_g(N);
+     var r, g, b;
+     if (cs.ZW < 1) {
+      r = X * 3.1339 + Y * -1.6170 + Z * -0.4906;
+      g = X * -0.9785 + Y * 1.9160 + Z * 0.0333;
+      b = X * 0.0720 + Y * -0.2290 + Z * 1.4057;
+     } else {
+      r = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
+      g = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
+      b = X * 0.0557 + Y * -0.2040 + Z * 1.0570;
+     }
+     dest[destOffset] = r <= 0 ? 0 : r >= 1 ? 255 : Math.sqrt(r) * 255 | 0;
+     dest[destOffset + 1] = g <= 0 ? 0 : g >= 1 ? 255 : Math.sqrt(g) * 255 | 0;
+     dest[destOffset + 2] = b <= 0 ? 0 : b >= 1 ? 255 : Math.sqrt(b) * 255 | 0;
+    }
+    LabCS.prototype = {
+     getRgb: ColorSpace.prototype.getRgb,
+     getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) {
+      convertToRgb(this, src, srcOffset, false, dest, destOffset);
+     },
+     getRgbBuffer: function LabCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
+      var maxVal = (1 << bits) - 1;
+      for (var i = 0; i < count; i++) {
+       convertToRgb(this, src, srcOffset, maxVal, dest, destOffset);
+       srcOffset += 3;
+       destOffset += 3 + alpha01;
+      }
+     },
+     getOutputLength: function LabCS_getOutputLength(inputLength, alpha01) {
+      return inputLength * (3 + alpha01) / 3 | 0;
+     },
+     isPassthrough: ColorSpace.prototype.isPassthrough,
+     fillRgb: ColorSpace.prototype.fillRgb,
+     isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {
+      return true;
+     },
+     usesZeroToOneRange: false
+    };
+    return LabCS;
+   }();
+   exports.ColorSpace = ColorSpace;
+  }));
+  (function (root, factory) {
    factory(root.pdfjsCoreFonts = {}, root.pdfjsSharedUtil, root.pdfjsCorePrimitives, root.pdfjsCoreStream, root.pdfjsCoreGlyphList, root.pdfjsCoreFontRenderer, root.pdfjsCoreEncodings, root.pdfjsCoreStandardFonts, root.pdfjsCoreUnicode, root.pdfjsCoreType1Parser, root.pdfjsCoreCFFParser);
   }(this, function (exports, sharedUtil, corePrimitives, coreStream, coreGlyphList, coreFontRenderer, coreEncodings, coreStandardFonts, coreUnicode, coreType1Parser, coreCFFParser) {
    var FONT_IDENTITY_MATRIX = sharedUtil.FONT_IDENTITY_MATRIX;
    var FontType = sharedUtil.FontType;
    var assert = sharedUtil.assert;
    var bytesToString = sharedUtil.bytesToString;
    var error = sharedUtil.error;
    var info = sharedUtil.info;
@@ -39195,2221 +41402,16 @@
    exports.ErrorFont = ErrorFont;
    exports.Font = Font;
    exports.FontFlags = FontFlags;
    exports.IdentityToUnicodeMap = IdentityToUnicodeMap;
    exports.ToUnicodeMap = ToUnicodeMap;
    exports.getFontType = getFontType;
   }));
   (function (root, factory) {
-   factory(root.pdfjsCorePsParser = {}, root.pdfjsSharedUtil, root.pdfjsCoreParser);
-  }(this, function (exports, sharedUtil, coreParser) {
-   var error = sharedUtil.error;
-   var isSpace = sharedUtil.isSpace;
-   var EOF = coreParser.EOF;
-   var PostScriptParser = function PostScriptParserClosure() {
-    function PostScriptParser(lexer) {
-     this.lexer = lexer;
-     this.operators = [];
-     this.token = null;
-     this.prev = null;
-    }
-    PostScriptParser.prototype = {
-     nextToken: function PostScriptParser_nextToken() {
-      this.prev = this.token;
-      this.token = this.lexer.getToken();
-     },
-     accept: function PostScriptParser_accept(type) {
-      if (this.token.type === type) {
-       this.nextToken();
-       return true;
-      }
-      return false;
-     },
-     expect: function PostScriptParser_expect(type) {
-      if (this.accept(type)) {
-       return true;
-      }
-      error('Unexpected symbol: found ' + this.token.type + ' expected ' + type + '.');
-     },
-     parse: function PostScriptParser_parse() {
-      this.nextToken();
-      this.expect(PostScriptTokenTypes.LBRACE);
-      this.parseBlock();
-      this.expect(PostScriptTokenTypes.RBRACE);
-      return this.operators;
-     },
-     parseBlock: function PostScriptParser_parseBlock() {
-      while (true) {
-       if (this.accept(PostScriptTokenTypes.NUMBER)) {
-        this.operators.push(this.prev.value);
-       } else if (this.accept(PostScriptTokenTypes.OPERATOR)) {
-        this.operators.push(this.prev.value);
-       } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
-        this.parseCondition();
-       } else {
-        return;
-       }
-      }
-     },
-     parseCondition: function PostScriptParser_parseCondition() {
-      var conditionLocation = this.operators.length;
-      this.operators.push(null, null);
-      this.parseBlock();
-      this.expect(PostScriptTokenTypes.RBRACE);
-      if (this.accept(PostScriptTokenTypes.IF)) {
-       this.operators[conditionLocation] = this.operators.length;
-       this.operators[conditionLocation + 1] = 'jz';
-      } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
-       var jumpLocation = this.operators.length;
-       this.operators.push(null, null);
-       var endOfTrue = this.operators.length;
-       this.parseBlock();
-       this.expect(PostScriptTokenTypes.RBRACE);
-       this.expect(PostScriptTokenTypes.IFELSE);
-       this.operators[jumpLocation] = this.operators.length;
-       this.operators[jumpLocation + 1] = 'j';
-       this.operators[conditionLocation] = endOfTrue;
-       this.operators[conditionLocation + 1] = 'jz';
-      } else {
-       error('PS Function: error parsing conditional.');
-      }
-     }
-    };
-    return PostScriptParser;
-   }();
-   var PostScriptTokenTypes = {
-    LBRACE: 0,
-    RBRACE: 1,
-    NUMBER: 2,
-    OPERATOR: 3,
-    IF: 4,
-    IFELSE: 5
-   };
-   var PostScriptToken = function PostScriptTokenClosure() {
-    function PostScriptToken(type, value) {
-     this.type = type;
-     this.value = value;
-    }
-    var opCache = Object.create(null);
-    PostScriptToken.getOperator = function PostScriptToken_getOperator(op) {
-     var opValue = opCache[op];
-     if (opValue) {
-      return opValue;
-     }
-     return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op);
-    };
-    PostScriptToken.LBRACE = new PostScriptToken(PostScriptTokenTypes.LBRACE, '{');
-    PostScriptToken.RBRACE = new PostScriptToken(PostScriptTokenTypes.RBRACE, '}');
-    PostScriptToken.IF = new PostScriptToken(PostScriptTokenTypes.IF, 'IF');
-    PostScriptToken.IFELSE = new PostScriptToken(PostScriptTokenTypes.IFELSE, 'IFELSE');
-    return PostScriptToken;
-   }();
-   var PostScriptLexer = function PostScriptLexerClosure() {
-    function PostScriptLexer(stream) {
-     this.stream = stream;
-     this.nextChar();
-     this.strBuf = [];
-    }
-    PostScriptLexer.prototype = {
-     nextChar: function PostScriptLexer_nextChar() {
-      return this.currentChar = this.stream.getByte();
-     },
-     getToken: function PostScriptLexer_getToken() {
-      var comment = false;
-      var ch = this.currentChar;
-      while (true) {
-       if (ch < 0) {
-        return EOF;
-       }
-       if (comment) {
-        if (ch === 0x0A || ch === 0x0D) {
-         comment = false;
-        }
-       } else if (ch === 0x25) {
-        comment = true;
-       } else if (!isSpace(ch)) {
-        break;
-       }
-       ch = this.nextChar();
-      }
-      switch (ch | 0) {
-      case 0x30:
-      case 0x31:
-      case 0x32:
-      case 0x33:
-      case 0x34:
-      case 0x35:
-      case 0x36:
-      case 0x37:
-      case 0x38:
-      case 0x39:
-      case 0x2B:
-      case 0x2D:
-      case 0x2E:
-       return new PostScriptToken(PostScriptTokenTypes.NUMBER, this.getNumber());
-      case 0x7B:
-       this.nextChar();
-       return PostScriptToken.LBRACE;
-      case 0x7D:
-       this.nextChar();
-       return PostScriptToken.RBRACE;
-      }
-      var strBuf = this.strBuf;
-      strBuf.length = 0;
-      strBuf[0] = String.fromCharCode(ch);
-      while ((ch = this.nextChar()) >= 0 && (ch >= 0x41 && ch <= 0x5A || ch >= 0x61 && ch <= 0x7A)) {
-       strBuf.push(String.fromCharCode(ch));
-      }
-      var str = strBuf.join('');
-      switch (str.toLowerCase()) {
-      case 'if':
-       return PostScriptToken.IF;
-      case 'ifelse':
-       return PostScriptToken.IFELSE;
-      default:
-       return PostScriptToken.getOperator(str);
-      }
-     },
-     getNumber: function PostScriptLexer_getNumber() {
-      var ch = this.currentChar;
-      var strBuf = this.strBuf;
-      strBuf.length = 0;
-      strBuf[0] = String.fromCharCode(ch);
-      while ((ch = this.nextChar()) >= 0) {
-       if (ch >= 0x30 && ch <= 0x39 || ch === 0x2D || ch === 0x2E) {
-        strBuf.push(String.fromCharCode(ch));
-       } else {
-        break;
-       }
-      }
-      var value = parseFloat(strBuf.join(''));
-      if (isNaN(value)) {
-       error('Invalid floating point number: ' + value);
-      }
-      return value;
-     }
-    };
-    return PostScriptLexer;
-   }();
-   exports.PostScriptLexer = PostScriptLexer;
-   exports.PostScriptParser = PostScriptParser;
-  }));
-  (function (root, factory) {
-   factory(root.pdfjsCoreFunction = {}, root.pdfjsSharedUtil, root.pdfjsCorePrimitives, root.pdfjsCorePsParser);
-  }(this, function (exports, sharedUtil, corePrimitives, corePsParser) {
-   var error = sharedUtil.error;
-   var info = sharedUtil.info;
-   var isArray = sharedUtil.isArray;
-   var isBool = sharedUtil.isBool;
-   var isDict = corePrimitives.isDict;
-   var isStream = corePrimitives.isStream;
-   var PostScriptLexer = corePsParser.PostScriptLexer;
-   var PostScriptParser = corePsParser.PostScriptParser;
-   var PDFFunction = function PDFFunctionClosure() {
-    var CONSTRUCT_SAMPLED = 0;
-    var CONSTRUCT_INTERPOLATED = 2;
-    var CONSTRUCT_STICHED = 3;
-    var CONSTRUCT_POSTSCRIPT = 4;
-    return {
-     getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps, str) {
-      var i, ii;
-      var length = 1;
-      for (i = 0, ii = size.length; i < ii; i++) {
-       length *= size[i];
-      }
-      length *= outputSize;
-      var array = new Array(length);
-      var codeSize = 0;
-      var codeBuf = 0;
-      var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1);
-      var strBytes = str.getBytes((length * bps + 7) / 8);
-      var strIdx = 0;
-      for (i = 0; i < length; i++) {
-       while (codeSize < bps) {
-        codeBuf <<= 8;
-        codeBuf |= strBytes[strIdx++];
-        codeSize += 8;
-       }
-       codeSize -= bps;
-       array[i] = (codeBuf >> codeSize) * sampleMul;
-       codeBuf &= (1 << codeSize) - 1;
-      }
-      return array;
-     },
-     getIR: function PDFFunction_getIR(xref, fn) {
-      var dict = fn.dict;
-      if (!dict) {
-       dict = fn;
-      }
-      var types = [
-       this.constructSampled,
-       null,
-       this.constructInterpolated,
-       this.constructStiched,
-       this.constructPostScript
-      ];
-      var typeNum = dict.get('FunctionType');
-      var typeFn = types[typeNum];
-      if (!typeFn) {
-       error('Unknown type of function');
-      }
-      return typeFn.call(this, fn, dict, xref);
-     },
-     fromIR: function PDFFunction_fromIR(IR) {
-      var type = IR[0];
-      switch (type) {
-      case CONSTRUCT_SAMPLED:
-       return this.constructSampledFromIR(IR);
-      case CONSTRUCT_INTERPOLATED:
-       return this.constructInterpolatedFromIR(IR);
-      case CONSTRUCT_STICHED:
-       return this.constructStichedFromIR(IR);
-      default:
-       return this.constructPostScriptFromIR(IR);
-      }
-     },
-     parse: function PDFFunction_parse(xref, fn) {
-      var IR = this.getIR(xref, fn);
-      return this.fromIR(IR);
-     },
-     parseArray: function PDFFunction_parseArray(xref, fnObj) {
-      if (!isArray(fnObj)) {
-       return this.parse(xref, fnObj);
-      }
-      var fnArray = [];
-      for (var j = 0, jj = fnObj.length; j < jj; j++) {
-       var obj = xref.fetchIfRef(fnObj[j]);
-       fnArray.push(PDFFunction.parse(xref, obj));
-      }
-      return function (src, srcOffset, dest, destOffset) {
-       for (var i = 0, ii = fnArray.length; i < ii; i++) {
-        fnArray[i](src, srcOffset, dest, destOffset + i);
-       }
-      };
-     },
-     constructSampled: function PDFFunction_constructSampled(str, dict) {
-      function toMultiArray(arr) {
-       var inputLength = arr.length;
-       var out = [];
-       var index = 0;
-       for (var i = 0; i < inputLength; i += 2) {
-        out[index] = [
-         arr[i],
-         arr[i + 1]
-        ];
-        ++index;
-       }
-       return out;
-      }
-      var domain = dict.getArray('Domain');
-      var range = dict.getArray('Range');
-      if (!domain || !range) {
-       error('No domain or range');
-      }
-      var inputSize = domain.length / 2;
-      var outputSize = range.length / 2;
-      domain = toMultiArray(domain);
-      range = toMultiArray(range);
-      var size = dict.get('Size');
-      var bps = dict.get('BitsPerSample');
-      var order = dict.get('Order') || 1;
-      if (order !== 1) {
-       info('No support for cubic spline interpolation: ' + order);
-      }
-      var encode = dict.getArray('Encode');
-      if (!encode) {
-       encode = [];
-       for (var i = 0; i < inputSize; ++i) {
-        encode.push(0);
-        encode.push(size[i] - 1);
-       }
-      }
-      encode = toMultiArray(encode);
-      var decode = dict.getArray('Decode');
-      if (!decode) {
-       decode = range;
-      } else {
-       decode = toMultiArray(decode);
-      }
-      var samples = this.getSampleArray(size, outputSize, bps, str);
-      return [
-       CONSTRUCT_SAMPLED,
-       inputSize,
-       domain,
-       encode,
-       decode,
-       samples,
-       size,
-       outputSize,
-       Math.pow(2, bps) - 1,
-       range
-      ];
-     },
-     constructSampledFromIR: function PDFFunction_constructSampledFromIR(IR) {
-      function interpolate(x, xmin, xmax, ymin, ymax) {
-       return ymin + (x - xmin) * ((ymax - ymin) / (xmax - xmin));
-      }
-      return function constructSampledFromIRResult(src, srcOffset, dest, destOffset) {
-       var m = IR[1];
-       var domain = IR[2];
-       var encode = IR[3];
-       var decode = IR[4];
-       var samples = IR[5];
-       var size = IR[6];
-       var n = IR[7];
-       var range = IR[9];
-       var cubeVertices = 1 << m;
-       var cubeN = new Float64Array(cubeVertices);
-       var cubeVertex = new Uint32Array(cubeVertices);
-       var i, j;
-       for (j = 0; j < cubeVertices; j++) {
-        cubeN[j] = 1;
-       }
-       var k = n, pos = 1;
-       for (i = 0; i < m; ++i) {
-        var domain_2i = domain[i][0];
-        var domain_2i_1 = domain[i][1];
-        var xi = Math.min(Math.max(src[srcOffset + i], domain_2i), domain_2i_1);
-        var e = interpolate(xi, domain_2i, domain_2i_1, encode[i][0], encode[i][1]);
-        var size_i = size[i];
-        e = Math.min(Math.max(e, 0), size_i - 1);
-        var e0 = e < size_i - 1 ? Math.floor(e) : e - 1;
-        var n0 = e0 + 1 - e;
-        var n1 = e - e0;
-        var offset0 = e0 * k;
-        var offset1 = offset0 + k;
-        for (j = 0; j < cubeVertices; j++) {
-         if (j & pos) {
-          cubeN[j] *= n1;
-          cubeVertex[j] += offset1;
-         } else {
-          cubeN[j] *= n0;
-          cubeVertex[j] += offset0;
-         }
-        }
-        k *= size_i;
-        pos <<= 1;
-       }
-       for (j = 0; j < n; ++j) {
-        var rj = 0;
-        for (i = 0; i < cubeVertices; i++) {
-         rj += samples[cubeVertex[i] + j] * cubeN[i];
-        }
-        rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);
-        dest[destOffset + j] = Math.min(Math.max(rj, range[j][0]), range[j][1]);
-       }
-      };
-     },
-     constructInterpolated: function PDFFunction_constructInterpolated(str, dict) {
-      var c0 = dict.getArray('C0') || [0];
-      var c1 = dict.getArray('C1') || [1];
-      var n = dict.get('N');
-      if (!isArray(c0) || !isArray(c1)) {
-       error('Illegal dictionary for interpolated function');
-      }
-      var length = c0.length;
-      var diff = [];
-      for (var i = 0; i < length; ++i) {
-       diff.push(c1[i] - c0[i]);
-      }
-      return [
-       CONSTRUCT_INTERPOLATED,
-       c0,
-       diff,
-       n
-      ];
-     },
-     constructInterpolatedFromIR: function PDFFunction_constructInterpolatedFromIR(IR) {
-      var c0 = IR[1];
-      var diff = IR[2];
-      var n = IR[3];
-      var length = diff.length;
-      return function constructInterpolatedFromIRResult(src, srcOffset, dest, destOffset) {
-       var x = n === 1 ? src[srcOffset] : Math.pow(src[srcOffset], n);
-       for (var j = 0; j < length; ++j) {
-        dest[destOffset + j] = c0[j] + x * diff[j];
-       }
-      };
-     },
-     constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
-      var domain = dict.getArray('Domain');
-      if (!domain) {
-       error('No domain');
-      }
-      var inputSize = domain.length / 2;
-      if (inputSize !== 1) {
-       error('Bad domain for stiched function');
-      }
-      var fnRefs = dict.get('Functions');
-      var fns = [];
-      for (var i = 0, ii = fnRefs.length; i < ii; ++i) {
-       fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i])));
-      }
-      var bounds = dict.getArray('Bounds');
-      var encode = dict.getArray('Encode');
-      return [
-       CONSTRUCT_STICHED,
-       domain,
-       bounds,
-       encode,
-       fns
-      ];
-     },
-     constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {
-      var domain = IR[1];
-      var bounds = IR[2];
-      var encode = IR[3];
-      var fnsIR = IR[4];
-      var fns = [];
-      var tmpBuf = new Float32Array(1);
-      for (var i = 0, ii = fnsIR.length; i < ii; i++) {
-       fns.push(PDFFunction.fromIR(fnsIR[i]));
-      }
-      return function constructStichedFromIRResult(src, srcOffset, dest, destOffset) {
-       var clip = function constructStichedFromIRClip(v, min, max) {
-        if (v > max) {
-         v = max;
-        } else if (v < min) {
-         v = min;
-        }
-        return v;
-       };
-       var v = clip(src[srcOffset], domain[0], domain[1]);
-       for (var i = 0, ii = bounds.length; i < ii; ++i) {
-        if (v < bounds[i]) {
-         break;
-        }
-       }
-       var dmin = domain[0];
-       if (i > 0) {
-        dmin = bounds[i - 1];
-       }
-       var dmax = domain[1];
-       if (i < bounds.length) {
-        dmax = bounds[i];
-       }
-       var rmin = encode[2 * i];
-       var rmax = encode[2 * i + 1];
-       tmpBuf[0] = dmin === dmax ? rmin : rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
-       fns[i](tmpBuf, 0, dest, destOffset);
-      };
-     },
-     constructPostScript: function PDFFunction_constructPostScript(fn, dict, xref) {
-      var domain = dict.getArray('Domain');
-      var range = dict.getArray('Range');
-      if (!domain) {
-       error('No domain.');
-      }
-      if (!range) {
-       error('No range.');
-      }
-      var lexer = new PostScriptLexer(fn);
-      var parser = new PostScriptParser(lexer);
-      var code = parser.parse();
-      return [
-       CONSTRUCT_POSTSCRIPT,
-       domain,
-       range,
-       code
-      ];
-     },
-     constructPostScriptFromIR: function PDFFunction_constructPostScriptFromIR(IR) {
-      var domain = IR[1];
-      var range = IR[2];
-      var code = IR[3];
-      var compiled = new PostScriptCompiler().compile(code, domain, range);
-      if (compiled) {
-       return new Function('src', 'srcOffset', 'dest', 'destOffset', compiled);
-      }
-      info('Unable to compile PS function');
-      var numOutputs = range.length >> 1;
-      var numInputs = domain.length >> 1;
-      var evaluator = new PostScriptEvaluator(code);
-      var cache = Object.create(null);
-      var MAX_CACHE_SIZE = 2048 * 4;
-      var cache_available = MAX_CACHE_SIZE;
-      var tmpBuf = new Float32Array(numInputs);
-      return function constructPostScriptFromIRResult(src, srcOffset, dest, destOffset) {
-       var i, value;
-       var key = '';
-       var input = tmpBuf;
-       for (i = 0; i < numInputs; i++) {
-        value = src[srcOffset + i];
-        input[i] = value;
-        key += value + '_';
-       }
-       var cachedValue = cache[key];
-       if (cachedValue !== undefined) {
-        dest.set(cachedValue, destOffset);
-        return;
-       }
-       var output = new Float32Array(numOutputs);
-       var stack = evaluator.execute(input);
-       var stackIndex = stack.length - numOutputs;
-       for (i = 0; i < numOutputs; i++) {
-        value = stack[stackIndex + i];
-        var bound = range[i * 2];
-        if (value < bound) {
-         value = bound;
-        } else {
-         bound = range[i * 2 + 1];
-         if (value > bound) {
-          value = bound;
-         }
-        }
-        output[i] = value;
-       }
-       if (cache_available > 0) {
-        cache_available--;
-        cache[key] = output;
-       }
-       dest.set(output, destOffset);
-      };
-     }
-    };
-   }();
-   function isPDFFunction(v) {
-    var fnDict;
-    if (typeof v !== 'object') {
-     return false;
-    } else if (isDict(v)) {
-     fnDict = v;
-    } else if (isStream(v)) {
-     fnDict = v.dict;
-    } else {
-     return false;
-    }
-    return fnDict.has('FunctionType');
-   }
-   var PostScriptStack = function PostScriptStackClosure() {
-    var MAX_STACK_SIZE = 100;
-    function PostScriptStack(initialStack) {
-     this.stack = !initialStack ? [] : Array.prototype.slice.call(initialStack, 0);
-    }
-    PostScriptStack.prototype = {
-     push: function PostScriptStack_push(value) {
-      if (this.stack.length >= MAX_STACK_SIZE) {
-       error('PostScript function stack overflow.');
-      }
-      this.stack.push(value);
-     },
-     pop: function PostScriptStack_pop() {
-      if (this.stack.length <= 0) {
-       error('PostScript function stack underflow.');
-      }
-      return this.stack.pop();
-     },
-     copy: function PostScriptStack_copy(n) {
-      if (this.stack.length + n >= MAX_STACK_SIZE) {
-       error('PostScript function stack overflow.');
-      }
-      var stack = this.stack;
-      for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) {
-       stack.push(stack[i]);
-      }
-     },
-     index: function PostScriptStack_index(n) {
-      this.push(this.stack[this.stack.length - n - 1]);
-     },
-     roll: function PostScriptStack_roll(n, p) {
-      var stack = this.stack;
-      var l = stack.length - n;
-      var r = stack.length - 1, c = l + (p - Math.floor(p / n) * n), i, j, t;
-      for (i = l, j = r; i < j; i++, j--) {
-       t = stack[i];
-       stack[i] = stack[j];
-       stack[j] = t;
-      }
-      for (i = l, j = c - 1; i < j; i++, j--) {
-       t = stack[i];
-       stack[i] = stack[j];
-       stack[j] = t;
-      }
-      for (i = c, j = r; i < j; i++, j--) {
-       t = stack[i];
-       stack[i] = stack[j];
-       stack[j] = t;
-      }
-     }
-    };
-    return PostScriptStack;
-   }();
-   var PostScriptEvaluator = function PostScriptEvaluatorClosure() {
-    function PostScriptEvaluator(operators) {
-     this.operators = operators;
-    }
-    PostScriptEvaluator.prototype = {
-     execute: function PostScriptEvaluator_execute(initialStack) {
-      var stack = new PostScriptStack(initialStack);
-      var counter = 0;
-      var operators = this.operators;
-      var length = operators.length;
-      var operator, a, b;
-      while (counter < length) {
-       operator = operators[counter++];
-       if (typeof operator === 'number') {
-        stack.push(operator);
-        continue;
-       }
-       switch (operator) {
-       case 'jz':
-        b = stack.pop();
-        a = stack.pop();
-        if (!a) {
-         counter = b;
-        }
-        break;
-       case 'j':
-        a = stack.pop();
-        counter = a;
-        break;
-       case 'abs':
-        a = stack.pop();
-        stack.push(Math.abs(a));
-        break;
-       case 'add':
-        b = stack.pop();
-        a = stack.pop();
-        stack.push(a + b);
-        break;
-       case 'and':
-        b = stack.pop();
-        a = stack.pop();
-        if (isBool(a) && isBool(b)) {
-         stack.push(a && b);
-        } else {
-         stack.push(a & b);
-        }
-        break;
-       case 'atan':
-        a = stack.pop();
-        stack.push(Math.atan(a));
-        break;
-       case 'bitshift':
-        b = stack.pop();
-        a = stack.pop();
-        if (a > 0) {
-         stack.push(a << b);
-        } else {
-         stack.push(a >> b);
-        }
-        break;
-       case 'ceiling':
-        a = stack.pop();
-        stack.push(Math.ceil(a));
-        break;
-       case 'copy':
-        a = stack.pop();
-        stack.copy(a);
-        break;
-       case 'cos':
-        a = stack.pop();
-        stack.push(Math.cos(a));
-        break;
-       case 'cvi':
-        a = stack.pop() | 0;
-        stack.push(a);
-        break;
-       case 'cvr':
-        break;
-       case 'div':
-        b = stack.pop();
-        a = stack.pop();
-        stack.push(a / b);
-        break;
-       case 'dup':
-        stack.copy(1);
-        break;
-       case 'eq':
-        b = stack.pop();
-        a = stack.pop();
-        stack.push(a === b);
-        break;
-       case 'exch':
-        stack.roll(2, 1);
-        break;
-       case 'exp':
-        b = stack.pop();
-        a = stack.pop();
-        stack.push(Math.pow(a, b));
-        break;
-       case 'false':
-        stack.push(false);
-        break;
-       case 'floor':
-        a = stack.pop();
-        stack.push(Math.floor(a));
-        break;
-       case 'ge':
-        b = stack.pop();
-        a = stack.pop();
-        stack.push(a >= b);
-        break;
-       case 'gt':
-        b = stack.pop();
-        a = stack.pop();
-        stack.push(a > b);
-        break;
-       case 'idiv':
-        b = stack.pop();
-        a = stack.pop();
-        stack.push(a / b | 0);
-        break;
-       case 'index':
-        a = stack.pop();
-        stack.index(a);
-        break;
-       case 'le':
-        b = stack.pop();
-        a = stack.pop();
-        stack.push(a <= b);
-        break;
-       case 'ln':
-        a = stack.pop();
-        stack.push(Math.log(a));
-        break;
-       case 'log':
-        a = stack.pop();
-        stack.push(Math.log(a) / Math.LN10);
-        break;
-       case 'lt':
-        b = stack.pop();
-        a = stack.pop();
-        stack.push(a < b);
-        break;
-       case 'mod':
-        b = stack.pop();
-        a = stack.pop();
-        stack.push(a % b);
-        break;
-       case 'mul':
-        b = stack.pop();
-        a = stack.pop();
-        stack.push(a * b);
-        break;
-       case 'ne':
-        b = stack.pop();
-        a = stack.pop();
-        stack.push(a !== b);
-        break;
-       case 'neg':
-        a = stack.pop();
-        stack.push(-a);
-        break;
-       case 'not':
-        a = stack.pop();
-        if (isBool(a)) {
-         stack.push(!a);
-        } else {
-         stack.push(~a);
-        }
-        break;
-       case 'or':
-        b = stack.pop();
-        a = stack.pop();
-        if (isBool(a) && isBool(b)) {
-         stack.push(a || b);
-        } else {
-         stack.push(a | b);
-        }
-        break;
-       case 'pop':
-        stack.pop();
-        break;
-       case 'roll':
-        b = stack.pop();
-        a = stack.pop();
-        stack.roll(a, b);
-        break;
-       case 'round':
-        a = stack.pop();
-        stack.push(Math.round(a));
-        break;
-       case 'sin':
-        a = stack.pop();
-        stack.push(Math.sin(a));
-        break;
-       case 'sqrt':
-        a = stack.pop();
-        stack.push(Math.sqrt(a));
-        break;
-       case 'sub':
-        b = stack.pop();
-        a = stack.pop();
-        stack.push(a - b);
-        break;
-       case 'true':
-        stack.push(true);
-        break;
-       case 'truncate':
-        a = stack.pop();
-        a = a < 0 ? Math.ceil(a) : Math.floor(a);
-        stack.push(a);
-        break;
-       case 'xor':
-        b = stack.pop();
-        a = stack.pop();
-        if (isBool(a) && isBool(b)) {
-         stack.push(a !== b);
-        } else {
-         stack.push(a ^ b);
-        }
-        break;
-       default:
-        error('Unknown operator ' + operator);
-        break;
-       }
-      }
-      return stack.stack;
-     }
-    };
-    return PostScriptEvaluator;
-   }();
-   var PostScriptCompiler = function PostScriptCompilerClosure() {
-    function AstNode(type) {
-     this.type = type;
-    }
-    AstNode.prototype.visit = function (visitor) {
-     throw new Error('abstract method');
-    };
-    function AstArgument(index, min, max) {
-     AstNode.call(this, 'args');
-     this.index = index;
-     this.min = min;
-     this.max = max;
-    }
-    AstArgument.prototype = Object.create(AstNode.prototype);
-    AstArgument.prototype.visit = function (visitor) {
-     visitor.visitArgument(this);
-    };
-    function AstLiteral(number) {
-     AstNode.call(this, 'literal');
-     this.number = number;
-     this.min = number;
-     this.max = number;
-    }
-    AstLiteral.prototype = Object.create(AstNode.prototype);
-    AstLiteral.prototype.visit = function (visitor) {
-     visitor.visitLiteral(this);
-    };
-    function AstBinaryOperation(op, arg1, arg2, min, max) {
-     AstNode.call(this, 'binary');
-     this.op = op;
-     this.arg1 = arg1;
-     this.arg2 = arg2;
-     this.min = min;
-     this.max = max;
-    }
-    AstBinaryOperation.prototype = Object.create(AstNode.prototype);
-    AstBinaryOperation.prototype.visit = function (visitor) {
-     visitor.visitBinaryOperation(this);
-    };
-    function AstMin(arg, max) {
-     AstNode.call(this, 'max');
-     this.arg = arg;
-     this.min = arg.min;
-     this.max = max;
-    }
-    AstMin.prototype = Object.create(AstNode.prototype);
-    AstMin.prototype.visit = function (visitor) {
-     visitor.visitMin(this);
-    };
-    function AstVariable(index, min, max) {
-     AstNode.call(this, 'var');
-     this.index = index;
-     this.min = min;
-     this.max = max;
-    }
-    AstVariable.prototype = Object.create(AstNode.prototype);
-    AstVariable.prototype.visit = function (visitor) {
-     visitor.visitVariable(this);
-    };
-    function AstVariableDefinition(variable, arg) {
-     AstNode.call(this, 'definition');
-     this.variable = variable;
-     this.arg = arg;
-    }
-    AstVariableDefinition.prototype = Object.create(AstNode.prototype);
-    AstVariableDefinition.prototype.visit = function (visitor) {
-     visitor.visitVariableDefinition(this);
-    };
-    function ExpressionBuilderVisitor() {
-     this.parts = [];
-    }
-    ExpressionBuilderVisitor.prototype = {
-     visitArgument: function (arg) {
-      this.parts.push('Math.max(', arg.min, ', Math.min(', arg.max, ', src[srcOffset + ', arg.index, ']))');
-     },
-     visitVariable: function (variable) {
-      this.parts.push('v', variable.index);
-     },
-     visitLiteral: function (literal) {
-      this.parts.push(literal.number);
-     },
-     visitBinaryOperation: function (operation) {
-      this.parts.push('(');
-      operation.arg1.visit(this);
-      this.parts.push(' ', operation.op, ' ');
-      operation.arg2.visit(this);
-      this.parts.push(')');
-     },
-     visitVariableDefinition: function (definition) {
-      this.parts.push('var ');
-      definition.variable.visit(this);
-      this.parts.push(' = ');
-      definition.arg.visit(this);
-      this.parts.push(';');
-     },
-     visitMin: function (max) {
-      this.parts.push('Math.min(');
-      max.arg.visit(this);
-      this.parts.push(', ', max.max, ')');
-     },
-     toString: function () {
-      return this.parts.join('');
-     }
-    };
-    function buildAddOperation(num1, num2) {
-     if (num2.type === 'literal' && num2.number === 0) {
-      return num1;
-     }
-     if (num1.type === 'literal' && num1.number === 0) {
-      return num2;
-     }
-     if (num2.type === 'literal' && num1.type === 'literal') {
-      return new AstLiteral(num1.number + num2.number);
-     }
-     return new AstBinaryOperation('+', num1, num2, num1.min + num2.min, num1.max + num2.max);
-    }
-    function buildMulOperation(num1, num2) {
-     if (num2.type === 'literal') {
-      if (num2.number === 0) {
-       return new AstLiteral(0);
-      } else if (num2.number === 1) {
-       return num1;
-      } else if (num1.type === 'literal') {
-       return new AstLiteral(num1.number * num2.number);
-      }
-     }
-     if (num1.type === 'literal') {
-      if (num1.number === 0) {
-       return new AstLiteral(0);
-      } else if (num1.number === 1) {
-       return num2;
-      }
-     }
-     var min = Math.min(num1.min * num2.min, num1.min * num2.max, num1.max * num2.min, num1.max * num2.max);
-     var max = Math.max(num1.min * num2.min, num1.min * num2.max, num1.max * num2.min, num1.max * num2.max);
-     return new AstBinaryOperation('*', num1, num2, min, max);
-    }
-    function buildSubOperation(num1, num2) {
-     if (num2.type === 'literal') {
-      if (num2.number === 0) {
-       return num1;
-      } else if (num1.type === 'literal') {
-       return new AstLiteral(num1.number - num2.number);
-      }
-     }
-     if (num2.type === 'binary' && num2.op === '-' && num1.type === 'literal' && num1.number === 1 && num2.arg1.type === 'literal' && num2.arg1.number === 1) {
-      return num2.arg2;
-     }
-     return new AstBinaryOperation('-', num1, num2, num1.min - num2.max, num1.max - num2.min);
-    }
-    function buildMinOperation(num1, max) {
-     if (num1.min >= max) {
-      return new AstLiteral(max);
-     } else if (num1.max <= max) {
-      return num1;
-     }
-     return new AstMin(num1, max);
-    }
-    function PostScriptCompiler() {
-    }
-    PostScriptCompiler.prototype = {
-     compile: function PostScriptCompiler_compile(code, domain, range) {
-      var stack = [];
-      var i, ii;
-      var instructions = [];
-      var inputSize = domain.length >> 1, outputSize = range.length >> 1;
-      var lastRegister = 0;
-      var n, j;
-      var num1, num2, ast1, ast2, tmpVar, item;
-      for (i = 0; i < inputSize; i++) {
-       stack.push(new AstArgument(i, domain[i * 2], domain[i * 2 + 1]));
-      }
-      for (i = 0, ii = code.length; i < ii; i++) {
-       item = code[i];
-       if (typeof item === 'number') {
-        stack.push(new AstLiteral(item));
-        continue;
-       }
-       switch (item) {
-       case 'add':
-        if (stack.length < 2) {
-         return null;
-        }
-        num2 = stack.pop();
-        num1 = stack.pop();
-        stack.push(buildAddOperation(num1, num2));
-        break;
-       case 'cvr':
-        if (stack.length < 1) {
-         return null;
-        }
-        break;
-       case 'mul':
-        if (stack.length < 2) {
-         return null;
-        }
-        num2 = stack.pop();
-        num1 = stack.pop();
-        stack.push(buildMulOperation(num1, num2));
-        break;
-       case 'sub':
-        if (stack.length < 2) {
-         return null;
-        }
-        num2 = stack.pop();
-        num1 = stack.pop();
-        stack.push(buildSubOperation(num1, num2));
-        break;
-       case 'exch':
-        if (stack.length < 2) {
-         return null;
-        }
-        ast1 = stack.pop();
-        ast2 = stack.pop();
-        stack.push(ast1, ast2);
-        break;
-       case 'pop':
-        if (stack.length < 1) {
-         return null;
-        }
-        stack.pop();
-        break;
-       case 'index':
-        if (stack.length < 1) {
-         return null;
-        }
-        num1 = stack.pop();
-        if (num1.type !== 'literal') {
-         return null;
-        }
-        n = num1.number;
-        if (n < 0 || (n | 0) !== n || stack.length < n) {
-         return null;
-        }
-        ast1 = stack[stack.length - n - 1];
-        if (ast1.type === 'literal' || ast1.type === 'var') {
-         stack.push(ast1);
-         break;
-        }
-        tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);
-        stack[stack.length - n - 1] = tmpVar;
-        stack.push(tmpVar);
-        instructions.push(new AstVariableDefinition(tmpVar, ast1));
-        break;
-       case 'dup':
-        if (stack.length < 1) {
-         return null;
-        }
-        if (typeof code[i + 1] === 'number' && code[i + 2] === 'gt' && code[i + 3] === i + 7 && code[i + 4] === 'jz' && code[i + 5] === 'pop' && code[i + 6] === code[i + 1]) {
-         num1 = stack.pop();
-         stack.push(buildMinOperation(num1, code[i + 1]));
-         i += 6;
-         break;
-        }
-        ast1 = stack[stack.length - 1];
-        if (ast1.type === 'literal' || ast1.type === 'var') {
-         stack.push(ast1);
-         break;
-        }
-        tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);
-        stack[stack.length - 1] = tmpVar;
-        stack.push(tmpVar);
-        instructions.push(new AstVariableDefinition(tmpVar, ast1));
-        break;
-       case 'roll':
-        if (stack.length < 2) {
-         return null;
-        }
-        num2 = stack.pop();
-        num1 = stack.pop();
-        if (num2.type !== 'literal' || num1.type !== 'literal') {
-         return null;
-        }
-        j = num2.number;
-        n = num1.number;
-        if (n <= 0 || (n | 0) !== n || (j | 0) !== j || stack.length < n) {
-         return null;
-        }
-        j = (j % n + n) % n;
-        if (j === 0) {
-         break;
-        }
-        Array.prototype.push.apply(stack, stack.splice(stack.length - n, n - j));
-        break;
-       default:
-        return null;
-       }
-      }
-      if (stack.length !== outputSize) {
-       return null;
-      }
-      var result = [];
-      instructions.forEach(function (instruction) {
-       var statementBuilder = new ExpressionBuilderVisitor();
-       instruction.visit(statementBuilder);
-       result.push(statementBuilder.toString());
-      });
-      stack.forEach(function (expr, i) {
-       var statementBuilder = new ExpressionBuilderVisitor();
-       expr.visit(statementBuilder);
-       var min = range[i * 2], max = range[i * 2 + 1];
-       var out = [statementBuilder.toString()];
-       if (min > expr.min) {
-        out.unshift('Math.max(', min, ', ');
-        out.push(')');
-       }
-       if (max < expr.max) {
-        out.unshift('Math.min(', max, ', ');
-        out.push(')');
-       }
-       out.unshift('dest[destOffset + ', i, '] = ');
-       out.push(';');
-       result.push(out.join(''));
-      });
-      return result.join('\n');
-     }
-    };
-    return PostScriptCompiler;
-   }();
-   exports.isPDFFunction = isPDFFunction;
-   exports.PDFFunction = PDFFunction;
-   exports.PostScriptEvaluator = PostScriptEvaluator;
-   exports.PostScriptCompiler = PostScriptCompiler;
-  }));
-  (function (root, factory) {
-   factory(root.pdfjsCoreColorSpace = {}, root.pdfjsSharedUtil, root.pdfjsCorePrimitives, root.pdfjsCoreFunction);
-  }(this, function (exports, sharedUtil, corePrimitives, coreFunction) {
-   var error = sharedUtil.error;
-   var info = sharedUtil.info;
-   var isArray = sharedUtil.isArray;
-   var isString = sharedUtil.isString;
-   var shadow = sharedUtil.shadow;
-   var warn = sharedUtil.warn;
-   var isDict = corePrimitives.isDict;
-   var isName = corePrimitives.isName;
-   var isStream = corePrimitives.isStream;
-   var PDFFunction = coreFunction.PDFFunction;
-   var ColorSpace = function ColorSpaceClosure() {
-    function resizeRgbImage(src, bpc, w1, h1, w2, h2, alpha01, dest) {
-     var COMPONENTS = 3;
-     alpha01 = alpha01 !== 1 ? 0 : alpha01;
-     var xRatio = w1 / w2;
-     var yRatio = h1 / h2;
-     var i, j, py, newIndex = 0, oldIndex;
-     var xScaled = new Uint16Array(w2);
-     var w1Scanline = w1 * COMPONENTS;
-     for (i = 0; i < w2; i++) {
-      xScaled[i] = Math.floor(i * xRatio) * COMPONENTS;
-     }
-     for (i = 0; i < h2; i++) {
-      py = Math.floor(i * yRatio) * w1Scanline;
-      for (j = 0; j < w2; j++) {
-       oldIndex = py + xScaled[j];
-       dest[newIndex++] = src[oldIndex++];
-       dest[newIndex++] = src[oldIndex++];
-       dest[newIndex++] = src[oldIndex++];
-       newIndex += alpha01;
-      }
-     }
-    }
-    function ColorSpace() {
-     error('should not call ColorSpace constructor');
-    }
-    ColorSpace.prototype = {
-     getRgb: function ColorSpace_getRgb(src, srcOffset) {
-      var rgb = new Uint8Array(3);
-      this.getRgbItem(src, srcOffset, rgb, 0);
-      return rgb;
-     },
-     getRgbItem: function ColorSpace_getRgbItem(src, srcOffset, dest, destOffset) {
-      error('Should not call ColorSpace.getRgbItem');
-     },
-     getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
-      error('Should not call ColorSpace.getRgbBuffer');
-     },
-     getOutputLength: function ColorSpace_getOutputLength(inputLength, alpha01) {
-      error('Should not call ColorSpace.getOutputLength');
-     },
-     isPassthrough: function ColorSpace_isPassthrough(bits) {
-      return false;
-     },
-     fillRgb: function ColorSpace_fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight, bpc, comps, alpha01) {
-      var count = originalWidth * originalHeight;
-      var rgbBuf = null;
-      var numComponentColors = 1 << bpc;
-      var needsResizing = originalHeight !== height || originalWidth !== width;
-      var i, ii;
-      if (this.isPassthrough(bpc)) {
-       rgbBuf = comps;
-      } else if (this.numComps === 1 && count > numComponentColors && this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') {
-       var allColors = bpc <= 8 ? new Uint8Array(numComponentColors) : new Uint16Array(numComponentColors);
-       var key;
-       for (i = 0; i < numComponentColors; i++) {
-        allColors[i] = i;
-       }
-       var colorMap = new Uint8Array(numComponentColors * 3);
-       this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc, 0);
-       var destPos, rgbPos;
-       if (!needsResizing) {
-        destPos = 0;
-        for (i = 0; i < count; ++i) {
-         key = comps[i] * 3;
-         dest[destPos++] = colorMap[key];
-         dest[destPos++] = colorMap[key + 1];
-         dest[destPos++] = colorMap[key + 2];
-         destPos += alpha01;
-        }
-       } else {
-        rgbBuf = new Uint8Array(count * 3);
-        rgbPos = 0;
-        for (i = 0; i < count; ++i) {
-         key = comps[i] * 3;
-         rgbBuf[rgbPos++] = colorMap[key];
-         rgbBuf[rgbPos++] = colorMap[key + 1];
-         rgbBuf[rgbPos++] = colorMap[key + 2];
-        }
-       }
-      } else {
-       if (!needsResizing) {
-        this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc, alpha01);
-       } else {
-        rgbBuf = new Uint8Array(count * 3);
-        this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc, 0);
-       }
-      }
-      if (rgbBuf) {
-       if (needsResizing) {
-        resizeRgbImage(rgbBuf, bpc, originalWidth, originalHeight, width, height, alpha01, dest);
-       } else {
-        rgbPos = 0;
-        destPos = 0;
-        for (i = 0, ii = width * actualHeight; i < ii; i++) {
-         dest[destPos++] = rgbBuf[rgbPos++];
-         dest[destPos++] = rgbBuf[rgbPos++];
-         dest[destPos++] = rgbBuf[rgbPos++];
-         destPos += alpha01;
-        }
-       }
-      }
-     },
-     usesZeroToOneRange: true
-    };
-    ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
-     var IR = ColorSpace.parseToIR(cs, xref, res);
-     if (IR instanceof AlternateCS) {
-      return IR;
-     }
-     return ColorSpace.fromIR(IR);
-    };
-    ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
-     var name = isArray(IR) ? IR[0] : IR;
-     var whitePoint, blackPoint, gamma;
-     switch (name) {
-     case 'DeviceGrayCS':
-      return this.singletons.gray;
-     case 'DeviceRgbCS':
-      return this.singletons.rgb;
-     case 'DeviceCmykCS':
-      return this.singletons.cmyk;
-     case 'CalGrayCS':
-      whitePoint = IR[1];
-      blackPoint = IR[2];
-      gamma = IR[3];
-      return new CalGrayCS(whitePoint, blackPoint, gamma);
-     case 'CalRGBCS':
-      whitePoint = IR[1];
-      blackPoint = IR[2];
-      gamma = IR[3];
-      var matrix = IR[4];
-      return new CalRGBCS(whitePoint, blackPoint, gamma, matrix);
-     case 'PatternCS':
-      var basePatternCS = IR[1];
-      if (basePatternCS) {
-       basePatternCS = ColorSpace.fromIR(basePatternCS);
-      }
-      return new PatternCS(basePatternCS);
-     case 'IndexedCS':
-      var baseIndexedCS = IR[1];
-      var hiVal = IR[2];
-      var lookup = IR[3];
-      return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup);
-     case 'AlternateCS':
-      var numComps = IR[1];
-      var alt = IR[2];
-      var tintFnIR = IR[3];
-      return new AlternateCS(numComps, ColorSpace.fromIR(alt), PDFFunction.fromIR(tintFnIR));
-     case 'LabCS':
-      whitePoint = IR[1];
-      blackPoint = IR[2];
-      var range = IR[3];
-      return new LabCS(whitePoint, blackPoint, range);
-     default:
-      error('Unknown name ' + name);
-     }
-     return null;
-    };
-    ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) {
-     if (isName(cs)) {
-      var colorSpaces = res.get('ColorSpace');
-      if (isDict(colorSpaces)) {
-       var refcs = colorSpaces.get(cs.name);
-       if (refcs) {
-        cs = refcs;
-       }
-      }
-     }
-     cs = xref.fetchIfRef(cs);
-     if (isName(cs)) {
-      switch (cs.name) {
-      case 'DeviceGray':
-      case 'G':
-       return 'DeviceGrayCS';
-      case 'DeviceRGB':
-      case 'RGB':
-       return 'DeviceRgbCS';
-      case 'DeviceCMYK':
-      case 'CMYK':
-       return 'DeviceCmykCS';
-      case 'Pattern':
-       return [
-        'PatternCS',
-        null
-       ];
-      default:
-       error('unrecognized colorspace ' + cs.name);
-      }
-     } else if (isArray(cs)) {
-      var mode = xref.fetchIfRef(cs[0]).name;
-      var numComps, params, alt, whitePoint, blackPoint, gamma;
-      switch (mode) {
-      case 'DeviceGray':
-      case 'G':
-       return 'DeviceGrayCS';
-      case 'DeviceRGB':
-      case 'RGB':
-       return 'DeviceRgbCS';
-      case 'DeviceCMYK':
-      case 'CMYK':
-       return 'DeviceCmykCS';
-      case 'CalGray':
-       params = xref.fetchIfRef(cs[1]);
-       whitePoint = params.getArray('WhitePoint');
-       blackPoint = params.getArray('BlackPoint');
-       gamma = params.get('Gamma');
-       return [
-        'CalGrayCS',
-        whitePoint,
-        blackPoint,
-        gamma
-       ];
-      case 'CalRGB':
-       params = xref.fetchIfRef(cs[1]);
-       whitePoint = params.getArray('WhitePoint');
-       blackPoint = params.getArray('BlackPoint');
-       gamma = params.getArray('Gamma');
-       var matrix = params.getArray('Matrix');
-       return [
-        'CalRGBCS',
-        whitePoint,
-        blackPoint,
-        gamma,
-        matrix
-       ];
-      case 'ICCBased':
-       var stream = xref.fetchIfRef(cs[1]);
-       var dict = stream.dict;
-       numComps = dict.get('N');
-       alt = dict.get('Alternate');
-       if (alt) {
-        var altIR = ColorSpace.parseToIR(alt, xref, res);
-        var altCS = ColorSpace.fromIR(altIR);
-        if (altCS.numComps === numComps) {
-         return altIR;
-        }
-        warn('ICCBased color space: Ignoring incorrect /Alternate entry.');
-       }
-       if (numComps === 1) {
-        return 'DeviceGrayCS';
-       } else if (numComps === 3) {
-        return 'DeviceRgbCS';
-       } else if (numComps === 4) {
-        return 'DeviceCmykCS';
-       }
-       break;
-      case 'Pattern':
-       var basePatternCS = cs[1] || null;
-       if (basePatternCS) {
-        basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);
-       }
-       return [
-        'PatternCS',
-        basePatternCS
-       ];
-      case 'Indexed':
-      case 'I':
-       var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res);
-       var hiVal = xref.fetchIfRef(cs[2]) + 1;
-       var lookup = xref.fetchIfRef(cs[3]);
-       if (isStream(lookup)) {
-        lookup = lookup.getBytes();
-       }
-       return [
-        'IndexedCS',
-        baseIndexedCS,
-        hiVal,
-        lookup
-       ];
-      case 'Separation':
-      case 'DeviceN':
-       var name = xref.fetchIfRef(cs[1]);
-       numComps = isArray(name) ? name.length : 1;
-       alt = ColorSpace.parseToIR(cs[2], xref, res);
-       var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
-       return [
-        'AlternateCS',
-        numComps,
-        alt,
-        tintFnIR
-       ];
-      case 'Lab':
-       params = xref.fetchIfRef(cs[1]);
-       whitePoint = params.getArray('WhitePoint');
-       blackPoint = params.getArray('BlackPoint');
-       var range = params.getArray('Range');
-       return [
-        'LabCS',
-        whitePoint,
-        blackPoint,
-        range
-       ];
-      default:
-       error('unimplemented color space object "' + mode + '"');
-      }
-     } else {
-      error('unrecognized color space object: "' + cs + '"');
-     }
-     return null;
-    };
-    ColorSpace.isDefaultDecode = function ColorSpace_isDefaultDecode(decode, n) {
-     if (!isArray(decode)) {
-      return true;
-     }
-     if (n * 2 !== decode.length) {
-      warn('The decode map is not the correct length');
-      return true;
-     }
-     for (var i = 0, ii = decode.length; i < ii; i += 2) {
-      if (decode[i] !== 0 || decode[i + 1] !== 1) {
-       return false;
-      }
-     }
-     return true;
-    };
-    ColorSpace.singletons = {
-     get gray() {
-      return shadow(this, 'gray', new DeviceGrayCS());
-     },
-     get rgb() {
-      return shadow(this, 'rgb', new DeviceRgbCS());
-     },
-     get cmyk() {
-      return shadow(this, 'cmyk', new DeviceCmykCS());
-     }
-    };
-    return ColorSpace;
-   }();
-   var AlternateCS = function AlternateCSClosure() {
-    function AlternateCS(numComps, base, tintFn) {
-     this.name = 'Alternate';
-     this.numComps = numComps;
-     this.defaultColor = new Float32Array(numComps);
-     for (var i = 0; i < numComps; ++i) {
-      this.defaultColor[i] = 1;
-     }
-     this.base = base;
-     this.tintFn = tintFn;
-     this.tmpBuf = new Float32Array(base.numComps);
-    }
-    AlternateCS.prototype = {
-     getRgb: ColorSpace.prototype.getRgb,
-     getRgbItem: function AlternateCS_getRgbItem(src, srcOffset, dest, destOffset) {
-      var tmpBuf = this.tmpBuf;
-      this.tintFn(src, srcOffset, tmpBuf, 0);
-      this.base.getRgbItem(tmpBuf, 0, dest, destOffset);
-     },
-     getRgbBuffer: function AlternateCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
-      var tintFn = this.tintFn;
-      var base = this.base;
-      var scale = 1 / ((1 << bits) - 1);
-      var baseNumComps = base.numComps;
-      var usesZeroToOneRange = base.usesZeroToOneRange;
-      var isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) && alpha01 === 0;
-      var pos = isPassthrough ? destOffset : 0;
-      var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count);
-      var numComps = this.numComps;
-      var scaled = new Float32Array(numComps);
-      var tinted = new Float32Array(baseNumComps);
-      var i, j;
-      for (i = 0; i < count; i++) {
-       for (j = 0; j < numComps; j++) {
-        scaled[j] = src[srcOffset++] * scale;
-       }
-       tintFn(scaled, 0, tinted, 0);
-       if (usesZeroToOneRange) {
-        for (j = 0; j < baseNumComps; j++) {
-         baseBuf[pos++] = tinted[j] * 255;
-        }
-       } else {
-        base.getRgbItem(tinted, 0, baseBuf, pos);
-        pos += baseNumComps;
-       }
-      }
-      if (!isPassthrough) {
-       base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01);
-      }
-     },
-     getOutputLength: function AlternateCS_getOutputLength(inputLength, alpha01) {
-      return this.base.getOutputLength(inputLength * this.base.numComps / this.numComps, alpha01);
-     },
-     isPassthrough: ColorSpace.prototype.isPassthrough,
-     fillRgb: ColorSpace.prototype.fillRgb,
-     isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {
-      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
-     },
-     usesZeroToOneRange: true
-    };
-    return AlternateCS;
-   }();
-   var PatternCS = function PatternCSClosure() {
-    function PatternCS(baseCS) {
-     this.name = 'Pattern';
-     this.base = baseCS;
-    }
-    PatternCS.prototype = {};
-    return PatternCS;
-   }();
-   var IndexedCS = function IndexedCSClosure() {
-    function IndexedCS(base, highVal, lookup) {
-     this.name = 'Indexed';
-     this.numComps = 1;
-     this.defaultColor = new Uint8Array(this.numComps);
-     this.base = base;
-     this.highVal = highVal;
-     var baseNumComps = base.numComps;
-     var length = baseNumComps * highVal;
-     if (isStream(lookup)) {
-      this.lookup = new Uint8Array(length);
-      var bytes = lookup.getBytes(length);
-      this.lookup.set(bytes);
-     } else if (isString(lookup)) {
-      this.lookup = new Uint8Array(length);
-      for (var i = 0; i < length; ++i) {
-       this.lookup[i] = lookup.charCodeAt(i);
-      }
-     } else if (lookup instanceof Uint8Array || lookup instanceof Array) {
-      this.lookup = lookup;
-     } else {
-      error('Unrecognized lookup table: ' + lookup);
-     }
-    }
-    IndexedCS.prototype = {
-     getRgb: ColorSpace.prototype.getRgb,
-     getRgbItem: function IndexedCS_getRgbItem(src, srcOffset, dest, destOffset) {
-      var numComps = this.base.numComps;
-      var start = src[srcOffset] * numComps;
-      this.base.getRgbItem(this.lookup, start, dest, destOffset);
-     },
-     getRgbBuffer: function IndexedCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
-      var base = this.base;
-      var numComps = base.numComps;
-      var outputDelta = base.getOutputLength(numComps, alpha01);
-      var lookup = this.lookup;
-      for (var i = 0; i < count; ++i) {
-       var lookupPos = src[srcOffset++] * numComps;
-       base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01);
-       destOffset += outputDelta;
-      }
-     },
-     getOutputLength: function IndexedCS_getOutputLength(inputLength, alpha01) {
-      return this.base.getOutputLength(inputLength * this.base.numComps, alpha01);
-     },
-     isPassthrough: ColorSpace.prototype.isPassthrough,
-     fillRgb: ColorSpace.prototype.fillRgb,
-     isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {
-      return true;
-     },
-     usesZeroToOneRange: true
-    };
-    return IndexedCS;
-   }();
-   var DeviceGrayCS = function DeviceGrayCSClosure() {
-    function DeviceGrayCS() {
-     this.name = 'DeviceGray';
-     this.numComps = 1;
-     this.defaultColor = new Float32Array(this.numComps);
-    }
-    DeviceGrayCS.prototype = {
-     getRgb: ColorSpace.prototype.getRgb,
-     getRgbItem: function DeviceGrayCS_getRgbItem(src, srcOffset, dest, destOffset) {
-      var c = src[srcOffset] * 255 | 0;
-      c = c < 0 ? 0 : c > 255 ? 255 : c;
-      dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c;
-     },
-     getRgbBuffer: function DeviceGrayCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
-      var scale = 255 / ((1 << bits) - 1);
-      var j = srcOffset, q = destOffset;
-      for (var i = 0; i < count; ++i) {
-       var c = scale * src[j++] | 0;
-       dest[q++] = c;
-       dest[q++] = c;
-       dest[q++] = c;
-       q += alpha01;
-      }
-     },
-     getOutputLength: function DeviceGrayCS_getOutputLength(inputLength, alpha01) {
-      return inputLength * (3 + alpha01);
-     },
-     isPassthrough: ColorSpace.prototype.isPassthrough,
-     fillRgb: ColorSpace.prototype.fillRgb,
-     isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
-      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
-     },
-     usesZeroToOneRange: true
-    };
-    return DeviceGrayCS;
-   }();
-   var DeviceRgbCS = function DeviceRgbCSClosure() {
-    function DeviceRgbCS() {
-     this.name = 'DeviceRGB';
-     this.numComps = 3;
-     this.defaultColor = new Float32Array(this.numComps);
-    }
-    DeviceRgbCS.prototype = {
-     getRgb: ColorSpace.prototype.getRgb,
-     getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset, dest, destOffset) {
-      var r = src[srcOffset] * 255 | 0;
-      var g = src[srcOffset + 1] * 255 | 0;
-      var b = src[srcOffset + 2] * 255 | 0;
-      dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r;
-      dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g;
-      dest[destOffset + 2] = b < 0 ? 0 : b > 255 ? 255 : b;
-     },
-     getRgbBuffer: function DeviceRgbCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
-      if (bits === 8 && alpha01 === 0) {
-       dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset);
-       return;
-      }
-      var scale = 255 / ((1 << bits) - 1);
-      var j = srcOffset, q = destOffset;
-      for (var i = 0; i < count; ++i) {
-       dest[q++] = scale * src[j++] | 0;
-       dest[q++] = scale * src[j++] | 0;
-       dest[q++] = scale * src[j++] | 0;
-       q += alpha01;
-      }
-     },
-     getOutputLength: function DeviceRgbCS_getOutputLength(inputLength, alpha01) {
-      return inputLength * (3 + alpha01) / 3 | 0;
-     },
-     isPassthrough: function DeviceRgbCS_isPassthrough(bits) {
-      return bits === 8;
-     },
-     fillRgb: ColorSpace.prototype.fillRgb,
-     isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
-      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
-     },
-     usesZeroToOneRange: true
-    };
-    return DeviceRgbCS;
-   }();
-   var DeviceCmykCS = function DeviceCmykCSClosure() {
-    function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
-     var c = src[srcOffset + 0] * srcScale;
-     var m = src[srcOffset + 1] * srcScale;
-     var y = src[srcOffset + 2] * srcScale;
-     var k = src[srcOffset + 3] * srcScale;
-     var r = 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) + 255 | 0;
-     var g = 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) + 255 | 0;
-     var b = 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) + 255 | 0;
-     dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r;
-     dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g;
-     dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b;
-    }
-    function DeviceCmykCS() {
-     this.name = 'DeviceCMYK';
-     this.numComps = 4;
-     this.defaultColor = new Float32Array(this.numComps);
-     this.defaultColor[3] = 1;
-    }
-    DeviceCmykCS.prototype = {
-     getRgb: ColorSpace.prototype.getRgb,
-     getRgbItem: function DeviceCmykCS_getRgbItem(src, srcOffset, dest, destOffset) {
-      convertToRgb(src, srcOffset, 1, dest, destOffset);
-     },
-     getRgbBuffer: function DeviceCmykCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
-      var scale = 1 / ((1 << bits) - 1);
-      for (var i = 0; i < count; i++) {
-       convertToRgb(src, srcOffset, scale, dest, destOffset);
-       srcOffset += 4;
-       destOffset += 3 + alpha01;
-      }
-     },
-     getOutputLength: function DeviceCmykCS_getOutputLength(inputLength, alpha01) {
-      return inputLength / 4 * (3 + alpha01) | 0;
-     },
-     isPassthrough: ColorSpace.prototype.isPassthrough,
-     fillRgb: ColorSpace.prototype.fillRgb,
-     isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {
-      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
-     },
-     usesZeroToOneRange: true
-    };
-    return DeviceCmykCS;
-   }();
-   var CalGrayCS = function CalGrayCSClosure() {
-    function CalGrayCS(whitePoint, blackPoint, gamma) {
-     this.name = 'CalGray';
-     this.numComps = 1;
-     this.defaultColor = new Float32Array(this.numComps);
-     if (!whitePoint) {
-      error('WhitePoint missing - required for color space CalGray');
-     }
-     blackPoint = blackPoint || [
-      0,
-      0,
-      0
-     ];
-     gamma = gamma || 1;
-     this.XW = whitePoint[0];
-     this.YW = whitePoint[1];
-     this.ZW = whitePoint[2];
-     this.XB = blackPoint[0];
-     this.YB = blackPoint[1];
-     this.ZB = blackPoint[2];
-     this.G = gamma;
-     if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
-      error('Invalid WhitePoint components for ' + this.name + ', no fallback available');
-     }
-     if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
-      info('Invalid BlackPoint for ' + this.name + ', falling back to default');
-      this.XB = this.YB = this.ZB = 0;
-     }
-     if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) {
-      warn(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB + ', ZB: ' + this.ZB + ', only default values are supported.');
-     }
-     if (this.G < 1) {
-      info('Invalid Gamma: ' + this.G + ' for ' + this.name + ', falling back to default');
-      this.G = 1;
-     }
-    }
-    function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
-     var A = src[srcOffset] * scale;
-     var AG = Math.pow(A, cs.G);
-     var L = cs.YW * AG;
-     var val = Math.max(295.8 * Math.pow(L, 0.333333333333333333) - 40.8, 0) | 0;
-     dest[destOffset] = val;
-     dest[destOffset + 1] = val;
-     dest[destOffset + 2] = val;
-    }
-    CalGrayCS.prototype = {
-     getRgb: ColorSpace.prototype.getRgb,
-     getRgbItem: function CalGrayCS_getRgbItem(src, srcOffset, dest, destOffset) {
-      convertToRgb(this, src, srcOffset, dest, destOffset, 1);
-     },
-     getRgbBuffer: function CalGrayCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
-      var scale = 1 / ((1 << bits) - 1);
-      for (var i = 0; i < count; ++i) {
-       convertToRgb(this, src, srcOffset, dest, destOffset, scale);
-       srcOffset += 1;
-       destOffset += 3 + alpha01;
-      }
-     },
-     getOutputLength: function CalGrayCS_getOutputLength(inputLength, alpha01) {
-      return inputLength * (3 + alpha01);
-     },
-     isPassthrough: ColorSpace.prototype.isPassthrough,
-     fillRgb: ColorSpace.prototype.fillRgb,
-     isDefaultDecode: function CalGrayCS_isDefaultDecode(decodeMap) {
-      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
-     },
-     usesZeroToOneRange: true
-    };
-    return CalGrayCS;
-   }();
-   var CalRGBCS = function CalRGBCSClosure() {
-    var BRADFORD_SCALE_MATRIX = new Float32Array([
-     0.8951,
-     0.2664,
-     -0.1614,
-     -0.7502,
-     1.7135,
-     0.0367,
-     0.0389,
-     -0.0685,
-     1.0296
-    ]);
-    var BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([
-     0.9869929,
-     -0.1470543,
-     0.1599627,
-     0.4323053,
-     0.5183603,
-     0.0492912,
-     -0.0085287,
-     0.0400428,
-     0.9684867
-    ]);
-    var SRGB_D65_XYZ_TO_RGB_MATRIX = new Float32Array([
-     3.2404542,
-     -1.5371385,
-     -0.4985314,
-     -0.9692660,
-     1.8760108,
-     0.0415560,
-     0.0556434,
-     -0.2040259,
-     1.0572252
-    ]);
-    var FLAT_WHITEPOINT_MATRIX = new Float32Array([
-     1,
-     1,
-     1
-    ]);
-    var tempNormalizeMatrix = new Float32Array(3);
-    var tempConvertMatrix1 = new Float32Array(3);
-    var tempConvertMatrix2 = new Float32Array(3);
-    var DECODE_L_CONSTANT = Math.pow((8 + 16) / 116, 3) / 8.0;
-    function CalRGBCS(whitePoint, blackPoint, gamma, matrix) {
-     this.name = 'CalRGB';
-     this.numComps = 3;
-     this.defaultColor = new Float32Array(this.numComps);
-     if (!whitePoint) {
-      error('WhitePoint missing - required for color space CalRGB');
-     }
-     blackPoint = blackPoint || new Float32Array(3);
-     gamma = gamma || new Float32Array([
-      1,
-      1,
-      1
-     ]);
-     matrix = matrix || new Float32Array([
-      1,
-      0,
-      0,
-      0,
-      1,
-      0,
-      0,
-      0,
-      1
-     ]);
-     var XW = whitePoint[0];
-     var YW = whitePoint[1];
-     var ZW = whitePoint[2];
-     this.whitePoint = whitePoint;
-     var XB = blackPoint[0];
-     var YB = blackPoint[1];
-     var ZB = blackPoint[2];
-     this.blackPoint = blackPoint;
-     this.GR = gamma[0];
-     this.GG = gamma[1];
-     this.GB = gamma[2];
-     this.MXA = matrix[0];
-     this.MYA = matrix[1];
-     this.MZA = matrix[2];
-     this.MXB = matrix[3];
-     this.MYB = matrix[4];
-     this.MZB = matrix[5];
-     this.MXC = matrix[6];
-     this.MYC = matrix[7];
-     this.MZC = matrix[8];
-     if (XW < 0 || ZW < 0 || YW !== 1) {
-      error('Invalid WhitePoint components for ' + this.name + ', no fallback available');
-     }
-     if (XB < 0 || YB < 0 || ZB < 0) {
-      info('Invalid BlackPoint for ' + this.name + ' [' + XB + ', ' + YB + ', ' + ZB + '], falling back to default');
-      this.blackPoint = new Float32Array(3);
-     }
-     if (this.GR < 0 || this.GG < 0 || this.GB < 0) {
-      info('Invalid Gamma [' + this.GR + ', ' + this.GG + ', ' + this.GB + '] for ' + this.name + ', falling back to default');
-      this.GR = this.GG = this.GB = 1;
-     }
-     if (this.MXA < 0 || this.MYA < 0 || this.MZA < 0 || this.MXB < 0 || this.MYB < 0 || this.MZB < 0 || this.MXC < 0 || this.MYC < 0 || this.MZC < 0) {
-      info('Invalid Matrix for ' + this.name + ' [' + this.MXA + ', ' + this.MYA + ', ' + this.MZA + this.MXB + ', ' + this.MYB + ', ' + this.MZB + this.MXC + ', ' + this.MYC + ', ' + this.MZC + '], falling back to default');
-      this.MXA = this.MYB = this.MZC = 1;
-      this.MXB = this.MYA = this.MZA = this.MXC = this.MYC = this.MZB = 0;
-     }
-    }
-    function matrixProduct(a, b, result) {
-     result[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
-     result[1] = a[3] * b[0] + a[4] * b[1] + a[5] * b[2];
-     result[2] = a[6] * b[0] + a[7] * b[1] + a[8] * b[2];
-    }
-    function convertToFlat(sourceWhitePoint, LMS, result) {
-     result[0] = LMS[0] * 1 / sourceWhitePoint[0];
-     result[1] = LMS[1] * 1 / sourceWhitePoint[1];
-     result[2] = LMS[2] * 1 / sourceWhitePoint[2];
-    }
-    function convertToD65(sourceWhitePoint, LMS, result) {
-     var D65X = 0.95047;
-     var D65Y = 1;
-     var D65Z = 1.08883;
-     result[0] = LMS[0] * D65X / sourceWhitePoint[0];
-     result[1] = LMS[1] * D65Y / sourceWhitePoint[1];
-     result[2] = LMS[2] * D65Z / sourceWhitePoint[2];
-    }
-    function sRGBTransferFunction(color) {
-     if (color <= 0.0031308) {
-      return adjustToRange(0, 1, 12.92 * color);
-     }
-     return adjustToRange(0, 1, (1 + 0.055) * Math.pow(color, 1 / 2.4) - 0.055);
-    }
-    function adjustToRange(min, max, value) {
-     return Math.max(min, Math.min(max, value));
-    }
-    function decodeL(L) {
-     if (L < 0) {
-      return -decodeL(-L);
-     }
-     if (L > 8.0) {
-      return Math.pow((L + 16) / 116, 3);
-     }
-     return L * DECODE_L_CONSTANT;
-    }
-    function compensateBlackPoint(sourceBlackPoint, XYZ_Flat, result) {
-     if (sourceBlackPoint[0] === 0 && sourceBlackPoint[1] === 0 && sourceBlackPoint[2] === 0) {
-      result[0] = XYZ_Flat[0];
-      result[1] = XYZ_Flat[1];
-      result[2] = XYZ_Flat[2];
-      return;
-     }
-     var zeroDecodeL = decodeL(0);
-     var X_DST = zeroDecodeL;
-     var X_SRC = decodeL(sourceBlackPoint[0]);
-     var Y_DST = zeroDecodeL;
-     var Y_SRC = decodeL(sourceBlackPoint[1]);
-     var Z_DST = zeroDecodeL;
-     var Z_SRC = decodeL(sourceBlackPoint[2]);
-     var X_Scale = (1 - X_DST) / (1 - X_SRC);
-     var X_Offset = 1 - X_Scale;
-     var Y_Scale = (1 - Y_DST) / (1 - Y_SRC);
-     var Y_Offset = 1 - Y_Scale;
-     var Z_Scale = (1 - Z_DST) / (1 - Z_SRC);
-     var Z_Offset = 1 - Z_Scale;
-     result[0] = XYZ_Flat[0] * X_Scale + X_Offset;
-     result[1] = XYZ_Flat[1] * Y_Scale + Y_Offset;
-     result[2] = XYZ_Flat[2] * Z_Scale + Z_Offset;
-    }
-    function normalizeWhitePointToFlat(sourceWhitePoint, XYZ_In, result) {
-     if (sourceWhitePoint[0] === 1 && sourceWhitePoint[2] === 1) {
-      result[0] = XYZ_In[0];
-      result[1] = XYZ_In[1];
-      result[2] = XYZ_In[2];
-      return;
-     }
-     var LMS = result;
-     matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
-     var LMS_Flat = tempNormalizeMatrix;
-     convertToFlat(sourceWhitePoint, LMS, LMS_Flat);
-     matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_Flat, result);
-    }
-    function normalizeWhitePointToD65(sourceWhitePoint, XYZ_In, result) {
-     var LMS = result;
-     matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
-     var LMS_D65 = tempNormalizeMatrix;
-     convertToD65(sourceWhitePoint, LMS, LMS_D65);
-     matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_D65, result);
-    }
-    function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
-     var A = adjustToRange(0, 1, src[srcOffset] * scale);
-     var B = adjustToRange(0, 1, src[srcOffset + 1] * scale);
-     var C = adjustToRange(0, 1, src[srcOffset + 2] * scale);
-     var AGR = Math.pow(A, cs.GR);
-     var BGG = Math.pow(B, cs.GG);
-     var CGB = Math.pow(C, cs.GB);
-     var X = cs.MXA * AGR + cs.MXB * BGG + cs.MXC * CGB;
-     var Y = cs.MYA * AGR + cs.MYB * BGG + cs.MYC * CGB;
-     var Z = cs.MZA * AGR + cs.MZB * BGG + cs.MZC * CGB;
-     var XYZ = tempConvertMatrix1;
-     XYZ[0] = X;
-     XYZ[1] = Y;
-     XYZ[2] = Z;
-     var XYZ_Flat = tempConvertMatrix2;
-     normalizeWhitePointToFlat(cs.whitePoint, XYZ, XYZ_Flat);