Merge f-t to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Sat, 07 Mar 2015 19:38:53 -0800
changeset 232416 fecf1afb083053ea25d5f10c4a03b7080c888fe9
parent 232404 ae68dca2cda697325a2b013e2ee9ea78696609a0 (current diff)
parent 232415 bdacb3e22b546a7879ba00c6700092da28901d8e (diff)
child 232453 a444db7e60f3ff18efff1fef05390019b80253d5
child 232458 82f5f6a22f8fadabe0a0925c5a6e9a04aee6ad22
child 232463 88b540f6db2a23963d8ba45d302dbe2d44d8b2d1
push id28379
push userphilringnalda@gmail.com
push dateSun, 08 Mar 2015 03:39:06 +0000
treeherdermozilla-central@fecf1afb0830 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone39.0a1
first release with
nightly linux32
fecf1afb0830 / 39.0a1 / 20150308030227 / files
nightly linux64
fecf1afb0830 / 39.0a1 / 20150308030227 / files
nightly mac
fecf1afb0830 / 39.0a1 / 20150308030227 / files
nightly win32
fecf1afb0830 / 39.0a1 / 20150308030227 / files
nightly win64
fecf1afb0830 / 39.0a1 / 20150308030227 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge f-t to m-c, a=merge
mobile/android/base/resources/drawable-hdpi/arrow_popup_bg.9.png
mobile/android/base/resources/drawable-mdpi/arrow_popup_bg.9.png
mobile/android/base/resources/drawable-xhdpi/arrow_popup_bg.9.png
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -456,24 +456,21 @@ function findChildShell(aDocument, aDocS
       return docShell;
   }
   return null;
 }
 
 var gPopupBlockerObserver = {
   _reportButton: null,
 
-  onReportButtonEvent: function (aEvent)
+  onReportButtonClick: function (aEvent)
   {
-    if ((aEvent.type == "click" && aEvent.button != 0) ||
-        (aEvent.target != this._reportButton) ||
-        (aEvent.type == "keypress" && aEvent.charCode != Ci.nsIDOMKeyEvent.DOM_VK_SPACE &&
-         aEvent.keyCode != Ci.nsIDOMKeyEvent.DOM_VK_RETURN)) {
-      return; // We're only interested in left click and space and enter keypresses
-    }
+    if (aEvent.button != 0 || aEvent.target != this._reportButton)
+      return;
+
     document.getElementById("blockedPopupOptions")
             .openPopup(this._reportButton, "after_end", 0, 2, false, false, aEvent);
   },
 
   handleEvent: function (aEvent)
   {
     if (aEvent.originalTarget != gBrowser.selectedBrowser)
       return;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -817,22 +817,21 @@
                   <label id="identity-icon-label" class="plain" flex="1"/>
                   <label id="identity-icon-country-label" class="plain"/>
                 </hbox>
               </box>
               <box id="urlbar-display-box" align="center">
                 <label class="urlbar-display urlbar-display-switchtab" value="&urlbar.switchToTab.label;"/>
               </box>
               <hbox id="urlbar-icons">
-                <toolbarbutton id="page-report-button"
-                               class="tabbable urlbar-icon"
-                               hidden="true"
-                               tooltiptext="&pageReportIcon.tooltip;"
-                               onclick="gPopupBlockerObserver.onReportButtonEvent(event);"
-                               onkeypress="gPopupBlockerObserver.onReportButtonEvent(event);"/>
+                <image id="page-report-button"
+                       class="urlbar-icon"
+                       hidden="true"
+                       tooltiptext="&pageReportIcon.tooltip;"
+                       onclick="gPopupBlockerObserver.onReportButtonClick(event);"/>
                 <toolbarbutton id="reader-mode-button"
                                class="tabbable"
                                hidden="true"
                                onclick="ReaderParent.handleReaderButtonEvent(event);"
                                onkeypress="ReaderParent.handleReaderButtonEvent(event);"/>
               </hbox>
               <toolbarbutton id="urlbar-go-button"
                              class="chromeclass-toolbar-additional"
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -93,31 +93,39 @@ pageInfoTreeView.prototype = {
     var treecol = tree.columns.getNamedColumn(columnname);
 
     this.sortdir =
       gTreeUtils.sort(
         tree,
         this,
         this.data,
         treecol.index,
-        function textComparator(a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); },
+        function textComparator(a, b) { return (a || "").toLowerCase().localeCompare((b || "").toLowerCase()); },
         this.sortcol,
         this.sortdir
       );
 
+    Array.forEach(tree.columns, function(col) {
+      col.element.removeAttribute("sortActive");
+      col.element.removeAttribute("sortDirection");
+    });
+    treecol.element.setAttribute("sortActive", "true");
+    treecol.element.setAttribute("sortDirection", this.sortdir ?
+                                                  "ascending" : "descending");
+
     this.sortcol = treecol.index;
   },
 
   getRowProperties: function(row) { return ""; },
   getCellProperties: function(row, column) { return ""; },
   getColumnProperties: function(column) { return ""; },
   isContainer: function(index) { return false; },
   isContainerOpen: function(index) { return false; },
   isSeparator: function(index) { return false; },
-  isSorted: function() { },
+  isSorted: function() { return this.sortcol > -1 },
   canDrop: function(index, orientation) { return false; },
   drop: function(row, orientation) { return false; },
   getParentIndex: function(index) { return 0; },
   hasNextSibling: function(index, after) { return false; },
   getLevel: function(index) { return 0; },
   getImageSrc: function(row, column) { },
   getProgressMode: function(row, column) { },
   getCellValue: function(row, column) { },
@@ -182,34 +190,43 @@ gImageView.getCellText = function(row, c
   return value || "";
 };
 
 gImageView.onPageMediaSort = function(columnname) {
   var tree = document.getElementById(this.treeid);
   var treecol = tree.columns.getNamedColumn(columnname);
 
   var comparator;
-  if (treecol.index == COL_IMAGE_SIZE || treecol.index == COL_IMAGE_COUNT) {
+  var index = treecol.index;
+  if (index == COL_IMAGE_SIZE || index == COL_IMAGE_COUNT) {
     comparator = function numComparator(a, b) { return a - b; };
   } else {
-    comparator = function textComparator(a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); };
+    comparator = function textComparator(a, b) { return (a || "").toLowerCase().localeCompare((b || "").toLowerCase()); };
   }
 
   this.sortdir =
     gTreeUtils.sort(
       tree,
       this,
       this.data,
-      treecol.index,
+      index,
       comparator,
       this.sortcol,
       this.sortdir
     );
 
-  this.sortcol = treecol.index;
+  Array.forEach(tree.columns, function(col) {
+    col.element.removeAttribute("sortActive");
+    col.element.removeAttribute("sortDirection");
+  });
+  treecol.element.setAttribute("sortActive", "true");
+  treecol.element.setAttribute("sortDirection", this.sortdir ?
+                                                "ascending" : "descending");
+
+  this.sortcol = index;
 };
 
 var gImageHash = { };
 
 // localized strings (will be filled in when the document is loaded)
 // this isn't all of them, these are just the ones that would otherwise have been loaded inside a loop
 var gStrings = { };
 var gBundle;
@@ -1235,16 +1252,24 @@ function doCopy()
           text.push(tmp);
         elem.removeAttribute("copybuffer");
       }
     }
     gClipboardHelper.copyString(text.join("\n"), document);
   }
 }
 
+function doSelectAllMedia()
+{
+  var tree = document.getElementById("imagetree");
+
+  if (tree)
+    tree.view.selection.selectAll();
+}
+
 function doSelectAll()
 {
   var elem = document.commandDispatcher.focusedElement;
 
   if (elem && "treeBoxObject" in elem)
     elem.view.selection.selectAll();
 }
 
--- a/browser/base/content/pageinfo/pageInfo.xul
+++ b/browser/base/content/pageinfo/pageInfo.xul
@@ -230,16 +230,19 @@
         </grid>
         <hbox id="imageSaveBox" align="end">
           <vbox id="blockImageBox">
             <checkbox id="blockImage" hidden="true" oncommand="onBlockImage()"
                       accesskey="&mediaBlockImage.accesskey;"/>
             <label control="thepreviewimage" value="&mediaPreview;" class="header"/>
           </vbox>
           <spacer id="imageSaveBoxSpacer" flex="1"/>
+          <button label="&selectall.label;" accesskey="&selectall.accesskey;"
+                  id="selectallbutton"
+                  oncommand="doSelectAllMedia();"/>
           <button label="&mediaSaveAs;" accesskey="&mediaSaveAs.accesskey;"
                   icon="save" id="imagesaveasbutton"
                   oncommand="saveMedia();"/>
         </hbox>
         <vbox id="imagecontainerbox" class="inset iframe" flex="1" pack="center">
           <hbox id="theimagecontainer" pack="center">
             <image id="thepreviewimage"/>
           </hbox>
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -511,28 +511,43 @@ function openPreferences(paneID, extraAr
 
   // This function is duplicated from preferences.js.
   function internalPrefCategoryNameToFriendlyName(aName) {
     return (aName || "").replace(/^pane./, function(toReplace) { return toReplace[4].toLowerCase(); });
   }
 
   if (getBoolPref("browser.preferences.inContent")) {
     let win = Services.wm.getMostRecentWindow("navigator:browser");
-    if (!win) {
-      return;
-    }
-
     let friendlyCategoryName = internalPrefCategoryNameToFriendlyName(paneID);
     let preferencesURL = "about:preferences" +
                          (friendlyCategoryName ? "#" + friendlyCategoryName : "");
-    let newLoad = !win.switchToTabHavingURI(preferencesURL, true, {ignoreFragment: true});
-    let browser = win.gBrowser.selectedBrowser;
+    let newLoad = true;
+    let browser = null;
+    if (!win) {
+      const Cc = Components.classes;
+      const Ci = Components.interfaces;
+      let windowArguments = Cc["@mozilla.org/supports-array;1"]
+                              .createInstance(Ci.nsISupportsArray);
+      let supportsStringPrefURL = Cc["@mozilla.org/supports-string;1"]
+                                    .createInstance(Ci.nsISupportsString);
+      supportsStringPrefURL.data = preferencesURL;
+      windowArguments.AppendElement(supportsStringPrefURL);
+
+      win = Services.ww.openWindow(null, Services.prefs.getCharPref("browser.chromeURL"),
+                                   "_blank", "chrome,dialog=no,all", windowArguments);
+    } else {
+      newLoad = !win.switchToTabHavingURI(preferencesURL, true, {ignoreFragment: true});
+      browser = win.gBrowser.selectedBrowser;
+    }
 
     if (newLoad) {
       Services.obs.addObserver(function advancedPaneLoadedObs(prefWin, topic, data) {
+        if (!browser) {
+          browser = win.gBrowser.selectedBrowser;
+        }
         if (prefWin != browser.contentWindow) {
           return;
         }
         Services.obs.removeObserver(advancedPaneLoadedObs, "advanced-pane-loaded");
         switchToAdvancedSubPane(browser.contentDocument);
       }, "advanced-pane-loaded", false);
     } else {
       if (paneID) {
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -32,16 +32,17 @@ struct RedirEntry {
   URI_SAFE_FOR_UNTRUSTED_CONTENT.  Also note, however, that adding
   URI_SAFE_FOR_UNTRUSTED_CONTENT will allow random web sites to link to that
   URI.  Perhaps we should separate the two concepts out...
  */
 static RedirEntry kRedirMap[] = {
 #ifdef MOZ_SAFE_BROWSING
   { "blocked", "chrome://browser/content/blockedSite.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
+    nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT },
 #endif
   { "certerror", "chrome://browser/content/certerror/aboutCertError.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT },
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -1611,25 +1611,19 @@ richlistitem[type~="action"][actiontype=
 
 #urlbar-stop-button:hover:active {
   background-image: radial-gradient(circle closest-side, hsla(5,100%,75%,.1), transparent);
   -moz-image-region: rect(28px, 28px, 42px, 14px);
 }
 
 /* Popup blocker button */
 #page-report-button {
-  -moz-appearance: none;
-  padding: 0;
   list-style-image: url("chrome://browser/skin/Info.png");
 }
 
-#page-report-button:focus {
-  outline: 1px dotted;
-}
-
 /* Reader mode button */
 
 #reader-mode-button {
   -moz-appearance: none;
   padding: 0;
   list-style-image: url("chrome://browser/skin/reader-mode-16.png");
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -2496,40 +2496,30 @@ richlistitem[type~="action"][actiontype=
 
   #urlbar > toolbarbutton > .toolbarbutton-icon {
     width: 14px;
   }
 }
 
 /* POPUP BLOCKER BUTTON */
 #page-report-button {
-  -moz-appearance: none;
-  padding: 0;
-  border-width: 0;
   list-style-image: url("chrome://browser/skin/urlbar-popup-blocked.png");
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
-#page-report-button > .toolbarbutton-icon {
-  width: 16px;
-}
-
-#page-report-button:focus {
-  @hudButtonFocused@
-}
-
 #page-report-button:hover:active,
 #page-report-button[open="true"] {
   -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
 @media (min-resolution: 2dppx) {
   #page-report-button {
     list-style-image: url("chrome://browser/skin/urlbar-popup-blocked@2x.png");
     -moz-image-region: rect(0, 32px, 32px, 0);
+    width: 22px;
   }
 
   #page-report-button:hover:active,
   #page-report-button[open="true"] {
     -moz-image-region: rect(0, 64px, 32px, 32px);
   }
 }
 
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1558,24 +1558,20 @@ richlistitem[type~="action"][actiontype=
 #urlbar-stop-button:hover:active {
   background-image: radial-gradient(circle closest-side, hsla(5,100%,75%,.1), transparent);
   -moz-image-region: rect(28px, 28px, 42px, 14px);
 }
 
 /* popup blocker button */
 
 #page-report-button {
-  -moz-appearance: none;
-  padding: 0;
-  border-width: 0;
   list-style-image: url("chrome://browser/skin/urlbar-popup-blocked.png");
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
-#page-report-button:focus,
 #page-report-button:hover {
   -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
 #page-report-button:hover:active,
 #page-report-button[open="true"] {
   -moz-image-region: rect(0, 48px, 16px, 32px);
 }
--- a/dom/bindings/Exceptions.cpp
+++ b/dom/bindings/Exceptions.cpp
@@ -251,18 +251,20 @@ protected:
 
   virtual nsresult GetColNo(int32_t* aColNo)
   {
     *aColNo = mColNo;
     return NS_OK;
   }
 
   nsCOMPtr<nsIStackFrame> mCaller;
+  nsCOMPtr<nsIStackFrame> mAsyncCaller;
   nsString mFilename;
   nsString mFunname;
+  nsString mAsyncCause;
   int32_t mLineno;
   int32_t mColNo;
   uint32_t mLanguage;
 };
 
 StackFrame::StackFrame(uint32_t aLanguage,
                        const char* aFilename,
                        const char* aFunctionName,
@@ -275,17 +277,17 @@ StackFrame::StackFrame(uint32_t aLanguag
   CopyUTF8toUTF16(aFilename, mFilename);
   CopyUTF8toUTF16(aFunctionName, mFunname);
 }
 
 StackFrame::~StackFrame()
 {
 }
 
-NS_IMPL_CYCLE_COLLECTION(StackFrame, mCaller)
+NS_IMPL_CYCLE_COLLECTION(StackFrame, mCaller, mAsyncCaller)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(StackFrame)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(StackFrame)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StackFrame)
   NS_INTERFACE_MAP_ENTRY(nsIStackFrame)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
@@ -300,18 +302,21 @@ public:
   explicit JSStackFrame(JS::Handle<JSObject*> aStack);
 
   static already_AddRefed<nsIStackFrame>
   CreateStack(JSContext* aCx, int32_t aMaxDepth = -1);
 
   NS_IMETHOD GetLanguageName(nsACString& aLanguageName) MOZ_OVERRIDE;
   NS_IMETHOD GetFilename(nsAString& aFilename) MOZ_OVERRIDE;
   NS_IMETHOD GetName(nsAString& aFunction) MOZ_OVERRIDE;
+  NS_IMETHOD GetAsyncCause(nsAString& aAsyncCause) MOZ_OVERRIDE;
+  NS_IMETHOD GetAsyncCaller(nsIStackFrame** aAsyncCaller) MOZ_OVERRIDE;
   NS_IMETHOD GetCaller(nsIStackFrame** aCaller) MOZ_OVERRIDE;
   NS_IMETHOD GetFormattedStack(nsAString& aStack) MOZ_OVERRIDE;
+  NS_IMETHOD GetNativeSavedFrame(JS::MutableHandle<JS::Value> aSavedFrame) MOZ_OVERRIDE;
 
 protected:
   virtual bool IsJSFrame() const MOZ_OVERRIDE {
     return true;
   }
 
   virtual nsresult GetLineno(int32_t* aLineNo) MOZ_OVERRIDE;
   virtual nsresult GetColNo(int32_t* aColNo) MOZ_OVERRIDE;
@@ -321,26 +326,30 @@ private:
 
   JS::Heap<JSObject*> mStack;
   nsString mFormattedStack;
 
   bool mFilenameInitialized;
   bool mFunnameInitialized;
   bool mLinenoInitialized;
   bool mColNoInitialized;
+  bool mAsyncCauseInitialized;
+  bool mAsyncCallerInitialized;
   bool mCallerInitialized;
   bool mFormattedStackInitialized;
 };
 
 JSStackFrame::JSStackFrame(JS::Handle<JSObject*> aStack)
   : mStack(aStack)
   , mFilenameInitialized(false)
   , mFunnameInitialized(false)
   , mLinenoInitialized(false)
   , mColNoInitialized(false)
+  , mAsyncCauseInitialized(false)
+  , mAsyncCallerInitialized(false)
   , mCallerInitialized(false)
   , mFormattedStackInitialized(false)
 {
   MOZ_ASSERT(mStack);
 
   mozilla::HoldJSObjects(this);
   mLineno = 0;
   mLanguage = nsIProgrammingLanguage::JAVASCRIPT;
@@ -573,16 +582,94 @@ NS_IMETHODIMP StackFrame::GetColumnNumbe
 
 /* readonly attribute AUTF8String sourceLine; */
 NS_IMETHODIMP StackFrame::GetSourceLine(nsACString& aSourceLine)
 {
   aSourceLine.Truncate();
   return NS_OK;
 }
 
+/* readonly attribute AString asyncCause; */
+NS_IMETHODIMP JSStackFrame::GetAsyncCause(nsAString& aAsyncCause)
+{
+  NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
+  ThreadsafeAutoJSContext cx;
+  JS::Rooted<JSString*> asyncCause(cx);
+  bool canCache = false, useCachedValue = false;
+  GetValueIfNotCached(cx, mStack, JS::GetSavedFrameAsyncCause,
+                      mAsyncCauseInitialized, &canCache, &useCachedValue,
+                      &asyncCause);
+
+  if (useCachedValue) {
+    return StackFrame::GetAsyncCause(aAsyncCause);
+  }
+
+  if (asyncCause) {
+    nsAutoJSString str;
+    if (!str.init(cx, asyncCause)) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    aAsyncCause = str;
+  } else {
+    aAsyncCause.SetIsVoid(true);
+  }
+
+  if (canCache) {
+    mAsyncCause = aAsyncCause;
+    mAsyncCauseInitialized = true;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP StackFrame::GetAsyncCause(nsAString& aAsyncCause)
+{
+  // The async cause must be set to null if empty.
+  if (mAsyncCause.IsEmpty()) {
+    aAsyncCause.SetIsVoid(true);
+  } else {
+    aAsyncCause.Assign(mAsyncCause);
+  }
+
+  return NS_OK;
+}
+
+/* readonly attribute nsIStackFrame asyncCaller; */
+NS_IMETHODIMP JSStackFrame::GetAsyncCaller(nsIStackFrame** aAsyncCaller)
+{
+  NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
+  ThreadsafeAutoJSContext cx;
+  JS::Rooted<JSObject*> asyncCallerObj(cx);
+  bool canCache = false, useCachedValue = false;
+  GetValueIfNotCached(cx, mStack, JS::GetSavedFrameAsyncParent,
+                      mAsyncCallerInitialized, &canCache, &useCachedValue,
+                      &asyncCallerObj);
+
+  if (useCachedValue) {
+    return StackFrame::GetAsyncCaller(aAsyncCaller);
+  }
+
+  nsCOMPtr<nsIStackFrame> asyncCaller =
+    asyncCallerObj ? new JSStackFrame(asyncCallerObj) : nullptr;
+  asyncCaller.forget(aAsyncCaller);
+
+  if (canCache) {
+    mAsyncCaller = *aAsyncCaller;
+    mAsyncCallerInitialized = true;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP StackFrame::GetAsyncCaller(nsIStackFrame** aAsyncCaller)
+{
+  NS_IF_ADDREF(*aAsyncCaller = mAsyncCaller);
+  return NS_OK;
+}
+
 /* readonly attribute nsIStackFrame caller; */
 NS_IMETHODIMP JSStackFrame::GetCaller(nsIStackFrame** aCaller)
 {
   NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
   ThreadsafeAutoJSContext cx;
   JS::Rooted<JSObject*> callerObj(cx);
   bool canCache = false, useCachedValue = false;
   GetValueIfNotCached(cx, mStack, JS::GetSavedFrameParent, mCallerInitialized,
@@ -659,16 +746,29 @@ NS_IMETHODIMP JSStackFrame::GetFormatted
 }
 
 NS_IMETHODIMP StackFrame::GetFormattedStack(nsAString& aStack)
 {
   aStack.Truncate();
   return NS_OK;
 }
 
+/* readonly attribute jsval nativeSavedFrame; */
+NS_IMETHODIMP JSStackFrame::GetNativeSavedFrame(JS::MutableHandle<JS::Value> aSavedFrame)
+{
+  aSavedFrame.setObjectOrNull(mStack);
+  return NS_OK;
+}
+
+NS_IMETHODIMP StackFrame::GetNativeSavedFrame(JS::MutableHandle<JS::Value> aSavedFrame)
+{
+  aSavedFrame.setNull();
+  return NS_OK;
+}
+
 /* AUTF8String toString (); */
 NS_IMETHODIMP StackFrame::ToString(nsACString& _retval)
 {
   _retval.Truncate();
 
   const char* frametype = IsJSFrame() ? "JS" : "native";
 
   nsString filename;
--- a/js/xpconnect/idl/xpccomponents.idl
+++ b/js/xpconnect/idl/xpccomponents.idl
@@ -117,17 +117,17 @@ interface nsIXPCComponents_utils_Sandbox
 interface ScheduledGCCallback : nsISupports
 {
     void callback();
 };
 
 /**
 * interface of Components.utils
 */
-[scriptable, uuid(2617a800-63c1-11e4-9803-0800200c9a66)]
+[scriptable, uuid(0354f8b4-08c6-4074-a466-2b6524b64ca3)]
 interface nsIXPCComponents_Utils : nsISupports
 {
 
     /* reportError is designed to be called from JavaScript only.
      *
      * It will report a JS Error object to the JS console, and return. It
      * is meant for use in exception handler blocks which want to "eat"
      * an exception, but still want to report it to the console.
@@ -359,16 +359,30 @@ interface nsIXPCComponents_Utils : nsISu
     jsval nondeterministicGetWeakMapKeys(in jsval aMap);
 
     [implicit_jscontext]
     jsval getJSTestingFunctions();
 
     /*
      * To be called from JS only.
      *
+     * Call 'function', using the provided stack as the async stack responsible
+     * for the call, and propagate its return value or the exception it throws.
+     * The function is called with no arguments, and 'this' is 'undefined'.
+     *
+     * The code in the function will see the given stack frame as the
+     * asyncCaller of its own stack frame, instead of the current caller.
+     */
+    [implicit_jscontext]
+    jsval callFunctionWithAsyncStack(in jsval function, in nsIStackFrame stack,
+                                     in AString asyncCause);
+
+    /*
+     * To be called from JS only.
+     *
      * Returns the global object with which the given object is associated.
      *
      * @param obj The JavaScript object whose global is to be gotten.
      * @return the corresponding global.
      */
     [implicit_jscontext]
     jsval getGlobalForObject(in jsval obj);
 
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2896,16 +2896,57 @@ nsXPCComponents_Utils::GetJSTestingFunct
 {
     JSObject *obj = js::GetTestingFunctions(cx);
     if (!obj)
         return NS_ERROR_XPC_JAVASCRIPT_ERROR;
     retval.setObject(*obj);
     return NS_OK;
 }
 
+/* jsval callFunctionWithStack(in jsval function, in nsIStackFrame stack,
+                               in AString asyncCause); */
+NS_IMETHODIMP
+nsXPCComponents_Utils::CallFunctionWithAsyncStack(HandleValue function,
+                                                  nsIStackFrame *stack,
+                                                  const nsAString &asyncCause,
+                                                  JSContext *cx,
+                                                  MutableHandleValue retval)
+{
+    nsresult rv;
+
+    if (!stack || asyncCause.IsEmpty()) {
+        return NS_ERROR_INVALID_ARG;
+    }
+
+    JS::Rooted<JS::Value> asyncStack(cx);
+    rv = stack->GetNativeSavedFrame(&asyncStack);
+    if (NS_FAILED(rv))
+        return rv;
+    if (!asyncStack.isObject()) {
+        JS_ReportError(cx, "Must use a native JavaScript stack frame");
+        return NS_ERROR_INVALID_ARG;
+    }
+
+    JS::Rooted<JSObject*> asyncStackObj(cx, &asyncStack.toObject());
+    JS::Rooted<JSString*> asyncCauseString(cx, JS_NewUCStringCopyN(cx, asyncCause.BeginReading(),
+                                                                       asyncCause.Length()));
+    if (!asyncCauseString)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    JS::AutoSetAsyncStackForNewCalls sas(cx, asyncStackObj, asyncCauseString);
+
+    if (!JS_CallFunctionValue(cx, JS::NullPtr(), function,
+                              JS::HandleValueArray::empty(), retval))
+    {
+        return NS_ERROR_XPC_JAVASCRIPT_ERROR;
+    }
+
+    return NS_OK;
+}
+
 /* void getGlobalForObject(); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::GetGlobalForObject(HandleValue object,
                                           JSContext *cx,
                                           MutableHandleValue retval)
 {
     // First argument must be an object.
     if (object.isPrimitive())
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_callFunctionWithAsyncStack.js
@@ -0,0 +1,23 @@
+function run_test() {
+  function getAsyncStack() {
+    return Components.stack;
+  }
+
+  // asyncCause may contain non-ASCII characters.
+  let testAsyncCause = "Tes" + String.fromCharCode(355) + "String";
+
+  Components.utils.callFunctionWithAsyncStack(function asyncCallback() {
+    let stack = Components.stack;
+
+    do_check_eq(stack.name, "asyncCallback");
+    do_check_eq(stack.caller.name, null);
+    do_check_eq(stack.asyncCause, null);
+
+    do_check_eq(stack.asyncCaller.name, "getAsyncStack");
+    do_check_eq(stack.asyncCaller.asyncCause, testAsyncCause);
+    do_check_eq(stack.asyncCaller.asyncCaller, null);
+
+    do_check_eq(stack.asyncCaller.caller.name, "run_test");
+    do_check_eq(stack.asyncCaller.caller.asyncCause, null);
+  }, getAsyncStack(), testAsyncCause);
+}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -50,16 +50,17 @@ support-files =
 [test_bug1033253.js]
 [test_bug1033920.js]
 [test_bug1033927.js]
 [test_bug1034262.js]
 [test_bug1082450.js]
 [test_bug1081990.js]
 [test_bug1110546.js]
 [test_bug_442086.js]
+[test_callFunctionWithAsyncStack.js]
 [test_file.js]
 [test_blob.js]
 [test_blob2.js]
 [test_file2.js]
 [test_import.js]
 [test_import_fail.js]
 [test_interposition.js]
 [test_isModuleLoaded.js]
deleted file mode 100644
index bc795478a6682aca741553bc17b2666480e97853..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
index 0000000000000000000000000000000000000000..00a2c0f1c1def3e5b30907d54ecbcebba426cca6
GIT binary patch
literal 455
zc$@*p0XY7NP)<h;3K|Lk000e1NJLTq001cf001cn1^@s6s9*s00004wNkl<Zc-rlm
z&1%9x7)3Qd23iFbsheOL7wyVTQ3N*uQCETr67~Hb#9rYDB1)^Bh(jlEmbv##{0zyY
zRJ#Az-$|iIxd4nvdBPWg2t@^=KXA+l$@S^ES=uAu5c(==qAnVuX@CZKHS#0+yjuiA
zPCf*^iC82e6<q_Q<i+II=?i}&dK9dRmgtBN(Gy>yF9rtalh-4^LtphL(K46(g%jQh
z8H!Ad#YD^uFd;7^zeit-{@~h-ddx<hl^sqTiK&>2g;<J}0hZ*=$sf_zp+CBIHGSry
zEk0S{l(4nP#l|2xxeI!R^tSQvFG&Xc+hSIgvC=i6Td_09mfSTx8ND$c!KHZ&xzq_m
zJ!X}80fMKZIXz=~6FkE6xh!*oZE$<&Gu%r;b_J5tGod%dqjF8M$$f0VoUHgsij>^Y
zGo`nS$3@BLOmg;M$=R7?bSk-bl1|b|I!Pz#B%P#_{FjneJx^NkWd8K;I99wZTJzp*
x#SVrQdqGz0s#&u?Y0XZrHGAgPe0_MD;~Qh<U3o^&FIxZr002ovPDHLkV1l^;&F=sJ
deleted file mode 100644
index e4c734e3fed51d0df14141141c10827b85ebc024..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
index 0000000000000000000000000000000000000000..4d33b8c5312758745ce3a81faf76447046df4a63
GIT binary patch
literal 287
zc$@(r0pR|LP)<h;3K|Lk000e1NJLTq000~S000~a1^@s6at+^<0002yNkl<Zc-rlj
zzY2pe7{pC*5bfgP;1tN<3%DtEcQQi3zW;-?C!AnusYz{<p?>h&a(5wrzbM+Sn<KkQ
z5NXLW-l=9`3=)un44f><s7dG{ZNlckIVgbw+7U%<PA|C?R)7lBpaC5?ThdWe)1!D7
z8go|jz!vmi00xYf7;1WYRP>Br1twgInt}_Mz}1n7+MZq|y`N5F%JpwK%TL1Ap#!}X
zy~X;T37#;`eK21LH1yK+eh8F2)|#6??g(2L>80r{kH91F2>kOvuTPuz$2-XP6yyW;
l-eP!fqJp%EK^ozo)*b9gqe0N}0eJub002ovPDHLkV1fcRegFUf
deleted file mode 100644
index 12ede284e6149243681deb98ede3c802c2c0ece8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
index 0000000000000000000000000000000000000000..685358e69ad4ac7d3a691892e6d137a9793a59e7
GIT binary patch
literal 664
zc$@*40%!e+P)<h;3K|Lk000e1NJLTq001@s001@!1^@s6j74hQ0007CNkl<Zc-rln
zT}vWS0EVkkCv7A}yAT8|YC#Z<ZVE9k63k%H#I)`I|B&_-o&$%;X=$0!_UsX!+w;E9
z`50m592}(gdry(Q{SJ3brV>XYfLx4x%EZSvxkqWq8llbL1rds(D2Wq`C}r%iOJs(0
z$XSAaEfg?Vk-$??6*W;8XBkr`t4el6mqKg>zr0EzgH;G=h^A<Xwm26T8F5ZVi_8Wc
zDs&3Jx_U<HSd^Ku1|e6XBf6p|t}~`bR)_31U21eYw&eb}S^=|BW`;JibxFXDxD^92
z6!$Pn88hyXtXs0XbZOG9OxNJERWn<#z*5&3;D_joJ3_}|A|Az5JY~d`j0u?|I`rw(
zq+>+q#4UNqvKHCL4Q8j$tUVC+Q_RFOEHc83KO=KWhXI`~=~$t2E=kN@tvZLc%Pc)G
zi<_XOco8eH&X^ThOR}Hna!0ooUF}udDi-osZE#p`*aDl`niKLWep$R_gq`t9_M9#w
zx?R!rl<r%_0+zJO{_SvR$83dVOzLe%*m6s{jOo^)YnARn()lWJAk8)$aCm3T*si7G
zaxZk5(9LYe8r?sfGb47wo^A6VGUUlLXTR@5%9dNv<&kbZy4LCbsn{9+{MY=KOgXsU
zMeLbQ_jJ6VbD~&2LCic2*L##QtgWZxHnDt?SQHZ*G05T@i7n_fiit&Wv3D=##k`mo
z^I~4ii+M3G=Ec027xQ9X%!~ccV$Q$JarX6_(=SY&d&TYSM+v7tBRTuw&)HA4&VF2X
y_Bw>q7g(IWa^&nKF{iKfIe!t;>8rE<<nK3H<7x$v?j0-u0000<MNUMnLSTZOc0JAj
new file mode 100644
index 0000000000000000000000000000000000000000..f50b3c570aebda371e8a660505d8088368fcc217
GIT binary patch
literal 1240
zc$@*)1Sk86P)<h;3K|Lk000e1NJLTq002<{002=41^@s6s*g%G000D^Nkl<Zc-rlq
ze@_!Z5QbajN1+Hsgw_-*6hlEnY=j^LL{b#eHV6U=eE$!kbICJtvR+A{2j1aa@`gX}
zoo8oex5@30%RTJ#>j9P7C!Zmu4%ic;rx}p-``}<haB6A@4Wp41OFgP*3-(@th8g$N
zK#PoxiVC7J(YR4DMY6ue@H=Y24h317D9kYPhIp}sHX(W@niNfmN@zMoQcqL(e1>le
zbtHh92*`X)<`oRMNsK)g&4^}2bD}b;q)6&%4xcmlE)j<UEyQGIJ}H1BtXPrNj8^vr
z#$Jl5qF17t=(T7;w3s3-;H!quD!$9aF-=@W;v5+iqy;!k?--{9O1!j!ks2o7h?YeS
z(TZqQ^fpCW#a9ELZ}43sjtX&=h;y8{hwlPX`+#Pk1vpJPR9V#}OhqQwMDImS(Fe4i
zBB`e)KG*QwAdc6>HAkElq-JE_JyNq!OIQKUkoxnYI;;5(Q<2F{(Uxdiw1ak2B=xk7
z&rN(ciDQ|#=81F0fYj3ND;vWy9y1wOrk5;H8qsQQU??)VC)yXa&;k0A0;w1EwvXRk
z{BID?D)GG{Ud_m{+myA<!U9cJOL*P@Y_gKk%6`V+SJ9EEZPXEU`TMV=@3+2=@Oyy&
z9pY&kkn^Uri}2_x8#N2HjHhU}RZ?96eiVITRSz*1nLQSLLnr7o1yV2S?HIpp{I`hb
zqXAhb?iX;-ves<uD+?!Bg$hl#LCSCP!UI;ci?PV;chQ;X+~^_&vVP9+d5Z5YaU4+I
zo5a~5?g|_x`pL$8&<iI`7B10z*Gc`B0eFJ3$m|cJpDC2}cY*H{1F}VY>%_ZcvT-u#
zjW<HnQZCV4Z5D3PLk<nVa|7)%&{c{QdQ+(92IL{}Z3Wp_hKDWbe6N0}=fVko61}81
zyk&KEN&7Z^<tzYbO<$)_Ayfr<MrpTAS+5g!9S+aoGHOb?C&Yp|7gjmhuhA>^*wwo9
zl#3XE*BMX<@`8A}#J5MhYs6nQ=f*-Wh`OoRemKi{Y1x$WKE30Z=B!zmC4eDF&BpJ<
zbwr$6(#vp|4f^6=n~R00N1Hi*S2o!8w`sg>QeR8?GJ^mu$jg|LZV_*j_-pXcqfSqV
zy*8B<esk{pXApOYd!^sar5D5n4xS28Hx=ELwI5z*SlSnLm)6ZiA+EyVRuGHkki8hQ
zGj{@rR~d(R6+rC7?9hwm&|Mr9;+Noj_!uE}iSu3|c7o&0V}Yp0oQ^~MM-YEGM2F}Q
z9il^Yhz`*qIz)%)5FMgJbchboAv#2d=nx&ELv)A^(IGlShv*O;qC<3u4$&bxM2G0#
z;yA>tLiFzw{Y%-0`BK)u*-qe_ZNEJ*!0iFQ$CAK37Qaz7;EgK3+n2!IKEGv}&@EHH
z@0`GWXTN!$(9Qe*eFns*+<-G6v@iNJk^!cX#ATz;#ks>=9G}pXz=WnS8*iEw*2q1s
zSz(P_LbJjYqED?GaB5v#S;x&!Ea(2rPps#%IX|(U`!hdLhfyXnKQRuZPx4G~B&yGp
z9RQ?HH%{R3Iok<7KJopYf%^X*xCgNQUoiaX|M?9_5r0NCITtqo0000<MNUMnLSTaS
C^G}-q
--- a/mobile/android/base/resources/layout/anchored_popup.xml
+++ b/mobile/android/base/resources/layout/anchored_popup.xml
@@ -1,17 +1,22 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
 
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-            android:layout_width="@dimen/doorhanger_width"
-            android:layout_height="wrap_content"
-            android:layout_alignParentTop="true"
-            android:background="@drawable/anchored_popup_bg">
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:background="@drawable/dropshadow"
+              android:padding="3dp">
 
-    <LinearLayout android:id="@+id/content"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:orientation="vertical"/>
+    <ScrollView android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:background="@drawable/anchored_popup_bg">
 
-</ScrollView>
+        <LinearLayout android:id="@+id/content"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:orientation="vertical"/>
+
+    </ScrollView>
+</LinearLayout>
--- a/mobile/android/base/resources/values-large-v11/dimens.xml
+++ b/mobile/android/base/resources/values-large-v11/dimens.xml
@@ -1,16 +1,17 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
 
 <resources>
 
     <dimen name="arrow_popup_container_width">400dp</dimen>
+    <dimen name="doorhanger_offsetY">2dp</dimen>
 
     <dimen name="browser_toolbar_height">56dp</dimen>
     <dimen name="browser_toolbar_button_padding">16dp</dimen>
     <dimen name="browser_toolbar_favicon_size">16dp</dimen>
 
     <dimen name="tabs_counter_size">26sp</dimen>
     <dimen name="panel_grid_view_column_width">200dp</dimen>
 
--- a/mobile/android/base/resources/values-xlarge-v11/dimens.xml
+++ b/mobile/android/base/resources/values-xlarge-v11/dimens.xml
@@ -1,18 +1,16 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
 
 <resources>
 
     <dimen name="browser_toolbar_height">56dp</dimen>
-    <dimen name="doorhanger_offsetX">5dp</dimen>
-    <dimen name="doorhanger_offsetY">2dp</dimen>
     <dimen name="remote_tab_child_row_height">56dp</dimen>
     <dimen name="remote_tab_group_row_height">34dp</dimen>
     <dimen name="tabs_counter_size">26sp</dimen>
     <dimen name="tabs_panel_indicator_width">60dp</dimen>
     <dimen name="tabs_panel_list_padding">8dip</dimen>
     <dimen name="panel_grid_view_column_width">250dp</dimen>
     <dimen name="new_tablet_tab_panel_grid_padding">48dp</dimen>
 
--- a/mobile/android/base/resources/values/dimens.xml
+++ b/mobile/android/base/resources/values/dimens.xml
@@ -92,17 +92,17 @@
     <!-- Padding at the top of the site identity popup, when no identity data is available. -->
     <dimen name="identity_padding_top">5dp</dimen>
 
     <dimen name="doorhanger_width">300dp</dimen>
     <dimen name="doorhanger_input_width">250dp</dimen>
     <dimen name="doorhanger_spinner_textsize">9sp</dimen>
     <dimen name="doorhanger_padding">15dp</dimen>
     <dimen name="doorhanger_offsetX">10dp</dimen>
-    <dimen name="doorhanger_offsetY">3dp</dimen>
+    <dimen name="doorhanger_offsetY">7dp</dimen>
 
     <dimen name="flow_layout_spacing">6dp</dimen>
     <dimen name="menu_item_icon">21dp</dimen>
     <dimen name="menu_item_textsize">16sp</dimen>
     <dimen name="menu_item_state_icon">18dp</dimen>
     <!-- This is chosen to match Android's listPreferredItemHeight.
          TODO: We should inherit these from the system.
          http://androidxref.com/4.2.2_r1/xref/frameworks/base/core/res/res/values/themes.xml#123 -->
--- a/toolkit/content/browser-child.js
+++ b/toolkit/content/browser-child.js
@@ -135,16 +135,17 @@ let WebProgressListener = {
     json.canGoBack = docShell.canGoBack;
     json.canGoForward = docShell.canGoForward;
 
     if (aWebProgress && aWebProgress.isTopLevel) {
       json.documentURI = content.document.documentURIObject.spec;
       json.charset = content.document.characterSet;
       json.mayEnableCharacterEncodingMenu = docShell.mayEnableCharacterEncodingMenu;
       json.principal = content.document.nodePrincipal;
+      json.synthetic = content.document.mozSyntheticDocument;
     }
 
     sendAsyncMessage("Content:LocationChange", json, objects);
   },
 
   onStatusChange: function onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
     let json = this._setupJSON(aWebProgress, aRequest);
     let objects = this._setupObjects(aWebProgress);
@@ -321,32 +322,16 @@ addEventListener("ImageContentLoaded", f
     let req = content.document.imageRequest;
     if (!req.image)
       return;
     sendAsyncMessage("ImageDocumentLoaded", { width: req.image.width,
                                               height: req.image.height });
   }
 }, false);
 
-let DocumentObserver = {
-  init: function() {
-    Services.obs.addObserver(this, "document-element-inserted", false);
-    addEventListener("unload", () => {
-      Services.obs.removeObserver(this, "document-element-inserted");
-    });
-  },
-
-  observe: function(aSubject, aTopic, aData) {
-    if (aSubject == content.document) {
-      sendAsyncMessage("DocumentInserted", {synthetic: aSubject.mozSyntheticDocument});
-    }
-  },
-};
-DocumentObserver.init();
-
 const ZoomManager = {
   get fullZoom() {
     return this._cache.fullZoom;
   },
 
   get textZoom() {
     return this._cache.textZoom;
   },
--- a/toolkit/content/tests/browser/browser.ini
+++ b/toolkit/content/tests/browser/browser.ini
@@ -13,16 +13,19 @@ skip-if = e10s # Bug 1064580
 [browser_default_image_filename.js]
 skip-if = e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly
 [browser_f7_caret_browsing.js]
 skip-if = e10s
 [browser_findbar.js]
 skip-if = e10s # Disabled for e10s: Bug ?????? - seems to be a timing issue with RemoteFinder.jsm messages coming later than the tests expect.
 [browser_input_file_tooltips.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (TypeError: doc.createElement is not a function)
+[browser_isSynthetic.js]
+support-files =
+  empty.png
 [browser_keyevents_during_autoscrolling.js]
 skip-if = e10s # Bug 921935 - focusmanager issues with e10s
 [browser_save_resend_postdata.js]
 support-files =
   common/mockTransfer.js
   data/post_form_inner.sjs
   data/post_form_outer.sjs
 skip-if = e10s # Bug ?????? - test directly manipulates content (gBrowser.contentDocument.getElementById("postForm").submit();)
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_isSynthetic.js
@@ -0,0 +1,72 @@
+function LocationChangeListener(browser) {
+  this.browser = browser;
+  browser.addProgressListener(this);
+}
+
+LocationChangeListener.prototype = {
+  wasSynthetic: false,
+  browser: null,
+
+  destroy: function() {
+    this.browser.removeProgressListener(this);
+  },
+
+  onLocationChange: function(webProgress, request, location, flags) {
+    this.wasSynthetic = this.browser.isSyntheticDocument;
+  },
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+                                         Ci.nsISupportsWeakReference])
+}
+
+const FILES = gTestPath.replace("browser_isSynthetic.js", "")
+                       .replace("chrome://mochitests/content/", "http://example.com/");
+
+function waitForPageShow(browser) {
+  return ContentTask.spawn(browser, null, function*() {
+    Cu.import("resource://gre/modules/PromiseUtils.jsm");
+    yield new Promise(resolve => {
+      let listener = () => {
+        removeEventListener("pageshow", listener, true);
+        resolve();
+      }
+      addEventListener("pageshow", listener, true);
+    });
+  });
+}
+
+add_task(function*() {
+  let tab = gBrowser.addTab("about:blank");
+  let browser = tab.linkedBrowser;
+  yield BrowserTestUtils.browserLoaded(browser);
+  let listener = new LocationChangeListener(browser);
+
+  is(browser.isSyntheticDocument, false, "Should not be synthetic");
+
+  let loadPromise = waitForPageShow(browser);
+  browser.loadURI("data:text/html;charset=utf-8,<html/>");
+  yield loadPromise;
+  is(listener.wasSynthetic, false, "Should not be synthetic");
+  is(browser.isSyntheticDocument, false, "Should not be synthetic");
+
+  loadPromise = waitForPageShow(browser);
+  browser.loadURI(FILES + "empty.png");
+  yield loadPromise;
+  is(listener.wasSynthetic, true, "Should be synthetic");
+  is(browser.isSyntheticDocument, true, "Should be synthetic");
+
+  loadPromise = waitForPageShow(browser);
+  browser.goBack();
+  yield loadPromise;
+  is(listener.wasSynthetic, false, "Should not be synthetic");
+  is(browser.isSyntheticDocument, false, "Should not be synthetic");
+
+  loadPromise = waitForPageShow(browser);
+  browser.goForward();
+  yield loadPromise;
+  is(listener.wasSynthetic, true, "Should be synthetic");
+  is(browser.isSyntheticDocument, true, "Should be synthetic");
+
+  listener.destroy();
+  gBrowser.removeTab(tab);
+});
new file mode 100644
index 0000000000000000000000000000000000000000..17ddf0c3ee9a761829d2a460090c3d56c046dc77
GIT binary patch
literal 14528
zc%1E<J&)r=7{})hAwi@oph2Rtyh6H@aK<m2Y+^Z%mSm4a!pmwmh@^pY>`5}(_~mS8
z<J}5Dbp;Zl;sZd-7eIoFFF`>M4HXhJ7sk$e?CdRY<ui)y_?h|tfA-8XlWFqo?DYKy
zg|`a`p$F|&^PFApCC6*`+4-yK#jou0y5H)B2o(>K<6it-{R*MVL)z&^UE>4Q@|>b+
zdwo)j9Umn{tH-`+U6P3FlOc6${2xF3#B<cH@gJ8A(eN8&L|Zojxwtv)ST~ne)#mGZ
zL5o#p;E>4VVrT4zYFy(}UzL4N!kFjMCedY$KTayRu5rdSynt|}Vp*_6>5x0B7Nt`8
zsCx7+C$oDjR<JAzVpT0Eswi`d!s`Wg)&hH=o;M#aaO|$ekD|y|F`iDR#i>&Cf+3cw
z)hZTcEXx9GA%xd%WX6IU9?VUaK1~u@0rey5xm<E@_Pt3|<M{%&Q5Nsz_$!bbF8Yr3
zB92WTOGOdqiEL}7@h8DJeKgy`WK105Mj_KlxjF_jjN5UJldBA)ldI@<W!Sm)2|g#G
zHwi3qa>btHAkWGld65^6ygl!|s^0td5giQjwMorh8Hwp0SyD5X>1&<FI!kQ?#EiV4
z<9TC!o@Hmt$Kx7}G^@CWhG|hZ2|m*Bt|-rsG})muZAlOn_UTAvRhCt`B8U}L6gN!f
zEq6Q&mi@LFnRjv7YP;*>*>rGyCzo~04G-H=2VUTqkxm_RNU-k?HM|aP(+opxyJ2Ly
z7HKzi7AR6`tNlaC>YGQBP_32~;ZRZfLjTZG1i4bGRFor2DibMvgl&1oy6IVyB=Z;6
z_P?~=kY}tv3@BT*%<=z3<k)0TEgG`4xz@LGH(gII$kXlUvSLir^~E=XkR;Qu#xLg|
zpAjUQbQ-Ism8?v<m8O`j;jQR?8U3#Vn33;iOh?4MEgd&n?KcU%K{Pc3ay(=`eYbg=
zC(QIXo_G1q0O9NiEk`{&qS|VCQybpc3)s{mx}xE{@P;Z`*peJ#k7cH##CkOo+il-X
za$!74>l869SW3<d?PmS1w)X;U?-uR4>LZs%y1bC=gf~>l`a6H`3$|4tdbw0mN*dk`
z?<&q{Ovc?NW%DUq^hs_!SJ&I4>t%HF0p9pYpYIp&V#C1pDtNV7$xF(YUjPCSfB*y_
z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz
z00bZadC8E%`tN_lwQKy8uj^kv`_n-PaaQZxK<MTjgg*NMp}%MB`Wr$M5ux9oAf$eS
z&|BWupZ@%qwSBYQJnqE5^#7X8>g;wldj-Av{QmP#-uU*%<UfY(lhfw+?>+ha9~bwj
ADF6Tf
--- a/toolkit/content/widgets/remote-browser.xml
+++ b/toolkit/content/widgets/remote-browser.xml
@@ -317,20 +317,16 @@
             case "Forms:ShowDropDown": {
               Cu.import("resource://gre/modules/SelectParentHelper.jsm");
               let menulist = document.getElementById(this.getAttribute("selectmenulist"));
               SelectParentHelper.populate(menulist, data.options, data.selectedIndex);
               SelectParentHelper.open(this, menulist, data.rect);
               break;
             }
 
-            case "DocumentInserted":
-              this._isSyntheticDocument = data.synthetic;
-              break;
-
             case "FullZoomChange": {
               this._fullZoom = data.value;
               let event = document.createEvent("Events");
               event.initEvent("FullZoomChange", true, false);
               this.dispatchEvent(event);
               break;
             }
 
--- a/toolkit/modules/RemoteWebProgress.jsm
+++ b/toolkit/modules/RemoteWebProgress.jsm
@@ -193,16 +193,17 @@ RemoteWebProgressManager.prototype = {
       if (isTopLevel) {
         this._browser.webNavigation._currentURI = location;
         this._browser._characterSet = json.charset;
         this._browser._documentURI = newURI(json.documentURI);
         this._browser._contentTitle = "";
         this._browser._imageDocument = null;
         this._browser._mayEnableCharacterEncodingMenu = json.mayEnableCharacterEncodingMenu;
         this._browser._contentPrincipal = json.principal;
+        this._browser._isSyntheticDocument = json.synthetic;
       }
 
       this._callProgressListeners("onLocationChange", webProgress, request, location, flags);
       break;
 
     case "Content:SecurityChange":
       let [status, state] = this._fixSSLStatusAndState(json.status, json.state);
 
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -4631,17 +4631,17 @@ mozilla::BrowserTabsRemoteAutostart()
   bool disabledForA11y = Preferences::GetBool("browser.tabs.remote.autostart.disabled-because-using-a11y", false);
   // Only disable for IME for the automatic pref, not the opt-in one.
   bool disabledForIME = trialPref && KeyboardMayHaveIME();
 
   if (prefEnabled) {
     if (gSafeMode) {
       LogE10sBlockedReason("Safe mode");
     } else if (disabledForA11y) {
-      LogE10sBlockedReason("An accessibility tool is active");
+      LogE10sBlockedReason("An accessibility tool is or was active. See bug 1115956.");
     } else if (disabledForIME) {
       LogE10sBlockedReason("The keyboard being used has activated IME");
     } else {
       gBrowserTabsRemoteAutostart = true;
     }
   }
 #endif
 
--- a/xpcom/base/nsIException.idl
+++ b/xpcom/base/nsIException.idl
@@ -5,35 +5,41 @@
 
 /*
  * Interfaces for representing cross-language exceptions and stack traces.
  */
 
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(8272a3d5-2a94-40c0-8ab6-be76583a0221)]
+[scriptable, uuid(28bfb2a2-5ea6-4738-918b-049dc4d51f0b)]
 interface nsIStackFrame : nsISupports
 {
     // see nsIProgrammingLanguage for list of language consts
     readonly attribute uint32_t                language;
     readonly attribute AUTF8String             languageName;
     readonly attribute AString                 filename;
     readonly attribute AString                 name;
     // Valid line numbers begin at '1'. '0' indicates unknown.
     readonly attribute int32_t                 lineNumber;
     readonly attribute int32_t                 columnNumber;
     readonly attribute AUTF8String             sourceLine;
+    readonly attribute AString                 asyncCause;
+    readonly attribute nsIStackFrame           asyncCaller;
     readonly attribute nsIStackFrame           caller;
 
     // Returns a formatted stack string that looks like the sort of
     // string that would be returned by .stack on JS Error objects.
     // Only works on JS-language stack frames.
     readonly attribute AString                 formattedStack;
 
+    // Returns the underlying SavedFrame object for native JavaScript stacks,
+    // or null if this is not a native JavaScript stack frame.
+    readonly attribute jsval                   nativeSavedFrame;
+
     AUTF8String toString();
 };
 
 [scriptable, uuid(1caf1461-be1d-4b79-a552-5292b6bf3c35)]
 interface nsIException : nsISupports
 {
     // A custom message set by the thrower.
     [binaryname(MessageMoz)] readonly attribute AUTF8String message;