Merge autoland to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Mon, 20 Feb 2017 20:26:48 -0800
changeset 372908 276bd9ed3dbf85f4a6dac67df54a5f2631804de5
parent 372877 d0462b0948e0b1147dcce615bddcc46379bdadb2 (current diff)
parent 372907 ddf86248e3013a84b69f4890f1c2969c731edfd0 (diff)
child 372951 d84beb192e57e26846c82d3df3599381f4663792
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone54.0a1
Merge autoland to m-c, a=merge
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1530,18 +1530,19 @@ pref("browser.esedbreader.loglevel", "Er
 pref("browser.laterrun.enabled", false);
 
 pref("browser.migrate.automigrate.enabled", false);
 // 4 here means the suggestion notification will be automatically
 // hidden the 4th day, so it will actually be shown on 3 different days.
 pref("browser.migrate.automigrate.daysToOfferUndo", 4);
 pref("browser.migrate.automigrate.ui.enabled", true);
 
-pref("browser.migrate.chrome.history.limit", 0);
-pref("browser.migrate.chrome.history.maxAgeInDays", 0);
+// See comments in bug 1340115 on how we got to these numbers.
+pref("browser.migrate.chrome.history.limit", 2000);
+pref("browser.migrate.chrome.history.maxAgeInDays", 180);
 
 // Enable browser frames for use on desktop.  Only exposed to chrome callers.
 pref("dom.mozBrowserFramesEnabled", true);
 
 pref("extensions.pocket.enabled", true);
 
 pref("signon.schemeUpgrades", true);
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -6458,59 +6458,62 @@ var MailIntegration = {
          .getService(Ci.nsIExternalProtocolService);
     if (extProtocolSvc)
       extProtocolSvc.loadUrl(aURL);
   }
 };
 
 function BrowserOpenAddonsMgr(aView) {
   return new Promise(resolve => {
-    if (aView) {
-      let emWindow;
-      let browserWindow;
-
-      var receivePong = function(aSubject, aTopic, aData) {
-        let browserWin = aSubject.QueryInterface(Ci.nsIInterfaceRequestor)
-                                 .getInterface(Ci.nsIWebNavigation)
-                                 .QueryInterface(Ci.nsIDocShellTreeItem)
-                                 .rootTreeItem
-                                 .QueryInterface(Ci.nsIInterfaceRequestor)
-                                 .getInterface(Ci.nsIDOMWindow);
-        if (!emWindow || browserWin == window /* favor the current window */) {
-          emWindow = aSubject;
-          browserWindow = browserWin;
-        }
+    let emWindow;
+    let browserWindow;
+
+    var receivePong = function(aSubject, aTopic, aData) {
+      let browserWin = aSubject.QueryInterface(Ci.nsIInterfaceRequestor)
+                               .getInterface(Ci.nsIWebNavigation)
+                               .QueryInterface(Ci.nsIDocShellTreeItem)
+                               .rootTreeItem
+                               .QueryInterface(Ci.nsIInterfaceRequestor)
+                               .getInterface(Ci.nsIDOMWindow);
+      if (!emWindow || browserWin == window /* favor the current window */) {
+        emWindow = aSubject;
+        browserWindow = browserWin;
       }
-      Services.obs.addObserver(receivePong, "EM-pong", false);
-      Services.obs.notifyObservers(null, "EM-ping", "");
-      Services.obs.removeObserver(receivePong, "EM-pong");
-
-      if (emWindow) {
+    }
+    Services.obs.addObserver(receivePong, "EM-pong", false);
+    Services.obs.notifyObservers(null, "EM-ping", "");
+    Services.obs.removeObserver(receivePong, "EM-pong");
+
+    if (emWindow) {
+      if (aView) {
         emWindow.loadView(aView);
-        browserWindow.gBrowser.selectedTab =
-          browserWindow.gBrowser._getTabForContentWindow(emWindow);
-        emWindow.focus();
-        resolve(emWindow);
-        return;
       }
-    }
-
-    switchToTabHavingURI("about:addons", true);
-
-    if (aView) {
-      // This must be a new load, else the ping/pong would have
-      // found the window above.
-      Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
-        Services.obs.removeObserver(observer, aTopic);
+      browserWindow.gBrowser.selectedTab =
+        browserWindow.gBrowser._getTabForContentWindow(emWindow);
+      emWindow.focus();
+      resolve(emWindow);
+      return;
+    }
+
+    // This must be a new load, else the ping/pong would have
+    // found the window above.
+    let whereToOpen = (window.gBrowser && isTabEmpty(gBrowser.selectedTab)) ?
+                      "current" :
+                      "tab";
+    openUILinkIn("about:addons", whereToOpen);
+
+    Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
+      Services.obs.removeObserver(observer, aTopic);
+      if (aView) {
         aSubject.loadView(aView);
-        resolve(aSubject);
-      }, "EM-loaded", false);
-    } else {
-      resolve();
-    }
+      }
+      aSubject.QueryInterface(Ci.nsIDOMWindow);
+      aSubject.focus();
+      resolve(aSubject);
+    }, "EM-loaded", false);
   });
 }
 
 function AddKeywordForSearchField() {
   let mm = gBrowser.selectedBrowser.messageManager;
 
   let onMessage = (message) => {
     mm.removeMessageListener("ContextMenu:SearchFieldBookmarkData:Result", onMessage);
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4989,37 +4989,40 @@ nsDocShell::DisplayLoadError(nsresult aE
       if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) {
         error.AssignLiteral("nssBadCert");
 
         // If this is an HTTP Strict Transport Security host or a pinned host
         // and the certificate is bad, don't allow overrides (RFC 6797 section
         // 12.1, HPKP draft spec section 2.6).
         uint32_t flags =
           UsePrivateBrowsing() ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
+        OriginAttributes originAttributes;
+        originAttributes.Inherit(mOriginAttributes);
         bool isStsHost = false;
         bool isPinnedHost = false;
         if (XRE_IsParentProcess()) {
           nsCOMPtr<nsISiteSecurityService> sss =
             do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
           NS_ENSURE_SUCCESS(rv, rv);
           rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI,
-                                flags, nullptr, &isStsHost);
+                                flags, originAttributes, nullptr, &isStsHost);
           NS_ENSURE_SUCCESS(rv, rv);
           rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HPKP, aURI,
-                                flags, nullptr, &isPinnedHost);
+                                flags, originAttributes, nullptr,
+                                &isPinnedHost);
           NS_ENSURE_SUCCESS(rv, rv);
         } else {
           mozilla::dom::ContentChild* cc =
             mozilla::dom::ContentChild::GetSingleton();
           mozilla::ipc::URIParams uri;
           SerializeURI(aURI, uri);
           cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, flags,
-                              &isStsHost);
+                              originAttributes, &isStsHost);
           cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HPKP, uri, flags,
-                              &isPinnedHost);
+                              originAttributes, &isPinnedHost);
         }
 
         if (Preferences::GetBool(
               "browser.xul.error_pages.expert_bad_cert", false)) {
           cssClass.AssignLiteral("expertBadCert");
         }
 
         // HSTS/pinning takes precedence over the expert bad cert pref. We
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -1957,16 +1957,19 @@ GK_ATOM(ondevicelight, "ondevicelight")
 
 // Audio channel events
 GK_ATOM(onmozinterruptbegin, "onmozinterruptbegin")
 GK_ATOM(onmozinterruptend, "onmozinterruptend")
 
 // MediaDevices device change event
 GK_ATOM(ondevicechange, "ondevicechange")
 
+// HTML element attributes that only exposed to XBL and chrome content
+GK_ATOM(mozinputrangeignorepreventdefault, "mozinputrangeignorepreventdefault")
+
 //---------------------------------------------------------------------------
 // Special atoms
 //---------------------------------------------------------------------------
 
 // Node types
 GK_ATOM(cdataTagName, "#cdata-section")
 GK_ATOM(commentTagName, "#comment")
 GK_ATOM(documentNodeName, "#document")
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -4919,17 +4919,18 @@ HTMLInputElement::PostHandleEvent(EventC
   return MaybeInitPickers(aVisitor);
 }
 
 void
 HTMLInputElement::PostHandleEventForRangeThumb(EventChainPostVisitor& aVisitor)
 {
   MOZ_ASSERT(mType == NS_FORM_INPUT_RANGE);
 
-  if (nsEventStatus_eConsumeNoDefault == aVisitor.mEventStatus ||
+  if ((nsEventStatus_eConsumeNoDefault == aVisitor.mEventStatus &&
+       !MozInputRangeIgnorePreventDefault()) ||
       !(aVisitor.mEvent->mClass == eMouseEventClass ||
         aVisitor.mEvent->mClass == eTouchEventClass ||
         aVisitor.mEvent->mClass == eKeyboardEventClass)) {
     return;
   }
 
   nsRangeFrame* rangeFrame = do_QueryFrame(GetPrimaryFrame());
   if (!rangeFrame && mIsDraggingRange) {
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -777,16 +777,22 @@ public:
   int32_t InputTextLength(CallerType aCallerType);
 
   void MozGetFileNameArray(nsTArray<nsString>& aFileNames, ErrorResult& aRv);
 
   void MozSetFileNameArray(const Sequence< nsString >& aFileNames, ErrorResult& aRv);
   void MozSetFileArray(const Sequence<OwningNonNull<File>>& aFiles);
   void MozSetDirectory(const nsAString& aDirectoryPath, ErrorResult& aRv);
 
+  bool MozInputRangeIgnorePreventDefault() const
+  {
+    return (IsInChromeDocument() || IsInNativeAnonymousSubtree()) &&
+      GetBoolAttr(nsGkAtoms::mozinputrangeignorepreventdefault);
+  }
+
   /*
    * The following functions are called from datetime picker to let input box
    * know the current state of the picker or to update the input box on changes.
    */
   void GetDateTimeInputBoxValue(DateTimeValue& aValue);
   void UpdateDateTimeInputBox(const DateTimeValue& aValue);
   void SetDateTimePickerState(bool aOpen);
 
@@ -1463,17 +1469,17 @@ protected:
   bool IsPopupBlocked() const;
 
   GetFilesHelper* GetOrCreateGetFilesHelper(bool aRecursiveFlag,
                                             ErrorResult& aRv);
 
   void ClearGetFilesHelpers();
 
   /**
-   * nsINode::SetMayBeApzAware() will be invoked in this function if necessary 
+   * nsINode::SetMayBeApzAware() will be invoked in this function if necessary
    * to prevent default action of APZC so that we can increase/decrease the
    * value of this InputElement when mouse wheel event comes without scrolling
    * the page.
    *
    * SetMayBeApzAware() will set flag MayBeApzAware which is checked by apzc to
    * decide whether to add this element into its dispatch-to-content region.
    */
   void UpdateApzAwareFlag();
--- a/dom/html/test/forms/chrome.ini
+++ b/dom/html/test/forms/chrome.ini
@@ -1,5 +1,6 @@
 [DEFAULT]
 support-files =
   submit_invalid_file.sjs
 [test_autocompleteinfo.html]
 [test_submit_invalid_file.html]
+[test_input_range_mozinputrangeignorepreventdefault_chrome.html]
--- a/dom/html/test/forms/mochitest.ini
+++ b/dom/html/test/forms/mochitest.ini
@@ -55,16 +55,17 @@ skip-if = os == "android"
 skip-if = os == "android"
 [test_input_number_validation.html]
 # We don't build ICU for Firefox for Android:
 skip-if = os == "android"
 [test_input_number_focus.html]
 [test_input_range_attr_order.html]
 [test_input_range_key_events.html]
 [test_input_range_mouse_and_touch_events.html]
+[test_input_range_mozinputrangeignorepreventdefault.html]
 [test_input_range_rounding.html]
 [test_input_sanitization.html]
 [test_input_textarea_set_value_no_scroll.html]
 [test_input_time_key_events.html]
 skip-if = os == "android"
 [test_input_types_pref.html]
 [test_input_typing_sanitization.html]
 [test_input_untrusted_key_events.html]
new file mode 100644
--- /dev/null
+++ b/dom/html/test/forms/test_input_range_mozinputrangeignorepreventdefault.html
@@ -0,0 +1,94 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1338961
+-->
+<head>
+  <title>Test mouse and touch events for range</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <style>
+    /* synthesizeMouse and synthesizeFunc uses getBoundingClientRect. We set
+     * the following properties to avoid fractional values in the rect returned
+     * by getBoundingClientRect in order to avoid rounding that would occur
+     * when event coordinates are internally converted to be relative to the
+     * top-left of the element. (Such rounding would make it difficult to
+     * predict exactly what value the input should take on for events at
+     * certain coordinates.)
+     */
+    input { margin: 0 ! important; width: 200px ! important; }
+  </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1338961">Mozilla Bug 1338961</a>
+<p id="display"></p>
+<div id="content">
+  <input id="range" type="range" mozinputrangeignorepreventdefault="true">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/**
+ * Test for Bug 1338961
+ * This test ensures mozinputrangeignorepreventdefault has no effect in
+ * content html.
+ **/
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+  test(synthesizeMouse, "click", "mousedown", "mousemove", "mouseup");
+  test(synthesizeTouch, "tap", "touchstart", "touchmove", "touchend");
+  SimpleTest.finish();
+});
+
+function flush() {
+  // Flush style, specifically to flush the 'direction' property so that the
+  // browser uses the new value for thumb positioning.
+  var flush = document.body.clientWidth;
+}
+
+const QUARTER_OF_RANGE = "25";
+
+function test(synthesizeFunc, clickOrTap, startName, moveName, endName) {
+  var elem = document.getElementById("range");
+  elem.focus();
+  flush();
+
+  var width = parseFloat(window.getComputedStyle(elem).width);
+  var height = parseFloat(window.getComputedStyle(elem).height);
+  var borderLeft = parseFloat(window.getComputedStyle(elem).borderLeftWidth);
+  var borderTop = parseFloat(window.getComputedStyle(elem).borderTopWidth);
+  var paddingLeft = parseFloat(window.getComputedStyle(elem).paddingLeft);
+  var paddingTop = parseFloat(window.getComputedStyle(elem).paddingTop);
+
+  // Extrema for mouse/touch events:
+  var midY = height / 2 + borderTop + paddingTop;
+  var minX = borderLeft + paddingLeft;
+  var midX = minX + width / 2;
+  var maxX = minX + width;
+
+  function preventDefault(e) {
+    e.preventDefault();
+  }
+
+  // Test that preventDefault() works:
+  elem.value = QUARTER_OF_RANGE;
+  elem.addEventListener(startName, preventDefault);
+  synthesizeFunc(elem, midX, midY, {});
+  is(elem.value, QUARTER_OF_RANGE, "Test that preventDefault() works");
+  elem.removeEventListener(startName, preventDefault);
+
+  // Test that preventDefault() on the parent node works:
+  elem.value = QUARTER_OF_RANGE;
+  elem.parentNode.addEventListener(startName, preventDefault);
+  synthesizeFunc(elem, midX, midY, {});
+  is(elem.value, QUARTER_OF_RANGE, "Test that preventDefault() on the parent node works");
+  elem.parentNode.removeEventListener(startName, preventDefault);
+}
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/html/test/forms/test_input_range_mozinputrangeignorepreventdefault_chrome.html
@@ -0,0 +1,95 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1338961
+-->
+<head>
+  <title>Test mouse and touch events for range</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <style>
+    /* synthesizeMouse and synthesizeFunc uses getBoundingClientRect. We set
+     * the following properties to avoid fractional values in the rect returned
+     * by getBoundingClientRect in order to avoid rounding that would occur
+     * when event coordinates are internally converted to be relative to the
+     * top-left of the element. (Such rounding would make it difficult to
+     * predict exactly what value the input should take on for events at
+     * certain coordinates.)
+     */
+    input { margin: 0 ! important; width: 200px ! important; }
+  </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1338961">Mozilla Bug 1338961</a>
+<p id="display"></p>
+<div id="content">
+  <input id="range" type="range" mozinputrangeignorepreventdefault="true">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/**
+ * Test for Bug 1338961
+ * This test ensures mozinputrangeignorepreventdefault has it's desired effect in
+ * chrome html.
+ **/
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+  test(synthesizeMouse, "click", "mousedown", "mousemove", "mouseup");
+  test(synthesizeTouch, "tap", "touchstart", "touchmove", "touchend");
+  SimpleTest.finish();
+});
+
+function flush() {
+  // Flush style, specifically to flush the 'direction' property so that the
+  // browser uses the new value for thumb positioning.
+  var flush = document.body.clientWidth;
+}
+
+const MIDDLE_OF_RANGE = "50";
+const QUARTER_OF_RANGE = "25";
+
+function test(synthesizeFunc, clickOrTap, startName, moveName, endName) {
+  var elem = document.getElementById("range");
+  elem.focus();
+  flush();
+
+  var width = parseFloat(window.getComputedStyle(elem).width);
+  var height = parseFloat(window.getComputedStyle(elem).height);
+  var borderLeft = parseFloat(window.getComputedStyle(elem).borderLeftWidth);
+  var borderTop = parseFloat(window.getComputedStyle(elem).borderTopWidth);
+  var paddingLeft = parseFloat(window.getComputedStyle(elem).paddingLeft);
+  var paddingTop = parseFloat(window.getComputedStyle(elem).paddingTop);
+
+  // Extrema for mouse/touch events:
+  var midY = height / 2 + borderTop + paddingTop;
+  var minX = borderLeft + paddingLeft;
+  var midX = minX + width / 2;
+  var maxX = minX + width;
+
+  function preventDefault(e) {
+    e.preventDefault();
+  }
+
+  // Test that preventDefault() is ignored:
+  elem.value = QUARTER_OF_RANGE;
+  elem.addEventListener(startName, preventDefault);
+  synthesizeFunc(elem, midX, midY, {});
+  is(elem.value, MIDDLE_OF_RANGE, "Test that preventDefault() is ignored");
+  elem.removeEventListener(startName, preventDefault);
+
+  // Test that preventDefault() on the parent node works:
+  elem.value = QUARTER_OF_RANGE;
+  elem.parentNode.addEventListener(startName, preventDefault);
+  synthesizeFunc(elem, midX, midY, {});
+  is(elem.value, MIDDLE_OF_RANGE, "Test that preventDefault() on the parent node is ignored");
+  elem.parentNode.removeEventListener(startName, preventDefault);
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -3365,44 +3365,47 @@ ContentParent::RecvNSSU2FTokenSign(nsTAr
   free(buffer);
   if (NS_FAILED(rv)) {
     return IPC_FAIL_NO_REASON(this);
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-ContentParent::RecvIsSecureURI(const uint32_t& type,
-                               const URIParams& uri,
-                               const uint32_t& flags,
-                               bool* isSecureURI)
+ContentParent::RecvIsSecureURI(const uint32_t& aType,
+                               const URIParams& aURI,
+                               const uint32_t& aFlags,
+                               const OriginAttributes& aOriginAttributes,
+                               bool* aIsSecureURI)
 {
   nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID));
   if (!sss) {
     return IPC_FAIL_NO_REASON(this);
   }
-  nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri);
+  nsCOMPtr<nsIURI> ourURI = DeserializeURI(aURI);
   if (!ourURI) {
     return IPC_FAIL_NO_REASON(this);
   }
-  nsresult rv = sss->IsSecureURI(type, ourURI, flags, nullptr, isSecureURI);
+  nsresult rv = sss->IsSecureURI(aType, ourURI, aFlags, aOriginAttributes, nullptr,
+                                 aIsSecureURI);
   if (NS_FAILED(rv)) {
     return IPC_FAIL_NO_REASON(this);
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-ContentParent::RecvAccumulateMixedContentHSTS(const URIParams& aURI, const bool& aActive, const bool& aHSTSPriming)
+ContentParent::RecvAccumulateMixedContentHSTS(const URIParams& aURI, const bool& aActive, const bool& aHSTSPriming,
+                                              const OriginAttributes& aOriginAttributes)
 {
   nsCOMPtr<nsIURI> ourURI = DeserializeURI(aURI);
   if (!ourURI) {
     return IPC_FAIL_NO_REASON(this);
   }
-  nsMixedContentBlocker::AccumulateMixedContentHSTS(ourURI, aActive, aHSTSPriming);
+  nsMixedContentBlocker::AccumulateMixedContentHSTS(ourURI, aActive, aHSTSPriming, aOriginAttributes);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 ContentParent::RecvLoadURIExternal(const URIParams& uri,
                                    PBrowserParent* windowContext)
 {
   nsCOMPtr<nsIExternalProtocolService> extProtService(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -807,21 +807,24 @@ private:
                                                           nsTArray<uint8_t>* aRegistration) override;
 
   virtual mozilla::ipc::IPCResult RecvNSSU2FTokenSign(nsTArray<uint8_t>&& aApplication,
                                                       nsTArray<uint8_t>&& aChallenge,
                                                       nsTArray<uint8_t>&& aKeyHandle,
                                                       nsTArray<uint8_t>* aSignature) override;
 
   virtual mozilla::ipc::IPCResult RecvIsSecureURI(const uint32_t& aType, const URIParams& aURI,
-                                                  const uint32_t& aFlags, bool* aIsSecureURI) override;
+                                                  const uint32_t& aFlags,
+                                                  const OriginAttributes& aOriginAttributes,
+                                                  bool* aIsSecureURI) override;
 
   virtual mozilla::ipc::IPCResult RecvAccumulateMixedContentHSTS(const URIParams& aURI,
                                                                  const bool& aActive,
-                                                                 const bool& aHSTSPriming) override;
+                                                                 const bool& aHSTSPriming,
+                                                                 const OriginAttributes& aOriginAttributes) override;
 
   virtual bool DeallocPHalParent(PHalParent*) override;
 
   virtual bool
   DeallocPHeapSnapshotTempFileHelperParent(PHeapSnapshotTempFileHelperParent*) override;
 
   virtual PCycleCollectWithLogsParent*
   AllocPCycleCollectWithLogsParent(const bool& aDumpAllTraces,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -791,20 +791,22 @@ parent:
      * |challenge| The Challenge to satisfy in the response.
      * |keyHandle| The Key Handle opaque object to use.
      * |signature| The resulting signature.
      */
     sync NSSU2FTokenSign(uint8_t[] application, uint8_t[] challenge,
                          uint8_t[] keyHandle)
         returns (uint8_t[] signature);
 
-    sync IsSecureURI(uint32_t type, URIParams uri, uint32_t flags)
+    sync IsSecureURI(uint32_t aType, URIParams aURI, uint32_t aFlags,
+                     OriginAttributes aOriginAttributes)
         returns (bool isSecureURI);
 
-    async AccumulateMixedContentHSTS(URIParams uri, bool active, bool hasHSTSPriming);
+    async AccumulateMixedContentHSTS(URIParams aURI, bool aActive, bool aHasHSTSPriming,
+                                     OriginAttributes aOriginAttributes);
 
     nested(inside_cpow) async PHal();
 
     async PHeapSnapshotTempFileHelper();
 
     async PNecko();
 
     async PPrinting();
--- a/dom/media/webm/WebMDemuxer.cpp
+++ b/dom/media/webm/WebMDemuxer.cpp
@@ -561,95 +561,104 @@ WebMDemuxer::GetTrackCrypto(TrackInfo::T
     // crypto.mMode is not used for WebMs
     crypto.mIVSize = WEBM_IV_SIZE;
     crypto.mKeyId = Move(initData);
   }
 
   return crypto;
 }
 
-bool
+nsresult
 WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType,
                            MediaRawDataQueue *aSamples)
 {
   if (mIsMediaSource) {
     // To ensure mLastWebMBlockOffset is properly up to date.
     EnsureUpToDateIndex();
   }
 
-  RefPtr<NesteggPacketHolder> holder(NextPacket(aType));
+  RefPtr<NesteggPacketHolder> holder;
+  nsresult rv = NextPacket(aType, holder);
 
-  if (!holder) {
-    return false;
+  if (NS_FAILED(rv)) {
+    return rv;
   }
 
   int r = 0;
   unsigned int count = 0;
   r = nestegg_packet_count(holder->Packet(), &count);
   if (r == -1) {
-    return false;
+    return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
   }
   int64_t tstamp = holder->Timestamp();
   int64_t duration = holder->Duration();
 
   // The end time of this frame is the start time of the next frame. Fetch
   // the timestamp of the next packet for this track.  If we've reached the
   // end of the resource, use the file's duration as the end time of this
   // video frame.
   int64_t next_tstamp = INT64_MIN;
   if (aType == TrackInfo::kAudioTrack) {
-    RefPtr<NesteggPacketHolder> next_holder(NextPacket(aType));
+    RefPtr<NesteggPacketHolder> next_holder;
+    rv = NextPacket(aType, next_holder);
+    if (NS_FAILED(rv) && rv != NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
+      return rv;
+    }
     if (next_holder) {
       next_tstamp = next_holder->Timestamp();
       PushAudioPacket(next_holder);
     } else if (duration >= 0) {
       next_tstamp = tstamp + duration;
     } else if (!mIsMediaSource
                || (mIsMediaSource && mLastAudioFrameTime.isSome())) {
       next_tstamp = tstamp;
       next_tstamp += tstamp - mLastAudioFrameTime.refOr(0);
     } else {
       PushAudioPacket(holder);
     }
     mLastAudioFrameTime = Some(tstamp);
   } else if (aType == TrackInfo::kVideoTrack) {
-    RefPtr<NesteggPacketHolder> next_holder(NextPacket(aType));
+    RefPtr<NesteggPacketHolder> next_holder;
+    rv = NextPacket(aType, next_holder);
+    if (NS_FAILED(rv) && rv != NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
+      return rv;
+    }
     if (next_holder) {
       next_tstamp = next_holder->Timestamp();
       PushVideoPacket(next_holder);
     } else if (duration >= 0) {
       next_tstamp = tstamp + duration;
     } else if (!mIsMediaSource
                || (mIsMediaSource && mLastVideoFrameTime.isSome())) {
       next_tstamp = tstamp;
       next_tstamp += tstamp - mLastVideoFrameTime.refOr(0);
     } else {
       PushVideoPacket(holder);
     }
     mLastVideoFrameTime = Some(tstamp);
   }
 
   if (mIsMediaSource && next_tstamp == INT64_MIN) {
-    return false;
+    return NS_ERROR_DOM_MEDIA_END_OF_STREAM;
   }
 
   int64_t discardPadding = 0;
   if (aType == TrackInfo::kAudioTrack) {
     (void) nestegg_packet_discard_padding(holder->Packet(), &discardPadding);
   }
 
   int packetEncryption = nestegg_packet_encryption(holder->Packet());
 
   for (uint32_t i = 0; i < count; ++i) {
     unsigned char* data;
     size_t length;
     r = nestegg_packet_data(holder->Packet(), i, &data, &length);
     if (r == -1) {
       WEBM_DEBUG("nestegg_packet_data failed r=%d", r);
-      return false;
+      return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
     }
     unsigned char* alphaData;
     size_t alphaLength = 0;
     // Check packets for alpha information if file has declared alpha frames
     // may be present.
     if (mInfo.mVideo.HasAlpha()) {
       r = nestegg_packet_additional_data(holder->Packet(),
                                          1,
@@ -701,23 +710,23 @@ WebMDemuxer::GetNextPacket(TrackInfo::Tr
 
     WEBM_DEBUG("push sample tstamp: %" PRId64 " next_tstamp: %" PRId64 " length: %" PRIuSIZE " kf: %d",
                tstamp, next_tstamp, length, isKeyframe);
     RefPtr<MediaRawData> sample;
     if (mInfo.mVideo.HasAlpha() && alphaLength != 0) {
       sample = new MediaRawData(data, length, alphaData, alphaLength);
       if ((length && !sample->Data()) || (alphaLength && !sample->AlphaData())) {
         // OOM.
-        return false;
+        return NS_ERROR_OUT_OF_MEMORY;
       }
     } else {
       sample = new MediaRawData(data, length);
       if (length && !sample->Data()) {
         // OOM.
-        return false;
+        return NS_ERROR_OUT_OF_MEMORY;
       }
     }
     sample->mTimecode = tstamp;
     sample->mTime = tstamp;
     sample->mDuration = next_tstamp - tstamp;
     sample->mOffset = holder->Offset();
     sample->mKeyframe = isKeyframe;
     if (discardPadding && i == count - 1) {
@@ -826,79 +835,88 @@ WebMDemuxer::GetNextPacket(TrackInfo::Tr
         }
       }
     }
     if (aType == TrackInfo::kVideoTrack) {
       sample->mTrackInfo = mSharedVideoTrackInfo;
     }
     aSamples->Push(sample);
   }
-  return true;
+  return NS_OK;
 }
 
-RefPtr<NesteggPacketHolder>
-WebMDemuxer::NextPacket(TrackInfo::TrackType aType)
+nsresult
+WebMDemuxer::NextPacket(TrackInfo::TrackType aType,
+                        RefPtr<NesteggPacketHolder>& aPacket)
 {
   bool isVideo = aType == TrackInfo::kVideoTrack;
 
   // Flag to indicate that we do need to playback these types of
   // packets.
   bool hasType = isVideo ? mHasVideo : mHasAudio;
 
   if (!hasType) {
-    return nullptr;
+    return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
   }
 
   // The packet queue for the type that we are interested in.
   WebMPacketQueue &packets = isVideo ? mVideoPackets : mAudioPackets;
 
   if (packets.GetSize() > 0) {
-    return packets.PopFront();
+    aPacket = packets.PopFront();
+    return NS_OK;
   }
 
   // Track we are interested in
   uint32_t ourTrack = isVideo ? mVideoTrack : mAudioTrack;
 
   do {
-    RefPtr<NesteggPacketHolder> holder = DemuxPacket(aType);
+    RefPtr<NesteggPacketHolder> holder;
+    nsresult rv = DemuxPacket(aType, holder);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
     if (!holder) {
-      return nullptr;
+      return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
     }
 
     if (ourTrack == holder->Track()) {
-      return holder;
+      aPacket = holder;
+      return NS_OK;
     }
   } while (true);
 }
 
-RefPtr<NesteggPacketHolder>
-WebMDemuxer::DemuxPacket(TrackInfo::TrackType aType)
+nsresult
+WebMDemuxer::DemuxPacket(TrackInfo::TrackType aType,
+                         RefPtr<NesteggPacketHolder>& aPacket)
 {
   nestegg_packet* packet;
   int r = nestegg_read_packet(Context(aType), &packet);
   if (r == 0) {
     nestegg_read_reset(Context(aType));
-    return nullptr;
+    return NS_ERROR_DOM_MEDIA_END_OF_STREAM;
   } else if (r < 0) {
-    return nullptr;
+    return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
   }
 
   unsigned int track = 0;
   r = nestegg_packet_track(packet, &track);
   if (r == -1) {
-    return nullptr;
+    return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
   }
 
   int64_t offset = Resource(aType).Tell();
   RefPtr<NesteggPacketHolder> holder = new NesteggPacketHolder();
   if (!holder->Init(packet, offset, track, false)) {
-    return nullptr;
+    return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
   }
 
-  return holder;
+  aPacket = holder;
+  return NS_OK;
 }
 
 void
 WebMDemuxer::PushAudioPacket(NesteggPacketHolder* aItem)
 {
   mAudioPackets.PushFront(aItem);
 }
 
@@ -1048,62 +1066,70 @@ RefPtr<WebMTrackDemuxer::SeekPromise>
 WebMTrackDemuxer::Seek(const media::TimeUnit& aTime)
 {
   // Seeks to aTime. Upon success, SeekPromise will be resolved with the
   // actual time seeked to. Typically the random access point time
 
   media::TimeUnit seekTime = aTime;
   mSamples.Reset();
   mParent->SeekInternal(mType, aTime);
-  mParent->GetNextPacket(mType, &mSamples);
+  nsresult rv = mParent->GetNextPacket(mType, &mSamples);
+  if (NS_FAILED(rv)) {
+    return SeekPromise::CreateAndReject(rv, __func__);
+  }
   mNeedKeyframe = true;
 
   // Check what time we actually seeked to.
   if (mSamples.GetSize() > 0) {
     const RefPtr<MediaRawData>& sample = mSamples.First();
     seekTime = media::TimeUnit::FromMicroseconds(sample->mTime);
   }
   SetNextKeyFrameTime();
 
   return SeekPromise::CreateAndResolve(seekTime, __func__);
 }
 
-RefPtr<MediaRawData>
-WebMTrackDemuxer::NextSample()
+nsresult
+WebMTrackDemuxer::NextSample(RefPtr<MediaRawData>& aData)
 {
-  while (mSamples.GetSize() < 1 && mParent->GetNextPacket(mType, &mSamples)) {
+  nsresult rv;
+  while (mSamples.GetSize() < 1 &&
+         NS_SUCCEEDED((rv = mParent->GetNextPacket(mType, &mSamples)))) {
   }
   if (mSamples.GetSize()) {
-    return mSamples.PopFront();
+    aData = mSamples.PopFront();
+    return NS_OK;
   }
-  return nullptr;
+  return rv;
 }
 
 RefPtr<WebMTrackDemuxer::SamplesPromise>
 WebMTrackDemuxer::GetSamples(int32_t aNumSamples)
 {
   RefPtr<SamplesHolder> samples = new SamplesHolder;
   MOZ_ASSERT(aNumSamples);
 
+  nsresult rv = NS_ERROR_DOM_MEDIA_END_OF_STREAM;
+
   while (aNumSamples) {
-    RefPtr<MediaRawData> sample(NextSample());
-    if (!sample) {
+    RefPtr<MediaRawData> sample;
+    rv = NextSample(sample);
+    if (NS_FAILED(rv)) {
       break;
     }
     if (mNeedKeyframe && !sample->mKeyframe) {
       continue;
     }
     mNeedKeyframe = false;
     samples->mSamples.AppendElement(sample);
     aNumSamples--;
   }
 
   if (samples->mSamples.IsEmpty()) {
-    return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM,
-                                           __func__);
+    return SamplesPromise::CreateAndReject(rv, __func__);
   } else {
     UpdateSamples(samples->mSamples);
     return SamplesPromise::CreateAndResolve(samples, __func__);
   }
 }
 
 void
 WebMTrackDemuxer::SetNextKeyFrameTime()
@@ -1128,17 +1154,18 @@ WebMTrackDemuxer::SetNextKeyFrameTime()
   }
   Maybe<int64_t> startTime;
   if (skipSamplesQueue.GetSize()) {
     const RefPtr<MediaRawData>& sample = skipSamplesQueue.First();
     startTime.emplace(sample->mTimecode);
   }
   // Demux and buffer frames until we find a keyframe.
   RefPtr<MediaRawData> sample;
-  while (!foundKeyframe && (sample = NextSample())) {
+  nsresult rv = NS_OK;
+  while (!foundKeyframe && NS_SUCCEEDED((rv = NextSample(sample)))) {
     if (sample->mKeyframe) {
       frameTime = sample->mTime;
       foundKeyframe = true;
     }
     int64_t sampleTimecode = sample->mTimecode;
     skipSamplesQueue.Push(sample.forget());
     if (!startTime) {
       startTime.emplace(sampleTimecode);
@@ -1214,29 +1241,32 @@ WebMTrackDemuxer::GetNextRandomAccessPoi
 
 RefPtr<WebMTrackDemuxer::SkipAccessPointPromise>
 WebMTrackDemuxer::SkipToNextRandomAccessPoint(
   const media::TimeUnit& aTimeThreshold)
 {
   uint32_t parsed = 0;
   bool found = false;
   RefPtr<MediaRawData> sample;
+  nsresult rv = NS_OK;
   int64_t sampleTime;
 
   WEBM_DEBUG("TimeThreshold: %f", aTimeThreshold.ToSeconds());
-  while (!found && (sample = NextSample())) {
+  while (!found && NS_SUCCEEDED((rv = NextSample(sample)))) {
     parsed++;
     sampleTime = sample->mTime;
     if (sample->mKeyframe && sampleTime >= aTimeThreshold.ToMicroseconds()) {
       found = true;
       mSamples.Reset();
       mSamples.PushFront(sample.forget());
     }
   }
-  SetNextKeyFrameTime();
+  if (NS_SUCCEEDED(rv)) {
+    SetNextKeyFrameTime();
+  }
   if (found) {
     WEBM_DEBUG("next sample: %f (parsed: %d)",
                media::TimeUnit::FromMicroseconds(sampleTime).ToSeconds(),
                parsed);
     return SkipAccessPointPromise::CreateAndResolve(parsed, __func__);
   } else {
     SkipFailureHolder failure(NS_ERROR_DOM_MEDIA_END_OF_STREAM, parsed);
     return SkipAccessPointPromise::CreateAndReject(Move(failure), __func__);
--- a/dom/media/webm/WebMDemuxer.h
+++ b/dom/media/webm/WebMDemuxer.h
@@ -119,17 +119,18 @@ public:
 
   bool IsSeekableOnlyInBufferedRanges() const override;
 
   UniquePtr<EncryptionInfo> GetCrypto() override;
 
   bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset);
 
   // Demux next WebM packet and append samples to MediaRawDataQueue
-  bool GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples);
+  nsresult GetNextPacket(TrackInfo::TrackType aType,
+                         MediaRawDataQueue *aSamples);
 
   nsresult Reset(TrackInfo::TrackType aType);
 
   // Pushes a packet to the front of the audio packet queue.
   void PushAudioPacket(NesteggPacketHolder* aItem);
 
   // Pushes a packet to the front of the video packet queue.
   void PushVideoPacket(NesteggPacketHolder* aItem);
@@ -187,21 +188,23 @@ private:
   media::TimeIntervals GetBuffered();
   nsresult SeekInternal(TrackInfo::TrackType aType,
                         const media::TimeUnit& aTarget);
   CryptoTrack GetTrackCrypto(TrackInfo::TrackType aType, size_t aTrackNumber);
 
   // Read a packet from the nestegg file. Returns nullptr if all packets for
   // the particular track have been read. Pass TrackInfo::kVideoTrack or
   // TrackInfo::kVideoTrack to indicate the type of the packet we want to read.
-  RefPtr<NesteggPacketHolder> NextPacket(TrackInfo::TrackType aType);
+  nsresult NextPacket(TrackInfo::TrackType aType,
+                      RefPtr<NesteggPacketHolder>& aPacket);
 
   // Internal method that demuxes the next packet from the stream. The caller
   // is responsible for making sure it doesn't get lost.
-  RefPtr<NesteggPacketHolder> DemuxPacket(TrackInfo::TrackType aType);
+  nsresult DemuxPacket(TrackInfo::TrackType aType,
+                       RefPtr<NesteggPacketHolder>& aPacket);
 
   // libnestegg audio and video context for webm container.
   // Access on reader's thread only.
   NestEggContext mVideoContext;
   NestEggContext mAudioContext;
   MediaResourceIndex& Resource(TrackInfo::TrackType aType)
   {
     return aType == TrackInfo::kVideoTrack
@@ -289,17 +292,17 @@ public:
 
   void BreakCycles() override;
 
 private:
   friend class WebMDemuxer;
   ~WebMTrackDemuxer();
   void UpdateSamples(nsTArray<RefPtr<MediaRawData>>& aSamples);
   void SetNextKeyFrameTime();
-  RefPtr<MediaRawData> NextSample ();
+  nsresult NextSample(RefPtr<MediaRawData>& aData);
   RefPtr<WebMDemuxer> mParent;
   TrackInfo::TrackType mType;
   UniquePtr<TrackInfo> mInfo;
   Maybe<media::TimeUnit> mNextKeyframeTime;
   bool mNeedKeyframe;
 
   // Queued samples extracted by the demuxer, but not yet returned.
   MediaRawDataQueue mSamples;
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -859,25 +859,32 @@ nsMixedContentBlocker::ShouldLoad(bool a
   // If there is no securityUI, document doesn't have a security state.
   // Allow load and return early.
   if (!securityUI) {
     *aDecision = nsIContentPolicy::ACCEPT;
     return NS_OK;
   }
   nsresult stateRV = securityUI->GetState(&state);
 
+  OriginAttributes originAttributes;
+  if (principal) {
+    originAttributes.Inherit(principal->OriginAttributesRef());
+  } else if (aRequestPrincipal) {
+    originAttributes.Inherit(aRequestPrincipal->OriginAttributesRef());
+  }
+
   bool doHSTSPriming = false;
   if (IsEligibleForHSTSPriming(aContentLocation)) {
     bool hsts = false;
     bool cached = false;
     nsCOMPtr<nsISiteSecurityService> sss =
       do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aContentLocation,
-        0, &cached, &hsts);
+        0, originAttributes, &cached, &hsts);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (hsts && sUseHSTS) {
       // assume we will be upgraded later
       *aDecision = ACCEPT;
       return NS_OK;
     }
 
@@ -902,24 +909,26 @@ nsMixedContentBlocker::ShouldLoad(bool a
   // is not blocked (e.g., for images).  For more detail, see:
   //   https://bugzilla.mozilla.org/show_bug.cgi?id=1198572#c19
   //
   // We do not count requests aHadInsecureImageRedirect=true, since these are
   // just an artifact of the image caching system.
   bool active = (classification == eMixedScript);
   if (!aHadInsecureImageRedirect) {
     if (XRE_IsParentProcess()) {
-      AccumulateMixedContentHSTS(innerContentLocation, active, doHSTSPriming);
+      AccumulateMixedContentHSTS(innerContentLocation, active, doHSTSPriming,
+                                 originAttributes);
     } else {
       // Ask the parent process to do the same call
       mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
       if (cc) {
         mozilla::ipc::URIParams uri;
         SerializeURI(innerContentLocation, uri);
-        cc->SendAccumulateMixedContentHSTS(uri, active, doHSTSPriming);
+        cc->SendAccumulateMixedContentHSTS(uri, active, doHSTSPriming,
+                                           originAttributes);
       }
     }
   }
 
   // set hasMixedContentObjectSubrequest on this object if necessary
   if (aContentType == TYPE_OBJECT_SUBREQUEST) {
     rootDoc->SetHasMixedContentObjectSubrequest(true);
   }
@@ -1092,32 +1101,35 @@ enum MixedContentHSTSPrimingState {
   eMCB_HSTS_PASSIVE_DO_PRIMING = 3,
   eMCB_HSTS_ACTIVE_NO_PRIMING  = 4,
   eMCB_HSTS_ACTIVE_DO_PRIMING  = 5
 };
 
 // Record information on when HSTS would have made mixed content not mixed
 // content (regardless of whether it was actually blocked)
 void
-nsMixedContentBlocker::AccumulateMixedContentHSTS(nsIURI* aURI, bool aActive, bool aHasHSTSPriming)
+nsMixedContentBlocker::AccumulateMixedContentHSTS(
+  nsIURI* aURI, bool aActive, bool aHasHSTSPriming,
+  const OriginAttributes& aOriginAttributes)
 {
   // This method must only be called in the parent, because
   // nsSiteSecurityService is only available in the parent
   if (!XRE_IsParentProcess()) {
     MOZ_ASSERT(false);
     return;
   }
 
   bool hsts;
   nsresult rv;
   nsCOMPtr<nsISiteSecurityService> sss = do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
   if (NS_FAILED(rv)) {
     return;
   }
-  rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, 0, nullptr, &hsts);
+  rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, 0,
+                        aOriginAttributes, nullptr, &hsts);
   if (NS_FAILED(rv)) {
     return;
   }
 
   // states: would upgrade, would prime, hsts info cached
   // active, passive
   //
   if (!aActive) {
--- a/dom/security/nsMixedContentBlocker.h
+++ b/dom/security/nsMixedContentBlocker.h
@@ -23,16 +23,18 @@ enum MixedContentTypes {
   eMixedDisplay
 };
 
 #include "nsIContentPolicy.h"
 #include "nsIChannel.h"
 #include "nsIChannelEventSink.h"
 #include "imgRequest.h"
 
+using mozilla::OriginAttributes;
+
 class nsILoadInfo; // forward declaration
 
 class nsMixedContentBlocker : public nsIContentPolicy,
                               public nsIChannelEventSink
 {
 private:
   virtual ~nsMixedContentBlocker();
 
@@ -58,17 +60,18 @@ public:
                              nsIURI* aRequestingLocation,
                              nsISupports* aRequestingContext,
                              const nsACString& aMimeGuess,
                              nsISupports* aExtra,
                              nsIPrincipal* aRequestPrincipal,
                              int16_t* aDecision);
   static void AccumulateMixedContentHSTS(nsIURI* aURI,
                                          bool aActive,
-                                         bool aHasHSTSPriming);
+                                         bool aHasHSTSPriming,
+                                         const OriginAttributes& aOriginAttributes);
   /* If the document associated with aRequestingContext requires priming for
    * aURI, propagate that to the LoadInfo so the HttpChannel will find out about
    * it.
    *
    * @param aURI The URI associated with the load
    * @param aRequestingContext the requesting context passed to ShouldLoad
    * @param aLoadInfo the LoadInfo for the load
    */
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -7,16 +7,17 @@
 #include "mozilla/ServoRestyleManager.h"
 
 #include "mozilla/DocumentStyleRootIterator.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/dom/ChildIterator.h"
 #include "nsContentUtils.h"
 #include "nsPrintfCString.h"
+#include "nsRefreshDriver.h"
 #include "nsStyleChangeList.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
 
 ServoRestyleManager::ServoRestyleManager(nsPresContext* aPresContext)
   : RestyleManager(StyleBackendType::Servo, aPresContext)
@@ -361,16 +362,20 @@ ServoRestyleManager::ProcessPendingResty
   // Create a AnimationsWithDestroyedFrame during restyling process to
   // stop animations and transitions on elements that have no frame at the end
   // of the restyling process.
   AnimationsWithDestroyedFrame animationsWithDestroyedFrame(this);
 
   ServoStyleSet* styleSet = StyleSet();
   nsIDocument* doc = PresContext()->Document();
 
+  // Ensure the refresh driver is active during traversal to avoid mutating
+  // mActiveTimer and mMostRecentRefresh time.
+  PresContext()->RefreshDriver()->MostRecentRefresh();
+
   mInStyleRefresh = true;
 
   // Perform the Servo traversal, and the post-traversal if required.
   if (styleSet->StyleDocument()) {
 
     PresContext()->EffectCompositor()->ClearElementsToRestyle();
 
     // First do any queued-up frame creation. (see bugs 827239 and 997506).
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -1235,17 +1235,21 @@ nsRefreshDriver::RestoreNormalRefresh()
   mTestControllingRefreshes = false;
   EnsureTimerStarted(eAllowTimeToGoBackwards);
   mCompletedTransaction = mPendingTransaction;
 }
 
 TimeStamp
 nsRefreshDriver::MostRecentRefresh() const
 {
-  const_cast<nsRefreshDriver*>(this)->EnsureTimerStarted();
+  // In case of stylo traversal, we have already activated the refresh driver in
+  // ServoRestyleManager::ProcessPendingRestyles().
+  if (!ServoStyleSet::IsInServoTraversal()) {
+    const_cast<nsRefreshDriver*>(this)->EnsureTimerStarted();
+  }
 
   return mMostRecentRefresh;
 }
 
 int64_t
 nsRefreshDriver::MostRecentRefreshEpochTime() const
 {
   const_cast<nsRefreshDriver*>(this)->EnsureTimerStarted();
@@ -1318,16 +1322,20 @@ nsRefreshDriver::RemoveImageRequest(imgI
       start->mEntries.RemoveEntry(aRequest);
     }
   }
 }
 
 void
 nsRefreshDriver::EnsureTimerStarted(EnsureTimerStartedFlags aFlags)
 {
+  MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal(),
+             "EnsureTimerStarted should be called only when we are not "
+             "in servo traversal");
+
   if (mTestControllingRefreshes)
     return;
 
   // will it already fire, and no other changes needed?
   if (mActiveTimer && !(aFlags & eForceAdjustTimer))
     return;
 
   if (IsFrozen() || !mPresContext) {
--- a/layout/reftests/css-grid/reftest-stylo.list
+++ b/layout/reftests/css-grid/reftest-stylo.list
@@ -157,30 +157,30 @@ fails == grid-item-margin-left-right-aut
 fails == grid-item-margin-left-right-auto-002.html grid-item-margin-left-right-auto-002.html
 fails == grid-item-margin-left-right-auto-003.html grid-item-margin-left-right-auto-003.html
 fails == grid-item-margin-left-right-auto-004.html grid-item-margin-left-right-auto-004.html
 fails == grid-item-margin-right-auto-001.html grid-item-margin-right-auto-001.html
 fails == grid-item-margin-right-auto-002.html grid-item-margin-right-auto-002.html
 fails == grid-item-margin-right-auto-003.html grid-item-margin-right-auto-003.html
 fails == grid-item-margin-right-auto-004.html grid-item-margin-right-auto-004.html
 fails == grid-container-min-max-width-height-001.html grid-container-min-max-width-height-001.html
-fails == grid-clamping-001.html grid-clamping-001.html
+== grid-clamping-001.html grid-clamping-001.html
 fails == grid-clamping-002.html grid-clamping-002.html
 fails == grid-repeat-auto-fill-fit-001.html grid-repeat-auto-fill-fit-001.html
 fails == grid-repeat-auto-fill-fit-002.html grid-repeat-auto-fill-fit-002.html
 fails == grid-repeat-auto-fill-fit-003.html grid-repeat-auto-fill-fit-003.html
 fails == grid-repeat-auto-fill-fit-004.html grid-repeat-auto-fill-fit-004.html
 fails == grid-repeat-auto-fill-fit-005.html grid-repeat-auto-fill-fit-005.html
 fails == grid-repeat-auto-fill-fit-006.html grid-repeat-auto-fill-fit-006.html
 fails == grid-repeat-auto-fill-fit-007.html grid-repeat-auto-fill-fit-007.html
 fails == grid-repeat-auto-fill-fit-008.html grid-repeat-auto-fill-fit-008.html
 fails == grid-repeat-auto-fill-fit-009.html grid-repeat-auto-fill-fit-009.html
 fails == grid-repeat-auto-fill-fit-010.html grid-repeat-auto-fill-fit-010.html
 fails == grid-repeat-auto-fill-fit-011.html grid-repeat-auto-fill-fit-011.html
-fails asserts-if(stylo,144) == grid-item-blockifying-001.html grid-item-blockifying-001.html # bug 1335339
+fails asserts-if(stylo,48) == grid-item-blockifying-001.html grid-item-blockifying-001.html # bug 1335339
 fails == grid-fragmentation-001.html grid-fragmentation-001.html
 fails == grid-fragmentation-002.html grid-fragmentation-002.html
 fails == grid-fragmentation-003.html grid-fragmentation-003.html
 fails == grid-fragmentation-004.html grid-fragmentation-004.html
 fails == grid-fragmentation-005.html grid-fragmentation-005.html
 fails == grid-fragmentation-006.html grid-fragmentation-006.html
 fails == grid-fragmentation-007.html grid-fragmentation-007.html
 fails == grid-fragmentation-008.html grid-fragmentation-008.html
@@ -213,33 +213,33 @@ fails == grid-fragmentation-031.html gri
 fails == grid-fragmentation-dyn3-001.html grid-fragmentation-dyn3-001.html
 fails == grid-fragmentation-dyn4-001.html grid-fragmentation-dyn4-001.html
 fails == grid-fragmentation-dyn1-002.html grid-fragmentation-dyn1-002.html
 fails == grid-fragmentation-dyn3-002.html grid-fragmentation-dyn3-002.html
 fails == grid-fragmentation-dyn3-003.html grid-fragmentation-dyn3-003.html
 fails == grid-fragmentation-dyn4-004.html grid-fragmentation-dyn4-004.html
 fails == grid-fragmentation-dyn4-005.html grid-fragmentation-dyn4-005.html
 fails == grid-fragmentation-dyn5-005.html grid-fragmentation-dyn5-005.html
-fails == grid-fragmentation-dyn1-006.html grid-fragmentation-dyn1-006.html
+skip == grid-fragmentation-dyn1-006.html grid-fragmentation-dyn1-006.html
 fails == grid-fragmentation-dyn3-007.html grid-fragmentation-dyn3-007.html
 fails == grid-fragmentation-dyn5-007.html grid-fragmentation-dyn5-007.html
 fails == grid-fragmentation-dyn5-008.html grid-fragmentation-dyn5-008.html
 fails == grid-fragmentation-dyn3-009.html grid-fragmentation-dyn3-009.html
 fails == grid-fragmentation-dyn3-009.html grid-fragmentation-dyn3-009.html
 fails == grid-fragmentation-dyn4-015.html grid-fragmentation-dyn4-015.html
 fails == grid-fragmentation-dyn1-015.html grid-fragmentation-dyn1-015.html
 fails == grid-fragmentation-dyn1-016.html grid-fragmentation-dyn1-016.html
 fails == grid-fragmentation-dyn5-016.html grid-fragmentation-dyn5-016.html
 fails == grid-fragmentation-dyn3-017.html grid-fragmentation-dyn3-017.html
 fails == grid-fragmentation-dyn2-018.html grid-fragmentation-dyn2-018.html
-fails == grid-fragmentation-dyn1-019.html grid-fragmentation-dyn1-019.html
-fails == grid-fragmentation-dyn2-019.html grid-fragmentation-dyn2-019.html
-fails == grid-fragmentation-dyn3-019.html grid-fragmentation-dyn3-019.html
-fails == grid-fragmentation-dyn4-019.html grid-fragmentation-dyn4-019.html
-fails == grid-fragmentation-dyn5-019.html grid-fragmentation-dyn5-019.html
+# fails == grid-fragmentation-dyn1-019.html grid-fragmentation-dyn1-019.html # bug 1341104
+# fails == grid-fragmentation-dyn2-019.html grid-fragmentation-dyn2-019.html # bug 1341104
+# fails == grid-fragmentation-dyn3-019.html grid-fragmentation-dyn3-019.html # bug 1341104
+# fails == grid-fragmentation-dyn4-019.html grid-fragmentation-dyn4-019.html # bug 1341104
+# fails == grid-fragmentation-dyn5-019.html grid-fragmentation-dyn5-019.html # bug 1341104
 fails == grid-fragmentation-dyn1-020.html grid-fragmentation-dyn1-020.html
 fails == grid-fragmentation-dyn2-020.html grid-fragmentation-dyn2-020.html
 skip == grid-fragmentation-dyn1-021.html grid-fragmentation-dyn1-021.html
 skip == grid-fragmentation-dyn2-021.html grid-fragmentation-dyn2-021.html
 skip == grid-fragmentation-dyn3-021.html grid-fragmentation-dyn3-021.html
 skip asserts(1-10) == grid-fragmentation-dyn4-021.html grid-fragmentation-dyn4-021.html
 skip == grid-fragmentation-dyn5-021.html grid-fragmentation-dyn5-021.html
 skip == grid-fragmentation-dyn2-022.html grid-fragmentation-dyn2-022.html
--- a/layout/reftests/svg/reftest-stylo.list
+++ b/layout/reftests/svg/reftest-stylo.list
@@ -38,17 +38,17 @@ fuzzy-if(/^Windows\x20NT\x2010\.0/.test(
 == clipPath-basic-02.svg clipPath-basic-02.svg
 == clipPath-basic-03.svg clipPath-basic-03.svg
 == clipPath-basic-04.svg clipPath-basic-04.svg
 == clipPath-basic-05.svg clipPath-basic-05.svg
 == clipPath-basic-06.svg clipPath-basic-06.svg
 == clipPath-basic-07.svg clipPath-basic-07.svg
 == clipPath-winding-01.svg clipPath-winding-01.svg
 == clip-surface-clone-01.svg clip-surface-clone-01.svg
-fails == comments-in-pres-attrs.svg pass.svg
+== comments-in-pres-attrs.svg pass.svg
 == conditions-01.svg conditions-01.svg
 == conditions-02.svg conditions-02.svg
 == conditions-03.svg conditions-03.svg
 == conditions-04.svg conditions-04.svg
 == conditions-05.svg conditions-05.svg
 == conditions-07.svg conditions-07.svg
 fuzzy-if(skiaContent,1,320) == conditions-08.svg conditions-08.svg
 == conditions-09.svg conditions-09.svg
--- a/layout/style/test/stylo-failures.md
+++ b/layout/style/test/stylo-failures.md
@@ -410,20 +410,16 @@ Any line which doesn't follow the format
     * test_value_storage.html `writing-mode` [8]
 * Incorrect parsing
   * calc() doesn't support dividing expression servo/servo#15192
     * test_value_storage.html `calc(50px/` [7]
     * ... `calc(2em / ` [9]
   * calc() doesn't support number value servo/servo#15205
     * test_value_storage.html `calc(1 +` [1]
     * ... `calc(-2.5)` [1]
-  * incorrect parsing function for column-{gap,width} servo/servo#15088
-    * test_compute_data_with_start_struct.html ` column-` [4]
-    * test_value_storage.html `column-gap` [3]
-    * ... `column-width` [3]
   * size part of shorthand background/mask always desires two values servo/servo#15199
     * test_value_storage.html `'background'` [18]
     * ... `/ auto none` [34]
     * ... `/ auto repeat` [17]
   * border shorthands do not reset border-image servo/servo#15202
     * test_inherit_storage.html `for property 'border-image-` [5]
     * test_initial_storage.html `for property 'border-image-` [10]
     * test_value_storage.html `(for 'border-image-` [60]
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1249,17 +1249,17 @@ pref("privacy.trackingprotection.pbmode.
 // Annotate channels based on the tracking protection list in all modes
 pref("privacy.trackingprotection.annotate_channels",  true);
 // Lower the priority of network loads for resources on the tracking protection list.
 // Note that this requires the privacy.trackingprotection.annotate_channels pref to be on in order to have any effect.
 pref("privacy.trackingprotection.lower_network_priority",  false);
 
 pref("dom.event.contextmenu.enabled",       true);
 pref("dom.event.clipboardevents.enabled",   true);
-#if defined(XP_WIN) && !defined(RELEASE_OR_BETA) || defined(MOZ_WIDGET_GTK) && !defined(RELEASE_OR_BETA) || defined(XP_MACOSX) && !defined(RELEASE_OR_BETA)
+#if defined(XP_WIN) && !defined(RELEASE_OR_BETA) || defined(MOZ_WIDGET_GTK) && !defined(RELEASE_OR_BETA) || defined(XP_MACOSX) && !defined(RELEASE_OR_BETA) || defined(MOZ_WIDGET_ANDROID) && !defined(RELEASE_OR_BETA)
 pref("dom.event.highrestimestamp.enabled",  true);
 #else
 pref("dom.event.highrestimestamp.enabled",  false);
 #endif
 
 pref("dom.webcomponents.enabled",           false);
 pref("dom.webcomponents.customelements.enabled", false);
 
@@ -1479,18 +1479,19 @@ pref("network.http.request.max-start-del
 pref("network.http.request.max-attempts", 10);
 
 // Headers
 pref("network.http.accept.default", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
 
 // Prefs allowing granular control of referers
 // 0=don't send any, 1=send only on clicks, 2=send on image requests as well
 pref("network.http.sendRefererHeader",      2);
-// 0=no referrer, 1=same origin, 2=strict-origin-when-cross-origin,
-// 3=no-referre-when-downgrade(default)
+// Set the default Referrer Policy to be used unless overriden by the site
+// 0=no-referrer, 1=same-origin, 2=strict-origin-when-cross-origin,
+// 3=no-referrer-when-downgrade
 pref("network.http.referer.userControlPolicy", 3);
 // false=real referer, true=spoof referer (use target URI as referer)
 pref("network.http.referer.spoofSource", false);
 // false=allow onion referer, true=hide onion referer (use target URI as referer)
 pref("network.http.referer.hideOnionSource", false);
 // 0=full URI, 1=scheme+host+port+path, 2=scheme+host+port
 pref("network.http.referer.trimmingPolicy", 0);
 // 0=full URI, 1=scheme+host+port+path, 2=scheme+host+port
--- a/mozglue/misc/TimeStamp.h
+++ b/mozglue/misc/TimeStamp.h
@@ -418,19 +418,22 @@ public:
 
   /**
    * The system timestamps are the same as the TimeStamp
    * retrieved by mozilla::TimeStamp. Since we need this for
    * vsync timestamps, we enable the creation of mozilla::TimeStamps
    * on platforms that support vsync aligned refresh drivers / compositors
    * Verified true as of Jan 31, 2015: B2G and OS X
    * False on Windows 7
+   * Android's event time uses CLOCK_MONOTONIC via SystemClock.uptimeMilles.
+   * So it is same value of TimeStamp posix implementation.
    * UNTESTED ON OTHER PLATFORMS
    */
-#if defined(MOZ_WIDGET_GONK) || defined(XP_DARWIN)
+#if defined(MOZ_WIDGET_GONK) || defined(XP_DARWIN) || \
+    defined(MOZ_WIDGET_ANDROID)
   static TimeStamp FromSystemTime(int64_t aSystemTime)
   {
     static_assert(sizeof(aSystemTime) == sizeof(TimeStampValue),
                   "System timestamp should be same units as TimeStampValue");
     return TimeStamp(aSystemTime);
   }
 #endif
 
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -2159,16 +2159,17 @@ NS_IsSrcdocChannel(nsIChannel *aChannel)
 }
 
 nsresult
 NS_ShouldSecureUpgrade(nsIURI* aURI,
                        nsILoadInfo* aLoadInfo,
                        nsIPrincipal* aChannelResultPrincipal,
                        bool aPrivateBrowsing,
                        bool aAllowSTS,
+                       const OriginAttributes& aOriginAttributes,
                        bool& aShouldUpgrade)
 {
   // Even if we're in private browsing mode, we still enforce existing STS
   // data (it is read-only).
   // if the connection is not using SSL and either the exact host matches or
   // a superdomain wants to force HTTPS, do it.
   bool isHttps = false;
   nsresult rv = aURI->SchemeIs("https", &isHttps);
@@ -2217,17 +2218,17 @@ NS_ShouldSecureUpgrade(nsIURI* aURI,
 
     // enforce Strict-Transport-Security
     nsISiteSecurityService* sss = gHttpHandler->GetSSService();
     NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY);
 
     bool isStsHost = false;
     uint32_t flags = aPrivateBrowsing ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
     rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, flags,
-                          nullptr, &isStsHost);
+                          aOriginAttributes, nullptr, &isStsHost);
 
     // if the SSS check fails, it's likely because this load is on a
     // malformed URI or something else in the setup is wrong, so any error
     // should be reported.
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (isStsHost) {
       LOG(("nsHttpChannel::Connect() STS permissions found\n"));
--- a/netwerk/base/nsNetUtil.h
+++ b/netwerk/base/nsNetUtil.h
@@ -950,16 +950,17 @@ bool NS_IsValidHTTPToken(const nsACStrin
 /**
  * Return true if the given request must be upgraded to HTTPS.
  */
 nsresult NS_ShouldSecureUpgrade(nsIURI* aURI,
                                 nsILoadInfo* aLoadInfo,
                                 nsIPrincipal* aChannelResultPrincipal,
                                 bool aPrivateBrowsing,
                                 bool aAllowSTS,
+                                const mozilla::OriginAttributes& aOriginAttributes,
                                 bool& aShouldUpgrade);
 
 /**
  * Returns an https URI for channels that need to go through secure upgrades.
  */
 nsresult NS_GetSecureUpgradedURI(nsIURI* aURI, nsIURI** aUpgradedURI);
 
 nsresult NS_CompareLoadInfoAndLoadContext(nsIChannel *aChannel);
--- a/netwerk/protocol/http/HSTSPrimerListener.cpp
+++ b/netwerk/protocol/http/HSTSPrimerListener.cpp
@@ -144,18 +144,22 @@ HSTSPrimingListener::CheckHSTSPrimingReq
   nsCOMPtr<nsISiteSecurityService> sss = do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIURI> uri;
   rv = httpChannel->GetURI(getter_AddRefs(uri));
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(uri, NS_ERROR_CONTENT_BLOCKED);
 
+  OriginAttributes originAttributes;
+  NS_GetOriginAttributes(httpChannel, originAttributes);
+
   bool hsts;
-  rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, 0, nullptr, &hsts);
+  rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, 0,
+                        originAttributes, nullptr, &hsts);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (hsts) {
     // An HSTS upgrade was found
     return NS_OK;
   }
 
   // There is no HSTS upgrade available
@@ -217,17 +221,22 @@ HSTSPrimingListener::StartHSTSPriming(ns
   rv = NS_GetSecureUpgradedURI(finalChannelURI, getter_AddRefs(uri));
   NS_ENSURE_SUCCESS(rv,rv);
 
   // check the HSTS cache
   bool hsts;
   bool cached;
   nsCOMPtr<nsISiteSecurityService> sss = do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, 0, &cached, &hsts);
+
+  OriginAttributes originAttributes;
+  NS_GetOriginAttributes(aRequestChannel, originAttributes);
+
+  rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, 0,
+                        originAttributes, &cached, &hsts);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (hsts) {
     // already saw this host and will upgrade if allowed by preferences
     return aCallback->OnHSTSPrimingSucceeded(true);
   }
 
   if (cached) {
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -2939,21 +2939,24 @@ HttpChannelChild::ShouldInterceptURI(nsI
   bool isHttps = false;
   nsresult rv = aURI->SchemeIs("https", &isHttps);
   NS_ENSURE_SUCCESS(rv, false);
   nsCOMPtr<nsIPrincipal> resultPrincipal;
   if (!isHttps && mLoadInfo) {
       nsContentUtils::GetSecurityManager()->
         GetChannelResultPrincipal(this, getter_AddRefs(resultPrincipal));
   }
+  OriginAttributes originAttributes;
+  NS_ENSURE_TRUE(NS_GetOriginAttributes(this, originAttributes), false);
   rv = NS_ShouldSecureUpgrade(aURI,
                               mLoadInfo,
                               resultPrincipal,
                               mPrivateBrowsing,
                               mAllowSTS,
+                              originAttributes,
                               aShouldUpgrade);
   NS_ENSURE_SUCCESS(rv, false);
 
   nsCOMPtr<nsIURI> upgradedURI;
   if (aShouldUpgrade) {
     rv = NS_GetSecureUpgradedURI(aURI, getter_AddRefs(upgradedURI));
     NS_ENSURE_SUCCESS(rv, false);
   }
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -384,22 +384,27 @@ nsHttpChannel::Connect()
     bool isHttps = false;
     rv = mURI->SchemeIs("https", &isHttps);
     NS_ENSURE_SUCCESS(rv,rv);
     nsCOMPtr<nsIPrincipal> resultPrincipal;
     if (!isHttps && mLoadInfo) {
         nsContentUtils::GetSecurityManager()->
           GetChannelResultPrincipal(this, getter_AddRefs(resultPrincipal));
     }
+    OriginAttributes originAttributes;
+    if (!NS_GetOriginAttributes(this, originAttributes)) {
+        return NS_ERROR_FAILURE;
+    }
     bool shouldUpgrade = false;
     rv = NS_ShouldSecureUpgrade(mURI,
                                 mLoadInfo,
                                 resultPrincipal,
                                 mPrivateBrowsing,
                                 mAllowSTS,
+                                originAttributes,
                                 shouldUpgrade);
     NS_ENSURE_SUCCESS(rv, rv);
     if (shouldUpgrade) {
         return AsyncCall(&nsHttpChannel::HandleAsyncRedirectChannelToHttps);
     }
 
     // ensure that we are using a valid hostname
     if (!net_IsValidHostName(nsDependentCString(mConnectionInfo->Origin())))
@@ -1628,19 +1633,22 @@ nsHttpChannel::ProcessSingleSecurityHead
 
     nsAutoCString securityHeader;
     nsresult rv = mResponseHead->GetHeader(atom, securityHeader);
     if (NS_SUCCEEDED(rv)) {
         nsISiteSecurityService* sss = gHttpHandler->GetSSService();
         NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY);
         // Process header will now discard the headers itself if the channel
         // wasn't secure (whereas before it had to be checked manually)
+        OriginAttributes originAttributes;
+        NS_GetOriginAttributes(this, originAttributes);
         uint32_t failureResult;
         rv = sss->ProcessHeader(aType, mURI, securityHeader, aSSLStatus,
-                                aFlags, nullptr, nullptr, &failureResult);
+                                aFlags, originAttributes, nullptr, nullptr,
+                                &failureResult);
         if (NS_FAILED(rv)) {
             nsAutoString consoleErrorCategory;
             nsAutoString consoleErrorTag;
             switch (aType) {
                 case nsISiteSecurityService::HEADER_HSTS:
                     GetSTSConsoleErrorTag(failureResult, consoleErrorTag);
                     consoleErrorCategory = NS_LITERAL_STRING("Invalid HSTS Headers");
                     break;
@@ -8271,18 +8279,20 @@ nsHttpChannel::OnHSTSPrimingFailed(nsres
                 (wouldBlock) ?  HSTSPrimingResult::eHSTS_PRIMING_FAILED_BLOCK :
                 HSTSPrimingResult::eHSTS_PRIMING_FAILED_ACCEPT);
     }
 
     // Don't visit again for at least
     // security.mixed_content.hsts_priming_cache_timeout seconds.
     nsISiteSecurityService* sss = gHttpHandler->GetSSService();
     NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY);
+    OriginAttributes originAttributes;
+    NS_GetOriginAttributes(this, originAttributes);
     nsresult rv = sss->CacheNegativeHSTSResult(mURI,
-            nsMixedContentBlocker::sHSTSPrimingCacheTimeout);
+            nsMixedContentBlocker::sHSTSPrimingCacheTimeout, originAttributes);
     if (NS_FAILED(rv)) {
         NS_ERROR("nsISiteSecurityService::CacheNegativeHSTSResult failed");
     }
 
     // If we would block, go ahead and abort with the error provided
     if (wouldBlock) {
         CloseCacheEntry(false);
         return AsyncAbort(aError);
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -2272,19 +2272,32 @@ nsHttpHandler::SpeculativeConnectInterna
     bool isStsHost = false;
     if (!sss)
         return NS_OK;
 
     nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(aCallbacks);
     uint32_t flags = 0;
     if (loadContext && loadContext->UsePrivateBrowsing())
         flags |= nsISocketProvider::NO_PERMANENT_STORAGE;
+
+    OriginAttributes originAttributes;
+    // If the principal is given, we use the originAttributes from this
+    // principal. Otherwise, we use the originAttributes from the
+    // loadContext.
+    if (aPrincipal) {
+        originAttributes.Inherit(aPrincipal->OriginAttributesRef());
+    } else if (loadContext) {
+        loadContext->GetOriginAttributes(originAttributes);
+        originAttributes.StripAttributes(OriginAttributes::STRIP_ADDON_ID);
+    }
+
     nsCOMPtr<nsIURI> clone;
     if (NS_SUCCEEDED(sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS,
-                                      aURI, flags, nullptr, &isStsHost)) &&
+                                      aURI, flags, originAttributes,
+                                      nullptr, &isStsHost)) &&
                                       isStsHost) {
         if (NS_SUCCEEDED(NS_GetSecureUpgradedURI(aURI,
                                                  getter_AddRefs(clone)))) {
             aURI = clone.get();
             // (NOTE: We better make sure |clone| stays alive until the end
             // of the function now, since our aURI arg now points to it!)
         }
     }
@@ -2320,27 +2333,16 @@ nsHttpHandler::SpeculativeConnectInterna
     int32_t port = -1;
     rv = aURI->GetPort(&port);
     if (NS_FAILED(rv))
         return rv;
 
     nsAutoCString username;
     aURI->GetUsername(username);
 
-    OriginAttributes originAttributes;
-    // If the principal is given, we use the originAttributes from this
-    // principal. Otherwise, we use the originAttributes from the
-    // loadContext.
-    if (aPrincipal) {
-        originAttributes.Inherit(aPrincipal->OriginAttributesRef());
-    } else if (loadContext) {
-        loadContext->GetOriginAttributes(originAttributes);
-        originAttributes.StripAttributes(OriginAttributes::STRIP_ADDON_ID);
-    }
-
     auto *ci =
         new nsHttpConnectionInfo(host, port, EmptyCString(), username, nullptr,
                                  originAttributes, usingSSL);
     ci->SetAnonymous(anonymous);
 
     return SpeculativeConnect(ci, aCallbacks);
 }
 
--- a/security/certverifier/NSSCertDBTrustDomain.cpp
+++ b/security/certverifier/NSSCertDBTrustDomain.cpp
@@ -862,18 +862,18 @@ NSSCertDBTrustDomain::IsChainValid(const
   // If mHostname isn't set, we're not verifying in the context of a TLS
   // handshake, so don't verify HPKP in those cases.
   if (mHostname && (mPinningMode != CertVerifier::pinningDisabled) &&
       !skipPinningChecksBecauseOfMITMMode) {
     bool enforceTestMode =
       (mPinningMode == CertVerifier::pinningEnforceTestMode);
     bool chainHasValidPins;
     nsresult nsrv = PublicKeyPinningService::ChainHasValidPins(
-      certList, mHostname, time, enforceTestMode, chainHasValidPins,
-      mPinningTelemetryInfo);
+      certList, mHostname, time, enforceTestMode, mOriginAttributes,
+      chainHasValidPins, mPinningTelemetryInfo);
     if (NS_FAILED(nsrv)) {
       return Result::FATAL_ERROR_LIBRARY_FAILURE;
     }
     if (!chainHasValidPins) {
       return Result::ERROR_KEY_PINNING_FAILURE;
     }
   }
 
--- a/security/manager/ssl/PublicKeyPinningService.cpp
+++ b/security/manager/ssl/PublicKeyPinningService.cpp
@@ -159,16 +159,17 @@ PublicKeyPinningService::ChainMatchesPin
   return EvalChain(certList, nullptr, &aSHA256keys, chainMatchesPinset);
 }
 
 // Returns via one of the output parameters the most relevant pinning
 // information that is valid for the given host at the given time.
 // Dynamic pins are prioritized over static pins.
 static nsresult
 FindPinningInformation(const char* hostname, mozilla::pkix::Time time,
+                       const OriginAttributes& originAttributes,
                /*out*/ nsTArray<nsCString>& dynamicFingerprints,
                /*out*/ const TransportSecurityPreload*& staticFingerprints)
 {
   if (!hostname || hostname[0] == 0) {
     return NS_ERROR_INVALID_ARG;
   }
   staticFingerprints = nullptr;
   dynamicFingerprints.Clear();
@@ -185,17 +186,18 @@ FindPinningInformation(const char* hostn
     MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
            ("pkpin: Querying pinsets for host: '%s'\n", evalHost));
     // Attempt dynamic pins first
     nsresult rv;
     bool found;
     bool includeSubdomains;
     nsTArray<nsCString> pinArray;
     rv = sssService->GetKeyPinsForHostname(nsDependentCString(evalHost), time,
-                                           pinArray, &includeSubdomains, &found);
+                                           originAttributes, pinArray,
+                                           &includeSubdomains, &found);
     if (NS_FAILED(rv)) {
       return rv;
     }
     if (found && (evalHost == hostname || includeSubdomains)) {
       MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
              ("pkpin: Found dyn match for host: '%s'\n", evalHost));
       dynamicFingerprints = pinArray;
       return NS_OK;
@@ -236,31 +238,32 @@ FindPinningInformation(const char* hostn
 // Returns true via the output parameter if the given certificate list meets
 // pinning requirements for the given host at the given time. It must be the
 // case that either there is an intersection between the set of hashes of
 // subject public key info data in the list and the most relevant non-expired
 // pinset for the host or there is no pinning information for the host.
 static nsresult
 CheckPinsForHostname(const UniqueCERTCertList& certList, const char* hostname,
                      bool enforceTestMode, mozilla::pkix::Time time,
+                     const OriginAttributes& originAttributes,
              /*out*/ bool& chainHasValidPins,
     /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo)
 {
   chainHasValidPins = false;
   if (!certList) {
     return NS_ERROR_INVALID_ARG;
   }
   if (!hostname || hostname[0] == 0) {
     return NS_ERROR_INVALID_ARG;
   }
 
   nsTArray<nsCString> dynamicFingerprints;
   const TransportSecurityPreload* staticFingerprints = nullptr;
-  nsresult rv = FindPinningInformation(hostname, time, dynamicFingerprints,
-                                       staticFingerprints);
+  nsresult rv = FindPinningInformation(hostname, time, originAttributes,
+                                       dynamicFingerprints, staticFingerprints);
   // If we have no pinning information, the certificate chain trivially
   // validates with respect to pinning.
   if (dynamicFingerprints.Length() == 0 && !staticFingerprints) {
     chainHasValidPins = true;
     return NS_OK;
   }
   if (dynamicFingerprints.Length() > 0) {
     return EvalChain(certList, nullptr, &dynamicFingerprints, chainHasValidPins);
@@ -321,48 +324,52 @@ CheckPinsForHostname(const UniqueCERTCer
             staticFingerprints->mIsMoz ? "mozilla" : "non-mozilla",
             hostname, staticFingerprints->mTestMode ? "test" : "production"));
   }
 
   return NS_OK;
 }
 
 nsresult
-PublicKeyPinningService::ChainHasValidPins(const UniqueCERTCertList& certList,
-                                           const char* hostname,
-                                           mozilla::pkix::Time time,
-                                           bool enforceTestMode,
-                                   /*out*/ bool& chainHasValidPins,
-                          /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo)
+PublicKeyPinningService::ChainHasValidPins(
+  const UniqueCERTCertList& certList,
+  const char* hostname,
+  mozilla::pkix::Time time,
+  bool enforceTestMode,
+  const OriginAttributes& originAttributes,
+  /*out*/ bool& chainHasValidPins,
+  /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo)
 {
   chainHasValidPins = false;
   if (!certList) {
     return NS_ERROR_INVALID_ARG;
   }
   if (!hostname || hostname[0] == 0) {
     return NS_ERROR_INVALID_ARG;
   }
   nsAutoCString canonicalizedHostname(CanonicalizeHostname(hostname));
   return CheckPinsForHostname(certList, canonicalizedHostname.get(),
-                              enforceTestMode, time, chainHasValidPins,
-                              pinningTelemetryInfo);
+                              enforceTestMode, time, originAttributes,
+                              chainHasValidPins, pinningTelemetryInfo);
 }
 
 nsresult
 PublicKeyPinningService::HostHasPins(const char* hostname,
                                      mozilla::pkix::Time time,
                                      bool enforceTestMode,
+                                     const OriginAttributes& originAttributes,
                                      /*out*/ bool& hostHasPins)
 {
   hostHasPins = false;
   nsAutoCString canonicalizedHostname(CanonicalizeHostname(hostname));
   nsTArray<nsCString> dynamicFingerprints;
   const TransportSecurityPreload* staticFingerprints = nullptr;
   nsresult rv = FindPinningInformation(canonicalizedHostname.get(), time,
-                                       dynamicFingerprints, staticFingerprints);
+                                       originAttributes, dynamicFingerprints,
+                                       staticFingerprints);
   if (NS_FAILED(rv)) {
     return rv;
   }
   if (dynamicFingerprints.Length() > 0) {
     hostHasPins = true;
   } else if (staticFingerprints) {
     hostHasPins = !staticFingerprints->mTestMode || enforceTestMode;
   }
--- a/security/manager/ssl/PublicKeyPinningService.h
+++ b/security/manager/ssl/PublicKeyPinningService.h
@@ -8,16 +8,22 @@
 #include "CertVerifier.h"
 #include "ScopedNSSTypes.h"
 #include "cert.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "pkix/Time.h"
 
 namespace mozilla {
+class OriginAttributes;
+}
+
+using mozilla::OriginAttributes;
+
+namespace mozilla {
 namespace psm {
 
 class PublicKeyPinningService
 {
 public:
   /**
    * Sets chainHasValidPins to true if the given (host, certList) passes pinning
    * checks, or to false otherwise. If the host is pinned, returns true via
@@ -26,16 +32,17 @@ public:
    * and the tail is the trust anchor.
    * Note: if an alt name is a wildcard, it won't necessarily find a pinset
    * that would otherwise be valid for it
    */
   static nsresult ChainHasValidPins(const UniqueCERTCertList& certList,
                                     const char* hostname,
                                     mozilla::pkix::Time time,
                                     bool enforceTestMode,
+                                    const OriginAttributes& originAttributes,
                             /*out*/ bool& chainHasValidPins,
                    /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo);
   /**
    * Sets chainMatchesPinset to true if there is any intersection between the
    * certificate list and the pins specified in the aSHA256keys array.
    * Values passed in are assumed to be in base64 encoded form.
    */
   static nsresult ChainMatchesPinset(const UniqueCERTCertList& certList,
@@ -45,16 +52,17 @@ public:
   /**
    * Returns true via the output parameter hostHasPins if there is pinning
    * information for the given host that is valid at the given time, and false
    * otherwise.
    */
   static nsresult HostHasPins(const char* hostname,
                               mozilla::pkix::Time time,
                               bool enforceTestMode,
+                              const OriginAttributes& originAttributes,
                       /*out*/ bool& hostHasPins);
 
   /**
    * Given a hostname of potentially mixed case with potentially multiple
    * trailing '.' (see bug 1118522), canonicalizes it to lowercase with no
    * trailing '.'.
    */
   static nsAutoCString CanonicalizeHostname(const char* hostname);
--- a/security/manager/ssl/SSLServerCertVerification.cpp
+++ b/security/manager/ssl/SSLServerCertVerification.cpp
@@ -519,27 +519,29 @@ CertErrorRunnable::CheckCertOverrides()
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
             ("[%p][%p] Creating new URI failed\n", mFdForLogging, this));
     return new SSLServerCertVerificationResult(mInfoObject,
                                                mDefaultErrorCodeToReport);
   }
   nsrv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS,
                           uri,
                           mProviderFlags,
+                          mInfoObject->GetOriginAttributes(),
                           nullptr,
                           &strictTransportSecurityEnabled);
   if (NS_FAILED(nsrv)) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
            ("[%p][%p] checking for HSTS failed\n", mFdForLogging, this));
     return new SSLServerCertVerificationResult(mInfoObject,
                                                mDefaultErrorCodeToReport);
   }
   nsrv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HPKP,
                           uri,
                           mProviderFlags,
+                          mInfoObject->GetOriginAttributes(),
                           nullptr,
                           &hasPinningInformation);
   if (NS_FAILED(nsrv)) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
            ("[%p][%p] checking for HPKP failed\n", mFdForLogging, this));
     return new SSLServerCertVerificationResult(mInfoObject,
                                                mDefaultErrorCodeToReport);
   }
--- a/security/manager/ssl/nsISiteSecurityService.idl
+++ b/security/manager/ssl/nsISiteSecurityService.idl
@@ -18,26 +18,30 @@ namespace mozilla
   namespace pkix
   {
     class Time;
   }
 }
 %}
 [ref] native nsCStringTArrayRef(nsTArray<nsCString>);
 [ref] native mozillaPkixTime(mozilla::pkix::Time);
+[ref] native const_OriginAttributesRef(const mozilla::OriginAttributes);
 
 // [infallible] attributes are only allowed on [builtinclass]
 [scriptable, uuid(31313372-842c-4110-bdf1-6aea17c845ad), builtinclass]
 interface nsISiteSecurityState : nsISupports
 {
   readonly attribute ACString hostname;
   [infallible] readonly attribute long long expireTime;
   [infallible] readonly attribute short securityPropertyState;
   [infallible] readonly attribute boolean includeSubdomains;
 
+  [implicit_jscontext]
+  readonly attribute jsval originAttributes;
+
   /*
    * SECURITY_PROPERTY_SET and SECURITY_PROPERTY_UNSET correspond to indicating
    * a site has or does not have the security property in question,
    * respectively.
    * SECURITY_PROPERTY_KNOCKOUT indicates a value on a preloaded
    * list is being overridden, and the associated site does not have the
    * security property in question.
    * SECURITY_PROPERTY_NEGATIVE is used when we've gotten a negative result from
@@ -98,65 +102,103 @@ interface nsISiteSecurityService : nsISu
      * in future HTTPS connections.
      *
      * @param aType the type of security header in question.
      * @param aSourceURI the URI of the resource with the HTTP header.
      * @param aHeader the HTTP response header specifying security data.
      * @param aSSLStatus the SSLStatus of the current channel.
      * @param aFlags  options for this request as defined in nsISocketProvider:
      *                  NO_PERMANENT_STORAGE
+     * @param aOriginAttributes the origin attributes that isolate this origin,
+     *                          (note that this implementation does not isolate
+     *                          by userContextId because of the risk of man-in-
+     *                          the-middle attacks before trust-on-second-use
+     *                          happens).
      * @param aMaxAge the parsed max-age directive of the header.
      * @param aIncludeSubdomains the parsed includeSubdomains directive.
      * @param aFailureResult a more specific failure result if NS_ERROR_FAILURE
                              was returned.
      * @return NS_OK            if it succeeds
      *         NS_ERROR_FAILURE if it can't be parsed
      *         NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA
      *                          if there are unrecognized tokens in the header.
      */
+    [binaryname(ProcessHeader), noscript]
+    void processHeaderNative(in uint32_t aType,
+                             in nsIURI aSourceURI,
+                             in ACString aHeader,
+                             in nsISSLStatus aSSLStatus,
+                             in uint32_t aFlags,
+                             in const_OriginAttributesRef aOriginAttributes,
+                             [optional] out unsigned long long aMaxAge,
+                             [optional] out boolean aIncludeSubdomains,
+                             [optional] out uint32_t aFailureResult);
+
+    [binaryname(ProcessHeaderScriptable), implicit_jscontext, optional_argc]
     void processHeader(in uint32_t aType,
                        in nsIURI aSourceURI,
                        in ACString aHeader,
                        in nsISSLStatus aSSLStatus,
                        in uint32_t aFlags,
+                       [optional] in jsval aOriginAttributes,
                        [optional] out unsigned long long aMaxAge,
                        [optional] out boolean aIncludeSubdomains,
                        [optional] out uint32_t aFailureResult);
 
     /**
      * Given a header type, removes state relating to that header of a host,
      * including the includeSubdomains state that would affect subdomains.
      * This essentially removes the state for the domain tree rooted at this
      * host.
      * @param aType   the type of security state in question
      * @param aURI    the URI of the target host
      * @param aFlags  options for this request as defined in nsISocketProvider:
      *                  NO_PERMANENT_STORAGE
+     * @param aOriginAttributes the origin attributes that isolate this origin,
+     *                          (note that this implementation does not isolate
+     *                          by userContextId because of the risk of man-in-
+     *                          the-middle attacks before trust-on-second-use
+     *                          happens).
      */
+    [implicit_jscontext, optional_argc]
     void removeState(in uint32_t aType,
                      in nsIURI aURI,
-                     in uint32_t aFlags);
+                     in uint32_t aFlags,
+                     [optional] in jsval aOriginAttributes);
 
     /**
      * Checks whether or not the URI's hostname has a given security state set.
      * For example, for HSTS:
      * The URI is an HSTS URI if either the host has the HSTS state set, or one
      * of its super-domains has the HSTS "includeSubdomains" flag set.
      * NOTE: this function makes decisions based only on the
      * host contained in the URI, and disregards other portions of the URI
      * such as path and port.
      *
      * @param aType the type of security state in question.
      * @param aURI the URI to query for STS state.
      * @param aFlags  options for this request as defined in nsISocketProvider:
      *                  NO_PERMANENT_STORAGE
+     * @param aOriginAttributes the origin attributes that isolate this origin,
+     *                          (note that this implementation does not isolate
+     *                          by userContextId because of the risk of man-in-
+     *                          the-middle attacks before trust-on-second-use
+     *                          happens).
      * @param aCached true if we have cached information regarding whether or not
      *                  the host is HSTS, false otherwise.
      */
+    [binaryname(IsSecureURI), noscript]
+    boolean isSecureURINative(in uint32_t aType, in nsIURI aURI,
+                              in uint32_t aFlags,
+                              in const_OriginAttributesRef aOriginAttributes,
+                              [optional] out boolean aCached);
+
+    [binaryname(IsSecureURIScriptable), implicit_jscontext, optional_argc]
     boolean isSecureURI(in uint32_t aType, in nsIURI aURI, in uint32_t aFlags,
+                        [optional] in jsval aOriginAttributes,
                         [optional] out boolean aCached);
 
     /**
      * Removes all non-preloaded security state by resetting to factory-original
      * settings.
      */
     void clearAll();
 
@@ -169,64 +211,86 @@ interface nsISiteSecurityService : nsISu
      * Returns an array of sha256-hashed key pins for the given domain, if any.
      * If these pins also apply to subdomains of the given domain,
      * aIncludeSubdomains will be true. Pins returned are only for non-built-in
      * pin entries.
      *
      * @param aHostname the hostname (punycode) to be queried about
      * @param evalTime the time at which the pins should be valid. This is in
               mozilla::pkix::Time which uses internally seconds since 0 AD.
+     * @param aOriginAttributes the origin attributes that isolate this origin,
+     *                          (note that this implementation does not isolate
+     *                          by userContextId because of the risk of man-in-
+     *                          the-middle attacks before trust-on-second-use
+     *                          happens).
      * @param aPinArray the set of sha256-hashed key pins for the given domain
      * @param aIncludeSubdomains true if the pins apply to subdomains of the
      *        given domain
      */
-    [noscript] boolean getKeyPinsForHostname(in ACString aHostname,
-                                             in mozillaPkixTime evalTime,
-                                             out nsCStringTArrayRef aPinArray,
-                                             out boolean aIncludeSubdomains);
+    [noscript] boolean getKeyPinsForHostname(
+      in ACString aHostname,
+      in mozillaPkixTime evalTime,
+      in const_OriginAttributesRef aOriginAttributes,
+      out nsCStringTArrayRef aPinArray,
+      out boolean aIncludeSubdomains);
 
     /**
      * Set public-key pins for a host. The resulting pins will be permanent
      * and visible from private and non-private contexts. These pins replace
      * any already set by this mechanism or those built-in to Gecko.
      *
      * @param aHost the hostname (punycode) that pins will apply to
      * @param aIncludeSubdomains whether these pins also apply to subdomains
      * @param aExpires the time this pin should expire (millis since epoch)
      * @param aPinCount number of keys being pinnned
      * @param aSha256Pins array of hashed key fingerprints (SHA-256, base64)
      * @param aIsPreload are these key pins for a preload entry? (false by
      *        default)
+     * @param aOriginAttributes the origin attributes that isolate this origin,
+     *                          (note that this implementation does not isolate
+     *                          by userContextId because of the risk of man-in-
+     *                          the-middle attacks before trust-on-second-use
+     *                          happens).
      */
-     boolean setKeyPins(in ACString aHost, in boolean aIncludeSubdomains,
-                        in int64_t aExpires, in unsigned long aPinCount,
-                        [array, size_is(aPinCount)] in string aSha256Pins,
-                        [optional] in boolean aIsPreload);
+    [implicit_jscontext, optional_argc]
+    boolean setKeyPins(in ACString aHost, in boolean aIncludeSubdomains,
+                       in int64_t aExpires, in unsigned long aPinCount,
+                       [array, size_is(aPinCount)] in string aSha256Pins,
+                       [optional] in boolean aIsPreload,
+                       [optional] in jsval aOriginAttributes);
 
     /**
      * Set an HSTS preload entry for a host. The resulting entries will be
      * permanent and visible from private and non-private contexts. These
      * entries replace any already set by this mechanism or those built-in to
      * Gecko.
      *
      * @param aHost the hostname (punycode) that the entry applies to
      * @param aIncludeSubdomains whether this entry also applies to subdomains
      * @param aExpires the time this entry should expire (millis since epoch)
      */
-     boolean setHSTSPreload(in ACString aHost, in boolean aIncludesSubdomains,
-                            in int64_t aExpires);
+    boolean setHSTSPreload(in ACString aHost,
+                           in boolean aIncludesSubdomains,
+                           in int64_t aExpires);
 
     /**
      * Mark a host as declining to provide a given security state so that features
      * such as HSTS priming will not flood a server with requests.
      *
      * @param aURI the nsIURI that this applies to
      * @param aMaxAge lifetime (in seconds) of this negative cache
+     * @param aOriginAttributes the origin attributes that isolate this origin,
+     *                          (note that this implementation does not isolate
+     *                          by userContextId because of the risk of man-in-
+     *                          the-middle attacks before trust-on-second-use
+     *                          happens).
      */
-    [noscript] void cacheNegativeHSTSResult(in nsIURI aURI, in unsigned long long aMaxAge);
+    [noscript] void cacheNegativeHSTSResult(
+      in nsIURI aURI, in unsigned long long aMaxAge,
+      in const_OriginAttributesRef aOriginAttributes);
 
     /**
      * Returns an enumerator of the nsISiteSecurityService storage. Each item in
      * the enumeration is a nsISiteSecurityState that can be QueryInterfaced to
      * the appropriate nsISiteHSTSState or nsISiteHPKPState, depending on the
      * provided type. Doesn't include preloaded entries (either the hard-coded
      * ones or the preloaded-delivered-by-kinto ones).
      *
--- a/security/manager/ssl/nsSiteSecurityService.cpp
+++ b/security/manager/ssl/nsSiteSecurityService.cpp
@@ -7,23 +7,25 @@
 #include "CertVerifier.h"
 #include "PublicKeyPinningService.h"
 #include "ScopedNSSTypes.h"
 #include "SharedCertVerifier.h"
 #include "base64.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Base64.h"
 #include "mozilla/dom/PContent.h"
+#include "mozilla/dom/ToJSValue.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Preferences.h"
 #include "nsArrayEnumerator.h"
 #include "nsCOMArray.h"
 #include "nsCRTGlue.h"
 #include "nsISSLStatus.h"
+#include "nsIScriptSecurityManager.h"
 #include "nsISocketProvider.h"
 #include "nsIURI.h"
 #include "nsIX509Cert.h"
 #include "nsNSSComponent.h"
 #include "nsNetUtil.h"
 #include "nsPromiseFlatString.h"
 #include "nsReadableUtils.h"
 #include "nsSecurityHeaderParser.h"
@@ -53,18 +55,20 @@ static LazyLogModule gSSSLog("nsSSServic
 const char kHSTSKeySuffix[] = ":HSTS";
 const char kHPKPKeySuffix[] = ":HPKP";
 
 ////////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_ISUPPORTS(SiteHSTSState, nsISiteSecurityState, nsISiteHSTSState)
 
 SiteHSTSState::SiteHSTSState(const nsCString& aHost,
+                             const OriginAttributes& aOriginAttributes,
                              const nsCString& aStateString)
   : mHostname(aHost)
+  , mOriginAttributes(aOriginAttributes)
   , mHSTSExpireTime(0)
   , mHSTSState(SecurityPropertyUnset)
   , mHSTSIncludeSubdomains(false)
 {
   uint32_t hstsState = 0;
   uint32_t hstsIncludeSubdomains = 0; // PR_sscanf doesn't handle bools.
   int32_t matches = PR_sscanf(aStateString.get(), "%lld,%lu,%lu",
                               &mHSTSExpireTime, &hstsState,
@@ -82,21 +86,23 @@ SiteHSTSState::SiteHSTSState(const nsCSt
     SSSLOG(("%s is not a valid SiteHSTSState", aStateString.get()));
     mHSTSExpireTime = 0;
     mHSTSState = SecurityPropertyUnset;
     mHSTSIncludeSubdomains = false;
   }
 }
 
 SiteHSTSState::SiteHSTSState(const nsCString& aHost,
+                             const OriginAttributes& aOriginAttributes,
                              PRTime aHSTSExpireTime,
                              SecurityPropertyState aHSTSState,
                              bool aHSTSIncludeSubdomains)
 
   : mHostname(aHost)
+  , mOriginAttributes(aOriginAttributes)
   , mHSTSExpireTime(aHSTSExpireTime)
   , mHSTSState(aHSTSState)
   , mHSTSIncludeSubdomains(aHSTSIncludeSubdomains)
 {
 }
 
 void
 SiteHSTSState::ToString(nsCString& aString)
@@ -135,16 +141,26 @@ SiteHSTSState::GetSecurityPropertyState(
 NS_IMETHODIMP
 SiteHSTSState::GetIncludeSubdomains(bool* aIncludeSubdomains)
 {
   NS_ENSURE_ARG(aIncludeSubdomains);
   *aIncludeSubdomains = mHSTSIncludeSubdomains;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+SiteHSTSState::GetOriginAttributes(JSContext* aCx,
+  JS::MutableHandle<JS::Value> aOriginAttributes)
+{
+  if (!ToJSValue(aCx, mOriginAttributes, aOriginAttributes)) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_ISUPPORTS(SiteHPKPState, nsISiteSecurityState, nsISiteHPKPState)
 
 static bool
 stringIsBase64EncodingOf256bitValue(nsCString& encodedString) {
   nsAutoCString binaryValue;
   nsresult rv = mozilla::Base64Decode(encodedString, binaryValue);
@@ -160,18 +176,20 @@ stringIsBase64EncodingOf256bitValue(nsCS
 SiteHPKPState::SiteHPKPState()
   : mExpireTime(0)
   , mState(SecurityPropertyUnset)
   , mIncludeSubdomains(false)
 {
 }
 
 SiteHPKPState::SiteHPKPState(const nsCString& aHost,
+                             const OriginAttributes& aOriginAttributes,
                              const nsCString& aStateString)
   : mHostname(aHost)
+  , mOriginAttributes(aOriginAttributes)
   , mExpireTime(0)
   , mState(SecurityPropertyUnset)
   , mIncludeSubdomains(false)
 {
   uint32_t hpkpState = 0;
   uint32_t hpkpIncludeSubdomains = 0; // PR_sscanf doesn't handle bools.
   const uint32_t MaxMergedHPKPPinSize = 1024;
   char mergedHPKPins[MaxMergedHPKPPinSize];
@@ -223,21 +241,23 @@ SiteHPKPState::SiteHPKPState(const nsCSt
     mIncludeSubdomains = false;
     if (!mSHA256keys.IsEmpty()) {
       mSHA256keys.Clear();
     }
   }
 }
 
 SiteHPKPState::SiteHPKPState(const nsCString& aHost,
+                             const OriginAttributes& aOriginAttributes,
                              PRTime aExpireTime,
                              SecurityPropertyState aState,
                              bool aIncludeSubdomains,
                              nsTArray<nsCString>& aSHA256keys)
   : mHostname(aHost)
+  , mOriginAttributes(aOriginAttributes)
   , mExpireTime(aExpireTime)
   , mState(aState)
   , mIncludeSubdomains(aIncludeSubdomains)
   , mSHA256keys(aSHA256keys)
 {
 }
 
 NS_IMETHODIMP
@@ -300,16 +320,26 @@ SiteHPKPState::GetSha256Keys(nsISimpleEn
     }
     if (!keys.AppendObject(variant)) {
       return NS_ERROR_FAILURE;
     }
   }
   return NS_NewArrayEnumerator(aSha256Keys, keys);
 }
 
+NS_IMETHODIMP
+SiteHPKPState::GetOriginAttributes(JSContext* aCx,
+  JS::MutableHandle<JS::Value> aOriginAttributes)
+{
+  if (!ToJSValue(aCx, mOriginAttributes, aOriginAttributes)) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 const uint64_t kSixtyDaysInSeconds = 60 * 24 * 60 * 60;
 
 nsSiteSecurityService::nsSiteSecurityService()
   : mMaxMaxAge(kSixtyDaysInSeconds)
   , mUsePreloadList(true)
   , mPreloadListTimeOffset(0)
@@ -391,19 +421,29 @@ nsSiteSecurityService::GetHost(nsIURI* a
   if (aResult.IsEmpty()) {
     return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
 }
 
 static void
-SetStorageKey(nsAutoCString& storageKey, const nsACString& hostname, uint32_t aType)
+SetStorageKey(const nsACString& hostname, uint32_t aType,
+              const OriginAttributes& aOriginAttributes,
+              /*out*/ nsAutoCString& storageKey)
 {
   storageKey = hostname;
+
+  // Don't isolate by userContextId.
+  OriginAttributes originAttributesNoUserContext = aOriginAttributes;
+  originAttributesNoUserContext.mUserContextId =
+    nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID;
+  nsAutoCString originAttributesSuffix;
+  originAttributesNoUserContext.CreateSuffix(originAttributesSuffix);
+  storageKey.Append(originAttributesSuffix);
   switch (aType) {
     case nsISiteSecurityService::HEADER_HSTS:
       storageKey.AppendASCII(kHSTSKeySuffix);
       break;
     case nsISiteSecurityService::HEADER_HPKP:
       storageKey.AppendASCII(kHPKPKeySuffix);
       break;
     default:
@@ -421,97 +461,121 @@ ExpireTimeFromMaxAge(uint64_t maxAge)
 
 nsresult
 nsSiteSecurityService::SetHSTSState(uint32_t aType,
                                     const char* aHost,
                                     int64_t maxage,
                                     bool includeSubdomains,
                                     uint32_t flags,
                                     SecurityPropertyState aHSTSState,
-                                    bool aIsPreload)
+                                    bool aIsPreload,
+                                    const OriginAttributes& aOriginAttributes)
 {
   nsAutoCString hostname(aHost);
   // If max-age is zero, that's an indication to immediately remove the
   // security state, so here's a shortcut.
   if (!maxage) {
-    return RemoveStateInternal(aType, hostname, flags, aIsPreload);
+    return RemoveStateInternal(aType, hostname, flags, aIsPreload,
+                               aOriginAttributes);
   }
 
   MOZ_ASSERT((aHSTSState == SecurityPropertySet ||
               aHSTSState == SecurityPropertyNegative),
       "HSTS State must be SecurityPropertySet or SecurityPropertyNegative");
+  if (aIsPreload && aOriginAttributes != OriginAttributes()) {
+    return NS_ERROR_INVALID_ARG;
+  }
 
   int64_t expiretime = ExpireTimeFromMaxAge(maxage);
-  RefPtr<SiteHSTSState> siteState =
-    new SiteHSTSState(hostname, expiretime, aHSTSState, includeSubdomains);
+  RefPtr<SiteHSTSState> siteState = new SiteHSTSState(
+    hostname, aOriginAttributes, expiretime, aHSTSState, includeSubdomains);
   nsAutoCString stateString;
   siteState->ToString(stateString);
   SSSLOG(("SSS: setting state for %s", hostname.get()));
   bool isPrivate = flags & nsISocketProvider::NO_PERMANENT_STORAGE;
   mozilla::DataStorageType storageType = isPrivate
                                          ? mozilla::DataStorage_Private
                                          : mozilla::DataStorage_Persistent;
   nsAutoCString storageKey;
-  SetStorageKey(storageKey, hostname, aType);
+  SetStorageKey(hostname, aType, aOriginAttributes, storageKey);
   nsresult rv;
   if (aIsPreload) {
     SSSLOG(("SSS: storing entry for %s in dynamic preloads", hostname.get()));
     rv = mPreloadStateStorage->Put(storageKey, stateString,
                                    mozilla::DataStorage_Persistent);
   } else {
     SSSLOG(("SSS: storing HSTS site entry for %s", hostname.get()));
     rv = mSiteStateStorage->Put(storageKey, stateString, storageType);
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSiteSecurityService::CacheNegativeHSTSResult(nsIURI* aSourceURI,
-                                               uint64_t aMaxAge)
+nsSiteSecurityService::CacheNegativeHSTSResult(
+  nsIURI* aSourceURI,
+  uint64_t aMaxAge,
+  const OriginAttributes& aOriginAttributes)
 {
   nsAutoCString hostname;
   nsresult rv = GetHost(aSourceURI, hostname);
   NS_ENSURE_SUCCESS(rv, rv);
   return SetHSTSState(nsISiteSecurityService::HEADER_HSTS, hostname.get(),
-                      aMaxAge, false, 0, SecurityPropertyNegative, false);
+                      aMaxAge, false, 0, SecurityPropertyNegative, false,
+                      aOriginAttributes);
 }
 
 nsresult
-nsSiteSecurityService::RemoveStateInternal(uint32_t aType,
-                                           const nsAutoCString& aHost,
-                                           uint32_t aFlags, bool aIsPreload)
+nsSiteSecurityService::RemoveStateInternal(
+  uint32_t aType, nsIURI* aURI, uint32_t aFlags,
+  const OriginAttributes& aOriginAttributes)
+{
+  nsAutoCString hostname;
+  GetHost(aURI, hostname);
+  return RemoveStateInternal(aType, hostname, aFlags, false, aOriginAttributes);
+}
+
+nsresult
+nsSiteSecurityService::RemoveStateInternal(
+  uint32_t aType,
+  const nsAutoCString& aHost,
+  uint32_t aFlags, bool aIsPreload,
+  const OriginAttributes& aOriginAttributes)
 {
    // Child processes are not allowed direct access to this.
    if (!XRE_IsParentProcess()) {
      MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::RemoveStateInternal");
    }
 
   // Only HSTS is supported at the moment.
   NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
                  aType == nsISiteSecurityService::HEADER_HPKP,
                  NS_ERROR_NOT_IMPLEMENTED);
+  if (aIsPreload && aOriginAttributes != OriginAttributes()) {
+    return NS_ERROR_INVALID_ARG;
+  }
 
   bool isPrivate = aFlags & nsISocketProvider::NO_PERMANENT_STORAGE;
   mozilla::DataStorageType storageType = isPrivate
                                          ? mozilla::DataStorage_Private
                                          : mozilla::DataStorage_Persistent;
   // If this host is in the preload list, we have to store a knockout entry.
   nsAutoCString storageKey;
-  SetStorageKey(storageKey, aHost, aType);
+  SetStorageKey(aHost, aType, aOriginAttributes, storageKey);
 
   nsCString value = mPreloadStateStorage->Get(storageKey,
                                               mozilla::DataStorage_Persistent);
-  RefPtr<SiteHSTSState> dynamicState = new SiteHSTSState(aHost, value);
+  RefPtr<SiteHSTSState> dynamicState =
+    new SiteHSTSState(aHost, aOriginAttributes, value);
   if (GetPreloadListEntry(aHost.get()) ||
       dynamicState->mHSTSState != SecurityPropertyUnset) {
     SSSLOG(("SSS: storing knockout entry for %s", aHost.get()));
-    RefPtr<SiteHSTSState> siteState =
-      new SiteHSTSState(aHost, 0, SecurityPropertyKnockout, false);
+    RefPtr<SiteHSTSState> siteState = new SiteHSTSState(
+      aHost, aOriginAttributes, 0, SecurityPropertyKnockout, false);
     nsAutoCString stateString;
     siteState->ToString(stateString);
     nsresult rv;
     if (aIsPreload) {
       rv = mPreloadStateStorage->Put(storageKey, stateString,
                                      mozilla::DataStorage_Persistent);
     } else {
       rv = mSiteStateStorage->Put(storageKey, stateString, storageType);
@@ -526,37 +590,72 @@ nsSiteSecurityService::RemoveStateIntern
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI,
-                                   uint32_t aFlags)
+                                   uint32_t aFlags,
+                                   JS::HandleValue aOriginAttributes,
+                                   JSContext* aCx, uint8_t aArgc)
 {
-  nsAutoCString hostname;
-  GetHost(aURI, hostname);
-  return RemoveStateInternal(aType, hostname, aFlags, false);
+  OriginAttributes originAttributes;
+  if (aArgc > 0) {
+    // OriginAttributes were passed in.
+    if (!aOriginAttributes.isObject() ||
+        !originAttributes.Init(aCx, aOriginAttributes)) {
+      return NS_ERROR_INVALID_ARG;
+    }
+  }
+  return RemoveStateInternal(aType, aURI, aFlags, originAttributes);
 }
 
 static bool
 HostIsIPAddress(const nsCString& hostname)
 {
   PRNetAddr hostAddr;
   PRErrorCode prv = PR_StringToNetAddr(hostname.get(), &hostAddr);
   return (prv == PR_SUCCESS);
 }
 
 NS_IMETHODIMP
+nsSiteSecurityService::ProcessHeaderScriptable(
+  uint32_t aType,
+  nsIURI* aSourceURI,
+  const nsACString& aHeader,
+  nsISSLStatus* aSSLStatus,
+  uint32_t aFlags,
+  JS::HandleValue aOriginAttributes,
+  uint64_t* aMaxAge,
+  bool* aIncludeSubdomains,
+  uint32_t* aFailureResult,
+  JSContext* aCx,
+  uint8_t aArgc)
+{
+  OriginAttributes originAttributes;
+  if (aArgc > 0) {
+    if (!aOriginAttributes.isObject() ||
+        !originAttributes.Init(aCx, aOriginAttributes)) {
+      return NS_ERROR_INVALID_ARG;
+    }
+  }
+  return ProcessHeader(aType, aSourceURI, aHeader, aSSLStatus, aFlags,
+                       originAttributes, aMaxAge, aIncludeSubdomains,
+                       aFailureResult);
+}
+
+NS_IMETHODIMP
 nsSiteSecurityService::ProcessHeader(uint32_t aType,
                                      nsIURI* aSourceURI,
                                      const nsACString& aHeader,
                                      nsISSLStatus* aSSLStatus,
                                      uint32_t aFlags,
+                                     const OriginAttributes& aOriginAttributes,
                                      uint64_t* aMaxAge,
                                      bool* aIncludeSubdomains,
                                      uint32_t* aFailureResult)
 {
   // Child processes are not allowed direct access to this.
   if (!XRE_IsParentProcess()) {
     MOZ_CRASH("Child process: no direct access to "
               "nsISiteSecurityService::ProcessHeader");
@@ -566,29 +665,31 @@ nsSiteSecurityService::ProcessHeader(uin
     *aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
   }
   NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
                  aType == nsISiteSecurityService::HEADER_HPKP,
                  NS_ERROR_NOT_IMPLEMENTED);
 
   NS_ENSURE_ARG(aSSLStatus);
   return ProcessHeaderInternal(aType, aSourceURI, PromiseFlatCString(aHeader),
-                               aSSLStatus, aFlags, aMaxAge, aIncludeSubdomains,
-                               aFailureResult);
+                               aSSLStatus, aFlags, aOriginAttributes, aMaxAge,
+                               aIncludeSubdomains, aFailureResult);
 }
 
 nsresult
-nsSiteSecurityService::ProcessHeaderInternal(uint32_t aType,
-                                             nsIURI* aSourceURI,
-                                             const nsCString& aHeader,
-                                             nsISSLStatus* aSSLStatus,
-                                             uint32_t aFlags,
-                                             uint64_t* aMaxAge,
-                                             bool* aIncludeSubdomains,
-                                             uint32_t* aFailureResult)
+nsSiteSecurityService::ProcessHeaderInternal(
+  uint32_t aType,
+  nsIURI* aSourceURI,
+  const nsCString& aHeader,
+  nsISSLStatus* aSSLStatus,
+  uint32_t aFlags,
+  const OriginAttributes& aOriginAttributes,
+  uint64_t* aMaxAge,
+  bool* aIncludeSubdomains,
+  uint32_t* aFailureResult)
 {
   if (aFailureResult) {
     *aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
   }
   // Only HSTS and HPKP are supported at the moment.
   NS_ENSURE_TRUE(aType == nsISiteSecurityService::HEADER_HSTS ||
                  aType == nsISiteSecurityService::HEADER_HPKP,
                  NS_ERROR_NOT_IMPLEMENTED);
@@ -630,22 +731,23 @@ nsSiteSecurityService::ProcessHeaderInte
   NS_ENSURE_SUCCESS(rv, rv);
   if (HostIsIPAddress(host)) {
     /* Don't process headers if a site is accessed by IP address. */
     return NS_OK;
   }
 
   switch (aType) {
     case nsISiteSecurityService::HEADER_HSTS:
-      rv = ProcessSTSHeader(aSourceURI, aHeader, aFlags, aMaxAge,
+      rv = ProcessSTSHeader(aSourceURI, aHeader, aFlags, aOriginAttributes, aMaxAge,
                             aIncludeSubdomains, aFailureResult);
       break;
     case nsISiteSecurityService::HEADER_HPKP:
-      rv = ProcessPKPHeader(aSourceURI, aHeader, aSSLStatus, aFlags, aMaxAge,
-                            aIncludeSubdomains, aFailureResult);
+      rv = ProcessPKPHeader(aSourceURI, aHeader, aSSLStatus, aFlags,
+                            aOriginAttributes, aMaxAge, aIncludeSubdomains,
+                            aFailureResult);
       break;
     default:
       MOZ_CRASH("unexpected header type");
   }
   return rv;
 }
 
 static uint32_t
@@ -785,23 +887,25 @@ ParseSSSHeaders(uint32_t aType,
               directive->mName.get()));
       foundUnrecognizedDirective = true;
     }
   }
   return nsISiteSecurityService::Success;
 }
 
 nsresult
-nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
-                                        const nsCString& aHeader,
-                                        nsISSLStatus* aSSLStatus,
-                                        uint32_t aFlags,
-                                        uint64_t* aMaxAge,
-                                        bool* aIncludeSubdomains,
-                                        uint32_t* aFailureResult)
+nsSiteSecurityService::ProcessPKPHeader(
+  nsIURI* aSourceURI,
+  const nsCString& aHeader,
+  nsISSLStatus* aSSLStatus,
+  uint32_t aFlags,
+  const OriginAttributes& aOriginAttributes,
+  uint64_t* aMaxAge,
+  bool* aIncludeSubdomains,
+  uint32_t* aFailureResult)
 {
   if (aFailureResult) {
     *aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
   }
   SSSLOG(("SSS: processing HPKP header '%s'", aHeader.get()));
   NS_ENSURE_ARG(aSSLStatus);
 
   const uint32_t aType = nsISiteSecurityService::HEADER_HPKP;
@@ -858,17 +962,18 @@ nsSiteSecurityService::ProcessPKPHeader(
                               CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
   if (certVerifier->VerifySSLServerCert(nssCert,
                                         nullptr, // stapledOCSPResponse
                                         nullptr, // sctsFromTLSExtension
                                         now, nullptr, // pinarg
                                         host.get(), // hostname
                                         certList,
                                         false, // don't store intermediates
-                                        flags)
+                                        flags,
+                                        aOriginAttributes)
         != mozilla::pkix::Success) {
     return NS_ERROR_FAILURE;
   }
 
   CERTCertListNode* rootNode = CERT_LIST_TAIL(certList);
   if (CERT_LIST_END(rootNode, certList)) {
     return NS_ERROR_FAILURE;
   }
@@ -882,17 +987,17 @@ nsSiteSecurityService::ProcessPKPHeader(
     if (aFailureResult) {
       *aFailureResult = nsISiteSecurityService::ERROR_ROOT_NOT_BUILT_IN;
     }
     return NS_ERROR_FAILURE;
   }
 
   // if maxAge == 0 we must delete all state, for now no hole-punching
   if (maxAge == 0) {
-    return RemoveState(aType, aSourceURI, aFlags);
+    return RemoveStateInternal(aType, aSourceURI, aFlags, aOriginAttributes);
   }
 
   // clamp maxAge to the maximum set by pref
   if (maxAge > mMaxMaxAge) {
     maxAge = mMaxMaxAge;
   }
 
   bool chainMatchesPinset;
@@ -932,22 +1037,22 @@ nsSiteSecurityService::ProcessPKPHeader(
     if (aFailureResult) {
       *aFailureResult = nsISiteSecurityService::ERROR_NO_BACKUP_PIN;
     }
     return NS_ERROR_FAILURE;
   }
 
   int64_t expireTime = ExpireTimeFromMaxAge(maxAge);
   RefPtr<SiteHPKPState> dynamicEntry =
-    new SiteHPKPState(host, expireTime, SecurityPropertySet,
+    new SiteHPKPState(host, aOriginAttributes, expireTime, SecurityPropertySet,
                       foundIncludeSubdomains, sha256keys);
   SSSLOG(("SSS: about to set pins for  %s, expires=%" PRId64 " now=%" PRId64 " maxAge=%" PRIu64 "\n",
            host.get(), expireTime, PR_Now() / PR_USEC_PER_MSEC, maxAge));
 
-  rv = SetHPKPState(host.get(), *dynamicEntry, aFlags, false);
+  rv = SetHPKPState(host.get(), *dynamicEntry, aFlags, false, aOriginAttributes);
   if (NS_FAILED(rv)) {
     SSSLOG(("SSS: failed to set pins for %s\n", host.get()));
     if (aFailureResult) {
       *aFailureResult = nsISiteSecurityService::ERROR_COULD_NOT_SAVE_STATE;
     }
     return rv;
   }
 
@@ -960,22 +1065,24 @@ nsSiteSecurityService::ProcessPKPHeader(
   }
 
   return foundUnrecognizedDirective
            ? NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA
            : NS_OK;
 }
 
 nsresult
-nsSiteSecurityService::ProcessSTSHeader(nsIURI* aSourceURI,
-                                        const nsCString& aHeader,
-                                        uint32_t aFlags,
-                                        uint64_t* aMaxAge,
-                                        bool* aIncludeSubdomains,
-                                        uint32_t* aFailureResult)
+nsSiteSecurityService::ProcessSTSHeader(
+  nsIURI* aSourceURI,
+  const nsCString& aHeader,
+  uint32_t aFlags,
+  const OriginAttributes& aOriginAttributes,
+  uint64_t* aMaxAge,
+  bool* aIncludeSubdomains,
+  uint32_t* aFailureResult)
 {
   if (aFailureResult) {
     *aFailureResult = nsISiteSecurityService::ERROR_UNKNOWN;
   }
   SSSLOG(("SSS: processing HSTS header '%s'", aHeader.get()));
 
   const uint32_t aType = nsISiteSecurityService::HEADER_HSTS;
   bool foundMaxAge = false;
@@ -1005,17 +1112,17 @@ nsSiteSecurityService::ProcessSTSHeader(
   }
 
   nsAutoCString hostname;
   nsresult rv = GetHost(aSourceURI, hostname);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // record the successfully parsed header data.
   rv = SetHSTSState(aType, hostname.get(), maxAge, foundIncludeSubdomains,
-                    aFlags, SecurityPropertySet, false);
+                    aFlags, SecurityPropertySet, false, aOriginAttributes);
   if (NS_FAILED(rv)) {
     SSSLOG(("SSS: failed to set STS state"));
     if (aFailureResult) {
       *aFailureResult = nsISiteSecurityService::ERROR_COULD_NOT_SAVE_STATE;
     }
     return rv;
   }
 
@@ -1028,19 +1135,37 @@ nsSiteSecurityService::ProcessSTSHeader(
   }
 
   return foundUnrecognizedDirective
            ? NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA
            : NS_OK;
 }
 
 NS_IMETHODIMP
+nsSiteSecurityService::IsSecureURIScriptable(uint32_t aType, nsIURI* aURI,
+                                             uint32_t aFlags,
+                                             JS::HandleValue aOriginAttributes,
+                                             bool* aCached, JSContext* aCx,
+                                             uint8_t aArgc,  bool* aResult)
+{
+  OriginAttributes originAttributes;
+  if (aArgc > 0) {
+    if (!aOriginAttributes.isObject() ||
+        !originAttributes.Init(aCx, aOriginAttributes)) {
+      return NS_ERROR_INVALID_ARG;
+    }
+  }
+  return IsSecureURI(aType, aURI, aFlags, originAttributes, aCached, aResult);
+}
+
+NS_IMETHODIMP
 nsSiteSecurityService::IsSecureURI(uint32_t aType, nsIURI* aURI,
-                                   uint32_t aFlags, bool* aCached,
-                                   bool* aResult)
+                                   uint32_t aFlags,
+                                   const OriginAttributes& aOriginAttributes,
+                                   bool* aCached, bool* aResult)
 {
    // Child processes are not allowed direct access to this.
    if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
      MOZ_CRASH("Child process: no direct access to nsISiteSecurityService::IsSecureURI for non-HSTS entries");
    }
 
   NS_ENSURE_ARG(aURI);
   NS_ENSURE_ARG(aResult);
@@ -1054,17 +1179,18 @@ nsSiteSecurityService::IsSecureURI(uint3
   nsresult rv = GetHost(aURI, hostname);
   NS_ENSURE_SUCCESS(rv, rv);
   /* An IP address never qualifies as a secure URI. */
   if (HostIsIPAddress(hostname)) {
     *aResult = false;
     return NS_OK;
   }
 
-  return IsSecureHost(aType, hostname, aFlags, aCached, aResult);
+  return IsSecureHost(aType, hostname, aFlags, aOriginAttributes, aCached,
+                      aResult);
 }
 
 int STSPreloadCompare(const void *key, const void *entry)
 {
   const char *keyStr = (const char *)key;
   const nsSTSPreload *preloadEntry = (const nsSTSPreload *)entry;
   return strcmp(keyStr, &kSTSHostTable[preloadEntry->mHostIndex]);
 }
@@ -1089,36 +1215,40 @@ nsSiteSecurityService::GetPreloadListEnt
 
 // Allows us to determine if we have an HSTS entry for a given host (and, if
 // so, what that state is). The return value says whether or not we know
 // anything about this host (true if the host has an HSTS entry). aHost is
 // the host which we wish to deteming HSTS information on,
 // aRequireIncludeSubdomains specifies whether we require includeSubdomains
 // to be set on the entry (with the other parameters being as per IsSecureHost).
 bool
-nsSiteSecurityService::HostHasHSTSEntry(const nsAutoCString& aHost,
-                                        bool aRequireIncludeSubdomains,
-                                        uint32_t aFlags, bool* aResult,
-                                        bool* aCached)
+nsSiteSecurityService::HostHasHSTSEntry(
+  const nsAutoCString& aHost, bool aRequireIncludeSubdomains, uint32_t aFlags,
+  const OriginAttributes& aOriginAttributes, bool* aResult, bool* aCached)
 {
   // First we check for an entry in site security storage. If that entry exists,
   // we don't want to check in the preload lists. We only want to use the
   // stored value if it is not a knockout entry, however.
   // Additionally, if it is a knockout entry, we want to stop looking for data
   // on the host, because the knockout entry indicates "we have no information
   // regarding the security status of this host".
   bool isPrivate = aFlags & nsISocketProvider::NO_PERMANENT_STORAGE;
   mozilla::DataStorageType storageType = isPrivate
                                          ? mozilla::DataStorage_Private
                                          : mozilla::DataStorage_Persistent;
   nsAutoCString storageKey;
   SSSLOG(("Seeking HSTS entry for %s", aHost.get()));
-  SetStorageKey(storageKey, aHost, nsISiteSecurityService::HEADER_HSTS);
+  SetStorageKey(aHost, nsISiteSecurityService::HEADER_HSTS, aOriginAttributes,
+                storageKey);
+  nsAutoCString preloadKey;
+  SetStorageKey(aHost, nsISiteSecurityService::HEADER_HSTS, OriginAttributes(),
+                preloadKey);
   nsCString value = mSiteStateStorage->Get(storageKey, storageType);
-  RefPtr<SiteHSTSState> siteState = new SiteHSTSState(aHost, value);
+  RefPtr<SiteHSTSState> siteState =
+    new SiteHSTSState(aHost, aOriginAttributes, value);
   if (siteState->mHSTSState != SecurityPropertyUnset) {
     SSSLOG(("Found HSTS entry for %s", aHost.get()));
     bool expired = siteState->IsExpired(nsISiteSecurityService::HEADER_HSTS);
     if (!expired) {
       SSSLOG(("Entry for %s is not expired", aHost.get()));
       if (aCached) {
         *aCached = true;
       }
@@ -1132,52 +1262,54 @@ nsSiteSecurityService::HostHasHSTSEntry(
       }
     }
 
     if (expired) {
       SSSLOG(("Entry %s is expired - checking for preload state", aHost.get()));
       // If the entry is expired and is not in either the static or dynamic
       // preload lists, we can remove it.
       // First, check the dynamic preload list.
-      value = mPreloadStateStorage->Get(storageKey,
+      value = mPreloadStateStorage->Get(preloadKey,
                                         mozilla::DataStorage_Persistent);
-      RefPtr<SiteHSTSState> dynamicState = new SiteHSTSState(aHost, value);
+      RefPtr<SiteHSTSState> dynamicState =
+        new SiteHSTSState(aHost, aOriginAttributes, value);
       if (dynamicState->mHSTSState == SecurityPropertyUnset) {
         SSSLOG(("No dynamic preload - checking for static preload"));
         // Now check the static preload list.
         if (!GetPreloadListEntry(aHost.get())) {
           SSSLOG(("No static preload - removing expired entry"));
           mSiteStateStorage->Remove(storageKey, storageType);
         }
       }
     }
     return false;
   }
 
   // Next, look in the dynamic preload list.
-  value = mPreloadStateStorage->Get(storageKey,
+  value = mPreloadStateStorage->Get(preloadKey,
                                     mozilla::DataStorage_Persistent);
-  RefPtr<SiteHSTSState> dynamicState = new SiteHSTSState(aHost, value);
+  RefPtr<SiteHSTSState> dynamicState =
+    new SiteHSTSState(aHost, aOriginAttributes, value);
   if (dynamicState->mHSTSState != SecurityPropertyUnset) {
     SSSLOG(("Found dynamic preload entry for %s", aHost.get()));
     bool expired = dynamicState->IsExpired(nsISiteSecurityService::HEADER_HSTS);
     if (!expired) {
       if (dynamicState->mHSTSState == SecurityPropertySet) {
         *aResult = aRequireIncludeSubdomains ? dynamicState->mHSTSIncludeSubdomains
                                              : true;
         return true;
       } else if (dynamicState->mHSTSState == SecurityPropertyNegative) {
         *aResult = false;
         return true;
       }
     } else {
       // if a dynamic preload has expired and is not in the static preload
       // list, we can remove it.
       if (!GetPreloadListEntry(aHost.get())) {
-        mPreloadStateStorage->Remove(storageKey,
+        mPreloadStateStorage->Remove(preloadKey,
                                      mozilla::DataStorage_Persistent);
       }
     }
     return false;
   }
 
   const nsSTSPreload* preload = nullptr;
 
@@ -1194,18 +1326,19 @@ nsSiteSecurityService::HostHasHSTSEntry(
     return true;
   }
 
   return false;
 }
 
 nsresult
 nsSiteSecurityService::IsSecureHost(uint32_t aType, const nsACString& aHost,
-                                    uint32_t aFlags, bool* aCached,
-                                    bool* aResult)
+                                    uint32_t aFlags,
+                                    const OriginAttributes& aOriginAttributes,
+                                    bool* aCached, bool* aResult)
 {
   // Child processes are not allowed direct access to this.
   if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
     MOZ_CRASH("Child process: no direct access to "
               "nsISiteSecurityService::IsSecureHost for non-HSTS entries");
   }
 
   NS_ENSURE_ARG(aResult);
@@ -1235,32 +1368,33 @@ nsSiteSecurityService::IsSecureHost(uint
     if (certVerifier->mPinningMode ==
         CertVerifier::PinningMode::pinningDisabled) {
       return NS_OK;
     }
     bool enforceTestMode = certVerifier->mPinningMode ==
                            CertVerifier::PinningMode::pinningEnforceTestMode;
     return PublicKeyPinningService::HostHasPins(flatHost.get(),
                                                 mozilla::pkix::Now(),
-                                                enforceTestMode, *aResult);
+                                                enforceTestMode, aOriginAttributes,
+                                                *aResult);
   }
 
   // Holepunch chart.apis.google.com and subdomains.
   nsAutoCString host(
     PublicKeyPinningService::CanonicalizeHostname(flatHost.get()));
   if (host.EqualsLiteral("chart.apis.google.com") ||
       StringEndsWith(host, NS_LITERAL_CSTRING(".chart.apis.google.com"))) {
     if (aCached) {
       *aCached = true;
     }
     return NS_OK;
   }
 
   // First check the exact host.
-  if (HostHasHSTSEntry(host, false, aFlags, aResult, aCached)) {
+  if (HostHasHSTSEntry(host, false, aFlags, aOriginAttributes, aResult, aCached)) {
     return NS_OK;
   }
 
 
   SSSLOG(("no HSTS data for %s found, walking up domain", host.get()));
   const char *subdomain;
 
   uint32_t offset = 0;
@@ -1275,17 +1409,18 @@ nsSiteSecurityService::IsSecureHost(uint
       break;
     }
 
     // Do the same thing as with the exact host except now we're looking at
     // ancestor domains of the original host and, therefore, we have to require
     // that the entry includes subdomains.
     nsAutoCString subdomainString(subdomain);
 
-    if (HostHasHSTSEntry(subdomainString, true, aFlags, aResult, aCached)) {
+    if (HostHasHSTSEntry(subdomainString, true, aFlags, aOriginAttributes, aResult,
+                         aCached)) {
       break;
     }
 
     SSSLOG(("no HSTS data for %s found, walking up domain", subdomain));
   }
 
   // Use whatever we ended up with, which defaults to false.
   return NS_OK;
@@ -1314,21 +1449,23 @@ nsSiteSecurityService::ClearPreloads()
 }
 
 bool entryStateNotOK(SiteHPKPState& state, mozilla::pkix::Time& aEvalTime) {
   return state.mState != SecurityPropertySet || state.IsExpired(aEvalTime) ||
          state.mSHA256keys.Length() < 1;
 }
 
 NS_IMETHODIMP
-nsSiteSecurityService::GetKeyPinsForHostname(const nsACString& aHostname,
-                                             mozilla::pkix::Time& aEvalTime,
-                                             /*out*/ nsTArray<nsCString>& pinArray,
-                                             /*out*/ bool* aIncludeSubdomains,
-                                             /*out*/ bool* afound)
+nsSiteSecurityService::GetKeyPinsForHostname(
+  const nsACString& aHostname,
+  mozilla::pkix::Time& aEvalTime,
+  const OriginAttributes& aOriginAttributes,
+  /*out*/ nsTArray<nsCString>& pinArray,
+  /*out*/ bool* aIncludeSubdomains,
+  /*out*/ bool* afound)
 {
   // Child processes are not allowed direct access to this.
   if (!XRE_IsParentProcess()) {
     MOZ_CRASH("Child process: no direct access to "
               "nsISiteSecurityService::GetKeyPinsForHostname");
   }
 
   NS_ENSURE_ARG(afound);
@@ -1337,33 +1474,40 @@ nsSiteSecurityService::GetKeyPinsForHost
   SSSLOG(("Top of GetKeyPinsForHostname for %s", flatHostname.get()));
   *afound = false;
   *aIncludeSubdomains = false;
   pinArray.Clear();
 
   nsAutoCString host(
     PublicKeyPinningService::CanonicalizeHostname(flatHostname.get()));
   nsAutoCString storageKey;
-  SetStorageKey(storageKey, host, nsISiteSecurityService::HEADER_HPKP);
+  SetStorageKey(host, nsISiteSecurityService::HEADER_HPKP, aOriginAttributes,
+                storageKey);
 
   SSSLOG(("storagekey '%s'\n", storageKey.get()));
   mozilla::DataStorageType storageType = mozilla::DataStorage_Persistent;
   nsCString value = mSiteStateStorage->Get(storageKey, storageType);
 
   // decode now
-  RefPtr<SiteHPKPState> foundEntry = new SiteHPKPState(host, value);
+  RefPtr<SiteHPKPState> foundEntry =
+    new SiteHPKPState(host, aOriginAttributes, value);
   if (entryStateNotOK(*foundEntry, aEvalTime)) {
     // not in permanent storage, try now private
     value = mSiteStateStorage->Get(storageKey, mozilla::DataStorage_Private);
-    RefPtr<SiteHPKPState> privateEntry = new SiteHPKPState(host, value);
+    RefPtr<SiteHPKPState> privateEntry =
+      new SiteHPKPState(host, aOriginAttributes, value);
     if (entryStateNotOK(*privateEntry, aEvalTime)) {
       // not in private storage, try dynamic preload
-      value = mPreloadStateStorage->Get(storageKey,
+      nsAutoCString preloadKey;
+      SetStorageKey(host, nsISiteSecurityService::HEADER_HPKP,
+                    OriginAttributes(), preloadKey);
+      value = mPreloadStateStorage->Get(preloadKey,
                                         mozilla::DataStorage_Persistent);
-      RefPtr<SiteHPKPState> preloadEntry = new SiteHPKPState(host, value);
+      RefPtr<SiteHPKPState> preloadEntry =
+        new SiteHPKPState(host, aOriginAttributes, value);
       if (entryStateNotOK(*preloadEntry, aEvalTime)) {
         return NS_OK;
       }
       foundEntry = preloadEntry;
     } else {
       foundEntry = privateEntry;
     }
   }
@@ -1374,46 +1518,59 @@ nsSiteSecurityService::GetKeyPinsForHost
 }
 
 NS_IMETHODIMP
 nsSiteSecurityService::SetKeyPins(const nsACString& aHost,
                                   bool aIncludeSubdomains,
                                   int64_t aExpires, uint32_t aPinCount,
                                   const char** aSha256Pins,
                                   bool aIsPreload,
+                                  JS::HandleValue aOriginAttributes,
+                                  JSContext* aCx,
+                                  uint8_t aArgc,
                                   /*out*/ bool* aResult)
 {
   // Child processes are not allowed direct access to this.
   if (!XRE_IsParentProcess()) {
     MOZ_CRASH("Child process: no direct access to "
               "nsISiteSecurityService::SetKeyPins");
   }
 
   NS_ENSURE_ARG_POINTER(aResult);
   NS_ENSURE_ARG_POINTER(aSha256Pins);
+  OriginAttributes originAttributes;
+  if (aArgc > 1) {
+    // OriginAttributes were passed in.
+    if (!aOriginAttributes.isObject() ||
+        !originAttributes.Init(aCx, aOriginAttributes)) {
+      return NS_ERROR_INVALID_ARG;
+    }
+  }
+  if (aIsPreload && originAttributes != OriginAttributes()) {
+    return NS_ERROR_INVALID_ARG;
+  }
 
   SSSLOG(("Top of SetKeyPins"));
 
   nsTArray<nsCString> sha256keys;
   for (unsigned int i = 0; i < aPinCount; i++) {
     nsAutoCString pin(aSha256Pins[i]);
     SSSLOG(("SetPins pin=%s\n", pin.get()));
     if (!stringIsBase64EncodingOf256bitValue(pin)) {
       return NS_ERROR_INVALID_ARG;
     }
     sha256keys.AppendElement(pin);
   }
   // we always store data in permanent storage (ie no flags)
   const nsCString& flatHost = PromiseFlatCString(aHost);
   nsAutoCString host(
     PublicKeyPinningService::CanonicalizeHostname(flatHost.get()));
-  RefPtr<SiteHPKPState> dynamicEntry =
-    new SiteHPKPState(host, aExpires, SecurityPropertySet, aIncludeSubdomains,
-                      sha256keys);
-  return SetHPKPState(host.get(), *dynamicEntry, 0, aIsPreload);
+  RefPtr<SiteHPKPState> dynamicEntry = new SiteHPKPState(host, originAttributes,
+    aExpires, SecurityPropertySet, aIncludeSubdomains, sha256keys);
+  return SetHPKPState(host.get(), *dynamicEntry, 0, aIsPreload, originAttributes);
 }
 
 NS_IMETHODIMP
 nsSiteSecurityService::SetHSTSPreload(const nsACString& aHost,
                                       bool aIncludeSubdomains,
                                       int64_t aExpires,
                               /*out*/ bool* aResult)
 {
@@ -1426,27 +1583,33 @@ nsSiteSecurityService::SetHSTSPreload(co
   NS_ENSURE_ARG_POINTER(aResult);
 
   SSSLOG(("Top of SetHSTSPreload"));
 
   const nsCString& flatHost = PromiseFlatCString(aHost);
   nsAutoCString host(
     PublicKeyPinningService::CanonicalizeHostname(flatHost.get()));
   return SetHSTSState(nsISiteSecurityService::HEADER_HSTS, host.get(), aExpires,
-                      aIncludeSubdomains, 0, SecurityPropertySet, true);
+                      aIncludeSubdomains, 0, SecurityPropertySet, true,
+                      OriginAttributes());
 }
 
 nsresult
 nsSiteSecurityService::SetHPKPState(const char* aHost, SiteHPKPState& entry,
-                                    uint32_t aFlags, bool aIsPreload)
+                                    uint32_t aFlags, bool aIsPreload,
+                                    const OriginAttributes& aOriginAttributes)
 {
+  if (aIsPreload && aOriginAttributes != OriginAttributes()) {
+    return NS_ERROR_INVALID_ARG;
+  }
   SSSLOG(("Top of SetPKPState"));
   nsAutoCString host(aHost);
   nsAutoCString storageKey;
-  SetStorageKey(storageKey, host, nsISiteSecurityService::HEADER_HPKP);
+  SetStorageKey(host, nsISiteSecurityService::HEADER_HPKP, aOriginAttributes,
+                storageKey);
   bool isPrivate = aFlags & nsISocketProvider::NO_PERMANENT_STORAGE;
   mozilla::DataStorageType storageType = isPrivate
                                          ? mozilla::DataStorage_Private
                                          : mozilla::DataStorage_Persistent;
   nsAutoCString stateString;
   entry.ToString(stateString);
 
   nsresult rv;
@@ -1483,25 +1646,31 @@ nsSiteSecurityService::Enumerate(uint32_
 
   nsCOMArray<nsISiteSecurityState> states;
   for (const mozilla::dom::DataStorageItem& item : items) {
     if (!StringEndsWith(item.key(), keySuffix)) {
       // The key does not end with correct suffix, so is not the type we want.
       continue;
     }
 
-    nsCString hostname(
+    nsCString origin(
       StringHead(item.key(), item.key().Length() - keySuffix.Length()));
+    nsAutoCString hostname;
+    OriginAttributes originAttributes;
+    if (!originAttributes.PopulateFromOrigin(origin, hostname)) {
+      return NS_ERROR_FAILURE;
+    }
+
     nsCOMPtr<nsISiteSecurityState> state;
     switch(aType) {
       case nsISiteSecurityService::HEADER_HSTS:
-        state = new SiteHSTSState(hostname, item.value());
+        state = new SiteHSTSState(hostname, originAttributes, item.value());
         break;
       case nsISiteSecurityService::HEADER_HPKP:
-        state = new SiteHPKPState(hostname, item.value());
+        state = new SiteHPKPState(hostname, originAttributes, item.value());
         break;
       default:
         MOZ_ASSERT_UNREACHABLE("SSS:Enumerate got invalid type");
     }
 
     states.AppendObject(state);
   }
 
--- a/security/manager/ssl/nsSiteSecurityService.h
+++ b/security/manager/ssl/nsSiteSecurityService.h
@@ -1,28 +1,31 @@
 /* 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 __nsSiteSecurityService_h__
 #define __nsSiteSecurityService_h__
 
+#include "mozilla/BasePrincipal.h"
 #include "mozilla/DataStorage.h"
 #include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIObserver.h"
 #include "nsISiteSecurityService.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "pkix/pkixtypes.h"
 #include "prtime.h"
 
 class nsIURI;
 class nsISSLStatus;
 
+using mozilla::OriginAttributes;
+
 // {16955eee-6c48-4152-9309-c42a465138a1}
 #define NS_SITE_SECURITY_SERVICE_CID \
   {0x16955eee, 0x6c48, 0x4152, \
     {0x93, 0x09, 0xc4, 0x2a, 0x46, 0x51, 0x38, 0xa1} }
 
 /**
  * SecurityPropertyState: A utility enum for representing the different states
  * a security property can be in.
@@ -39,35 +42,40 @@ enum SecurityPropertyState {
   SecurityPropertyNegative = nsISiteSecurityState::SECURITY_PROPERTY_NEGATIVE,
 };
 
 /**
  * SiteHPKPState: A utility class that encodes/decodes a string describing
  * the public key pins of a site.
  * HPKP state consists of:
  *  - Hostname (nsCString)
+ *  - Origin attributes (OriginAttributes)
  *  - Expiry time (PRTime (aka int64_t) in milliseconds)
  *  - A state flag (SecurityPropertyState, default SecurityPropertyUnset)
  *  - An include subdomains flag (bool, default false)
  *  - An array of sha-256 hashed base 64 encoded fingerprints of required keys
  */
 class SiteHPKPState : public nsISiteHPKPState
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISITEHPKPSTATE
   NS_DECL_NSISITESECURITYSTATE
 
   SiteHPKPState();
-  SiteHPKPState(const nsCString& aHost, const nsCString& aStateString);
-  SiteHPKPState(const nsCString& aHost, PRTime aExpireTime,
-                SecurityPropertyState aState, bool aIncludeSubdomains,
-                nsTArray<nsCString>& SHA256keys);
+  SiteHPKPState(const nsCString& aHost,
+                const OriginAttributes& aOriginAttributes,
+                const nsCString& aStateString);
+  SiteHPKPState(const nsCString& aHost,
+                const OriginAttributes& aOriginAttributes,
+                PRTime aExpireTime, SecurityPropertyState aState,
+                bool aIncludeSubdomains, nsTArray<nsCString>& SHA256keys);
 
   nsCString mHostname;
+  OriginAttributes mOriginAttributes;
   PRTime mExpireTime;
   SecurityPropertyState mState;
   bool mIncludeSubdomains;
   nsTArray<nsCString> mSHA256keys;
 
   bool IsExpired(mozilla::pkix::Time aTime)
   {
     if (aTime > mozilla::pkix::TimeFromEpochInSeconds(mExpireTime /
@@ -83,32 +91,38 @@ protected:
   virtual ~SiteHPKPState() {};
 };
 
 /**
  * SiteHSTSState: A utility class that encodes/decodes a string describing
  * the security state of a site. Currently only handles HSTS.
  * HSTS state consists of:
  *  - Hostname (nsCString)
+ *  - Origin attributes (OriginAttributes)
  *  - Expiry time (PRTime (aka int64_t) in milliseconds)
  *  - A state flag (SecurityPropertyState, default SecurityPropertyUnset)
  *  - An include subdomains flag (bool, default false)
  */
 class SiteHSTSState : public nsISiteHSTSState
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISITEHSTSSTATE
   NS_DECL_NSISITESECURITYSTATE
 
-  SiteHSTSState(const nsCString& aHost, const nsCString& aStateString);
-  SiteHSTSState(const nsCString& aHost, PRTime aHSTSExpireTime,
-                SecurityPropertyState aHSTSState, bool aHSTSIncludeSubdomains);
+  SiteHSTSState(const nsCString& aHost,
+                const OriginAttributes& aOriginAttributes,
+                const nsCString& aStateString);
+  SiteHSTSState(const nsCString& aHost,
+                const OriginAttributes& aOriginAttributes,
+                PRTime aHSTSExpireTime, SecurityPropertyState aHSTSState,
+                bool aHSTSIncludeSubdomains);
 
   nsCString mHostname;
+  OriginAttributes mOriginAttributes;
   PRTime mHSTSExpireTime;
   SecurityPropertyState mHSTSState;
   bool mHSTSIncludeSubdomains;
 
   bool IsExpired(uint32_t aType)
   {
     // If mHSTSExpireTime is 0, this entry never expires (this is the case for
     // knockout entries).
@@ -145,40 +159,52 @@ public:
 
 protected:
   virtual ~nsSiteSecurityService();
 
 private:
   nsresult GetHost(nsIURI *aURI, nsACString &aResult);
   nsresult SetHSTSState(uint32_t aType, const char* aHost, int64_t maxage,
                         bool includeSubdomains, uint32_t flags,
-                        SecurityPropertyState aHSTSState, bool aIsPreload);
+                        SecurityPropertyState aHSTSState, bool aIsPreload,
+                        const OriginAttributes& aOriginAttributes);
   nsresult ProcessHeaderInternal(uint32_t aType, nsIURI* aSourceURI,
                                  const nsCString& aHeader,
                                  nsISSLStatus* aSSLStatus,
-                                 uint32_t aFlags, uint64_t* aMaxAge,
-                                 bool* aIncludeSubdomains,
+                                 uint32_t aFlags,
+                                 const OriginAttributes& aOriginAttributes,
+                                 uint64_t* aMaxAge, bool* aIncludeSubdomains,
                                  uint32_t* aFailureResult);
   nsresult ProcessSTSHeader(nsIURI* aSourceURI, const nsCString& aHeader,
-                            uint32_t flags, uint64_t* aMaxAge,
-                            bool* aIncludeSubdomains, uint32_t* aFailureResult);
+                            uint32_t flags,
+                            const OriginAttributes& aOriginAttributes,
+                            uint64_t* aMaxAge, bool* aIncludeSubdomains,
+                            uint32_t* aFailureResult);
   nsresult ProcessPKPHeader(nsIURI* aSourceURI, const nsCString& aHeader,
                             nsISSLStatus* aSSLStatus, uint32_t flags,
+                            const OriginAttributes& aOriginAttributes,
                             uint64_t* aMaxAge, bool* aIncludeSubdomains,
                             uint32_t* aFailureResult);
   nsresult SetHPKPState(const char* aHost, SiteHPKPState& entry, uint32_t flags,
-                        bool aIsPreload);
+                        bool aIsPreload,
+                        const OriginAttributes& aOriginAttributes);
+  nsresult RemoveStateInternal(uint32_t aType, nsIURI* aURI, uint32_t aFlags,
+                               const OriginAttributes& aOriginAttributes);
   nsresult RemoveStateInternal(uint32_t aType, const nsAutoCString& aHost,
-                               uint32_t aFlags, bool aIsPreload);
+                               uint32_t aFlags, bool aIsPreload,
+                               const OriginAttributes& aOriginAttributes);
   bool HostHasHSTSEntry(const nsAutoCString& aHost,
                         bool aRequireIncludeSubdomains, uint32_t aFlags,
+                        const OriginAttributes& aOriginAttributes,
                         bool* aResult, bool* aCached);
   const nsSTSPreload *GetPreloadListEntry(const char *aHost);
   nsresult IsSecureHost(uint32_t aType, const nsACString& aHost,
-                        uint32_t aFlags, bool* aCached, bool* aResult);
+                        uint32_t aFlags,
+                        const OriginAttributes& aOriginAttributes,
+                        bool* aCached, bool* aResult);
 
   uint64_t mMaxMaxAge;
   bool mUsePreloadList;
   int64_t mPreloadListTimeOffset;
   bool mProcessPKPHeadersFromNonBuiltInRoots;
   RefPtr<mozilla::DataStorage> mSiteStateStorage;
   RefPtr<mozilla::DataStorage> mPreloadStateStorage;
 };
--- a/security/manager/ssl/tests/unit/test_forget_about_site_security_headers.js
+++ b/security/manager/ssl/tests/unit/test_forget_about_site_security_headers.js
@@ -96,8 +96,63 @@ add_task(function* () {
             "a.pinning2.example.com should not be HSTS now (subdomain case)");
   Assert.ok(!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0),
             "a.pinning2.example.com should not be HPKP now (subdomain case)");
 
   Assert.ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
                              unrelatedURI, 0),
             "example.org should still be HSTS");
 });
+
+// Test the case of processing HSTS and HPKP headers for a.pinning2.example.com
+// with various originAttributes, using "Forget About Site" on example.com, and
+// then checking that the platform doesn't consider the subdomain to be HSTS or
+// HPKP for any originAttributes any longer. Also test that unrelated sites
+// don't also get removed.
+add_task(function* () {
+  let originAttributesList = [
+    {},
+    { userContextId: 1 },
+    { firstPartyDomain: "foo.com" },
+    { userContextId: 1, firstPartyDomain: "foo.com" },
+  ];
+
+  let unrelatedURI = Services.io.newURI("https://example.org");
+
+  for (let originAttributes of originAttributesList) {
+    sss.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri, GOOD_MAX_AGE,
+                      sslStatus, 0, originAttributes);
+    sss.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
+                      GOOD_MAX_AGE + VALID_PIN + BACKUP_PIN, sslStatus, 0,
+                      originAttributes);
+
+    Assert.ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+                               0, originAttributes),
+              "a.pinning2.example.com should be HSTS (originAttributes case)");
+    Assert.ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
+                               0, originAttributes),
+              "a.pinning2.example.com should be HPKP (originAttributes case)");
+
+    // Add an unrelated site to HSTS.  Not HPKP because we have no valid keys.
+    sss.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, unrelatedURI,
+                      GOOD_MAX_AGE, sslStatus, 0, originAttributes);
+    Assert.ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
+                              unrelatedURI, 0, originAttributes),
+              "example.org should be HSTS (originAttributes case)");
+  }
+
+  yield ForgetAboutSite.removeDataFromDomain("example.com");
+
+  for (let originAttributes of originAttributesList) {
+    Assert.ok(!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+                                0, originAttributes),
+              "a.pinning2.example.com should not be HSTS now " +
+              "(originAttributes case)");
+    Assert.ok(!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
+                                0, originAttributes),
+              "a.pinning2.example.com should not be HPKP now " +
+              "(originAttributes case)");
+
+    Assert.ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
+                              unrelatedURI, 0, originAttributes),
+              "example.org should still be HSTS (originAttributes case)");
+  }
+});
--- a/security/manager/ssl/tests/unit/test_pinning_header_parsing.js
+++ b/security/manager/ssl/tests/unit/test_pinning_header_parsing.js
@@ -45,17 +45,17 @@ function checkPassValidPin(pinValue, set
   } else {
     // add a known valid pin!
     let validPinValue = "max-age=5000;" + VALID_PIN1 + BACKUP_PIN1;
     gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
                              validPinValue, sslStatus, 0);
   }
   try {
     gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
-                             pinValue, sslStatus, 0, maxAge);
+                             pinValue, sslStatus, 0, {}, maxAge);
     ok(true, "Valid pin should be accepted");
   } catch (e) {
     ok(false, "Valid pin should have been accepted");
   }
 
   // check that maxAge was processed correctly
   if (settingPin && expectedMaxAge) {
     ok(maxAge.value == expectedMaxAge, `max-age value should be ${expectedMaxAge}`);
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_sss_originAttributes.js
@@ -0,0 +1,141 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * vim: sw=2 ts=2 sts=2
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// Ensures nsISiteSecurityService APIs respects origin attributes.
+
+do_register_cleanup(() => {
+  Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
+  Services.prefs.clearUserPref(
+    "security.cert_pinning.process_headers_from_non_builtin_roots");
+});
+
+const GOOD_MAX_AGE_SECONDS = 69403;
+const NON_ISSUED_KEY_HASH = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+const PINNING_ROOT_KEY_HASH = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
+const VALID_PIN = `pin-sha256="${PINNING_ROOT_KEY_HASH}";`;
+const BACKUP_PIN = `pin-sha256="${NON_ISSUED_KEY_HASH}";`;
+const GOOD_MAX_AGE = `max-age=${GOOD_MAX_AGE_SECONDS};`;
+
+do_get_profile(); // must be done before instantiating nsIX509CertDB
+
+Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
+Services.prefs.setBoolPref(
+  "security.cert_pinning.process_headers_from_non_builtin_roots", true);
+
+let certdb = Cc["@mozilla.org/security/x509certdb;1"]
+               .getService(Ci.nsIX509CertDB);
+addCertFromFile(certdb, "test_pinning_dynamic/pinningroot.pem", "CTu,CTu,CTu");
+
+let sss = Cc["@mozilla.org/ssservice;1"]
+            .getService(Ci.nsISiteSecurityService);
+let host = "a.pinning2.example.com";
+let uri = Services.io.newURI("https://" + host);
+
+// This test re-uses certificates from pinning tests because that's easier and
+// simpler than recreating new certificates, hence the slightly longer than
+// necessary domain name.
+let sslStatus = new FakeSSLStatus(constructCertFromFile(
+  "test_pinning_dynamic/a.pinning2.example.com-pinningroot.pem"));
+
+// Check if originAttributes1 and originAttributes2 are isolated with respect
+// to HSTS/HPKP storage.
+function doTest(originAttributes1, originAttributes2, shouldShare) {
+  sss.clearAll();
+  for (let type of [Ci.nsISiteSecurityService.HEADER_HSTS,
+                    Ci.nsISiteSecurityService.HEADER_HPKP]) {
+    let header = GOOD_MAX_AGE;
+    if (type == Ci.nsISiteSecurityService.HEADER_HPKP) {
+      header += VALID_PIN + BACKUP_PIN;
+    }
+    // Set HSTS or HPKP for originAttributes1.
+    sss.processHeader(type, uri, header, sslStatus, 0, originAttributes1);
+    ok(sss.isSecureURI(type, uri, 0, originAttributes1),
+       "URI should be secure given original origin attributes");
+    equal(sss.isSecureURI(type, uri, 0, originAttributes2), shouldShare,
+          "URI should be secure given different origin attributes if and " +
+          "only if shouldShare is true");
+
+    if (!shouldShare) {
+      // Remove originAttributes2 from the storage.
+      sss.removeState(type, uri, 0, originAttributes2);
+      ok(sss.isSecureURI(type, uri, 0, originAttributes1),
+         "URI should still be secure given original origin attributes");
+    }
+
+    // Remove originAttributes1 from the storage.
+    sss.removeState(type, uri, 0, originAttributes1);
+    ok(!sss.isSecureURI(type, uri, 0, originAttributes1),
+       "URI should be not be secure after removeState");
+  }
+  // Set HPKP for originAttributes1.
+  sss.setKeyPins(host, false, Date.now() + 1234567890, 2,
+                 [NON_ISSUED_KEY_HASH, PINNING_ROOT_KEY_HASH], false,
+                 originAttributes1);
+  ok(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0,
+                     originAttributes1),
+     "URI should be secure after setKeyPins given original origin attributes");
+  equal(sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0,
+                        originAttributes2),
+        shouldShare, "URI should be secure after setKeyPins given different " +
+        "origin attributes if and only if shouldShare is true");
+
+  sss.clearAll();
+  ok(!sss.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0,
+                      originAttributes1),
+     "URI should not be secure after clearAll");
+}
+
+function testInvalidOriginAttributes(originAttributes) {
+  for (let type of [Ci.nsISiteSecurityService.HEADER_HSTS,
+                    Ci.nsISiteSecurityService.HEADER_HPKP]) {
+    let header = GOOD_MAX_AGE;
+    if (type == Ci.nsISiteSecurityService.HEADER_HPKP) {
+      header += VALID_PIN + BACKUP_PIN;
+    }
+
+    let callbacks = [
+      () => sss.processHeader(type, uri, header, sslStatus, 0,
+                              originAttributes),
+      () => sss.isSecureURI(type, uri, 0, originAttributes),
+      () => sss.removeState(type, uri, 0, originAttributes),
+    ];
+
+    for (let callback of callbacks) {
+      throws(callback, /NS_ERROR_ILLEGAL_VALUE/,
+             "Should get an error with invalid origin attributes");
+    }
+  }
+
+  throws(() => sss.setKeyPins(host, false, Date.now() + 1234567890, 2,
+                              [NON_ISSUED_KEY_HASH, PINNING_ROOT_KEY_HASH],
+                              false, originAttributes),
+         /NS_ERROR_ILLEGAL_VALUE/,
+         "Should get an error with invalid origin attributes");
+}
+
+function run_test() {
+  sss.clearAll();
+  let originAttributesList = [];
+  for (let userContextId of [0, 1, 2]) {
+    for (let firstPartyDomain of ["", "foo.com", "bar.com"]) {
+      originAttributesList.push({ userContextId, firstPartyDomain });
+    }
+  }
+  for (let attrs1 of originAttributesList) {
+    for (let attrs2 of originAttributesList) {
+      // SSS storage is not isolated by userContext
+      doTest(attrs1, attrs2,
+             attrs1.firstPartyDomain == attrs2.firstPartyDomain);
+    }
+  }
+
+  testInvalidOriginAttributes(undefined);
+  testInvalidOriginAttributes(null);
+  testInvalidOriginAttributes(1);
+  testInvalidOriginAttributes("foo");
+}
--- a/security/manager/ssl/tests/unit/test_sts_ipv4_ipv6.js
+++ b/security/manager/ssl/tests/unit/test_sts_ipv4_ipv6.js
@@ -14,17 +14,17 @@ function check_ip(s, v, ip) {
   str += "/";
 
   let uri = Services.io.newURI(str);
   ok(!s.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
 
   let parsedMaxAge = {};
   let parsedIncludeSubdomains = {};
   s.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
-                  "max-age=1000;includeSubdomains", sslStatus, 0,
+                  "max-age=1000;includeSubdomains", sslStatus, 0, {},
                   parsedMaxAge, parsedIncludeSubdomains);
   ok(!s.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0),
      "URI should not be secure if it contains an IP address");
 
   /* Test that processHeader will ignore headers for an uri, if the uri
    * contains an IP address not a hostname.
    * If processHeader indeed ignore the header, then the output parameters will
    * remain empty, and we shouldn't see the values passed as the header.
--- a/security/manager/ssl/tests/unit/test_sts_parser.js
+++ b/security/manager/ssl/tests/unit/test_sts_parser.js
@@ -12,31 +12,31 @@ let sss = Cc["@mozilla.org/ssservice;1"]
 let sslStatus = new FakeSSLStatus();
 
 function testSuccess(header, expectedMaxAge, expectedIncludeSubdomains) {
   let dummyUri = Services.io.newURI("https://foo.com/bar.html");
   let maxAge = {};
   let includeSubdomains = {};
 
   sss.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, dummyUri, header,
-                    sslStatus, 0, maxAge, includeSubdomains);
+                    sslStatus, 0, {}, maxAge, includeSubdomains);
 
   equal(maxAge.value, expectedMaxAge, "Did not correctly parse maxAge");
   equal(includeSubdomains.value, expectedIncludeSubdomains,
         "Did not correctly parse presence/absence of includeSubdomains");
 }
 
 function testFailure(header) {
   let dummyUri = Services.io.newURI("https://foo.com/bar.html");
   let maxAge = {};
   let includeSubdomains = {};
 
   throws(() => {
     sss.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, dummyUri, header,
-                      sslStatus, 0, maxAge, includeSubdomains);
+                      sslStatus, 0, {}, maxAge, includeSubdomains);
   }, "Parsed invalid header: " + header);
 }
 
 function run_test() {
     // SHOULD SUCCEED:
     testSuccess("max-age=100", 100, false);
     testSuccess("max-age  =100", 100, false);
     testSuccess(" max-age=100", 100, false);
--- a/security/manager/ssl/tests/unit/xpcshell.ini
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -122,16 +122,17 @@ requesttimeoutfactor = 2
 [test_sdr_preexisting.js]
 [test_session_resumption.js]
 run-sequentially = hardcoded ports
 [test_signed_apps.js]
 [test_signed_dir.js]
 tags = addons psm
 [test_sss_enumerate.js]
 [test_sss_eviction.js]
+[test_sss_originAttributes.js]
 [test_sss_readstate.js]
 [test_sss_readstate_child.js]
 support-files = sss_readstate_child_worker.js
 # bug 1124289 - run_test_in_child violates the sandbox on android
 skip-if = toolkit == 'android'
 [test_sss_readstate_empty.js]
 [test_sss_readstate_garbage.js]
 [test_sss_readstate_huge.js]
--- a/security/manager/tools/getHSTSPreloadList.js
+++ b/security/manager/tools/getHSTSPreloadList.js
@@ -114,17 +114,17 @@ function processStsHeader(host, header, 
   var includeSubdomains = { value: false };
   var error = ERROR_NONE;
   if (header != null && securityInfo != null) {
     try {
       var uri = Services.io.newURI("https://" + host.name);
       var sslStatus = securityInfo.QueryInterface(Ci.nsISSLStatusProvider)
                                   .SSLStatus;
       gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS,
-                               uri, header, sslStatus, 0, maxAge,
+                               uri, header, sslStatus, 0, {}, maxAge,
                                includeSubdomains);
     }
     catch (e) {
       dump("ERROR: could not process header '" + header + "' from " +
            host.name + ": " + e + "\n");
       error = e;
     }
   } else if (status == 0) {
--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -1491,18 +1491,20 @@ dependencies = [
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "profile 0.0.1",
  "profile_traits 0.0.1",
  "script 0.0.1",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
  "servo_config 0.0.1",
+ "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "style 0.0.1",
+ "style_traits 0.0.1",
  "webdriver_server 0.0.1",
  "webrender 0.17.0 (git+https://github.com/servo/webrender)",
  "webrender_traits 0.16.0 (git+https://github.com/servo/webrender)",
  "webvr 0.0.1",
  "webvr_traits 0.0.1",
 ]
 
 [[package]]
@@ -2640,17 +2642,17 @@ dependencies = [
 [[package]]
 name = "servo_url"
 version = "0.0.1"
 dependencies = [
  "heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "url_serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url_serde 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "sha1"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -3105,17 +3107,17 @@ dependencies = [
  "heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "url_serde"
-version = "0.1.1"
+version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "user32-sys"
@@ -3604,17 +3606,17 @@ dependencies = [
 "checksum unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a078ebdd62c0e71a709c3d53d2af693fe09fe93fbff8344aebe289b78f9032"
 "checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff"
 "checksum unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e5430ae21ef212551680d0021fc7dbd936e8b268c5ea8fdae8814e0b2496d80f"
 "checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3"
 "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
 "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
 "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
 "checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e"
-"checksum url_serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c89041feeb06fab9bbf5e3b3fef87605f263e0d98ea080a500a11f41295e230"
+"checksum url_serde 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "64ddbc0a67ae30778179166934129e0aeb92c5b7051d8e0b519e3bce73aff106"
 "checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47"
 "checksum utf-8 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9aee9ba280438b56d1ebc5329f2094f0ff457f811eeeff0b278d75aa99db400"
 "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
 "checksum uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7cfec50b0842181ba6e713151b72f4ec84a6a7e2c9c8a8a3ffc37bb1cd16b231"
 "checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f"
 "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
 "checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
 "checksum webdriver 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdc28802daddee94267a657ffeac2593a33881fb7a3a44fedd320b1319efcaf6"
--- a/servo/components/constellation/constellation.rs
+++ b/servo/components/constellation/constellation.rs
@@ -73,18 +73,18 @@ use compositing::compositor_thread::Msg 
 use debugger;
 use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg};
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::{Size2D, TypedSize2D};
 use event_loop::EventLoop;
 use frame::{Frame, FrameChange, FrameState, FrameTreeIterator, FullFrameTreeIterator};
 use gfx::font_cache_thread::FontCacheThread;
 use gfx_traits::Epoch;
-use ipc_channel::Error;
-use ipc_channel::ipc::{self, IpcSender};
+use ipc_channel::{Error as IpcError};
+use ipc_channel::ipc::{self, IpcSender, IpcReceiver};
 use ipc_channel::router::ROUTER;
 use layout_traits::LayoutThreadFactory;
 use log::{Log, LogLevel, LogLevelFilter, LogMetadata, LogRecord};
 use msg::constellation_msg::{FrameId, FrameType, PipelineId};
 use msg::constellation_msg::{Key, KeyModifiers, KeyState};
 use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
 use net_traits::{self, IpcSend, ResourceThreads};
 use net_traits::image_cache_thread::ImageCacheThread;
@@ -98,16 +98,17 @@ use script_traits::{AnimationState, Anim
 use script_traits::{ConstellationControlMsg, ConstellationMsg as FromCompositorMsg, DiscardBrowsingContext};
 use script_traits::{DocumentActivity, DocumentState, LayoutControlMsg, LoadData};
 use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerEventRequest};
 use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory};
 use script_traits::{LogEntry, ServiceWorkerMsg, webdriver_msg};
 use script_traits::{MozBrowserErrorType, MozBrowserEvent, WebDriverCommandMsg, WindowSizeData};
 use script_traits::{SWManagerMsg, ScopeThings, WindowSizeType};
 use script_traits::WebVREventMsg;
+use serde::{Deserialize, Serialize};
 use servo_config::opts;
 use servo_config::prefs::PREFS;
 use servo_rand::{Rng, SeedableRng, ServoRng, random};
 use servo_remutex::ReentrantMutex;
 use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::collections::{HashMap, VecDeque};
 use std::iter::once;
@@ -140,25 +141,25 @@ use webvr_traits::WebVRMsg;
 /// type.
 pub struct Constellation<Message, LTF, STF> {
     /// An IPC channel for script threads to send messages to the constellation.
     /// This is the script threads' view of `script_receiver`.
     script_sender: IpcSender<FromScriptMsg>,
 
     /// A channel for the constellation to receive messages from script threads.
     /// This is the constellation's view of `script_sender`.
-    script_receiver: Receiver<FromScriptMsg>,
+    script_receiver: Receiver<Result<FromScriptMsg, IpcError>>,
 
     /// An IPC channel for layout threads to send messages to the constellation.
     /// This is the layout threads' view of `layout_receiver`.
     layout_sender: IpcSender<FromLayoutMsg>,
 
     /// A channel for the constellation to receive messages from layout threads.
     /// This is the constellation's view of `layout_sender`.
-    layout_receiver: Receiver<FromLayoutMsg>,
+    layout_receiver: Receiver<Result<FromLayoutMsg, IpcError>>,
 
     /// A channel for the constellation to receive messages from the compositor thread.
     compositor_receiver: Receiver<FromCompositorMsg>,
 
     /// A channel (the implementation of which is port-specific) for the
     /// constellation to send messages to the compositor thread.
     compositor_proxy: Box<CompositorProxy>,
 
@@ -201,17 +202,17 @@ pub struct Constellation<Message, LTF, S
     /// An IPC channel for Service Worker Manager threads to send
     /// messages to the constellation.  This is the SW Manager thread's
     /// view of `swmanager_receiver`.
     swmanager_sender: IpcSender<SWManagerMsg>,
 
     /// A channel for the constellation to receive messages from the
     /// Service Worker Manager thread. This is the constellation's view of
     /// `swmanager_sender`.
-    swmanager_receiver: Receiver<SWManagerMsg>,
+    swmanager_receiver: Receiver<Result<SWManagerMsg, IpcError>>,
 
     /// A channel for the constellation to send messages to the
     /// time profiler thread.
     time_profiler_chan: time::ProfilerChan,
 
     /// A channel for the constellation to send messages to the
     /// memory profiler thread.
     mem_profiler_chan: mem::ProfilerChan,
@@ -463,36 +464,50 @@ fn log_entry(record: &LogRecord) -> Opti
         )),
         _ => None,
     }
 }
 
 /// The number of warnings to include in each crash report.
 const WARNINGS_BUFFER_SIZE: usize = 32;
 
+/// Route an ipc receiver to an mpsc receiver, preserving any errors.
+/// This is the same as `route_ipc_receiver_to_new_mpsc_receiver`,
+/// but does not panic on deserializtion errors.
+fn route_ipc_receiver_to_new_mpsc_receiver_preserving_errors<T>(ipc_receiver: IpcReceiver<T>)
+    -> Receiver<Result<T, IpcError>>
+    where T: Deserialize + Serialize + Send + 'static
+{
+        let (mpsc_sender, mpsc_receiver) = channel();
+        ROUTER.add_route(ipc_receiver.to_opaque(), Box::new(move |message| {
+            drop(mpsc_sender.send(message.to::<T>()))
+        }));
+        mpsc_receiver
+}
+
 impl<Message, LTF, STF> Constellation<Message, LTF, STF>
     where LTF: LayoutThreadFactory<Message=Message>,
           STF: ScriptThreadFactory<Message=Message>
 {
     /// Create a new constellation thread.
     pub fn start(state: InitialConstellationState) -> (Sender<FromCompositorMsg>, IpcSender<SWManagerMsg>) {
         let (compositor_sender, compositor_receiver) = channel();
 
         // service worker manager to communicate with constellation
         let (swmanager_sender, swmanager_receiver) = ipc::channel().expect("ipc channel failure");
         let sw_mgr_clone = swmanager_sender.clone();
 
         thread::Builder::new().name("Constellation".to_owned()).spawn(move || {
             let (ipc_script_sender, ipc_script_receiver) = ipc::channel().expect("ipc channel failure");
-            let script_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_script_receiver);
+            let script_receiver = route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(ipc_script_receiver);
 
             let (ipc_layout_sender, ipc_layout_receiver) = ipc::channel().expect("ipc channel failure");
-            let layout_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_layout_receiver);
+            let layout_receiver = route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(ipc_layout_receiver);
 
-            let swmanager_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(swmanager_receiver);
+            let swmanager_receiver = route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(swmanager_receiver);
 
             PipelineNamespace::install(PipelineNamespaceId(0));
 
             let mut constellation: Constellation<Message, LTF, STF> = Constellation {
                 script_sender: ipc_script_sender,
                 layout_sender: ipc_layout_sender,
                 script_receiver: script_receiver,
                 compositor_receiver: compositor_receiver,
@@ -771,23 +786,34 @@ impl<Message, LTF, STF> Constellation<Me
         // other than panic.
         let request = {
             let receiver_from_script = &self.script_receiver;
             let receiver_from_compositor = &self.compositor_receiver;
             let receiver_from_layout = &self.layout_receiver;
             let receiver_from_swmanager = &self.swmanager_receiver;
             select! {
                 msg = receiver_from_script.recv() =>
-                    Request::Script(msg.expect("Unexpected script channel panic in constellation")),
+                    msg.expect("Unexpected script channel panic in constellation").map(Request::Script),
                 msg = receiver_from_compositor.recv() =>
-                    Request::Compositor(msg.expect("Unexpected compositor channel panic in constellation")),
+                    Ok(Request::Compositor(msg.expect("Unexpected compositor channel panic in constellation"))),
                 msg = receiver_from_layout.recv() =>
-                    Request::Layout(msg.expect("Unexpected layout channel panic in constellation")),
+                    msg.expect("Unexpected layout channel panic in constellation").map(Request::Layout),
                 msg = receiver_from_swmanager.recv() =>
-                    Request::FromSWManager(msg.expect("Unexpected panic channel panic in constellation"))
+                    msg.expect("Unexpected panic channel panic in constellation").map(Request::FromSWManager)
+            }
+        };
+
+        let request = match request {
+            Ok(request) => request,
+            Err(err) => {
+                // Treat deserialization error the same as receiving a panic message
+                debug!("Deserialization failed ({:?}).", err);
+                let reason = format!("Deserialization failed ({})", err);
+                let root_frame_id = self.root_frame_id;
+                return self.handle_panic(root_frame_id, reason, None);
             }
         };
 
         match request {
             Request::Compositor(message) => {
                 self.handle_request_from_compositor(message)
             },
             Request::Script(message) => {
@@ -1223,17 +1249,17 @@ impl<Message, LTF, STF> Constellation<Me
         self.compositor_proxy.send(ToCompositorMsg::ShutdownComplete);
     }
 
     fn handle_pipeline_exited(&mut self, pipeline_id: PipelineId) {
         debug!("Pipeline {:?} exited.", pipeline_id);
         self.pipelines.remove(&pipeline_id);
     }
 
-    fn handle_send_error(&mut self, pipeline_id: PipelineId, err: Error) {
+    fn handle_send_error(&mut self, pipeline_id: PipelineId, err: IpcError) {
         // Treat send error the same as receiving a panic message
         debug!("Pipeline {:?} send error ({}).", pipeline_id, err);
         let top_level_frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
         let reason = format!("Send failed ({})", err);
         self.handle_panic(top_level_frame_id, reason, None);
     }
 
     fn handle_panic(&mut self, top_level_frame_id: FrameId, reason: String, backtrace: Option<String>) {
--- a/servo/components/constellation/lib.rs
+++ b/servo/components/constellation/lib.rs
@@ -26,16 +26,17 @@ extern crate ipc_channel;
 extern crate layout_traits;
 #[macro_use]
 extern crate log;
 extern crate msg;
 extern crate net_traits;
 extern crate offscreen_gl_context;
 extern crate profile_traits;
 extern crate script_traits;
+extern crate serde;
 #[macro_use]
 extern crate serde_derive;
 extern crate servo_config;
 extern crate servo_rand;
 extern crate servo_remutex;
 extern crate servo_url;
 extern crate style_traits;
 extern crate webrender_traits;
--- a/servo/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/servo/components/script/dom/bindings/codegen/CodegenRust.py
@@ -4030,27 +4030,24 @@ def convertConstIDLValueToRust(value):
 
     if tag == IDLType.Tags.bool:
         return toStringBool(value.value)
 
     raise TypeError("Const value of unhandled type: " + value.type)
 
 
 class CGConstant(CGThing):
-    def __init__(self, constants):
+    def __init__(self, constant):
         CGThing.__init__(self)
-        self.constants = constants
+        self.constant = constant
 
     def define(self):
-        def stringDecl(const):
-            name = const.identifier.name
-            value = convertConstIDLValueToRust(const.value)
-            return CGGeneric("pub const %s: %s = %s;\n" % (name, builtinNames[const.value.type.tag()], value))
-
-        return CGIndenter(CGList(stringDecl(m) for m in self.constants)).define()
+        name = self.constant.identifier.name
+        value = convertConstIDLValueToRust(self.constant.value)
+        return "pub const %s: %s = %s;\n" % (name, builtinNames[self.constant.value.type.tag()], value)
 
 
 def getUnionTypeTemplateVars(type, descriptorProvider):
     if type.isGeckoInterface():
         name = type.inner.identifier.name
         typeName = descriptorProvider.getDescriptor(name).returnType
     elif type.isEnum():
         name = type.inner.identifier.name
@@ -5718,20 +5715,20 @@ class CGDescriptor(CGThing):
                 if (not m.isStatic() and not descriptor.interface.isCallback()):
                     cgThings.append(CGMemberJITInfo(descriptor, m))
 
         if descriptor.concrete:
             cgThings.append(CGClassFinalizeHook(descriptor))
             cgThings.append(CGClassTraceHook(descriptor))
 
         # If there are no constant members, don't make a module for constants
-        constMembers = [m for m in descriptor.interface.members if m.isConst()]
+        constMembers = [CGConstant(m) for m in descriptor.interface.members if m.isConst()]
         if constMembers:
             cgThings.append(CGNamespace.build([descriptor.name + "Constants"],
-                                              CGConstant(constMembers),
+                                              CGIndenter(CGList(constMembers)),
                                               public=True))
             reexports.append(descriptor.name + 'Constants')
 
         if descriptor.proxy:
             cgThings.append(CGDefineProxyHandler(descriptor))
 
         properties = PropertyArrays(descriptor)
 
--- a/servo/components/servo/Cargo.toml
+++ b/servo/components/servo/Cargo.toml
@@ -42,18 +42,20 @@ net = {path = "../net"}
 net_traits = {path = "../net_traits"}
 plugins = {path = "../plugins", optional = true}
 profile = {path = "../profile"}
 profile_traits = {path = "../profile_traits"}
 script = {path = "../script"}
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
 servo_config = {path = "../config"}
+servo_geometry = {path = "../geometry"}
 servo_url = {path = "../url"}
 style = {path = "../style", features = ["servo"]}
+style_traits = {path = "../style_traits", features = ["servo"]}
 webvr = {path = "../webvr"}
 webvr_traits = {path = "../webvr_traits"}
 webdriver_server = {path = "../webdriver_server", optional = true}
 
 [dependencies.webrender]
 git = "https://github.com/servo/webrender"
 default-features = false
 features = ["serde_derive"]
--- a/servo/components/servo/lib.rs
+++ b/servo/components/servo/lib.rs
@@ -40,26 +40,28 @@ pub extern crate msg;
 pub extern crate net;
 pub extern crate net_traits;
 pub extern crate profile;
 pub extern crate profile_traits;
 pub extern crate script;
 pub extern crate script_traits;
 pub extern crate script_layout_interface;
 pub extern crate servo_config;
+pub extern crate servo_geometry;
 pub extern crate servo_url;
 pub extern crate style;
+pub extern crate style_traits;
+pub extern crate webrender_traits;
 pub extern crate webvr;
 pub extern crate webvr_traits;
 
 #[cfg(feature = "webdriver")]
 extern crate webdriver_server;
 
 extern crate webrender;
-extern crate webrender_traits;
 
 #[cfg(feature = "webdriver")]
 fn webdriver(port: u16, constellation: Sender<ConstellationMsg>) {
     webdriver_server::start_server(port, constellation);
 }
 
 #[cfg(not(feature = "webdriver"))]
 fn webdriver(_port: u16, _constellation: Sender<ConstellationMsg>) { }
--- a/servo/components/style/build_gecko.rs
+++ b/servo/components/style/build_gecko.rs
@@ -280,16 +280,17 @@ mod bindings {
             "mozilla::ServoStyleSheet",
             "mozilla::ServoElementSnapshot.*",
             "mozilla::CSSPseudoClassType",
             "mozilla::css::SheetParsingMode",
             "mozilla::HalfCorner",
             "mozilla::PropertyStyleAnimationValuePair",
             "mozilla::TraversalRootBehavior",
             "mozilla::StyleShapeRadius",
+            "mozilla::StyleGrid.*",
             ".*ThreadSafe.*Holder",
             "AnonymousContent",
             "AudioContext",
             "CapturingContentInfo",
             "DefaultDelete",
             "DOMIntersectionObserverEntry",
             "Element",
             "FontFamilyList",
--- a/servo/components/style/gecko/values.rs
+++ b/servo/components/style/gecko/values.rs
@@ -3,23 +3,24 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #![allow(unsafe_code)]
 
 //! Different kind of helpers to interact with Gecko values.
 
 use app_units::Au;
 use cssparser::RGBA;
-use gecko_bindings::structs::{nsStyleCoord, StyleShapeRadius};
+use gecko_bindings::structs::{nsStyleCoord, StyleGridTrackBreadth, StyleShapeRadius};
 use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
 use std::cmp::max;
-use values::{Auto, Either, None_};
+use values::{Auto, Either, None_, Normal};
 use values::computed::{Angle, LengthOrPercentageOrNone, Number};
 use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
 use values::computed::basic_shape::ShapeRadius;
+use values::specified::grid::{TrackBreadth, TrackKeyword};
 
 /// A trait that defines an interface to convert from and to `nsStyleCoord`s.
 pub trait GeckoStyleCoordConvertible : Sized {
     /// Convert this to a `nsStyleCoord`.
     fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T);
     /// Given a `nsStyleCoord`, try to get a value of this type..
     fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self>;
 }
@@ -132,16 +133,49 @@ impl GeckoStyleCoordConvertible for Leng
             CoordDataValue::Percent(p) => Some(LengthOrPercentageOrNone::Percentage(p)),
             CoordDataValue::None => Some(LengthOrPercentageOrNone::None),
             CoordDataValue::Calc(calc) => Some(LengthOrPercentageOrNone::Calc(calc.into())),
             _ => None,
         }
     }
 }
 
+impl<L: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible for TrackBreadth<L> {
+    fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
+        match *self {
+            TrackBreadth::Breadth(ref lop) => lop.to_gecko_style_coord(coord),
+            TrackBreadth::Flex(fr) => coord.set_value(CoordDataValue::FlexFraction(fr)),
+            TrackBreadth::Keyword(TrackKeyword::Auto) => coord.set_value(CoordDataValue::Auto),
+            TrackBreadth::Keyword(TrackKeyword::MinContent) =>
+                coord.set_value(CoordDataValue::Enumerated(StyleGridTrackBreadth::MinContent as u32)),
+            TrackBreadth::Keyword(TrackKeyword::MaxContent) =>
+                coord.set_value(CoordDataValue::Enumerated(StyleGridTrackBreadth::MaxContent as u32)),
+        }
+    }
+
+    fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
+        L::from_gecko_style_coord(coord).map(TrackBreadth::Breadth).or_else(|| {
+            match coord.as_value() {
+                CoordDataValue::Enumerated(v) => {
+                    if v == StyleGridTrackBreadth::MinContent as u32 {
+                        Some(TrackBreadth::Keyword(TrackKeyword::MinContent))
+                    } else if v == StyleGridTrackBreadth::MaxContent as u32 {
+                        Some(TrackBreadth::Keyword(TrackKeyword::MaxContent))
+                    } else {
+                        None
+                    }
+                },
+                CoordDataValue::FlexFraction(fr) => Some(TrackBreadth::Flex(fr)),
+                CoordDataValue::Auto => Some(TrackBreadth::Keyword(TrackKeyword::Auto)),
+                _ => L::from_gecko_style_coord(coord).map(TrackBreadth::Breadth),
+            }
+        })
+    }
+}
+
 impl GeckoStyleCoordConvertible for ShapeRadius {
     fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
         match *self {
             ShapeRadius::ClosestSide => {
                 coord.set_value(CoordDataValue::Enumerated(StyleShapeRadius::ClosestSide as u32))
             }
             ShapeRadius::FarthestSide => {
                 coord.set_value(CoordDataValue::Enumerated(StyleShapeRadius::FarthestSide as u32))
@@ -218,16 +252,30 @@ impl GeckoStyleCoordConvertible for None
         if let CoordDataValue::None = coord.as_value() {
             Some(None_)
         } else {
             None
         }
     }
 }
 
+impl GeckoStyleCoordConvertible for Normal {
+    fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
+        coord.set_value(CoordDataValue::Normal)
+    }
+
+    fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
+        if let CoordDataValue::Normal = coord.as_value() {
+            Some(Normal)
+        } else {
+            None
+        }
+    }
+}
+
 /// Convert a given RGBA value to `nscolor`.
 pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 {
     ((rgba.alpha as u32) << 24) |
     ((rgba.blue as u32) << 16) |
     ((rgba.green as u32) << 8) |
     (rgba.red as u32)
 }
 
--- a/servo/components/style/gecko_bindings/structs_debug.rs
+++ b/servo/components/style/gecko_bindings/structs_debug.rs
@@ -532,22 +532,16 @@ pub mod root {
     pub const NS_STYLE_FONT_BUTTON: ::std::os::raw::c_uint = 13;
     pub const NS_STYLE_FONT_PULL_DOWN_MENU: ::std::os::raw::c_uint = 14;
     pub const NS_STYLE_FONT_LIST: ::std::os::raw::c_uint = 15;
     pub const NS_STYLE_FONT_FIELD: ::std::os::raw::c_uint = 16;
     pub const NS_STYLE_GRID_AUTO_FLOW_ROW: ::std::os::raw::c_uint = 1;
     pub const NS_STYLE_GRID_AUTO_FLOW_COLUMN: ::std::os::raw::c_uint = 2;
     pub const NS_STYLE_GRID_AUTO_FLOW_DENSE: ::std::os::raw::c_uint = 4;
     pub const NS_STYLE_GRID_TEMPLATE_SUBGRID: ::std::os::raw::c_uint = 0;
-    pub const NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT: ::std::os::raw::c_uint
-              =
-        1;
-    pub const NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT: ::std::os::raw::c_uint
-              =
-        2;
     pub const NS_STYLE_GRID_REPEAT_AUTO_FILL: ::std::os::raw::c_uint = 0;
     pub const NS_STYLE_GRID_REPEAT_AUTO_FIT: ::std::os::raw::c_uint = 1;
     pub const NS_STYLE_WIDTH_MAX_CONTENT: ::std::os::raw::c_uint = 0;
     pub const NS_STYLE_WIDTH_MIN_CONTENT: ::std::os::raw::c_uint = 1;
     pub const NS_STYLE_WIDTH_FIT_CONTENT: ::std::os::raw::c_uint = 2;
     pub const NS_STYLE_WIDTH_AVAILABLE: ::std::os::raw::c_uint = 3;
     pub const NS_STYLE_POSITION_STATIC: ::std::os::raw::c_uint = 0;
     pub const NS_STYLE_POSITION_RELATIVE: ::std::os::raw::c_uint = 1;
@@ -5808,16 +5802,19 @@ pub mod root {
             MozGridGroup = 32,
             MozGridLine = 33,
             MozStack = 34,
             MozInlineStack = 35,
             MozDeck = 36,
             MozGroupbox = 37,
             MozPopup = 38,
         }
+        #[repr(u8)]
+        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+        pub enum StyleGridTrackBreadth { MaxContent = 1, MinContent = 2, }
         #[repr(C)]
         #[derive(Debug, Copy, Clone)]
         pub struct WritingMode([u8; 0]);
         #[repr(u32)]
         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
         pub enum LogicalSide {
             eLogicalSideBStart = 0,
             eLogicalSideBEnd = 1,
--- a/servo/components/style/gecko_bindings/structs_release.rs
+++ b/servo/components/style/gecko_bindings/structs_release.rs
@@ -532,22 +532,16 @@ pub mod root {
     pub const NS_STYLE_FONT_BUTTON: ::std::os::raw::c_uint = 13;
     pub const NS_STYLE_FONT_PULL_DOWN_MENU: ::std::os::raw::c_uint = 14;
     pub const NS_STYLE_FONT_LIST: ::std::os::raw::c_uint = 15;
     pub const NS_STYLE_FONT_FIELD: ::std::os::raw::c_uint = 16;
     pub const NS_STYLE_GRID_AUTO_FLOW_ROW: ::std::os::raw::c_uint = 1;
     pub const NS_STYLE_GRID_AUTO_FLOW_COLUMN: ::std::os::raw::c_uint = 2;
     pub const NS_STYLE_GRID_AUTO_FLOW_DENSE: ::std::os::raw::c_uint = 4;
     pub const NS_STYLE_GRID_TEMPLATE_SUBGRID: ::std::os::raw::c_uint = 0;
-    pub const NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT: ::std::os::raw::c_uint
-              =
-        1;
-    pub const NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT: ::std::os::raw::c_uint
-              =
-        2;
     pub const NS_STYLE_GRID_REPEAT_AUTO_FILL: ::std::os::raw::c_uint = 0;
     pub const NS_STYLE_GRID_REPEAT_AUTO_FIT: ::std::os::raw::c_uint = 1;
     pub const NS_STYLE_WIDTH_MAX_CONTENT: ::std::os::raw::c_uint = 0;
     pub const NS_STYLE_WIDTH_MIN_CONTENT: ::std::os::raw::c_uint = 1;
     pub const NS_STYLE_WIDTH_FIT_CONTENT: ::std::os::raw::c_uint = 2;
     pub const NS_STYLE_WIDTH_AVAILABLE: ::std::os::raw::c_uint = 3;
     pub const NS_STYLE_POSITION_STATIC: ::std::os::raw::c_uint = 0;
     pub const NS_STYLE_POSITION_RELATIVE: ::std::os::raw::c_uint = 1;
@@ -5648,16 +5642,19 @@ pub mod root {
             MozGridGroup = 32,
             MozGridLine = 33,
             MozStack = 34,
             MozInlineStack = 35,
             MozDeck = 36,
             MozGroupbox = 37,
             MozPopup = 38,
         }
+        #[repr(u8)]
+        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+        pub enum StyleGridTrackBreadth { MaxContent = 1, MinContent = 2, }
         #[repr(C)]
         #[derive(Debug, Copy, Clone)]
         pub struct WritingMode([u8; 0]);
         #[repr(u32)]
         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
         pub enum LogicalSide {
             eLogicalSideBStart = 0,
             eLogicalSideBEnd = 1,
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -623,16 +623,17 @@ impl Debug for ${style_struct.gecko_stru
                    # transition
                    "transition-duration", "transition-timing-function",
                    "transition-property", "transition-delay",
                    ]
 
     # Types used with predefined_type()-defined properties that we can auto-generate.
     predefined_types = {
         "length::LengthOrAuto": impl_style_coord,
+        "length::LengthOrNormal": impl_style_coord,
         "Length": impl_absolute_length,
         "Position": impl_position,
         "LengthOrPercentage": impl_style_coord,
         "LengthOrPercentageOrAuto": impl_style_coord,
         "LengthOrPercentageOrNone": impl_style_coord,
         "LengthOrNone": impl_style_coord,
         "Number": impl_simple,
         "Opacity": impl_simple,
@@ -956,17 +957,17 @@ fn static_assert() {
                               need_clone=True) %>
     % endfor
 </%self:impl_trait>
 
 <% skip_position_longhands = " ".join(x.ident for x in SIDES + GRID_LINES) %>
 <%self:impl_trait style_struct_name="Position"
                   skip_longhands="${skip_position_longhands} z-index box-sizing order align-content
                                   justify-content align-self justify-self align-items
-                                  justify-items">
+                                  justify-items grid-auto-rows grid-auto-columns">
     % for side in SIDES:
     <% impl_split_style_coord("%s" % side.ident,
                               "mOffset",
                               side.index,
                               need_clone=True) %>
     % endfor
 
     pub fn set_z_index(&mut self, v: longhands::z_index::computed_value::T) {
@@ -1078,16 +1079,46 @@ fn static_assert() {
 
     pub fn copy_${value.name}_from(&mut self, other: &Self) {
         self.gecko.${value.gecko}.mHasSpan = other.gecko.${value.gecko}.mHasSpan;
         self.gecko.${value.gecko}.mInteger = other.gecko.${value.gecko}.mInteger;
         self.gecko.${value.gecko}.mLineName.assign(&*other.gecko.${value.gecko}.mLineName);
     }
     % endfor
 
+    % for kind in ["rows", "columns"]:
+    pub fn set_grid_auto_${kind}(&mut self, v: longhands::grid_auto_rows::computed_value::T) {
+        use values::specified::grid::TrackSize;
+
+        match v {
+            TrackSize::FitContent(lop) => {
+                // Gecko sets min value to None and max value to the actual value in fit-content
+                // https://dxr.mozilla.org/mozilla-central/rev/0eef1d5/layout/style/nsRuleNode.cpp#8221
+                self.gecko.mGridAuto${kind.title()}Min.set_value(CoordDataValue::None);
+                lop.to_gecko_style_coord(&mut self.gecko.mGridAuto${kind.title()}Max);
+            },
+            TrackSize::Breadth(breadth) => {
+                // Set the value to both fields if there's one breadth value
+                // https://dxr.mozilla.org/mozilla-central/rev/0eef1d5/layout/style/nsRuleNode.cpp#8230
+                breadth.to_gecko_style_coord(&mut self.gecko.mGridAuto${kind.title()}Min);
+                breadth.to_gecko_style_coord(&mut self.gecko.mGridAuto${kind.title()}Max);
+            },
+            TrackSize::MinMax(min, max) => {
+                min.to_gecko_style_coord(&mut self.gecko.mGridAuto${kind.title()}Min);
+                max.to_gecko_style_coord(&mut self.gecko.mGridAuto${kind.title()}Max);
+            },
+        }
+    }
+
+    pub fn copy_grid_auto_${kind}_from(&mut self, other: &Self) {
+        self.gecko.mGridAuto${kind.title()}Min.copy_from(&other.gecko.mGridAuto${kind.title()}Min);
+        self.gecko.mGridAuto${kind.title()}Max.copy_from(&other.gecko.mGridAuto${kind.title()}Max);
+    }
+    % endfor
+
 </%self:impl_trait>
 
 <% skip_outline_longhands = " ".join("outline-style outline-width".split() +
                                      ["-moz-outline-radius-{0}".format(x.ident.replace("_", ""))
                                       for x in CORNERS]) %>
 <%self:impl_trait style_struct_name="Outline"
                   skip_longhands="${skip_outline_longhands}"
                   skip_additionals="*">
@@ -3006,43 +3037,32 @@ clip-path
         self.gecko.mCursor = other.gecko.mCursor;
         unsafe {
             Gecko_CopyCursorArrayFrom(&mut self.gecko, &other.gecko);
         }
     }
 </%self:impl_trait>
 
 <%self:impl_trait style_struct_name="Column"
-                  skip_longhands="column-count column-gap column-rule-width">
+                  skip_longhands="column-count column-rule-width">
 
     #[allow(unused_unsafe)]
     pub fn set_column_count(&mut self, v: longhands::column_count::computed_value::T) {
         use gecko_bindings::structs::{NS_STYLE_COLUMN_COUNT_AUTO, nsStyleColumn_kMaxColumnCount};
 
         self.gecko.mColumnCount = match v.0 {
             Some(number) => unsafe {
                 cmp::min(number, nsStyleColumn_kMaxColumnCount)
             },
             None => NS_STYLE_COLUMN_COUNT_AUTO
         };
     }
 
     ${impl_simple_copy('column_count', 'mColumnCount')}
 
-    pub fn set_column_gap(&mut self, v: longhands::column_gap::computed_value::T) {
-        use values::Either;
-
-        match v {
-            Either::First(len) => self.gecko.mColumnGap.set(len),
-            Either::Second(_normal) => self.gecko.mColumnGap.set_value(CoordDataValue::Normal),
-        }
-    }
-
-    <%call expr="impl_coord_copy('column_gap', 'mColumnGap')"></%call>
-
     <% impl_app_units("column_rule_width", "mColumnRuleWidth", need_clone=True,
                       round_to_pixels=True) %>
 </%self:impl_trait>
 
 <%self:impl_trait style_struct_name="Counters"
                   skip_longhands="content">
     pub fn set_content(&mut self, v: longhands::content::computed_value::T) {
         use properties::longhands::content::computed_value::T;
--- a/servo/components/style/properties/longhand/position.mako.rs
+++ b/servo/components/style/properties/longhand/position.mako.rs
@@ -250,33 +250,36 @@
 ${helpers.predefined_type("object-position",
                           "Position",
                           "computed::Position::zero()",
                           products="gecko",
                           boxed="True",
                           spec="https://drafts.csswg.org/css-images-3/#the-object-position",
                           animatable=True)}
 
-<% grid_longhands = ["grid-row-start", "grid-row-end", "grid-column-start", "grid-column-end"] %>
+% for kind in ["row", "column"]:
+    ${helpers.predefined_type("grid-%s-gap" % kind,
+                              "LengthOrPercentage",
+                              "computed::LengthOrPercentage::Length(Au(0))",
+                              spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-gap" % kind,
+                              animatable=True,
+                              products="gecko")}
 
-% for longhand in grid_longhands:
-    ${helpers.predefined_type("%s" % longhand,
-                              "GridLine",
+    % for range in ["start", "end"]:
+        ${helpers.predefined_type("grid-%s-%s" % (kind, range),
+                                  "GridLine",
+                                  "Default::default()",
+                                  animatable=False,
+                                  spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-%s" % (kind, range),
+                                  products="gecko",
+                                  boxed=True)}
+    % endfor
+
+    // NOTE: According to the spec, this should handle multiple values of `<track-size>`,
+    // but gecko supports only a single value
+    ${helpers.predefined_type("grid-auto-%ss" % kind,
+                              "TrackSize",
                               "Default::default()",
                               animatable=False,
-                              spec="https://drafts.csswg.org/css-grid/#propdef-%s" % longhand,
+                              spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-%ss" % kind,
                               products="gecko",
                               boxed=True)}
 % endfor
-
-${helpers.predefined_type("grid-row-gap",
-                          "LengthOrPercentage",
-                          "computed::LengthOrPercentage::Length(Au(0))",
-                          spec="https://drafts.csswg.org/css-grid/#propdef-grid-row-gap",
-                          animatable=True,
-                          products="gecko")}
-
-${helpers.predefined_type("grid-column-gap",
-                          "LengthOrPercentage",
-                          "computed::LengthOrPercentage::Length(Au(0))",
-                          spec="https://drafts.csswg.org/css-grid/#propdef-grid-column-gap",
-                          animatable=True,
-                          products="gecko")}
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -6,16 +6,17 @@
 
 use app_units::Au;
 use euclid::size::Size2D;
 use font_metrics::FontMetricsProvider;
 use properties::ComputedValues;
 use std::fmt;
 use style_traits::ToCss;
 use super::{CSSFloat, RGBA, specified};
+use super::specified::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
 
 pub use cssparser::Color as CSSColor;
 pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientKind, Image};
 pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
 pub use super::{Auto, Either, None_};
 #[cfg(feature = "gecko")]
 pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
 pub use super::specified::{Angle, BorderStyle, GridLine, Time, UrlOrNone};
@@ -321,16 +322,22 @@ impl ToCss for ClipRect {
         try!(self.left.to_css(dest));
         dest.write_str(")")
     }
 }
 
 /// rect(...) | auto
 pub type ClipRectOrAuto = Either<ClipRect, Auto>;
 
+/// The computed value of a grid `<track-breadth>`
+pub type TrackBreadth = GenericTrackBreadth<LengthOrPercentage>;
+
+/// The computed value of a grid `<track-size>`
+pub type TrackSize = GenericTrackSize<LengthOrPercentage>;
+
 impl ClipRectOrAuto {
     /// Return an auto (default for clip-rect and image-region) value
     pub fn auto() -> Self {
         Either::Second(Auto)
     }
 
     /// Check if it is auto
     pub fn is_auto(&self) -> bool {
--- a/servo/components/style/values/specified/grid.rs
+++ b/servo/components/style/values/specified/grid.rs
@@ -1,28 +1,36 @@
 /* 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/. */
 
-//! A grid line type.
+//! Necessary types for [grid](https://drafts.csswg.org/css-grid/).
 
-use cssparser::Parser;
+use cssparser::{Parser, Token};
 use parser::{Parse, ParserContext};
 use std::fmt;
 use style_traits::ToCss;
-use values::HasViewportPercentage;
-use values::computed::ComputedValueAsSpecified;
+use values::{CSSFloat, HasViewportPercentage};
+use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
+use values::specified::LengthOrPercentage;
 
 #[derive(PartialEq, Clone, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+/// A `<grid-line>` type.
+///
 /// https://drafts.csswg.org/css-grid/#typedef-grid-row-start-grid-line
 #[allow(missing_docs)]
 pub struct GridLine {
+    /// Flag to check whether it's a `span` keyword.
     pub is_span: bool,
+    /// A custom identifier for named lines.
+    ///
+    /// https://drafts.csswg.org/css-grid/#grid-placement-slot
     pub ident: Option<String>,
+    /// Denotes the nth grid line from grid item's placement.
     pub integer: Option<i32>,
 }
 
 impl Default for GridLine {
     fn default() -> Self {
         GridLine {
             is_span: false,
             ident: None,
@@ -92,8 +100,204 @@ impl Parse for GridLine {
         }
 
         Ok(grid_line)
     }
 }
 
 impl ComputedValueAsSpecified for GridLine {}
 no_viewport_percentage!(GridLine);
+
+define_css_keyword_enum!{ TrackKeyword:
+    "auto" => Auto,
+    "max-content" => MaxContent,
+    "min-content" => MinContent
+}
+
+#[derive(Clone, PartialEq, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+/// A track breadth for explicit grid track sizing. It's generic solely to
+/// avoid re-implementing it for the computed type.
+///
+/// https://drafts.csswg.org/css-grid/#typedef-track-breadth
+pub enum TrackBreadth<L> {
+    /// The generic type is almost always a non-negative `<length-percentage>`
+    Breadth(L),
+    /// A flex fraction specified in `fr` units.
+    Flex(CSSFloat),
+    /// One of the track-sizing keywords (`auto`, `min-content`, `max-content`)
+    Keyword(TrackKeyword),
+}
+
+/// Parse a single flexible length.
+pub fn parse_flex(input: &mut Parser) -> Result<CSSFloat, ()> {
+    match try!(input.next()) {
+        Token::Dimension(ref value, ref unit) if unit.to_lowercase() == "fr" && value.value.is_sign_positive()
+            => Ok(value.value),
+        _ => Err(()),
+    }
+}
+
+impl Parse for TrackBreadth<LengthOrPercentage> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        if let Ok(lop) = input.try(LengthOrPercentage::parse_non_negative) {
+            Ok(TrackBreadth::Breadth(lop))
+        } else {
+            if let Ok(f) = input.try(parse_flex) {
+                Ok(TrackBreadth::Flex(f))
+            } else {
+                TrackKeyword::parse(input).map(TrackBreadth::Keyword)
+            }
+        }
+    }
+}
+
+impl<L: ToCss> ToCss for TrackBreadth<L> {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        match *self {
+            TrackBreadth::Breadth(ref lop) => lop.to_css(dest),
+            TrackBreadth::Flex(ref value) => write!(dest, "{}fr", value),
+            TrackBreadth::Keyword(ref k) => k.to_css(dest),
+        }
+    }
+}
+
+impl HasViewportPercentage for TrackBreadth<LengthOrPercentage> {
+    #[inline]
+    fn has_viewport_percentage(&self) -> bool {
+        if let TrackBreadth::Breadth(ref lop) = *self {
+            lop.has_viewport_percentage()
+        } else {
+            false
+        }
+    }
+}
+
+impl<L: ToComputedValue> ToComputedValue for TrackBreadth<L> {
+    type ComputedValue = TrackBreadth<L::ComputedValue>;
+
+    #[inline]
+    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
+        match *self {
+            TrackBreadth::Breadth(ref lop) => TrackBreadth::Breadth(lop.to_computed_value(context)),
+            TrackBreadth::Flex(fr) => TrackBreadth::Flex(fr),
+            TrackBreadth::Keyword(k) => TrackBreadth::Keyword(k),
+        }
+    }
+
+    #[inline]
+    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
+        match *computed {
+            TrackBreadth::Breadth(ref lop) =>
+                TrackBreadth::Breadth(ToComputedValue::from_computed_value(lop)),
+            TrackBreadth::Flex(fr) => TrackBreadth::Flex(fr),
+            TrackBreadth::Keyword(k) => TrackBreadth::Keyword(k),
+        }
+    }
+}
+
+#[derive(Clone, PartialEq, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+/// A `<track-size>` type for explicit grid track sizing. Like `<track-breadth>`, this is
+/// generic only to avoid code bloat. It only takes `<length-percentage>`
+///
+/// https://drafts.csswg.org/css-grid/#typedef-track-size
+pub enum TrackSize<L> {
+    /// A flexible `<track-breadth>`
+    Breadth(TrackBreadth<L>),
+    /// A `minmax` function for a range over an inflexible `<track-breadth>`
+    /// and a flexible `<track-breadth>`
+    ///
+    /// https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-minmax
+    MinMax(TrackBreadth<L>, TrackBreadth<L>),
+    /// A `fit-content` function.
+    ///
+    /// https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-fit-content
+    FitContent(L),
+}
+
+impl<L> Default for TrackSize<L> {
+    fn default() -> Self {
+        TrackSize::Breadth(TrackBreadth::Keyword(TrackKeyword::Auto))
+    }
+}
+
+impl Parse for TrackSize<LengthOrPercentage> {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        if let Ok(b) = input.try(|i| TrackBreadth::parse(context, i)) {
+            Ok(TrackSize::Breadth(b))
+        } else {
+            if input.try(|i| i.expect_function_matching("minmax")).is_ok() {
+                Ok(try!(input.parse_nested_block(|input| {
+                    let inflexible_breadth = if let Ok(lop) = input.try(LengthOrPercentage::parse_non_negative) {
+                        Ok(TrackBreadth::Breadth(lop))
+                    } else {
+                        TrackKeyword::parse(input).map(TrackBreadth::Keyword)
+                    };
+
+                    try!(input.expect_comma());
+                    Ok(TrackSize::MinMax(try!(inflexible_breadth), try!(TrackBreadth::parse(context, input))))
+                })))
+            } else {
+                try!(input.expect_function_matching("fit-content"));
+                Ok(try!(LengthOrPercentage::parse(context, input).map(TrackSize::FitContent)))
+            }
+        }
+    }
+}
+
+impl<L: ToCss> ToCss for TrackSize<L> {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        match *self {
+            TrackSize::Breadth(ref b) => b.to_css(dest),
+            TrackSize::MinMax(ref infexible, ref flexible) => {
+                try!(dest.write_str("minmax("));
+                try!(infexible.to_css(dest));
+                try!(dest.write_str(","));
+                try!(flexible.to_css(dest));
+                dest.write_str(")")
+            },
+            TrackSize::FitContent(ref lop) => {
+                try!(dest.write_str("fit-content("));
+                try!(lop.to_css(dest));
+                dest.write_str(")")
+            },
+        }
+    }
+}
+
+impl HasViewportPercentage for TrackSize<LengthOrPercentage> {
+    #[inline]
+    fn has_viewport_percentage(&self) -> bool {
+        match *self {
+            TrackSize::Breadth(ref b) => b.has_viewport_percentage(),
+            TrackSize::MinMax(ref inf_b, ref b) => inf_b.has_viewport_percentage() || b.has_viewport_percentage(),
+            TrackSize::FitContent(ref lop) => lop.has_viewport_percentage(),
+        }
+    }
+}
+
+impl<L: ToComputedValue> ToComputedValue for TrackSize<L> {
+    type ComputedValue = TrackSize<L::ComputedValue>;
+
+    #[inline]
+    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
+        match *self {
+            TrackSize::Breadth(ref b) => TrackSize::Breadth(b.to_computed_value(context)),
+            TrackSize::MinMax(ref b_1, ref b_2) =>
+                TrackSize::MinMax(b_1.to_computed_value(context), b_2.to_computed_value(context)),
+            TrackSize::FitContent(ref lop) => TrackSize::FitContent(lop.to_computed_value(context)),
+        }
+    }
+
+    #[inline]
+    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
+        match *computed {
+            TrackSize::Breadth(ref b) =>
+                TrackSize::Breadth(ToComputedValue::from_computed_value(b)),
+            TrackSize::MinMax(ref b_1, ref b_2) =>
+                TrackSize::MinMax(ToComputedValue::from_computed_value(b_1),
+                                  ToComputedValue::from_computed_value(b_2)),
+            TrackSize::FitContent(ref lop) =>
+                TrackSize::FitContent(ToComputedValue::from_computed_value(lop)),
+        }
+    }
+}
--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.rs
@@ -491,20 +491,34 @@ impl Length {
 }
 
 impl Parse for Length {
     fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         Length::parse_internal(input, AllowedNumericType::All)
     }
 }
 
-impl<T> Either<Length, T> {
+impl Either<Length, Normal> {
     #[inline]
     #[allow(missing_docs)]
-    pub fn parse_non_negative_length(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+    pub fn parse_non_negative_length(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        if input.try(|input| Normal::parse(context, input)).is_ok() {
+            return Ok(Either::Second(Normal));
+        }
+        Length::parse_internal(input, AllowedNumericType::NonNegative).map(Either::First)
+    }
+}
+
+impl Either<Length, Auto> {
+    #[inline]
+    #[allow(missing_docs)]
+    pub fn parse_non_negative_length(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        if input.try(|input| Auto::parse(context, input)).is_ok() {
+            return Ok(Either::Second(Auto));
+        }
         Length::parse_internal(input, AllowedNumericType::NonNegative).map(Either::First)
     }
 }
 
 /// A calc sum expression node.
 #[derive(Clone, Debug)]
 pub struct CalcSumNode {
     /// The products of this node.
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -5,29 +5,30 @@
 //! Specified values.
 //!
 //! TODO(emilio): Enhance docs.
 
 use app_units::Au;
 use cssparser::{self, Parser, Token};
 use euclid::size::Size2D;
 use parser::{ParserContext, Parse};
+use self::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
 use self::url::SpecifiedUrl;
 use std::ascii::AsciiExt;
 use std::f32::consts::PI;
 use std::fmt;
 use std::ops::Mul;
 use style_traits::ToCss;
 use super::{Auto, CSSFloat, HasViewportPercentage, Either, None_};
 use super::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
 use super::computed::Shadow as ComputedShadow;
 
 #[cfg(feature = "gecko")]
 pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
-pub use self::grid::GridLine;
+pub use self::grid::{GridLine, TrackKeyword};
 pub use self::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient};
 pub use self::image::{GradientKind, HorizontalDirection, Image, LengthOrKeyword, LengthOrPercentageOrKeyword};
 pub use self::image::{SizeKeyword, VerticalDirection};
 pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage};
 pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
 pub use self::length::{LengthOrPercentageOrNone, LengthOrPercentageOrAutoOrContent, NoCalcLength, CalcUnit};
 pub use self::position::{HorizontalPosition, Position, VerticalPosition};
 
@@ -549,16 +550,22 @@ impl ToCss for Opacity {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         self.0.to_css(dest)
     }
 }
 
 #[allow(missing_docs)]
 pub type UrlOrNone = Either<SpecifiedUrl, None_>;
 
+/// The specified value of a grid `<track-breadth>`
+pub type TrackBreadth = GenericTrackBreadth<LengthOrPercentage>;
+
+/// The specified value of a grid `<track-size>`
+pub type TrackSize = GenericTrackSize<LengthOrPercentage>;
+
 #[derive(Debug, Clone, PartialEq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[allow(missing_docs)]
 pub struct Shadow {
     pub offset_x: Length,
     pub offset_y: Length,
     pub blur_radius: Length,
     pub spread_radius: Length,
--- a/servo/support/rust-task_info/src/lib.rs
+++ b/servo/support/rust-task_info/src/lib.rs
@@ -5,14 +5,10 @@
 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
 #![crate_name = "task_info"]
 #![crate_type = "rlib"]
 
-#![feature(libc)]
-
-extern crate libc;
-
 pub mod task_basic_info;
 
--- a/servo/support/rust-task_info/src/task_basic_info.rs
+++ b/servo/support/rust-task_info/src/task_basic_info.rs
@@ -5,17 +5,20 @@
 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
 //! Interface to the measurements in the task_basic_info struct, gathered by
 //! invoking `task_info()` with the `TASK_BASIC_INFO` flavor.
 
-use libc::{c_int, size_t};
+use std::os::raw::c_int;
+
+#[allow(non_camel_case_types)]
+type size_t = usize;
 
 /// Obtains task_basic_info::virtual_size.
 pub fn virtual_size() -> Option<usize> {
     let mut virtual_size: size_t = 0;
     let rv = unsafe {
         TaskBasicInfoVirtualSize(&mut virtual_size)
     };
     if rv == 0 { Some(virtual_size as usize) } else { None }
new file mode 100644
--- /dev/null
+++ b/servo/tests/unit/style/parsing/column.rs
@@ -0,0 +1,42 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use cssparser::Parser;
+use media_queries::CSSErrorReporterTest;
+use servo_url::ServoUrl;
+use style::parser::ParserContext;
+use style::stylesheets::Origin;
+use style_traits::ToCss;
+
+#[test]
+fn test_column_width() {
+    use style::properties::longhands::column_width;
+
+    assert_roundtrip_with_context!(column_width::parse, "auto");
+    assert_roundtrip_with_context!(column_width::parse, "6px");
+    assert_roundtrip_with_context!(column_width::parse, "2.5em");
+    assert_roundtrip_with_context!(column_width::parse, "0.3vw");
+
+    let url = ServoUrl::parse("http://localhost").unwrap();
+    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+
+    let mut negative = Parser::new("-6px");
+    assert!(column_width::parse(&context, &mut negative).is_err());
+}
+
+#[test]
+fn test_column_gap() {
+    use style::properties::longhands::column_gap;
+
+    assert_roundtrip_with_context!(column_gap::parse, "normal");
+    assert_roundtrip_with_context!(column_gap::parse, "6px");
+    assert_roundtrip_with_context!(column_gap::parse, "2.5em");
+    assert_roundtrip_with_context!(column_gap::parse, "0.3vw");
+
+    let url = ServoUrl::parse("http://localhost").unwrap();
+    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+
+    let mut negative = Parser::new("-6px");
+    assert!(column_gap::parse(&context, &mut negative).is_err());
+}
--- a/servo/tests/unit/style/parsing/mod.rs
+++ b/servo/tests/unit/style/parsing/mod.rs
@@ -65,16 +65,17 @@ macro_rules! parse_longhand {
         $name::parse(&context, &mut Parser::new($s)).unwrap()
     }};
 }
 
 mod animation;
 mod background;
 mod basic_shape;
 mod border;
+mod column;
 mod font;
 mod image;
 mod inherited_box;
 mod inherited_text;
 mod mask;
 mod outline;
 mod position;
 mod selectors;
--- a/toolkit/components/places/UnifiedComplete.js
+++ b/toolkit/components/places/UnifiedComplete.js
@@ -260,16 +260,18 @@ const SQL_BOOKMARKED_URL_QUERY = urlQuer
 
 const SQL_BOOKMARKED_TYPED_URL_QUERY = urlQuery("AND bookmarked AND h.typed = 1");
 
 // Getters
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
+Cu.importGlobalProperties(["fetch"]);
+
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
                                   "resource://gre/modules/TelemetryStopwatch.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
                                   "resource://gre/modules/Preferences.jsm");
@@ -554,34 +556,31 @@ function PrefillSite(url, title) {
   this.uri = NetUtil.newURI(url);
   this.title = title;
   this._matchTitle = title.toLowerCase();
 }
 
 /**
  * Storage object for Prefill Sites.
  *   add(url, title): adds a site to storage
- *   populate() : populates the  storage with data (hard-coded for now)
+ *   populate(sites) : populates the  storage with array of [url,title]
  *   sites[]: resulting array of sites (PrefillSite objects)
  */
 XPCOMUtils.defineLazyGetter(this, "PrefillSiteStorage", () => Object.seal({
   sites: [],
 
   add(url, title) {
     let site = new PrefillSite(url, title);
     this.sites.push(site);
   },
 
-  populate() {
-    this.add("https://google.com/", "Google");
-    this.add("https://youtube.com/", "YouTube");
-    this.add("https://facebook.com/", "Facebook");
-    this.add("https://baidu.com/", "\u767E\u5EA6\u4E00\u4E0B\uFF0C\u4F60\u5C31\u77E5\u9053");
-    this.add("https://wikipedia.org/", "Wikipedia");
-    this.add("https://yahoo.com/", "Yahoo");
+  populate(sites) {
+    for (let site of sites) {
+      this.add(site[0], site[1]);
+    }
   },
 }));
 
 XPCOMUtils.defineLazyGetter(this, "ProfileAgeCreatedPromise", () => {
   return (new ProfileAge(null, null)).created;
 });
 
 // Helper functions
@@ -2072,17 +2071,21 @@ function UnifiedComplete() {
   // open pages should be set to false.
   Prefs;
 
   if (Prefs.prefillSitesEnabled) {
     // force initializing the profile age check
     // to ensure the off-main-thread-IO happens ASAP
     // and we don't have to wait for it when doing an autocomplete lookup
     ProfileAgeCreatedPromise;
-    PrefillSiteStorage.populate(); // with hard-coded data for now
+
+    fetch("chrome://global/content/unifiedcomplete-top-urls.json")
+      .then(response => response.json())
+      .then(sites => PrefillSiteStorage.populate(sites))
+      .catch(ex => Cu.reportError(ex));
   }
 }
 
 UnifiedComplete.prototype = {
   // Database handling
 
   /**
    * Promise resolved when the database initialization has completed, or null
@@ -2143,16 +2146,20 @@ UnifiedComplete.prototype = {
   unregisterOpenPage(uri, userContextId) {
     SwitchToTabStorage.delete(uri, userContextId);
   },
 
   addPrefillSite(url, title) {
     PrefillSiteStorage.add(url, title);
   },
 
+  populatePrefillSiteStorage(json) {
+    PrefillSiteStorage.populate(json);
+  },
+
   // nsIAutoCompleteSearch
 
   startSearch(searchString, searchParam, previousResult, listener) {
     // Stop the search in case the controller has not taken care of it.
     if (this._currentSearch) {
       this.stopSearch();
     }
 
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/jar.mn
@@ -0,0 +1,2 @@
+toolkit.jar:
+  content/global/unifiedcomplete-top-urls.json
--- a/toolkit/components/places/moz.build
+++ b/toolkit/components/places/moz.build
@@ -90,8 +90,10 @@ if CONFIG['MOZ_PLACES']:
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 with Files('**'):
     BUG_COMPONENT = ('Toolkit', 'Places')
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
+
+JAR_MANIFESTS += ['jar.mn']
--- a/toolkit/components/places/mozIPlacesAutoComplete.idl
+++ b/toolkit/components/places/mozIPlacesAutoComplete.idl
@@ -140,9 +140,17 @@ interface mozIPlacesAutoComplete : nsISu
    * Add a site to list of Prefill Sites.
    *
    * @param url
    *        The URL of added site.
    * @param title
    *        The title of added site.
    */
   void addPrefillSite(in AUTF8String url, in AUTF8String title);
+
+  /**
+   * Populate list of Prefill Sites from JSON.
+   *
+   * @param sites
+   *        Array of [url,title] to populate from.
+   */
+  void populatePrefillSiteStorage(in jsval sites);
 };
--- a/toolkit/components/places/tests/unifiedcomplete/test_prefill_sites.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_prefill_sites.js
@@ -4,16 +4,18 @@
  */
 
 const PREF_FEATURE_ENABLED = "browser.urlbar.usepreloadedtopurls.enabled";
 const PREF_FEATURE_EXPIRE_DAYS = "browser.urlbar.usepreloadedtopurls.expire_days";
 
 const autocompleteObject = Cc["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"]
                              .getService(Ci.mozIPlacesAutoComplete);
 
+Cu.importGlobalProperties(["fetch"]);
+
 // With or without trailing slash - no matter. URI.spec does have it always.
 // Then, check_autocomplete() doesn't cut it off (uses stripPrefix()).
 let yahoooURI = NetUtil.newURI("https://yahooo.com/");
 let gooogleURI = NetUtil.newURI("https://gooogle.com/");
 
 autocompleteObject.addPrefillSite(yahoooURI.spec, "Yahooo");
 autocompleteObject.addPrefillSite(gooogleURI.spec, "Gooogle");
 
@@ -109,8 +111,32 @@ add_task(function* test_sorting_against_
       { uri: yahoooURI, title: "Yahooo",  style: ["prefill-site"] },
       { uri: gooogleURI, title: "Gooogle", style: ["prefill-site"] },
     ],
   });
 
   yield cleanup();
 });
 
+add_task(function* test_data_file() {
+  let response = yield fetch("chrome://global/content/unifiedcomplete-top-urls.json");
+
+  do_print("Source file is supplied and fetched OK");
+  Assert.ok(response.ok);
+
+  do_print("The JSON is parsed");
+  let sites = yield response.json();
+
+  do_print("Storage is populated");
+  autocompleteObject.populatePrefillSiteStorage(sites);
+
+  let lastSite = sites.pop();
+  let uri = NetUtil.newURI(lastSite[0]);
+  let title = lastSite[1];
+
+  do_print("Storage is populated from JSON correctly");
+  yield check_autocomplete({
+    search: uri.host.slice(1), // omit 1st letter to avoid style:"autofill" result
+    matches: [ { uri, title,  style: ["prefill-site"] } ],
+  });
+
+  yield cleanup();
+});
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/unifiedcomplete-top-urls.json
@@ -0,0 +1,8 @@
+[
+  ["https://google.com/", "Google"],
+  ["https://youtube.com/", "YouTube"],
+  ["https://facebook.com/", "Facebook"],
+  ["https://baidu.com/", "\u767E\u5EA6\u4E00\u4E0B\uFF0C\u4F60\u5C31\u77E5\u9053"],
+  ["https://wikipedia.org/", "Wikipedia"],
+  ["https://yahoo.com/", "Yahoo"]
+]
\ No newline at end of file
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -155,31 +155,31 @@
                   tabindex="-1"/>
           <div anonid="scrubberStack" class="scrubberStack progressContainer" role="none">
             <div class="progressBackgroundBar stackItem" role="none">
               <div class="progressStack" role="none">
                 <progress anonid="bufferBar" class="bufferBar" value="0" max="100" tabindex="-1"></progress>
                 <progress anonid="progressBar" class="progressBar" value="0" max="100" tabindex="-1"></progress>
               </div>
             </div>
-            <input type="range" anonid="scrubber" class="scrubber" tabindex="-1"/>
+            <input type="range" anonid="scrubber" class="scrubber" tabindex="-1" mozinputrangeignorepreventdefault="true" />
           </div>
           <span anonid="positionLabel" class="positionLabel" role="presentation"></span>
           <span anonid="durationLabel" class="durationLabel" role="presentation"></span>
           <span anonid="positionDurationBox" class="positionDurationBox" aria-hidden="true">
             &positionAndDuration.nameFormat;
           </span>
           <div anonid="controlBarSpacer" class="controlBarSpacer" hidden="true" role="none"></div>
           <button anonid="muteButton"
                   class="muteButton"
                   mutelabel="&muteButton.muteLabel;"
                   unmutelabel="&muteButton.unmuteLabel;"
                   tabindex="-1"/>
           <div anonid="volumeStack" class="volumeStack progressContainer" role="none">
-            <input type="range" anonid="volumeControl" class="volumeControl" min="0" max="100" step="1" tabindex="-1"/>
+            <input type="range" anonid="volumeControl" class="volumeControl" min="0" max="100" step="1" tabindex="-1" mozinputrangeignorepreventdefault="true" />
           </div>
           <button anonid="closedCaptionButton" class="closedCaptionButton"/>
           <button anonid="fullscreenButton"
                   class="fullscreenButton"
                   enterfullscreenlabel="&fullscreenButton.enterfullscreenlabel;"
                   exitfullscreenlabel="&fullscreenButton.exitfullscreenlabel;"/>
         </div>
         <div anonid="textTrackList" class="textTrackList" hidden="true" offlabel="&closedCaption.off;"></div>
--- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm
+++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm
@@ -197,29 +197,27 @@ this.ForgetAboutSite = {
     }));
 
     // HSTS and HPKP
     try {
       let sss = Cc["@mozilla.org/ssservice;1"].
                 getService(Ci.nsISiteSecurityService);
       for (let type of [Ci.nsISiteSecurityService.HEADER_HSTS,
                         Ci.nsISiteSecurityService.HEADER_HPKP]) {
-        sss.removeState(type, httpsURI, 0);
-
         // Also remove HSTS/HPKP information for subdomains by enumerating the
         // information in the site security service.
         let enumerator = sss.enumerate(type);
         while (enumerator.hasMoreElements()) {
           let entry = enumerator.getNext();
           let hostname = entry.QueryInterface(Ci.nsISiteSecurityState).hostname;
           // If the hostname is aDomain's subdomain, we remove its state.
-          if (hostname.endsWith("." + aDomain)) {
+          if (hostname == aDomain || hostname.endsWith("." + aDomain)) {
             // This uri is used as a key to remove the state.
             let uri = caUtils.makeURI("https://" + hostname);
-            sss.removeState(type, uri, 0);
+            sss.removeState(type, uri, 0, entry.originAttributes);
           }
         }
       }
     } catch (e) {
       Cu.reportError("Exception thrown while clearing HSTS/HPKP: " +
                      e.toString());
     }
 
--- a/widget/NativeKeyToDOMKeyName.h
+++ b/widget/NativeKeyToDOMKeyName.h
@@ -196,16 +196,17 @@ KEY_MAP_GTK     (Enter, GDK_3270_Enter)
 KEY_MAP_ANDROID (Enter, AKEYCODE_DPAD_CENTER)
 KEY_MAP_ANDROID (Enter, AKEYCODE_ENTER)
 KEY_MAP_ANDROID (Enter, AKEYCODE_NUMPAD_ENTER)
 
 // Tab
 KEY_MAP_WIN     (Tab, VK_TAB)
 KEY_MAP_COCOA   (Tab, kVK_Tab)
 KEY_MAP_GTK     (Tab, GDK_Tab)
+KEY_MAP_GTK     (Tab, GDK_ISO_Left_Tab) // Shift+Tab
 KEY_MAP_GTK     (Tab, GDK_KP_Tab)
 KEY_MAP_ANDROID (Tab, AKEYCODE_TAB)
 
 /******************************************************************************
  * Navigation Keys
  ******************************************************************************/
 // ArrowDown
 KEY_MAP_WIN     (ArrowDown, VK_DOWN)
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -97,16 +97,30 @@ NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, n
 
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/CompositorSession.h"
 #include "mozilla/layers/LayerTransactionParent.h"
 #include "mozilla/layers/UiCompositorControllerChild.h"
 #include "mozilla/Services.h"
 #include "nsThreadUtils.h"
 
+static TimeStamp
+GetEventTimeStamp(int64_t aEventTime)
+{
+    // Android's event time is SystemClock.uptimeMillis that is counted in ms
+    // since OS was booted.
+    // (https://developer.android.com/reference/android/os/SystemClock.html)
+    // and this SystemClock.uptimeMillis uses SYSTEM_TIME_MONOTONIC.
+    // Our posix implemententaion of TimeStamp::Now uses SYSTEM_TIME_MONOTONIC
+    //  too. Due to same implementation, we can use this via FromSystemTime.
+    int64_t tick =
+        BaseTimeDurationPlatformUtils::TicksFromMilliseconds(aEventTime);
+    return TimeStamp::FromSystemTime(tick);
+}
+
 // All the toplevel windows that have been created; these are in
 // stacking order, so the window at gTopLevelWindows[0] is the topmost
 // one.
 static nsTArray<nsWindow*> gTopLevelWindows;
 
 static bool sFailedToCreateGLContext = false;
 
 // Multitouch swipe thresholds in inches
@@ -633,17 +647,17 @@ public:
         }
 
         if (!controller) {
             return false;
         }
 
         ScreenPoint origin = ScreenPoint(aX, aY);
 
-        ScrollWheelInput input(aTime, TimeStamp::Now(), GetModifiers(aMetaState),
+        ScrollWheelInput input(aTime, GetEventTimeStamp(aTime), GetModifiers(aMetaState),
                                ScrollWheelInput::SCROLLMODE_SMOOTH,
                                ScrollWheelInput::SCROLLDELTA_PIXEL,
                                origin,
                                aHScroll, aVScroll,
                                false);
 
         ScrollableLayerGuid guid;
         uint64_t blockId;
@@ -752,17 +766,17 @@ public:
         }
 
         if (mouseType == MouseInput::MOUSE_NONE) {
             return false;
         }
 
         ScreenPoint origin = ScreenPoint(aX, aY);
 
-        MouseInput input(mouseType, buttonType, nsIDOMMouseEvent::MOZ_SOURCE_MOUSE, ConvertButtons(buttons), origin, aTime, TimeStamp(), GetModifiers(aMetaState));
+        MouseInput input(mouseType, buttonType, nsIDOMMouseEvent::MOZ_SOURCE_MOUSE, ConvertButtons(buttons), origin, aTime, GetEventTimeStamp(aTime), GetModifiers(aMetaState));
 
         ScrollableLayerGuid guid;
         uint64_t blockId;
         nsEventStatus status = controller->ReceiveInputEvent(input, &guid, &blockId);
 
         if (status == nsEventStatus_eConsumeNoDefault) {
             return true;
         }
@@ -823,17 +837,17 @@ public:
             case sdk::MotionEvent::ACTION_OUTSIDE:
             case sdk::MotionEvent::ACTION_CANCEL:
                 type = MultiTouchInput::MULTITOUCH_CANCEL;
                 break;
             default:
                 return false;
         }
 
-        MultiTouchInput input(type, aTime, TimeStamp(), 0);
+        MultiTouchInput input(type, aTime, GetEventTimeStamp(aTime), 0);
         input.modifiers = GetModifiers(aMetaState);
         input.mTouches.SetCapacity(endIndex - startIndex);
 
         nsTArray<float> x(aX->GetElements());
         nsTArray<float> y(aY->GetElements());
         nsTArray<float> orientation(aOrientation->GetElements());
         nsTArray<float> pressure(aPressure->GetElements());
         nsTArray<float> toolMajor(aToolMajor->GetElements());
@@ -2525,16 +2539,17 @@ InitKeyEvent(WidgetKeyboardEvent& event,
     if (event.mKeyNameIndex == KEY_NAME_INDEX_USE_STRING &&
             domPrintableKeyValue) {
         event.mKeyValue = char16_t(domPrintableKeyValue);
     }
 
     event.mLocation =
         WidgetKeyboardEvent::ComputeLocationFromCodeValue(event.mCodeNameIndex);
     event.mTime = time;
+    event.mTimeStamp = GetEventTimeStamp(time);
 }
 
 void
 nsWindow::GeckoViewSupport::OnKeyEvent(int32_t aAction, int32_t aKeyCode,
         int32_t aScanCode, int32_t aMetaState, int64_t aTime,
         int32_t aUnicodeChar, int32_t aBaseUnicodeChar,
         int32_t aDomPrintableKeyValue, int32_t aRepeatCount, int32_t aFlags,
         bool aIsSynthesizedImeKey, jni::Object::Param originalEvent)