Merge m-c to fx-team, a=merge
authorWes Kocher <wkocher@mozilla.com>
Wed, 25 May 2016 15:39:27 -0700
changeset 338077 9ef45b3ae61d40b772319a314205ddacfe00cff9
parent 338076 94bc94b961768538296b30ef704f99fcfe9d5874 (current diff)
parent 338009 8d0aadfe7da782d415363880008b4ca027686137 (diff)
child 338078 73817edbdfd6f66e75b13eeb9a883994d04f178d
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone49.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 fx-team, a=merge
testing/marionette/emulator.js
testing/marionette/harness/marionette/b2g_update_test.py
testing/marionette/harness/marionette/runner/mixins/b2g.py
testing/marionette/harness/marionette/tests/unit/test_emulator.py
toolkit/mozapps/update/tests/chrome/test_0091_installed.xul
toolkit/mozapps/update/tests/unit_aus_update/uiOnlyAllowOneWindow.js
--- a/accessible/ipc/DocAccessibleParent.cpp
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -59,17 +59,31 @@ DocAccessibleParent::RecvShowEvent(const
   for (uint32_t i = 0; i < consumed; i++) {
     uint64_t id = aData.NewTree()[i].ID();
     MOZ_ASSERT(mAccessibles.GetEntry(id));
   }
 #endif
 
   MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
 
-  ProxyShowHideEvent(parent->ChildAt(newChildIdx), parent, true, aFromUser);
+  ProxyAccessible* target = parent->ChildAt(newChildIdx);
+  ProxyShowHideEvent(target, parent, true, aFromUser);
+
+  if (!nsCoreUtils::AccEventObserversExist()) {
+    return true;
+  }
+
+  uint32_t type = nsIAccessibleEvent::EVENT_SHOW;
+  xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(target);
+  xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
+  nsIDOMNode* node = nullptr;
+  RefPtr<xpcAccEvent> event = new xpcAccEvent(type, xpcAcc, doc, node,
+                                              aFromUser);
+  nsCoreUtils::DispatchAccEvent(Move(event));
+
   return true;
 }
 
 uint32_t
 DocAccessibleParent::AddSubtree(ProxyAccessible* aParent,
                                 const nsTArray<a11y::AccessibleData>& aNewTree,
                                 uint32_t aIdx, uint32_t aIdxInParent)
 {
@@ -136,21 +150,41 @@ DocAccessibleParent::RecvHideEvent(const
   ProxyAccessible* root = rootEntry->mProxy;
   if (!root) {
     NS_ERROR("invalid root being removed!");
     return true;
   }
 
   ProxyAccessible* parent = root->Parent();
   ProxyShowHideEvent(root, parent, false, aFromUser);
+
+  RefPtr<xpcAccHideEvent> event = nullptr;
+  if (nsCoreUtils::AccEventObserversExist()) {
+    uint32_t type = nsIAccessibleEvent::EVENT_HIDE;
+    xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(root);
+    xpcAccessibleGeneric* xpcParent = GetXPCAccessible(parent);
+    ProxyAccessible* next = root->NextSibling();
+    xpcAccessibleGeneric* xpcNext = next ? GetXPCAccessible(next) : nullptr;
+    ProxyAccessible* prev = root->PrevSibling();
+    xpcAccessibleGeneric* xpcPrev = prev ? GetXPCAccessible(prev) : nullptr;
+    xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
+    nsIDOMNode* node = nullptr;
+    event = new xpcAccHideEvent(type, xpcAcc, doc, node, aFromUser, xpcParent,
+                                xpcNext, xpcPrev);
+  }
+
   parent->RemoveChild(root);
   root->Shutdown();
 
   MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
 
+  if (event) {
+    nsCoreUtils::DispatchAccEvent(Move(event));
+  }
+
   return true;
 }
 
 bool
 DocAccessibleParent::RecvEvent(const uint64_t& aID, const uint32_t& aEventType)
 {
   ProxyAccessible* proxy = GetAccessible(aID);
   if (!proxy) {
--- a/accessible/tests/browser/browser.ini
+++ b/accessible/tests/browser/browser.ini
@@ -15,29 +15,25 @@ support-files =
 
 # Caching tests
 [browser_caching_name.js]
 skip-if = e10s
 
 # Events tests
 [browser_events_caretmove.js]
 [browser_events_hide.js]
-skip-if = e10s
 [browser_events_show.js]
-skip-if = e10s
 [browser_events_statechange.js]
 [browser_events_textchange.js]
 
 # Tree update tests
 [browser_treeupdate_ariadialog.js]
-skip-if = e10s
 [browser_treeupdate_ariaowns.js]
 skip-if = e10s
 [browser_treeupdate_canvas.js]
-skip-if = e10s
 [browser_treeupdate_cssoverflow.js]
 [browser_treeupdate_doc.js]
 skip-if = e10s
 [browser_treeupdate_gencontent.js]
 [browser_treeupdate_hidden.js]
 [browser_treeupdate_imagemap.js]
 skip-if = e10s
 [browser_treeupdate_list.js]
--- a/accessible/tests/browser/browser_events_hide.js
+++ b/accessible/tests/browser/browser_events_hide.js
@@ -10,23 +10,26 @@
  * Test hide event and its interface:
  *   - targetParent
  *   - targetNextSibling
  *   - targetPrevSibling
  */
 addAccessibleTask(`
   <div id="parent">
     <div id="previous"></div>
-    <div id="div"></div>
+    <div id="to-hide"></div>
     <div id="next"></div>
-  </div>`, function*(browser) {
-  let onHide = waitForEvent(EVENT_HIDE, 'div');
-  yield invokeSetStyle(browser, 'div', 'visibility', 'hidden');
-  let event = yield onHide;
-  let hideEvent = event.QueryInterface(Ci.nsIAccessibleHideEvent);
+  </div>`,
+  function*(browser, accDoc) {
+    let acc = findAccessibleChildByID(accDoc, 'to-hide');
+    let onHide = waitForEvent(EVENT_HIDE, acc);
+    yield invokeSetStyle(browser, 'to-hide', 'visibility', 'hidden');
+    let event = yield onHide;
+    let hideEvent = event.QueryInterface(Ci.nsIAccessibleHideEvent);
 
-  is(getAccessibleDOMNodeID(hideEvent.targetParent), 'parent',
-    'Correct target parent.');
-  is(getAccessibleDOMNodeID(hideEvent.targetNextSibling), 'next',
-    'Correct target next sibling.');
-  is(getAccessibleDOMNodeID(hideEvent.targetPrevSibling), 'previous',
-    'Correct target previous sibling.');
-});
+    is(getAccessibleDOMNodeID(hideEvent.targetParent), 'parent',
+      'Correct target parent.');
+    is(getAccessibleDOMNodeID(hideEvent.targetNextSibling), 'next',
+      'Correct target next sibling.');
+    is(getAccessibleDOMNodeID(hideEvent.targetPrevSibling), 'previous',
+      'Correct target previous sibling.');
+  }
+);
--- a/accessible/tests/browser/browser_treeupdate_doc.js
+++ b/accessible/tests/browser/browser_treeupdate_doc.js
@@ -28,203 +28,203 @@ addAccessibleTask(`
   /* ================= Initial tree check =================================== */
   let tree = {
     role: ROLE_DOCUMENT,
     children: [ ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Write iframe document ================================ */
-  let onReorder = waitForEvent(EVENT_REORDER, id);
+  let reorderEventPromise = waitForEvent(EVENT_REORDER, id);
   yield ContentTask.spawn(browser, id, id => {
     let docNode = content.document.getElementById('iframe').contentDocument;
     let newHTMLNode = docNode.createElement('html');
     let newBodyNode = docNode.createElement('body');
     let newTextNode = docNode.createTextNode('New Wave');
     newBodyNode.id = id;
     newBodyNode.appendChild(newTextNode);
     newHTMLNode.appendChild(newBodyNode);
     docNode.replaceChild(newHTMLNode, docNode.documentElement);
   });
-  yield onReorder;
+  yield reorderEventPromise;
 
   tree = {
     role: ROLE_DOCUMENT,
     children: [
       {
         role: ROLE_TEXT_LEAF,
         name: 'New Wave'
       }
     ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Replace iframe HTML element ========================== */
-  onReorder = waitForEvent(EVENT_REORDER, id);
+  reorderEventPromise = waitForEvent(EVENT_REORDER, id);
   yield ContentTask.spawn(browser, id, id => {
     let docNode = content.document.getElementById('iframe').contentDocument;
     // We can't use open/write/close outside of iframe document because of
     // security error.
     let script = docNode.createElement('script');
     script.textContent = `
       document.open();
       document.write('<body id="${id}">hello</body>');
       document.close();`;
     docNode.body.appendChild(script);
   });
-  yield onReorder;
+  yield reorderEventPromise;
 
   tree = {
     role: ROLE_DOCUMENT,
     children: [
       {
         role: ROLE_TEXT_LEAF,
         name: 'hello'
       }
     ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Replace iframe body ================================== */
-  onReorder = waitForEvent(EVENT_REORDER, id);
+  reorderEventPromise = waitForEvent(EVENT_REORDER, id);
   yield ContentTask.spawn(browser, id, id => {
     let docNode = content.document.getElementById('iframe').contentDocument;
     let newBodyNode = docNode.createElement('body');
     let newTextNode = docNode.createTextNode('New Hello');
     newBodyNode.id = id;
     newBodyNode.appendChild(newTextNode);
     newBodyNode.setAttribute('role', 'button');
     docNode.documentElement.replaceChild(newBodyNode, docNode.body);
   });
-  yield onReorder;
+  yield reorderEventPromise;
 
   tree = {
     role: ROLE_PUSHBUTTON,
     children: [
       {
         role: ROLE_TEXT_LEAF,
         name: 'New Hello'
       }
     ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Open iframe document ================================= */
-  onReorder = waitForEvent(EVENT_REORDER, id);
+  reorderEventPromise = waitForEvent(EVENT_REORDER, id);
   yield ContentTask.spawn(browser, id, id => {
     // Open document.
     let docNode = content.document.getElementById('iframe').contentDocument;
     let script = docNode.createElement('script');
     script.textContent = `
       function closeMe() {
         document.write('Works?');
         document.close();
       }
       window.closeMe = closeMe;
       document.open();
       document.write('<body id="${id}"></body>');`;
     docNode.body.appendChild(script);
   });
-  yield onReorder;
+  yield reorderEventPromise;
 
   tree = {
     role: ROLE_DOCUMENT,
     children: [ ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Close iframe document ================================ */
-  onReorder = waitForEvent(EVENT_REORDER, id);
+  reorderEventPromise = waitForEvent(EVENT_REORDER, id);
   yield ContentTask.spawn(browser, {}, () => {
     // Write and close document.
     let docNode = content.document.getElementById('iframe').contentDocument;
     docNode.write('Works?');
     docNode.close();
   });
-  yield onReorder;
+  yield reorderEventPromise;
 
   tree = {
     role: ROLE_DOCUMENT,
     children: [
       {
         role: ROLE_TEXT_LEAF,
         name: 'Works?'
       }
     ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Remove HTML from iframe document ===================== */
-  onReorder = waitForEvent(EVENT_REORDER);
+  reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
   yield ContentTask.spawn(browser, {}, () => {
     // Remove HTML element.
     let docNode = content.document.getElementById('iframe').contentDocument;
     docNode.removeChild(docNode.firstChild);
   });
-  let event = yield onReorder;
+  let event = yield reorderEventPromise;
 
   ok(event.accessible instanceof nsIAccessibleDocument,
     'Reorder should happen on the document');
   tree = {
     role: ROLE_DOCUMENT,
     children: [ ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Insert HTML to iframe document ======================= */
-  onReorder = waitForEvent(EVENT_REORDER, id);
+  reorderEventPromise = waitForEvent(EVENT_REORDER, id);
   yield ContentTask.spawn(browser, id, id => {
     // Insert HTML element.
     let docNode = content.document.getElementById('iframe').contentDocument;
     let html = docNode.createElement('html');
     let body = docNode.createElement('body');
     let text = docNode.createTextNode('Haha');
     body.appendChild(text);
     body.id = id;
     html.appendChild(body);
     docNode.appendChild(html);
   });
-  yield onReorder;
+  yield reorderEventPromise;
 
   tree = {
     role: ROLE_DOCUMENT,
     children: [
       {
         role: ROLE_TEXT_LEAF,
         name: 'Haha'
       }
     ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Remove body from iframe document ===================== */
-  onReorder = waitForEvent(EVENT_REORDER);
+  reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
   yield ContentTask.spawn(browser, {}, () => {
     // Remove body element.
     let docNode = content.document.getElementById('iframe').contentDocument;
     docNode.documentElement.removeChild(docNode.body);
   });
-  event = yield onReorder;
+  event = yield reorderEventPromise;
 
   ok(event.accessible instanceof nsIAccessibleDocument,
     'Reorder should happen on the document');
   tree = {
     role: ROLE_DOCUMENT,
     children: [ ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================ Insert element under document element while body missed */
-  onReorder = waitForEvent(EVENT_REORDER);
+  reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
   yield ContentTask.spawn(browser, {}, () => {
     let docNode = content.document.getElementById('iframe').contentDocument;
     let inputNode = content.window.inputNode = docNode.createElement('input');
     docNode.documentElement.appendChild(inputNode);
   });
-  event = yield onReorder;
+  event = yield reorderEventPromise;
 
   ok(event.accessible instanceof nsIAccessibleDocument,
     'Reorder should happen on the document');
   tree = {
     DOCUMENT: [
       { ENTRY: [ ] }
     ]
   };
@@ -232,68 +232,68 @@ addAccessibleTask(`
 
   yield ContentTask.spawn(browser, {}, () => {
     let docNode = content.document.getElementById('iframe').contentDocument;
     // Remove aftermath of this test before next test starts.
     docNode.documentElement.removeChild(content.window.inputNode);
   });
 
   /* ================= Insert body to iframe document ======================= */
-  onReorder = waitForEvent(EVENT_REORDER, id);
+  reorderEventPromise = waitForEvent(EVENT_REORDER, id);
   yield ContentTask.spawn(browser, id, id => {
     // Write and close document.
     let docNode = content.document.getElementById('iframe').contentDocument;
     // Insert body element.
     let body = docNode.createElement('body');
     let text = docNode.createTextNode('Yo ho ho i butylka roma!');
     body.appendChild(text);
     body.id = id;
     docNode.documentElement.appendChild(body);
   });
-  yield onReorder;
+  yield reorderEventPromise;
 
   tree = {
     role: ROLE_DOCUMENT,
     children: [
       {
         role: ROLE_TEXT_LEAF,
         name: 'Yo ho ho i butylka roma!'
       }
     ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Change source ======================================== */
-  onReorder = waitForEvent(EVENT_REORDER, 'iframe');
+  reorderEventPromise = waitForEvent(EVENT_REORDER, 'iframe');
   yield invokeSetAttribute(browser, 'iframe', 'src',
     `data:text/html,<html><body id="${id}"><input></body></html>`);
-  event = yield onReorder;
+  event = yield reorderEventPromise;
 
   tree = {
     INTERNAL_FRAME: [
       { DOCUMENT: [
         { ENTRY: [ ] }
       ] }
     ]
   };
   testAccessibleTree(event.accessible, tree);
   iframe = findAccessibleChildByID(event.accessible, id);
 
   /* ================= Replace iframe body on ARIA role body ================ */
-  onReorder = waitForEvent(EVENT_REORDER, id);
+  reorderEventPromise = waitForEvent(EVENT_REORDER, id);
   yield ContentTask.spawn(browser, id, id => {
     let docNode = content.document.getElementById('iframe').contentDocument;
     let newBodyNode = docNode.createElement('body');
     let newTextNode = docNode.createTextNode('New Hello');
     newBodyNode.appendChild(newTextNode);
     newBodyNode.setAttribute('role', 'button');
     newBodyNode.id = id;
     docNode.documentElement.replaceChild(newBodyNode, docNode.body);
   });
-  yield onReorder;
+  yield reorderEventPromise;
 
   tree = {
     role: ROLE_PUSHBUTTON,
     children: [
       {
         role: ROLE_TEXT_LEAF,
         name: 'New Hello'
       }
--- a/accessible/tests/browser/events.js
+++ b/accessible/tests/browser/events.js
@@ -37,38 +37,54 @@ function eventToString(event) {
     info += `, start: ${event.start}, length: ${event.length}, ${tcType} text: ${event.modifiedText}`;
   }
 
   info += `. Target: ${prettyName(event.accessible)}`;
   return info;
 }
 
 /**
- * A helper function that waits for an accessible event of certain type that
- * belongs to a certain DOMNode (defined by its id).
- * @param  {String}  id         expected content element id for the event
- * @param  {Number}  eventType  expected accessible event type
- * @return {Promise}            promise that resolves to an event
+ * A helper function that returns a promise that resolves when an accessible
+ * event of the given type with the given target (defined by its id or
+ * accessible) is observed.
+ * @param  {String|nsIAccessible}  expectedIdOrAcc  expected content element id
+ *                                                  for the event
+ * @param  {Number}                eventType        expected accessible event
+ *                                                  type
+ * @return {Promise}                                promise that resolves to an
+ *                                                  event
  */
-function waitForEvent(eventType, id) {
+function waitForEvent(eventType, expectedIdOrAcc) {
   return new Promise(resolve => {
     let eventObserver = {
       observe(subject, topic, data) {
         if (topic !== 'accessible-event') {
           return;
         }
 
         let event = subject.QueryInterface(nsIAccessibleEvent);
         Logger.log(eventToString(event));
 
-        let domID = getAccessibleDOMNodeID(event.accessible);
-        // If event's accessible does not match expected event type or DOMNode
-        // id, skip thie event.
-        if (domID === id && event.eventType === eventType) {
-          Logger.log(`Correct event DOMNode id: ${id}`);
+        // If event type does not match expected type, skip the event.
+        if (event.eventType !== eventType) {
+          return;
+        }
+
+        let acc = event.accessible;
+        let id = getAccessibleDOMNodeID(acc);
+        let isID = typeof expectedIdOrAcc === 'string';
+        let actualIdOrAcc = isID ? id : acc;
+        // If event's accessible does not match expected DOMNode id or
+        // accessible, skip the event.
+        if (actualIdOrAcc === expectedIdOrAcc) {
+          if (isID) {
+            Logger.log(`Correct event DOMNode id: ${id}`);
+          } else {
+            Logger.log(`Correct event accessible: ${prettyName(acc)}`);
+          }
           Logger.log(`Correct event type: ${eventTypeToString(eventType)}`);
           ok(event.accessibleDocument instanceof nsIAccessibleDocument,
             'Accessible document present.');
 
           Services.obs.removeObserver(this, 'accessible-event');
           resolve(event);
         }
       }
--- a/addon-sdk/source/test/jetpack-package.ini
+++ b/addon-sdk/source/test/jetpack-package.ini
@@ -32,16 +32,17 @@ support-files =
 [test-base64.js]
 [test-bootstrap.js]
 [test-browser-events.js]
 [test-buffer.js]
 [test-byte-streams.js]
 [test-child_process.js]
 [test-chrome.js]
 [test-clipboard.js]
+subsuite = clipboard
 [test-collection.js]
 [test-commonjs-test-adapter.js]
 [test-content-events.js]
 [test-content-script.js]
 [test-content-sync-worker.js]
 [test-content-worker.js]
 [test-context-menu.js]
 [test-context-menu@2.js]
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -144,23 +144,16 @@ pref("app.update.url", "https://aus5.moz
 //pref("app.update.url.override", "");
 
 // app.update.interval is in branding section
 // app.update.promptWaitTime is in branding section
 
 // Show the Update Checking/Ready UI when the user was idle for x seconds
 pref("app.update.idletime", 60);
 
-// Whether or not we show a dialog box informing the user that the update was
-// successfully applied. This is off in Firefox by default since we show a
-// upgrade start page instead! Other apps may wish to show this UI, and supply
-// a whatsNewURL field in their brand.properties that contains a link to a page
-// which tells users what's new in this new update.
-pref("app.update.showInstalledUI", false);
-
 // Whether or not to attempt using the service for updates.
 #ifdef MOZ_MAINTENANCE_SERVICE
 pref("app.update.service.enabled", true);
 #endif
 
 // Symmetric (can be overridden by individual extensions) update preferences.
 // e.g.
 //  extensions.{GUID}.update.enabled
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -154,16 +154,17 @@ tags = audiochannel
 skip-if = os == "mac" # The Fitt's Law back button is not supported on OS X
 [browser_beforeunload_duplicate_dialogs.js]
 [browser_blob-channelname.js]
 [browser_bookmark_popup.js]
 skip-if = (os == "linux" && debug) # mouseover not reliable on linux debug builds
 [browser_bookmark_titles.js]
 skip-if = buildapp == 'mulet' || toolkit == "windows" # Disabled on Windows due to frequent failures (bugs 825739, 841341)
 [browser_bug321000.js]
+subsuite = clipboard
 skip-if = true # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
 [browser_bug356571.js]
 [browser_bug380960.js]
 [browser_bug386835.js]
 [browser_bug406216.js]
 [browser_bug408415.js]
 [browser_bug409481.js]
 [browser_bug409624.js]
@@ -198,31 +199,33 @@ skip-if = buildapp == 'mulet'
 [browser_bug495058.js]
 [browser_bug517902.js]
 skip-if = (os == 'linux' && e10s) # bug 1161699
 [browser_bug519216.js]
 [browser_bug520538.js]
 [browser_bug521216.js]
 [browser_bug533232.js]
 [browser_bug537013.js]
+subsuite = clipboard
 skip-if = buildapp == 'mulet' || e10s # Bug 1134458 - Find bar doesn't work correctly in a detached tab
 [browser_bug537474.js]
 [browser_bug550565.js]
 [browser_bug553455.js]
 skip-if = buildapp == 'mulet' # Bug 1066070 - I don't think either popup notifications nor addon install stuff works on mulet?
 [browser_bug555224.js]
 [browser_bug555767.js]
 [browser_bug559991.js]
 [browser_bug561636.js]
 skip-if = os == 'win' # bug 1057615
 [browser_bug563588.js]
 [browser_bug565575.js]
 [browser_bug565667.js]
 skip-if = toolkit != "cocoa"
 [browser_bug567306.js]
+subsuite = clipboard
 [browser_bug575561.js]
 [browser_bug575830.js]
 [browser_bug577121.js]
 [browser_bug578534.js]
 [browser_bug579872.js]
 [browser_bug580638.js]
 [browser_bug580956.js]
 [browser_bug581242.js]
@@ -274,16 +277,17 @@ tags = mcb
 [browser_mixedContentFramesOnHttp.js]
 tags = mcb
 [browser_bug970746.js]
 [browser_bug1015721.js]
 skip-if = os == 'win'
 [browser_bug1064280_changeUrlInPinnedTab.js]
 [browser_accesskeys.js]
 [browser_clipboard.js]
+subsuite = clipboard
 [browser_clipboard_pastefile.js]
 [browser_contentAreaClick.js]
 [browser_contextmenu.js]
 tags = fullscreen
 skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
 [browser_contextmenu_input.js]
 skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
 [browser_ctrlTab.js]
@@ -327,16 +331,17 @@ skip-if = buildapp == 'mulet'
 [browser_keywordBookmarklets.js]
 [browser_keywordSearch.js]
 [browser_keywordSearch_postData.js]
 [browser_lastAccessedTab.js]
 skip-if = toolkit == "windows" # Disabled on Windows due to frequent failures (bug 969405)
 [browser_menuButtonFitts.js]
 skip-if = os != "win" # The Fitts Law menu button is only supported on Windows (bug 969376)
 [browser_middleMouse_noJSPaste.js]
+subsuite = clipboard
 [browser_minimize.js]
 [browser_misused_characters_in_strings.js]
 [browser_mixedcontent_securityflags.js]
 tags = mcb
 [browser_offlineQuotaNotification.js]
 skip-if = buildapp == 'mulet'
 [browser_feed_discovery.js]
 support-files = feed_discovery.html
--- a/browser/base/content/test/urlbar/browser.ini
+++ b/browser/base/content/test/urlbar/browser.ini
@@ -19,35 +19,38 @@ skip-if = (os == "linux" || os == "mac")
 [browser_bug1104165-switchtab-decodeuri.js]
 [browser_bug1003461-switchtab-override.js]
 [browser_bug1024133-switchtab-override-keynav.js]
 [browser_bug1025195_switchToTabHavingURI_aOpenParams.js]
 [browser_bug1070778.js]
 [browser_bug1225194-remotetab.js]
 [browser_bug304198.js]
 [browser_bug556061.js]
+subsuite = clipboard
 [browser_bug562649.js]
 [browser_bug623155.js]
 support-files =
   redirect_bug623155.sjs
 [browser_bug783614.js]
 [browser_canonizeURL.js]
 [browser_locationBarCommand.js]
 skip-if = os == "linux" # Linux: Intermittent failures, bug 917535
 [browser_locationBarExternalLoad.js]
 [browser_moz_action_link.js]
 [browser_removeUnsafeProtocolsFromURLBarPaste.js]
+subsuite = clipboard
 [browser_search_favicon.js]
 [browser_tabMatchesInAwesomebar.js]
 support-files =
   moz.png
 [browser_tabMatchesInAwesomebar_perwindowpb.js]
 skip-if = os == 'linux' # Bug 1104755
 [browser_urlbarAutoFillTrimURLs.js]
 [browser_urlbarCopying.js]
+subsuite = clipboard
 support-files =
   authenticate.sjs
 [browser_urlbarDecode.js]
 [browser_urlbarDelete.js]
 [browser_urlbarEnter.js]
 [browser_urlbarEnterAfterMouseOver.js]
 skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
 [browser_urlbarHashChangeProxyState.js]
@@ -64,26 +67,28 @@ support-files =
   searchSuggestionEngine.xml
   searchSuggestionEngine.sjs
 [browser_urlbarSearchTelemetry.js]
 support-files =
   searchSuggestionEngine.xml
   searchSuggestionEngine.sjs
 [browser_urlbarStop.js]
 [browser_urlbarTrimURLs.js]
+subsuite = clipboard
 [browser_urlbarUpdateForDomainCompletion.js]
 [browser_urlbar_autoFill_backspaced.js]
 [browser_urlbar_blanking.js]
 support-files =
   file_blank_but_not_blank.html
 [browser_urlbar_locationchange_urlbar_edit_dos.js]
 support-files =
   file_urlbar_edit_dos.html
 [browser_urlbar_searchsettings.js]
 [browser_urlbar_stop_pending.js]
 support-files =
   slow-page.sjs
 [browser_urlbar_remoteness_switch.js]
 run-if = e10s
 [browser_urlHighlight.js]
 [browser_wyciwyg_urlbarCopying.js]
+subsuite = clipboard
 support-files =
   test_wyciwyg_copying.html
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -61,28 +61,31 @@ skip-if = os == "mac"
 [browser_941083_invalidate_wrapper_cache_createWidget.js]
 [browser_942581_unregisterArea_keeps_placements.js]
 [browser_943683_migration_test.js]
 [browser_944887_destroyWidget_should_destroy_in_palette.js]
 [browser_945739_showInPrivateBrowsing_customize_mode.js]
 [browser_947914_button_addons.js]
 skip-if = os == "linux" # Intermittent failures
 [browser_947914_button_copy.js]
+subsuite = clipboard
 skip-if = os == "linux" # Intermittent failures on Linux
 [browser_947914_button_cut.js]
+subsuite = clipboard
 skip-if = os == "linux" # Intermittent failures on Linux
 [browser_947914_button_find.js]
 skip-if = os == "linux" # Intermittent failures
 [browser_947914_button_history.js]
 skip-if = os == "linux" # Intermittent failures
 [browser_947914_button_newPrivateWindow.js]
 skip-if = os == "linux" # Intermittent failures
 [browser_947914_button_newWindow.js]
 skip-if = os == "linux" # Intermittent failures
 [browser_947914_button_paste.js]
+subsuite = clipboard
 skip-if = os == "linux" # Intermittent failures on Linux
 [browser_947914_button_print.js]
 skip-if = os == "linux" # Intermittent failures on Linux
 [browser_947914_button_savePage.js]
 skip-if = os == "linux" # Intermittent failures
 [browser_947914_button_zoomIn.js]
 skip-if = os == "linux" # Intermittent failures
 [browser_947914_button_zoomOut.js]
--- a/browser/components/extensions/test/browser/browser_ext_history.js
+++ b/browser/components/extensions/test/browser/browser_ext_history.js
@@ -104,38 +104,40 @@ add_task(function* test_delete() {
 });
 
 add_task(function* test_search() {
   const SINGLE_VISIT_URL = "http://example.com/";
   const DOUBLE_VISIT_URL = "http://example.com/2/";
   const MOZILLA_VISIT_URL = "http://mozilla.com/";
 
   function background() {
+    const futureTime = Date.now() + 24 * 60 * 60 * 1000;
+
     browser.test.onMessage.addListener(msg => {
       browser.history.search({text: ""}).then(results => {
         browser.test.sendMessage("empty-search", results);
         return browser.history.search({text: "mozilla.com"});
       }).then(results => {
         browser.test.sendMessage("text-search", results);
         return browser.history.search({text: "example.com", maxResults: 1});
       }).then(results => {
         browser.test.sendMessage("max-results-search", results);
-        return browser.history.search({text: "", startTime: Date.now()});
+        return browser.history.search({text: "", startTime: futureTime});
       }).then(results => {
         browser.test.assertEq(0, results.length, "no results returned for late start time");
         return browser.history.search({text: "", endTime: 0});
       }).then(results => {
         browser.test.assertEq(0, results.length, "no results returned for early end time");
         return browser.history.search({text: "", startTime: Date.now(), endTime: 0});
       }).then(results => {
         browser.test.fail("history.search rejects with startTime that is after the endTime");
       }, error => {
         browser.test.assertEq(
+          "The startTime cannot be after the endTime",
           error.message,
-          "The startTime cannot be after the endTime",
           "history.search rejects with startTime that is after the endTime");
       }).then(() => {
         browser.test.notifyPass("search");
       });
     });
 
     browser.test.sendMessage("ready");
   }
--- a/browser/components/places/tests/browser/browser.ini
+++ b/browser/components/places/tests/browser/browser.ini
@@ -9,20 +9,23 @@ support-files =
   framedPage.html
   frameLeft.html
   frameRight.html
   sidebarpanels_click_test_page.html
   keyword_form.html
 
 [browser_0_library_left_pane_migration.js]
 [browser_410196_paste_into_tags.js]
+subsuite = clipboard
 [browser_416459_cut.js]
+subsuite = clipboard
 [browser_423515.js]
 [browser_425884.js]
 [browser_435851_copy_query.js]
+subsuite = clipboard
 [browser_475045.js]
 [browser_555547.js]
 [browser_bookmarklet_windowOpen.js]
 support-files =
   pageopeningwindow.html
 [browser_bookmarkProperties_addFolderDefaultButton.js]
 [browser_bookmarkProperties_addKeywordForThisSearch.js]
 [browser_bookmarkProperties_addLivemark.js]
--- a/browser/modules/ContentLinkHandler.jsm
+++ b/browser/modules/ContentLinkHandler.jsm
@@ -160,51 +160,16 @@ this.ContentLinkHandler = {
           break;
       }
     }
   },
 
   getLinkIconURI: function(aLink) {
     let targetDoc = aLink.ownerDocument;
     var uri = BrowserUtils.makeURI(aLink.href, targetDoc.characterSet);
-
-    // Verify that the load of this icon is legal.
-    // Some error or special pages can load their favicon.
-    // To be on the safe side, only allow chrome:// favicons.
-    var isAllowedPage = [
-      /^about:neterror\?/,
-      /^about:blocked\?/,
-      /^about:certerror\?/,
-      /^about:home$/,
-    ].some(re => re.test(targetDoc.documentURI));
-
-    if (!isAllowedPage || !uri.schemeIs("chrome")) {
-      var ssm = Services.scriptSecurityManager;
-      try {
-        ssm.checkLoadURIWithPrincipal(targetDoc.nodePrincipal, uri,
-                                      Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
-      } catch(e) {
-        return null;
-      }
-    }
-
-    try {
-      var contentPolicy = Cc["@mozilla.org/layout/content-policy;1"].
-                          getService(Ci.nsIContentPolicy);
-    } catch(e) {
-      return null; // Refuse to load if we can't do a security check.
-    }
-
-    // Security says okay, now ask content policy
-    if (contentPolicy.shouldLoad(Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE,
-                                 uri, targetDoc.documentURIObject,
-                                 aLink, aLink.type, null)
-                                 != Ci.nsIContentPolicy.ACCEPT)
-      return null;
-
     try {
       uri.userPass = "";
     } catch(e) {
       // some URIs are immutable
     }
     return uri;
   },
 };
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -448,23 +448,23 @@ class Automation(object):
           self.dumpScreen(utilityPath)
 
         (line, didTimeout) = self.readWithTimeout(logsource, timeout)
 
         if not hitMaxTime and maxTime and datetime.now() - startTime > timedelta(seconds = maxTime):
           # Kill the application.
           hitMaxTime = True
           self.log.info("TEST-UNEXPECTED-FAIL | %s | application ran for longer than allowed maximum time of %d seconds", self.lastTestSeen, int(maxTime))
-          self.log.warning("Force-terminating active process(es).");
+          self.log.error("Force-terminating active process(es).");
           self.killAndGetStack(proc.pid, utilityPath, debuggerInfo)
       if didTimeout:
         if line:
           self.log.info(line.rstrip().decode("UTF-8", "ignore"))
         self.log.info("TEST-UNEXPECTED-FAIL | %s | application timed out after %d seconds with no output", self.lastTestSeen, int(timeout))
-        self.log.warning("Force-terminating active process(es).");
+        self.log.error("Force-terminating active process(es).");
         if browserProcessId == -1:
           browserProcessId = proc.pid
         self.killAndGetStack(browserProcessId, utilityPath, debuggerInfo)
 
     status = proc.wait()
     printstatus("Main app process", status)
     if status == 0:
       self.lastTestSeen = "Main app process exited normally"
--- a/devtools/client/commandline/test/browser.ini
+++ b/devtools/client/commandline/test/browser.ini
@@ -78,16 +78,17 @@ support-files =
 [browser_cmd_paintflashing.js]
 [browser_cmd_pref1.js]
 [browser_cmd_pref2.js]
 [browser_cmd_pref3.js]
 [browser_cmd_qsa.js]
 [browser_cmd_restart.js]
 [browser_cmd_rulers.js]
 [browser_cmd_screenshot.js]
+subsuite = clipboard
 support-files =
   browser_cmd_screenshot.html
 [browser_cmd_settings.js]
 [browser_gcli_async.js]
 [browser_gcli_canon.js]
 [browser_gcli_cli1.js]
 [browser_gcli_cli2.js]
 [browser_gcli_completion1.js]
--- a/devtools/client/debugger/test/mochitest/browser.ini
+++ b/devtools/client/debugger/test/mochitest/browser.ini
@@ -453,23 +453,25 @@ skip-if = e10s && debug
 [browser_dbg_source-maps-02.js]
 skip-if = e10s && debug
 [browser_dbg_source-maps-03.js]
 skip-if = e10s && debug
 [browser_dbg_source-maps-04.js]
 skip-if = e10s # Bug 1093535
 [browser_dbg_sources-cache.js]
 [browser_dbg_sources-contextmenu-01.js]
+subsuite = clipboard
 [browser_dbg_sources-contextmenu-02.js]
 skip-if = e10s && debug
 [browser_dbg_sources-eval-01.js]
 skip-if = true # non-named eval sources turned off for now, bug 1124106
 [browser_dbg_sources-eval-02.js]
 [browser_dbg_sources-iframe-reload.js]
 [browser_dbg_sources-keybindings.js]
+subsuite = clipboard
 skip-if = e10s && debug
 [browser_dbg_sources-labels.js]
 skip-if = e10s && debug
 [browser_dbg_sources-large.js]
 [browser_dbg_sources-sorting.js]
 skip-if = e10s && debug
 [browser_dbg_sources-bookmarklet.js]
 skip-if = e10s && debug
@@ -488,16 +490,17 @@ skip-if = e10s && debug
 skip-if = e10s && (debug || asan) # timeouts
 [browser_dbg_stack-06.js]
 skip-if = e10s && debug
 [browser_dbg_stack-07.js]
 skip-if = e10s && debug
 [browser_dbg_stack-contextmenu-01.js]
 skip-if = e10s && debug
 [browser_dbg_stack-contextmenu-02.js]
+subsuite = clipboard
 skip-if = e10s && debug
 [browser_dbg_step-out.js]
 skip-if = e10s && debug
 [browser_dbg_tabactor-01.js]
 skip-if = e10s # TODO
 [browser_dbg_tabactor-02.js]
 skip-if = e10s # TODO
 [browser_dbg_terminate-on-tab-close.js]
@@ -510,16 +513,17 @@ skip-if = e10s && debug
 skip-if = e10s && debug
 [browser_dbg_variables-view-04.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-05.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-06.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-accessibility.js]
+subsuite = clipboard
 skip-if = e10s && debug
 [browser_dbg_variables-view-data.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-edit-cancel.js]
 skip-if = e10s && debug
 [browser_dbg_variables-view-edit-click.js]
 skip-if = e10s || (os == 'mac' || os == 'win') && (debug == false) # Bug 986166
 [browser_dbg_variables-view-edit-getset-01.js]
--- a/devtools/client/eyedropper/test/browser.ini
+++ b/devtools/client/eyedropper/test/browser.ini
@@ -1,11 +1,11 @@
 [DEFAULT]
 tags = devtools
-subsuite = devtools
+subsuite = clipboard
 support-files =
   color-block.html
   head.js
   !/devtools/client/commandline/test/helpers.js
   !/devtools/client/framework/test/shared-head.js
 
 [browser_eyedropper_basic.js]
 skip-if = os == "win" && debug # bug 963492
--- a/devtools/client/inspector/computed/test/browser.ini
+++ b/devtools/client/inspector/computed/test/browser.ini
@@ -27,11 +27,13 @@ support-files =
 [browser_computed_media-queries.js]
 [browser_computed_no-results-placeholder.js]
 [browser_computed_original-source-link.js]
 [browser_computed_pseudo-element_01.js]
 [browser_computed_refresh-on-style-change_01.js]
 [browser_computed_search-filter.js]
 [browser_computed_search-filter_clear.js]
 [browser_computed_search-filter_context-menu.js]
+subsuite = clipboard
 [browser_computed_search-filter_escape-keypress.js]
 [browser_computed_select-and-copy-styles.js]
+subsuite = clipboard
 [browser_computed_style-editor-link.js]
--- a/devtools/client/inspector/markup/test/browser.ini
+++ b/devtools/client/inspector/markup/test/browser.ini
@@ -56,16 +56,17 @@ skip-if = os == "mac" # Full keyboard na
 skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
 [browser_markup_accessibility_semantics.js]
 [browser_markup_anonymous_01.js]
 [browser_markup_anonymous_02.js]
 skip-if = e10s # scratchpad.xul is not loading in e10s window
 [browser_markup_anonymous_03.js]
 [browser_markup_anonymous_04.js]
 [browser_markup_copy_image_data.js]
+subsuite = clipboard
 [browser_markup_css_completion_style_attribute_01.js]
 [browser_markup_css_completion_style_attribute_02.js]
 [browser_markup_dragdrop_autoscroll.js]
 [browser_markup_dragdrop_distance.js]
 [browser_markup_dragdrop_draggable.js]
 [browser_markup_dragdrop_dragRootNode.js]
 [browser_markup_dragdrop_escapeKeyPress.js]
 [browser_markup_dragdrop_invalidNodes.js]
@@ -85,16 +86,17 @@ skip-if = e10s # scratchpad.xul is not l
 [browser_markup_events_jquery_1.11.1.js]
 [browser_markup_events_jquery_2.1.1.js]
 [browser_markup_events-overflow.js]
 skip-if = true # Bug 1177550
 [browser_markup_links_01.js]
 [browser_markup_links_02.js]
 [browser_markup_links_03.js]
 [browser_markup_links_04.js]
+subsuite = clipboard
 [browser_markup_links_05.js]
 [browser_markup_links_06.js]
 [browser_markup_links_07.js]
 [browser_markup_load_01.js]
 [browser_markup_html_edit_01.js]
 [browser_markup_html_edit_02.js]
 [browser_markup_html_edit_03.js]
 [browser_markup_image_tooltip.js]
--- a/devtools/client/inspector/rules/test/browser.ini
+++ b/devtools/client/inspector/rules/test/browser.ini
@@ -81,16 +81,17 @@ support-files =
 [browser_rules_completion-popup-hidden-after-navigation.js]
 [browser_rules_content_01.js]
 [browser_rules_content_02.js]
 skip-if = e10s && debug # Bug 1250058 - Docshell leak on debug e10s
 [browser_rules_context-menu-show-mdn-docs-01.js]
 [browser_rules_context-menu-show-mdn-docs-02.js]
 [browser_rules_context-menu-show-mdn-docs-03.js]
 [browser_rules_copy_styles.js]
+subsuite = clipboard
 [browser_rules_cssom.js]
 [browser_rules_cubicbezier-appears-on-swatch-click.js]
 [browser_rules_cubicbezier-commit-on-ENTER.js]
 [browser_rules_cubicbezier-revert-on-ESC.js]
 [browser_rules_custom.js]
 [browser_rules_cycle-angle.js]
 [browser_rules_cycle-color.js]
 [browser_rules_edit-property-cancel.js]
@@ -178,18 +179,20 @@ skip-if = (os == "win" && debug) # bug 9
 [browser_rules_search-filter_04.js]
 [browser_rules_search-filter_05.js]
 [browser_rules_search-filter_06.js]
 [browser_rules_search-filter_07.js]
 [browser_rules_search-filter_08.js]
 [browser_rules_search-filter_09.js]
 [browser_rules_search-filter_10.js]
 [browser_rules_search-filter_context-menu.js]
+subsuite = clipboard
 [browser_rules_search-filter_escape-keypress.js]
 [browser_rules_select-and-copy-styles.js]
+subsuite = clipboard
 [browser_rules_selector-highlighter_01.js]
 [browser_rules_selector-highlighter_02.js]
 [browser_rules_selector-highlighter_03.js]
 [browser_rules_selector_highlight.js]
 [browser_rules_strict-search-filter-computed-list_01.js]
 [browser_rules_strict-search-filter_01.js]
 [browser_rules_strict-search-filter_02.js]
 [browser_rules_strict-search-filter_03.js]
--- a/devtools/client/inspector/shared/test/browser.ini
+++ b/devtools/client/inspector/shared/test/browser.ini
@@ -15,17 +15,19 @@ support-files =
   !/devtools/client/commandline/test/helpers.js
   !/devtools/client/inspector/test/head.js
   !/devtools/client/framework/test/shared-head.js
   !/devtools/client/shared/test/test-actor.js
   !/devtools/client/shared/test/test-actor-registry.js
 
 [browser_styleinspector_context-menu-copy-color_01.js]
 [browser_styleinspector_context-menu-copy-color_02.js]
+subsuite = clipboard
 [browser_styleinspector_context-menu-copy-urls.js]
+subsuite = clipboard
 [browser_styleinspector_csslogic-content-stylesheets.js]
 skip-if = e10s && debug # Bug 1250058 (docshell leak when opening 2 toolboxes)
 [browser_styleinspector_output-parser.js]
 [browser_styleinspector_refresh_when_active.js]
 [browser_styleinspector_tooltip-background-image.js]
 [browser_styleinspector_tooltip-closes-on-new-selection.js]
 skip-if = e10s # Bug 1111546 (e10s)
 [browser_styleinspector_tooltip-longhand-fontfamily.js]
--- a/devtools/client/inspector/test/browser.ini
+++ b/devtools/client/inspector/test/browser.ini
@@ -91,20 +91,24 @@ skip-if = os == "mac" # Full keyboard na
 [browser_inspector_highlighter-zoom.js]
 [browser_inspector_iframe-navigation.js]
 [browser_inspector_infobar_01.js]
 [browser_inspector_initialization.js]
 skip-if = (e10s && debug) # Bug 1250058 - Docshell leak on debug e10s
 [browser_inspector_inspect-object-element.js]
 [browser_inspector_invalidate.js]
 [browser_inspector_keyboard-shortcuts-copy-outerhtml.js]
+subsuite = clipboard
 [browser_inspector_keyboard-shortcuts.js]
 [browser_inspector_menu-01-sensitivity.js]
+subsuite = clipboard
 [browser_inspector_menu-02-copy-items.js]
+subsuite = clipboard
 [browser_inspector_menu-03-paste-items.js]
+subsuite = clipboard
 [browser_inspector_menu-04-use-in-console.js]
 [browser_inspector_menu-05-attribute-items.js]
 [browser_inspector_menu-06-other.js]
 [browser_inspector_navigation.js]
 [browser_inspector_pane-toggle-01.js]
 [browser_inspector_pane-toggle-02.js]
 [browser_inspector_pane-toggle-03.js]
 [browser_inspector_pane-toggle-04.js]
--- a/devtools/client/jsonview/test/browser.ini
+++ b/devtools/client/jsonview/test/browser.ini
@@ -12,14 +12,17 @@ support-files =
   simple_json.json^headers^
   valid_json.json
   valid_json.json^headers^
   !/devtools/client/commandline/test/head.js
   !/devtools/client/framework/test/head.js
   !/devtools/client/framework/test/shared-head.js
 
 [browser_jsonview_copy_headers.js]
+subsuite = clipboard
 [browser_jsonview_copy_json.js]
+subsuite = clipboard
 [browser_jsonview_copy_rawdata.js]
+subsuite = clipboard
 [browser_jsonview_filter.js]
 [browser_jsonview_invalid_json.js]
 [browser_jsonview_valid_json.js]
 [browser_jsonview_save_json.js]
--- a/devtools/client/netmonitor/har/test/browser.ini
+++ b/devtools/client/netmonitor/har/test/browser.ini
@@ -1,11 +1,11 @@
 [DEFAULT]
 tags = devtools
-subsuite = devtools
+subsuite = clipboard
 support-files =
   head.js
   html_har_post-data-test-page.html
   !/devtools/client/netmonitor/test/head.js
   !/devtools/client/netmonitor/test/html_simple-test-page.html
 
 [browser_net_har_copy_all_as_har.js]
 [browser_net_har_post_data.js]
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -54,22 +54,29 @@ skip-if = (toolkit == "cocoa" && e10s) #
 [browser_net_charts-05.js]
 [browser_net_charts-06.js]
 [browser_net_charts-07.js]
 [browser_net_clear.js]
 [browser_net_complex-params.js]
 [browser_net_content-type.js]
 [browser_net_curl-utils.js]
 [browser_net_copy_image_as_data_uri.js]
+subsuite = clipboard
 [browser_net_copy_svg_image_as_data_uri.js]
+subsuite = clipboard
 [browser_net_copy_url.js]
+subsuite = clipboard
 [browser_net_copy_params.js]
+subsuite = clipboard
 [browser_net_copy_response.js]
+subsuite = clipboard
 [browser_net_copy_headers.js]
+subsuite = clipboard
 [browser_net_copy_as_curl.js]
+subsuite = clipboard
 skip-if = e10s # Bug 1091596
 [browser_net_cyrillic-01.js]
 [browser_net_cyrillic-02.js]
 [browser_net_details-no-duplicated-content.js]
 skip-if = (os == 'linux' && e10s && debug) # Bug 1242204
 [browser_net_filter-01.js]
 [browser_net_filter-02.js]
 [browser_net_filter-03.js]
--- a/devtools/client/webconsole/test/browser.ini
+++ b/devtools/client/webconsole/test/browser.ini
@@ -144,33 +144,36 @@ support-files =
   !/devtools/client/framework/test/shared-head.js
   !/devtools/client/netmonitor/test/sjs_cors-test-server.sjs
   !/image/test/mochitest/blue.png
 
 [browser_bug1045902_console_csp_ignore_reflected_xss_message.js]
 skip-if = (e10s && debug) || (e10s && os == 'win') # Bug 1221499 enabled these on windows
 [browser_bug664688_sandbox_update_after_navigation.js]
 [browser_bug_638949_copy_link_location.js]
+subsuite = clipboard
 [browser_bug_862916_console_dir_and_filter_off.js]
 skip-if = (e10s && (os == 'win' || os == 'mac')) # Bug 1243976
 [browser_bug_865288_repeat_different_objects.js]
 [browser_bug_865871_variables_view_close_on_esc_key.js]
 [browser_bug_869003_inspect_cross_domain_object.js]
 [browser_bug_871156_ctrlw_close_tab.js]
 [browser_cached_messages.js]
 [browser_console.js]
 [browser_console_addonsdk_loader_exception.js]
 [browser_console_clear_method.js]
 [browser_console_clear_on_reload.js]
 [browser_console_click_focus.js]
 [browser_console_consolejsm_output.js]
 [browser_console_copy_command.js]
+subsuite = clipboard
 [browser_console_dead_objects.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_console_copy_entire_message_context_menu.js]
+subsuite = clipboard
 [browser_console_error_source_click.js]
 [browser_console_filters.js]
 [browser_console_iframe_messages.js]
 [browser_console_keyboard_accessibility.js]
 [browser_console_log_inspectable_object.js]
 [browser_console_native_getters.js]
 [browser_console_navigation_marker.js]
 [browser_console_netlogging.js]
@@ -210,16 +213,17 @@ tags = mcb
 [browser_webconsole_bug_582201_duplicate_errors.js]
 [browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js]
 [browser_webconsole_bug_585237_line_limit.js]
 [browser_webconsole_bug_585956_console_trace.js]
 [browser_webconsole_bug_585991_autocomplete_keys.js]
 [browser_webconsole_bug_585991_autocomplete_popup.js]
 [browser_webconsole_bug_586388_select_all.js]
 [browser_webconsole_bug_587617_output_copy.js]
+subsuite = clipboard
 [browser_webconsole_bug_588342_document_focus.js]
 [browser_webconsole_bug_588730_text_node_insertion.js]
 [browser_webconsole_bug_588967_input_expansion.js]
 [browser_webconsole_bug_589162_css_filter.js]
 [browser_webconsole_bug_592442_closing_brackets.js]
 [browser_webconsole_bug_593003_iframe_wrong_hud.js]
 [browser_webconsole_bug_594497_history_arrow_keys.js]
 [browser_webconsole_bug_595223_file_uri.js]
@@ -236,31 +240,33 @@ skip-if = e10s # Bug 1042253 - webconsol
 [browser_webconsole_bug_600183_charset.js]
 [browser_webconsole_bug_601177_log_levels.js]
 [browser_webconsole_bug_601352_scroll.js]
 [browser_webconsole_bug_601667_filter_buttons.js]
 [browser_webconsole_bug_603750_websocket.js]
 [browser_webconsole_bug_611795.js]
 [browser_webconsole_bug_613013_console_api_iframe.js]
 [browser_webconsole_bug_613280_jsterm_copy.js]
+subsuite = clipboard
 [browser_webconsole_bug_613642_maintain_scroll.js]
 [browser_webconsole_bug_613642_prune_scroll.js]
 [browser_webconsole_bug_614793_jsterm_scroll.js]
 [browser_webconsole_bug_618078_network_exceptions.js]
 [browser_webconsole_bug_621644_jsterm_dollar.js]
 [browser_webconsole_bug_622303_persistent_filters.js]
 [browser_webconsole_bug_623749_ctrl_a_select_all_winnt.js]
 skip-if = os != "win"
 [browser_webconsole_bug_630733_response_redirect_headers.js]
 [browser_webconsole_bug_632275_getters_document_width.js]
 [browser_webconsole_bug_632347_iterators_generators.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_632817.js]
 [browser_webconsole_bug_642108_pruneTest.js]
 [browser_webconsole_autocomplete_and_selfxss.js]
+subsuite = clipboard
 [browser_webconsole_bug_644419_log_limits.js]
 [browser_webconsole_bug_646025_console_file_location.js]
 [browser_webconsole_bug_651501_document_body_autocomplete.js]
 [browser_webconsole_bug_653531_highlighter_console_helper.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_658368_time_methods.js]
 [browser_webconsole_bug_659907_console_dir.js]
 [browser_webconsole_bug_660806_history_nav.js]
@@ -323,16 +329,17 @@ skip-if = e10s # Bug 1042253 - webconsol
 [browser_webconsole_netlogging.js]
 [browser_webconsole_netlogging_basic.js]
 [browser_webconsole_netlogging_panel.js]
 [browser_webconsole_netlogging_reset_filter.js]
 [browser_webconsole_notifications.js]
 [browser_webconsole_open-links-without-callback.js]
 [browser_webconsole_promise.js]
 [browser_webconsole_output_copy_newlines.js]
+subsuite = clipboard
 [browser_webconsole_output_order.js]
 [browser_webconsole_property_provider.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_scratchpad_panel_link.js]
 [browser_webconsole_split.js]
 [browser_webconsole_split_escape_key.js]
 [browser_webconsole_split_focus.js]
 [browser_webconsole_split_persist.js]
--- a/dom/base/ResponsiveImageSelector.cpp
+++ b/dom/base/ResponsiveImageSelector.cpp
@@ -240,22 +240,18 @@ bool
 ResponsiveImageSelector::SetSizesFromDescriptor(const nsAString & aSizes)
 {
   ClearSelectedCandidate();
   mSizeQueries.Clear();
   mSizeValues.Clear();
 
   nsCSSParser cssParser;
 
-  if (!cssParser.ParseSourceSizeList(aSizes, nullptr, 0,
-                                     mSizeQueries, mSizeValues, true)) {
-    return false;
-  }
-
-  return mSizeQueries.Length() > 0;
+  return cssParser.ParseSourceSizeList(aSizes, nullptr, 0,
+                                       mSizeQueries, mSizeValues, true);
 }
 
 void
 ResponsiveImageSelector::AppendCandidateIfUnique(const ResponsiveImageCandidate & aCandidate)
 {
   int numCandidates = mCandidates.Length();
 
   // With the exception of Default, which should not be added until we are done
--- a/dom/base/test/chrome.ini
+++ b/dom/base/test/chrome.ini
@@ -13,16 +13,17 @@ support-files =
 [test_domrequesthelper.xul]
 [test_url.xul]
 [test_console.xul]
 [test_navigator_resolve_identity_xrays.xul]
 support-files = file_navigator_resolve_identity_xrays.xul
 [test_sendQueryContentAndSelectionSetEvent.html]
 [test_bug1016960.html]
 [test_copypaste.xul]
+subsuite = clipboard
 [test_messagemanager_principal.html]
 [test_messagemanager_send_principal.html]
 skip-if = buildapp == 'mulet'
 [test_bug945152.html]
 run-if = os == 'linux'
 [test_bug1008126.html]
 run-if = os == 'linux'
 [test_sandboxed_blob_uri.html]
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -307,17 +307,19 @@ skip-if = buildapp == 'mulet'
 [test_base.xhtml]
 [test_blob_fragment_and_query.html]
 [test_blobconstructor.html]
 [test_bug5141.html]
 [test_bug28293.html]
 [test_bug28293.xhtml]
 [test_bug51034.html]
 [test_bug116083.html]
+subsuite = clipboard
 [test_bug166235.html]
+subsuite = clipboard
 skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(clipboard undefined) b2g-debug(clipboard undefined) b2g-desktop(clipboard undefined)
 [test_bug199959.html]
 [test_bug218236.html]
 [test_bug218277.html]
 [test_bug238409.html]
 [test_bug254337.html]
 [test_bug270145.xhtml]
 [test_bug276037-1.html]
@@ -673,20 +675,23 @@ skip-if = buildapp == 'b2g'
 [test_change_policy.html]
 skip-if = buildapp == 'b2g' #no ssl support
 [test_classList.html]
 [test_clearTimeoutIntervalNoArg.html]
 [test_consoleEmptyStack.html]
 [test_constructor-assignment.html]
 [test_constructor.html]
 [test_copyimage.html]
+subsuite = clipboard
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || (toolkit != 'cocoa' && toolkit != 'gonk' && toolkit != 'gtk2' && toolkit != 'gtk3' && toolkit != 'windows') #b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_copypaste.html]
+subsuite = clipboard
 skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 904183 # b2g(clipboard undefined) b2g-debug(clipboard undefined) b2g-desktop(clipboard undefined)
 [test_copypaste.xhtml]
+subsuite = clipboard
 skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 904183 # b2g(bug 904183) b2g-debug(bug 904183) b2g-desktop(bug 904183)
 [test_createHTMLDocument.html]
 [test_declare_stylesheet_obsolete.html]
 [test_dialogArguments.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # showmodaldialog
 [test_document.all_iteration.html]
 [test_document.all_unqualified.html]
 [test_document_constructor.html]
--- a/dom/browser-element/mochitest/mochitest.ini
+++ b/dom/browser-element/mochitest/mochitest.ini
@@ -181,16 +181,17 @@ skip-if = buildapp == 'b2g'
 [test_browserElement_inproc_Close.html]
 [test_browserElement_inproc_CloseApp.html]
 skip-if = toolkit == 'android' || buildapp == 'b2g' # android(FAILS, bug 796982) androidx86(FAILS, bug 796982)
 [test_browserElement_inproc_CloseFromOpener.html]
 skip-if = buildapp == 'b2g'
 [test_browserElement_inproc_ContextmenuEvents.html]
 [test_browserElement_inproc_CookiesNotThirdParty.html]
 [test_browserElement_inproc_CopyPaste.html]
+subsuite = clipboard
 skip-if = (os == "android") # Disabled on Android, see bug 1230421
 [test_browserElement_inproc_DOMRequestError.html]
 [test_browserElement_inproc_DataURI.html]
 [test_browserElement_inproc_DisallowEmbedAppsInOOP.html]
 skip-if = buildapp != 'mulet'
 [test_browserElement_inproc_DocumentFirstPaint.html]
 [test_browserElement_inproc_Download.html]
 disabled = bug 1022281
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -3577,26 +3577,41 @@ struct MOZ_STACK_CLASS CanvasBidiProcess
                               mDrawTarget);
       inlineCoord += textRunMetrics.mAdvanceWidth;
       // old code was:
       //   point.x += width * mAppUnitsPerDevPixel;
       // TODO: restore this if/when we move to fractional coords
       // throughout the text layout process
     }
 
+    mCtx->EnsureTarget();
+
+    // If the operation is 'fill' with a simple color, we defer to gfxTextRun
+    // which will handle color/svg-in-ot fonts appropriately. Such fonts will
+    // not render well via the code below.
+    if (mOp == CanvasRenderingContext2D::TextDrawOperation::FILL &&
+        mState->StyleIsColor(CanvasRenderingContext2D::Style::FILL)) {
+      RefPtr<gfxContext> thebes =
+        gfxContext::ForDrawTargetWithTransform(mCtx->mTarget);
+      nscolor fill = mState->colorStyles[CanvasRenderingContext2D::Style::FILL];
+      thebes->SetColor(Color::FromABGR(fill));
+      gfxTextRun::DrawParams params(thebes);
+      mTextRun->Draw(gfxTextRun::Range(mTextRun.get()), point, params);
+      return;
+    }
+
     uint32_t numRuns;
     const gfxTextRun::GlyphRun *runs = mTextRun->GetGlyphRuns(&numRuns);
     const int32_t appUnitsPerDevUnit = mAppUnitsPerDevPixel;
     const double devUnitsPerAppUnit = 1.0/double(appUnitsPerDevUnit);
     Point baselineOrigin =
       Point(point.x * devUnitsPerAppUnit, point.y * devUnitsPerAppUnit);
 
     float advanceSum = 0;
 
-    mCtx->EnsureTarget();
     for (uint32_t c = 0; c < numRuns; c++) {
       gfxFont *font = runs[c].mFont;
 
       bool verticalFont =
         runs[c].mOrientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT;
 
       const float& baselineOriginInline =
         verticalFont ? baselineOrigin.y : baselineOrigin.x;
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -490,19 +490,20 @@ WebGLContext::ValidateUniformArraySetter
         return false;
 
     if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
         return false;
 
     if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, this, funcName))
         return false;
 
+    MOZ_ASSERT((size_t)loc->mActiveInfo->mElemCount > loc->mArrayIndex);
+    size_t uniformElemCount = loc->mActiveInfo->mElemCount - loc->mArrayIndex;
     *out_rawLoc = loc->mLoc;
-    *out_numElementsToUpload = std::min((size_t)loc->mActiveInfo->mElemCount,
-                                        setterArraySize / setterElemSize);
+    *out_numElementsToUpload = std::min(uniformElemCount, setterArraySize / setterElemSize);
     return true;
 }
 
 bool
 WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
                                                uint8_t setterCols,
                                                uint8_t setterRows,
                                                GLenum setterType,
@@ -524,19 +525,21 @@ WebGLContext::ValidateUniformMatrixArray
         return false;
 
     if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, this, funcName))
         return false;
 
     if (!ValidateUniformMatrixTranspose(setterTranspose, funcName))
         return false;
 
+    MOZ_ASSERT((size_t)loc->mActiveInfo->mElemCount > loc->mArrayIndex);
+    size_t uniformElemCount = loc->mActiveInfo->mElemCount - loc->mArrayIndex;
     *out_rawLoc = loc->mLoc;
-    *out_numElementsToUpload = std::min((size_t)loc->mActiveInfo->mElemCount,
-                                        setterArraySize / setterElemSize);
+    *out_numElementsToUpload = std::min(uniformElemCount, setterArraySize / setterElemSize);
+
     return true;
 }
 
 bool
 WebGLContext::ValidateAttribIndex(GLuint index, const char* info)
 {
     bool valid = (index < MaxVertexAttribs());
 
--- a/dom/canvas/WebGLExtensionBase.cpp
+++ b/dom/canvas/WebGLExtensionBase.cpp
@@ -16,16 +16,18 @@ WebGLExtensionBase::WebGLExtensionBase(W
 WebGLExtensionBase::~WebGLExtensionBase()
 {
 }
 
 void
 WebGLExtensionBase::MarkLost()
 {
     mIsLost = true;
+
+    OnMarkLost();
 }
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLExtensionBase)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLExtensionBase, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLExtensionBase, Release)
 
 } // namespace mozilla
--- a/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp
+++ b/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp
@@ -244,11 +244,17 @@ WebGLExtensionDisjointTimerQuery::IsSupp
          gl->IsSupported(gl::GLFeature::get_query_object_i64v) &&
          gl->IsSupported(gl::GLFeature::query_counter) && // provides GL_TIMESTAMP
          gl->IsSupported(gl::GLFeature::sync); // provides glGetInteger64v
   // 'sync' provides glGetInteger64v either by supporting ARB_sync, GL3+, or GLES3+.
   // Since there are no differences between support for glGetInteger64v and support for
   // 'sync', we just piggy-back off of 'sync'.
 }
 
+void
+WebGLExtensionDisjointTimerQuery::OnMarkLost()
+{
+  mActiveQuery = nullptr;
+}
+
 IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionDisjointTimerQuery, EXT_disjoint_timer_query)
 
 } // namespace mozilla
--- a/dom/canvas/WebGLExtensions.h
+++ b/dom/canvas/WebGLExtensions.h
@@ -44,16 +44,18 @@ public:
     void MarkLost();
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLExtensionBase)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLExtensionBase)
 
 protected:
     virtual ~WebGLExtensionBase();
 
+    virtual void OnMarkLost() { }
+
     bool mIsLost;
 };
 
 #define DECL_WEBGL_EXTENSION_GOOP \
     virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
 
 #define IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionType, WebGLBindingType)\
     JSObject*                                                    \
@@ -382,16 +384,18 @@ public:
                            GLenum pname,
                            JS::MutableHandle<JS::Value> retval);
 
     static bool IsSupported(const WebGLContext*);
 
     DECL_WEBGL_EXTENSION_GOOP
 
 private:
+    virtual void OnMarkLost() override;
+
     /**
      * An active TIME_ELAPSED query participating in a begin/end block.
      */
     WebGLRefPtr<WebGLTimerQuery> mActiveQuery;
 };
 
 } // namespace mozilla
 
--- a/dom/canvas/WebGLProgram.cpp
+++ b/dom/canvas/WebGLProgram.cpp
@@ -781,18 +781,24 @@ WebGLProgram::GetUniformLocation(const n
     if (!IsLinked()) {
         mContext->ErrorInvalidOperation("getUniformLocation: `program` must be linked.");
         return nullptr;
     }
 
     const NS_LossyConvertUTF16toASCII userName(userName_wide);
 
     nsDependentCString baseUserName;
-    bool isArray;
-    size_t arrayIndex;
+    bool isArray = false;
+    // GLES 2.0.25, Section 2.10, p35
+    // If the the uniform location is an array, then the location of the first
+    // element of that array can be retrieved by either using the name of the
+    // uniform array, or the name of the uniform array appended with "[0]".
+    // The ParseName() can't recognize this rule. So always initialize
+    // arrayIndex with 0.
+    size_t arrayIndex = 0;
     if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
         return nullptr;
 
     const WebGLActiveInfo* activeInfo;
     if (!LinkInfo()->FindUniform(baseUserName, &activeInfo))
         return nullptr;
 
     const nsCString& baseMappedName = activeInfo->mBaseMappedName;
@@ -807,17 +813,18 @@ WebGLProgram::GetUniformLocation(const n
     gl::GLContext* gl = mContext->GL();
     gl->MakeCurrent();
 
     GLint loc = gl->fGetUniformLocation(mGLName, mappedName.BeginReading());
     if (loc == -1)
         return nullptr;
 
     RefPtr<WebGLUniformLocation> locObj = new WebGLUniformLocation(mContext, LinkInfo(),
-                                                                     loc, activeInfo);
+                                                                   loc, arrayIndex,
+                                                                   activeInfo);
     return locObj.forget();
 }
 
 void
 WebGLProgram::GetUniformIndices(const dom::Sequence<nsString>& uniformNames,
                                 dom::Nullable< nsTArray<GLuint> >& retval) const
 {
     size_t count = uniformNames.Length();
--- a/dom/canvas/WebGLShaderValidator.cpp
+++ b/dom/canvas/WebGLShaderValidator.cpp
@@ -78,16 +78,19 @@ ChooseValidatorCompileOptions(const ShBu
         if (gl->Vendor() == gl::GLVendor::Intel) {
             options |= SH_EMULATE_BUILT_IN_FUNCTIONS;
         }
 
         // Work around bug 636926
         if (gl->Vendor() == gl::GLVendor::NVIDIA) {
             options |= SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX;
         }
+
+        // Work around that Mac drivers handle struct scopes incorrectly.
+        options |= SH_REGENERATE_STRUCT_NAMES;
     }
 #endif
 
     return options;
 }
 
 } // namespace webgl
 
--- a/dom/canvas/WebGLUniformLocation.cpp
+++ b/dom/canvas/WebGLUniformLocation.cpp
@@ -11,20 +11,23 @@
 #include "WebGLActiveInfo.h"
 #include "WebGLContext.h"
 #include "WebGLProgram.h"
 
 namespace mozilla {
 
 WebGLUniformLocation::WebGLUniformLocation(WebGLContext* webgl,
                                            const webgl::LinkedProgramInfo* linkInfo,
-                                           GLuint loc, const WebGLActiveInfo* activeInfo)
+                                           GLuint loc,
+                                           size_t arrayIndex,
+                                           const WebGLActiveInfo* activeInfo)
     : WebGLContextBoundObject(webgl)
     , mLinkInfo(linkInfo)
     , mLoc(loc)
+    , mArrayIndex(arrayIndex)
     , mActiveInfo(activeInfo)
 { }
 
 WebGLUniformLocation::~WebGLUniformLocation()
 { }
 
 bool
 WebGLUniformLocation::ValidateForProgram(WebGLProgram* prog, WebGLContext* webgl,
--- a/dom/canvas/WebGLUniformLocation.h
+++ b/dom/canvas/WebGLUniformLocation.h
@@ -36,20 +36,21 @@ public:
     virtual JSObject* WrapObject(JSContext* js, JS::Handle<JSObject*> givenProto) override;
 
     WebGLContext* GetParentObject() const {
         return mContext;
     }
 
     const WeakPtr<const webgl::LinkedProgramInfo> mLinkInfo;
     const GLuint mLoc;
+    const size_t mArrayIndex;
     const WebGLActiveInfo* const mActiveInfo;
 
     WebGLUniformLocation(WebGLContext* webgl, const webgl::LinkedProgramInfo* linkInfo,
-                         GLuint loc, const WebGLActiveInfo* activeInfo);
+                         GLuint loc, size_t arrayIndex, const WebGLActiveInfo* activeInfo);
 
     bool ValidateForProgram(WebGLProgram* prog, WebGLContext* webgl,
                             const char* funcName) const;
     bool ValidateSamplerSetter(GLint value, WebGLContext* webgl,
                                const char* funcName) const;
     bool ValidateSizeAndType(uint8_t setterElemSize, GLenum setterType,
                              WebGLContext* webgl, const char* funcName) const;
     bool ValidateArrayLength(uint8_t setterElemSize, size_t setterArraySize,
--- a/dom/canvas/test/webgl-conf/generated-mochitest.ini
+++ b/dom/canvas/test/webgl-conf/generated-mochitest.ini
@@ -2657,17 +2657,16 @@ fail-if = (os == 'mac' && os_version == 
 [generated/test_conformance__glsl__misc__large-loop-compile.html]
 fail-if = (os == 'win' && os_version == '5.1')
 [generated/test_conformance__glsl__misc__non-ascii-comments.vert.html]
 [generated/test_conformance__glsl__misc__non-ascii.vert.html]
 [generated/test_conformance__glsl__misc__re-compile-re-link.html]
 fail-if = (os == 'android' && android_version == '10')
 [generated/test_conformance__glsl__misc__shader-precision-format-obeyed.html]
 [generated/test_conformance__glsl__misc__shader-struct-scope.html]
-fail-if = (os == 'mac')
 [generated/test_conformance__glsl__misc__shader-uniform-packing-restrictions.html]
 skip-if = (os == 'android')
 [generated/test_conformance__glsl__misc__shader-varying-packing-restrictions.html]
 [generated/test_conformance__glsl__misc__shader-with-256-character-define.html]
 [generated/test_conformance__glsl__misc__shader-with-256-character-identifier.frag.html]
 [generated/test_conformance__glsl__misc__shader-with-257-character-define.html]
 [generated/test_conformance__glsl__misc__shader-with-257-character-identifier.frag.html]
 [generated/test_conformance__glsl__misc__shader-with-_webgl-identifier.vert.html]
@@ -2745,17 +2744,16 @@ fail-if = 1
 [generated/test_conformance__glsl__misc__shaders-with-name-conflicts.html]
 [generated/test_conformance__glsl__misc__shaders-with-uniform-structs.html]
 [generated/test_conformance__glsl__misc__shaders-with-varyings.html]
 [generated/test_conformance__glsl__misc__shared.html]
 [generated/test_conformance__glsl__misc__struct-equals.html]
 [generated/test_conformance__glsl__misc__struct-mixed-array-declarators.html]
 [generated/test_conformance__glsl__misc__struct-nesting-exceeds-maximum.html]
 [generated/test_conformance__glsl__misc__struct-nesting-of-variable-names.html]
-fail-if = (os == 'mac' && os_version == '10.10')
 [generated/test_conformance__glsl__misc__struct-nesting-under-maximum.html]
 [generated/test_conformance__glsl__misc__struct-specifiers-in-uniforms.html]
 [generated/test_conformance__glsl__misc__struct-unary-operators.html]
 [generated/test_conformance__glsl__misc__ternary-operators-in-global-initializers.html]
 [generated/test_conformance__glsl__misc__ternary-operators-in-initializers.html]
 [generated/test_conformance__glsl__misc__uniform-location-length-limits.html]
 [generated/test_conformance__glsl__reserved___webgl_field.vert.html]
 [generated/test_conformance__glsl__reserved___webgl_function.vert.html]
--- a/dom/canvas/test/webgl-conf/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conf/mochitest-errata.ini
@@ -400,19 +400,16 @@ skip-if = (os == 'linux')
 skip-if = (os == 'mac')
 [generated/test_conformance__canvas__viewport-unchanged-upon-resize.html]
 # New OSX r7 machines and 10.10.5 is causing perma failure (bug 1216549)
 skip-if = (os == 'mac')
 [generated/test_conformance__rendering__multisample-corruption.html]
 # application crashed [@ gldAttachDrawable + 0x9e0]. Also crash on Android.
 skip-if = (os == 'mac') || (os == 'android')
 
-[generated/test_conformance__glsl__misc__shader-struct-scope.html]
-fail-if = (os == 'mac')
-
 [generated/test_conformance__extensions__oes-vertex-array-object.html]
 # 10.6 crash:
 # PROCESS-CRASH | dom/canvas/test/webgl-conf/generated/test_conformance__extensions__oes-vertex-array-object.html | application crashed [@ gleRunVertexSubmitImmediate + 0xf24]
 skip-if = (os == 'mac' && os_version == '10.6')
 
 ####################
 # 10.6
 [generated/test_conformance__glsl__constructors__glsl-construct-mat3.html]
@@ -434,21 +431,16 @@ fail-if = (os == 'mac' && os_version == 
 # 10.8
 [generated/test_conformance__glsl__functions__glsl-function-smoothstep-gentype.html]
 fail-if = (os == 'mac' && os_version == '10.8')
 [generated/test_conformance__glsl__variables__gl-pointcoord.html]
 fail-if = (os == 'mac' && os_version == '10.8')
 [generated/test_conformance__limits__gl-max-texture-dimensions.html]
 fail-if = (os == 'mac' && os_version == '10.8')
 
-####################
-# 10.10
-[generated/test_conformance__glsl__misc__struct-nesting-of-variable-names.html]
-fail-if = (os == 'mac' && os_version == '10.10')
-
 ########################################################################
 ########################################################################
 # Win
 
 [generated/test_conformance__glsl__misc__large-loop-compile.html]
 fail-if = (os == 'win' && os_version == '5.1')
 [generated/test_conformance__textures__copy-tex-image-2d-formats.html]
 # Assert failure in DEBUG
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -97,17 +97,17 @@ PDMFactory::EnsureInit() const
         NS_NewRunnableFunction([]() { ClearOnShutdown(&sInstance); });
       NS_DispatchToMainThread(runnable);
     }
   }
 }
 
 already_AddRefed<MediaDataDecoder>
 PDMFactory::CreateDecoder(const TrackInfo& aConfig,
-                          FlushableTaskQueue* aTaskQueue,
+                          TaskQueue* aTaskQueue,
                           MediaDataDecoderCallback* aCallback,
                           DecoderDoctorDiagnostics* aDiagnostics,
                           layers::LayersBackend aLayersBackend,
                           layers::ImageContainer* aImageContainer) const
 {
   bool isEncrypted = mEMEPDM && aConfig.mCrypto.mValid;
 
   if (isEncrypted) {
@@ -152,17 +152,17 @@ PDMFactory::CreateDecoder(const TrackInf
   }
   NS_WARNING("Unable to create a decoder, no platform found.");
   return nullptr;
 }
 
 already_AddRefed<MediaDataDecoder>
 PDMFactory::CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
                                  const TrackInfo& aConfig,
-                                 FlushableTaskQueue* aTaskQueue,
+                                 TaskQueue* aTaskQueue,
                                  MediaDataDecoderCallback* aCallback,
                                  DecoderDoctorDiagnostics* aDiagnostics,
                                  layers::LayersBackend aLayersBackend,
                                  layers::ImageContainer* aImageContainer) const
 {
   MOZ_ASSERT(aPDM);
   RefPtr<MediaDataDecoder> m;
 
--- a/dom/media/platforms/PDMFactory.h
+++ b/dom/media/platforms/PDMFactory.h
@@ -26,17 +26,17 @@ public:
 
   // Factory method that creates the appropriate PlatformDecoderModule for
   // the platform we're running on. Caller is responsible for deleting this
   // instance. It's expected that there will be multiple
   // PlatformDecoderModules alive at the same time.
   // This is called on the decode task queue.
   already_AddRefed<MediaDataDecoder>
   CreateDecoder(const TrackInfo& aConfig,
-                FlushableTaskQueue* aTaskQueue,
+                TaskQueue* aTaskQueue,
                 MediaDataDecoderCallback* aCallback,
                 DecoderDoctorDiagnostics* aDiagnostics,
                 layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE,
                 layers::ImageContainer* aImageContainer = nullptr) const;
 
   bool SupportsMimeType(const nsACString& aMimeType,
                         DecoderDoctorDiagnostics* aDiagnostics) const;
 
@@ -57,17 +57,17 @@ private:
   // Returns the first PDM in our list supporting the mimetype.
   already_AddRefed<PlatformDecoderModule>
   GetDecoder(const nsACString& aMimeType,
              DecoderDoctorDiagnostics* aDiagnostics) const;
 
   already_AddRefed<MediaDataDecoder>
   CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
                        const TrackInfo& aConfig,
-                       FlushableTaskQueue* aTaskQueue,
+                       TaskQueue* aTaskQueue,
                        MediaDataDecoderCallback* aCallback,
                        DecoderDoctorDiagnostics* aDiagnostics,
                        layers::LayersBackend aLayersBackend,
                        layers::ImageContainer* aImageContainer) const;
 
   nsTArray<RefPtr<PlatformDecoderModule>> mCurrentPDMs;
   RefPtr<PlatformDecoderModule> mEMEPDM;
 
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -2,17 +2,16 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #if !defined(PlatformDecoderModule_h_)
 #define PlatformDecoderModule_h_
 
-#include "FlushableTaskQueue.h"
 #include "MediaDecoderReader.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "nsTArray.h"
 #include "mozilla/RefPtr.h"
 #include <queue>
 
 namespace mozilla {
@@ -23,17 +22,17 @@ class MediaRawData;
 class DecoderDoctorDiagnostics;
 
 namespace layers {
 class ImageContainer;
 } // namespace layers
 
 class MediaDataDecoder;
 class MediaDataDecoderCallback;
-class FlushableTaskQueue;
+class TaskQueue;
 class CDMProxy;
 
 // The PlatformDecoderModule interface is used by the MediaFormatReader to
 // abstract access to decoders provided by various
 // platforms.
 // Each platform (Windows, MacOSX, Linux, B2G etc) must implement a
 // PlatformDecoderModule to provide access to its decoders in order to get
 // decompressed H.264/AAC from the MediaFormatReader.
@@ -85,33 +84,33 @@ protected:
   // COINIT_MULTITHREADED.
   // Returns nullptr if the decoder can't be created.
   // It is safe to store a reference to aConfig.
   // This is called on the decode task queue.
   virtual already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const VideoInfo& aConfig,
                      layers::LayersBackend aLayersBackend,
                      layers::ImageContainer* aImageContainer,
-                     FlushableTaskQueue* aVideoTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) = 0;
 
   // Creates an Audio decoder with the specified properties.
   // Asynchronous decoding of audio should be done in runnables dispatched to
   // aAudioTaskQueue. If the task queue isn't needed, the decoder should
   // not hold a reference to it.
   // Output and errors should be returned to the reader via aCallback.
   // Returns nullptr if the decoder can't be created.
   // On Windows the task queue's threads in have MSCOM initialized with
   // COINIT_MULTITHREADED.
   // It is safe to store a reference to aConfig.
   // This is called on the decode task queue.
   virtual already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const AudioInfo& aConfig,
-                     FlushableTaskQueue* aAudioTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) = 0;
 };
 
 // A callback used by MediaDataDecoder to return output/errors to the
 // MediaFormatReader.
 // Implementation is threadsafe, and can be called on any thread.
 class MediaDataDecoderCallback {
--- a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp
@@ -21,47 +21,47 @@ AgnosticDecoderModule::SupportsMimeType(
     VorbisDataDecoder::IsVorbis(aMimeType) ||
     WaveDataDecoder::IsWave(aMimeType);
 }
 
 already_AddRefed<MediaDataDecoder>
 AgnosticDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig,
                                           layers::LayersBackend aLayersBackend,
                                           layers::ImageContainer* aImageContainer,
-                                          FlushableTaskQueue* aVideoTaskQueue,
+                                          TaskQueue* aTaskQueue,
                                           MediaDataDecoderCallback* aCallback,
                                           DecoderDoctorDiagnostics* aDiagnostics)
 {
   RefPtr<MediaDataDecoder> m;
 
   if (VPXDecoder::IsVPX(aConfig.mMimeType)) {
     m = new VPXDecoder(*aConfig.GetAsVideoInfo(),
                        aImageContainer,
-                       aVideoTaskQueue,
+                       aTaskQueue,
                        aCallback);
   }
 
   return m.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 AgnosticDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig,
-                                          FlushableTaskQueue* aAudioTaskQueue,
+                                          TaskQueue* aTaskQueue,
                                           MediaDataDecoderCallback* aCallback,
                                           DecoderDoctorDiagnostics* aDiagnostics)
 {
   RefPtr<MediaDataDecoder> m;
 
   if (VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) {
     m = new VorbisDataDecoder(*aConfig.GetAsAudioInfo(),
-                              aAudioTaskQueue,
+                              aTaskQueue,
                               aCallback);
   } else if (OpusDataDecoder::IsOpus(aConfig.mMimeType)) {
     m = new OpusDataDecoder(*aConfig.GetAsAudioInfo(),
-                            aAudioTaskQueue,
+                            aTaskQueue,
                             aCallback);
   } else if (WaveDataDecoder::IsWave(aConfig.mMimeType)) {
     m = new WaveDataDecoder(*aConfig.GetAsAudioInfo(), aCallback);
   }
 
   return m.forget();
 }
 
--- a/dom/media/platforms/agnostic/AgnosticDecoderModule.h
+++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.h
@@ -20,23 +20,23 @@ public:
   }
 
 protected:
   // Decode thread.
   already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const VideoInfo& aConfig,
                      layers::LayersBackend aLayersBackend,
                      layers::ImageContainer* aImageContainer,
-                     FlushableTaskQueue* aVideoTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
   // Decode thread.
   already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const AudioInfo& aConfig,
-                     FlushableTaskQueue* aAudioTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 };
 
 } // namespace mozilla
 
 #endif /* AgnosticDecoderModule_h_ */
--- a/dom/media/platforms/agnostic/BlankDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/BlankDecoderModule.cpp
@@ -196,32 +196,32 @@ private:
 class BlankDecoderModule : public PlatformDecoderModule {
 public:
 
   // Decode thread.
   already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const VideoInfo& aConfig,
                      layers::LayersBackend aLayersBackend,
                      layers::ImageContainer* aImageContainer,
-                     FlushableTaskQueue* aVideoTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override {
     BlankVideoDataCreator* creator = new BlankVideoDataCreator(
       aConfig.mDisplay.width, aConfig.mDisplay.height, aImageContainer);
     RefPtr<MediaDataDecoder> decoder =
       new BlankMediaDataDecoder<BlankVideoDataCreator>(creator,
                                                        aCallback,
                                                        TrackInfo::kVideoTrack);
     return decoder.forget();
   }
 
   // Decode thread.
   already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const AudioInfo& aConfig,
-                     FlushableTaskQueue* aAudioTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override {
     BlankAudioDataCreator* creator = new BlankAudioDataCreator(
       aConfig.mChannels, aConfig.mRate);
 
     RefPtr<MediaDataDecoder> decoder =
       new BlankMediaDataDecoder<BlankAudioDataCreator>(creator,
                                                        aCallback,
--- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
@@ -233,38 +233,38 @@ CreateDecoderWrapper(MediaDataDecoderCal
     new EMEMediaDataDecoderProxy(thread.forget(), aCallback, aProxy, aTaskQueue));
   return decoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 EMEDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig,
                                      layers::LayersBackend aLayersBackend,
                                      layers::ImageContainer* aImageContainer,
-                                     FlushableTaskQueue* aVideoTaskQueue,
+                                     TaskQueue* aTaskQueue,
                                      MediaDataDecoderCallback* aCallback,
                                      DecoderDoctorDiagnostics* aDiagnostics)
 {
   MOZ_ASSERT(aConfig.mCrypto.mValid);
 
   if (SupportsMimeType(aConfig.mMimeType, nullptr)) {
     // GMP decodes. Assume that means it can decrypt too.
-    RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback, mProxy, aVideoTaskQueue);
+    RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback, mProxy, aTaskQueue);
     wrapper->SetProxyTarget(new EMEVideoDecoder(mProxy,
                                                 aConfig,
                                                 aLayersBackend,
                                                 aImageContainer,
-                                                aVideoTaskQueue,
+                                                aTaskQueue,
                                                 wrapper->Callback()));
     return wrapper.forget();
   }
 
   MOZ_ASSERT(mPDM);
   RefPtr<MediaDataDecoder> decoder(
     mPDM->CreateDecoder(aConfig,
-                        aVideoTaskQueue,
+                        aTaskQueue,
                         aCallback,
                         aDiagnostics,
                         aLayersBackend,
                         aImageContainer));
   if (!decoder) {
     return nullptr;
   }
 
@@ -272,35 +272,35 @@ EMEDecoderModule::CreateVideoDecoder(con
                                                          aCallback,
                                                          mProxy,
                                                          AbstractThread::GetCurrent()->AsTaskQueue()));
   return emeDecoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 EMEDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig,
-                                     FlushableTaskQueue* aAudioTaskQueue,
+                                     TaskQueue* aTaskQueue,
                                      MediaDataDecoderCallback* aCallback,
                                      DecoderDoctorDiagnostics* aDiagnostics)
 {
   MOZ_ASSERT(aConfig.mCrypto.mValid);
 
   if (SupportsMimeType(aConfig.mMimeType, nullptr)) {
     // GMP decodes. Assume that means it can decrypt too.
-    RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback, mProxy, aAudioTaskQueue);
+    RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback, mProxy, aTaskQueue);
     wrapper->SetProxyTarget(new EMEAudioDecoder(mProxy,
                                                 aConfig,
-                                                aAudioTaskQueue,
+                                                aTaskQueue,
                                                 wrapper->Callback()));
     return wrapper.forget();
   }
 
   MOZ_ASSERT(mPDM);
   RefPtr<MediaDataDecoder> decoder(
-    mPDM->CreateDecoder(aConfig, aAudioTaskQueue, aCallback, aDiagnostics));
+    mPDM->CreateDecoder(aConfig, aTaskQueue, aCallback, aDiagnostics));
   if (!decoder) {
     return nullptr;
   }
 
   RefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(decoder,
                                                          aCallback,
                                                          mProxy,
                                                          AbstractThread::GetCurrent()->AsTaskQueue()));
--- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h
+++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.h
@@ -24,24 +24,24 @@ public:
   virtual ~EMEDecoderModule();
 
 protected:
   // Decode thread.
   already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const VideoInfo& aConfig,
                     layers::LayersBackend aLayersBackend,
                     layers::ImageContainer* aImageContainer,
-                    FlushableTaskQueue* aVideoTaskQueue,
+                    TaskQueue* aTaskQueue,
                     MediaDataDecoderCallback* aCallback,
                     DecoderDoctorDiagnostics* aDiagnostics) override;
 
   // Decode thread.
   already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const AudioInfo& aConfig,
-                     FlushableTaskQueue* aAudioTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
   ConversionRequired
   DecoderNeedsConversion(const TrackInfo& aConfig) const override;
 
   bool
   SupportsMimeType(const nsACString& aMimeType,
--- a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
@@ -44,17 +44,17 @@ CreateDecoderWrapper(MediaDataDecoderCal
   RefPtr<MediaDataDecoderProxy> decoder(new MediaDataDecoderProxy(thread.forget(), aCallback));
   return decoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 GMPDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig,
                                      layers::LayersBackend aLayersBackend,
                                      layers::ImageContainer* aImageContainer,
-                                     FlushableTaskQueue* aVideoTaskQueue,
+                                     TaskQueue* aTaskQueue,
                                      MediaDataDecoderCallback* aCallback,
                                      DecoderDoctorDiagnostics* aDiagnostics)
 {
   if (!aConfig.mMimeType.EqualsLiteral("video/avc")) {
     return nullptr;
   }
 
   if (aDiagnostics) {
@@ -63,41 +63,41 @@ GMPDecoderModule::CreateVideoDecoder(con
       aDiagnostics->SetGMP(preferredGMP.value());
     }
   }
 
   RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback);
   wrapper->SetProxyTarget(new GMPVideoDecoder(aConfig,
                                               aLayersBackend,
                                               aImageContainer,
-                                              aVideoTaskQueue,
+                                              aTaskQueue,
                                               wrapper->Callback()));
   return wrapper.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 GMPDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig,
-                                     FlushableTaskQueue* aAudioTaskQueue,
+                                     TaskQueue* aTaskQueue,
                                      MediaDataDecoderCallback* aCallback,
                                      DecoderDoctorDiagnostics* aDiagnostics)
 {
   if (!aConfig.mMimeType.EqualsLiteral("audio/mp4a-latm")) {
     return nullptr;
   }
 
   if (aDiagnostics) {
     const Maybe<nsCString> preferredGMP = PreferredGMP(aConfig.mMimeType);
     if (preferredGMP.isSome()) {
       aDiagnostics->SetGMP(preferredGMP.value());
     }
   }
 
   RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback);
   wrapper->SetProxyTarget(new GMPAudioDecoder(aConfig,
-                                              aAudioTaskQueue,
+                                              aTaskQueue,
                                               wrapper->Callback()));
   return wrapper.forget();
 }
 
 PlatformDecoderModule::ConversionRequired
 GMPDecoderModule::DecoderNeedsConversion(const TrackInfo& aConfig) const
 {
   // GMPVideoCodecType::kGMPVideoCodecH264 specifies that encoded frames must be in AVCC format.
--- a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h
+++ b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h
@@ -31,24 +31,24 @@ public:
 
   virtual ~GMPDecoderModule();
 
   // Decode thread.
   already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const VideoInfo& aConfig,
                      layers::LayersBackend aLayersBackend,
                      layers::ImageContainer* aImageContainer,
-                     FlushableTaskQueue* aVideoTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
   // Decode thread.
   already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const AudioInfo& aConfig,
-                     FlushableTaskQueue* aAudioTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
   ConversionRequired
   DecoderNeedsConversion(const TrackInfo& aConfig) const override;
 
   bool
   SupportsMimeType(const nsACString& aMimeType,
--- a/dom/media/platforms/android/AndroidDecoderModule.cpp
+++ b/dom/media/platforms/android/AndroidDecoderModule.cpp
@@ -264,33 +264,33 @@ AndroidDecoderModule::SupportsMimeType(c
   // Accessing a stale local reference leading to a SIGSEGV crash.
   // To avoid this we check for wav types here.
   if (aMimeType.EqualsLiteral("audio/x-wav") ||
       aMimeType.EqualsLiteral("audio/wave; codecs=1") ||
       aMimeType.EqualsLiteral("audio/wave; codecs=6") ||
       aMimeType.EqualsLiteral("audio/wave; codecs=7") ||
       aMimeType.EqualsLiteral("audio/wave; codecs=65534")) {
     return false;
-  }  
+  }
 
   if ((VPXDecoder::IsVPX(aMimeType, VPXDecoder::VP8) &&
        !GetFeatureStatus(nsIGfxInfo::FEATURE_VP8_HW_DECODE)) ||
       (VPXDecoder::IsVPX(aMimeType, VPXDecoder::VP9) &&
        !GetFeatureStatus(nsIGfxInfo::FEATURE_VP9_HW_DECODE))) {
     return false;
   }
 
   return widget::HardwareCodecCapabilityUtils::FindDecoderCodecInfoForMimeType(
       nsCString(TranslateMimeType(aMimeType)));
 }
 
 already_AddRefed<MediaDataDecoder>
 AndroidDecoderModule::CreateVideoDecoder(
     const VideoInfo& aConfig, layers::LayersBackend aLayersBackend,
-    layers::ImageContainer* aImageContainer, FlushableTaskQueue* aVideoTaskQueue,
+    layers::ImageContainer* aImageContainer, TaskQueue* aTaskQueue,
     MediaDataDecoderCallback* aCallback,
     DecoderDoctorDiagnostics* aDiagnostics)
 {
   MediaFormat::LocalRef format;
 
   NS_ENSURE_SUCCESS(MediaFormat::CreateVideoFormat(
       TranslateMimeType(aConfig.mMimeType),
       aConfig.mDisplay.width,
@@ -300,17 +300,17 @@ AndroidDecoderModule::CreateVideoDecoder
   RefPtr<MediaDataDecoder> decoder =
     new VideoDataDecoder(aConfig, format, aCallback, aImageContainer);
 
   return decoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 AndroidDecoderModule::CreateAudioDecoder(
-    const AudioInfo& aConfig, FlushableTaskQueue* aAudioTaskQueue,
+    const AudioInfo& aConfig, TaskQueue* aTaskQueue,
     MediaDataDecoderCallback* aCallback,
     DecoderDoctorDiagnostics* aDiagnostics)
 {
   MOZ_ASSERT(aConfig.mBitDepth == 16, "We only handle 16-bit audio!");
 
   MediaFormat::LocalRef format;
 
   LOG("CreateAudioFormat with mimeType=%s, mRate=%d, channels=%d",
--- a/dom/media/platforms/android/AndroidDecoderModule.h
+++ b/dom/media/platforms/android/AndroidDecoderModule.h
@@ -20,23 +20,23 @@ namespace mozilla {
 typedef std::deque<RefPtr<MediaRawData>> SampleQueue;
 
 class AndroidDecoderModule : public PlatformDecoderModule {
 public:
   already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const VideoInfo& aConfig,
                      layers::LayersBackend aLayersBackend,
                      layers::ImageContainer* aImageContainer,
-                     FlushableTaskQueue* aVideoTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
   already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const AudioInfo& aConfig,
-                     FlushableTaskQueue* aAudioTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
 
   AndroidDecoderModule() {}
   virtual ~AndroidDecoderModule() {}
 
   bool SupportsMimeType(const nsACString& aMimeType,
--- a/dom/media/platforms/apple/AppleDecoderModule.cpp
+++ b/dom/media/platforms/apple/AppleDecoderModule.cpp
@@ -72,49 +72,49 @@ AppleDecoderModule::Startup()
   }
   return NS_OK;
 }
 
 already_AddRefed<MediaDataDecoder>
 AppleDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig,
                                        layers::LayersBackend aLayersBackend,
                                        layers::ImageContainer* aImageContainer,
-                                       FlushableTaskQueue* aVideoTaskQueue,
+                                       TaskQueue* aTaskQueue,
                                        MediaDataDecoderCallback* aCallback,
                                        DecoderDoctorDiagnostics* aDiagnostics)
 {
   RefPtr<MediaDataDecoder> decoder;
 
   if (sIsVDAAvailable && (!sIsVTHWAvailable || MediaPrefs::AppleForceVDA())) {
     decoder =
       AppleVDADecoder::CreateVDADecoder(aConfig,
-                                        aVideoTaskQueue,
+                                        aTaskQueue,
                                         aCallback,
                                         aImageContainer);
     if (decoder) {
       return decoder.forget();
     }
   }
   // We fallback here if VDA isn't available, or is available but isn't
   // supported by the current platform.
   if (sIsVTAvailable) {
     decoder =
-      new AppleVTDecoder(aConfig, aVideoTaskQueue, aCallback, aImageContainer);
+      new AppleVTDecoder(aConfig, aTaskQueue, aCallback, aImageContainer);
   }
   return decoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 AppleDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig,
-                                       FlushableTaskQueue* aAudioTaskQueue,
+                                       TaskQueue* aTaskQueue,
                                        MediaDataDecoderCallback* aCallback,
                                        DecoderDoctorDiagnostics* aDiagnostics)
 {
   RefPtr<MediaDataDecoder> decoder =
-    new AppleATDecoder(aConfig, aAudioTaskQueue, aCallback);
+    new AppleATDecoder(aConfig, aTaskQueue, aCallback);
   return decoder.forget();
 }
 
 bool
 AppleDecoderModule::SupportsMimeType(const nsACString& aMimeType,
                                      DecoderDoctorDiagnostics* aDiagnostics) const
 {
   return (sIsCoreMediaAvailable &&
--- a/dom/media/platforms/apple/AppleDecoderModule.h
+++ b/dom/media/platforms/apple/AppleDecoderModule.h
@@ -18,24 +18,24 @@ public:
 
   nsresult Startup() override;
 
   // Decode thread.
   already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const VideoInfo& aConfig,
                      layers::LayersBackend aLayersBackend,
                      layers::ImageContainer* aImageContainer,
-                     FlushableTaskQueue* aVideoTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
   // Decode thread.
   already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const AudioInfo& aConfig,
-                     FlushableTaskQueue* aAudioTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
   bool SupportsMimeType(const nsACString& aMimeType,
                         DecoderDoctorDiagnostics* aDiagnostics) const override;
 
   ConversionRequired
   DecoderNeedsConversion(const TrackInfo& aConfig) const override;
--- a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp
@@ -10,17 +10,17 @@
 #include "TimeUnits.h"
 
 #define MAX_CHANNELS 16
 
 namespace mozilla
 {
 
 FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(FFmpegLibWrapper* aLib,
-  FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
+  TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
   const AudioInfo& aConfig)
   : FFmpegDataDecoder(aLib, aTaskQueue, aCallback, GetCodecId(aConfig.mMimeType))
 {
   MOZ_COUNT_CTOR(FFmpegAudioDecoder);
   // Use a new MediaByteBuffer as the object will be modified during initialization.
   mExtraData = new MediaByteBuffer;
   mExtraData->AppendElements(*aConfig.mCodecSpecificConfig);
 }
--- a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.h
+++ b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.h
@@ -16,17 +16,17 @@ namespace mozilla
 template <int V> class FFmpegAudioDecoder
 {
 };
 
 template <>
 class FFmpegAudioDecoder<LIBAV_VER> : public FFmpegDataDecoder<LIBAV_VER>
 {
 public:
-  FFmpegAudioDecoder(FFmpegLibWrapper* aLib, FlushableTaskQueue* aTaskQueue,
+  FFmpegAudioDecoder(FFmpegLibWrapper* aLib, TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      const AudioInfo& aConfig);
   virtual ~FFmpegAudioDecoder();
 
   RefPtr<InitPromise> Init() override;
   void InitCodecContext() override;
   static AVCodecID GetCodecId(const nsACString& aMimeType);
   const char* GetDescriptionName() const override
--- a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h
+++ b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h
@@ -29,37 +29,37 @@ public:
 
   explicit FFmpegDecoderModule(FFmpegLibWrapper* aLib) : mLib(aLib) {}
   virtual ~FFmpegDecoderModule() {}
 
   already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const VideoInfo& aConfig,
                      layers::LayersBackend aLayersBackend,
                      layers::ImageContainer* aImageContainer,
-                     FlushableTaskQueue* aVideoTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override
   {
     RefPtr<MediaDataDecoder> decoder =
-      new FFmpegVideoDecoder<V>(mLib, aVideoTaskQueue, aCallback, aConfig,
+      new FFmpegVideoDecoder<V>(mLib, aTaskQueue, aCallback, aConfig,
                                 aImageContainer);
     return decoder.forget();
   }
 
   already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const AudioInfo& aConfig,
-                     FlushableTaskQueue* aAudioTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override
   {
 #ifdef USING_MOZFFVPX
     return nullptr;
 #else
     RefPtr<MediaDataDecoder> decoder =
-      new FFmpegAudioDecoder<V>(mLib, aAudioTaskQueue, aCallback, aConfig);
+      new FFmpegAudioDecoder<V>(mLib, aTaskQueue, aCallback, aConfig);
     return decoder.forget();
 #endif
   }
 
   bool SupportsMimeType(const nsACString& aMimeType,
                         DecoderDoctorDiagnostics* aDiagnostics) const override
   {
     AVCodecID videoCodec = FFmpegVideoDecoder<V>::GetCodecId(aMimeType);
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
@@ -96,17 +96,17 @@ FFmpegVideoDecoder<LIBAV_VER>::PtsCorrec
 {
   mNumFaultyPts = 0;
   mNumFaultyDts = 0;
   mLastPts = INT64_MIN;
   mLastDts = INT64_MIN;
 }
 
 FFmpegVideoDecoder<LIBAV_VER>::FFmpegVideoDecoder(FFmpegLibWrapper* aLib,
-  FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
+  TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
   const VideoInfo& aConfig,
   ImageContainer* aImageContainer)
   : FFmpegDataDecoder(aLib, aTaskQueue, aCallback, GetCodecId(aConfig.mMimeType))
   , mImageContainer(aImageContainer)
   , mInfo(aConfig)
   , mCodecParser(nullptr)
   , mLastInputDts(INT64_MIN)
 {
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
@@ -22,17 +22,17 @@ class FFmpegVideoDecoder : public FFmpeg
 
 template <>
 class FFmpegVideoDecoder<LIBAV_VER> : public FFmpegDataDecoder<LIBAV_VER>
 {
   typedef mozilla::layers::Image Image;
   typedef mozilla::layers::ImageContainer ImageContainer;
 
 public:
-  FFmpegVideoDecoder(FFmpegLibWrapper* aLib, FlushableTaskQueue* aTaskQueue,
+  FFmpegVideoDecoder(FFmpegLibWrapper* aLib, TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      const VideoInfo& aConfig,
                      ImageContainer* aImageContainer);
   virtual ~FFmpegVideoDecoder();
 
   RefPtr<InitPromise> Init() override;
   void InitCodecContext() override;
   const char* GetDescriptionName() const override
--- a/dom/media/platforms/gonk/GonkDecoderModule.cpp
+++ b/dom/media/platforms/gonk/GonkDecoderModule.cpp
@@ -17,29 +17,29 @@ GonkDecoderModule::GonkDecoderModule()
 GonkDecoderModule::~GonkDecoderModule()
 {
 }
 
 already_AddRefed<MediaDataDecoder>
 GonkDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig,
                                      mozilla::layers::LayersBackend aLayersBackend,
                                      mozilla::layers::ImageContainer* aImageContainer,
-                                     FlushableTaskQueue* aVideoTaskQueue,
+                                     TaskQueue* aTaskQueue,
                                      MediaDataDecoderCallback* aCallback,
                                      DecoderDoctorDiagnostics* aDiagnostics)
 {
   RefPtr<MediaDataDecoder> decoder =
   new GonkMediaDataDecoder(new GonkVideoDecoderManager(aImageContainer, aConfig),
                            aCallback);
   return decoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 GonkDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig,
-                                      FlushableTaskQueue* aAudioTaskQueue,
+                                      TaskQueue* aTaskQueue,
                                       MediaDataDecoderCallback* aCallback,
                                       DecoderDoctorDiagnostics* aDiagnostics)
 {
   RefPtr<MediaDataDecoder> decoder =
   new GonkMediaDataDecoder(new GonkAudioDecoderManager(aConfig),
                            aCallback);
   return decoder.forget();
 }
--- a/dom/media/platforms/gonk/GonkDecoderModule.h
+++ b/dom/media/platforms/gonk/GonkDecoderModule.h
@@ -16,24 +16,24 @@ public:
   GonkDecoderModule();
   virtual ~GonkDecoderModule();
 
   // Decode thread.
   already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const VideoInfo& aConfig,
                      mozilla::layers::LayersBackend aLayersBackend,
                      mozilla::layers::ImageContainer* aImageContainer,
-                     FlushableTaskQueue* aVideoTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
   // Decode thread.
   already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const AudioInfo& aConfig,
-                     FlushableTaskQueue* aAudioTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
   ConversionRequired
   DecoderNeedsConversion(const TrackInfo& aConfig) const override;
 
   bool SupportsMimeType(const nsACString& aMimeType,
                         DecoderDoctorDiagnostics* aDiagnostics) const override;
--- a/dom/media/platforms/omx/OmxDecoderModule.cpp
+++ b/dom/media/platforms/omx/OmxDecoderModule.cpp
@@ -10,27 +10,27 @@
 #include "OmxPlatformLayer.h"
 
 namespace mozilla {
 
 already_AddRefed<MediaDataDecoder>
 OmxDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig,
                                      mozilla::layers::LayersBackend aLayersBackend,
                                      mozilla::layers::ImageContainer* aImageContainer,
-                                     FlushableTaskQueue* aVideoTaskQueue,
+                                     TaskQueue* aTaskQueue,
                                      MediaDataDecoderCallback* aCallback,
                                      DecoderDoctorDiagnostics* aDiagnostics)
 {
   RefPtr<OmxDataDecoder> decoder = new OmxDataDecoder(aConfig, aCallback, aImageContainer);
   return decoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 OmxDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig,
-                                     FlushableTaskQueue* aAudioTaskQueue,
+                                     TaskQueue* aTaskQueue,
                                      MediaDataDecoderCallback* aCallback,
                                      DecoderDoctorDiagnostics* aDiagnostics)
 {
   RefPtr<OmxDataDecoder> decoder = new OmxDataDecoder(aConfig, aCallback, nullptr);
   return decoder.forget();
 }
 
 PlatformDecoderModule::ConversionRequired
--- a/dom/media/platforms/omx/OmxDecoderModule.h
+++ b/dom/media/platforms/omx/OmxDecoderModule.h
@@ -12,23 +12,23 @@
 namespace mozilla {
 
 class OmxDecoderModule : public PlatformDecoderModule {
 public:
   already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const VideoInfo& aConfig,
                      mozilla::layers::LayersBackend aLayersBackend,
                      mozilla::layers::ImageContainer* aImageContainer,
-                     FlushableTaskQueue* aVideoTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
   already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const AudioInfo& aConfig,
-                     FlushableTaskQueue* aAudioTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
   bool SupportsMimeType(const nsACString& aMimeType,
                         DecoderDoctorDiagnostics* aDiagnostics) const override;
 
   ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override;
 };
--- a/dom/media/platforms/wmf/WMFDecoderModule.cpp
+++ b/dom/media/platforms/wmf/WMFDecoderModule.cpp
@@ -73,50 +73,50 @@ WMFDecoderModule::Startup()
   mWMFInitialized = SUCCEEDED(wmf::MFStartup());
   return mWMFInitialized ? NS_OK : NS_ERROR_FAILURE;
 }
 
 already_AddRefed<MediaDataDecoder>
 WMFDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig,
                                      layers::LayersBackend aLayersBackend,
                                      layers::ImageContainer* aImageContainer,
-                                     FlushableTaskQueue* aVideoTaskQueue,
+                                     TaskQueue* aTaskQueue,
                                      MediaDataDecoderCallback* aCallback,
                                      DecoderDoctorDiagnostics* aDiagnostics)
 {
   nsAutoPtr<WMFVideoMFTManager> manager(
     new WMFVideoMFTManager(aConfig,
                            aLayersBackend,
                            aImageContainer,
                            sDXVAEnabled));
 
   if (!manager->Init()) {
     return nullptr;
   }
 
   RefPtr<MediaDataDecoder> decoder =
-    new WMFMediaDataDecoder(manager.forget(), aVideoTaskQueue, aCallback);
+    new WMFMediaDataDecoder(manager.forget(), aTaskQueue, aCallback);
 
   return decoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 WMFDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig,
-                                     FlushableTaskQueue* aAudioTaskQueue,
+                                     TaskQueue* aTaskQueue,
                                      MediaDataDecoderCallback* aCallback,
                                      DecoderDoctorDiagnostics* aDiagnostics)
 {
   nsAutoPtr<WMFAudioMFTManager> manager(new WMFAudioMFTManager(aConfig));
 
   if (!manager->Init()) {
     return nullptr;
   }
 
   RefPtr<MediaDataDecoder> decoder =
-    new WMFMediaDataDecoder(manager.forget(), aAudioTaskQueue, aCallback);
+    new WMFMediaDataDecoder(manager.forget(), aTaskQueue, aCallback);
   return decoder.forget();
 }
 
 static bool
 CanCreateMFTDecoder(const GUID& aGuid)
 {
   if (FAILED(wmf::MFStartup())) {
     return false;
--- a/dom/media/platforms/wmf/WMFDecoderModule.h
+++ b/dom/media/platforms/wmf/WMFDecoderModule.h
@@ -18,23 +18,23 @@ public:
 
   // Initializes the module, loads required dynamic libraries, etc.
   nsresult Startup() override;
 
   already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const VideoInfo& aConfig,
                      layers::LayersBackend aLayersBackend,
                      layers::ImageContainer* aImageContainer,
-                     FlushableTaskQueue* aVideoTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
   already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const AudioInfo& aConfig,
-                     FlushableTaskQueue* aAudioTaskQueue,
+                     TaskQueue* aTaskQueue,
                      MediaDataDecoderCallback* aCallback,
                      DecoderDoctorDiagnostics* aDiagnostics) override;
 
   bool SupportsMimeType(const nsACString& aMimeType,
                         DecoderDoctorDiagnostics* aDiagnostics) const override;
 
   ConversionRequired
   DecoderNeedsConversion(const TrackInfo& aConfig) const override;
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -14,25 +14,25 @@
 
 namespace mozilla
 {
 
 H264Converter::H264Converter(PlatformDecoderModule* aPDM,
                              const VideoInfo& aConfig,
                              layers::LayersBackend aLayersBackend,
                              layers::ImageContainer* aImageContainer,
-                             FlushableTaskQueue* aVideoTaskQueue,
+                             TaskQueue* aTaskQueue,
                              MediaDataDecoderCallback* aCallback,
                              DecoderDoctorDiagnostics* aDiagnostics)
   : mPDM(aPDM)
   , mOriginalConfig(aConfig)
   , mCurrentConfig(aConfig)
   , mLayersBackend(aLayersBackend)
   , mImageContainer(aImageContainer)
-  , mVideoTaskQueue(aVideoTaskQueue)
+  , mTaskQueue(aTaskQueue)
   , mCallback(aCallback)
   , mDecoder(nullptr)
   , mNeedAVCC(aPDM->DecoderNeedsConversion(aConfig) == PlatformDecoderModule::kNeedAVCC)
   , mLastError(NS_OK)
 {
   CreateDecoder(aDiagnostics);
 }
 
@@ -144,17 +144,17 @@ H264Converter::CreateDecoder(DecoderDoct
     // When using a decoder handling AnnexB, we get here only once from the
     // constructor. We do want to get the dimensions extracted from the SPS.
     mOriginalConfig = mCurrentConfig;
   }
 
   mDecoder = mPDM->CreateVideoDecoder(mNeedAVCC ? mCurrentConfig : mOriginalConfig,
                                       mLayersBackend,
                                       mImageContainer,
-                                      mVideoTaskQueue,
+                                      mTaskQueue,
                                       mCallback,
                                       aDiagnostics);
   if (!mDecoder) {
     mLastError = NS_ERROR_FAILURE;
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
--- a/dom/media/platforms/wrappers/H264Converter.h
+++ b/dom/media/platforms/wrappers/H264Converter.h
@@ -20,17 +20,17 @@ namespace mozilla {
 
 class H264Converter : public MediaDataDecoder {
 public:
 
   H264Converter(PlatformDecoderModule* aPDM,
                 const VideoInfo& aConfig,
                 layers::LayersBackend aLayersBackend,
                 layers::ImageContainer* aImageContainer,
-                FlushableTaskQueue* aVideoTaskQueue,
+                TaskQueue* aTaskQueue,
                 MediaDataDecoderCallback* aCallback,
                 DecoderDoctorDiagnostics* aDiagnostics);
   virtual ~H264Converter();
 
   RefPtr<InitPromise> Init() override;
   nsresult Input(MediaRawData* aSample) override;
   nsresult Flush() override;
   nsresult Drain() override;
@@ -60,17 +60,17 @@ private:
   void OnDecoderInitDone(const TrackType aTrackType);
   void OnDecoderInitFailed(MediaDataDecoder::DecoderFailureReason aReason);
 
   RefPtr<PlatformDecoderModule> mPDM;
   VideoInfo mOriginalConfig;
   VideoInfo mCurrentConfig;
   layers::LayersBackend mLayersBackend;
   RefPtr<layers::ImageContainer> mImageContainer;
-  RefPtr<FlushableTaskQueue> mVideoTaskQueue;
+  const RefPtr<TaskQueue> mTaskQueue;
   nsTArray<RefPtr<MediaRawData>> mMediaRawSamples;
   MediaDataDecoderCallback* mCallback;
   RefPtr<MediaDataDecoder> mDecoder;
   MozPromiseRequestHolder<InitPromise> mInitPromiseRequest;
   bool mNeedAVCC;
   nsresult mLastError;
 };
 
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -124,16 +124,17 @@ skip-if = buildapp == 'b2g' || buildapp 
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_bug834153.html]
 [test_peerConnection_bug1013809.html]
 skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
 [test_peerConnection_bug1042791.html]
 skip-if = buildapp == 'b2g' || buildapp == 'mulet' || os == 'android' # bug 1043403 # Bug 1141029 Mulet parity with B2G Desktop for TC
 [test_peerConnection_bug1064223.html]
 [test_peerConnection_capturedVideo.html]
+subsuite = clipboard
 tags=capturestream
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_captureStream_canvas_2d.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_multiple_captureStream_canvas_2d.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_captureStream_canvas_webgl.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
--- a/dom/presentation/PresentationReceiver.cpp
+++ b/dom/presentation/PresentationReceiver.cpp
@@ -62,33 +62,18 @@ PresentationReceiver::Init()
   mWindowId = GetOwner()->WindowID();
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if (NS_WARN_IF(!service)) {
     return false;
   }
 
-  // A session may already be connecting before the web content
-  // request for access in a receiving browsing context.
-  nsAutoString sessionId;
-  nsresult rv = service->GetExistentSessionIdAtLaunch(mWindowId, sessionId);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return false;
-  }
-
-  if (!sessionId.IsEmpty()) {
-    rv = NotifySessionConnect(mWindowId, sessionId);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return false;
-    }
-  }
-
   // Register listener for incoming sessions.
-  rv = service->RegisterRespondingListener(mWindowId, this);
+  nsresult rv = service->RegisterRespondingListener(mWindowId, this);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
 
   return true;
 }
 
 void PresentationReceiver::Shutdown()
--- a/dom/presentation/PresentationService.cpp
+++ b/dom/presentation/PresentationService.cpp
@@ -143,17 +143,20 @@ PresentationDeviceRequest::Cancel()
 
   return info->ReplyError(NS_ERROR_DOM_ABORT_ERR);
 }
 
 /*
  * Implementation of PresentationService
  */
 
-NS_IMPL_ISUPPORTS(PresentationService, nsIPresentationService, nsIObserver)
+NS_IMPL_ISUPPORTS_INHERITED(PresentationService,
+                            PresentationServiceBase,
+                            nsIPresentationService,
+                            nsIObserver)
 
 PresentationService::PresentationService()
   : mIsAvailable(false)
 {
 }
 
 PresentationService::~PresentationService()
 {
@@ -220,21 +223,21 @@ PresentationService::Observe(nsISupports
   return NS_ERROR_UNEXPECTED;
 }
 
 void
 PresentationService::HandleShutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+  Shutdown();
+
   mAvailabilityListeners.Clear();
-  mRespondingListeners.Clear();
   mSessionInfoAtController.Clear();
   mSessionInfoAtReceiver.Clear();
-  mRespondingSessionIds.Clear();
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (obs) {
     obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
     obs->RemoveObserver(this, PRESENTATION_DEVICE_CHANGE_TOPIC);
     obs->RemoveObserver(this, PRESENTATION_SESSION_REQUEST_TOPIC);
   }
 }
@@ -401,22 +404,17 @@ PresentationService::StartSession(const 
   MOZ_ASSERT(!aSessionId.IsEmpty());
 
   // Create session info  and set the callback. The callback is called when the
   // request is finished.
   RefPtr<PresentationSessionInfo> info =
     new PresentationControllingInfo(aUrl, aSessionId, aCallback);
   mSessionInfoAtController.Put(aSessionId, info);
 
-  // Only track the info when an actual window ID, which would never be 0, is
-  // provided (for an in-process sender page).
-  if (aWindowId != 0) {
-    mRespondingSessionIds.Put(aWindowId, new nsString(aSessionId));
-    mRespondingWindowIds.Put(aSessionId, aWindowId);
-  }
+  AddRespondingSessionId(aWindowId, aSessionId);
 
   nsCOMPtr<nsIPresentationDeviceRequest> request =
     new PresentationDeviceRequest(aUrl, aSessionId, aOrigin);
 
   if (aDeviceId.IsVoid()) {
     // Pop up a prompt and ask user to select a device.
     nsCOMPtr<nsIPresentationDevicePrompt> prompt =
       do_GetService(PRESENTATION_DEVICE_PROMPT_CONTRACTID);
@@ -586,27 +584,37 @@ PresentationService::UnregisterSessionLi
     NS_WARN_IF(NS_FAILED(info->Close(NS_OK, nsIPresentationSessionListener::STATE_TERMINATED)));
     UntrackSessionInfo(aSessionId, aRole);
     return info->SetListener(nullptr);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PresentationService::RegisterRespondingListener(uint64_t aWindowId,
-                                                nsIPresentationRespondingListener* aListener)
+PresentationService::RegisterRespondingListener(
+  uint64_t aWindowId,
+  nsIPresentationRespondingListener* aListener)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aListener);
 
   nsCOMPtr<nsIPresentationRespondingListener> listener;
   if (mRespondingListeners.Get(aWindowId, getter_AddRefs(listener))) {
     return (listener == aListener) ? NS_OK : NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
+  nsTArray<nsString>* sessionIdArray;
+  if (!mRespondingSessionIds.Get(aWindowId, &sessionIdArray)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  for (const auto& id : *sessionIdArray) {
+    aListener->NotifySessionConnect(aWindowId, id);
+  }
+
   mRespondingListeners.Put(aWindowId, aListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationService::UnregisterRespondingListener(uint64_t aWindowId)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -614,42 +622,37 @@ PresentationService::UnregisterRespondin
   mRespondingListeners.Remove(aWindowId);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationService::GetExistentSessionIdAtLaunch(uint64_t aWindowId,
                                                   nsAString& aSessionId)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-
-  nsString* sessionId = mRespondingSessionIds.Get(aWindowId);
-  if (sessionId) {
-    aSessionId.Assign(*sessionId);
-  } else {
-    aSessionId.Truncate();
-  }
-  return NS_OK;
+  return GetExistentSessionIdAtLaunchInternal(aWindowId, aSessionId);
 }
 
 NS_IMETHODIMP
 PresentationService::NotifyReceiverReady(const nsAString& aSessionId,
                                          uint64_t aWindowId)
 {
   RefPtr<PresentationSessionInfo> info =
     GetSessionInfo(aSessionId, nsIPresentationService::ROLE_RECEIVER);
   if (NS_WARN_IF(!info)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  // Only track the responding info when an actual window ID, which would never
-  // be 0, is provided (for an in-process receiver page).
-  if (aWindowId != 0) {
-    mRespondingSessionIds.Put(aWindowId, new nsString(aSessionId));
-    mRespondingWindowIds.Put(aSessionId, aWindowId);
+  AddRespondingSessionId(aWindowId, aSessionId);
+
+  nsCOMPtr<nsIPresentationRespondingListener> listener;
+  if (mRespondingListeners.Get(aWindowId, getter_AddRefs(listener))) {
+    nsresult rv = listener->NotifySessionConnect(aWindowId, aSessionId);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
 
   return static_cast<PresentationPresentingInfo*>(info.get())->NotifyResponderReady();
 }
 
 NS_IMETHODIMP
 PresentationService::UntrackSessionInfo(const nsAString& aSessionId,
                                         uint8_t aRole)
@@ -659,33 +662,26 @@ PresentationService::UntrackSessionInfo(
   // Remove the session info.
   if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
     mSessionInfoAtController.Remove(aSessionId);
   } else {
     mSessionInfoAtReceiver.Remove(aSessionId);
   }
 
   // Remove the in-process responding info if there's still any.
-  uint64_t windowId = 0;
-  if (mRespondingWindowIds.Get(aSessionId, &windowId)) {
-    mRespondingWindowIds.Remove(aSessionId);
-    mRespondingSessionIds.Remove(windowId);
-  }
+  RemoveRespondingSessionId(aSessionId);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationService::GetWindowIdBySessionId(const nsAString& aSessionId,
                                             uint64_t* aWindowId)
 {
-  if (mRespondingWindowIds.Get(aSessionId, aWindowId)) {
-    return NS_OK;
-  }
-  return NS_ERROR_NOT_AVAILABLE;
+  return GetWindowIdBySessionIdInternal(aSessionId, aWindowId);
 }
 
 bool
 PresentationService::IsSessionAccessible(const nsAString& aSessionId,
                                          const uint8_t aRole,
                                          base::ProcessId aProcessId)
 {
   MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
--- a/dom/presentation/PresentationService.h
+++ b/dom/presentation/PresentationService.h
@@ -4,33 +4,34 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_PresentationService_h
 #define mozilla_dom_PresentationService_h
 
 #include "nsCOMPtr.h"
 #include "nsIObserver.h"
-#include "nsRefPtrHashtable.h"
 #include "nsTObserverArray.h"
+#include "PresentationServiceBase.h"
 #include "PresentationSessionInfo.h"
 
 class nsIPresentationSessionRequest;
 class nsIURI;
 
 namespace mozilla {
 namespace dom {
 
 class PresentationRespondingInfo;
 
 class PresentationService final : public nsIPresentationService
                                 , public nsIObserver
+                                , public PresentationServiceBase
 {
 public:
-  NS_DECL_ISUPPORTS
+  NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIPRESENTATIONSERVICE
 
   PresentationService();
   bool Init();
 
   already_AddRefed<PresentationSessionInfo>
   GetSessionInfo(const nsAString& aSessionId, const uint8_t aRole)
@@ -48,41 +49,25 @@ public:
     }
   }
 
   bool IsSessionAccessible(const nsAString& aSessionId,
                            const uint8_t aRole,
                            base::ProcessId aProcessId);
 
 private:
-  ~PresentationService();
+  virtual ~PresentationService();
   void HandleShutdown();
   nsresult HandleDeviceChange();
   nsresult HandleSessionRequest(nsIPresentationSessionRequest* aRequest);
   void NotifyAvailableChange(bool aIsAvailable);
   bool IsAppInstalled(nsIURI* aUri);
 
   bool mIsAvailable;
   nsTObserverArray<nsCOMPtr<nsIPresentationAvailabilityListener>> mAvailabilityListeners;
-
-  // Store the responding listener based on the window ID of the (in-process or
-  // OOP) receiver page.
-  // TODO Bug 1195605 - Support many-to-one session.
-  // So far responding listeners are registered but |notifySessionConnect| hasn't
-  // been called in any place until many-to-one session becomes supported.
-  nsRefPtrHashtable<nsUint64HashKey, nsIPresentationRespondingListener> mRespondingListeners;
-
   nsRefPtrHashtable<nsStringHashKey, PresentationSessionInfo> mSessionInfoAtController;
   nsRefPtrHashtable<nsStringHashKey, PresentationSessionInfo> mSessionInfoAtReceiver;
-
-  // Store the mapping between the window ID of the in-process page and the ID
-  // of the responding session. It's used for an in-process receiver page to
-  // retrieve the correspondent session ID. Besides, also keep the mapping
-  // between the responding session ID and the window ID to help look up the
-  // window ID.
-  nsClassHashtable<nsUint64HashKey, nsString> mRespondingSessionIds;
-  nsDataHashtable<nsStringHashKey, uint64_t> mRespondingWindowIds;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_PresentationService_h
new file mode 100644
--- /dev/null
+++ b/dom/presentation/PresentationServiceBase.cpp
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "PresentationServiceBase.h"
+
+#include "nsString.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_ISUPPORTS0(PresentationServiceBase)
+
+nsresult
+PresentationServiceBase::GetExistentSessionIdAtLaunchInternal(
+  uint64_t aWindowId,
+  nsAString& aSessionId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsTArray<nsString>* sessionIdArray;
+  if (mRespondingSessionIds.Get(aWindowId, &sessionIdArray) &&
+      !sessionIdArray->IsEmpty()) {
+    aSessionId.Assign((*sessionIdArray)[0]);
+  }
+  else {
+    aSessionId.Truncate();
+  }
+  return NS_OK;
+}
+
+nsresult
+PresentationServiceBase::GetWindowIdBySessionIdInternal(
+  const nsAString& aSessionId,
+  uint64_t* aWindowId)
+{
+  if (mRespondingWindowIds.Get(aSessionId, aWindowId)) {
+    return NS_OK;
+  }
+  return NS_ERROR_NOT_AVAILABLE;
+}
+
+void
+PresentationServiceBase::AddRespondingSessionId(uint64_t aWindowId,
+                                                const nsAString& aSessionId)
+{
+  if (NS_WARN_IF(aWindowId == 0)) {
+    return;
+  }
+
+  nsTArray<nsString>* sessionIdArray;
+  if (!mRespondingSessionIds.Get(aWindowId, &sessionIdArray)) {
+    sessionIdArray = new nsTArray<nsString>();
+    mRespondingSessionIds.Put(aWindowId, sessionIdArray);
+  }
+
+  sessionIdArray->AppendElement(nsString(aSessionId));
+  mRespondingWindowIds.Put(aSessionId, aWindowId);
+}
+
+void
+PresentationServiceBase::RemoveRespondingSessionId(const nsAString& aSessionId)
+{
+  uint64_t windowId = 0;
+  if (mRespondingWindowIds.Get(aSessionId, &windowId)) {
+    mRespondingWindowIds.Remove(aSessionId);
+    nsTArray<nsString>* sessionIdArray;
+    if (mRespondingSessionIds.Get(windowId, &sessionIdArray)) {
+      sessionIdArray->RemoveElement(nsString(aSessionId));
+      if (sessionIdArray->IsEmpty()) {
+        mRespondingSessionIds.Remove(windowId);
+      }
+    }
+  }
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/presentation/PresentationServiceBase.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PresentationServiceBase_h
+#define mozilla_dom_PresentationServiceBase_h
+
+#include "nsRefPtrHashtable.h"
+#include "nsTArray.h"
+
+class nsIPresentationRespondingListener;
+class nsString;
+
+namespace mozilla {
+namespace dom {
+
+class PresentationServiceBase : public nsISupports
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  PresentationServiceBase() = default;
+
+protected:
+  virtual ~PresentationServiceBase() = default;
+
+  void Shutdown()
+  {
+    mRespondingListeners.Clear();
+    mRespondingSessionIds.Clear();
+    mRespondingWindowIds.Clear();
+  }
+  nsresult GetExistentSessionIdAtLaunchInternal(uint64_t aWindowId, nsAString& aSessionId);
+  nsresult GetWindowIdBySessionIdInternal(const nsAString& aSessionId, uint64_t* aWindowId);
+  void AddRespondingSessionId(uint64_t aWindowId, const nsAString& aSessionId);
+  void RemoveRespondingSessionId(const nsAString& aSessionId);
+
+  // Store the responding listener based on the window ID of the (in-process or
+  // OOP) receiver page.
+  nsRefPtrHashtable<nsUint64HashKey, nsIPresentationRespondingListener> mRespondingListeners;
+
+  // Store the mapping between the window ID of the in-process and OOP page and the ID
+  // of the responding session. It's used for an receiver page to retrieve
+  // the correspondent session ID. Besides, also keep the mapping
+  // between the responding session ID and the window ID to help look up the
+  // window ID.
+  nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mRespondingSessionIds;
+  nsDataHashtable<nsStringHashKey, uint64_t> mRespondingWindowIds;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PresentationServiceBase_h
--- a/dom/presentation/ipc/PPresentation.ipdl
+++ b/dom/presentation/ipc/PPresentation.ipdl
@@ -13,16 +13,17 @@ namespace mozilla {
 namespace dom {
 
 struct StartSessionRequest
 {
   nsString url;
   nsString sessionId;
   nsString origin;
   nsString deviceId;
+  uint64_t windowId;
 };
 
 struct SendSessionMessageRequest
 {
   nsString sessionId;
   uint8_t role;
   nsString data;
 };
@@ -67,13 +68,13 @@ parent:
   async RegisterSessionHandler(nsString aSessionId, uint8_t aRole);
   async UnregisterSessionHandler(nsString aSessionId, uint8_t aRole);
 
   async RegisterRespondingHandler(uint64_t aWindowId);
   async UnregisterRespondingHandler(uint64_t aWindowId);
 
   async PPresentationRequest(PresentationIPCRequest aRequest);
 
-  async NotifyReceiverReady(nsString aSessionId);
+  async NotifyReceiverReady(nsString aSessionId, uint64_t aWindowId);
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/presentation/ipc/PresentationIPCService.cpp
+++ b/dom/presentation/ipc/PresentationIPCService.cpp
@@ -18,55 +18,57 @@ using namespace mozilla::dom;
 using namespace mozilla::ipc;
 
 namespace {
 
 PresentationChild* sPresentationChild;
 
 } // anonymous
 
-NS_IMPL_ISUPPORTS(PresentationIPCService, nsIPresentationService)
+NS_IMPL_ISUPPORTS_INHERITED(PresentationIPCService,
+                            PresentationServiceBase,
+                            nsIPresentationService)
 
 PresentationIPCService::PresentationIPCService()
 {
   ContentChild* contentChild = ContentChild::GetSingleton();
   if (NS_WARN_IF(!contentChild)) {
     return;
   }
   sPresentationChild = new PresentationChild(this);
   NS_WARN_IF(!contentChild->SendPPresentationConstructor(sPresentationChild));
 }
 
 /* virtual */
 PresentationIPCService::~PresentationIPCService()
 {
+  Shutdown();
+
   mAvailabilityListeners.Clear();
   mSessionListeners.Clear();
-  mRespondingSessionIds.Clear();
-  mRespondingWindowIds.Clear();
   sPresentationChild = nullptr;
 }
 
 NS_IMETHODIMP
 PresentationIPCService::StartSession(const nsAString& aUrl,
                                      const nsAString& aSessionId,
                                      const nsAString& aOrigin,
                                      const nsAString& aDeviceId,
                                      uint64_t aWindowId,
                                      nsIPresentationServiceCallback* aCallback)
 {
   if (aWindowId != 0) {
-    mRespondingSessionIds.Put(aWindowId, new nsString(aSessionId));
-    mRespondingWindowIds.Put(aSessionId, aWindowId);
+    AddRespondingSessionId(aWindowId, aSessionId);
   }
 
   return SendRequest(aCallback, StartSessionRequest(nsString(aUrl),
                                                     nsString(aSessionId),
                                                     nsString(aOrigin),
-                                                    nsString(aDeviceId)));
+                                                    nsString(aDeviceId),
+                                                    aWindowId));
 }
 
 NS_IMETHODIMP
 PresentationIPCService::SendSessionMessage(const nsAString& aSessionId,
                                            uint8_t aRole,
                                            const nsAString& aData)
 {
   MOZ_ASSERT(!aSessionId.IsEmpty());
@@ -186,20 +188,17 @@ PresentationIPCService::UnregisterRespon
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationIPCService::GetWindowIdBySessionId(const nsAString& aSessionId,
                                                uint64_t* aWindowId)
 {
-  if (mRespondingWindowIds.Get(aSessionId, aWindowId)) {
-    return NS_OK;
-  }
-  return NS_ERROR_NOT_AVAILABLE;
+  return GetWindowIdBySessionIdInternal(aSessionId, aWindowId);
 }
 
 nsresult
 PresentationIPCService::NotifySessionStateChange(const nsAString& aSessionId,
                                                  uint16_t aState)
 {
   nsCOMPtr<nsIPresentationSessionListener> listener;
   if (NS_WARN_IF(!mSessionListeners.Get(aSessionId, getter_AddRefs(listener)))) {
@@ -244,61 +243,48 @@ PresentationIPCService::NotifyAvailableC
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationIPCService::GetExistentSessionIdAtLaunch(uint64_t aWindowId,
                                                      nsAString& aSessionId)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-
-  nsString* sessionId = mRespondingSessionIds.Get(aWindowId);
-  if (sessionId) {
-    aSessionId.Assign(*sessionId);
-  } else {
-    aSessionId.Truncate();
-  }
-  return NS_OK;
+  return GetExistentSessionIdAtLaunchInternal(aWindowId, aSessionId);;
 }
 
 NS_IMETHODIMP
 PresentationIPCService::NotifyReceiverReady(const nsAString& aSessionId,
                                             uint64_t aWindowId)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // No actual window uses 0 as its ID.
   if (NS_WARN_IF(aWindowId == 0)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Track the responding info for an OOP receiver page.
-  mRespondingSessionIds.Put(aWindowId, new nsString(aSessionId));
-  mRespondingWindowIds.Put(aSessionId, aWindowId);
+  AddRespondingSessionId(aWindowId, aSessionId);
 
-  NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsString(aSessionId)));
+  NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsString(aSessionId),
+                                                          aWindowId));
 
   // Release mCallback after using aSessionId
   // because aSessionId is held by mCallback.
   mCallback = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationIPCService::UntrackSessionInfo(const nsAString& aSessionId,
                                            uint8_t aRole)
 {
   // Remove the OOP responding info (if it has never been used).
-  uint64_t windowId = 0;
-  if (mRespondingWindowIds.Get(aSessionId, &windowId)) {
-    mRespondingWindowIds.Remove(aSessionId);
-    mRespondingSessionIds.Remove(windowId);
-  }
-
+  RemoveRespondingSessionId(aSessionId);
   return NS_OK;
 }
 
 void
 PresentationIPCService::NotifyPresentationChildDestroyed()
 {
   sPresentationChild = nullptr;
 }
--- a/dom/presentation/ipc/PresentationIPCService.h
+++ b/dom/presentation/ipc/PresentationIPCService.h
@@ -2,32 +2,33 @@
 /* vim: set sw=2 ts=8 et ft=cpp : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_PresentationIPCService_h
 #define mozilla_dom_PresentationIPCService_h
 
+#include "mozilla/dom/PresentationServiceBase.h"
 #include "nsIPresentationService.h"
-#include "nsRefPtrHashtable.h"
 #include "nsTObserverArray.h"
 
 class nsIDocShell;
 
 namespace mozilla {
 namespace dom {
 
 class PresentationIPCRequest;
 class PresentationResponderLoadingCallback;
 
 class PresentationIPCService final : public nsIPresentationService
+                                   , public PresentationServiceBase
 {
 public:
-  NS_DECL_ISUPPORTS
+  NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIPRESENTATIONSERVICE
 
   PresentationIPCService();
 
   nsresult NotifyAvailableChange(bool aAvailable);
 
   nsresult NotifySessionStateChange(const nsAString& aSessionId,
                                     uint16_t aState);
@@ -45,24 +46,15 @@ public:
 
 private:
   virtual ~PresentationIPCService();
   nsresult SendRequest(nsIPresentationServiceCallback* aCallback,
                        const PresentationIPCRequest& aRequest);
 
   nsTObserverArray<nsCOMPtr<nsIPresentationAvailabilityListener> > mAvailabilityListeners;
   nsRefPtrHashtable<nsStringHashKey, nsIPresentationSessionListener> mSessionListeners;
-  nsRefPtrHashtable<nsUint64HashKey, nsIPresentationRespondingListener> mRespondingListeners;
   RefPtr<PresentationResponderLoadingCallback> mCallback;
-
-  // Store the mapping between the window ID of the OOP page (in this process)
-  // and the ID of the responding session. It's used for an OOP receiver page
-  // to retrieve the correspondent session ID. Besides, also keep the mapping
-  // between the responding session ID and the window ID to help look up the
-  // window ID.
-  nsClassHashtable<nsUint64HashKey, nsString> mRespondingSessionIds;
-  nsDataHashtable<nsStringHashKey, uint64_t> mRespondingWindowIds;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_PresentationIPCService_h
--- a/dom/presentation/ipc/PresentationParent.cpp
+++ b/dom/presentation/ipc/PresentationParent.cpp
@@ -227,22 +227,23 @@ PresentationParent::NotifySessionConnect
   if (NS_WARN_IF(mActorDestroyed ||
                  !SendNotifySessionConnect(aWindowId, nsString(aSessionId)))) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 bool
-PresentationParent::RecvNotifyReceiverReady(const nsString& aSessionId)
+PresentationParent::RecvNotifyReceiverReady(const nsString& aSessionId,
+                                            const uint64_t& aWindowId)
 {
   MOZ_ASSERT(mService);
 
   // Set window ID to 0 since the window is from content process.
-  NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId, 0)));
+  NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId, aWindowId)));
   return true;
 }
 
 /*
  * Implementation of PresentationRequestParent
  */
 
 NS_IMPL_ISUPPORTS(PresentationRequestParent, nsIPresentationServiceCallback)
@@ -268,17 +269,18 @@ PresentationRequestParent::ActorDestroy(
 
 nsresult
 PresentationRequestParent::DoRequest(const StartSessionRequest& aRequest)
 {
   MOZ_ASSERT(mService);
 
   // Set window ID to 0 since the window is from content process.
   return mService->StartSession(aRequest.url(), aRequest.sessionId(),
-                                aRequest.origin(), aRequest.deviceId(), 0, this);
+                                aRequest.origin(), aRequest.deviceId(),
+                                aRequest.windowId(), this);
 }
 
 nsresult
 PresentationRequestParent::DoRequest(const SendSessionMessageRequest& aRequest)
 {
   MOZ_ASSERT(mService);
 
   // Validate the accessibility (primarily for receiver side) so that a
--- a/dom/presentation/ipc/PresentationParent.h
+++ b/dom/presentation/ipc/PresentationParent.h
@@ -53,17 +53,18 @@ public:
 
   virtual bool RecvUnregisterSessionHandler(const nsString& aSessionId,
                                             const uint8_t& aRole) override;
 
   virtual bool RecvRegisterRespondingHandler(const uint64_t& aWindowId) override;
 
   virtual bool RecvUnregisterRespondingHandler(const uint64_t& aWindowId) override;
 
-  virtual bool RecvNotifyReceiverReady(const nsString& aSessionId) override;
+  virtual bool RecvNotifyReceiverReady(const nsString& aSessionId,
+                                       const uint64_t& aWindowId) override;
 
 private:
   virtual ~PresentationParent();
 
   bool mActorDestroyed;
   nsCOMPtr<nsIPresentationService> mService;
   nsTArray<nsString> mSessionIdsAtController;
   nsTArray<nsString> mSessionIdsAtReceiver;
--- a/dom/presentation/moz.build
+++ b/dom/presentation/moz.build
@@ -17,32 +17,34 @@ EXPORTS.mozilla.dom += [
     'Presentation.h',
     'PresentationAvailability.h',
     'PresentationCallbacks.h',
     'PresentationConnection.h',
     'PresentationDeviceManager.h',
     'PresentationReceiver.h',
     'PresentationRequest.h',
     'PresentationService.h',
+    'PresentationServiceBase.h',
     'PresentationSessionInfo.h',
     'PresentationTCPSessionTransport.h',
 ]
 
 UNIFIED_SOURCES += [
     'ipc/PresentationChild.cpp',
     'ipc/PresentationIPCService.cpp',
     'ipc/PresentationParent.cpp',
     'Presentation.cpp',
     'PresentationAvailability.cpp',
     'PresentationCallbacks.cpp',
     'PresentationConnection.cpp',
     'PresentationDeviceManager.cpp',
     'PresentationReceiver.cpp',
     'PresentationRequest.cpp',
     'PresentationService.cpp',
+    'PresentationServiceBase.cpp',
     'PresentationSessionInfo.cpp',
     'PresentationSessionRequest.cpp',
     'PresentationTCPSessionTransport.cpp',
 ]
 
 EXTRA_COMPONENTS += [
     'PresentationDataChannelSessionTransport.js',
     'PresentationDataChannelSessionTransport.manifest',
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -87,16 +87,19 @@ DoCheckLoadURIChecks(nsIURI* aURI, nsILo
 
   nsresult rv = NS_OK;
 
   nsCOMPtr<nsIPrincipal> loadingPrincipal = aLoadInfo->LoadingPrincipal();
   uint32_t flags = nsIScriptSecurityManager::STANDARD;
   if (aLoadInfo->GetAllowChrome()) {
     flags |= nsIScriptSecurityManager::ALLOW_CHROME;
   }
+  if (aLoadInfo->GetDisallowScript()) {
+    flags |= nsIScriptSecurityManager::DISALLOW_SCRIPT;
+  }
 
   bool isImageInEditorType = IsImageLoadInEditorAppType(aLoadInfo);
 
   // We don't have a loadingPrincipal for TYPE_DOCUMENT
   if (aLoadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT &&
       !isImageInEditorType) {
     rv = nsContentUtils::GetSecurityManager()->
       CheckLoadURIWithPrincipal(loadingPrincipal,
--- a/dom/tests/mochitest/general/mochitest.ini
+++ b/dom/tests/mochitest/general/mochitest.ini
@@ -61,16 +61,17 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bug628069_2.html]
 [test_bug631440.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug653364.html]
 [test_bug861217.html]
 [test_clientRects.html]
 [test_clipboard_disallowed.html]
 [test_clipboard_events.html]
+subsuite = clipboard
 skip-if = buildapp == 'b2g' # b2g(clipboard undefined) b2g-debug(clipboard undefined) b2g-desktop(clipboard undefined)
 [test_consoleAPI.html]
 [test_DOMMatrix.html]
 [test_domWindowUtils.html]
 [test_domWindowUtils_scrollXY.html]
 [test_domWindowUtils_scrollbarSize.html]
 [test_donottrack.html]
 skip-if = buildapp == 'mulet'
@@ -115,17 +116,19 @@ run-if = e10s
 [test_windowProperties.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_windowedhistoryframes.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_navigation_timing.html]
 skip-if = buildapp == 'b2g' || buildapp == 'mulet'
 [test_bug1012662_editor.html]
 skip-if = (toolkit == 'android') # Disabled on Android, see bug 1230231
+subsuite = clipboard
 [test_bug1012662_noeditor.html]
+subsuite = clipboard
 skip-if = (toolkit == 'android') # Disabled on Android, see bug 1230231
 [test_bug1161721.html]
 [test_bug1170911.html]
 [test_storagePermissionsAccept.html]
 skip-if = buildapp == 'b2g' # Bug 1184427 - no SSL certs on b2g
 [test_storagePermissionsRejectForeign.html]
 skip-if = buildapp == 'b2g' # Bug 1184427 - no SSL certs on b2g
 [test_storagePermissionsReject.html]
--- a/dom/tests/unit/test_Fetch.js
+++ b/dom/tests/unit/test_Fetch.js
@@ -115,17 +115,17 @@ add_test(function test_GetData() {
   }).catch(function(e){
     do_report_unexpected_exception(e);
     do_test_finished();
     run_next_test();
   });
 });
 
 // test a GET with no init
-add_test(function test_GetData() {
+add_test(function test_GetDataNoInit() {
   do_test_pending();
 
   let testData = createTestData("/getData");
 
   server.registerPathHandler(testData.testPath, function(aRequest, aResponse) {
     try {
       // send a response
       writeDataToResponse(testData.response, aResponse);
@@ -198,17 +198,17 @@ add_test(function test_get50x() {
     run_next_test();
   });
 });
 
 // test a failure to connect
 add_test(function test_getTestFailedConnect() {
   do_test_pending();
   // try a server that's not there
-  fetch("ftp://localhost/should/fail").then(response => {
+  fetch("http://localhost:4/should/fail").then(response => {
     do_throw("Request should not succeed");
   }).catch(err => {
     do_check_eq(true, err instanceof TypeError);
     do_test_finished();
     run_next_test();
   });
 });
 
@@ -251,17 +251,17 @@ add_test(function test_PostJSONData() {
   }).catch(function(e) {
     do_report_unexpected_exception(e);
     do_test_finished();
     run_next_test();
   });
 });
 
 // test POSTing some text
-add_test(function test_PostJSONData() {
+add_test(function test_PostTextData() {
   do_test_pending();
 
   let testData = createTestData("/postTextData");
   testData.request.body = "A plain text body";
   testData.request.contentType = "text/plain";
   let responseHeaderName = "some-response-header";
   testData.response.headers[responseHeaderName] = "some header value";
 
--- a/dom/webidl/Node.webidl
+++ b/dom/webidl/Node.webidl
@@ -29,16 +29,18 @@ interface Node : EventTarget {
   [Constant]
   readonly attribute unsigned short nodeType;
   [Pure]
   readonly attribute DOMString nodeName;
 
   [Pure]
   readonly attribute DOMString? baseURI;
 
+  [Pure, BinaryName=getComposedDoc]
+  readonly attribute boolean isConnected;
   [Pure]
   readonly attribute Document? ownerDocument;
   [Pure, Pref="dom.node.rootNode.enabled"]
   readonly attribute Node rootNode;
   [Pure]
   readonly attribute Node? parentNode;
   [Pure]
   readonly attribute Element? parentElement;
--- a/editor/libeditor/tests/browserscope/mochitest.ini
+++ b/editor/libeditor/tests/browserscope/mochitest.ini
@@ -49,11 +49,12 @@ support-files =
   lib/richtext/LICENSE
   lib/richtext/README.Mozilla
   lib/richtext/richtext/editable.html
   lib/richtext/richtext/richtext.html
   lib/richtext/richtext/js/range.js
   lib/richtext/currentStatus.js
 
 [test_richtext2.html]
+subsuite = clipboard
 skip-if = os == 'android' && debug # Bug 1202045
 [test_richtext.html]
 
--- a/editor/libeditor/tests/chrome.ini
+++ b/editor/libeditor/tests/chrome.ini
@@ -4,33 +4,37 @@ support-files = green.png
 
 [test_bug46555.html]
 [test_bug366682.html]
 support-files = spellcheck.js
 [test_bug471319.html]
 [test_bug483651.html]
 [test_bug489202.xul]
 [test_bug490879.xul]
+subsuite = clipboard
 [test_bug569988.html]
 skip-if = buildapp == 'mulet'
 [test_bug599983.xul]
 skip-if = buildapp == 'mulet'
 [test_bug607584.xul]
 [test_bug616590.xul]
 [test_bug635636.html]
 [test_bug636465.xul]
 [test_bug646194.xul]
 [test_bug780908.xul]
 [test_bug830600.html]
+subsuite = clipboard
 [test_bug1053048.html]
 [test_bug1100966.html]
 [test_bug1102906.html]
 [test_bug1101392.html]
+subsuite = clipboard
 [test_bug1140105.html]
 [test_bug1140617.xul]
+subsuite = clipboard
 [test_bug1153237.html]
 [test_bug1154791.html]
 [test_bug1248128.html]
 [test_bug1248185.html]
 [test_bug1250010.html]
 [test_bug1257363.html]
 [test_composition_event_created_in_chrome.html]
 [test_contenteditable_text_input_handling.html]
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -25,74 +25,84 @@ skip-if = os != "mac"
 [test_bug332636.html]
 support-files = test_bug332636.html^headers^
 [test_bug372345.html]
 skip-if = toolkit == 'android'
 [test_bug404320.html]
 [test_bug408231.html]
 skip-if = toolkit == 'android'
 [test_bug410986.html]
+subsuite = clipboard
 skip-if = toolkit == 'android'
 [test_bug414526.html]
 [test_bug417418.html]
 skip-if = android_version == '18' # bug 1147989
 [test_bug432225.html]
 skip-if = toolkit == 'android'
 [test_bug439808.html]
 [test_bug442186.html]
 [test_bug449243.html]
 [test_bug455992.html]
 [test_bug456244.html]
 [test_bug460740.html]
 [test_bug468353.html]
 [test_bug471722.html]
 [test_bug478725.html]
+subsuite = clipboard
 skip-if = toolkit == 'android'
 [test_bug480647.html]
 [test_bug480972.html]
+subsuite = clipboard
 skip-if = toolkit == 'android'
 [test_bug484181.html]
 skip-if = toolkit == 'android'
 [test_bug487524.html]
 [test_bug502673.html]
 [test_bug514156.html]
 [test_bug520189.html]
+subsuite = clipboard
 skip-if = toolkit == 'android'
 [test_bug525389.html]
+subsuite = clipboard
 skip-if = toolkit == 'android'
 [test_bug537046.html]
 [test_bug549262.html]
 skip-if = toolkit == 'android'
 [test_bug550434.html]
 skip-if = android_version == '18' # bug 1147989
 [test_bug551704.html]
+subsuite = clipboard
 [test_bug552782.html]
 [test_bug567213.html]
 [test_bug570144.html]
 [test_bug578771.html]
 skip-if = android_version == '18' # bug 1147989
 [test_bug586662.html]
 skip-if = toolkit == 'android'
 [test_bug587461.html]
 [test_bug590554.html]
 [test_bug592592.html]
 [test_bug596001.html]
+subsuite = clipboard
 [test_bug596333.html]
 skip-if = toolkit == 'android'
 [test_bug596506.html]
 [test_bug597331.html]
 skip-if = buildapp == 'mulet' || toolkit == 'android' || asan || (os == "win" && os_version != "5.1") # Bug 718316, Bug 1211213
 [test_bug597784.html]
 [test_bug599322.html]
+subsuite = clipboard
 skip-if = toolkit == 'android'
 [test_bug599983.html]
 [test_bug600570.html]
+subsuite = clipboard
 skip-if = toolkit == 'android' || (os == "win" && os_version != "5.1") # Bug 718316
 [test_bug602130.html]
 [test_bug603556.html]
+subsuite = clipboard
 [test_bug604532.html]
 skip-if = toolkit == 'android'
 [test_bug607584.html]
 [test_bug611182.html]
 skip-if = toolkit == 'android'
 [test_bug612128.html]
 [test_bug612447.html]
 [test_bug620906.html]
@@ -105,21 +115,23 @@ skip-if = toolkit == 'android' #bug 9577
 [test_bug640321.html]
 skip-if = android_version == '18' # bug 1147989
 [test_bug641466.html]
 [test_bug645914.html]
 [test_bug668599.html]
 [test_bug674770-1.html]
 skip-if = toolkit == 'android' || (os == 'linux' && e10s && (debug||asan)) # Bug 972110
 [test_bug674770-2.html]
+subsuite = clipboard
 skip-if = toolkit == 'android'
 [test_bug674861.html]
 [test_bug676401.html]
 [test_bug677752.html]
 [test_bug681229.html]
+subsuite = clipboard
 [test_bug686203.html]
 [test_bug692520.html]
 [test_bug697842.html]
 [test_bug725069.html]
 [test_bug735059.html]
 [test_bug738366.html]
 [test_bug740784.html]
 [test_bug742261.html]
@@ -143,29 +155,32 @@ skip-if = toolkit == 'android'
 skip-if = os != "win"
 [test_bug966552.html]
 skip-if = os != "win"
 [test_bug998188.html]
 [test_bug1026397.html]
 [test_bug1067255.html]
 [test_bug1094000.html]
 [test_CF_HTML_clipboard.html]
+subsuite = clipboard
 [test_contenteditable_focus.html]
 [test_dom_input_event_on_htmleditor.html]
 skip-if = toolkit == 'android' # bug 1054087
 [test_dom_input_event_on_texteditor.html]
 [test_keypress_untrusted_event.html]
 [test_root_element_replacement.html]
 [test_select_all_without_body.html]
 [test_spellcheck_pref.html]
 skip-if = toolkit == 'android'
 [test_bug1068979.html]
+subsuite = clipboard
 [test_bug1109465.html]
 [test_bug1162952.html]
 [test_bug1186799.html]
 [test_bug1181130-1.html]
 [test_bug1181130-2.html]
 [test_backspace_vs.html]
 [test_css_chrome_load_access.html]
 skip-if = toolkit == 'android' # chrome urls not available due to packaging
 [test_bug1247483.html]
+subsuite = clipboard
 skip-if = toolkit == 'android'
 [test_bug1258085.html]
--- a/gfx/cairo/cairo/src/cairo-quartz-font.c
+++ b/gfx/cairo/cairo/src/cairo-quartz-font.c
@@ -565,17 +565,17 @@ static cairo_int_status_t
 
     /* scale(1,-1) * font->base.scale */
     textMatrix = CGAffineTransformMake (font->base.scale.xx,
 					font->base.scale.yx,
 					-font->base.scale.xy,
 					-font->base.scale.yy,
 					0, 0);
 
-    ctFont = CTFontCreateWithGraphicsFont (font_face->cgFont, 0.0, NULL, NULL);
+    ctFont = CTFontCreateWithGraphicsFont (font_face->cgFont, 1.0, NULL, NULL);
     glyphPath = CTFontCreatePathForGlyph (ctFont, glyph, &textMatrix);
     CFRelease (ctFont);
     if (!glyphPath)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     path = _cairo_path_fixed_create ();
     if (!path) {
 	CGPathRelease (glyphPath);
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -2632,27 +2632,47 @@ gfxFontGroup::GetUnderlineOffset()
     return mUnderlineOffset;
 }
 
 already_AddRefed<gfxFont>
 gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh,
                               Script aRunScript, gfxFont *aPrevMatchedFont,
                               uint8_t *aMatchType)
 {
-    // If the char is a cluster extender or NNBSP, we want to use the same
-    // font as the preceding character if possible. This is preferable to using
-    // the font group because it avoids breaks in shaping within a cluster.
-    const uint32_t NARROW_NO_BREAK_SPACE = 0x202f;
-    if (aPrevMatchedFont &&
-        (IsClusterExtender(aCh) || aCh == NARROW_NO_BREAK_SPACE) &&
+    // If the char is a cluster extender, we want to use the same font as the
+    // preceding character if possible. This is preferable to using the font
+    // group because it avoids breaks in shaping within a cluster.
+    if (aPrevMatchedFont && IsClusterExtender(aCh) &&
         aPrevMatchedFont->HasCharacter(aCh)) {
         RefPtr<gfxFont> ret = aPrevMatchedFont;
         return ret.forget();
     }
 
+    // Special cases for NNBSP (as used in Mongolian):
+    const uint32_t NARROW_NO_BREAK_SPACE = 0x202f;
+    if (aCh == NARROW_NO_BREAK_SPACE) {
+        // If there is no preceding character, try the font that we'd use
+        // for the next char (unless it's just another NNBSP; we don't try
+        // to look ahead through a whole run of them).
+        if (!aPrevCh && aNextCh && aNextCh != NARROW_NO_BREAK_SPACE) {
+            RefPtr<gfxFont> nextFont =
+                FindFontForChar(aNextCh, 0, 0, aRunScript, aPrevMatchedFont,
+                                aMatchType);
+            if (nextFont && nextFont->HasCharacter(aCh)) {
+                return nextFont.forget();
+            }
+        }
+        // Otherwise, treat NNBSP like a cluster extender (as above) and try
+        // to continue the preceding font run.
+        if (aPrevMatchedFont && aPrevMatchedFont->HasCharacter(aCh)) {
+            RefPtr<gfxFont> ret = aPrevMatchedFont;
+            return ret.forget();
+        }
+    }
+
     // To optimize common cases, try the first font in the font-group
     // before going into the more detailed checks below
     uint32_t nextIndex = 0;
     bool isJoinControl = gfxFontUtils::IsJoinControl(aCh);
     bool wasJoinCauser = gfxFontUtils::IsJoinCauser(aPrevCh);
     bool isVarSelector = gfxFontUtils::IsVarSelector(aCh);
 
     if (!isJoinControl && !wasJoinCauser && !isVarSelector) {
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -982,17 +982,18 @@ GeckoChildProcessHost::PerformAsyncLaunc
   bool shouldSandboxCurrentProcess = false;
 
   // XXX: Bug 1124167: We should get rid of the process specific logic for
   // sandboxing in this class at some point. Unfortunately it will take a bit
   // of reorganizing so I don't think this patch is the right time.
   switch (mProcessType) {
     case GeckoProcessType_Content:
 #if defined(MOZ_CONTENT_SANDBOX)
-      if (!PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX")) {
+      if (mSandboxLevel > 0 &&
+          !PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX")) {
         mSandboxBroker.SetSecurityLevelForContentProcess(mSandboxLevel);
         cmdLine.AppendLooseValue(UTF8ToWide("-sandbox"));
         shouldSandboxCurrentProcess = true;
         AddContentSandboxAllowedFiles(mSandboxLevel, mAllowedFilesRead);
       }
 #endif // MOZ_CONTENT_SANDBOX
       break;
     case GeckoProcessType_Plugin:
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -11,20 +11,16 @@ make_min_ver := 3.81
 ifneq ($(make_min_ver),$(firstword $(sort $(make_min_ver) $(MAKE_VERSION))))
 $(error GNU Make $(make_min_ver) or higher is required)
 endif
 
 DASH_R		= -r
 
 # Define keyword generator before rules.mk, see bug 323979 comment 50
 
-GARBAGE += jsautokw.h host_jskwgen$(HOST_BIN_SUFFIX)
-
-GARBAGE += selfhosted.out.h
-
 USE_HOST_CXX = 1
 
 ifdef HAVE_DTRACE
 ifneq ($(OS_ARCH),Darwin)
 DTRACE_PROBE_OBJ = $(LIBRARY_NAME)-dtrace.$(OBJ_SUFFIX)
 endif
 MOZILLA_DTRACE_SRC = $(srcdir)/devtools/javascript-trace.d
 endif
@@ -215,24 +211,16 @@ endif
 ifneq (,$(SHARED_LIBRARY))
 	$(SYSINSTALL) $(SHARED_LIBRARY) $(DESTDIR)$(libdir)
 endif
 ifneq (,$(IMPORT_LIBRARY))
 	$(SYSINSTALL) $(IMPORT_LIBRARY) $(DESTDIR)$(libdir)
 endif
 	$(MAKE) -C shell install
 
-# Use CURDIR to avoid finding a jsautokw.h in the source tree (from a
-# previous build?) via VPATH when we're building in a separate tree.
-$(CURDIR)/jsautokw.h: host_jskwgen$(HOST_BIN_SUFFIX)
-	./host_jskwgen$(HOST_BIN_SUFFIX) $@
-
-# Force auto-header generation before compiling any source that may use them
-$(OBJS): $(CURDIR)/jsautokw.h
-
 ifdef HAVE_DTRACE
 javascript-trace.h: $(srcdir)/devtools/javascript-trace.d
 	dtrace -x nolibs -h -s $(srcdir)/devtools/javascript-trace.d -o javascript-trace.h.in
 	sed -e 's/if _DTRACE_VERSION/ifdef INCLUDE_MOZILLA_DTRACE/' \
 	    -e '/const/!s/char \*/const char */g' \
 	    javascript-trace.h.in > javascript-trace.h
 
 # We can't automatically generate dependencies on auto-generated headers;
new file mode 100644
--- /dev/null
+++ b/js/src/jsautokw.py
@@ -0,0 +1,22 @@
+# 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/.
+
+from __future__ import print_function
+
+import os
+import sys
+import subprocess
+
+def main(output, exe):
+    # moz.build passes in the exe name without any path, so to run it we need to
+    # prepend the './'
+    run_exe = exe if os.path.isabs(exe) else './%s' % exe
+
+    # Use universal_newlines so everything is '\n', which gets converted to
+    # '\r\n' when writing out the file in Windows.
+    data = subprocess.check_output([run_exe], universal_newlines=True)
+    output.write(data)
+
+if __name__ == '__main__':
+    main(sys.stdout, *sys.argv[1:])
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -398,33 +398,38 @@ JS_FRIEND_API(bool)
 js::RunningWithTrustedPrincipals(JSContext* cx)
 {
     return cx->runningWithTrustedPrincipals();
 }
 
 JS_FRIEND_API(JSFunction*)
 js::GetOutermostEnclosingFunctionOfScriptedCaller(JSContext* cx)
 {
-    ScriptFrameIter iter(cx, FrameIter::STOP_AT_SAVED);
+    ScriptFrameIter iter(cx, FrameIter::GO_THROUGH_SAVED);
 
     // Skip eval frames.
     while (!iter.done() && iter.isEvalFrame())
         ++iter;
 
     if (iter.done())
         return nullptr;
 
     if (!iter.isFunctionFrame())
         return nullptr;
 
+    if (iter.compartment() != cx->compartment())
+        return nullptr;
+
     RootedFunction curr(cx, iter.callee(cx));
     for (StaticScopeIter<NoGC> i(curr); !i.done(); i++) {
         if (i.type() == StaticScopeIter<NoGC>::Function)
             curr = &i.fun();
     }
+
+    assertSameCompartment(cx, curr);
     return curr;
 }
 
 JS_FRIEND_API(JSFunction*)
 js::DefineFunctionWithReserved(JSContext* cx, JSObject* objArg, const char* name, JSNative call,
                                unsigned nargs, unsigned attrs)
 {
     RootedObject obj(cx, objArg);
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -598,16 +598,23 @@ else:
     SOURCES += [
         'perf/pm_stub.cpp'
     ]
 
 HostSimplePrograms([
     'host_jskwgen',
 ])
 
+GENERATED_FILES += ['jsautokw.h']
+jsautokw = GENERATED_FILES['jsautokw.h']
+jsautokw.script = 'jsautokw.py'
+jsautokw.inputs += [
+    '!host_jskwgen%s' % CONFIG['HOST_BIN_SUFFIX'],
+]
+
 # JavaScript must be built shared, even for static builds, as it is used by
 # other modules which are always built shared. Failure to do so results in
 # the js code getting copied into xpinstall and jsd as well as mozilla-bin,
 # and then the static data cells used for locking no longer work.
 #
 # In fact, we now build both a static and a shared library, as the
 # JS shell would like to link to the static library.
 
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -2041,19 +2041,23 @@ nsCSSRendering::DetermineBackgroundColor
     if (aDrawBackgroundImage || !bg->IsTransparent()) {
       aDrawBackgroundColor = true;
     } else {
       bgColor = NS_RGBA(0,0,0,0);
     }
   }
 
   // We can skip painting the background color if a background image is opaque.
+  nsStyleImageLayers::Repeat repeat = bg->BottomLayer().mRepeat;
+  bool xFullRepeat = repeat.mXRepeat == NS_STYLE_IMAGELAYER_REPEAT_REPEAT ||
+                     repeat.mXRepeat == NS_STYLE_IMAGELAYER_REPEAT_ROUND;
+  bool yFullRepeat = repeat.mYRepeat == NS_STYLE_IMAGELAYER_REPEAT_REPEAT ||
+                     repeat.mYRepeat == NS_STYLE_IMAGELAYER_REPEAT_ROUND;
   if (aDrawBackgroundColor &&
-      bg->BottomLayer().mRepeat.mXRepeat == NS_STYLE_IMAGELAYER_REPEAT_REPEAT &&
-      bg->BottomLayer().mRepeat.mYRepeat == NS_STYLE_IMAGELAYER_REPEAT_REPEAT &&
+      xFullRepeat && yFullRepeat &&
       bg->BottomLayer().mImage.IsOpaque() &&
       bg->BottomLayer().mBlendMode == NS_STYLE_BLEND_NORMAL) {
     aDrawBackgroundColor = false;
   }
 
   return bgColor;
 }
 
@@ -3097,17 +3101,18 @@ nsCSSRendering::PaintBackgroundWithSC(co
             ctx->SetOp(co);
           }
 
           result &=
             state.mImageRenderer.DrawBackground(&aParams.presCtx,
                                                 aParams.renderingCtx,
                                                 state.mDestArea, state.mFillArea,
                                                 state.mAnchor + paintBorderArea.TopLeft(),
-                                                clipState.mDirtyRect);
+                                                clipState.mDirtyRect,
+                                                state.mRepeatSize);
 
           if (co != CompositionOp::OP_OVER) {
             ctx->SetOp(CompositionOp::OP_OVER);
           }
         }
       }
     }
   }
@@ -3220,51 +3225,124 @@ nsCSSRendering::ComputeImageLayerPositio
       }
     }
   }
   *aAttachedToFrame = attachedToFrame;
 
   return bgPositioningArea;
 }
 
+// Implementation of the formula for computation of background-repeat round
+// See http://dev.w3.org/csswg/css3-background/#the-background-size
+// This function returns the adjusted size of the background image.
+static nscoord
+ComputeRoundedSize(nscoord aCurrentSize, nscoord aPositioningSize)
+{
+  float repeatCount = NS_roundf(float(aPositioningSize) / float(aCurrentSize));
+  if (repeatCount < 1.0f) {
+    return aPositioningSize;
+  }
+  return nscoord(NS_lround(float(aPositioningSize) / repeatCount));
+}
+
 // Apply the CSS image sizing algorithm as it applies to background images.
 // See http://www.w3.org/TR/css3-background/#the-background-size .
 // aIntrinsicSize is the size that the background image 'would like to be'.
 // It can be found by calling nsImageRenderer::ComputeIntrinsicSize.
 static nsSize
 ComputeDrawnSizeForBackground(const CSSSizeOrRatio& aIntrinsicSize,
                               const nsSize& aBgPositioningArea,
-                              const nsStyleImageLayers::Size& aLayerSize)
+                              const nsStyleImageLayers::Size& aLayerSize,
+                              uint8_t aXRepeat, uint8_t aYRepeat)
 {
+  nsSize imageSize;
+
   // Size is dictated by cover or contain rules.
   if (aLayerSize.mWidthType == nsStyleImageLayers::Size::eContain ||
       aLayerSize.mWidthType == nsStyleImageLayers::Size::eCover) {
     nsImageRenderer::FitType fitType =
       aLayerSize.mWidthType == nsStyleImageLayers::Size::eCover
         ? nsImageRenderer::COVER
         : nsImageRenderer::CONTAIN;
-    return nsImageRenderer::ComputeConstrainedSize(aBgPositioningArea,
-                                                   aIntrinsicSize.mRatio,
-                                                   fitType);
-  }
-
-  // No cover/contain constraint, use default algorithm.
-  CSSSizeOrRatio specifiedSize;
-  if (aLayerSize.mWidthType == nsStyleImageLayers::Size::eLengthPercentage) {
-    specifiedSize.SetWidth(
-      aLayerSize.ResolveWidthLengthPercentage(aBgPositioningArea));
-  }
-  if (aLayerSize.mHeightType == nsStyleImageLayers::Size::eLengthPercentage) {
-    specifiedSize.SetHeight(
-      aLayerSize.ResolveHeightLengthPercentage(aBgPositioningArea));
-  }
-
-  return nsImageRenderer::ComputeConcreteSize(specifiedSize,
-                                              aIntrinsicSize,
-                                              aBgPositioningArea);
+    imageSize = nsImageRenderer::ComputeConstrainedSize(aBgPositioningArea,
+                                                        aIntrinsicSize.mRatio,
+                                                        fitType);
+  } else {
+    // No cover/contain constraint, use default algorithm.
+    CSSSizeOrRatio specifiedSize;
+    if (aLayerSize.mWidthType == nsStyleImageLayers::Size::eLengthPercentage) {
+      specifiedSize.SetWidth(
+        aLayerSize.ResolveWidthLengthPercentage(aBgPositioningArea));
+    }
+    if (aLayerSize.mHeightType == nsStyleImageLayers::Size::eLengthPercentage) {
+      specifiedSize.SetHeight(
+        aLayerSize.ResolveHeightLengthPercentage(aBgPositioningArea));
+    }
+
+    imageSize = nsImageRenderer::ComputeConcreteSize(specifiedSize,
+                                                     aIntrinsicSize,
+                                                     aBgPositioningArea);
+  }
+
+  // See https://www.w3.org/TR/css3-background/#background-size .
+  // "If 'background-repeat' is 'round' for one (or both) dimensions, there is a second
+  //  step. The UA must scale the image in that dimension (or both dimensions) so that
+  //  it fits a whole number of times in the background positioning area."
+  // "If 'background-repeat' is 'round' for one dimension only and if 'background-size'
+  //  is 'auto' for the other dimension, then there is a third step: that other dimension
+  //  is scaled so that the original aspect ratio is restored."
+  bool isRepeatRoundInBothDimensions = aXRepeat == NS_STYLE_IMAGELAYER_REPEAT_ROUND &&
+                                       aYRepeat == NS_STYLE_IMAGELAYER_REPEAT_ROUND;
+
+  // Calculate the rounded size only if the background-size computation
+  // returned a correct size for the image.
+  if (imageSize.width && aXRepeat == NS_STYLE_IMAGELAYER_REPEAT_ROUND) {
+    imageSize.width = ComputeRoundedSize(imageSize.width, aBgPositioningArea.width);
+    if (!isRepeatRoundInBothDimensions &&
+        aLayerSize.mHeightType == nsStyleImageLayers::Size::DimensionType::eAuto) {
+      // Restore intrinsic rato
+      if (aIntrinsicSize.mRatio.width) {
+        float scale = float(aIntrinsicSize.mRatio.height) / aIntrinsicSize.mRatio.width;
+        imageSize.height = NSCoordSaturatingNonnegativeMultiply(imageSize.width, scale);
+      }
+    }
+  }
+
+  // Calculate the rounded size only if the background-size computation
+  // returned a correct size for the image.
+  if (imageSize.height && aYRepeat == NS_STYLE_IMAGELAYER_REPEAT_ROUND) {
+    imageSize.height = ComputeRoundedSize(imageSize.height, aBgPositioningArea.height);
+    if (!isRepeatRoundInBothDimensions &&
+        aLayerSize.mWidthType == nsStyleImageLayers::Size::DimensionType::eAuto) {
+      // Restore intrinsic rato
+      if (aIntrinsicSize.mRatio.height) {
+        float scale = float(aIntrinsicSize.mRatio.width) / aIntrinsicSize.mRatio.height;
+        imageSize.width = NSCoordSaturatingNonnegativeMultiply(imageSize.height, scale);
+      }
+    }
+  }
+
+  return imageSize;
+}
+
+/* ComputeSpacedRepeatSize
+ * aImageDimension: the image width/height
+ * aAvailableSpace: the background positioning area width/height
+ * aRepeatSize: the image size plus gap size of app units for use as spacing
+ */
+static nscoord
+ComputeSpacedRepeatSize(nscoord aImageDimension,
+                        nscoord aAvailableSpace) {
+  float ratio = aAvailableSpace / aImageDimension;
+
+  if (ratio < 2.0f) { // If you can't repeat at least twice, then don't repeat.
+    return aImageDimension;
+  } else {
+    return (aAvailableSpace - aImageDimension) / (NSToIntFloor(ratio) - 1);
+  }
 }
 
 nsBackgroundLayerState
 nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext,
                                   nsIFrame* aForFrame,
                                   uint32_t aFlags,
                                   const nsRect& aBorderArea,
                                   const nsRect& aBGClipRect,
@@ -3379,50 +3457,80 @@ nsCSSRendering::PrepareImageLayer(nsPres
       // always clipped to the viewport when we draw to the screen. (But it's
       // not a pure optimization since it can affect the values of pixels at the
       // edge of the viewport --- whether they're sampled from a putative "next
       // tile" or not.)
       bgClipRect.IntersectRect(bgClipRect, bgPositioningArea + aBorderArea.TopLeft());
     }
   }
 
-  // Scale the image as specified for background-size and as required for
-  // proper background positioning when background-position is defined with
-  // percentages.
+  int repeatX = aLayer.mRepeat.mXRepeat;
+  int repeatY = aLayer.mRepeat.mYRepeat;
+
+  // Scale the image as specified for background-size and background-repeat.
+  // Also as required for proper background positioning when background-position
+  // is defined with percentages.
   CSSSizeOrRatio intrinsicSize = state.mImageRenderer.ComputeIntrinsicSize();
   nsSize bgPositionSize = bgPositioningArea.Size();
   nsSize imageSize = ComputeDrawnSizeForBackground(intrinsicSize,
                                                    bgPositionSize,
-                                                   aLayer.mSize);
+                                                   aLayer.mSize,
+                                                   repeatX,
+                                                   repeatY);
+
   if (imageSize.width <= 0 || imageSize.height <= 0)
     return state;
 
   state.mImageRenderer.SetPreferredSize(intrinsicSize,
                                         imageSize);
 
   // Compute the position of the background now that the background's size is
   // determined.
   nsImageRenderer::ComputeObjectAnchorPoint(aLayer.mPosition,
                                             bgPositionSize, imageSize,
                                             &imageTopLeft, &state.mAnchor);
+  state.mRepeatSize = imageSize;
+  if (repeatX == NS_STYLE_IMAGELAYER_REPEAT_SPACE) {
+    state.mRepeatSize.width = ComputeSpacedRepeatSize(imageSize.width,
+                                                      bgPositionSize.width);
+    if (state.mRepeatSize.width > imageSize.width) {
+      imageTopLeft.x = 0;
+      state.mAnchor.x = 0;
+    } else {
+      repeatX = NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT;
+    }
+  }
+
+  if (repeatY == NS_STYLE_IMAGELAYER_REPEAT_SPACE) {
+    state.mRepeatSize.height = ComputeSpacedRepeatSize(imageSize.height,
+                                                       bgPositionSize.height);
+    if (state.mRepeatSize.height > imageSize.height) {
+      imageTopLeft.y = 0;
+      state.mAnchor.y = 0;
+    } else {
+      repeatY = NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT;
+    }
+  }
+
   imageTopLeft += bgPositioningArea.TopLeft();
   state.mAnchor += bgPositioningArea.TopLeft();
-
   state.mDestArea = nsRect(imageTopLeft + aBorderArea.TopLeft(), imageSize);
   state.mFillArea = state.mDestArea;
-  int repeatX = aLayer.mRepeat.mXRepeat;
-  int repeatY = aLayer.mRepeat.mYRepeat;
 
   ExtendMode repeatMode = ExtendMode::CLAMP;
-  if (repeatX == NS_STYLE_IMAGELAYER_REPEAT_REPEAT) {
+  if (repeatX == NS_STYLE_IMAGELAYER_REPEAT_REPEAT ||
+      repeatX == NS_STYLE_IMAGELAYER_REPEAT_ROUND ||
+      repeatX == NS_STYLE_IMAGELAYER_REPEAT_SPACE) {
     state.mFillArea.x = bgClipRect.x;
     state.mFillArea.width = bgClipRect.width;
     repeatMode = ExtendMode::REPEAT_X;
   }
-  if (repeatY == NS_STYLE_IMAGELAYER_REPEAT_REPEAT) {
+  if (repeatY == NS_STYLE_IMAGELAYER_REPEAT_REPEAT ||
+      repeatY == NS_STYLE_IMAGELAYER_REPEAT_ROUND ||
+      repeatY == NS_STYLE_IMAGELAYER_REPEAT_SPACE) {
     state.mFillArea.y = bgClipRect.y;
     state.mFillArea.height = bgClipRect.height;
 
     /***
      * We're repeating on the X axis already,
      * so if we have to repeat in the Y axis,
      * we really need to repeat in both directions.
      */
@@ -5117,16 +5225,17 @@ RGBALuminanceOperation(uint8_t *aData,
 
 DrawResult
 nsImageRenderer::Draw(nsPresContext*       aPresContext,
                       nsRenderingContext&  aRenderingContext,
                       const nsRect&        aDirtyRect,
                       const nsRect&        aDest,
                       const nsRect&        aFill,
                       const nsPoint&       aAnchor,
+                      const nsSize&        aRepeatSize,
                       const CSSIntRect&    aSrc)
 {
   if (!IsReady()) {
     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
     return DrawResult::TEMPORARY_ERROR;
   }
   if (aDest.IsEmpty() || aFill.IsEmpty() ||
       mSize.width <= 0 || mSize.height <= 0) {
@@ -5153,17 +5262,18 @@ nsImageRenderer::Draw(nsPresContext*    
     case eStyleImageType_Image:
     {
       CSSIntSize imageSize(nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
                            nsPresContext::AppUnitsToIntCSSPixels(mSize.height));
       result =
         nsLayoutUtils::DrawBackgroundImage(*ctx,
                                            aPresContext,
                                            mImageContainer, imageSize, filter,
-                                           aDest, aFill, aAnchor, aDirtyRect,
+                                           aDest, aFill, aRepeatSize,
+                                           aAnchor, aDirtyRect,
                                            ConvertImageRendererToDrawFlags(mFlags),
                                            mExtendMode);
       break;
     }
     case eStyleImageType_Gradient:
     {
       nsCSSRendering::PaintGradient(aPresContext, aRenderingContext,
                                     mGradientData, aDirtyRect,
@@ -5250,29 +5360,30 @@ nsImageRenderer::DrawableForElement(cons
 }
 
 DrawResult
 nsImageRenderer::DrawBackground(nsPresContext*       aPresContext,
                                 nsRenderingContext&  aRenderingContext,
                                 const nsRect&        aDest,
                                 const nsRect&        aFill,
                                 const nsPoint&       aAnchor,
-                                const nsRect&        aDirty)
+                                const nsRect&        aDirty,
+                                const nsSize&        aRepeatSize)
 {
   if (!IsReady()) {
     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
     return DrawResult::TEMPORARY_ERROR;
   }
   if (aDest.IsEmpty() || aFill.IsEmpty() ||
       mSize.width <= 0 || mSize.height <= 0) {
     return DrawResult::SUCCESS;
   }
 
   return Draw(aPresContext, aRenderingContext,
-              aDirty, aDest, aFill, aAnchor,
+              aDirty, aDest, aFill, aAnchor, aRepeatSize,
               CSSIntRect(0, 0,
                          nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
                          nsPresContext::AppUnitsToIntCSSPixels(mSize.height)));
 }
 
 /**
  * Compute the size and position of the master copy of the image. I.e., a single
  * tile used to fill the dest rect.
@@ -5426,17 +5537,17 @@ nsImageRenderer::DrawBorderImageComponen
                                     drawFlags);
   }
 
   nsRect destTile = RequiresScaling(aFill, aHFill, aVFill, aUnitSize)
                   ? ComputeTile(aFill, aHFill, aVFill, aUnitSize)
                   : aFill;
 
   return Draw(aPresContext, aRenderingContext, aDirtyRect, destTile,
-              aFill, destTile.TopLeft(), aSrc);
+              aFill, destTile.TopLeft(), nsSize(0, 0), aSrc);
 }
 
 bool
 nsImageRenderer::IsRasterImage()
 {
   if (mType != eStyleImageType_Image || !mImageContainer)
     return false;
   return mImageContainer->GetType() == imgIContainer::TYPE_RASTER;
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -212,17 +212,18 @@ public:
    * arguments.
    * @see nsLayoutUtils::DrawImage() for parameters.
    */
   DrawResult DrawBackground(nsPresContext*       aPresContext,
                             nsRenderingContext&  aRenderingContext,
                             const nsRect&        aDest,
                             const nsRect&        aFill,
                             const nsPoint&       aAnchor,
-                            const nsRect&        aDirty);
+                            const nsRect&        aDirty,
+                            const nsSize&        aRepeatSize);
 
   /**
    * Draw the image to a single component of a border-image style rendering.
    * aFill The destination rect to be drawn into
    * aSrc is the part of the image to be rendered into a tile (aUnitSize in
    * aFill), if aSrc and the dest tile are different sizes, the image will be
    * scaled to map aSrc onto the dest tile.
    * aHFill and aVFill are the repeat patterns for the component -
@@ -268,20 +269,21 @@ private:
    * @see nsLayoutUtils::DrawImage() for other parameters.
    */
   DrawResult Draw(nsPresContext*       aPresContext,
                   nsRenderingContext&  aRenderingContext,
                   const nsRect&        aDirtyRect,
                   const nsRect&        aDest,
                   const nsRect&        aFill,
                   const nsPoint&       aAnchor,
+                  const nsSize&        aRepeatSize,
                   const mozilla::CSSIntRect& aSrc);
 
   /**
-   * Helper method for creating a gfxDrawable from mPaintServerFrame or 
+   * Helper method for creating a gfxDrawable from mPaintServerFrame or
    * mImageElementSurface.
    * Requires mType is eStyleImageType_Element.
    * Returns null if we cannot create the drawable.
    */
   already_AddRefed<gfxDrawable> DrawableForElement(const nsRect& aImageRect,
                                                    nsRenderingContext&  aRenderingContext);
 
   nsIFrame*                 mForFrame;
@@ -331,16 +333,21 @@ struct nsBackgroundLayerState {
    */
   nsRect mFillArea;
   /**
    * The anchor point that should be snapped to a pixel corner. Same
    * coordinate system as aBorderArea/aBGClipRect passed into
    * PrepareImageLayer.
    */
   nsPoint mAnchor;
+  /**
+   * The background-repeat property space keyword computes the
+   * repeat size which is image size plus spacing.
+   */
+  nsSize mRepeatSize;
 };
 
 struct nsCSSRendering {
   typedef mozilla::gfx::CompositionOp CompositionOp;
   typedef mozilla::gfx::DrawTarget DrawTarget;
   typedef mozilla::gfx::Float Float;
   typedef mozilla::gfx::Point Point;
   typedef mozilla::gfx::Rect Rect;
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2907,16 +2907,18 @@ nsDisplayBackgroundImage::GetOpaqueRegio
   // which expects frames to be sent to it in content order, not reverse
   // content order which we'll produce here.
   // Of course, if there's only one frame in the flow, it doesn't matter.
   if (mFrame->StyleBorder()->mBoxDecorationBreak ==
         NS_STYLE_BOX_DECORATION_BREAK_CLONE ||
       (!mFrame->GetPrevContinuation() && !mFrame->GetNextContinuation())) {
     const nsStyleImageLayers::Layer& layer = mBackgroundStyle->mImage.mLayers[mLayer];
     if (layer.mImage.IsOpaque() && layer.mBlendMode == NS_STYLE_BLEND_NORMAL &&
+        layer.mRepeat.mXRepeat != NS_STYLE_IMAGELAYER_REPEAT_SPACE &&
+        layer.mRepeat.mYRepeat != NS_STYLE_IMAGELAYER_REPEAT_SPACE &&
         layer.mClip != NS_STYLE_IMAGELAYER_CLIP_TEXT) {
       result = GetInsideClipRegion(this, layer.mClip, mBounds, mBackgroundRect);
     }
   }
 
   return result;
 }
 
@@ -4948,18 +4950,16 @@ nsDisplayFixedPosition::nsDisplayFixedPo
 {
   MOZ_COUNT_CTOR(nsDisplayFixedPosition);
   Init(aBuilder);
 }
 
 void
 nsDisplayFixedPosition::Init(nsDisplayListBuilder* aBuilder)
 {
-  bool snap;
-  mVisibleRect = GetBounds(aBuilder, &snap);
   mAnimatedGeometryRootForScrollMetadata = mAnimatedGeometryRoot;
   if (ShouldFixToViewport(aBuilder)) {
     mAnimatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(this);
   }
 }
 
 /* static */ nsDisplayFixedPosition*
 nsDisplayFixedPosition::CreateForFixedBackground(nsDisplayListBuilder* aBuilder,
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -6673,17 +6673,16 @@ ComputeSnappedImageDrawingParameters(gfx
 
   ImageRegion region =
     ImageRegion::CreateWithSamplingRestriction(imageSpaceFill, subimage, extendMode);
 
   return SnappedImageDrawingParameters(transform, intImageSize,
                                        region, svgViewportSize);
 }
 
-
 static DrawResult
 DrawImageInternal(gfxContext&            aContext,
                   nsPresContext*         aPresContext,
                   imgIContainer*         aImage,
                   Filter                 aGraphicsFilter,
                   const nsRect&          aDest,
                   const nsRect&          aFill,
                   const nsPoint&         aAnchor,
@@ -6915,33 +6914,54 @@ nsLayoutUtils::ComputeSizeForDrawingWith
 /* static */ DrawResult
 nsLayoutUtils::DrawBackgroundImage(gfxContext&         aContext,
                                    nsPresContext*      aPresContext,
                                    imgIContainer*      aImage,
                                    const CSSIntSize&   aImageSize,
                                    Filter              aGraphicsFilter,
                                    const nsRect&       aDest,
                                    const nsRect&       aFill,
+                                   const nsSize&       aRepeatSize,
                                    const nsPoint&      aAnchor,
                                    const nsRect&       aDirty,
                                    uint32_t            aImageFlags,
                                    ExtendMode          aExtendMode)
 {
   PROFILER_LABEL("layout", "nsLayoutUtils::DrawBackgroundImage",
                  js::ProfileEntry::Category::GRAPHICS);
 
   if (UseBackgroundNearestFiltering()) {
     aGraphicsFilter = Filter::POINT;
   }
 
   SVGImageContext svgContext(aImageSize, Nothing());
 
-  return DrawImageInternal(aContext, aPresContext, aImage,
-                           aGraphicsFilter, aDest, aFill, aAnchor,
-                           aDirty, &svgContext, aImageFlags, aExtendMode);
+  /* Fast path when there is no need for image spacing */
+  if (aRepeatSize.width == aDest.width && aRepeatSize.height == aDest.height) {
+    return DrawImageInternal(aContext, aPresContext, aImage,
+                             aGraphicsFilter, aDest, aFill, aAnchor,
+                             aDirty, &svgContext, aImageFlags, aExtendMode);
+  }
+
+  nsPoint firstTilePos = aDest.TopLeft() +
+                         nsPoint(NSToIntFloor(float(aFill.x - aDest.x) / aRepeatSize.width) * aRepeatSize.width,
+                                 NSToIntFloor(float(aFill.y - aDest.y) / aRepeatSize.height) * aRepeatSize.height);
+  for (int32_t i = firstTilePos.x; i < aFill.XMost(); i += aRepeatSize.width) {
+    for (int32_t j = firstTilePos.y; j < aFill.YMost(); j += aRepeatSize.height) {
+      nsRect dest(i, j, aDest.width, aDest.height);
+      DrawResult result = DrawImageInternal(aContext, aPresContext, aImage, aGraphicsFilter,
+                                            dest, dest, aAnchor, aDirty, &svgContext,
+                                            aImageFlags, ExtendMode::CLAMP);
+      if (result != DrawResult::SUCCESS) {
+        return result;
+      }
+    }
+  }
+
+  return DrawResult::SUCCESS;
 }
 
 /* static */ DrawResult
 nsLayoutUtils::DrawImage(gfxContext&         aContext,
                          nsPresContext*      aPresContext,
                          imgIContainer*      aImage,
                          Filter              aGraphicsFilter,
                          const nsRect&       aDest,
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1730,31 +1730,37 @@ public:
    *                            app units.
    *   @param aImage            The image.
    *   @param aImageSize        The unscaled size of the image being drawn.
    *                            (This might be the image's size if no scaling
    *                            occurs, or it might be the image's size if
    *                            the image is a vector image being rendered at
    *                            that size.)
    *   @param aDest             The position and scaled area where one copy of
-   *                            the image should be drawn.
+   *                            the image should be drawn. This area represents
+   *                            the image itself in its correct position as defined
+   *                            with the background-position css property.
    *   @param aFill             The area to be filled with copies of the image.
+   *   @param aRepeatSize       The distance between the positions of two subsequent
+   *                            repeats of the image. Sizes larger than aDest.Size()
+   *                            create gaps between the images.
    *   @param aAnchor           A point in aFill which we will ensure is
    *                            pixel-aligned in the output.
    *   @param aDirty            Pixels outside this area may be skipped.
    *   @param aImageFlags       Image flags of the imgIContainer::FLAG_* variety.
    *   @param aExtendMode       How to extend the image over the dest rect.
    */
   static DrawResult DrawBackgroundImage(gfxContext&         aContext,
                                         nsPresContext*      aPresContext,
                                         imgIContainer*      aImage,
                                         const CSSIntSize&   aImageSize,
                                         Filter              aGraphicsFilter,
                                         const nsRect&       aDest,
                                         const nsRect&       aFill,
+                                        const nsSize&       aRepeatSize,
                                         const nsPoint&      aAnchor,
                                         const nsRect&       aDirty,
                                         uint32_t            aImageFlags,
                                         ExtendMode          aExtendMode);
 
   /**
    * Draw an image.
    * See https://wiki.mozilla.org/Gecko:Image_Snapping_and_Rendering
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -822,26 +822,26 @@ struct nsGridContainerFrame::TrackSizing
                (mMinSizingFunctions.Length() >= 1 &&
                 mRepeatAutoStart < mMinSizingFunctions.Length()));
   }
 
   /**
    * Initialize the number of auto-fill/fit tracks to use and return that.
    * (zero if no auto-fill/fit track was specified)
    */
-  uint32_t InitRepeatTracks(nscoord aGridGap, nscoord aMinSize, nscoord aSize,
-                            nscoord aMaxSize)
+  uint32_t InitRepeatTracks(const nsStyleCoord& aGridGap, nscoord aMinSize,
+                            nscoord aSize, nscoord aMaxSize)
   {
     uint32_t repeatTracks =
       CalculateRepeatFillCount(aGridGap, aMinSize, aSize, aMaxSize);
     SetNumRepeatTracks(repeatTracks);
     return repeatTracks;
   }
 
-  uint32_t CalculateRepeatFillCount(nscoord aGridGap,
+  uint32_t CalculateRepeatFillCount(const nsStyleCoord& aGridGap,
                                     nscoord aMinSize,
                                     nscoord aSize,
                                     nscoord aMaxSize) const
   {
     if (!mHasRepeatAuto) {
       return 0;
     }
     // Spec quotes are from https://drafts.csswg.org/css-grid/#repeat-notation
@@ -872,28 +872,30 @@ struct nsGridContainerFrame::TrackSizing
         // Use a minimum 1px for the repeat() track-size.
         if (trackSize < AppUnitsPerCSSPixel()) {
           trackSize = AppUnitsPerCSSPixel();
         }
         repeatTrackSize = trackSize;
       }
       sum += trackSize;
     }
+    nscoord gridGap =
+      std::max(nscoord(0), nsRuleNode::ComputeCoordPercentCalc(aGridGap, aSize));
     if (numTracks > 1) {
       // Add grid-gaps for all the tracks including the repeat() track.
-      sum += aGridGap * (numTracks - 1);
+      sum += gridGap * (numTracks - 1);
     }
     nscoord available = maxFill != NS_UNCONSTRAINEDSIZE ? maxFill : aMinSize;
     nscoord spaceToFill = available - sum;
     if (spaceToFill <= 0) {
       // "if any number of repetitions would overflow, then 1 repetition"
       return 1;
     }
     // Calculate the max number of tracks that fits without overflow.
-    uint32_t numRepeatTracks = (spaceToFill / (repeatTrackSize + aGridGap)) + 1;
+    uint32_t numRepeatTracks = (spaceToFill / (repeatTrackSize + gridGap)) + 1;
     if (maxFill == NS_UNCONSTRAINEDSIZE) {
       // "Otherwise, if the grid container has a definite min size in
       // the relevant axis, the number of repetitions is the largest possible
       // positive integer that fulfills that minimum requirement."
       ++numRepeatTracks; // one more to ensure the grid is at least min-size
     }
     // Clamp the number of repeat tracks so that the last line <= kMaxLine.
     // (note that |numTracks| already includes one repeat() track)
@@ -980,17 +982,17 @@ struct nsGridContainerFrame::TrackSizing
 /**
  * State for the tracks in one dimension.
  */
 struct nsGridContainerFrame::Tracks
 {
   explicit Tracks(LogicalAxis aAxis) : mAxis(aAxis) {}
 
   void Initialize(const TrackSizingFunctions& aFunctions,
-                  nscoord                     aGridGap,
+                  const nsStyleCoord&         aGridGap,
                   uint32_t                    aNumTracks,
                   nscoord                     aContentBoxSize);
 
   /**
    * Return true if aRange spans at least one track with an intrinsic sizing
    * function and does not span any tracks with a <flex> max-sizing function.
    * @param aRange the span of tracks to check
    * @param aConstraint if MIN_ISIZE, treat a <flex> min-sizing as 'min-content'
@@ -3155,32 +3157,32 @@ nsGridContainerFrame::Grid::PlaceGridIte
     auto finalRowRepeatCount = aState.mRowFunctions.NumRepeatTracks() - numEmptyRows;
     aState.mRowFunctions.SetNumRepeatTracks(finalRowRepeatCount);
   }
 }
 
 void
 nsGridContainerFrame::Tracks::Initialize(
   const TrackSizingFunctions& aFunctions,
-  nscoord                     aGridGap,
+  const nsStyleCoord&         aGridGap,
   uint32_t                    aNumTracks,
   nscoord                     aContentBoxSize)
 {
   MOZ_ASSERT(aNumTracks >= aFunctions.mExplicitGridOffset +
                              aFunctions.NumExplicitTracks());
   mSizes.SetLength(aNumTracks);
   PodZero(mSizes.Elements(), mSizes.Length());
   for (uint32_t i = 0, len = mSizes.Length(); i < len; ++i) {
     mSizes[i].Initialize(aContentBoxSize,
                          aFunctions.MinSizingFor(i),
                          aFunctions.MaxSizingFor(i));
   }
-  mGridGap = aGridGap;
+  auto gap = nsRuleNode::ComputeCoordPercentCalc(aGridGap, aContentBoxSize);
+  mGridGap = std::max(nscoord(0), gap);
   mContentBoxSize = aContentBoxSize;
-  MOZ_ASSERT(mGridGap >= nscoord(0), "negative grid gap");
 }
 
 /**
  * Return the [min|max]-content contribution of aChild to its parent (i.e.
  * the child's margin-box) in aAxis.
  */
 static nscoord
 ContentContribution(nsIFrame*                         aChild,
--- a/layout/inspector/tests/test_bug877690.html
+++ b/layout/inspector/tests/test_bug877690.html
@@ -88,17 +88,17 @@ function do_test() {
       "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen",
       "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
       "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod",
       "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum",
       "powderblue", "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown",
       "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey",
       "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "transparent", "turquoise",
       "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen", "no-repeat", "repeat",
-      "repeat-x", "repeat-y", "fixed", "scroll", "local", "center", "top", "bottom", "left", "right",
+      "repeat-x", "repeat-y", "space", "round", "fixed", "scroll", "local", "center", "top", "bottom", "left", "right",
       "border-box", "padding-box", "content-box", "border-box", "padding-box", "content-box", "text", "contain",
       "cover", "rgb", "hsl", "rgba", "hsla", "none", "-moz-element", "-moz-image-rect", "url", "linear-gradient",
       "radial-gradient", "repeating-linear-gradient", "repeating-radial-gradient", "-moz-linear-gradient",
       "-moz-radial-gradient", "-moz-repeating-linear-gradient", "-moz-repeating-radial-gradient" ];
   ok(testValues(values, expected), "Shorthand property values.");
 
   var prop = "border";
   var values = getCSSValuesForProperty(prop);
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -1554,17 +1554,19 @@ nsPrintEngine::FirePrintingErrorEvent(ns
   event->SetTrusted(true);
 
   RefPtr<AsyncEventDispatcher> asyncDispatcher =
     new AsyncEventDispatcher(doc, event);
   asyncDispatcher->mOnlyChromeDispatch = true;
   asyncDispatcher->RunDOMEventWhenSafe();
 
   // Inform any progress listeners of the Error.
-  mPrt->DoOnStatusChange(aPrintError);
+  if (mPrt) {
+    mPrt->DoOnStatusChange(aPrintError);
+  }
 }
 
 //-----------------------------------------------------------------
 //-- Section: Reflow Methods
 //-----------------------------------------------------------------
 
 nsresult
 nsPrintEngine::ReconstructAndReflow(bool doSetPixelScale)
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1273154-2-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+      body {
+        /* Force a large line-height so that we don't get a positioning
+           discrepancy on the test span depending on which font's metrics
+           are used in line-height computation. */
+        font: 64px/2 serif;
+      }
+      span {
+        font-family: "Mongolian Baiti", "Times New Roman", serif;
+        font-size: 32px;
+      }
+    </style>
+  </head>
+  <body>
+    <span>&#x202F;&#x1824;&#x1828;</span>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1273154-2.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+      body {
+        /* Force a large line-height so that we don't get a positioning
+           discrepancy on the test span depending on which font's metrics
+           are used in line-height computation. */
+        font: 64px/2 serif;
+      }
+      span {
+        /* Times does NOT support Mongolian characters, so the entire text
+           should be rendered as a single Mongolian Baiti run, including
+           the initial U+202F, even though it _is_ available in Times. */
+        font-family: "Times New Roman", "Mongolian Baiti", serif;
+        font-size: 32px;
+      }
+    </style>
+  </head>
+  <body>
+    <span>&#x202F;&#x1824;&#x1828;</span>
+  </body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1949,9 +1949,10 @@ random-if(OSX==1006) == 1238243-2.html 1
 fuzzy(100,2000) == 1239564.html 1239564-ref.html
 == 1242172-1.html 1242172-1-ref.html
 == 1242172-2.html 1242172-2-ref.html
 == 1242781.html 1242781-ref.html
 == 1263845.html 1263845-ref.html
 == 1260543-1.html 1260543-1-ref.html
 == 1272997-1.html 1272997-1-ref.html
 random-if(!winWidget) == 1273154-1.html 1273154-1-ref.html # depends on Windows font
+random-if(!winWidget) == 1273154-2.html 1273154-2-ref.html # depends on Windows font
 == 1274368-1.html 1274368-1-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-grid/grid-column-gap-004-ref.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Reference: Percentage 'grid-column-gap'</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1266268">
+  <style type="text/css">
+html,body {
+    color:black; background-color:white; font-size:16px; padding:0; margin:0;
+}
+separator { clear:both; display:block; height:6px; }
+
+.grid {
+  display: grid;
+  float: left;
+  position: relative;
+  border: 1px solid;
+  border-block-start: 2px solid blue;
+  grid-template: 3px 5px 7px / 11px 7px 5px;
+  padding: 1px 1px 3px 2px;
+  margin-right: 4px;
+  width: 60px;
+  height: 40px;
+  grid-column-gap: 6px;
+}
+.vl.grid, .vr.grid, .vlr.grid, .vrl.grid { grid-column-gap: 4px; }
+
+item1,item2,item3 {
+  display: block;
+  background: grey;
+  justify-self: stretch;
+  align-self: stretch;
+}
+
+item1 { grid-area: 1 / 1; }
+item2 { grid-area: 2 / 2; }
+item3 { grid-area: 3 / 3; }
+
+.hl  { writing-mode: horizontal-tb; direction:ltr; }
+.hr  { writing-mode: horizontal-tb; direction:rtl; }
+.vl  { writing-mode: vertical-lr; }
+.vr  { writing-mode: vertical-rl; }
+.vlr { writing-mode: vertical-lr; direction:rtl; }
+.vrl { writing-mode: vertical-rl; direction:ltr; }
+
+.astart { align-content:start; }
+.aend { align-content:end; }
+.aflexstart { align-content:flex-start; }
+.aflexend { align-content:flex-end; }
+.acenter { align-content:center; }
+.aleft { align-content:left; }
+.aright { align-content:right; }
+
+.aspace-between{ align-content:space-between; }
+.aspace-around { align-content:space-around;  }
+.aspace-evenly { align-content:space-evenly;  }
+
+.astretch1, .astretch2, .astretch3, .astretch4 { align-content:stretch; }
+.astretch2 { grid-template-rows: minmax(3px,auto) 5px 7px; }
+.astretch3 { grid-template-rows: minmax(3px,auto) minmax(5px,auto) 7px; }
+.astretch4 { grid-template-rows: minmax(3px,auto) minmax(5px,auto) minmax(7px,auto); }
+
+</style>
+</head>
+<body>
+
+<script>
+var gridwm = [ "hl", "hr", "vl", "vr", "vlr", "vrl" ];
+var test = [ "start", "end", "flexstart", "flexend", "center", "left", "right",
+             "space-between", "space-around", "space-evenly",
+             "stretch1", "stretch2", "stretch3", "stretch4" ];
+for (var k = 0; k < test.length; ++k) {
+  for (var i = 0; i < gridwm.length; ++i) {
+      var div = document.createElement("div");
+      div.className = "grid a" + test[k] + " " + gridwm[i];
+      div.appendChild(document.createElement("item1"));
+      div.appendChild(document.createElement("item2"));
+      div.appendChild(document.createElement("item3"));
+      document.body.appendChild(div)
+  }
+    document.body.appendChild(document.createElement("separator"));
+}
+</script>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-grid/grid-column-gap-004.html
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>CSS Grid Test: Percentage 'grid-column-gap'</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1266268">
+  <link rel="help" href="http://dev.w3.org/csswg/css-grid/#gutters">
+  <link rel="match" href="grid-column-gap-004-ref.html">
+  <style type="text/css">
+html,body {
+    color:black; background-color:white; font-size:16px; padding:0; margin:0;
+}
+separator { clear:both; display:block; height:6px; }
+
+.grid {
+  display: grid;
+  float: left;
+  position: relative;
+  border: 1px solid;
+  border-block-start: 2px solid blue;
+  grid-template: 3px 5px 7px / 11px 7px 5px;
+  padding: 1px 1px 3px 2px;
+  margin-right: 4px;
+  width: 60px;
+  height: 40px;
+  grid-column-gap: 10%;
+}
+
+item1,item2,item3 {
+  display: block;
+  background: grey;
+  justify-self: stretch;
+  align-self: stretch;
+}
+
+item1 { grid-area: 1 / 1; }
+item2 { grid-area: 2 / 2; }
+item3 { grid-area: 3 / 3; }
+
+.hl  { writing-mode: horizontal-tb; direction:ltr; }
+.hr  { writing-mode: horizontal-tb; direction:rtl; }
+.vl  { writing-mode: vertical-lr; }
+.vr  { writing-mode: vertical-rl; }
+.vlr { writing-mode: vertical-lr; direction:rtl; }
+.vrl { writing-mode: vertical-rl; direction:ltr; }
+
+.astart { align-content:start; }
+.aend { align-content:end; }
+.aflexstart { align-content:flex-start; }
+.aflexend { align-content:flex-end; }
+.acenter { align-content:center; }
+.aleft { align-content:left; }
+.aright { align-content:right; }
+
+.aspace-between{ align-content:space-between; }
+.aspace-around { align-content:space-around;  }
+.aspace-evenly { align-content:space-evenly;  }
+
+.astretch1, .astretch2, .astretch3, .astretch4 { align-content:stretch; }
+.astretch2 { grid-template-rows: minmax(3px,auto) 5px 7px; }
+.astretch3 { grid-template-rows: minmax(3px,auto) minmax(5px,auto) 7px; }
+.astretch4 { grid-template-rows: minmax(3px,auto) minmax(5px,auto) minmax(7px,auto); }
+
+</style>
+</head>
+<body>
+
+<script>
+var gridwm = [ "hl", "hr", "vl", "vr", "vlr", "vrl" ];
+var test = [ "start", "end", "flexstart", "flexend", "center", "left", "right",
+             "space-between", "space-around", "space-evenly",
+             "stretch1", "stretch2", "stretch3", "stretch4" ];
+for (var k = 0; k < test.length; ++k) {
+  for (var i = 0; i < gridwm.length; ++i) {
+      var div = document.createElement("div");
+      div.className = "grid a" + test[k] + " " + gridwm[i];
+      div.appendChild(document.createElement("item1"));
+      div.appendChild(document.createElement("item2"));
+      div.appendChild(document.createElement("item3"));
+      document.body.appendChild(div)
+  }
+    document.body.appendChild(document.createElement("separator"));
+}
+</script>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-grid/grid-row-gap-005-ref.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Reference: Percentage 'grid-row-gap'</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1266268">
+  <style type="text/css">
+html,body {
+    color:black; background-color:white; font-size:16px; padding:0; margin:0;
+}
+separator { clear:both; display:block; height:6px; }
+
+.grid {
+  display: grid;
+  float: left;
+  position: relative;
+  border: 1px solid;
+  border-block-start: 2px solid blue;
+  grid-template: 3px 5px 7px / 11px 7px 5px;
+  padding: 1px 1px 3px 2px;
+  margin-right: 4px;
+  width: 40px;
+  height: 30px;
+  grid-row-gap: 3px;
+}
+.vl.grid, .vr.grid, .vlr.grid, .vrl.grid { grid-row-gap: 4px; }
+
+item1,item2,item3 {
+  display: block;
+  background: grey;
+  justify-self: stretch;
+  align-self: stretch;
+}
+
+item1 { grid-area: 1 / 1; }
+item2 { grid-area: 2 / 2; }
+item3 { grid-area: 3 / 3; }
+
+.hl  { writing-mode: horizontal-tb; direction:ltr; }
+.hr  { writing-mode: horizontal-tb; direction:rtl; }
+.vl  { writing-mode: vertical-lr; }
+.vr  { writing-mode: vertical-rl; }
+.vlr { writing-mode: vertical-lr; direction:rtl; }
+.vrl { writing-mode: vertical-rl; direction:ltr; }
+
+.astart { align-content:start; }
+.aend { align-content:end; }
+.aflexstart { align-content:flex-start; }
+.aflexend { align-content:flex-end; }
+.acenter { align-content:center; }
+.aleft { align-content:left; }
+.aright { align-content:right; }
+
+.aspace-between{ align-content:space-between; }
+.aspace-around { align-content:space-around;  }
+.aspace-evenly { align-content:space-evenly;  }
+
+.astretch1, .astretch2, .astretch3, .astretch4 { align-content:stretch; }
+.astretch2 { grid-template-rows: minmax(3px,auto) 5px 7px; }
+.astretch3 { grid-template-rows: minmax(3px,auto) minmax(5px,auto) 7px; }
+.astretch4 { grid-template-rows: minmax(3px,auto) minmax(5px,auto) minmax(7px,auto); }
+
+</style>
+</head>
+<body>
+
+<script>
+var gridwm = [ "hl", "hr", "vl", "vr", "vlr", "vrl" ];
+var test = [ "start", "end", "flexstart", "flexend", "center", "left", "right",
+             "space-between", "space-around", "space-evenly",
+             "stretch1", "stretch2", "stretch3", "stretch4" ];
+for (var k = 0; k < test.length; ++k) {
+  for (var i = 0; i < gridwm.length; ++i) {
+      var div = document.createElement("div");
+      div.className = "grid a" + test[k] + " " + gridwm[i];
+      div.appendChild(document.createElement("item1"));
+      div.appendChild(document.createElement("item2"));
+      div.appendChild(document.createElement("item3"));
+      document.body.appendChild(div)
+  }
+    document.body.appendChild(document.createElement("separator"));
+}
+</script>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-grid/grid-row-gap-005.html
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>CSS Grid Test: Percentage 'grid-row-gap'</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1266268">
+  <link rel="help" href="http://dev.w3.org/csswg/css-grid/#gutters">
+  <link rel="match" href="grid-row-gap-005-ref.html">
+  <style type="text/css">
+html,body {
+    color:black; background-color:white; font-size:16px; padding:0; margin:0;
+}
+separator { clear:both; display:block; height:6px; }
+
+.grid {
+  display: grid;
+  float: left;
+  position: relative;
+  border: 1px solid;
+  border-block-start: 2px solid blue;
+  grid-template: 3px 5px 7px / 11px 7px 5px;
+  padding: 1px 1px 3px 2px;
+  margin-right: 4px;
+  width: 40px;
+  height: 30px;
+  grid-row-gap: 10%;
+}
+
+item1,item2,item3 {
+  display: block;
+  background: grey;
+  justify-self: stretch;
+  align-self: stretch;
+}
+
+item1 { grid-area: 1 / 1; }
+item2 { grid-area: 2 / 2; }
+item3 { grid-area: 3 / 3; }
+
+.hl  { writing-mode: horizontal-tb; direction:ltr; }
+.hr  { writing-mode: horizontal-tb; direction:rtl; }
+.vl  { writing-mode: vertical-lr; }
+.vr  { writing-mode: vertical-rl; }
+.vlr { writing-mode: vertical-lr; direction:rtl; }
+.vrl { writing-mode: vertical-rl; direction:ltr; }
+
+.astart { align-content:start; }
+.aend { align-content:end; }
+.aflexstart { align-content:flex-start; }
+.aflexend { align-content:flex-end; }
+.acenter { align-content:center; }
+.aleft { align-content:left; }
+.aright { align-content:right; }
+
+.aspace-between{ align-content:space-between; }
+.aspace-around { align-content:space-around;  }
+.aspace-evenly { align-content:space-evenly;  }
+
+.astretch1, .astretch2, .astretch3, .astretch4 { align-content:stretch; }
+.astretch2 { grid-template-rows: minmax(3px,auto) 5px 7px; }
+.astretch3 { grid-template-rows: minmax(3px,auto) minmax(5px,auto) 7px; }
+.astretch4 { grid-template-rows: minmax(3px,auto) minmax(5px,auto) minmax(7px,auto); }
+
+</style>
+</head>
+<body>
+
+<script>
+var gridwm = [ "hl", "hr", "vl", "vr", "vlr", "vrl" ];
+var test = [ "start", "end", "flexstart", "flexend", "center", "left", "right",
+             "space-between", "space-around", "space-evenly",
+             "stretch1", "stretch2", "stretch3", "stretch4" ];
+for (var k = 0; k < test.length; ++k) {
+  for (var i = 0; i < gridwm.length; ++i) {
+      var div = document.createElement("div");
+      div.className = "grid a" + test[k] + " " + gridwm[i];
+      div.appendChild(document.createElement("item1"));
+      div.appendChild(document.createElement("item2"));
+      div.appendChild(document.createElement("item3"));
+      document.body.appendChild(div)
+  }
+    document.body.appendChild(document.createElement("separator"));
+}
+</script>
+
+
+</body>
+</html>
--- a/layout/reftests/css-grid/reftest.list
+++ b/layout/reftests/css-grid/reftest.list
@@ -78,20 +78,22 @@ fuzzy-if(winWidget,1,36) == grid-auto-mi
 == grid-item-stretch-001.html grid-item-stretch-001-ref.html
 == grid-align-content-001.html grid-align-content-001-ref.html
 == grid-justify-content-001.html grid-justify-content-001-ref.html
 skip-if(Android&&isDebugBuild) == grid-justify-content-002.html grid-justify-content-002-ref.html # Bug 1245884 - slow
 skip-if(Android&&isDebugBuild) == grid-justify-content-003.html grid-justify-content-003-ref.html # Bug 1245884 - slow
 skip-if(Android&&isDebugBuild) == grid-column-gap-001.html grid-column-gap-001-ref.html # Bug 1245884 - slow
 == grid-column-gap-002.html grid-column-gap-002-ref.html
 == grid-column-gap-003.html grid-column-gap-003-ref.html
+== grid-column-gap-004.html grid-column-gap-004-ref.html
 == grid-row-gap-001.html grid-row-gap-001-ref.html
 skip-if(Android&&isDebugBuild) == grid-row-gap-002.html grid-row-gap-002-ref.html # Bug 1245884 - slow
 skip-if(Android&&isDebugBuild) == grid-row-gap-003.html grid-row-gap-003-ref.html # Bug 1245884 - slow
 skip-if(Android&&isDebugBuild) == grid-row-gap-004.html grid-row-gap-004-ref.html # Bug 1245884 - slow
+== grid-row-gap-005.html grid-row-gap-005-ref.html
 == grid-container-overflow-001.html grid-container-overflow-001-ref.html
 == grid-item-margin-left-auto-001.html grid-item-margin-left-auto-001-ref.html
 == grid-item-margin-left-auto-002.html grid-item-margin-left-auto-002-ref.html
 == grid-item-margin-left-auto-003.html grid-item-margin-left-auto-003-ref.html
 == grid-item-margin-left-auto-004.html grid-item-margin-left-auto-004-ref.html
 == grid-item-margin-left-right-auto-001.html grid-item-margin-left-right-auto-001-ref.html
 == grid-item-margin-left-right-auto-002.html grid-item-margin-left-right-auto-002-ref.html
 == grid-item-margin-left-right-auto-003.html grid-item-margin-left-right-auto-003-ref.html
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..42f8a2100b241aebf5c62e5057a51a933e6ff4d6
GIT binary patch
literal 156
zc%17D@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@o&cW^*T{eW{{8L&@)Q*nxj)Kn
z2C}?8T^vIs!c9*t6g|MeapZyyCx5tG;>%xMaf|kGe7(+c_;Xn3)h_N?2`BbEYEqNf
jh)mQUWEGDofD?9o(@Z>PzdjKTG?u~B)z4*}Q$iB}(UCOa
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0289b0394131fd1e1ae6fec71a49e42522b9bfcd
GIT binary patch
literal 287
zc%17D@N?(olHy`uVBq!ia0vp^svyk41SGxwY!3laoCO|{#S9GG!XV7ZFl&wkP>{XE
z)7O>#0jn^pg-mGYlNzAVK2I0Nkch)?ub<^)G8ABa(3zpyWE<HWe)>Zex0q@~=Y)!Y
z7@@MwpFhVr6zDO(|75u5@{&J$IC9N)7i%u{T5-ehx!Rq5*Z&p#b?g7#*|PCn^dXHn
z_QTb+Ij{O}Nj|mXW&1ou;@IV6hVw11w%TH!WM<s|oalGHw{j0h+P9_|XS<Wx_?t3q
zMV5VPxUsAKXqb(~wa*ea7P%jKW-Dj*IB?^&<m9R5472wb-Z(DZ*6AT6s8!~@^3$yU
gIRW+c@7?!`pI1*ks?ZYz^eF>_r>mdKI;Vst0DnPpAOHXW
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-round-1-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image repeat</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <style type="text/css">
+      .outer {
+        width: 72px;
+        height: 72px;
+        border: 1px solid black;
+        background-image: url(aqua-yellow-32x32.png);
+        background-size: 36px 36px;
+        background-repeat: repeat;
+      }
+    </style>
+    </head>
+    <body>
+      <div class="outer"></div>
+    </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-round-1a.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image round</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-round-1-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'round' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 72px;
+        height: 72px;
+        border: 1px solid black;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: round;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-round-1b.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image round</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-round-1-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'round round' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 72px;
+        height: 72px;
+        border: 1px solid black;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: round round;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-round-1c.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image round</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-round-1-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'repeat round' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 72px;
+        height: 72px;
+        border: 1px solid black;
+        background-size: 36px 36px;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: repeat round;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-round-1d.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image round</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-round-1-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'round repeat' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 72px;
+        height: 72px;
+        border: 1px solid black;
+        background-size: 32px 36px;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: round repeat;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-round-1e.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image round</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-round-1-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'repeat round' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 72px;
+        height: 72px;
+        border: 1px solid black;
+        background-size: 36px 32px;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: repeat round;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-round-2-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image repeat</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <style type="text/css">
+    .outer {
+      width: 72px;
+      height: 72px;
+      border: 1px solid black;
+      background-image: url(aqua-yellow-32x32.png);
+      background-size: 36px 36px;
+      background-repeat: repeat-x;
+    }
+    </style>
+    </head>
+    <body>
+      <div class="outer"></div>
+    </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-round-2.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image round no-repeat</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-round-2-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'round no-repeat' works correctly or not.">
+    <style type="text/css">
+    .outer {
+      width: 72px;
+      height: 72px;
+      border: 1px solid black;
+      background-image: url(aqua-yellow-32x32.png);
+      background-repeat: round no-repeat;
+    }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-round-3-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image repeat</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <style type="text/css">
+      #outer {
+        width: 72px;
+        height: 72px;
+        border: 1px solid black;
+        background-image: url(aqua-yellow-32x32.png);
+        background-size: 36px 36px;
+        background-repeat: repeat-y;
+      }
+    </style>
+    </head>
+    <body>
+      <div id="outer"><div id=inner></div></div>
+    </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-round-3.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image no-repeat round</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-round-3-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'no-repeat round' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 72px;
+        height: 72px;
+        border: 1px solid black;
+        background-image: url(aqua-yellow-32x32.png);
+        background-size: 36px auto;
+        background-repeat: no-repeat round;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-round-4-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image repeat with specified position</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <style type="text/css">
+    .outer {
+      width: 72px;
+      height: 72px;
+      border: 1px solid black;
+      background-image: url(aqua-yellow-32x32.png);
+      background-size: 36px 36px;
+      background-repeat: repeat;
+      background-position: 5px 5px;
+    }
+    </style>
+    </head>
+    <body>
+      <div class="outer"></div>
+    </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-round-4.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image round with specified position</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-round-4-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'round' works correctly or not.">
+    <style type="text/css">
+      #outer {
+        width: 72px;
+        height: 72px;
+        border: 1px solid black;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: round;
+        background-position: 5px 5px;
+      }
+    </style>
+  </head>
+  <body>
+    <div id="outer"></div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-1-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: position background image</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <style type="text/css">
+      .outer
+      {
+        border: 1px solid black;
+        width: 106px;
+        height: 106px;
+        display: flex;
+        justify-content: space-between;
+        align-content: space-between;
+        flex-wrap: wrap;
+      }
+      .inner
+      {
+        height: 32px;
+        width: 32px;
+        background-image: url(aqua-yellow-32x32.png);
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer">
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+    </div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-1a.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image space</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-space-1-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'space' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 106px;
+        height: 106px;
+        border: 1px solid black;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: space;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-1b.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image space with position</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-space-1-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'space' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 106px;
+        height: 106px;
+        border: 1px solid black;
+        background-image: url(aqua-yellow-32x32.png);
+        background-position: 15px 15px;
+        background-repeat: space;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-1c.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image space</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-space-1-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'space space' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 106px;
+        height: 106px;
+        border: 1px solid black;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: space space;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-2-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: position background image</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <style type="text/css">
+      .outer {
+        width: 48px;
+        height: 48px;
+        border: 1px solid black;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: no-repeat;
+        background-position: 5px 5px;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-2.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image round with specified position</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-round-4-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'space' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 48px;
+        height: 48px;
+        border: 1px solid black;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: space;
+        background-position: 5px 5px;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-3-ref.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: position background image</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <style type="text/css">
+      .outer1
+      {
+        border: 1px solid black;
+        width: 106px;
+        height: 106px;
+        display: flex;
+        justify-content: space-between;
+      }
+      .inner1
+      {
+        height: 32px;
+        width: 32px;
+        background-image: url(aqua-yellow-32x32.png);
+        margin-top: 40px;
+      }
+      .outer2
+      {
+        border: 1px solid black;
+        width: 106px;
+        height: 106px;
+        display: flex;
+        align-content: space-between;
+        flex-wrap: wrap;
+      }
+      .inner2
+      {
+        height: 32px;
+        width: 32px;
+        background-image: url(aqua-yellow-32x32.png);
+        margin-left: 40px;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer1">
+      <div class="inner1"></div>
+      <div class="inner1"></div>
+      <div class="inner1"></div>
+    </div>
+    <div class="outer2">
+      <div class="inner2"></div>
+      <div class="inner2"></div>
+      <div class="inner2"></div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-3.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image round with specified position</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-round-3-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'no-repeat space' and 'space no-repeat' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 106px;
+        height: 106px;
+        border: 1px solid black;
+      }
+      .inner1 {
+        width: 106px;
+        height: 106px;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: space no-repeat;
+        background-position: 7px 40px;
+      }
+      .inner2 {
+        width: 106px;
+        height: 106px;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: no-repeat space;
+        background-position: 40px 7px;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer">
+      <div class="inner1"></div>
+    </div>
+    <div class="outer">
+      <div class="inner2"></div>
+    </div>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-4-ref.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: position background image</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <style type="text/css">
+      .outer
+      {
+        border: 1px solid black;
+        width: 96px;
+        height: 106px;
+        display: flex;
+        align-content: space-between;
+        flex-wrap: wrap;
+      }
+      .inner
+      {
+        height: 32px;
+        width: 32px;
+        background-image: url(aqua-yellow-32x32.png);
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer">
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+    </div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-4.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image space</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-space-1-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'repeat space' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 96px;
+        height: 106px;
+        border: 1px solid black;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: repeat space;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-5-ref.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: position background image</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <style type="text/css">
+      .outer
+      {
+        border: 1px solid black;
+        width: 106px;
+        height: 96px;
+        display: flex;
+        justify-content: space-between;
+        flex-wrap: wrap;
+      }
+      .inner
+      {
+        height: 32px;
+        width: 32px;
+        background-image: url(aqua-yellow-32x32.png);
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer">
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+    </div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-5.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image space</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-space-1-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'space repeat' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 106px;
+        height: 96px;
+        border: 1px solid black;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: space repeat;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-6-ref.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: position background image</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <style type="text/css">
+      .outer
+      {
+        border: 1px solid black;
+        width: 192px;
+        height: 106px;
+        display: flex;
+        align-content: space-between;
+        flex-wrap: wrap;
+      }
+      .inner
+      {
+        height: 32px;
+        width: 64px;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: no-repeat;
+        background-size: 64px 32px;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer">
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+    </div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-6.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image space</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-space-1-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'round space' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 192px;
+        height: 106px;
+        border: 1px solid black;
+        background-size: 60px 32px;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: round space;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-7-ref.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: position background image</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <style type="text/css">
+      .outer
+      {
+        border: 1px solid black;
+        width: 106px;
+        height: 192px;
+        display: flex;
+        justify-content: space-between;
+        flex-wrap: wrap;
+      }
+      .inner
+      {
+        height: 64px;
+        width: 32px;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: no-repeat;
+        background-size: 32px 64px;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer">
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+      <div class="inner"></div>
+    </div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-7.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image space</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-space-1-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'space round' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 106px;
+        height: 192px;
+        border: 1px solid black;
+        background-size: 32px 60px;
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: space round;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-8-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: position background image</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <style type="text/css">
+      .outer
+      {
+        border: 20px solid rgba(0, 0, 0, 0.5);
+        width: 106px;
+        height: 106px;
+        background-image: url(aqua-yellow-37x37.png);
+        background-repeat: repeat;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/background-repeat-space-8.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>CSS Background: background-repeat: background image space</title>
+    <link rel="author" title="Ethan Lin" href="mailto:ethlin@mozilla.com">
+    <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+    <link rel="help" href="https://www.w3.org/TR/css3-background/#background-repeat">
+    <link rel="match" href="background-repeat-space-1-ref.html">
+    <meta name="assert" content="Test checks whether background-repeat: 'space' works correctly or not.">
+    <style type="text/css">
+      .outer {
+        width: 106px;
+        height: 106px;
+        border: 20px solid rgba(0, 0, 0, .5);
+        background-image: url(aqua-yellow-32x32.png);
+        background-repeat: space;
+    </style>
+  </head>
+  <body>
+    <div class="outer"></div>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/background/reftest.list
@@ -0,0 +1,19 @@
+# mask-repeat round/space test cases
+== background-repeat-space-1a.html background-repeat-space-1-ref.html
+== background-repeat-space-1b.html background-repeat-space-1-ref.html
+== background-repeat-space-1c.html background-repeat-space-1-ref.html
+== background-repeat-space-2.html background-repeat-space-2-ref.html
+== background-repeat-space-3.html background-repeat-space-3-ref.html
+== background-repeat-space-4.html background-repeat-space-4-ref.html
+== background-repeat-space-5.html background-repeat-space-5-ref.html
+== background-repeat-space-6.html background-repeat-space-6-ref.html
+== background-repeat-space-7.html background-repeat-space-7-ref.html
+== background-repeat-space-8.html background-repeat-space-8-ref.html
+== background-repeat-round-1a.html background-repeat-round-1-ref.html
+== background-repeat-round-1b.html background-repeat-round-1-ref.html
+== background-repeat-round-1c.html background-repeat-round-1-ref.html
+== background-repeat-round-1d.html background-repeat-round-1-ref.html
+== background-repeat-round-1e.html background-repeat-round-1-ref.html
+== background-repeat-round-2.html background-repeat-round-2-ref.html
+== background-repeat-round-3.html background-repeat-round-3-ref.html
+== background-repeat-round-4.html background-repeat-round-4-ref.html
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -783,9 +783,10 @@ CSS_KEY(reset-size, reset_size)
 //CSS_KEY(start, start)
 CSS_KEY(srgb, srgb)
 CSS_KEY(symbolic, symbolic)
 CSS_KEY(symbols, symbols)
 CSS_KEY(text-after-edge, text_after_edge)
 CSS_KEY(text-before-edge, text_before_edge)
 CSS_KEY(use-script, use_script)
 CSS_KEY(-moz-crisp-edges, _moz_crisp_edges)
+CSS_KEY(space, space)
 
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -2148,44 +2148,41 @@ CSSParserImpl::ParseSourceSizeList(const
     // Percentages are not allowed in a <source-size-value>, to avoid
     // confusion about what it would be relative to.
     if (ParseNonNegativeVariant(value, VARIANT_LCALC, nullptr) !=
         CSSParseResult::Ok) {
       hitError = true;
       break;
     }
 
+    if (GetToken(true)) {
+      if (!mToken.IsSymbol(',')) {
+        REPORT_UNEXPECTED_TOKEN(PEParseSourceSizeListNotComma);
+        hitError = true;
+        break;
+      }
+    }
+
     aQueries.AppendElement(query.forget());
     aValues.AppendElement(value);
-
-    if (!GetToken(true)) {
-      // Expected EOF
-      break;
-    }
-
-    if (eCSSToken_Symbol != mToken.mType || mToken.mSymbol != ',') {
-      REPORT_UNEXPECTED_TOKEN(PEParseSourceSizeListNotComma);
-      hitError = true;
-      break;
-    }
   }
 
   if (hitError) {
     // Per spec, a parse failure in this list invalidates it
     // entirely. Currently, this grammar is specified standalone and not part of
     // any larger grammar, so it doesn't make sense to try to advance the token
     // beyond it.
     OUTPUT_ERROR();
   }
 
   CLEAR_ERROR();
   ReleaseScanner();
   mHTMLMediaMode = false;
 
-  return !hitError;
+  return !aQueries.IsEmpty();
 }
 
 bool
 CSSParserImpl::ParseColorString(const nsSubstring& aBuffer,
                                 nsIURI* aURI, // for error reporting
                                 uint32_t aLineNumber, // for error reporting
                                 nsCSSValue& aValue,
                                 bool aSuppressErrors /* false */)
@@ -9750,22 +9747,22 @@ bool
 CSSParserImpl::ParseGridGap()
 {
   nsCSSValue first;
   if (ParseSingleTokenVariant(first, VARIANT_INHERIT, nullptr)) {
     AppendValue(eCSSProperty_grid_row_gap, first);
     AppendValue(eCSSProperty_grid_column_gap, first);
     return true;
   }
-  if (ParseNonNegativeVariant(first, VARIANT_LCALC, nullptr) !=
+  if (ParseNonNegativeVariant(first, VARIANT_LPCALC, nullptr) !=
         CSSParseResult::Ok) {
     return false;
   }
   nsCSSValue second;
-  auto result = ParseNonNegativeVariant(second, VARIANT_LCALC, nullptr);
+  auto result = ParseNonNegativeVariant(second, VARIANT_LPCALC, nullptr);
   if (result == CSSParseResult::Error) {
     return false;
   }
   AppendValue(eCSSProperty_grid_row_gap, first);
   AppendValue(eCSSProperty_grid_column_gap,
               result == CSSParseResult::NotFound ? first : second);
   return true;
 }
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -2138,20 +2138,20 @@ CSS_PROP_POSITION(
 CSS_PROP_POSITION(
     grid-column-gap,
     grid_column_gap,
     GridColumnGap,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_NONNEGATIVE |
         CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
     "layout.css.grid.enabled",
-    VARIANT_HL | VARIANT_CALC,
+    VARIANT_HLP | VARIANT_CALC,
     nullptr,
     offsetof(nsStylePosition, mGridColumnGap),
-    eStyleAnimType_nscoord)
+    eStyleAnimType_Coord)
 CSS_PROP_POSITION(
     grid-column-start,
     grid_column_start,
     GridColumnStart,
     CSS_PROPERTY_PARSE_FUNCTION,
     "layout.css.grid.enabled",
     0,
     nullptr,
@@ -2182,20 +2182,20 @@ CSS_PROP_POSITION(
 CSS_PROP_POSITION(
     grid-row-gap,
     grid_row_gap,
     GridRowGap,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_NONNEGATIVE |
         CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
     "layout.css.grid.enabled",
-    VARIANT_HL | VARIANT_CALC,
+    VARIANT_HLP | VARIANT_CALC,
     nullptr,
     offsetof(nsStylePosition, mGridRowGap),
-    eStyleAnimType_nscoord)
+    eStyleAnimType_Coord)
 CSS_PROP_POSITION(
     grid-row-start,
     grid_row_start,
     GridRowStart,
     CSS_PROPERTY_PARSE_FUNCTION,
     "layout.css.grid.enabled",
     0,
     nullptr,
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -930,22 +930,26 @@ const KTableEntry nsCSSProps::kImageLaye
   { eCSSKeyword_UNKNOWN, -1 }
 };
 
 const KTableEntry nsCSSProps::kImageLayerRepeatKTable[] = {
   { eCSSKeyword_no_repeat,  NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT },
   { eCSSKeyword_repeat,     NS_STYLE_IMAGELAYER_REPEAT_REPEAT },
   { eCSSKeyword_repeat_x,   NS_STYLE_IMAGELAYER_REPEAT_REPEAT_X },
   { eCSSKeyword_repeat_y,   NS_STYLE_IMAGELAYER_REPEAT_REPEAT_Y },
+  { eCSSKeyword_round,      NS_STYLE_IMAGELAYER_REPEAT_ROUND},
+  { eCSSKeyword_space,      NS_STYLE_IMAGELAYER_REPEAT_SPACE},
   { eCSSKeyword_UNKNOWN, -1 }
 };
 
 const KTableEntry nsCSSProps::kImageLayerRepeatPartKTable[] = {
   { eCSSKeyword_no_repeat,  NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT },
   { eCSSKeyword_repeat,     NS_STYLE_IMAGELAYER_REPEAT_REPEAT },
+  { eCSSKeyword_round,      NS_STYLE_IMAGELAYER_REPEAT_ROUND},
+  { eCSSKeyword_space,      NS_STYLE_IMAGELAYER_REPEAT_SPACE},
   { eCSSKeyword_UNKNOWN, -1 }
 };
 
 const KTableEntry nsCSSProps::kImageLayerSizeKTable[] = {
   { eCSSKeyword_contain, NS_STYLE_IMAGELAYER_SIZE_CONTAIN },
   { eCSSKeyword_cover,   NS_STYLE_IMAGELAYER_SIZE_COVER },
   { eCSSKeyword_UNKNOWN, -1 }
 };
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -2831,25 +2831,25 @@ nsComputedDOMStyle::DoGetGridRowEnd()
 {
   return GetGridLine(StylePosition()->mGridRowEnd);
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetGridColumnGap()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-  val->SetAppUnits(StylePosition()->mGridColumnGap);
+  SetValueToCoord(val, StylePosition()->mGridColumnGap, true);
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetGridRowGap()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-  val->SetAppUnits(StylePosition()->mGridRowGap);
+  SetValueToCoord(val, StylePosition()->mGridRowGap, true);
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetPaddingTop()
 {
   return GetPaddingWidthFor(NS_SIDE_TOP);
 }
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -6515,16 +6515,20 @@ struct BackgroundItemComputer<nsCSSValue
       aComputedValue.mXRepeat = NS_STYLE_IMAGELAYER_REPEAT_REPEAT;
       aComputedValue.mYRepeat = NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT;
       break;
     case NS_STYLE_IMAGELAYER_REPEAT_REPEAT_Y:
       aComputedValue.mXRepeat = NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT;
       aComputedValue.mYRepeat = NS_STYLE_IMAGELAYER_REPEAT_REPEAT;
       break;
     default:
+      NS_ASSERTION(value == NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT ||
+                   value == NS_STYLE_IMAGELAYER_REPEAT_REPEAT ||
+                   value == NS_STYLE_IMAGELAYER_REPEAT_SPACE ||
+                   value == NS_STYLE_IMAGELAYER_REPEAT_ROUND, "Unexpected value");
       aComputedValue.mXRepeat = value;
       hasContraction = false;
       break;
     }
 
     if (hasContraction) {
       NS_ASSERTION(aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Null,
                    "Invalid unit.");
@@ -6533,17 +6537,19 @@ struct BackgroundItemComputer<nsCSSValue
 
     switch (aSpecifiedValue->mYValue.GetUnit()) {
     case eCSSUnit_Null:
       aComputedValue.mYRepeat = aComputedValue.mXRepeat;
       break;
     case eCSSUnit_Enumerated:
       value = aSpecifiedValue->mYValue.GetIntValue();
       NS_ASSERTION(value == NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT ||
-                   value == NS_STYLE_IMAGELAYER_REPEAT_REPEAT, "Unexpected value");
+                   value == NS_STYLE_IMAGELAYER_REPEAT_REPEAT ||
+                   value == NS_STYLE_IMAGELAYER_REPEAT_SPACE ||
+                   value == NS_STYLE_IMAGELAYER_REPEAT_ROUND, "Unexpected value");
       aComputedValue.mYRepeat = value;
       break;
     default:
       NS_NOTREACHED("Unexpected CSS value");
       break;
     }
   }
 };
@@ -8578,37 +8584,32 @@ nsRuleNode::ComputePositionData(void* aS
 
   // grid-row-end
   SetGridLine(*aRuleData->ValueForGridRowEnd(),
               pos->mGridRowEnd,
               parentPos->mGridRowEnd,
               conditions);
 
   // grid-column-gap
-  nsStyleCoord tempCoord;
   if (SetCoord(*aRuleData->ValueForGridColumnGap(),
-               tempCoord, nsStyleCoord(parentPos->mGridColumnGap,
-                                       nsStyleCoord::CoordConstructor),
-               SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_CALC_LENGTH_ONLY |
+               pos->mGridColumnGap, parentPos->mGridColumnGap,
+               SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
                SETCOORD_CALC_CLAMP_NONNEGATIVE | SETCOORD_UNSET_INITIAL,
                aContext, mPresContext, conditions)) {
-    pos->mGridColumnGap = tempCoord.GetCoordValue();
   } else {
     MOZ_ASSERT(aRuleData->ValueForGridColumnGap()->GetUnit() == eCSSUnit_Null,
                "unexpected unit");
   }
 
   // grid-row-gap
   if (SetCoord(*aRuleData->ValueForGridRowGap(),
-               tempCoord, nsStyleCoord(parentPos->mGridRowGap,
-                                       nsStyleCoord::CoordConstructor),
-               SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_CALC_LENGTH_ONLY |
+               pos->mGridRowGap, parentPos->mGridRowGap,
+               SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
                SETCOORD_CALC_CLAMP_NONNEGATIVE | SETCOORD_UNSET_INITIAL,
                aContext, mPresContext, conditions)) {
-    pos->mGridRowGap = tempCoord.GetCoordValue();
   } else {
     MOZ_ASSERT(aRuleData->ValueForGridRowGap()->GetUnit() == eCSSUnit_Null,
                "unexpected unit");
   }
 
   // z-index
   const nsCSSValue* zIndexValue = aRuleData->ValueForZIndex();
   if (! SetCoord(*zIndexValue, pos->mZIndex, parentPos->mZIndex,
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -295,16 +295,18 @@ enum class FillMode : uint32_t;
 #define NS_STYLE_IMAGELAYER_POSITION_LEFT            (1<<3)
 #define NS_STYLE_IMAGELAYER_POSITION_RIGHT           (1<<4)
 
 // See nsStyleImageLayers
 #define NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT         0x00
 #define NS_STYLE_IMAGELAYER_REPEAT_REPEAT_X          0x01
 #define NS_STYLE_IMAGELAYER_REPEAT_REPEAT_Y          0x02
 #define NS_STYLE_IMAGELAYER_REPEAT_REPEAT            0x03
+#define NS_STYLE_IMAGELAYER_REPEAT_SPACE             0x04
+#define NS_STYLE_IMAGELAYER_REPEAT_ROUND             0x05
 
 // See nsStyleImageLayers
 #define NS_STYLE_IMAGELAYER_SIZE_CONTAIN             0
 #define NS_STYLE_IMAGELAYER_SIZE_COVER               1
 
 // Mask mode
 #define NS_STYLE_MASK_MODE_ALPHA                0
 #define NS_STYLE_MASK_MODE_LUMINANCE            1
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -1417,16 +1417,18 @@ nsStylePosition::nsStylePosition(StyleSt
   , mJustifySelf(NS_STYLE_JUSTIFY_AUTO)
   , mFlexDirection(NS_STYLE_FLEX_DIRECTION_ROW)
   , mFlexWrap(NS_STYLE_FLEX_WRAP_NOWRAP)
   , mObjectFit(NS_STYLE_OBJECT_FIT_FILL)
   , mOrder(NS_STYLE_ORDER_INITIAL)
   , mFlexGrow(0.0f)
   , mFlexShrink(1.0f)
   , mZIndex(eStyleUnit_Auto)
+  , mGridColumnGap(nscoord(0), nsStyleCoord::CoordConstructor)
+  , mGridRowGap(nscoord(0), nsStyleCoord::CoordConstructor)
 {
   MOZ_COUNT_CTOR(nsStylePosition);
 
   // positioning values not inherited
 
   mObjectPosition.SetInitialPercentValues(0.5f);
 
   nsStyleCoord  autoCoord(eStyleUnit_Auto);
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1720,18 +1720,18 @@ public:
 
   // nullptr for 'none'
   RefPtr<mozilla::css::GridTemplateAreasValue> mGridTemplateAreas;
 
   nsStyleGridLine mGridColumnStart;
   nsStyleGridLine mGridColumnEnd;
   nsStyleGridLine mGridRowStart;
   nsStyleGridLine mGridRowEnd;
-  nscoord         mGridColumnGap;       // [reset] coord, calc
-  nscoord         mGridRowGap;          // [reset] coord, calc
+  nsStyleCoord    mGridColumnGap;       // [reset] coord, percent, calc
+  nsStyleCoord    mGridRowGap;          // [reset] coord, percent, calc
 
   // FIXME: Logical-coordinate equivalents to these WidthDepends... and
   // HeightDepends... methods have been introduced (see below); we probably
   // want to work towards removing the physical methods, and using the logical
   // ones in all cases.
 
   bool WidthDependsOnContainer() const
     {
--- a/layout/style/test/gen-css-properties.py
+++ b/layout/style/test/gen-css-properties.py
@@ -7,15 +7,18 @@ from __future__ import print_function
 import os
 import sys
 import subprocess
 
 def main(output, css_properties, exe):
     # moz.build passes in the exe name without any path, so to run it we need to
     # prepend the './'
     run_exe = exe if os.path.isabs(exe) else './%s' % exe
-    data = subprocess.check_output([run_exe])
+
+    # Use universal_newlines so everything is '\n', which gets converted to
+    # '\r\n' when writing out the file in Windows.
+    data = subprocess.check_output([run_exe], universal_newlines=True)
     with open(css_properties) as f:
         data += f.read()
     output.write(data)
 
 if __name__ == '__main__':
     main(sys.stdout, *sys.argv[1:])
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -2399,23 +2399,42 @@ var gCSSProperties = {
       "repeat-x, repeat-x",
       "repeat, no-repeat",
       "repeat-y, no-repeat, repeat-y",
       "repeat, repeat, repeat",
       "repeat no-repeat",
       "no-repeat repeat",
       "no-repeat no-repeat",
       "repeat repeat, repeat repeat",
+      "round, repeat",
+      "round repeat, repeat-x",
+      "round no-repeat, repeat-y",
+      "round round",
+      "space, repeat",
+      "space repeat, repeat-x",
+      "space no-repeat, repeat-y",
+      "space space",
+      "space round"
     ],
     invalid_values: [ "repeat repeat repeat",
                       "repeat-x repeat-y",
                       "repeat repeat-x",
                       "repeat repeat-y",
                       "repeat-x repeat",
-                      "repeat-y repeat" ]
+                      "repeat-y repeat",
+                      "round round round",
+                      "repeat-x round",
+                      "round repeat-x",
+                      "repeat-y round",
+                      "round repeat-y",
+                      "space space space",
+                      "repeat-x space",
+                      "space repeat-x",
+                      "repeat-y space",
+                      "space repeat-y" ]
   },
   "background-size": {
     domProp: "backgroundSize",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "auto", "auto auto" ],
     other_values: [ "contain", "cover", "100px auto", "auto 100px", "100% auto", "auto 100%", "25% 50px", "3em 40%",
       "calc(20px)",
@@ -6438,36 +6457,38 @@ if (IsCSSPropertyPrefEnabled("layout.css
     invalid_values: gridAreaInvalidValues
   };
 
   gCSSProperties["grid-column-gap"] = {
     domProp: "gridColumnGap",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "0" ],
-    other_values: [ "2px", "1em", "calc(1px + 1em)" ],
-    invalid_values: [ "-1px", "2%", "auto", "none", "1px 1px", "calc(1%)" ],
+    other_values: [ "2px", "2%", "1em", "calc(1px + 1em)", "calc(1%)",
+                    "calc(1% + 1ch)" ],
+    invalid_values: [ "-1px", "auto", "none", "1px 1px", "-1%" ],
   };
   gCSSProperties["grid-row-gap"] = {
     domProp: "gridRowGap",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "0" ],
-    other_values: [ "2px", "1em", "calc(1px + 1em)" ],
-    invalid_values: [ "-1px", "2%", "auto", "none", "1px 1px", "calc(1%)" ],
+    other_values: [ "2px", "2%", "1em", "calc(1px + 1em)", "calc(1%)",
+                    "calc(1% + 1ch)" ],
+    invalid_values: [ "-1px", "auto", "none", "1px 1px", "-1%" ],
   };
   gCSSProperties["grid-gap"] = {
     domProp: "gridGap",
     inherited: false,
     type: CSS_TYPE_TRUE_SHORTHAND,
     subproperties: [ "grid-column-gap", "grid-row-gap" ],
     initial_values: [ "0", "0 0" ],
-    other_values: [ "1ch 0", "1em 1px", "calc(1px + 1ch)" ],
+    other_values: [ "1ch 0", "1px 1%", "1em 1px", "calc(1px) calc(1%)" ],
     invalid_values: [ "-1px", "1px -1px", "1px 1px 1px", "inherit 1px",
-                      "1px 1%", "1px auto" ]
+                      "1px auto" ]
   };
 }
 
 if (IsCSSPropertyPrefEnabled("layout.css.display-contents.enabled")) {
   gCSSProperties["display"].other_values.push("contents");
 }
 
 if (IsCSSPropertyPrefEnabled("layout.css.contain.enabled")) {
--- a/layout/style/test/test_transitions_per_property.html
+++ b/layout/style/test/test_transitions_per_property.html
@@ -1892,16 +1892,18 @@ function test_font_weight(prop) {
 }
 
 function test_grid_gap(prop) {
   if (!SpecialPowers.getBoolPref("layout.css.grid.enabled")) {
     return;
   }
   test_length_transition(prop);
   test_length_clamped(prop);
+  test_percent_transition(prop);
+  test_percent_clamped(prop);
 }
 
 function test_pos_integer_or_auto_transition(prop) {
   div.style.setProperty("transition-property", "none", "");
   div.style.setProperty(prop, "4", "");
   is(cs.getPropertyValue(prop), "4",
      "integer-valued property " + prop + ": computed value before transition");
   div.style.setProperty("transition-property", prop, "");
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -499,17 +499,17 @@ class RefTest(object):
 
         return int(any(t.retcode != 0 for t in threads))
 
     def handleTimeout(self, timeout, proc, utilityPath, debuggerInfo):
         """handle process output timeout"""
         # TODO: bug 913975 : _processOutput should call self.processOutputLine
         # one more time one timeout (I think)
         self.log.error("%s | application timed out after %d seconds with no output" % (self.lastTestSeen, int(timeout)))
-        self.log.warning("Force-terminating active process(es).");
+        self.log.error("Force-terminating active process(es).");
         self.killAndGetStack(
             proc, utilityPath, debuggerInfo, dump_screen=not debuggerInfo)
 
     def dumpScreen(self, utilityPath):
         if self.haveDumpedScreen:
             self.log.info("Not taking screenshot here: see the one that was previously logged")
             return
         self.haveDumpedScreen = True
--- a/layout/tools/reftest/runreftestmulet.py
+++ b/layout/tools/reftest/runreftestmulet.py
@@ -157,17 +157,17 @@ class MuletReftest(RefTest):
 
         if self.build_type == "mulet":
             args += ['-chrome', 'chrome://b2g/content/shell.html']
         return cmd, args
 
     def _on_timeout(self):
         msg = "%s | application timed out after %s seconds with no output"
         self.log.testFail(msg % (self.last_test, self.timeout))
-        self.log.warning("Force-terminating active process(es).");
+        self.log.error("Force-terminating active process(es).");
 
         # kill process to get a stack
         self.runner.stop(sig=signal.SIGABRT)
 
     def _unlockScreen(self):
         self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
         self.marionette.import_script(os.path.abspath(
             os.path.join(__file__, os.path.pardir, "gaia_lock_screen.js")))
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1513,17 +1513,17 @@ pref("network.http.enforce-framing.soft"
 pref("network.http.enable-packaged-apps", false);
 
 // Enable this to bring in the signature verification if the signature exists.
 // Set to false if you don't need the signed packaged web app support (i.e. NSec).
 pref("network.http.signed-packages.enabled", false);
 
 // If it is set to false, headers with empty value will not appear in the header
 // array - behavior as it used to be. If it is true: empty headers coming from
-// the network will exits in header array as empty string. Call SetHeader with
+// the network will exist in header array as empty string. Call SetHeader with
 // an empty value will still delete the header.(Bug 6699259)
 pref("network.http.keep_empty_response_headers_as_empty_string", false);
 
 // default values for FTP
 // in a DSCP environment this should be 40 (0x28, or AF11), per RFC-4594,
 // Section 4.8 "High-Throughput Data Service Class", and 80 (0x50, or AF22)
 // per Section 4.7 "Low-Latency Data Service Class".
 pref("network.ftp.data.qos", 0);
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -460,16 +460,25 @@ NS_IMETHODIMP
 LoadInfo::GetAllowChrome(bool* aResult)
 {
   *aResult =
     (mSecurityFlags & nsILoadInfo::SEC_ALLOW_CHROME);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+LoadInfo::GetDisallowScript(bool* aResult)
+{
+  *aResult =
+    (mSecurityFlags & nsILoadInfo::SEC_DISALLOW_SCRIPT);
+  return NS_OK;
+}
+
+
+NS_IMETHODIMP
 LoadInfo::GetDontFollowRedirects(bool* aResult)
 {
   *aResult =
     (mSecurityFlags & nsILoadInfo::SEC_DONT_FOLLOW_REDIRECTS);
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/netwerk/base/nsILoadInfo.idl
+++ b/netwerk/base/nsILoadInfo.idl
@@ -143,44 +143,49 @@ interface nsILoadInfo : nsISupports
   const unsigned long SEC_ABOUT_BLANK_INHERITS = (1<<9);
 
   /**
    * Allow access to chrome: packages that are content accessible.
    */
   const unsigned long SEC_ALLOW_CHROME = (1<<10);
 
   /**
+   * Disallow access to javascript: uris.
+   */
+  const unsigned long SEC_DISALLOW_SCRIPT = (1<<11);
+
+  /**
    * Don't follow redirects. Instead the redirect response is returned
    * as a successful response for the channel.
    *
    * Redirects not initiated by a server response, i.e. REDIRECT_INTERNAL and
    * REDIRECT_STS_UPGRADE, are still followed.
    *
    * Note: If this flag is set and the channel response is a redirect, then
    * the response body might not be available.
    * This can happen if the redirect was cached.
    */
-  const unsigned long SEC_DONT_FOLLOW_REDIRECTS = (1<<11);
+  const unsigned long SEC_DONT_FOLLOW_REDIRECTS = (1<<12);
 
   /**
    * Force private browsing. Setting this flag the private browsing can be
    * enforce even when a loading is not happening in the context of a document.
    *
    * If the flag is true, even if a document context is present,
    * GetUsePrivateBrowsing will always return true.
    */
-  const unsigned long SEC_FORCE_PRIVATE_BROWSING = (1<<12);
+  const unsigned long SEC_FORCE_PRIVATE_BROWSING = (1<<13);
 
   /**
    * The SEC_FORCE_INHERIT_PRINCIPAL flag may be dropped when a load info
    * object is created.  Specifically, it will be dropped if the SEC_SANDBOXED
    * flag is also present.  This flag is set if SEC_FORCE_INHERIT_PRINCIPAL was
    * dropped.
    */
-  const unsigned long SEC_FORCE_INHERIT_PRINCIPAL_WAS_DROPPED = (1<<13);
+  const unsigned long SEC_FORCE_INHERIT_PRINCIPAL_WAS_DROPPED = (1<<14);
 
   /**
    * The loadingPrincipal is the principal that is responsible for the load.
    * It is *NOT* the principal tied to the resource/URI that this
    * channel is loading, it's the principal of the resource's
    * caller or requester. For example, if this channel is loading
    * an image from http://b.com that is embedded in a document
    * who's origin is http://a.com, the loadingPrincipal is http://a.com.
@@ -309,16 +314,22 @@ interface nsILoadInfo : nsISupports
 
   /**
    * If allowChrome is true, then use nsIScriptSecurityManager::ALLOW_CHROME
    * when calling CheckLoadURIWithPrincipal().
    */
   [infallible] readonly attribute boolean allowChrome;
 
   /**
+   * If disallowScript is true, then use nsIScriptSecurityManager::DISALLOW_SCRIPT
+   * when calling CheckLoadURIWithPrincipal().
+   */
+  [infallible] readonly attribute boolean disallowScript;
+
+  /**
    * Returns true if SEC_DONT_FOLLOW_REDIRECTS is set.
    */
   [infallible] readonly attribute boolean dontFollowRedirects;
 
   /**
    * The external contentPolicyType of the channel, used for security checks
    * like Mixed Content Blocking and Content Security Policy.
    *
--- a/netwerk/base/nsSimpleURI.cpp
+++ b/netwerk/base/nsSimpleURI.cpp
@@ -192,26 +192,22 @@ nsSimpleURI::GetHasRef(bool *result)
 }
 
 NS_IMETHODIMP
 nsSimpleURI::SetSpec(const nsACString &aSpec)
 {
     NS_ENSURE_STATE(mMutable);
     
     const nsAFlatCString& flat = PromiseFlatCString(aSpec);
-    const char* specPtr = flat.get();
 
     // filter out unexpected chars "\r\n\t" if necessary
     nsAutoCString filteredSpec;
-    int32_t specLen;
-    if (net_FilterURIString(specPtr, filteredSpec)) {
-        specPtr = filteredSpec.get();
-        specLen = filteredSpec.Length();
-    } else
-        specLen = flat.Length();
+    net_FilterURIString(flat, filteredSpec);
+    const char* specPtr = filteredSpec.get();
+    int32_t specLen = filteredSpec.Length();
 
     // nsSimpleURI currently restricts the charset to US-ASCII
     nsAutoCString spec;
     NS_EscapeURL(specPtr, specLen, esc_OnlyNonASCII|esc_AlwaysCopy, spec);
 
     int32_t colonPos = spec.FindChar(':');
     if (colonPos < 0 || !net_IsValidScheme(spec.get(), colonPos))
         return NS_ERROR_MALFORMED_URI;
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -1288,47 +1288,35 @@ IsSpecialProtocol(const nsACString &inpu
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetSpec(const nsACString &input)
 {
     ENSURE_MUTABLE();
 
     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
-    const char *spec = flat.get();
-    int32_t specLength = flat.Length();
-
-    LOG(("nsStandardURL::SetSpec [spec=%s]\n", spec));
-
-    if (!spec || !*spec)
-        return NS_ERROR_MALFORMED_URI;
+    LOG(("nsStandardURL::SetSpec [spec=%s]\n", flat.get()));
 
     if (input.Length() > (uint32_t) net_GetURLMaxLength()) {
         return NS_ERROR_MALFORMED_URI;
     }
 
-    // NUL characters aren't allowed
-    // \r\n\t are stripped out instead of returning error(see below)
-    if (input.Contains('\0')) {
+    // filter out unexpected chars "\r\n\t" if necessary
+    nsAutoCString filteredURI;
+    net_FilterURIString(flat, filteredURI);
+
+    if (filteredURI.Length() == 0) {
         return NS_ERROR_MALFORMED_URI;
     }
 
     // Make a backup of the curent URL
     nsStandardURL prevURL(false,false);
     prevURL.CopyMembers(this, eHonorRef);
     Clear();
 
-    // filter out unexpected chars "\r\n\t" if necessary
-    nsAutoCString filteredURI;
-    if (!net_FilterURIString(spec, filteredURI)) {
-        // Copy the content into filteredURI even if no whitespace was stripped.
-        // We need a non-const buffer to perform backslash replacement.
-        filteredURI = input;
-    }
-
     if (IsSpecialProtocol(filteredURI)) {
         // Bug 652186: Replace all backslashes with slashes when parsing paths
         // Stop when we reach the query or the hash.
         nsAutoCString::iterator start;
         nsAutoCString::iterator end;
         filteredURI.BeginWriting(start);
         filteredURI.EndWriting(end);
         while (start != end) {
@@ -1337,19 +1325,18 @@ nsStandardURL::SetSpec(const nsACString 
             }
             if (*start == '\\') {
                 *start = '/';
             }
             start++;
         }
     }
 
-    spec = filteredURI.get();
-    specLength = filteredURI.Length();
-
+    const char *spec = filteredURI.get();
+    int32_t specLength = filteredURI.Length();
 
     // parse the given URL...
     nsresult rv = ParseURL(spec, specLength);
     if (NS_SUCCEEDED(rv)) {
         // finally, use the URLSegment member variables to build a normalized
         // copy of |spec|
         rv = BuildNormalizedSpec(spec);
     }
@@ -2117,29 +2104,22 @@ nsresult nsStandardURL::CopyMembers(nsSt
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::Resolve(const nsACString &in, nsACString &out)
 {
     const nsPromiseFlatCString &flat = PromiseFlatCString(in);
-    const char *relpath = flat.get();
-
     // filter out unexpected chars "\r\n\t" if necessary
     nsAutoCString buf;
-    int32_t relpathLen;
-    if (!net_FilterURIString(relpath, buf)) {
-        // Copy the content into filteredURI even if no whitespace was stripped.
-        // We need a non-const buffer to perform backslash replacement.
-        buf = in;
-    }
-
-    relpath = buf.get();
-    relpathLen = buf.Length();
+    net_FilterURIString(flat, buf);
+
+    const char *relpath = buf.get();
+    int32_t relpathLen = buf.Length();
 
     char *result = nullptr;
 
     LOG(("nsStandardURL::Resolve [this=%p spec=%s relpath=%s]\n",
         this, mSpec.get(), relpath));
 
     NS_ASSERTION(mParser, "no parser: unitialized");
 
@@ -2535,17 +2515,17 @@ nsStandardURL::SetFilePath(const nsACStr
         return SetPath(flat);
 
     if (filepath && *filepath) {
         nsAutoCString spec;
         uint32_t dirPos, basePos, extPos;
         int32_t dirLen, baseLen, extLen;
         nsresult rv;
 
-        rv = mParser->ParseFilePath(filepath, -1,
+        rv = mParser->ParseFilePath(filepath, flat.Length(),
                                     &dirPos, &dirLen,
                                     &basePos, &baseLen,
                                     &extPos, &extLen);
         if (NS_FAILED(rv)) return rv;
 
         // build up new candidate spec
         spec.Assign(mSpec.get(), mPath.mPos);
 
@@ -2624,17 +2604,17 @@ nsStandardURL::SetQuery(const nsACString
             ShiftFromRef(-(mQuery.mLen + 1));
             mPath.mLen -= (mQuery.mLen + 1);
             mQuery.mPos = 0;
             mQuery.mLen = -1;
         }
         return NS_OK;
     }
 
-    int32_t queryLen = strlen(query);
+    int32_t queryLen = flat.Length();
     if (query[0] == '?') {
         query++;
         queryLen--;
     }
 
     if (mQuery.mLen < 0) {
         if (mRef.mLen < 0)
             mQuery.mPos = mSpec.Length();
@@ -2674,20 +2654,16 @@ nsStandardURL::SetRef(const nsACString &
 {
     ENSURE_MUTABLE();
 
     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
     const char *ref = flat.get();
 
     LOG(("nsStandardURL::SetRef [ref=%s]\n", ref));
 
-    if (input.Contains('\0')) {
-        return NS_ERROR_MALFORMED_URI;
-    }
-
     if (mPath.mLen < 0)
         return SetPath(flat);
 
     if (mSpec.Length() + input.Length() - Ref().Length() > (uint32_t) net_GetURLMaxLength()) {
         return NS_ERROR_MALFORMED_URI;
     }
 
     InvalidateCache();
@@ -2704,17 +2680,17 @@ nsStandardURL::SetRef(const nsACString &
         return NS_OK;
     }
 
     int32_t refLen = flat.Length();
     if (ref[0] == '#') {
         ref++;
         refLen--;
     }
-    
+
     if (mRef.mLen < 0) {
         mSpec.Append('#');
         ++mPath.mLen;  // Include the # in the path.
         mRef.mPos = mSpec.Length();
         mRef.mLen = 0;
     }
 
     // If precent encoding is necessary, `ref` will point to `buf`'s content.
@@ -2775,17 +2751,17 @@ nsStandardURL::SetFileName(const nsACStr
             mExtension.mLen = -1;
         }
     }
     else {
         nsresult rv;
         URLSegment basename, extension;
 
         // let the parser locate the basename and extension
-        rv = mParser->ParseFileName(filename, -1,
+        rv = mParser->ParseFileName(filename, flat.Length(),
                                     &basename.mPos, &basename.mLen,
                                     &extension.mPos, &extension.mLen);
         if (NS_FAILED(rv)) return rv;
 
         if (basename.mLen < 0) {
             // remove existing filename
             if (mBasename.mLen >= 0) {
                 uint32_t len = mBasename.mLen;
--- a/netwerk/base/nsURLHelper.cpp
+++ b/netwerk/base/nsURLHelper.cpp
@@ -470,22 +470,29 @@ net_IsValidSchemeChar(const char aChar)
     return false;
 }
 
 /* Extract URI-Scheme if possible */
 nsresult
 net_ExtractURLScheme(const nsACString &inURI,
                      nsACString& scheme)
 {
-    Tokenizer p(inURI, "\r\n\t");
+    nsACString::const_iterator start, end;
+    inURI.BeginReading(start);
+    inURI.EndReading(end);
 
-    while (p.CheckWhite() || p.CheckChar(' ')) {
-        // Skip leading whitespace
+    // Strip C0 and space from begining
+    while (start != end) {
+        if ((uint8_t) *start > 0x20) {
+            break;
+        }
+        start++;
     }
 
+    Tokenizer p(Substring(start, end), "\r\n\t");
     p.Record();
     if (!p.CheckChar(isAsciiAlpha)) {
         // First char must be alpha
         return NS_ERROR_MALFORMED_URI;
     }
 
     while (p.CheckChar(net_IsValidSchemeChar) || p.CheckWhite()) {
         // Skip valid scheme characters or \r\n\t
@@ -518,22 +525,30 @@ net_IsValidScheme(const char *scheme, ui
     }
 
     return true;
 }
 
 bool
 net_IsAbsoluteURL(const nsACString& uri)
 {
-    Tokenizer p(uri, "\r\n\t");
+    nsACString::const_iterator start, end;
+    uri.BeginReading(start);
+    uri.EndReading(end);
 
-    while (p.CheckWhite() || p.CheckChar(' ')) {
-        // Skip leading whitespace
+    // Strip C0 and space from begining
+    while (start != end) {
+        if ((uint8_t) *start > 0x20) {
+            break;
+        }
+        start++;
     }
 
+    Tokenizer p(Substring(start, end), "\r\n\t");
+
     // First char must be alpha
     if (!p.CheckChar(isAsciiAlpha)) {
         return false;
     }
 
     while (p.CheckChar(net_IsValidSchemeChar) || p.CheckWhite()) {
         // Skip valid scheme characters or \r\n\t
     }
@@ -549,48 +564,48 @@ net_IsAbsoluteURL(const nsACString& uri)
 
     if (p.CheckChar('/')) {
         // aSpec is really absolute. Ignore aBaseURI in this case
         return true;
     }
     return false;
 }
 
-bool
-net_FilterURIString(const char *str, nsACString& result)
+void
+net_FilterURIString(const nsACString& input, nsACString& result)
 {
-    NS_PRECONDITION(str, "Must have a non-null string!");
     result.Truncate();
-    const char *p = str;
 
-    // Figure out if we need to filter anything.
-    bool writing = false;
-    while (*p) {
-        if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-            writing = true;
+    nsACString::const_iterator start, end;
+    input.BeginReading(start);
+    input.EndReading(end);
+
+    // Strip C0 and space from begining
+    while (start != end) {
+        if ((uint8_t) *start > 0x20) {
             break;
         }
-        p++;
-    }
-
-    if (!writing) {
-        // Nothing to strip or filter
-        return false;
+        start++;
     }
 
-    nsAutoCString temp;
+    MOZ_ASSERT(!*end, "input should null terminated");
+    // Strip C0 and space from end
+    while (end != start) {
+        end--;
+        if ((uint8_t) *end > 0x20) {
+            end++;
+            break;
+        }
+    }
 
-    temp.Assign(str);
-    temp.Trim("\r\n\t ");
+    nsAutoCString temp(Substring(start, end));
     temp.StripChars("\r\n\t");
-
     result.Assign(temp);
+}
 
-    return true;
-}
 
 #if defined(XP_WIN)
 bool
 net_NormalizeFileURL(const nsACString &aURL, nsCString &aResultBuf)
 {
     bool writing = false;
 
     nsACString::const_iterator beginIter, endIter;
--- a/netwerk/base/nsURLHelper.h
+++ b/netwerk/base/nsURLHelper.h
@@ -100,31 +100,25 @@ nsresult net_ExtractURLScheme(const nsAC
 bool net_IsValidScheme(const char *scheme, uint32_t schemeLen);
 
 inline bool net_IsValidScheme(const nsAFlatCString &scheme)
 {
     return net_IsValidScheme(scheme.get(), scheme.Length());
 }
 
 /**
- * Filter out whitespace from a URI string.  The input is the |str|
- * pointer. |result| is written to if and only if there is whitespace that has
- * to be filtered out.  The return value is true if and only if |result| is
- * written to.
+ * This function strips out all C0 controls and space at the beginning and end
+ * of the URL and filters out \r, \n, \t from the middle of the URL.  This makes
+ * it safe to call on things like javascript: urls or data: urls, where we may
+ * in fact run into whitespace that is not properly encoded.
  *
- * This function strips out all whitespace at the beginning and end of the URL
- * and strips out \r, \n, \t from the middle of the URL.  This makes it safe to
- * call on things like javascript: urls or data: urls, where we may in fact run
- * into whitespace that is not properly encoded.
- *
- * @param str the pointer to the string to filter.  Must be non-null.
+ * @param input the URL spec we want to filter
  * @param result the out param to write to if filtering happens
- * @return whether result was written to
  */
-bool net_FilterURIString(const char *str, nsACString& result);
+void net_FilterURIString(const nsACString& input, nsACString& result);
 
 #if defined(XP_WIN)
 /**
  * On Win32 and OS/2 system's a back-slash in a file:// URL is equivalent to a
  * forward-slash.  This function maps any back-slashes to forward-slashes.
  *
  * @param aURL
  *        The URL string to normalize (UTF-8 encoded).  This can be a
--- a/netwerk/cache2/CacheStorageService.cpp
+++ b/netwerk/cache2/CacheStorageService.cpp
@@ -141,37 +141,43 @@ void CacheStorageService::Shutdown()
   LOG(("CacheStorageService::Shutdown - start"));
 
   mShutdown = true;
 
   nsCOMPtr<nsIRunnable> event =
     NewRunnableMethod(this, &CacheStorageService::ShutdownBackground);
   Dispatch(event);
 
-  mozilla::MutexAutoLock lock(mLock);
-  sGlobalEntryTables->Clear();
-  delete sGlobalEntryTables;
-  sGlobalEntryTables = nullptr;
+  {
+    mozilla::MutexAutoLock lock(mLock);
+#ifdef NS_FREE_PERMANENT_DATA
+    sGlobalEntryTables->Clear();
+    delete sGlobalEntryTables;
+#endif
+    sGlobalEntryTables = nullptr;
+  }
 
   LOG(("CacheStorageService::Shutdown - done"));
 }
 
 void CacheStorageService::ShutdownBackground()
 {
   MOZ_ASSERT(IsOnManagementThread());
 
   // Cancel purge timer to avoid leaking.
   if (mPurgeTimer) {
     mPurgeTimer->Cancel();
   }
 
+#ifdef NS_FREE_PERMANENT_DATA
   Pool(false).mFrecencyArray.Clear();
   Pool(false).mExpirationArray.Clear();
   Pool(true).mFrecencyArray.Clear();
   Pool(true).mExpirationArray.Clear();
+#endif
 }
 
 // Internal management methods
 
 namespace {
 
 // WalkCacheRunnable
 // Base class for particular storage entries visiting
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -2021,18 +2021,18 @@ nsCookieService::SetCookieStringInternal
     COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
                       "couldn't get base domain from URI");
     return;
   }
 
   nsCookieKey key(baseDomain, aOriginAttrs);
 
   // check default prefs
-  CookieStatus cookieStatus = CheckPrefs(aHostURI, aIsForeign, requireHostMatch,
-                                         aCookieHeader.get());
+  CookieStatus cookieStatus = CheckSafe(aHostURI, aIsForeign, requireHostMatch,
+                                        aCookieHeader.get(), true);
   // fire a notification if third party or if cookie was rejected
   // (but not if there was an error)
   switch (cookieStatus) {
   case STATUS_REJECTED:
     NotifyRejected(aHostURI);
     if (aIsForeign) {
       NotifyThirdParty(aHostURI, false, aChannel);
     }
@@ -2999,19 +2999,19 @@ nsCookieService::GetCookieStringInternal
     rv = aHostURI->GetAsciiHost(hostFromURI);
   if (NS_SUCCEEDED(rv))
     rv = aHostURI->GetPath(pathFromURI);
   if (NS_FAILED(rv)) {
     COOKIE_LOGFAILURE(GET_COOKIE, aHostURI, nullptr, "invalid host/path from URI");
     return;
   }
 
-  // check default prefs
-  CookieStatus cookieStatus = CheckPrefs(aHostURI, aIsForeign, requireHostMatch,
-                                         nullptr);
+  // make sure we are sending the cookie to the correct place and are allowed to
+  CookieStatus cookieStatus = CheckSafe(aHostURI, aIsForeign, requireHostMatch,
+                                        nullptr, false);
   // for GetCookie(), we don't fire rejection notifications.
   switch (cookieStatus) {
   case STATUS_REJECTED:
   case STATUS_REJECTED_WITH_ERROR:
     return;
   default:
     break;
   }
@@ -3782,33 +3782,35 @@ static inline bool IsSubdomainOf(const n
   if (a == b)
     return true;
   if (a.Length() > b.Length())
     return a[a.Length() - b.Length() - 1] == '.' && StringEndsWith(a, b);
   return false;
 }
 
 CookieStatus
-nsCookieService::CheckPrefs(nsIURI          *aHostURI,
-                            bool             aIsForeign,
-                            bool             aRequireHostMatch,
-                            const char      *aCookieHeader)
+nsCookieService::CheckSafe(nsIURI          *aHostURI,
+                           bool             aIsForeign,
+                           bool             aRequireHostMatch,
+                           const char      *aCookieHeader,
+                           bool             aCheckPrefs)
 {
   nsresult rv;
 
   // don't let ftp sites get/set cookies (could be a security issue)
   bool ftp;
   if (NS_SUCCEEDED(aHostURI->SchemeIs("ftp", &ftp)) && ftp) {
     COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "ftp sites cannot read cookies");
     return STATUS_REJECTED_WITH_ERROR;
   }
 
   // check the permission list first; if we find an entry, it overrides
   // default prefs. see bug 184059.
-  if (mPermissionService) {
+  // aCheckPrefs allows us to ignore user preferences
+  if (mPermissionService && aCheckPrefs) {
     nsCookieAccess access;
     // Not passing an nsIChannel here is probably OK; our implementation
     // doesn't do anything with it anyway.
     rv = mPermissionService->CanAccess(aHostURI, nullptr, &access);
 
     // if we found an entry, use it
     if (NS_SUCCEEDED(rv)) {
       switch (access) {
--- a/netwerk/cookie/nsCookieService.h
+++ b/netwerk/cookie/nsCookieService.h
@@ -299,17 +299,17 @@ class nsCookieService final : public nsI
     bool                          SetCookieInternal(nsIURI *aHostURI, const nsCookieKey& aKey, bool aRequireHostMatch, CookieStatus aStatus, nsDependentCString &aCookieHeader, int64_t aServerTime, bool aFromHttp, nsIChannel* aChannel);
     void                          AddInternal(const nsCookieKey& aKey, nsCookie *aCookie, int64_t aCurrentTimeInUsec, nsIURI *aHostURI, const char *aCookieHeader, bool aFromHttp);
     void                          RemoveCookieFromList(const nsListIter &aIter, mozIStorageBindingParamsArray *aParamsArray = nullptr);
     void                          AddCookieToList(const nsCookieKey& aKey, nsCookie *aCookie, DBState *aDBState, mozIStorageBindingParamsArray *aParamsArray, bool aWriteToDB = true);
     void                          UpdateCookieInList(nsCookie *aCookie, int64_t aLastAccessed, mozIStorageBindingParamsArray *aParamsArray);
     static bool                   GetTokenValue(nsASingleFragmentCString::const_char_iterator &aIter, nsASingleFragmentCString::const_char_iterator &aEndIter, nsDependentCSubstring &aTokenString, nsDependentCSubstring &aTokenValue, bool &aEqualsFound);
     static bool                   ParseAttributes(nsDependentCString &aCookieHeader, nsCookieAttributes &aCookie);
     bool                          RequireThirdPartyCheck();
-    CookieStatus                  CheckPrefs(nsIURI *aHostURI, bool aIsForeign, bool aRequireHostMatch, const char *aCookieHeader);
+    CookieStatus                  CheckSafe(nsIURI *aHostURI, bool aIsForeign, bool aRequireHostMatch, const char *aCookieHeader, bool aCheckPrefs);
     bool                          CheckDomain(nsCookieAttributes &aCookie, nsIURI *aHostURI, const nsCString &aBaseDomain, bool aRequireHostMatch);
     static bool                   CheckPath(nsCookieAttributes &aCookie, nsIURI *aHostURI);
     static bool                   GetExpiry(nsCookieAttributes &aCookie, int64_t aServerTime, int64_t aCurrentTime);
     void                          RemoveAllFromMemory();
     already_AddRefed<nsIArray>    PurgeCookies(int64_t aCurrentTimeInUsec);
     bool                          FindCookie(const nsCookieKey& aKey, const nsAFlatCString &aHost, const nsAFlatCString &aName, const nsAFlatCString &aPath, nsListIter &aIter);
     static void                   FindStaleCookie(nsCookieEntry *aEntry, int64_t aCurrentTime, nsListIter &aIter);
     void                          NotifyRejected(nsIURI *aHostURI);
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -433,18 +433,18 @@ HttpBaseChannel::SetNotificationCallback
 NS_IMETHODIMP
 HttpBaseChannel::GetContentType(nsACString& aContentType)
 {
   if (!mResponseHead) {
     aContentType.Truncate();
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  if (!mResponseHead->ContentType().IsEmpty()) {
-    aContentType = mResponseHead->ContentType();
+  mResponseHead->ContentType(aContentType);
+  if (!aContentType.IsEmpty()) {
     return NS_OK;
   }
 
   aContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -475,17 +475,17 @@ HttpBaseChannel::SetContentType(const ns
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetContentCharset(nsACString& aContentCharset)
 {
   if (!mResponseHead)
     return NS_ERROR_NOT_AVAILABLE;
 
-  aContentCharset = mResponseHead->ContentCharset();
+  mResponseHead->ContentCharset(aContentCharset);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::SetContentCharset(const nsACString& aContentCharset)
 {
   if (mListener) {
     if (!mResponseHead)
@@ -992,22 +992,24 @@ HttpBaseChannel::DoApplyContentConversio
 NS_IMETHODIMP
 HttpBaseChannel::GetContentEncodings(nsIUTF8StringEnumerator** aEncodings)
 {
   if (!mResponseHead) {
     *aEncodings = nullptr;
     return NS_OK;
   }
 
-  const char *encoding = mResponseHead->PeekHeader(nsHttp::Content_Encoding);
-  if (!encoding) {
+  nsAutoCString encoding;
+  mResponseHead->GetHeader(nsHttp::Content_Encoding, encoding);
+  if (encoding.IsEmpty()) {
     *aEncodings = nullptr;
     return NS_OK;
   }
-  nsContentEncodings* enumerator = new nsContentEncodings(this, encoding);
+  nsContentEncodings* enumerator = new nsContentEncodings(this,
+                                                          encoding.get());
   NS_ADDREF(*aEncodings = enumerator);
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // HttpBaseChannel::nsContentEncodings <public>
 //-----------------------------------------------------------------------------
 
@@ -1660,44 +1662,44 @@ HttpBaseChannel::SetResponseHeader(const
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::VisitResponseHeaders(nsIHttpHeaderVisitor *visitor)
 {
   if (!mResponseHead) {
     return NS_ERROR_NOT_AVAILABLE;
   }
-  return mResponseHead->Headers().VisitHeaders(visitor,
+  return mResponseHead->VisitHeaders(visitor,
     nsHttpHeaderArray::eFilterResponse);
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetOriginalResponseHeader(const nsACString& aHeader,
                                            nsIHttpHeaderVisitor *aVisitor)
 {
   if (!mResponseHead) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   nsHttpAtom atom = nsHttp::ResolveAtom(aHeader);
   if (!atom) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  return mResponseHead->Headers().GetOriginalHeader(atom, aVisitor);
+  return mResponseHead->GetOriginalHeader(atom, aVisitor);
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::VisitOriginalResponseHeaders(nsIHttpHeaderVisitor *aVisitor)
 {
   if (!mResponseHead) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  return mResponseHead->Headers().VisitHeaders(aVisitor,
+  return mResponseHead->VisitHeaders(aVisitor,
       nsHttpHeaderArray::eFilterResponseOriginal);
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetAllowPipelining(bool *value)
 {
   NS_ENSURE_ARG_POINTER(value);
   *value = mAllowPipelining;
@@ -1811,17 +1813,17 @@ HttpBaseChannel::GetResponseStatus(uint3
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetResponseStatusText(nsACString& aValue)
 {
   if (!mResponseHead)
     return NS_ERROR_NOT_AVAILABLE;
-  aValue = mResponseHead->StatusText();
+  mResponseHead->StatusText(aValue);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetRequestSucceeded(bool *aValue)
 {
   if (!mResponseHead)
     return NS_ERROR_NOT_AVAILABLE;
@@ -2015,19 +2017,21 @@ HttpBaseChannel::SetCookie(const char *a
 
   // empty header isn't an error
   if (!(aCookieHeader && *aCookieHeader))
     return NS_OK;
 
   nsICookieService *cs = gHttpHandler->GetCookieService();
   NS_ENSURE_TRUE(cs, NS_ERROR_FAILURE);
 
+  nsAutoCString date;
+  mResponseHead->GetHeader(nsHttp::Date, date);
   nsresult rv =
     cs->SetCookieStringFromHttp(mURI, nullptr, nullptr, aCookieHeader,
-                                mResponseHead->PeekHeader(nsHttp::Date), this);
+                                date.get(), this);
   if (NS_SUCCEEDED(rv)) {
     RefPtr<CookieNotifierRunnable> r =
       new CookieNotifierRunnable(this, aCookieHeader);
     NS_DispatchToMainThread(r);
   }
   return rv;
 }
 
@@ -2460,30 +2464,26 @@ HttpBaseChannel::GetEntityID(nsACString&
 
   uint64_t size = UINT64_MAX;
   nsAutoCString etag, lastmod;
   if (mResponseHead) {
     // Don't return an entity if the server sent the following header:
     // Accept-Ranges: none
     // Not sending the Accept-Ranges header means we can still try
     // sending range requests.
-    const char* acceptRanges =
-        mResponseHead->PeekHeader(nsHttp::Accept_Ranges);
-    if (acceptRanges &&
-        !nsHttp::FindToken(acceptRanges, "bytes", HTTP_HEADER_VALUE_SEPS)) {
+    nsAutoCString acceptRanges;
+    mResponseHead->GetHeader(nsHttp::Accept_Ranges, acceptRanges);
+    if (!acceptRanges.IsEmpty() &&
+        !nsHttp::FindToken(acceptRanges.get(), "bytes", HTTP_HEADER_VALUE_SEPS)) {
       return NS_ERROR_NOT_RESUMABLE;
     }
 
     size = mResponseHead->TotalEntitySize();
-    const char* cLastMod = mResponseHead->PeekHeader(nsHttp::Last_Modified);
-    if (cLastMod)
-      lastmod = cLastMod;
-    const char* cEtag = mResponseHead->PeekHeader(nsHttp::ETag);
-    if (cEtag)
-      etag = cEtag;
+    mResponseHead->GetHeader(nsHttp::Last_Modified, lastmod);
+    mResponseHead->GetHeader(nsHttp::ETag, etag);
   }
   nsCString entityID;
   NS_EscapeURL(etag.BeginReading(), etag.Length(), esc_AlwaysCopy |
                esc_FileBaseName | esc_Forced, entityID);
   entityID.Append('/');
   entityID.AppendInt(int64_t(size));
   entityID.Append('/');
   entityID.Append(lastmod);
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -45,17 +45,17 @@
 
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace net {
 
 extern bool
-WillRedirect(const nsHttpResponseHead * response);
+WillRedirect(nsHttpResponseHead * response);
 
 namespace {
 
 const uint32_t kMaxFileDescriptorsPerMessage = 250;
 
 #ifdef OS_POSIX
 // Keep this in sync with other platforms.
 static_assert(FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE == 250,
--- a/netwerk/protocol/http/HttpChannelParentListener.cpp
+++ b/netwerk/protocol/http/HttpChannelParentListener.cpp
@@ -298,20 +298,22 @@ public:
 NS_IMETHODIMP
 HttpChannelParentListener::ChannelIntercepted(nsIInterceptedChannel* aChannel)
 {
   if (mShouldSuspendIntercept) {
     mInterceptedChannel = aChannel;
     return NS_OK;
   }
 
-  aChannel->SynthesizeStatus(mSynthesizedResponseHead->Status(),
-                             mSynthesizedResponseHead->StatusText());
+  nsAutoCString statusText;
+  mSynthesizedResponseHead->StatusText(statusText);
+  aChannel->SynthesizeStatus(mSynthesizedResponseHead->Status(), statusText);
   nsCOMPtr<nsIHttpHeaderVisitor> visitor = new HeaderVisitor(aChannel);
-  mSynthesizedResponseHead->Headers().VisitHeaders(visitor);
+  mSynthesizedResponseHead->VisitHeaders(visitor,
+                                         nsHttpHeaderArray::eFilterResponse);
 
   nsCOMPtr<nsIRunnable> event = new FinishSynthesizedResponse(aChannel);
   NS_DispatchToCurrentThread(event);
 
   mSynthesizedResponseHead = nullptr;
 
   MOZ_ASSERT(mNextListener);
   RefPtr<HttpChannelParent> channel = do_QueryObject(mNextListener);
--- a/netwerk/protocol/http/PackagedAppService.cpp
+++ b/netwerk/protocol/http/PackagedAppService.cpp
@@ -134,17 +134,17 @@ HeaderCopier::VisitHeader(const nsACStri
 }
 
 bool
 HeaderCopier::ShouldCopy(const nsACString &aHeader) const
 {
   nsHttpAtom header = nsHttp::ResolveAtom(aHeader);
 
   // Don't overwrite the existing headers.
-  if (mHead->PeekHeader(header)) {
+  if (mHead->HasHeader(header)) {
     return false;
   }
 
   // A black list of headers we shouldn't copy.
   static const nsHttpAtom kHeadersCopyBlacklist[] = {
     nsHttp::Authentication,
     nsHttp::Cache_Control,
     nsHttp::Connection,
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -166,20 +166,20 @@ Hash(const char *buf, nsACString &hash)
     return NS_OK;
 }
 
 } // unnamed namespace
 
 // We only treat 3xx responses as redirects if they have a Location header and
 // the status code is in a whitelist.
 bool
-WillRedirect(const nsHttpResponseHead * response)
+WillRedirect(nsHttpResponseHead * response)
 {
     return nsHttpChannel::IsRedirectStatus(response->Status()) &&
-           response->PeekHeader(nsHttp::Location);
+           response->HasHeader(nsHttp::Location);
 }
 
 nsresult
 StoreAuthorizationMetaData(nsICacheEntry *entry, nsHttpRequestHead *requestHead);
 
 class AutoRedirectVetoNotifier
 {
 public:
@@ -961,17 +961,17 @@ nsHttpChannel::CallOnStartRequest()
         }
 
         if (!typeSniffersCalled && mTransactionPump) {
           mTransactionPump->PeekStream(CallTypeSniffers, thisChannel);
         }
     }
 
     bool unknownDecoderStarted = false;
-    if (mResponseHead && mResponseHead->ContentType().IsEmpty()) {
+    if (mResponseHead && !mResponseHead->HasContentType()) {
         MOZ_ASSERT(mConnectionInfo, "Should have connection info here");
         if (!mContentTypeHint.IsEmpty())
             mResponseHead->SetContentType(mContentTypeHint);
         else if (mResponseHead->Version() == NS_HTTP_VERSION_0_9 &&
                  mConnectionInfo->OriginPort() != mConnectionInfo->DefaultPort())
             mResponseHead->SetContentType(NS_LITERAL_CSTRING(TEXT_PLAIN));
         else {
             // Uh-oh.  We had better find out what type we are!
@@ -989,17 +989,17 @@ nsHttpChannel::CallOnStartRequest()
                 if (NS_SUCCEEDED(rv)) {
                     mListener = converter;
                     unknownDecoderStarted = true;
                 }
             }
         }
     }
 
-    if (mResponseHead && mResponseHead->ContentCharset().IsEmpty())
+    if (mResponseHead && !mResponseHead->HasContentCharset())
         mResponseHead->SetContentCharset(mContentCharsetHint);
 
     if (mResponseHead && mCacheEntry) {
         // If we have a cache entry, set its predicted size to TotalEntitySize to
         // avoid caching an entry that will exceed the max size limit.
         rv = mCacheEntry->SetPredictedDataSize(
             mResponseHead->TotalEntitySize());
         if (NS_ERROR_FILE_TOO_BIG == rv) {
@@ -1393,17 +1393,17 @@ nsHttpChannel::ProcessContentSignatureHe
       DoInvalidateCacheEntry(mURI);
       LOG(("An expected content-signature header is missing.\n"));
       return NS_ERROR_INVALID_SIGNATURE;
     }
 
     // we ensure a content type here to avoid running into problems with
     // content sniffing, which might sniff parts of the content before we can
     // verify the signature
-    if (aResponseHead->ContentType().IsEmpty()) {
+    if (!aResponseHead->HasContentType()) {
         NS_WARNING("Empty content type can get us in trouble when verifying "
                    "content signatures");
         return NS_ERROR_INVALID_SIGNATURE;
     }
     // create a new listener that meadiates the content
     RefPtr<ContentVerifier> contentVerifyingMediator =
       new ContentVerifier(mListener, mListenerContext);
     rv = contentVerifyingMediator->Init(
@@ -1551,23 +1551,23 @@ nsHttpChannel::ProcessAltService()
 
     nsAutoCString scheme;
     mURI->GetScheme(scheme);
     bool isHttp = scheme.Equals(NS_LITERAL_CSTRING("http"));
     if (!isHttp && !scheme.Equals(NS_LITERAL_CSTRING("https"))) {
         return;
     }
 
-    const char *altSvc;
-    if (!(altSvc = mResponseHead->PeekHeader(nsHttp::Alternate_Service))) {
+    nsAutoCString altSvc;
+    mResponseHead->GetHeader(nsHttp::Alternate_Service, altSvc);
+    if (altSvc.IsEmpty()) {
         return;
     }
 
-    nsCString buf(altSvc);
-    if (!nsHttp::IsReasonableHeaderValue(buf)) {
+    if (!nsHttp::IsReasonableHeaderValue(altSvc)) {
         LOG(("Alt-Svc Response Header seems unreasonable - skipping\n"));
         return;
     }
 
     nsAutoCString originHost;
     int32_t originPort = 80;
     mURI->GetPort(&originPort);
     if (NS_FAILED(mURI->GetHost(originHost))) {
@@ -1577,17 +1577,17 @@ nsHttpChannel::ProcessAltService()
     nsCOMPtr<nsIInterfaceRequestor> callbacks;
     nsCOMPtr<nsProxyInfo> proxyInfo;
     NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
                                            getter_AddRefs(callbacks));
     if (mProxyInfo) {
         proxyInfo = do_QueryInterface(mProxyInfo);
     }
 
-    AltSvcMapping::ProcessHeader(buf, scheme, originHost, originPort,
+    AltSvcMapping::ProcessHeader(altSvc, scheme, originHost, originPort,
                                  mUsername, mPrivateBrowsing, callbacks, proxyInfo,
                                  mCaps & NS_HTTP_DISALLOW_SPDY);
 }
 
 nsresult
 nsHttpChannel::ProcessResponse()
 {
     nsresult rv;
@@ -1603,18 +1603,20 @@ nsHttpChannel::ProcessResponse()
         Telemetry::Accumulate(Telemetry::HTTP_TRANSACTION_IS_SSL,
                               mConnectionInfo->EndToEndSSL());
         if (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI) {
             Telemetry::Accumulate(Telemetry::HTTP_PAGELOAD_IS_SSL,
                                   mConnectionInfo->EndToEndSSL());
         }
 
         // how often do we see something like Alternate-Protocol: "443:quic,p=1"
-        const char *alt_protocol = mResponseHead->PeekHeader(nsHttp::Alternate_Protocol);
-        bool saw_quic = (alt_protocol && PL_strstr(alt_protocol, "quic")) ? 1 : 0;
+        nsAutoCString alt_protocol;
+        mResponseHead->GetHeader(nsHttp::Alternate_Protocol, alt_protocol);
+        bool saw_quic = (!alt_protocol.IsEmpty() &&
+                         PL_strstr(alt_protocol.get(), "quic")) ? 1 : 0;
         Telemetry::Accumulate(Telemetry::HTTP_SAW_QUIC_ALT_PROTOCOL, saw_quic);
 
         // Gather data on how many URLS get redirected
         switch (httpStatus) {
             case 200:
                 Telemetry::Accumulate(Telemetry::HTTP_RESPONSE_STATUS_CODE, 0);
                 break;
             case 301:
@@ -1691,17 +1693,20 @@ nsHttpChannel::ProcessResponse()
 
     // notify "http-on-examine-response" observers
     gHttpHandler->OnExamineResponse(this);
 
     // Cookies and Alt-Service should not be handled on proxy failure either.
     // This would be consolidated with ProcessSecurityHeaders but it should
     // happen after OnExamineResponse.
     if (!mTransaction->ProxyConnectFailed() && (httpStatus != 407)) {
-        SetCookie(mResponseHead->PeekHeader(nsHttp::Set_Cookie));
+        nsAutoCString cookie;
+        if (NS_SUCCEEDED(mResponseHead->GetHeader(nsHttp::Set_Cookie, cookie))) {
+            SetCookie(cookie.get());
+        }
         if ((httpStatus < 500) && (httpStatus != 421)) {
             ProcessAltService();
         }
     }
 
     // handle unused username and password in url (see bug 232567)
     if (httpStatus != 401 && httpStatus != 407) {
         if (!mAuthRetryPending)
@@ -2475,46 +2480,48 @@ nsHttpChannel::EnsureAssocReq()
     // return NS_OK as long as we don't find a violation
     // (i.e. no header is ok, as are malformed headers, as are
     // transactions that have not been pipelined (unless those have been
     // opted in via pragma))
 
     if (!mResponseHead)
         return NS_OK;
 
-    const char *assoc_val = mResponseHead->PeekHeader(nsHttp::Assoc_Req);
-    if (!assoc_val)
+    nsAutoCString assoc_val;
+    if (NS_FAILED(mResponseHead->GetHeader(nsHttp::Assoc_Req, assoc_val))) {
         return NS_OK;
+    }
 
     if (!mTransaction || !mURI)
         return NS_OK;
 
     if (!mTransaction->PipelinePosition()) {
         // "Pragma: X-Verify-Assoc-Req" can be used to verify even non pipelined
         // transactions. It is used by test harness.
 
-        const char *pragma_val = mResponseHead->PeekHeader(nsHttp::Pragma);
-        if (!pragma_val ||
-            !nsHttp::FindToken(pragma_val, "X-Verify-Assoc-Req",
+        nsAutoCString pragma_val;
+        mResponseHead->GetHeader(nsHttp::Pragma, pragma_val);
+        if (pragma_val.IsEmpty() ||
+            !nsHttp::FindToken(pragma_val.get(), "X-Verify-Assoc-Req",
                                HTTP_HEADER_VALUE_SEPS))
             return NS_OK;
     }
 
-    char *method = net_FindCharNotInSet(assoc_val, HTTP_LWS);
+    char *method = net_FindCharNotInSet(assoc_val.get(), HTTP_LWS);
     if (!method)
         return NS_OK;
 
     bool equals;
     char *endofmethod;
 
-    assoc_val = nullptr;
+    char * assoc_valChar = nullptr;
     endofmethod = net_FindCharInSet(method, HTTP_LWS);
     if (endofmethod)
-        assoc_val = net_FindCharNotInSet(endofmethod, HTTP_LWS);
-    if (!assoc_val)
+        assoc_valChar = net_FindCharNotInSet(endofmethod, HTTP_LWS);
+    if (!assoc_valChar)
         return NS_OK;
 
     // check the method
     nsAutoCString methodHead;
     mRequestHead.Method(methodHead);
     if ((((int32_t)methodHead.Length()) != (endofmethod - method)) ||
         PL_strncmp(method,
                    methodHead.get(),
@@ -2526,52 +2533,52 @@ nsHttpChannel::EnsureAssocReq()
                                      nsHttpConnectionMgr::RedCorruptedContent,
                                      nullptr, 0);
 
         nsCOMPtr<nsIConsoleService> consoleService =
             do_GetService(NS_CONSOLESERVICE_CONTRACTID);
         if (consoleService) {
             nsAutoString message
                 (NS_LITERAL_STRING("Failed Assoc-Req. Received "));
-            AppendASCIItoUTF16(
-                mResponseHead->PeekHeader(nsHttp::Assoc_Req),
-                message);
+            nsAutoCString assoc_req;
+            mResponseHead->GetHeader(nsHttp::Assoc_Req, assoc_req);
+            AppendASCIItoUTF16(assoc_req, message);
             message += NS_LITERAL_STRING(" expected method ");
             AppendASCIItoUTF16(methodHead, message);
             consoleService->LogStringMessage(message.get());
         }
 
         if (gHttpHandler->EnforceAssocReq())
             return NS_ERROR_CORRUPTED_CONTENT;
         return NS_OK;
     }
 
     // check the URL
     nsCOMPtr<nsIURI> assoc_url;
-    if (NS_FAILED(NS_NewURI(getter_AddRefs(assoc_url), assoc_val)) ||
+    if (NS_FAILED(NS_NewURI(getter_AddRefs(assoc_url), assoc_valChar)) ||
         !assoc_url)
         return NS_OK;
 
     mURI->Equals(assoc_url, &equals);
     if (!equals) {
-        LOG(("  Assoc-Req failure URL %s", assoc_val));
+        LOG(("  Assoc-Req failure URL %s", assoc_valChar));
         if (mConnectionInfo)
             gHttpHandler->ConnMgr()->
                 PipelineFeedbackInfo(mConnectionInfo,
                                      nsHttpConnectionMgr::RedCorruptedContent,
                                      nullptr, 0);
 
         nsCOMPtr<nsIConsoleService> consoleService =
             do_GetService(NS_CONSOLESERVICE_CONTRACTID);
         if (consoleService) {
             nsAutoString message
                 (NS_LITERAL_STRING("Failed Assoc-Req. Received "));
-            AppendASCIItoUTF16(
-                mResponseHead->PeekHeader(nsHttp::Assoc_Req),
-                message);
+            nsAutoCString assoc_req;
+            mResponseHead->GetHeader(nsHttp::Assoc_Req, assoc_req);
+            AppendASCIItoUTF16(assoc_req, message);
             message += NS_LITERAL_STRING(" expected URL ");
             AppendASCIItoUTF16(mSpec.get(), message);
             consoleService->LogStringMessage(message.get());
         }
 
         if (gHttpHandler->EnforceAssocReq())
             return NS_ERROR_CORRUPTED_CONTENT;
     }
@@ -2582,19 +2589,22 @@ nsHttpChannel::EnsureAssocReq()
 // nsHttpChannel <byte-range>
 //-----------------------------------------------------------------------------
 
 bool
 nsHttpChannel::IsResumable(int64_t partialLen, int64_t contentLength,
                            bool ignoreMissingPartialLen) const
 {
     bool hasContentEncoding =
-        (mCachedResponseHead->PeekHeader(nsHttp::Content_Encoding) != nullptr);
-    const char *etag = mCachedResponseHead->PeekHeader(nsHttp::ETag);
-    bool hasWeakEtag = etag && !strncmp(etag, "W/", 2);
+        mCachedResponseHead->HasHeader(nsHttp::Content_Encoding);
+
+    nsAutoCString etag; 
+    mCachedResponseHead->GetHeader(nsHttp::ETag, etag);
+    bool hasWeakEtag = !etag.IsEmpty() &&
+                       StringBeginsWith(etag, NS_LITERAL_CSTRING("W/"));
 
     return (partialLen < contentLength) &&
            (partialLen > 0 || ignoreMissingPartialLen) &&
            !hasContentEncoding && !hasWeakEtag &&
            mCachedResponseHead->IsResumable() &&
            !mCustomConditionalRequest &&
            !mCachedResponseHead->NoStore();
 }
@@ -2622,32 +2632,33 @@ nsHttpChannel::MaybeSetupByteRangeReques
 
 nsresult
 nsHttpChannel::SetupByteRangeRequest(int64_t partialLen)
 {
     // cached content has been found to be partial, add necessary request
     // headers to complete cache entry.
 
     // use strongest validator available...
-    const char *val = mCachedResponseHead->PeekHeader(nsHttp::ETag);
-    if (!val)
-        val = mCachedResponseHead->PeekHeader(nsHttp::Last_Modified);
-    if (!val) {
+    nsAutoCString val;
+    mCachedResponseHead->GetHeader(nsHttp::ETag, val);
+    if (val.IsEmpty())
+        mCachedResponseHead->GetHeader(nsHttp::Last_Modified, val);
+    if (val.IsEmpty()) {
         // if we hit this code it means mCachedResponseHead->IsResumable() is
         // either broken or not being called.
         NS_NOTREACHED("no cache validator");
         mIsPartialRequest = false;
         return NS_ERROR_FAILURE;
     }
 
     char buf[64];
     PR_snprintf(buf, sizeof(buf), "bytes=%lld-", partialLen);
 
     mRequestHead.SetHeader(nsHttp::Range, nsDependentCString(buf));
-    mRequestHead.SetHeader(nsHttp::If_Range, nsDependentCString(val));
+    mRequestHead.SetHeader(nsHttp::If_Range, val);
     mIsPartialRequest = true;
 
     return NS_OK;
 }
 
 void
 nsHttpChannel::UntieByteRangeRequest()
 {
@@ -2668,32 +2679,37 @@ nsHttpChannel::ProcessPartialContent()
     NS_ENSURE_TRUE(mCachedResponseHead, NS_ERROR_NOT_INITIALIZED);
     NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_INITIALIZED);
 
     // Make sure to clear bogus content-encodings before looking at the header
     ClearBogusContentEncodingIfNeeded();
 
     // Check if the content-encoding we now got is different from the one we
     // got before
-    if (PL_strcasecmp(mResponseHead->PeekHeader(nsHttp::Content_Encoding),
-                      mCachedResponseHead->PeekHeader(nsHttp::Content_Encoding))
-                      != 0) {
+    nsAutoCString contentEncoding, cachedContentEncoding;
+    mResponseHead->GetHeader(nsHttp::Content_Encoding, contentEncoding);
+    mCachedResponseHead->GetHeader(nsHttp::Content_Encoding,
+                                   cachedContentEncoding);
+    if (PL_strcasecmp(contentEncoding.get(), cachedContentEncoding.get())
+        != 0) {
         Cancel(NS_ERROR_INVALID_CONTENT_ENCODING);
         return CallOnStartRequest();
     }
 
     nsresult rv;
 
     int64_t cachedContentLength = mCachedResponseHead->ContentLength();
     int64_t entitySize = mResponseHead->TotalEntitySize();
 
+    nsAutoCString contentRange;
+    mResponseHead->GetHeader(nsHttp::Content_Range, contentRange);
     LOG(("nsHttpChannel::ProcessPartialContent [this=%p trans=%p] "
          "original content-length %lld, entity-size %lld, content-range %s\n",
          this, mTransaction.get(), cachedContentLength, entitySize,
-         mResponseHead->PeekHeader(nsHttp::Content_Range)));
+         contentRange.get()));
 
     if ((entitySize >= 0) && (cachedContentLength >= 0) &&
         (entitySize != cachedContentLength)) {
         LOG(("nsHttpChannel::ProcessPartialContent [this=%p] "
              "206 has different total entity size than the content length "
              "of the original partially cached entity.\n", this));
 
         mCacheEntry->AsyncDoom(nullptr);
@@ -2716,17 +2732,17 @@ nsHttpChannel::ProcessPartialContent()
         }
     } else {
         // suspend the current transaction
         rv = mTransactionPump->Suspend();
         if (NS_FAILED(rv)) return rv;
     }
 
     // merge any new headers with the cached response headers
-    rv = mCachedResponseHead->UpdateHeaders(mResponseHead->Headers());
+    rv = mCachedResponseHead->UpdateHeaders(mResponseHead);
     if (NS_FAILED(rv)) return rv;
 
     // update the cached response head
     nsAutoCString head;
     mCachedResponseHead->Flatten(head, true);
     rv = mCacheEntry->SetMetaDataElement("response-head", head.get());
     if (NS_FAILED(rv)) return rv;
 
@@ -2852,17 +2868,17 @@ nsHttpChannel::ProcessNotModified()
             gHttpHandler->ConnMgr()->
                 PipelineFeedbackInfo(mConnectionInfo,
                                      nsHttpConnectionMgr::RedCorruptedContent,
                                      nullptr, 0);
         Telemetry::Accumulate(Telemetry::CACHE_LM_INCONSISTENT, true);
     }
 
     // merge any new headers with the cached response headers
-    rv = mCachedResponseHead->UpdateHeaders(mResponseHead->Headers());
+    rv = mCachedResponseHead->UpdateHeaders(mResponseHead);
     if (NS_FAILED(rv)) return rv;
 
     // update the cached response head
     nsAutoCString head;
     mCachedResponseHead->Flatten(head, true);
     rv = mCacheEntry->SetMetaDataElement("response-head", head.get());
     if (NS_FAILED(rv)) return rv;
 
@@ -3543,19 +3559,21 @@ nsHttpChannel::OnCacheEntryCheck(nsICach
         mLoadInfo && mLoadInfo->GetVerifySignedContent()) {
         doValidation = true;
     }
 
     nsAutoCString requestedETag;
     if (!doValidation &&
         NS_SUCCEEDED(mRequestHead.GetHeader(nsHttp::If_Match, requestedETag)) &&
         (methodWasGet || methodWasHead)) {
-        const char *cachedETag = mCachedResponseHead->PeekHeader(nsHttp::ETag);
-        if (cachedETag && (!strncmp(cachedETag, "W/", 2) ||
-            !requestedETag.Equals(cachedETag))) {
+        nsAutoCString cachedETag;
+        mCachedResponseHead->GetHeader(nsHttp::ETag, cachedETag);
+        if (!cachedETag.IsEmpty() &&
+            (StringBeginsWith(cachedETag, NS_LITERAL_CSTRING("W/")) ||
+             !requestedETag.Equals(cachedETag))) {
             // User has defined If-Match header, if the cached entry is not
             // matching the provided header value or the cached ETag is weak,
             // force validation.
             doValidation = true;
         }
     }
 
     if (!doValidation) {
@@ -3634,30 +3652,28 @@ nsHttpChannel::OnCacheEntryCheck(nsICach
                 // life-time.  nsHttpChannel is not designed to do that, so rather
                 // turn off concurrent read and wait for entry's completion.
                 // Then only re-validation or range-re-validation request will go out.
                 mConcurentCacheAccess = 0;
                 // This will cause that OnCacheEntryCheck is called again with the same
                 // entry after the writer is done.
                 wantCompleteEntry = true;
             } else {
-                const char *val;
+                nsAutoCString val;
                 // Add If-Modified-Since header if a Last-Modified was given
                 // and we are allowed to do this (see bugs 510359 and 269303)
                 if (canAddImsHeader) {
-                    val = mCachedResponseHead->PeekHeader(nsHttp::Last_Modified);
-                    if (val)
-                        mRequestHead.SetHeader(nsHttp::If_Modified_Since,
-                                               nsDependentCString(val));
+                    mCachedResponseHead->GetHeader(nsHttp::Last_Modified, val);
+                    if (!val.IsEmpty())
+                        mRequestHead.SetHeader(nsHttp::If_Modified_Since, val);
                 }
                 // Add If-None-Match header if an ETag was given in the response
-                val = mCachedResponseHead->PeekHeader(nsHttp::ETag);
-                if (val)
-                    mRequestHead.SetHeader(nsHttp::If_None_Match,
-                                           nsDependentCString(val));
+                mCachedResponseHead->GetHeader(nsHttp::ETag, val);
+                if (!val.IsEmpty())
+                    mRequestHead.SetHeader(nsHttp::If_None_Match, val);
                 mDidReval = true;
             }
         }
     }
 
     if (mCachedContentIsValid || mDidReval) {
         rv = OpenCacheInputStream(entry, mCachedContentIsValid, !!appCache);
         if (NS_FAILED(rv)) {
@@ -4635,29 +4651,32 @@ nsHttpChannel::InstallCacheListener(int6
     nsresult rv;
 
     LOG(("Preparing to write data into the cache [uri=%s]\n", mSpec.get()));
 
     MOZ_ASSERT(mCacheEntry);
     MOZ_ASSERT(mCacheEntryIsWriteOnly || mCachedContentIsPartial);
     MOZ_ASSERT(mListener);
 
+    nsAutoCString contentEncoding, contentType;
+    mResponseHead->GetHeader(nsHttp::Content_Encoding, contentEncoding);
+    mResponseHead->ContentType(contentType);
     // If the content is compressible and the server has not compressed it,
     // mark the cache entry for compression.
-    if ((mResponseHead->PeekHeader(nsHttp::Content_Encoding) == nullptr) && (
-         mResponseHead->ContentType().EqualsLiteral(TEXT_HTML) ||
-         mResponseHead->ContentType().EqualsLiteral(TEXT_PLAIN) ||
-         mResponseHead->ContentType().EqualsLiteral(TEXT_CSS) ||
-         mResponseHead->ContentType().EqualsLiteral(TEXT_JAVASCRIPT) ||
-         mResponseHead->ContentType().EqualsLiteral(TEXT_ECMASCRIPT) ||
-         mResponseHead->ContentType().EqualsLiteral(TEXT_XML) ||
-         mResponseHead->ContentType().EqualsLiteral(APPLICATION_JAVASCRIPT) ||
-         mResponseHead->ContentType().EqualsLiteral(APPLICATION_ECMASCRIPT) ||
-         mResponseHead->ContentType().EqualsLiteral(APPLICATION_XJAVASCRIPT) ||
-         mResponseHead->ContentType().EqualsLiteral(APPLICATION_XHTML_XML))) {
+    if (contentEncoding.IsEmpty() &&
+        (contentType.EqualsLiteral(TEXT_HTML) ||
+         contentType.EqualsLiteral(TEXT_PLAIN) ||
+         contentType.EqualsLiteral(TEXT_CSS) ||
+         contentType.EqualsLiteral(TEXT_JAVASCRIPT) ||
+         contentType.EqualsLiteral(TEXT_ECMASCRIPT) ||
+         contentType.EqualsLiteral(TEXT_XML) ||
+         contentType.EqualsLiteral(APPLICATION_JAVASCRIPT) ||
+         contentType.EqualsLiteral(APPLICATION_ECMASCRIPT) ||
+         contentType.EqualsLiteral(APPLICATION_XJAVASCRIPT) ||
+         contentType.EqualsLiteral(APPLICATION_XHTML_XML))) {
         rv = mCacheEntry->SetMetaDataElement("uncompressed-len", "0");
         if (NS_FAILED(rv)) {
             LOG(("unable to mark cache entry for compression"));
         }
     }
 
     LOG(("Trading cache input stream for output stream [channel=%p]", this));
 
@@ -4752,26 +4771,28 @@ void
 nsHttpChannel::ClearBogusContentEncodingIfNeeded()
 {
     // For .gz files, apache sends both a Content-Type: application/x-gzip
     // as well as Content-Encoding: gzip, which is completely wrong.  In
     // this case, we choose to ignore the rogue Content-Encoding header. We
     // must do this early on so as to prevent it from being seen up stream.
     // The same problem exists for Content-Encoding: compress in default
     // Apache installs.
+    nsAutoCString contentType;
+    mResponseHead->ContentType(contentType);
     if (mResponseHead->HasHeaderValue(nsHttp::Content_Encoding, "gzip") && (
-        mResponseHead->ContentType().EqualsLiteral(APPLICATION_GZIP) ||
-        mResponseHead->ContentType().EqualsLiteral(APPLICATION_GZIP2) ||
-        mResponseHead->ContentType().EqualsLiteral(APPLICATION_GZIP3))) {
+        contentType.EqualsLiteral(APPLICATION_GZIP) ||
+        contentType.EqualsLiteral(APPLICATION_GZIP2) ||
+        contentType.EqualsLiteral(APPLICATION_GZIP3))) {
         // clear the Content-Encoding header
         mResponseHead->ClearHeader(nsHttp::Content_Encoding);
     }
     else if (mResponseHead->HasHeaderValue(nsHttp::Content_Encoding, "compress") && (
-             mResponseHead->ContentType().EqualsLiteral(APPLICATION_COMPRESS) ||
-             mResponseHead->ContentType().EqualsLiteral(APPLICATION_COMPRESS2))) {
+             contentType.EqualsLiteral(APPLICATION_COMPRESS) ||
+             contentType.EqualsLiteral(APPLICATION_COMPRESS2))) {
         // clear the Content-Encoding header
         mResponseHead->ClearHeader(nsHttp::Content_Encoding);
     }
 }
 
 //-----------------------------------------------------------------------------
 // nsHttpChannel <redirect>
 //-----------------------------------------------------------------------------
@@ -4832,42 +4853,42 @@ nsHttpChannel::SetupReplacementChannel(n
 }
 
 nsresult
 nsHttpChannel::AsyncProcessRedirection(uint32_t redirectType)
 {
     LOG(("nsHttpChannel::AsyncProcessRedirection [this=%p type=%u]\n",
         this, redirectType));
 
-    const char *location = mResponseHead->PeekHeader(nsHttp::Location);
+    nsAutoCString location;
 
     // if a location header was not given, then we can't perform the redirect,
     // so just carry on as though this were a normal response.
-    if (!location)
+    if (NS_FAILED(mResponseHead->GetHeader(nsHttp::Location, location)))
         return NS_ERROR_FAILURE;
 
     // make sure non-ASCII characters in the location header are escaped.
     nsAutoCString locationBuf;
-    if (NS_EscapeURL(location, -1, esc_OnlyNonASCII, locationBuf))
-        location = locationBuf.get();
+    if (NS_EscapeURL(location.get(), -1, esc_OnlyNonASCII, locationBuf))
+        location = locationBuf;
 
     if (mRedirectionLimit == 0) {
         LOG(("redirection limit reached!\n"));
         return NS_ERROR_REDIRECT_LOOP;
     }
 
     mRedirectType = redirectType;
 
     LOG(("redirecting to: %s [redirection-limit=%u]\n",
-        location, uint32_t(mRedirectionLimit)));
-
-    nsresult rv = CreateNewURI(location, getter_AddRefs(mRedirectURI));
+        location.get(), uint32_t(mRedirectionLimit)));
+
+    nsresult rv = CreateNewURI(location.get(), getter_AddRefs(mRedirectURI));
 
     if (NS_FAILED(rv)) {
-        LOG(("Invalid URI for redirect: Location: %s\n", location));
+        LOG(("Invalid URI for redirect: Location: %s\n", location.get()));
         return NS_ERROR_CORRUPTED_CONTENT;
     }
 
     if (mApplicationCache) {
         // if we are redirected to a different origin check if there is a fallback
         // cache entry to fall back to. we don't care about file strict
         // checking, at least mURI is not a file URI.
         if (!NS_SecurityCompareURIs(mURI, mRedirectURI, false)) {
@@ -7169,27 +7190,28 @@ nsHttpChannel::MaybeInvalidateCacheEntry
       mURI->GetAsciiSpec(key);
       LOG(("MaybeInvalidateCacheEntryForSubsequentGet [this=%p uri=%s]\n",
           this, key.get()));
     }
 
     DoInvalidateCacheEntry(mURI);
 
     // Invalidate Location-header if set
-    const char *location = mResponseHead->PeekHeader(nsHttp::Location);
-    if (location) {
-        LOG(("  Location-header=%s\n", location));
-        InvalidateCacheEntryForLocation(location);
+    nsAutoCString location;
+    mResponseHead->GetHeader(nsHttp::Location, location);
+    if (!location.IsEmpty()) {
+        LOG(("  Location-header=%s\n", location.get()));
+        InvalidateCacheEntryForLocation(location.get());
     }
 
     // Invalidate Content-Location-header if set
-    location = mResponseHead->PeekHeader(nsHttp::Content_Location);
-    if (location) {
-        LOG(("  Content-Location-header=%s\n", location));
-        InvalidateCacheEntryForLocation(location);
+    mResponseHead->GetHeader(nsHttp::Content_Location, location);
+    if (!location.IsEmpty()) {
+        LOG(("  Content-Location-header=%s\n", location.get()));
+        InvalidateCacheEntryForLocation(location.get());
     }
 }
 
 void
 nsHttpChannel::InvalidateCacheEntryForLocation(const char *location)
 {
     nsAutoCString tmpCacheKey, tmpSpec;
     nsCOMPtr<nsIURI> resultingURI;
--- a/netwerk/protocol/http/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/nsHttpConnection.cpp
@@ -788,21 +788,22 @@ nsHttpConnection::SupportsPipelining(nsH
 
     // assuming connection is HTTP/1.1 with keep-alive enabled
     if (mConnInfo->UsingHttpProxy() && !mConnInfo->UsingConnect()) {
         // XXX check for bad proxy servers...
         return true;
     }
 
     // check for bad origin servers
-    const char *val = responseHead->PeekHeader(nsHttp::Server);
+    nsAutoCString val;
+    responseHead->GetHeader(nsHttp::Server, val);
 
     // If there is no server header we will assume it should not be banned
     // as facebook and some other prominent sites do this
-    if (!val)
+    if (val.IsEmpty())
         return true;
 
     // The blacklist is indexed by the first character. All of these servers are
     // known to return their identifier as the first thing in the server string,
     // so we can do a leading match.
 
     static const char *bad_servers[26][6] = {
         { nullptr }, { nullptr }, { nullptr }, { nullptr },                 // a - d
@@ -814,21 +815,21 @@ nsHttpConnection::SupportsPipelining(nsH
           "Netscape-Enterprise/5.", "Netscape-Enterprise/6.", nullptr }, // n
         { nullptr }, { nullptr }, { nullptr }, { nullptr },                 // o - r
         { nullptr }, { nullptr }, { nullptr }, { nullptr },                 // s - v
         { "WebLogic 3.", "WebLogic 4.","WebLogic 5.", "WebLogic 6.",
           "Winstone Servlet Engine v0.", nullptr },                      // w
         { nullptr }, { nullptr }, { nullptr }                              // x - z
     };
 
-    int index = val[0] - 'A'; // the whole table begins with capital letters
+    int index = val.get()[0] - 'A'; // the whole table begins with capital letters
     if ((index >= 0) && (index <= 25))
     {
         for (int i = 0; bad_servers[index][i] != nullptr; i++) {
-            if (!PL_strncmp (val, bad_servers[index][i], strlen (bad_servers[index][i]))) {
+            if (val.Equals(bad_servers[index][i])) {
                 LOG(("looks like this server does not support pipelining"));
                 gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
                     mConnInfo, nsHttpConnectionMgr::RedBannedServer, this , 0);
                 return false;
             }
         }
     }
 
@@ -963,26 +964,27 @@ nsHttpConnection::OnHeadersAvailable(nsA
     // header specifying the maximum number of times the connection can be
     // reused as well as the maximum amount of time the connection can be idle
     // before the server will close it.  we ignore the max reuse count, because
     // a "keep-alive" connection is by definition capable of being reused, and
     // we only care about being able to reuse it once.  if a timeout is not
     // specified then we use our advertized timeout value.
     bool foundKeepAliveMax = false;
     if (mKeepAlive) {
-        const char *val = responseHead->PeekHeader(nsHttp::Keep_Alive);
+        nsAutoCString keepAlive;
+        responseHead->GetHeader(nsHttp::Keep_Alive, keepAlive);
 
         if (!mUsingSpdyVersion) {
-            const char *cp = PL_strcasestr(val, "timeout=");
+            const char *cp = PL_strcasestr(keepAlive.get(), "timeout=");
             if (cp)
                 mIdleTimeout = PR_SecondsToInterval((uint32_t) atoi(cp + 8));
             else
                 mIdleTimeout = gHttpHandler->IdleTimeout();
 
-            cp = PL_strcasestr(val, "max=");
+            cp = PL_strcasestr(keepAlive.get(), "max=");
             if (cp) {
                 int maxUses = atoi(cp + 4);
                 if (maxUses > 0) {
                     foundKeepAliveMax = true;
                     mRemainingConnectionUses = static_cast<uint32_t>(maxUses);
                 }
             }
         }
@@ -1041,28 +1043,31 @@ nsHttpConnection::OnHeadersAvailable(nsA
     // Don't use persistent connection for Upgrade unless there's an auth failure:
     // some proxies expect to see auth response on persistent connection.
     if (hasUpgradeReq && responseStatus != 401 && responseStatus != 407) {
         LOG(("HTTP Upgrade in play - disable keepalive\n"));
         DontReuse();
     }
 
     if (responseStatus == 101) {
-        const char *upgradeResp = responseHead->PeekHeader(nsHttp::Upgrade);
-        if (!hasUpgradeReq || !upgradeResp ||
-            !nsHttp::FindToken(upgradeResp, upgradeReq.get(),
+        nsAutoCString upgradeResp;
+        bool hasUpgradeResp = NS_SUCCEEDED(responseHead->GetHeader(
+                                                nsHttp::Upgrade,
+                                                upgradeResp));
+        if (!hasUpgradeReq || !hasUpgradeResp ||
+            !nsHttp::FindToken(upgradeResp.get(), upgradeReq.get(),
                                HTTP_HEADER_VALUE_SEPS)) {
             LOG(("HTTP 101 Upgrade header mismatch req = %s, resp = %s\n",
                  upgradeReq.get(),
-                 upgradeResp ? upgradeResp :
-                               "RESPONSE's nsHttp::Upgrade is empty"));
+                 !upgradeResp.IsEmpty() ? upgradeResp.get() :
+                     "RESPONSE's nsHttp::Upgrade is empty"));
             Close(NS_ERROR_ABORT);
         }
         else {
-            LOG(("HTTP Upgrade Response to %s\n", upgradeResp));
+            LOG(("HTTP Upgrade Response to %s\n", upgradeResp.get()));
         }
     }
 
     mLastHttpResponseVersion = responseHead->Version();
 
     return NS_OK;
 }
 
--- a/netwerk/protocol/http/nsHttpResponseHead.cpp
+++ b/netwerk/protocol/http/nsHttpResponseHead.cpp
@@ -3,64 +3,246 @@
 /* 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/. */
 
 // HttpLog.h should generally be included first
 #include "HttpLog.h"
 
 #include "nsHttpResponseHead.h"
+#include "nsIHttpHeaderVisitor.h"
 #include "nsPrintfCString.h"
 #include "prtime.h"
 #include "plstr.h"
 #include "nsURLHelper.h"
 #include <algorithm>
 
 namespace mozilla {
 namespace net {
 
 //-----------------------------------------------------------------------------
 // nsHttpResponseHead <public>
 //-----------------------------------------------------------------------------
 
+nsHttpResponseHead::nsHttpResponseHead(const nsHttpResponseHead &aOther)
+    : mReentrantMonitor("nsHttpResponseHead.mReentrantMonitor")
+    , mInVisitHeaders(false)
+{
+    nsHttpResponseHead &other = const_cast<nsHttpResponseHead&>(aOther);
+    ReentrantMonitorAutoEnter monitor(other.mReentrantMonitor);
+
+    mHeaders = other.mHeaders;
+    mVersion = other.mVersion;
+    mStatus = other.mStatus;
+    mStatusText = other.mStatusText;
+    mContentLength = other.mContentLength;
+    mContentType = other.mContentType;
+    mContentCharset = other.mContentCharset;
+    mCacheControlPrivate = other.mCacheControlPrivate;
+    mCacheControlNoStore = other.mCacheControlNoStore;
+    mCacheControlNoCache = other.mCacheControlNoCache;
+    mCacheControlImmutable = other.mCacheControlImmutable;
+    mPragmaNoCache = other.mPragmaNoCache;
+}
+
+nsHttpResponseHead&
+nsHttpResponseHead::operator=(const nsHttpResponseHead &aOther)
+{
+    nsHttpResponseHead &other = const_cast<nsHttpResponseHead&>(aOther);
+    ReentrantMonitorAutoEnter monitorOther(other.mReentrantMonitor);
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+
+    mHeaders = other.mHeaders;
+    mVersion = other.mVersion;
+    mStatus = other.mStatus;
+    mStatusText = other.mStatusText;
+    mContentLength = other.mContentLength;
+    mContentType = other.mContentType;
+    mContentCharset = other.mContentCharset;
+    mCacheControlPrivate = other.mCacheControlPrivate;
+    mCacheControlNoStore = other.mCacheControlNoStore;
+    mCacheControlNoCache = other.mCacheControlNoCache;
+    mCacheControlImmutable = other.mCacheControlImmutable;
+    mPragmaNoCache = other.mPragmaNoCache;
+
+    return *this;
+}
+
+nsHttpVersion
+nsHttpResponseHead::Version()
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return mVersion;
+}
+
+uint16_t
+nsHttpResponseHead::Status()
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return mStatus;
+}
+
+void
+nsHttpResponseHead::StatusText(nsACString &aStatusText)
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    aStatusText = mStatusText;
+}
+
+int64_t
+nsHttpResponseHead::ContentLength()
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return mContentLength;
+}
+
+void
+nsHttpResponseHead::ContentType(nsACString &aContentType)
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    aContentType = mContentType;
+}
+
+void
+nsHttpResponseHead::ContentCharset(nsACString &aContentCharset)
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    aContentCharset = mContentCharset;
+}
+
+bool
+nsHttpResponseHead::Private()
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return mCacheControlPrivate;
+}
+
+bool
+nsHttpResponseHead::NoStore()
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return mCacheControlNoStore;
+}
+
+bool
+nsHttpResponseHead::NoCache()
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return (mCacheControlNoCache || mPragmaNoCache);
+}
+
+bool
+nsHttpResponseHead::Immutable()
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return mCacheControlImmutable;
+}
+
 nsresult
 nsHttpResponseHead::SetHeader(nsHttpAtom hdr,
                               const nsACString &val,
                               bool merge)
 {
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+
+    if (mInVisitHeaders) {
+        return NS_ERROR_FAILURE;
+    }
+
+    return SetHeader_locked(hdr, val, merge);
+}
+
+nsresult
+nsHttpResponseHead::SetHeader_locked(nsHttpAtom hdr,
+                                     const nsACString &val,
+                                     bool merge)
+{
     nsresult rv = mHeaders.SetHeader(hdr, val, merge,
                                      nsHttpHeaderArray::eVarietyResponse);
     if (NS_FAILED(rv)) return rv;
 
     // respond to changes in these headers.  we need to reparse the entire
     // header since the change may have merged in additional values.
     if (hdr == nsHttp::Cache_Control)
         ParseCacheControl(mHeaders.PeekHeader(hdr));
     else if (hdr == nsHttp::Pragma)
         ParsePragma(mHeaders.PeekHeader(hdr));
 
     return NS_OK;
 }
 
+nsresult
+nsHttpResponseHead::GetHeader(nsHttpAtom h, nsACString &v)
+{
+    v.Truncate();
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return mHeaders.GetHeader(h, v);
+}
+
+void
+nsHttpResponseHead::ClearHeader(nsHttpAtom h)
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    mHeaders.ClearHeader(h);
+}
+
+void
+nsHttpResponseHead::ClearHeaders()
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    mHeaders.Clear();
+}
+
+bool
+nsHttpResponseHead::HasHeaderValue(nsHttpAtom h, const char *v)
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return mHeaders.HasHeaderValue(h, v);
+}
+
+bool
+nsHttpResponseHead::HasHeader(nsHttpAtom h)
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return mHeaders.HasHeader(h);
+}
+
+void
+nsHttpResponseHead::SetContentType(const nsACString &s)
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    mContentType = s;
+}
+
+void
+nsHttpResponseHead::SetContentCharset(const nsACString &s)
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    mContentCharset = s;
+}
+
 void
 nsHttpResponseHead::SetContentLength(int64_t len)
 {
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+
     mContentLength = len;
     if (len < 0)
         mHeaders.ClearHeader(nsHttp::Content_Length);
     else
         mHeaders.SetHeader(nsHttp::Content_Length,
                            nsPrintfCString("%lld", len),
                            false,
                            nsHttpHeaderArray::eVarietyResponse);
 }
 
 void
 nsHttpResponseHead::Flatten(nsACString &buf, bool pruneTransients)
 {
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
     if (mVersion == NS_HTTP_VERSION_0_9)
         return;
 
     buf.AppendLiteral("HTTP/");
     if (mVersion == NS_HTTP_VERSION_2_0)
         buf.AppendLiteral("2.0 ");
     else if (mVersion == NS_HTTP_VERSION_1_1)
         buf.AppendLiteral("1.1 ");
@@ -74,54 +256,55 @@ nsHttpResponseHead::Flatten(nsACString &
 
 
     mHeaders.Flatten(buf, false, pruneTransients);
 }
 
 void
 nsHttpResponseHead::FlattenOriginalHeader(nsACString &buf)
 {
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
     if (mVersion == NS_HTTP_VERSION_0_9) {
         return;
     }
 
     buf.AppendLiteral("  OriginalHeaders");
     buf.AppendLiteral("\r\n");
 
     mHeaders.FlattenOriginalHeader(buf);
 }
 
 nsresult
 nsHttpResponseHead::Parse(char *block)
 {
-
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
     LOG(("nsHttpResponseHead::Parse [this=%p]\n", this));
 
     // this command works on a buffer as prepared by Flatten, as such it is
     // not very forgiving ;-)
 
     char *p = PL_strstr(block, "\r\n");
     if (!p)
         return NS_ERROR_UNEXPECTED;
 
     *p = 0;
-    ParseStatusLine(block);
+    ParseStatusLine_locked(block);
 
     do {
         block = p + 2;
 
         if (*block == 0)
             break;
 
         p = PL_strstr(block, "\r\n");
         if (!p)
             return NS_ERROR_UNEXPECTED;
 
         *p = 0;
-        ParseHeaderLine(block);
+        ParseHeaderLine_locked(block);
 
     } while (1);
 
     return NS_OK;
 }
 
 void
 nsHttpResponseHead::AssignDefaultStatusText()
@@ -275,16 +458,23 @@ nsHttpResponseHead::AssignDefaultStatusT
         mStatusText.AssignLiteral("No Reason Phrase");
         break;
     }
 }
 
 void
 nsHttpResponseHead::ParseStatusLine(const char *line)
 {
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    ParseStatusLine_locked(line);
+}
+
+void
+nsHttpResponseHead::ParseStatusLine_locked(const char *line)
+{
     //
     // Parse Status-Line:: HTTP-Version SP Status-Code SP Reason-Phrase CRLF
     //
 
     // HTTP-Version
     ParseVersion(line);
 
     if ((mVersion == NS_HTTP_VERSION_0_9) || !(line = PL_strchr(line, ' '))) {
@@ -309,16 +499,23 @@ nsHttpResponseHead::ParseStatusLine(cons
 
     LOG(("Have status line [version=%u status=%u statusText=%s]\n",
         unsigned(mVersion), unsigned(mStatus), mStatusText.get()));
 }
 
 nsresult
 nsHttpResponseHead::ParseHeaderLine(const char *line)
 {
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return ParseHeaderLine_locked(line);
+}
+
+nsresult
+nsHttpResponseHead::ParseHeaderLine_locked(const char *line)
+{
     nsHttpAtom hdr = {0};
     char *val;
 
     if (NS_FAILED(nsHttpHeaderArray::ParseHeaderLine(line, &hdr, &val))) {
         return NS_OK;
     } 
     nsresult rv = mHeaders.SetHeaderFromNet(hdr,
                                             nsDependentCString(val),
@@ -363,42 +560,43 @@ nsHttpResponseHead::ParseHeaderLine(cons
 //
 //    where responseTime == now
 //
 // This is typically a very small number.
 //
 nsresult
 nsHttpResponseHead::ComputeCurrentAge(uint32_t now,
                                       uint32_t requestTime,
-                                      uint32_t *result) const
+                                      uint32_t *result)
 {
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
     uint32_t dateValue;
     uint32_t ageValue;
 
     *result = 0;
 
     if (requestTime > now) {
         // for calculation purposes lets not allow the request to happen in the future
         requestTime = now;
     }
 
-    if (NS_FAILED(GetDateValue(&dateValue))) {
+    if (NS_FAILED(GetDateValue_locked(&dateValue))) {
         LOG(("nsHttpResponseHead::ComputeCurrentAge [this=%p] "
              "Date response header not set!\n", this));
         // Assume we have a fast connection and that our clock
         // is in sync with the server.
         dateValue = now;
     }
 
     // Compute apparent age
     if (now > dateValue)
         *result = now - dateValue;
 
     // Compute corrected received age
-    if (NS_SUCCEEDED(GetAgeValue(&ageValue)))
+    if (NS_SUCCEEDED(GetAgeValue_locked(&ageValue)))
         *result = std::max(*result, ageValue);
 
     // Compute current age
     *result += (now - requestTime);
     return NS_OK;
 }
 
 // From section 13.2.4 of RFC2616, we compute the freshness lifetime of a cached
@@ -408,32 +606,33 @@ nsHttpResponseHead::ComputeCurrentAge(ui
 // <or>
 //     freshnessLifetime = expires_value - date_value
 // <or>
 //     freshnessLifetime = min(one-week,(date_value - last_modified_value) * 0.10)
 // <or>
 //     freshnessLifetime = 0
 //
 nsresult
-nsHttpResponseHead::ComputeFreshnessLifetime(uint32_t *result) const
+nsHttpResponseHead::ComputeFreshnessLifetime(uint32_t *result)
 {
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
     *result = 0;
 
     // Try HTTP/1.1 style max-age directive...
-    if (NS_SUCCEEDED(GetMaxAgeValue(result)))
+    if (NS_SUCCEEDED(GetMaxAgeValue_locked(result)))
         return NS_OK;
 
     *result = 0;
 
     uint32_t date = 0, date2 = 0;
-    if (NS_FAILED(GetDateValue(&date)))
+    if (NS_FAILED(GetDateValue_locked(&date)))
         date = NowInSeconds(); // synthesize a date header if none exists
 
     // Try HTTP/1.0 style expires header...
-    if (NS_SUCCEEDED(GetExpiresValue(&date2))) {
+    if (NS_SUCCEEDED(GetExpiresValue_locked(&date2))) {
         if (date2 > date)
             *result = date2 - date;
         // the Expires header can specify a date in the past.
         return NS_OK;
     }
 
     // These responses can be cached indefinitely.
     if ((mStatus == 300) || (mStatus == 410) || nsHttp::IsPermanentRedirect(mStatus)) {
@@ -445,17 +644,17 @@ nsHttpResponseHead::ComputeFreshnessLife
 
     if (mStatus >= 400) {
         LOG(("nsHttpResponseHead::ComputeFreshnessLifetime [this = %p] "
              "Do not calculate heuristic max-age for most responses >= 400\n", this));
         return NS_OK;
     }
 
     // Fallback on heuristic using last modified header...
-    if (NS_SUCCEEDED(GetLastModifiedValue(&date2))) {
+    if (NS_SUCCEEDED(GetLastModifiedValue_locked(&date2))) {
         LOG(("using last-modified to determine freshness-lifetime\n"));
         LOG(("last-modified = %u, date = %u\n", date2, date));
         if (date2 <= date) {
             // this only makes sense if last-modified is actually in the past
             *result = (date - date2) / 10;
             const uint32_t kOneWeek = 60 * 60 * 24 * 7;
             *result = std::min(kOneWeek, *result);
             return NS_OK;
@@ -465,18 +664,19 @@ nsHttpResponseHead::ComputeFreshnessLife
     LOG(("nsHttpResponseHead::ComputeFreshnessLifetime [this = %p] "
          "Insufficient information to compute a non-zero freshness "
          "lifetime!\n", this));
 
     return NS_OK;
 }
 
 bool
-nsHttpResponseHead::MustValidate() const
+nsHttpResponseHead::MustValidate()
 {
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
     LOG(("nsHttpResponseHead::MustValidate ??\n"));
 
     // Some response codes are cacheable, but the rest are not.  This switch
     // should stay in sync with the list in nsHttpChannel::ProcessResponse
     switch (mStatus) {
         // Success codes
     case 200:
     case 203:
@@ -501,93 +701,105 @@ nsHttpResponseHead::MustValidate() const
     case 416:
     default:  // revalidate unknown error pages
         LOG(("Must validate since response is an uncacheable error page\n"));
         return true;
     }
 
     // The no-cache response header indicates that we must validate this
     // cached response before reusing.
-    if (NoCache()) {
+    if (mCacheControlNoCache || mPragmaNoCache) {
         LOG(("Must validate since response contains 'no-cache' header\n"));
         return true;
     }
 
     // Likewise, if the response is no-store, then we must validate this
     // cached response before reusing.  NOTE: it may seem odd that a no-store
     // response may be cached, but indeed all responses are cached in order
     // to support File->SaveAs, View->PageSource, and other browser features.
-    if (NoStore()) {
+    if (mCacheControlNoStore) {
         LOG(("Must validate since response contains 'no-store' header\n"));
         return true;
     }
 
     // Compare the Expires header to the Date header.  If the server sent an
     // Expires header with a timestamp in the past, then we must validate this
     // cached response before reusing.
-    if (ExpiresInPast()) {
+    if (ExpiresInPast_locked()) {
         LOG(("Must validate since Expires < Date\n"));
         return true;
     }
 
     LOG(("no mandatory validation requirement\n"));
     return false;
 }
 
 bool
-nsHttpResponseHead::MustValidateIfExpired() const
+nsHttpResponseHead::MustValidateIfExpired()
 {
     // according to RFC2616, section 14.9.4:
     //
     //  When the must-revalidate directive is present in a response received by a
     //  cache, that cache MUST NOT use the entry after it becomes stale to respond to
     //  a subsequent request without first revalidating it with the origin server.
     //
     return HasHeaderValue(nsHttp::Cache_Control, "must-revalidate");
 }
 
 bool
-nsHttpResponseHead::IsResumable() const
+nsHttpResponseHead::IsResumable()
 {
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
     // even though some HTTP/1.0 servers may support byte range requests, we're not
     // going to bother with them, since those servers wouldn't understand If-Range.
     // Also, while in theory it may be possible to resume when the status code
     // is not 200, it is unlikely to be worth the trouble, especially for
     // non-2xx responses.
     return mStatus == 200 &&
            mVersion >= NS_HTTP_VERSION_1_1 &&
-           PeekHeader(nsHttp::Content_Length) &&
-          (PeekHeader(nsHttp::ETag) || PeekHeader(nsHttp::Last_Modified)) &&
-           HasHeaderValue(nsHttp::Accept_Ranges, "bytes");
+           mHeaders.PeekHeader(nsHttp::Content_Length) &&
+           (mHeaders.PeekHeader(nsHttp::ETag) ||
+            mHeaders.PeekHeader(nsHttp::Last_Modified)) &&
+           mHeaders.HasHeaderValue(nsHttp::Accept_Ranges, "bytes");
 }
 
 bool
-nsHttpResponseHead::ExpiresInPast() const
+nsHttpResponseHead::ExpiresInPast()
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return ExpiresInPast_locked();
+}
+
+bool
+nsHttpResponseHead::ExpiresInPast_locked() const
 {
     uint32_t maxAgeVal, expiresVal, dateVal;
 
     // Bug #203271. Ensure max-age directive takes precedence over Expires
-    if (NS_SUCCEEDED(GetMaxAgeValue(&maxAgeVal))) {
+    if (NS_SUCCEEDED(GetMaxAgeValue_locked(&maxAgeVal))) {
         return false;
     }
 
-    return NS_SUCCEEDED(GetExpiresValue(&expiresVal)) &&
-           NS_SUCCEEDED(GetDateValue(&dateVal)) &&
+    return NS_SUCCEEDED(GetExpiresValue_locked(&expiresVal)) &&
+           NS_SUCCEEDED(GetDateValue_locked(&dateVal)) &&
            expiresVal < dateVal;
 }
 
 nsresult
-nsHttpResponseHead::UpdateHeaders(const nsHttpHeaderArray &headers)
+nsHttpResponseHead::UpdateHeaders(nsHttpResponseHead *aOther)
 {
     LOG(("nsHttpResponseHead::UpdateHeaders [this=%p]\n", this));
 
-    uint32_t i, count = headers.Count();
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    ReentrantMonitorAutoEnter monitorOther(aOther->mReentrantMonitor);
+
+    uint32_t i, count = aOther->mHeaders.Count();
     for (i=0; i<count; ++i) {
         nsHttpAtom header;
-        const char *val = headers.PeekHeaderAt(i, header);
+        const char *val = aOther->mHeaders.PeekHeaderAt(i, header);
 
         if (!val) {
             continue;
         }
 
         // Ignore any hop-by-hop headers...
         if (header == nsHttp::Connection          ||
             header == nsHttp::Proxy_Connection    ||
@@ -611,29 +823,31 @@ nsHttpResponseHead::UpdateHeaders(const 
             // on 304 responses
             header == nsHttp::Content_Length) {
             LOG(("ignoring response header [%s: %s]\n", header.get(), val));
         }
         else {
             LOG(("new response header [%s: %s]\n", header.get(), val));
 
             // overwrite the current header value with the new value...
-            SetHeader(header, nsDependentCString(val));
+            SetHeader_locked(header, nsDependentCString(val));
         }
     }
 
     return NS_OK;
 }
 
 void
 nsHttpResponseHead::Reset()
 {
     LOG(("nsHttpResponseHead::Reset\n"));
 
-    ClearHeaders();
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+
+    mHeaders.Clear();
 
     mVersion = NS_HTTP_VERSION_1_1;
     mStatus = 200;
     mContentLength = -1;
     mCacheControlPrivate = false;
     mCacheControlNoStore = false;
     mCacheControlNoCache = false;
     mCacheControlImmutable = false;
@@ -641,46 +855,60 @@ nsHttpResponseHead::Reset()
     mStatusText.Truncate();
     mContentType.Truncate();
     mContentCharset.Truncate();
 }
 
 nsresult
 nsHttpResponseHead::ParseDateHeader(nsHttpAtom header, uint32_t *result) const
 {
-    const char *val = PeekHeader(header);
+    const char *val = mHeaders.PeekHeader(header);
     if (!val)
         return NS_ERROR_NOT_AVAILABLE;
 
     PRTime time;
     PRStatus st = PR_ParseTimeString(val, true, &time);
     if (st != PR_SUCCESS)
         return NS_ERROR_NOT_AVAILABLE;
 
     *result = PRTimeToSeconds(time);
     return NS_OK;
 }
 
 nsresult
-nsHttpResponseHead::GetAgeValue(uint32_t *result) const
+nsHttpResponseHead::GetAgeValue(uint32_t *result)
 {
-    const char *val = PeekHeader(nsHttp::Age);
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return GetAgeValue_locked(result);
+}
+
+nsresult
+nsHttpResponseHead::GetAgeValue_locked(uint32_t *result) const
+{
+    const char *val = mHeaders.PeekHeader(nsHttp::Age);
     if (!val)
         return NS_ERROR_NOT_AVAILABLE;
 
     *result = (uint32_t) atoi(val);
     return NS_OK;
 }
 
 // Return the value of the (HTTP 1.1) max-age directive, which itself is a
 // component of the Cache-Control response header
 nsresult
-nsHttpResponseHead::GetMaxAgeValue(uint32_t *result) const
+nsHttpResponseHead::GetMaxAgeValue(uint32_t *result)
 {
-    const char *val = PeekHeader(nsHttp::Cache_Control);
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return GetMaxAgeValue_locked(result);
+}
+
+nsresult
+nsHttpResponseHead::GetMaxAgeValue_locked(uint32_t *result) const
+{
+    const char *val = mHeaders.PeekHeader(nsHttp::Cache_Control);
     if (!val)
         return NS_ERROR_NOT_AVAILABLE;
 
     const char *p = nsHttp::FindToken(val, "max-age", HTTP_HEADER_VALUE_SEPS "=");
     if (!p)
         return NS_ERROR_NOT_AVAILABLE;
     p += 7;
     while (*p == ' ' || *p == '\t')
@@ -694,19 +922,33 @@ nsHttpResponseHead::GetMaxAgeValue(uint3
     int maxAgeValue = atoi(p);
     if (maxAgeValue < 0)
         maxAgeValue = 0;
     *result = static_cast<uint32_t>(maxAgeValue);
     return NS_OK;
 }
 
 nsresult
-nsHttpResponseHead::GetExpiresValue(uint32_t *result) const
+nsHttpResponseHead::GetDateValue(uint32_t *result)
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return GetDateValue_locked(result);
+}
+
+nsresult
+nsHttpResponseHead::GetExpiresValue(uint32_t *result)
 {
-    const char *val = PeekHeader(nsHttp::Expires);
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return GetExpiresValue_locked(result);
+}
+
+nsresult
+nsHttpResponseHead::GetExpiresValue_locked(uint32_t *result) const
+{
+    const char *val = mHeaders.PeekHeader(nsHttp::Expires);
     if (!val)
         return NS_ERROR_NOT_AVAILABLE;
 
     PRTime time;
     PRStatus st = PR_ParseTimeString(val, true, &time);
     if (st != PR_SUCCESS) {
         // parsing failed... RFC 2616 section 14.21 says we should treat this
         // as an expiration time in the past.
@@ -716,22 +958,52 @@ nsHttpResponseHead::GetExpiresValue(uint
 
     if (time < 0)
         *result = 0;
     else
         *result = PRTimeToSeconds(time);
     return NS_OK;
 }
 
-int64_t
-nsHttpResponseHead::TotalEntitySize() const
+nsresult
+nsHttpResponseHead::GetLastModifiedValue(uint32_t *result)
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return ParseDateHeader(nsHttp::Last_Modified, result);
+}
+
+bool
+nsHttpResponseHead::operator==(const nsHttpResponseHead& aOther) const
 {
-    const char* contentRange = PeekHeader(nsHttp::Content_Range);
+    nsHttpResponseHead &curr = const_cast<nsHttpResponseHead&>(*this);
+    nsHttpResponseHead &other = const_cast<nsHttpResponseHead&>(aOther);
+    ReentrantMonitorAutoEnter monitorOther(other.mReentrantMonitor);
+    ReentrantMonitorAutoEnter monitor(curr.mReentrantMonitor);
+
+    return mHeaders == aOther.mHeaders &&
+           mVersion == aOther.mVersion &&
+           mStatus == aOther.mStatus &&
+           mStatusText == aOther.mStatusText &&
+           mContentLength == aOther.mContentLength &&
+           mContentType == aOther.mContentType &&
+           mContentCharset == aOther.mContentCharset &&
+           mCacheControlPrivate == aOther.mCacheControlPrivate &&
+           mCacheControlNoCache == aOther.mCacheControlNoCache &&
+           mCacheControlNoStore == aOther.mCacheControlNoStore &&
+           mCacheControlImmutable == aOther.mCacheControlImmutable &&
+           mPragmaNoCache == aOther.mPragmaNoCache;
+}
+
+int64_t
+nsHttpResponseHead::TotalEntitySize()
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    const char* contentRange = mHeaders.PeekHeader(nsHttp::Content_Range);
     if (!contentRange)
-        return ContentLength();
+        return mContentLength;
 
     // Total length is after a slash
     const char* slash = strrchr(contentRange, '/');
     if (!slash)
         return -1; // No idea what the length is
 
     slash++;
     if (*slash == '*') // Server doesn't know the length
@@ -842,10 +1114,46 @@ nsHttpResponseHead::ParsePragma(const ch
 
     // Although 'Pragma: no-cache' is not a standard HTTP response header (it's
     // a request header), caching is inhibited when this header is present so
     // as to match existing Navigator behavior.
     if (nsHttp::FindToken(val, "no-cache", HTTP_HEADER_VALUE_SEPS))
         mPragmaNoCache = true;
 }
 
+nsresult
+nsHttpResponseHead::VisitHeaders(nsIHttpHeaderVisitor *visitor,
+                                 nsHttpHeaderArray::VisitorFilter filter)
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    mInVisitHeaders = true;
+    nsresult rv = mHeaders.VisitHeaders(visitor, filter);
+    mInVisitHeaders = false;
+    return rv;
+}
+
+nsresult
+nsHttpResponseHead::GetOriginalHeader(nsHttpAtom aHeader,
+                                      nsIHttpHeaderVisitor *aVisitor)
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    mInVisitHeaders = true;
+    nsresult rv = mHeaders.GetOriginalHeader(aHeader, aVisitor);
+    mInVisitHeaders = false;
+    return rv;
+}
+
+bool
+nsHttpResponseHead::HasContentType()
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return !mContentType.IsEmpty();
+}
+
+bool
+nsHttpResponseHead::HasContentCharset()
+{
+    ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
+    return !mContentCharset.IsEmpty();
+}
+
 } // namespace net
 } // namespace mozilla
--- a/netwerk/protocol/http/nsHttpResponseHead.h
+++ b/netwerk/protocol/http/nsHttpResponseHead.h
@@ -4,16 +4,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsHttpResponseHead_h__
 #define nsHttpResponseHead_h__
 
 #include "nsHttpHeaderArray.h"
 #include "nsHttp.h"
 #include "nsString.h"
+#include "mozilla/ReentrantMonitor.h"
+
+class nsIHttpHeaderVisitor;
 
 // This needs to be forward declared here so we can include only this header
 // without also including PHttpChannelParams.h
 namespace IPC {
     template <typename> struct ParamTraits;
 } // namespace IPC
 
 namespace mozilla { namespace net {
@@ -28,144 +31,159 @@ class nsHttpResponseHead
 public:
     nsHttpResponseHead() : mVersion(NS_HTTP_VERSION_1_1)
                          , mStatus(200)
                          , mContentLength(-1)
                          , mCacheControlPrivate(false)
                          , mCacheControlNoStore(false)
                          , mCacheControlNoCache(false)
                          , mCacheControlImmutable(false)
-                         , mPragmaNoCache(false) {}
+                         , mPragmaNoCache(false)
+                         , mReentrantMonitor("nsHttpResponseHead.mReentrantMonitor")
+                         , mInVisitHeaders(false) {}
 
-    const nsHttpHeaderArray & Headers()   const { return mHeaders; }
-    nsHttpHeaderArray    &Headers()             { return mHeaders; }
-    nsHttpVersion         Version()       const { return mVersion; }
+    nsHttpResponseHead(const nsHttpResponseHead &aOther);
+    nsHttpResponseHead &operator=(const nsHttpResponseHead &aOther);
+
+    void Enter() { mReentrantMonitor.Enter(); }
+    void Exit() { mReentrantMonitor.Exit(); }
+
+    nsHttpVersion Version();
 // X11's Xlib.h #defines 'Status' to 'int' on some systems!
 #undef Status
-    uint16_t              Status()        const { return mStatus; }
-    const nsAFlatCString &StatusText()    const { return mStatusText; }
-    int64_t               ContentLength() const { return mContentLength; }
-    const nsAFlatCString &ContentType()   const { return mContentType; }
-    const nsAFlatCString &ContentCharset() const { return mContentCharset; }
-    bool                  Private() const { return mCacheControlPrivate; }
-    bool                  NoStore() const { return mCacheControlNoStore; }
-    bool                  NoCache() const { return (mCacheControlNoCache || mPragmaNoCache); }
-    bool                  Immutable() const { return mCacheControlImmutable; }
+    uint16_t Status();
+    void StatusText(nsACString &aStatusText);
+    int64_t ContentLength();
+    void ContentType(nsACString &aContentType);
+    void ContentCharset(nsACString &aContentCharset);
+    bool Private();
+    bool NoStore();
+    bool NoCache();
+    bool Immutable();
     /**
      * Full length of the entity. For byte-range requests, this may be larger
      * than ContentLength(), which will only represent the requested part of the
      * entity.
      */
-    int64_t               TotalEntitySize() const;
-
-    const char *PeekHeader(nsHttpAtom h) const      { return mHeaders.PeekHeader(h); }
-    nsresult SetHeader(nsHttpAtom h, const nsACString &v, bool m=false);
-    nsresult GetHeader(nsHttpAtom h, nsACString &v) const { return mHeaders.GetHeader(h, v); }
-    void     ClearHeader(nsHttpAtom h)              { mHeaders.ClearHeader(h); }
-    void     ClearHeaders()                         { mHeaders.Clear(); }
+    int64_t TotalEntitySize();
 
-    const char *FindHeaderValue(nsHttpAtom h, const char *v) const
-    {
-      return mHeaders.FindHeaderValue(h, v);
-    }
-    bool        HasHeaderValue(nsHttpAtom h, const char *v) const
-    {
-      return mHeaders.HasHeaderValue(h, v);
-    }
+    nsresult SetHeader(nsHttpAtom h, const nsACString &v, bool m=false);
+    nsresult GetHeader(nsHttpAtom h, nsACString &v);
+    void ClearHeader(nsHttpAtom h);
+    void ClearHeaders();
+    bool HasHeaderValue(nsHttpAtom h, const char *v);
+    bool HasHeader(nsHttpAtom h);
 
-    void     SetContentType(const nsACString &s)    { mContentType = s; }
-    void     SetContentCharset(const nsACString &s) { mContentCharset = s; }
-    void     SetContentLength(int64_t);
+    void SetContentType(const nsACString &s);
+    void SetContentCharset(const nsACString &s);
+    void SetContentLength(int64_t);
 
     // write out the response status line and headers as a single text block,
     // optionally pruning out transient headers (ie. headers that only make
     // sense the first time the response is handled).
     // Both functions append to the string supplied string.
-    void     Flatten(nsACString &, bool pruneTransients);
-    void     FlattenOriginalHeader(nsACString &buf);
+    void Flatten(nsACString &, bool pruneTransients);
+    void FlattenOriginalHeader(nsACString &buf);
 
     // parse flattened response head. block must be null terminated. parsing is
     // destructive.
     nsresult Parse(char *block);
 
     // parse the status line. line must be null terminated.
-    void     ParseStatusLine(const char *line);
+    void ParseStatusLine(const char *line);
 
     // parse a header line. line must be null terminated. parsing is destructive.
     nsresult ParseHeaderLine(const char *line);
 
     // cache validation support methods
-    nsresult ComputeFreshnessLifetime(uint32_t *) const;
-    nsresult ComputeCurrentAge(uint32_t now, uint32_t requestTime, uint32_t *result) const;
-    bool     MustValidate() const;
-    bool     MustValidateIfExpired() const;
+    nsresult ComputeFreshnessLifetime(uint32_t *);
+    nsresult ComputeCurrentAge(uint32_t now, uint32_t requestTime,
+                               uint32_t *result);
+    bool MustValidate();
+    bool MustValidateIfExpired();
 
     // returns true if the server appears to support byte range requests.
-    bool     IsResumable() const;
+    bool IsResumable();
 
     // returns true if the Expires header has a value in the past relative to the
     // value of the Date header.
-    bool     ExpiresInPast() const;
+    bool ExpiresInPast();
 
     // update headers...
-    nsresult UpdateHeaders(const nsHttpHeaderArray &headers);
+    nsresult UpdateHeaders(nsHttpResponseHead *headers);
 
     // reset the response head to it's initial state
-    void     Reset();
+    void Reset();
+
+    nsresult GetAgeValue(uint32_t *result);
+    nsresult GetMaxAgeValue(uint32_t *result);
+    nsresult GetDateValue(uint32_t *result);
+    nsresult GetExpiresValue(uint32_t *result);
+    nsresult GetLastModifiedValue(uint32_t *result);
+
+    bool operator==(const nsHttpResponseHead& aOther) const;
+
+    // Using this function it is possible to itereate through all headers
+    // automatically under one lock.
+    nsresult VisitHeaders(nsIHttpHeaderVisitor *visitor,
+                          nsHttpHeaderArray::VisitorFilter filter);
+    nsresult GetOriginalHeader(nsHttpAtom aHeader,
+                               nsIHttpHeaderVisitor *aVisitor);
+
+    bool HasContentType();
+    bool HasContentCharset();
+private:
+    nsresult SetHeader_locked(nsHttpAtom h, const nsACString &v,
+                              bool m=false);
+    void AssignDefaultStatusText();
+    void ParseVersion(const char *);
+    void ParseCacheControl(const char *);
+    void ParsePragma(const char *);
+
+    void ParseStatusLine_locked(const char *line);
+    nsresult ParseHeaderLine_locked(const char *line);
 
     // these return failure if the header does not exist.
     nsresult ParseDateHeader(nsHttpAtom header, uint32_t *result) const;
-    nsresult GetAgeValue(uint32_t *result) const;
-    nsresult GetMaxAgeValue(uint32_t *result) const;
-    nsresult GetDateValue(uint32_t *result) const
+
+    bool ExpiresInPast_locked() const;
+    nsresult GetAgeValue_locked(uint32_t *result) const;
+    nsresult GetExpiresValue_locked(uint32_t *result) const;
+    nsresult GetMaxAgeValue_locked(uint32_t *result) const;
+
+    nsresult GetDateValue_locked(uint32_t *result) const
     {
         return ParseDateHeader(nsHttp::Date, result);
     }
-    nsresult GetExpiresValue(uint32_t *result) const ;
-    nsresult GetLastModifiedValue(uint32_t *result) const
+
+    nsresult GetLastModifiedValue_locked(uint32_t *result) const
     {
         return ParseDateHeader(nsHttp::Last_Modified, result);
     }
 
-    bool operator==(const nsHttpResponseHead& aOther) const
-    {
-        return mHeaders == aOther.mHeaders &&
-               mVersion == aOther.mVersion &&
-               mStatus == aOther.mStatus &&
-               mStatusText == aOther.mStatusText &&
-               mContentLength == aOther.mContentLength &&
-               mContentType == aOther.mContentType &&
-               mContentCharset == aOther.mContentCharset &&
-               mCacheControlPrivate == aOther.mCacheControlPrivate &&
-               mCacheControlNoCache == aOther.mCacheControlNoCache &&
-               mCacheControlNoStore == aOther.mCacheControlNoStore &&
-               mCacheControlImmutable == aOther.mCacheControlImmutable &&
-               mPragmaNoCache == aOther.mPragmaNoCache;
-    }
-
-private:
-    void     AssignDefaultStatusText();
-    void     ParseVersion(const char *);
-    void     ParseCacheControl(const char *);
-    void     ParsePragma(const char *);
-
 private:
     // All members must be copy-constructable and assignable
     nsHttpHeaderArray mHeaders;
     nsHttpVersion     mVersion;
     uint16_t          mStatus;
     nsCString         mStatusText;
     int64_t           mContentLength;
     nsCString         mContentType;
     nsCString         mContentCharset;
     bool              mCacheControlPrivate;
     bool              mCacheControlNoStore;
     bool              mCacheControlNoCache;
     bool              mCacheControlImmutable;
     bool              mPragmaNoCache;
 
+    // We are using ReentrantMonitor instead of a Mutex because VisitHeader
+    // function calls nsIHttpHeaderVisitor::VisitHeader while under lock.
+    ReentrantMonitor  mReentrantMonitor;
+    // During VisitHeader we sould not allow cal to SetHeader.
+    bool              mInVisitHeaders;
+
     friend struct IPC::ParamTraits<nsHttpResponseHead>;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // nsHttpResponseHead_h__
--- a/netwerk/protocol/http/nsHttpTransaction.cpp
+++ b/netwerk/protocol/http/nsHttpTransaction.cpp
@@ -1860,17 +1860,17 @@ nsHttpTransaction::ProcessData(char *buf
         // the excess bytes back to the connection
         if (mResponseIsComplete && countRemaining) {
             MOZ_ASSERT(mConnection);
             mConnection->PushBack(buf + *countRead, countRemaining);
         }
 
         if (!mContentDecodingCheck && mResponseHead) {
             mContentDecoding =
-                !!mResponseHead->PeekHeader(nsHttp::Content_Encoding);
+                mResponseHead->HasHeader(nsHttp::Content_Encoding);
             mContentDecodingCheck = true;
         }
     }
 
     return NS_OK;
 }
 
 void
@@ -2222,24 +2222,24 @@ nsHttpTransaction::OnOutputStreamReady(n
 }
 
 // nsHttpTransaction::RestartVerifier
 
 static bool
 matchOld(nsHttpResponseHead *newHead, nsCString &old,
          nsHttpAtom headerAtom)
 {
-    const char *val;
+    nsAutoCString val;
 
-    val = newHead->PeekHeader(headerAtom);
-    if (val && old.IsEmpty())
+    newHead->GetHeader(headerAtom, val);
+    if (!val.IsEmpty() && old.IsEmpty())
         return false;
-    if (!val && !old.IsEmpty())
+    if (val.IsEmpty() && !old.IsEmpty())
         return false;
-    if (val && !old.Equals(val))
+    if (!val.IsEmpty() && !old.Equals(val))
         return false;
     return true;
 }
 
 bool
 nsHttpTransaction::RestartVerifier::Verify(int64_t contentLength,
                                            nsHttpResponseHead *newHead)
 {
@@ -2279,36 +2279,31 @@ nsHttpTransaction::RestartVerifier::Set(
 
     // Only RestartInProgress with 200 response code
     if (!head || (head->Status() != 200)) {
         return;
     }
 
     mContentLength = contentLength;
 
-    const char *val;
-    val = head->PeekHeader(nsHttp::ETag);
-    if (val) {
-        mETag.Assign(val);
+    nsAutoCString val;
+    if (NS_SUCCEEDED(head->GetHeader(nsHttp::ETag, val))) {
+        mETag = val;
     }
-    val = head->PeekHeader(nsHttp::Last_Modified);
-    if (val) {
-        mLastModified.Assign(val);
+    if (NS_SUCCEEDED(head->GetHeader(nsHttp::Last_Modified, val))) {
+        mLastModified = val;
     }
-    val = head->PeekHeader(nsHttp::Content_Range);
-    if (val) {
-        mContentRange.Assign(val);
+    if (NS_SUCCEEDED(head->GetHeader(nsHttp::Content_Range, val))) {
+        mContentRange = val;
     }
-    val = head->PeekHeader(nsHttp::Content_Encoding);
-    if (val) {
-        mContentEncoding.Assign(val);
+    if (NS_SUCCEEDED(head->GetHeader(nsHttp::Content_Encoding, val))) {
+        mContentEncoding = val;
     }
-    val = head->PeekHeader(nsHttp::Transfer_Encoding);
-    if (val) {
-        mTransferEncoding.Assign(val);
+    if (NS_SUCCEEDED(head->GetHeader(nsHttp::Transfer_Encoding, val))) {
+        mTransferEncoding = val;
     }
 
     // We can only restart with any confidence if we have a stored etag or
     // last-modified header
     if (mETag.IsEmpty() && mLastModified.IsEmpty()) {
         return;
     }
 
--- a/netwerk/protocol/http/nsIHttpChannel.idl
+++ b/netwerk/protocol/http/nsIHttpChannel.idl
@@ -326,16 +326,18 @@ interface nsIHttpChannel : nsIChannel
      *        contents of |aValue|.
      *
      * If aValue is empty and aMerge is false, the header will be cleared.
      *
      * @throws NS_ERROR_NOT_AVAILABLE if called before the response
      *         has been received (before onStartRequest).
      * @throws NS_ERROR_ILLEGAL_VALUE if changing the value of this response
      *         header is not allowed.
+     * @throws NS_ERROR_FAILURE if called during visitResponseHeaders,
+     *         VisitOriginalResponseHeaders or getOriginalResponseHeader.
      */
     void setResponseHeader(in ACString header,
                            in ACString value,
                            in boolean merge);
 
     /**
      * Call this method to visit all response headers.  Calling
      * setResponseHeader while visiting response headers has undefined
--- a/netwerk/protocol/rtsp/rtsp/RTSPConnectionHandler.h
+++ b/netwerk/protocol/rtsp/rtsp/RTSPConnectionHandler.h
@@ -993,17 +993,17 @@ struct RtspConnectionHandler : public AH
                 size_t trackIndex;
                 msg->findSize("trackIndex", &trackIndex);
                 TrackInfo *track = &mTracks.editItemAt(trackIndex);
                 if (!track) {
                   break;
                 }
 
                 if (track->mNumAccessUnitsReceiveds == 0) {
-                    if (gIOService->IsOffline()) {
+                    if (mozilla::net::gIOService->IsOffline()) {
                         LOGI("stream ended? aborting.");
                         disconnect();
                         break;
                     }
                     sp<AMessage> endStreamMsg = new AMessage(kWhatEndOfStream, id());
                     endStreamMsg->setSize("trackIndex", trackIndex);
                     endStreamMsg->post();
                     break;
--- a/netwerk/streamconv/converters/mozTXTToHTMLConv.cpp
+++ b/netwerk/streamconv/converters/mozTXTToHTMLConv.cpp
@@ -1223,62 +1223,68 @@ mozTXTToHTMLConv::ScanHTML(nsString& aIn
 #ifdef DEBUG_BenB_Perf
   PRTime parsing_start = PR_IntervalNow();
 #endif
 
   // Look for simple entities not included in a tags and scan them.
   // Skip all tags ("<[...]>") and content in an a link tag ("<a [...]</a>"),
   // comment tag ("<!--[...]-->"), style tag, script tag or head tag.
   // Unescape the rest (text between tags) and pass it to ScanTXT.
+  nsAutoCString canFollow(" \f\n\r\t>");
   for (int32_t i = 0; i < lengthOfInString;)
   {
     if (aInString[i] == '<')  // html tag
     {
       int32_t start = i;
-      if (Substring(aInString, i + 1, 2).LowerCaseEqualsASCII("a "))
+      if (i + 2 < lengthOfInString &&
+          nsCRT::ToLower(aInString[i + 1]) == 'a' &&
+          canFollow.FindChar(aInString[i + 2]) != kNotFound)
            // if a tag, skip until </a>.
-           // Make sure there's a space after, not to match "abbr".
+           // Make sure there's a white-space character after, not to match "abbr".
       {
         i = aInString.Find("</a>", true, i);
         if (i == kNotFound)
           i = lengthOfInString;
         else
           i += 4;
       }
       else if (Substring(aInString, i + 1, 3).LowerCaseEqualsASCII("!--"))
           // if out-commended code, skip until -->
       {
         i = aInString.Find("-->", false, i);
         if (i == kNotFound)
           i = lengthOfInString;
         else
           i += 3;
       }
-      else if (Substring(aInString, i + 1, 5).LowerCaseEqualsASCII("style") &&
-               (aInString.CharAt(i + 6) == ' ' || aInString.CharAt(i + 6) == '>'))
+      else if (i + 6 < lengthOfInString &&
+      Substring(aInString, i + 1, 5).LowerCaseEqualsASCII("style") &&
+               canFollow.FindChar(aInString[i + 6]) != kNotFound)
            // if style tag, skip until </style>
       {
         i = aInString.Find("</style>", true, i);
         if (i == kNotFound)
           i = lengthOfInString;
         else
           i += 8;
       }
-      else if (Substring(aInString, i + 1, 6).LowerCaseEqualsASCII("script") &&
-               (aInString.CharAt(i + 7) == ' ' || aInString.CharAt(i + 7) == '>'))
+      else if (i + 7 < lengthOfInString &&
+               Substring(aInString, i + 1, 6).LowerCaseEqualsASCII("script") &&
+               canFollow.FindChar(aInString[i + 7]) != kNotFound)
            // if script tag, skip until </script>
       {
         i = aInString.Find("</script>", true, i);
         if (i == kNotFound)
           i = lengthOfInString;
         else
           i += 9;
       }
-      else if (Substring(aInString, i + 1, 4).LowerCaseEqualsASCII("head") &&
-               (aInString.CharAt(i + 5) == ' ' || aInString.CharAt(i + 5) == '>'))
+      else if (i + 5 < lengthOfInString &&
+               Substring(aInString, i + 1, 4).LowerCaseEqualsASCII("head") &&
+               canFollow.FindChar(aInString[i + 5]) != kNotFound)
            // if head tag, skip until </head>
            // Make sure not to match <header>.
       {
         i = aInString.Find("</head>", true, i);
         if (i == kNotFound)
           i = lengthOfInString;
         else
           i += 7;
--- a/netwerk/streamconv/converters/nsMultiMixedConv.cpp
+++ b/netwerk/streamconv/converters/nsMultiMixedConv.cpp
@@ -416,17 +416,17 @@ nsPartChannel::GetResponseHead()
     return mResponseHead;
 }
 
 NS_IMETHODIMP
 nsPartChannel::VisitResponseHeaders(nsIHttpHeaderVisitor *visitor)
 {
     if (!mResponseHead)
         return NS_ERROR_NOT_AVAILABLE;
-    return mResponseHead->Headers().VisitHeaders(visitor,
+    return mResponseHead->VisitHeaders(visitor,
         mozilla::net::nsHttpHeaderArray::eFilterResponse);
 }
 
 //
 // nsIByteRangeRequest implementation...
 //
 
 NS_IMETHODIMP 
new file mode 100644
--- /dev/null
+++ b/netwerk/test/mochitests/file_cookie_access.html
@@ -0,0 +1,24 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="UTF-8">
+</head>
+<body>
+
+<pre id="test">
+<script type="application/javascript">
+  var old_cookie = document.cookie;
+  document.cookie = location.search.substring(1);
+  var new_cookie = document.cookie;
+  // Post back the previous cookie, and the newly set cookie.
+  window.opener.postMessage(old_cookie+"-"+new_cookie, "http://mochi.test:8888");
+</script>
+</pre>
+
+</body>
+</html>
--- a/netwerk/test/mochitests/mochitest.ini
+++ b/netwerk/test/mochitests/mochitest.ini
@@ -9,24 +9,26 @@ support-files =
   user_agent_update.sjs
   web_packaged_app.sjs
   file_loadinfo_redirectchain.sjs
   redirect_idn.html^headers^
   redirect_idn.html
   empty.html
   redirect.sjs
   !/dom/apps/tests/file_app.sjs
+  file_cookie_access.html
 
 [test_arraybufferinputstream.html]
 [test_partially_cached_content.html]
 [test_rel_preconnect.html]
 [test_uri_scheme.html]
 [test_user_agent_overrides.html]
 [test_user_agent_updates.html]
 [test_user_agent_updates_reset.html]
 [test_viewsource_unlinkable.html]
 [test_xhr_method_case.html]
 [test_web_packaged_app.html]
 skip-if = buildapp != 'mulet'
 [test_loadinfo_redirectchain.html]
 skip-if = buildapp == 'b2g' #no ssl support
 [test_idn_redirect.html]
 [test_redirect_ref.html]
+[test_cookie_access.html]
new file mode 100644
--- /dev/null
+++ b/netwerk/test/mochitests/test_cookie_access.html
@@ -0,0 +1,96 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=219157
+-->
+<head>
+  <meta charset="UTF-8">
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+var URI = "http://sub1.test1.example.com/tests/netwerk/test/mochitests/file_cookie_access.html";
+
+const chromeScript = SpecialPowers.loadChromeScript(_ => {
+  Components.utils.import("resource://gre/modules/Services.jsm");
+  var URI = "http://sub1.test1.example.com/tests/netwerk/test/mochitests/file_cookie_access.html";
+  var cp = Components.classes["@mozilla.org/cookie/permission;1"]
+                     .getService(Components.interfaces.nsICookiePermission);
+  var uriObj = Services.io.newURI(URI, null, null);
+
+  addMessageListener("setAccess", function(allow) { cp.setAccess(uriObj, allow ? cp.ACCESS_ALLOW : cp.ACCESS_DENY); });
+});
+
+var set_cookie = [undefined,     // step 0: there is no step 0
+                  "",            // step 1: set the cookie to ""
+                  "?c00k1e_2",   // step 2: will never be set. Even steps don' have access.
+                  "?c00k1e_3" ,  // step 3: set the cookie to this
+                  "?c00k1e_4" ,  // step 4: will never be set. Even steps don' have access.
+                  "?c00k1e_5" ,  // step 5: set the cookie to this
+                  "?c00k1e_6" ,  // step 6: will never be set. Even steps don' have access.
+                  "",            // step 7: set the cookie to "" - as a cleanup.
+                  ""];           // step 8: will never be set. Even steps don' have access.
+var step = 1;
+function start() {
+  chromeScript.sendSyncMessage("setAccess", step % 2 == 1);
+  var url = URI+set_cookie[step];
+  subwindow = window.open(url);
+}
+
+window.addEventListener("message", receiveMessage, false);
+
+start();
+
+function receiveMessage(event) {
+    switch (step) {
+      // Before: cookie="_WHAT_EVER_". After: cookie="". CAN SET COOKIE
+      case 1: is(event.data.substring(event.data.indexOf('-')),
+                 /* any coookie + */"-", "Step "+step+" - Got expected cookie"); break;
+
+      // Before: cookie="". After: cookie="c00k1e_2". CAN'T SET COOKIE
+      case 2: is(event.data, "-", "Step "+step+" - Got expected cookie"); break;
+
+      // Before: cookie="". After: cookie="c00k1e_3". CAN SET COOKIE
+      case 3: is(event.data, "-c00k1e_3", "Step "+step+" - Got expected cookie"); break;
+
+      // Before: cookie="c00k1e_3". After: cookie="c00k1e_3". CAN'T SET COOKIE
+      case 4: is(event.data, "c00k1e_3-c00k1e_3", "Step "+step+" - Got expected cookie"); break;
+
+      // Before: cookie="c00k1e_3". After: cookie="c00k1e_5". CAN SET COOKIE
+      case 5: is(event.data, "c00k1e_3-c00k1e_5", "Step "+step+" - Got expected cookie"); break;
+
+      // Before: cookie="c00k1e_5". After: cookie="c00k1e_5". CAN'T SET COOKIE
+      case 6: is(event.data, "c00k1e_5-c00k1e_5", "Step "+step+" - Got expected cookie"); break;
+
+      // Before: cookie="c00k1e_5". After: cookie="". CAN SET COOKIE
+      case 7: is(event.data, "c00k1e_5-", "Step "+step+" - Got expected cookie"); break;
+
+      // Before: cookie="". After: cookie="". CAN'T SET COOKIE
+      case 8: is(event.data, "-", "Step "+step+" - Got expected cookie"); break;
+
+      default: ok(false, "should not reach this step");
+    }
+    subwindow.close();
+    step++;
+    if (step == 9) {
+      SimpleTest.finish();
+      return;
+    }
+    start();
+}
+
+</script>
+</pre>
+
+</body>
+</html>
--- a/netwerk/test/unit/test_standardurl.js
+++ b/netwerk/test/unit/test_standardurl.js
@@ -341,8 +341,54 @@ add_test(function test_backslashReplacem
 
   url = stringToURL("http:\\\\test.com\\example.org/path\\to/file");
   do_check_eq(url.spec, "http://test.com/example.org/path/to/file");
   do_check_eq(url.host, "test.com");
   do_check_eq(url.path, "/example.org/path/to/file");
 
   run_next_test();
 });
+
+add_test(function test_trim_C0_and_space()
+{
+  var url = stringToURL("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f http://example.com/ \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ");
+  do_check_eq(url.spec, "http://example.com/");
+  url.spec = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f http://test.com/ \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ";
+  do_check_eq(url.spec, "http://test.com/");
+  Assert.throws(() => { url.spec = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19 "; }, "set empty spec");
+  run_next_test();
+});
+
+// This tests that C0-and-space characters in the path, query and ref are
+// percent encoded.
+add_test(function test_encode_C0_and_space()
+{
+  function toHex(d) {
+    var hex = d.toString(16);
+    if (hex.length == 1)
+      hex = "0"+hex;
+    return hex.toUpperCase();
+  }
+
+  for (var i=0x0; i<=0x20; i++) {
+    // These characters get filtered - they are not encoded.
+    if (String.fromCharCode(i) == '\r' ||
+        String.fromCharCode(i) == '\n' ||
+        String.fromCharCode(i) == '\t') {
+      continue;
+    }
+    var url = stringToURL("http://example.com/pa" + String.fromCharCode(i) + "th?qu" + String.fromCharCode(i) +"ery#ha" + String.fromCharCode(i) + "sh");
+    do_check_eq(url.spec, "http://example.com/pa%" + toHex(i) + "th?qu%" + toHex(i) + "ery#ha%" + toHex(i) + "sh");
+  }
+
+  // Additionally, we need to check the setters.
+  var url = stringToURL("http://example.com/path?query#hash");
+  url.filePath = "pa\0th";
+  do_check_eq(url.spec, "http://example.com/pa%00th?query#hash");
+  url.query = "qu\0ery";
+  do_check_eq(url.spec, "http://example.com/pa%00th?qu%00ery#hash");
+  url.ref = "ha\0sh";
+  do_check_eq(url.spec, "http://example.com/pa%00th?qu%00ery#ha%00sh");
+  url.fileName = "fi\0le.name";
+  do_check_eq(url.spec, "http://example.com/fi%00le.name?qu%00ery#ha%00sh");
+
+  run_next_test();
+});
--- a/security/manager/ssl/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/nsNSSIOLayer.cpp
@@ -1047,16 +1047,17 @@ uint32_t tlsIntoleranceTelemetryBucket(P
     case SSL_ERROR_ILLEGAL_PARAMETER_ALERT: return 6;
     case SSL_ERROR_NO_CYPHER_OVERLAP: return 7;
     case SSL_ERROR_UNSUPPORTED_VERSION: return 10;
     case SSL_ERROR_PROTOCOL_VERSION_ALERT: return 11;
     case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE: return 13;
     case SSL_ERROR_DECODE_ERROR_ALERT: return 14;
     case PR_CONNECT_RESET_ERROR: return 16;
     case PR_END_OF_FILE_ERROR: return 17;
+    case SSL_ERROR_INTERNAL_ERROR_ALERT: return 18;
     default: return 0;
   }
 }
 
 bool
 retryDueToTLSIntolerance(PRErrorCode err, nsNSSSocketInfo* socketInfo)
 {
   // This function is supposed to decide which error codes should
@@ -1662,16 +1663,19 @@ nsSSLIOLayerHelpers::loadVersionFallback
 {
   // see nsNSSComponent::setEnabledTLSVersions for pref handling rules
   uint32_t limit = Preferences::GetUint("security.tls.version.fallback-limit",
                                         3); // 3 = TLS 1.2
   SSLVersionRange defaults = { SSL_LIBRARY_VERSION_TLS_1_2,
                                SSL_LIBRARY_VERSION_TLS_1_2 };
   SSLVersionRange filledInRange;
   nsNSSComponent::FillTLSVersionRange(filledInRange, limit, limit, defaults);
+  if (filledInRange.max < SSL_LIBRARY_VERSION_TLS_1_2) {
+    filledInRange.max = SSL_LIBRARY_VERSION_TLS_1_2;
+  }
 
   mVersionFallbackLimit = filledInRange.max;
 }
 
 void
 nsSSLIOLayerHelpers::clearStoredData()
 {
   MutexAutoLock lock(mutex);
@@ -2538,18 +2542,21 @@ nsSSLIOLayerSetOptions(PRFileDesc* fd, b
     nsNSSComponent::UseWeakCiphersOnSocket(fd);
   }
 
   // when adjustForTLSIntolerance tweaks the maximum version downward,
   // we tell the server using this SCSV so they can detect a downgrade attack
   if (range.max < maxEnabledVersion) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
            ("[%p] nsSSLIOLayerSetOptions: enabling TLS_FALLBACK_SCSV\n", fd));
-    if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_FALLBACK_SCSV, true)) {
-      return NS_ERROR_FAILURE;
+    // Some servers will choke if we send the fallback SCSV with TLS 1.2.
+    if (range.max < SSL_LIBRARY_VERSION_TLS_1_2) {
+      if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_FALLBACK_SCSV, true)) {
+        return NS_ERROR_FAILURE;
+      }
     }
     // tell NSS the max enabled version to make anti-downgrade effective
     if (SECSuccess != SSL_SetDowngradeCheckVersion(fd, maxEnabledVersion)) {
       return NS_ERROR_FAILURE;
     }
   }
 
   bool enabled = infoObject->SharedState().IsOCSPStaplingEnabled();
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
@@ -106,31 +106,29 @@ SandboxBroker::SetSecurityLevelForConten
     accessTokenLevel = sandbox::USER_LOCKDOWN;
     initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
     delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_UNTRUSTED;
   } else if (aSandboxLevel >= 10) {
     jobLevel = sandbox::JOB_RESTRICTED;
     accessTokenLevel = sandbox::USER_LIMITED;
     initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
     delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
-  } else if (aSandboxLevel == 2) {
+  } else if (aSandboxLevel >= 2) {
     jobLevel = sandbox::JOB_INTERACTIVE;
     accessTokenLevel = sandbox::USER_INTERACTIVE;
     initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
     delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   } else if (aSandboxLevel == 1) {
     jobLevel = sandbox::JOB_NONE;
     accessTokenLevel = sandbox::USER_NON_ADMIN;
     initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
     delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   } else {
-    jobLevel = sandbox::JOB_NONE;
-    accessTokenLevel = sandbox::USER_NON_ADMIN;
-    initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_MEDIUM;
-    delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_MEDIUM;
+    MOZ_ASSERT_UNREACHABLE("Should not be called with aSandboxLevel < 1");
+    return false;
   }
 
   sandbox::ResultCode result = mPolicy->SetJobLevel(jobLevel,
                                                     0 /* ui_exceptions */);
   bool ret = (sandbox::SBOX_ALL_OK == result);
 
   result = mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
                                   accessTokenLevel);
@@ -141,34 +139,32 @@ SandboxBroker::SetSecurityLevelForConten
   result = mPolicy->SetDelayedIntegrityLevel(delayedIntegrityLevel);
   ret = ret && (sandbox::SBOX_ALL_OK == result);
 
   if (aSandboxLevel > 2) {
     result = mPolicy->SetAlternateDesktop(true);
     ret = ret && (sandbox::SBOX_ALL_OK == result);
   }
 
-  if (aSandboxLevel >= 1) {
-    sandbox::MitigationFlags mitigations =
-      sandbox::MITIGATION_BOTTOM_UP_ASLR |
-      sandbox::MITIGATION_HEAP_TERMINATE |
-      sandbox::MITIGATION_SEHOP |
-      sandbox::MITIGATION_DEP_NO_ATL_THUNK |
-      sandbox::MITIGATION_DEP;
+  sandbox::MitigationFlags mitigations =
+    sandbox::MITIGATION_BOTTOM_UP_ASLR |
+    sandbox::MITIGATION_HEAP_TERMINATE |
+    sandbox::MITIGATION_SEHOP |
+    sandbox::MITIGATION_DEP_NO_ATL_THUNK |
+    sandbox::MITIGATION_DEP;
 
-    result = mPolicy->SetProcessMitigations(mitigations);
-    ret = ret && (sandbox::SBOX_ALL_OK == result);
+  result = mPolicy->SetProcessMitigations(mitigations);
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
 
-    mitigations =
-      sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
-      sandbox::MITIGATION_DLL_SEARCH_ORDER;
+  mitigations =
+    sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
+    sandbox::MITIGATION_DLL_SEARCH_ORDER;
 
-    result = mPolicy->SetDelayedProcessMitigations(mitigations);
-    ret = ret && (sandbox::SBOX_ALL_OK == result);
-  }
+  result = mPolicy->SetDelayedProcessMitigations(mitigations);
+  ret = ret && (sandbox::SBOX_ALL_OK == result);
 
   // Add the policy for the client side of a pipe. It is just a file
   // in the \pipe\ namespace. We restrict it to pipes that start with
   // "chrome." so the sandboxed process cannot connect to system services.
   result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
                             sandbox::TargetPolicy::FILES_ALLOW_ANY,
                             L"\\??\\pipe\\chrome.*");
   ret = ret && (sandbox::SBOX_ALL_OK == result);
--- a/testing/docker/image_builder/VERSION
+++ b/testing/docker/image_builder/VERSION
@@ -1,1 +1,1 @@
-0.1.4
+0.1.5
--- a/testing/docker/image_builder/bin/build_image.sh
+++ b/testing/docker/image_builder/bin/build_image.sh
@@ -16,17 +16,17 @@ raise_error() {
 # Ensure that the PROJECT is specified so the image can be indexed