Merge m-i to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Sun, 27 Aug 2017 17:31:55 -0700
changeset 377137 d10c97627b51a226e19d0fa801201897fe1932f6
parent 377125 7aec8d3eaa72838f1d83767f46dcfcae8de510ff (current diff)
parent 377136 e774e827d2fb359580c6975d2df01d5730c48d61 (diff)
child 377146 239440f2b04907e078b01992c633146d657f5554
child 377215 f9a9fc4682840029af971b7e51c66dcd74af415c
push id32401
push userphilringnalda@gmail.com
push dateMon, 28 Aug 2017 00:32:10 +0000
treeherdermozilla-central@d10c97627b51 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone57.0a1
first release with
nightly linux32
d10c97627b51 / 57.0a1 / 20170828100127 / files
nightly linux64
d10c97627b51 / 57.0a1 / 20170828100127 / files
nightly mac
d10c97627b51 / 57.0a1 / 20170828100127 / files
nightly win32
d10c97627b51 / 57.0a1 / 20170828100127 / files
nightly win64
d10c97627b51 / 57.0a1 / 20170828100127 / 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 m-i to m-c, a=merge MozReview-Commit-ID: AX10UmzAEqg
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -60,17 +60,19 @@
         retargetdocumentfocus="urlbar"
         persist="screenX screenY width height sizemode">
 
 # All JS files which are not content (only) dependent that browser.xul
 # wishes to include *must* go into the global-scripts.inc file
 # so that they can be shared by macBrowserOverlay.xul.
 #include global-scripts.inc
 
-<script type="application/javascript" src="chrome://global/content/contentAreaUtils.js"/>
+<script type="application/javascript">
+  Services.scriptloader.loadSubScript("chrome://global/content/contentAreaUtils.js", this);
+</script>
 
 # All sets except for popupsets (commands, keys, stringbundles and broadcasters) *must* go into the
 # browser-sets.inc file for sharing with hiddenWindow.xul.
 #define FULL_BROWSER_WINDOW
 #include browser-sets.inc
 #undef FULL_BROWSER_WINDOW
 
   <popupset id="mainPopupSet">
--- a/browser/base/content/global-scripts.inc
+++ b/browser/base/content/global-scripts.inc
@@ -2,28 +2,34 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # If you update this list, you may need to add a mapping within the following
 # file so that ESLint works correctly:
 # tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js
 
-<script type="application/javascript" src="chrome://browser/content/browser.js"/>
+<script type="application/javascript">
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+for (let script of [
+  "chrome://browser/content/browser.js",
 
-<script type="application/javascript" src="chrome://browser/content/browser-captivePortal.js"/>
-<script type="application/javascript" src="chrome://browser/content/browser-compacttheme.js"/>
-<script type="application/javascript" src="chrome://browser/content/browser-feeds.js"/>
-<script type="application/javascript" src="chrome://browser/content/browser-media.js"/>
-<script type="application/javascript" src="chrome://browser/content/browser-pageActions.js"/>
-<script type="application/javascript" src="chrome://browser/content/browser-places.js"/>
-<script type="application/javascript" src="chrome://browser/content/browser-plugins.js"/>
-<script type="application/javascript" src="chrome://browser/content/browser-sidebar.js"/>
-<script type="application/javascript" src="chrome://browser/content/browser-tabsintitlebar.js"/>
-<script type="application/javascript" src="chrome://browser/content/browser-trackingprotection.js"/>
-
+  "chrome://browser/content/browser-captivePortal.js",
+  "chrome://browser/content/browser-compacttheme.js",
+  "chrome://browser/content/browser-feeds.js",
+  "chrome://browser/content/browser-media.js",
+  "chrome://browser/content/browser-pageActions.js",
+  "chrome://browser/content/browser-places.js",
+  "chrome://browser/content/browser-plugins.js",
+  "chrome://browser/content/browser-sidebar.js",
+  "chrome://browser/content/browser-tabsintitlebar.js",
+  "chrome://browser/content/browser-trackingprotection.js",
 #ifdef MOZ_DATA_REPORTING
-<script type="application/javascript" src="chrome://browser/content/browser-data-submission-info-bar.js"/>
+  "chrome://browser/content/browser-data-submission-info-bar.js",
+#endif
+#ifndef MOZILLA_OFFICIAL
+  "chrome://browser/content/browser-development-helpers.js",
 #endif
-
-#ifndef MOZILLA_OFFICIAL
-<script type="application/javascript" src="chrome://browser/content/browser-development-helpers.js"/>
-#endif
+]) {
+  Services.scriptloader.loadSubScript(script, this);
+}
+</script>
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -224,16 +224,40 @@ public:
   }
   nsresult GetAbsolutelyPositionedSelectionContainer(nsINode** aContainer);
   Element* GetPositionedElement() const
   {
     return mAbsolutelyPositionedObject;
   }
   nsresult GetElementZIndex(Element* aElement, int32_t* aZindex);
 
+  nsresult AddDefaultProperty(nsIAtom* aProperty,
+                              const nsAString& aAttribute,
+                              const nsAString& aValue);
+  nsresult RemoveDefaultProperty(nsIAtom* aProperty,
+                                 const nsAString& aAttribute,
+                                 const nsAString& aValue);
+  nsresult SetInlineProperty(nsIAtom* aProperty,
+                             const nsAString& aAttribute,
+                             const nsAString& aValue);
+  nsresult GetInlineProperty(nsIAtom* aProperty,
+                             const nsAString& aAttribute,
+                             const nsAString& aValue,
+                             bool* aFirst,
+                             bool* aAny,
+                             bool* aAll);
+  nsresult GetInlinePropertyWithAttrValue(nsIAtom* aProperty,
+                                          const nsAString& aAttr,
+                                          const nsAString& aValue,
+                                          bool* aFirst,
+                                          bool* aAny,
+                                          bool* aAll,
+                                          nsAString& outValue);
+  nsresult RemoveInlineProperty(nsIAtom* aProperty,
+                                const nsAString& aAttribute);
 protected:
   virtual ~HTMLEditor();
 
   using EditorBase::IsBlockNode;
   virtual bool IsBlockNode(nsINode *aNode) override;
 
 public:
   // XXX Why don't we move following methods above for grouping by the origins?
--- a/editor/libeditor/HTMLStyleEditor.cpp
+++ b/editor/libeditor/HTMLStyleEditor.cpp
@@ -50,16 +50,24 @@ IsEmptyTextNode(HTMLEditor* aThis, nsINo
 {
   bool isEmptyTextNode = false;
   return EditorBase::IsTextNode(aNode) &&
          NS_SUCCEEDED(aThis->IsEmptyNode(aNode, &isEmptyTextNode)) &&
          isEmptyTextNode;
 }
 
 NS_IMETHODIMP
+HTMLEditor::AddDefaultProperty(const nsAString& aProperty,
+                               const nsAString& aAttribute,
+                               const nsAString& aValue)
+{
+  return AddDefaultProperty(NS_Atomize(aProperty).take(), aAttribute, aValue);
+}
+
+nsresult
 HTMLEditor::AddDefaultProperty(nsIAtom* aProperty,
                                const nsAString& aAttribute,
                                const nsAString& aValue)
 {
   nsString outValue;
   int32_t index;
   nsString attr(aAttribute);
   if (TypeInState::FindPropInList(aProperty, attr, &outValue,
@@ -70,16 +78,25 @@ HTMLEditor::AddDefaultProperty(nsIAtom* 
     nsString value(aValue);
     PropItem *propItem = new PropItem(aProperty, attr, value);
     mDefaultStyles.AppendElement(propItem);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
+HTMLEditor::RemoveDefaultProperty(const nsAString& aProperty,
+                                  const nsAString& aAttribute,
+                                  const nsAString& aValue)
+{
+  return RemoveDefaultProperty(NS_Atomize(aProperty).take(), aAttribute,
+                               aValue);
+}
+
+nsresult
 HTMLEditor::RemoveDefaultProperty(nsIAtom* aProperty,
                                   const nsAString& aAttribute,
                                   const nsAString& aValue)
 {
   nsString outValue;
   int32_t index;
   nsString attr(aAttribute);
   if (TypeInState::FindPropInList(aProperty, attr, &outValue,
@@ -96,18 +113,25 @@ HTMLEditor::RemoveAllDefaultProperties()
   size_t defcon = mDefaultStyles.Length();
   for (size_t j = 0; j < defcon; j++) {
     delete mDefaultStyles[j];
   }
   mDefaultStyles.Clear();
   return NS_OK;
 }
 
+NS_IMETHODIMP
+HTMLEditor::SetInlineProperty(const nsAString& aProperty,
+                              const nsAString& aAttribute,
+                              const nsAString& aValue)
+{
+  return SetInlineProperty(NS_Atomize(aProperty).take(), aAttribute, aValue);
+}
 
-NS_IMETHODIMP
+nsresult
 HTMLEditor::SetInlineProperty(nsIAtom* aProperty,
                               const nsAString& aAttribute,
                               const nsAString& aValue)
 {
   NS_ENSURE_TRUE(aProperty, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(mRules, NS_ERROR_NOT_INITIALIZED);
   nsCOMPtr<nsIEditRules> rules(mRules);
   CommitComposition();
@@ -1136,16 +1160,28 @@ HTMLEditor::GetInlinePropertyBase(nsIAto
     // make sure that if none of the selection is set, we don't report all is
     // set
     *aAll = false;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
+HTMLEditor::GetInlineProperty(const nsAString& aProperty,
+                              const nsAString& aAttribute,
+                              const nsAString& aValue,
+                              bool* aFirst,
+                              bool* aAny,
+                              bool* aAll)
+{
+  return GetInlineProperty(NS_Atomize(aProperty).take(), aAttribute, aValue,
+                           aFirst, aAny, aAll);
+}
+
+nsresult
 HTMLEditor::GetInlineProperty(nsIAtom* aProperty,
                               const nsAString& aAttribute,
                               const nsAString& aValue,
                               bool* aFirst,
                               bool* aAny,
                               bool* aAll)
 {
   NS_ENSURE_TRUE(aProperty && aFirst && aAny && aAll, NS_ERROR_NULL_POINTER);
@@ -1154,16 +1190,30 @@ HTMLEditor::GetInlineProperty(nsIAtom* a
     att = &aAttribute;
   const nsAString *val = nullptr;
   if (!aValue.IsEmpty())
     val = &aValue;
   return GetInlinePropertyBase(*aProperty, att, val, aFirst, aAny, aAll, nullptr);
 }
 
 NS_IMETHODIMP
+HTMLEditor::GetInlinePropertyWithAttrValue(const nsAString& aProperty,
+                                           const nsAString& aAttribute,
+                                           const nsAString& aValue,
+                                           bool* aFirst,
+                                           bool* aAny,
+                                           bool* aAll,
+                                           nsAString& outValue)
+{
+  return GetInlinePropertyWithAttrValue(NS_Atomize(aProperty).take(),
+                                        aAttribute, aValue, aFirst, aAny,
+                                        aAll, outValue);
+}
+
+nsresult
 HTMLEditor::GetInlinePropertyWithAttrValue(nsIAtom* aProperty,
                                            const nsAString& aAttribute,
                                            const nsAString& aValue,
                                            bool* aFirst,
                                            bool* aAny,
                                            bool* aAll,
                                            nsAString& outValue)
 {
@@ -1185,16 +1235,23 @@ HTMLEditor::RemoveAllInlineProperties()
                                nsIEditor::eNext);
 
   nsresult rv = RemoveInlinePropertyImpl(nullptr, nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
   return ApplyDefaultProperties();
 }
 
 NS_IMETHODIMP
+HTMLEditor::RemoveInlineProperty(const nsAString& aProperty,
+                                 const nsAString& aAttribute)
+{
+  return RemoveInlineProperty(NS_Atomize(aProperty).take(), aAttribute);
+}
+
+nsresult
 HTMLEditor::RemoveInlineProperty(nsIAtom* aProperty,
                                  const nsAString& aAttribute)
 {
   return RemoveInlinePropertyImpl(aProperty, &aAttribute);
 }
 
 nsresult
 HTMLEditor::RemoveInlinePropertyImpl(nsIAtom* aProperty,
--- a/editor/libeditor/TextEditorTest.cpp
+++ b/editor/libeditor/TextEditorTest.cpp
@@ -166,68 +166,66 @@ nsresult TextEditorTest::TestTextPropert
   NS_ENSURE_TRUE(htmlEditor, NS_ERROR_FAILURE);
 
   bool any = false;
   bool all = false;
   bool first=false;
 
   const nsString& empty = EmptyString();
 
-  rv = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
-                                     &any, &all);
+  NS_NAMED_LITERAL_STRING(b, "b");
+  NS_NAMED_LITERAL_STRING(i, "i");
+  NS_NAMED_LITERAL_STRING(u, "u");
+
+  rv = htmlEditor->GetInlineProperty(b, empty, empty, &first, &any, &all);
   TEST_RESULT(rv);
   NS_ASSERTION(false==first, "first should be false");
   NS_ASSERTION(false==any, "any should be false");
   NS_ASSERTION(false==all, "all should be false");
-  rv = htmlEditor->SetInlineProperty(nsGkAtoms::b, empty, empty);
+  rv = htmlEditor->SetInlineProperty(b, empty, empty);
   TEST_RESULT(rv);
-  rv = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
-                                     &any, &all);
+  rv = htmlEditor->GetInlineProperty(b, empty, empty, &first, &any, &all);
   TEST_RESULT(rv);
   NS_ASSERTION(true==first, "first should be true");
   NS_ASSERTION(true==any, "any should be true");
   NS_ASSERTION(true==all, "all should be true");
   mEditor->DebugDumpContent();
 
   // remove the bold we just set
   printf("set the whole first text node to not bold\n");
-  rv = htmlEditor->RemoveInlineProperty(nsGkAtoms::b, empty);
+  rv = htmlEditor->RemoveInlineProperty(b, empty);
   TEST_RESULT(rv);
-  rv = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
-                                     &any, &all);
+  rv = htmlEditor->GetInlineProperty(b, empty, empty, &first, &any, &all);
   TEST_RESULT(rv);
   NS_ASSERTION(false==first, "first should be false");
   NS_ASSERTION(false==any, "any should be false");
   NS_ASSERTION(false==all, "all should be false");
   mEditor->DebugDumpContent();
 
   // set all but the first and last character to bold
   printf("set the first text node (1, length-1) to bold and italic, and (2, length-1) to underline.\n");
   selection->Collapse(textNode, 1);
   selection->Extend(textNode, length-1);
-  rv = htmlEditor->SetInlineProperty(nsGkAtoms::b, empty, empty);
+  rv = htmlEditor->SetInlineProperty(b, empty, empty);
   TEST_RESULT(rv);
-  rv = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
-                                     &any, &all);
+  rv = htmlEditor->GetInlineProperty(b, empty, empty, &first, &any, &all);
   TEST_RESULT(rv);
   NS_ASSERTION(true==first, "first should be true");
   NS_ASSERTION(true==any, "any should be true");
   NS_ASSERTION(true==all, "all should be true");
   mEditor->DebugDumpContent();
   // make all that same text italic
-  rv = htmlEditor->SetInlineProperty(nsGkAtoms::i, empty, empty);
+  rv = htmlEditor->SetInlineProperty(i, empty, empty);
   TEST_RESULT(rv);
-  rv = htmlEditor->GetInlineProperty(nsGkAtoms::i, empty, empty, &first,
-                                     &any, &all);
+  rv = htmlEditor->GetInlineProperty(i, empty, empty, &first, &any, &all);
   TEST_RESULT(rv);
   NS_ASSERTION(true==first, "first should be true");
   NS_ASSERTION(true==any, "any should be true");
   NS_ASSERTION(true==all, "all should be true");
-  rv = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
-                                     &any, &all);
+  rv = htmlEditor->GetInlineProperty(b, empty, empty, &first, &any, &all);
   TEST_RESULT(rv);
   NS_ASSERTION(true==first, "first should be true");
   NS_ASSERTION(true==any, "any should be true");
   NS_ASSERTION(true==all, "all should be true");
   mEditor->DebugDumpContent();
 
   // make all the text underlined, except for the first 2 and last 2 characters
   rv = doc->GetElementsByTagName(textTag, getter_AddRefs(nodeList));
@@ -238,20 +236,19 @@ nsresult TextEditorTest::TestTextPropert
   rv = nodeList->Item(count-2, getter_AddRefs(textNode));
   TEST_RESULT(rv);
   TEST_POINTER(textNode.get());
   textData = do_QueryInterface(textNode);
   textData->GetLength(&length);
   NS_ASSERTION(length==915, "wrong text node");
   selection->Collapse(textNode, 1);
   selection->Extend(textNode, length-2);
-  rv = htmlEditor->SetInlineProperty(nsGkAtoms::u, empty, empty);
+  rv = htmlEditor->SetInlineProperty(u, empty, empty);
   TEST_RESULT(rv);
-  rv = htmlEditor->GetInlineProperty(nsGkAtoms::u, empty, empty, &first,
-                                     &any, &all);
+  rv = htmlEditor->GetInlineProperty(u, empty, empty, &first, &any, &all);
   TEST_RESULT(rv);
   NS_ASSERTION(true==first, "first should be true");
   NS_ASSERTION(true==any, "any should be true");
   NS_ASSERTION(true==all, "all should be true");
   mEditor->DebugDumpContent();
 
   return rv;
 }
--- a/editor/libeditor/tests/test_bug1140105.html
+++ b/editor/libeditor/tests/test_bug1140105.html
@@ -33,23 +33,21 @@ SimpleTest.waitForFocus(function() {
   is(selRange.endContainer.nodeName, "#text", "selection should be in text node");
   is(selRange.endOffset, 9, "offset should be 9");
 
   var firstHas = {};
   var anyHas = {};
   var allHas = {};
   var editor = getEditor();
 
-  var atomService = SpecialPowers.Cc["@mozilla.org/atom-service;1"].getService(SpecialPowers.Ci.nsIAtomService);
-  var propAtom = atomService.getAtom("font");
-  editor.getInlineProperty(propAtom, "face", "Arial", firstHas, anyHas, allHas);
+  editor.getInlineProperty("font", "face", "Arial", firstHas, anyHas, allHas);
   is(firstHas.value, true, "Test for Arial: firstHas: true expected");
   is(anyHas.value, true, "Test for Arial: anyHas: true expected");
   is(allHas.value, true, "Test for Arial: allHas: true expected");
-  editor.getInlineProperty(propAtom, "face", "Courier", firstHas, anyHas, allHas);
+  editor.getInlineProperty("font", "face", "Courier", firstHas, anyHas, allHas);
   is(firstHas.value, false, "Test for Courier: firstHas: false expected");
   is(anyHas.value, false, "Test for Courier: anyHas: false expected");
   is(allHas.value, false, "Test for Courier: allHas: false expected");
 
   SimpleTest.finish();
 
 });
 
--- a/editor/nsIEditor.idl
+++ b/editor/nsIEditor.idl
@@ -3,17 +3,16 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "domstubs.idl"
 
 interface nsIURI;
-interface nsIAtom;
 interface nsIContent;
 interface nsISelection;
 interface nsISelectionController;
 interface nsIDocumentStateListener;
 interface nsIOutputStream;
 interface nsITransactionManager;
 interface nsITransaction;
 interface nsIEditorObserver;
--- a/editor/nsIHTMLEditor.idl
+++ b/editor/nsIHTMLEditor.idl
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
 
 #include "nsISupports.idl"
 #include "domstubs.idl"
 
-interface nsIAtom;
 interface nsIContent;
 interface nsIArray;
 interface nsISelection;
 interface nsIContentFilter;
 
 %{C++
 namespace mozilla {
 namespace dom {
@@ -45,32 +44,32 @@ interface nsIHTMLEditor : nsISupports
    * @param aProperty   the property to set by default
    * @param aAttribute  the attribute of the property, if applicable.
    *                    May be null.
    *                    Example: aProperty="font", aAttribute="color"
    * @param aValue      if aAttribute is not null, the value of the attribute.
    *                    Example: aProperty="font", aAttribute="color",
    *                             aValue="0x00FFFF"
    */
-  void addDefaultProperty(in nsIAtom aProperty,
+  void addDefaultProperty(in AString aProperty,
                           in AString aAttribute,
                           in AString aValue);
 
   /**
    * RemoveDefaultProperty() unregisters a default style property with the editor
    *
    * @param aProperty   the property to remove from defaults
    * @param aAttribute  the attribute of the property, if applicable.
    *                    May be null.
    *                    Example: aProperty="font", aAttribute="color"
    * @param aValue      if aAttribute is not null, the value of the attribute.
    *                    Example: aProperty="font", aAttribute="color",
    *                             aValue="0x00FFFF"
    */
-  void removeDefaultProperty(in nsIAtom aProperty,
+  void removeDefaultProperty(in AString aProperty,
                              in AString aAttribute,
                              in AString aValue);
 
   /**
    * RemoveAllDefaultProperties() unregisters all default style properties with the editor
    *
    */
   void removeAllDefaultProperties();
@@ -82,17 +81,17 @@ interface nsIHTMLEditor : nsISupports
    * @param aAttribute  the attribute of the property, if applicable.
    *                    May be null.
    *                    Example: aProperty="font", aAttribute="color"
    * @param aValue      if aAttribute is not null, the value of the attribute.
    *                    May be null.
    *                    Example: aProperty="font", aAttribute="color",
    *                             aValue="0x00FFFF"
    */
-  void setInlineProperty(in nsIAtom aProperty,
+  void setInlineProperty(in AString aProperty,
                          in AString aAttribute,
                          in AString aValue);
 
   /**
    * getInlineProperty() gets aggregate properties of the current selection.
    * All object in the current selection are scanned and their attributes are
    * represented in a list of Property object.
    *
@@ -106,29 +105,29 @@ interface nsIHTMLEditor : nsISupports
    *                             aValue="0x00FFFF"
    * @param aFirst      [OUT] PR_TRUE if the first text node in the
    *                          selection has the property
    * @param aAny        [OUT] PR_TRUE if any of the text nodes in the
    *                          selection have the property
    * @param aAll        [OUT] PR_TRUE if all of the text nodes in the
    *                          selection have the property
    */
-  void getInlineProperty(in nsIAtom aProperty,
-                         in AString  aAttribute,
-                         in AString  aValue,
+  void getInlineProperty(in AString aProperty,
+                         in AString aAttribute,
+                         in AString aValue,
                          out boolean aFirst,
                          out boolean aAny,
                          out boolean aAll);
 
-  AString getInlinePropertyWithAttrValue(in nsIAtom aProperty,
-                                           in AString  aAttribute,
-                                           in AString  aValue,
-                                           out boolean aFirst,
-                                           out boolean aAny,
-                                           out boolean aAll);
+  AString getInlinePropertyWithAttrValue(in AString aProperty,
+                                         in AString aAttribute,
+                                         in AString aValue,
+                                         out boolean aFirst,
+                                         out boolean aAny,
+                                         out boolean aAll);
 
   /**
    * removeAllInlineProperties() deletes all the inline properties from all
    * text in the current selection.
    */
   void removeAllInlineProperties();
 
 
@@ -144,17 +143,17 @@ interface nsIHTMLEditor : nsISupports
    * @param aAttribute  the attribute of the property, if applicable.
    *                    May be null.
    *                    Example: aProperty=nsIEditorProptery::font,
    *                    aAttribute="color"
    *                    nsIEditProperty::allAttributes is special.
    *                    It indicates that all content-based text properties
    *                    are to be removed from the selection.
    */
-  void removeInlineProperty(in nsIAtom aProperty, in AString  aAttribute);
+  void removeInlineProperty(in AString aProperty, in AString aAttribute);
 
   /**
    *  Increase font size for text in selection by 1 HTML unit
    *  All existing text is scanned for existing <FONT SIZE> attributes
    *  so they will be incremented instead of inserting new <FONT> tag
    */
   void increaseFontSize();
 
--- a/gfx/webrender_bindings/Moz2DImageRenderer.cpp
+++ b/gfx/webrender_bindings/Moz2DImageRenderer.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gfxUtils.h"
 #include "mozilla/Range.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/InlineTranslator.h"
 #include "mozilla/gfx/RecordedEvent.h"
 #include "WebRenderTypes.h"
+#include "webrender_ffi.h"
 
 #include <iostream>
 
 #ifdef MOZ_ENABLE_FREETYPE
 #include "mozilla/ThreadLocal.h"
 #endif
 
 namespace mozilla {
@@ -22,16 +23,18 @@ namespace wr {
 
 #ifdef MOZ_ENABLE_FREETYPE
 static MOZ_THREAD_LOCAL(FT_Library) sFTLibrary;
 #endif
 
 static bool Moz2DRenderCallback(const Range<const uint8_t> aBlob,
                                 gfx::IntSize aSize,
                                 gfx::SurfaceFormat aFormat,
+                                const uint16_t *aTileSize,
+                                const mozilla::wr::TileOffset *aTileOffset,
                                 Range<uint8_t> aOutput)
 {
   MOZ_ASSERT(aSize.width > 0 && aSize.height > 0);
   if (aSize.width <= 0 || aSize.height <= 0) {
     return false;
   }
 
   auto stride = aSize.width * gfx::BytesPerPixel(aFormat);
@@ -66,16 +69,28 @@ static bool Moz2DRenderCallback(const Ra
     aFormat,
     uninitialized
   );
 
   if (!dt) {
     return false;
   }
 
+  if (aTileOffset) {
+    // It's overkill to use a TiledDrawTarget for a single tile
+    // but it was the easiest way to get the offset handling working
+    gfx::TileSet tileset;
+    gfx::Tile tile;
+    tile.mDrawTarget = dt;
+    tile.mTileOrigin = gfx::IntPoint(aTileOffset->x * *aTileSize, aTileOffset->y * *aTileSize);
+    tileset.mTiles = &tile;
+    tileset.mTileCount = 1;
+    dt = gfx::Factory::CreateTiledDrawTarget(tileset);
+  }
+
   gfx::InlineTranslator translator(dt, fontContext);
 
   auto ret = translator.TranslateRecording((char*)aBlob.begin().get(), aBlob.length());
 
 #if 0
   static int i = 0;
   char filename[40];
   sprintf(filename, "out%d.png", i++);
@@ -88,19 +103,23 @@ static bool Moz2DRenderCallback(const Ra
 } // namespace
 } // namespace
 
 extern "C" {
 
 bool wr_moz2d_render_cb(const mozilla::wr::ByteSlice blob,
                         uint32_t width, uint32_t height,
                         mozilla::wr::ImageFormat aFormat,
+                        const uint16_t *aTileSize,
+                        const mozilla::wr::TileOffset *aTileOffset,
                         mozilla::wr::MutByteSlice output)
 {
   return mozilla::wr::Moz2DRenderCallback(mozilla::wr::ByteSliceToRange(blob),
                                           mozilla::gfx::IntSize(width, height),
                                           mozilla::wr::ImageFormatToSurfaceFormat(aFormat),
+                                          aTileSize,
+                                          aTileOffset,
                                           mozilla::wr::MutByteSliceToRange(output));
 }
 
 } // extern
 
 
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1585,11 +1585,13 @@ pub unsafe extern "C" fn wr_dec_ref_arc(
 // Update for the new blob image interface changes.
 //
 extern "C" {
      // TODO: figure out the API for tiled blob images.
      pub fn wr_moz2d_render_cb(blob: ByteSlice,
                                width: u32,
                                height: u32,
                                format: ImageFormat,
+                               tile_size: *const u16,
+                               tile_offset: *const TileOffset,
                                output: MutByteSlice)
                                -> bool;
 }
--- a/gfx/webrender_bindings/src/moz2d_renderer.rs
+++ b/gfx/webrender_bindings/src/moz2d_renderer.rs
@@ -1,74 +1,88 @@
 use webrender_api::*;
 use bindings::{ByteSlice, MutByteSlice, wr_moz2d_render_cb};
 use rayon::ThreadPool;
 
 use std::collections::hash_map::{HashMap, Entry};
+use std::ptr;
 use std::sync::mpsc::{channel, Sender, Receiver};
 use std::sync::Arc;
 
 pub struct Moz2dImageRenderer {
-    blob_commands: HashMap<ImageKey, Arc<BlobImageData>>,
+    blob_commands: HashMap<ImageKey, (Arc<BlobImageData>, Option<TileSize>)>,
 
     // The images rendered in the current frame (not kept here between frames)
     rendered_images: HashMap<BlobImageRequest, Option<BlobImageResult>>,
 
     tx: Sender<(BlobImageRequest, BlobImageResult)>,
     rx: Receiver<(BlobImageRequest, BlobImageResult)>,
 
     workers: Arc<ThreadPool>,
 }
 
+fn option_to_nullable<T>(option: &Option<T>) -> *const T {
+    match option {
+        &Some(ref x) => { x as *const T }
+        &None => { ptr::null() }
+    }
+}
+
 impl BlobImageRenderer for Moz2dImageRenderer {
-    fn add(&mut self, key: ImageKey, data: BlobImageData, _tiling: Option<TileSize>) {
-        self.blob_commands.insert(key, Arc::new(data));
+    fn add(&mut self, key: ImageKey, data: BlobImageData, tiling: Option<TileSize>) {
+        self.blob_commands.insert(key, (Arc::new(data), tiling));
     }
 
     fn update(&mut self, key: ImageKey, data: BlobImageData) {
-        self.blob_commands.insert(key, Arc::new(data));
+        let entry = self.blob_commands.get_mut(&key).unwrap();
+        entry.0 = Arc::new(data);
     }
 
     fn delete(&mut self, key: ImageKey) {
         self.blob_commands.remove(&key);
     }
 
     fn request(&mut self,
                _resources: &BlobImageResources,
                request: BlobImageRequest,
                descriptor: &BlobImageDescriptor,
                _dirty_rect: Option<DeviceUintRect>) {
         debug_assert!(!self.rendered_images.contains_key(&request));
         // TODO: implement tiling.
-        assert!(request.tile.is_none());
 
         // Add None in the map of rendered images. This makes it possible to differentiate
         // between commands that aren't finished yet (entry in the map is equal to None) and
         // keys that have never been requested (entry not in the map), which would cause deadlocks
         // if we were to block upon receving their result in resolve!
         self.rendered_images.insert(request, None);
 
         let tx = self.tx.clone();
         let descriptor = descriptor.clone();
-        let commands = Arc::clone(self.blob_commands.get(&request.key).unwrap());
+        let blob = &self.blob_commands[&request.key];
+        let tile_size = blob.1;
+        let commands = Arc::clone(&blob.0);
+
 
         self.workers.spawn(move || {
             let buf_size = (descriptor.width
                 * descriptor.height
                 * descriptor.format.bytes_per_pixel().unwrap()) as usize;
             let mut output = vec![255u8; buf_size];
 
             let result = unsafe {
                 if wr_moz2d_render_cb(
                     ByteSlice::new(&commands[..]),
                     descriptor.width,
                     descriptor.height,
                     descriptor.format,
+                    option_to_nullable(&tile_size),
+                    option_to_nullable(&request.tile),
                     MutByteSlice::new(output.as_mut_slice())
                 ) {
+
                     Ok(RasterizedBlobImage {
                         width: descriptor.width,
                         height: descriptor.height,
                         data: output,
                     })
                 } else {
                     Err(BlobImageError::Other("Unknown error".to_string()))
                 }
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -162,16 +162,18 @@ enum class YuvColorSpace : uint32_t {
 struct Arc_VecU8;
 
 struct DocumentHandle;
 
 // The renderer is responsible for submitting to the GPU the work prepared by the
 // RenderBackend.
 struct Renderer;
 
+struct Tiles;
+
 struct Vec_u8;
 
 struct WrRenderedEpochs;
 
 struct WrState;
 
 struct WrThreadPool;
 
@@ -410,16 +412,26 @@ struct ColorF {
   bool operator==(const ColorF& aOther) const {
     return r == aOther.r &&
            g == aOther.g &&
            b == aOther.b &&
            a == aOther.a;
   }
 };
 
+struct TypedPoint2D_u16__Tiles {
+  uint16_t x;
+  uint16_t y;
+
+  bool operator==(const TypedPoint2D_u16__Tiles& aOther) const {
+    return x == aOther.x &&
+           y == aOther.y;
+  }
+};
+
 struct TypedPoint2D_f32__LayerPixel {
   float x;
   float y;
 
   bool operator==(const TypedPoint2D_f32__LayerPixel& aOther) const {
     return x == aOther.x &&
            y == aOther.y;
   }
@@ -601,16 +613,18 @@ struct TextShadow {
     return offset == aOther.offset &&
            color == aOther.color &&
            blur_radius == aOther.blur_radius;
   }
 };
 
 typedef YuvColorSpace WrYuvColorSpace;
 
+typedef TypedPoint2D_u16__Tiles TileOffset;
+
 struct MutByteSlice {
   uint8_t *buffer;
   size_t len;
 
   bool operator==(const MutByteSlice& aOther) const {
     return buffer == aOther.buffer &&
            len == aOther.len;
   }
@@ -1083,16 +1097,18 @@ void wr_dp_push_yuv_planar_image(WrState
                                  WrYuvColorSpace aColorSpace,
                                  ImageRendering aImageRendering)
 WR_FUNC;
 
 extern bool wr_moz2d_render_cb(ByteSlice aBlob,
                                uint32_t aWidth,
                                uint32_t aHeight,
                                ImageFormat aFormat,
+                               const uint16_t *aTileSize,
+                               const TileOffset *aTileoffest,
                                MutByteSlice aOutput);
 
 extern void wr_notifier_external_event(WrWindowId aWindowId,
                                        size_t aRawEvent);
 
 extern void wr_notifier_new_frame_ready(WrWindowId aWindowId);
 
 extern void wr_notifier_new_scroll_frame_ready(WrWindowId aWindowId,
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -150,16 +150,182 @@ NewPromiseAllDataHolder(JSContext* cx, H
 
     dataHolder->setFixedSlot(PromiseAllDataHolderSlot_Promise, ObjectValue(*resultPromise));
     dataHolder->setFixedSlot(PromiseAllDataHolderSlot_RemainingElements, Int32Value(1));
     dataHolder->setFixedSlot(PromiseAllDataHolderSlot_ValuesArray, valuesArray);
     dataHolder->setFixedSlot(PromiseAllDataHolderSlot_ResolveFunction, ObjectValue(*resolve));
     return dataHolder;
 }
 
+namespace {
+// Generator used by PromiseObject::getID.
+mozilla::Atomic<uint64_t> gIDGenerator(0);
+} // namespace
+
+static MOZ_ALWAYS_INLINE bool
+ShouldCaptureDebugInfo(JSContext* cx)
+{
+    return cx->options().asyncStack() || cx->compartment()->isDebuggee();
+}
+
+class PromiseDebugInfo : public NativeObject
+{
+  private:
+    enum Slots {
+        Slot_AllocationSite,
+        Slot_ResolutionSite,
+        Slot_AllocationTime,
+        Slot_ResolutionTime,
+        Slot_Id,
+        SlotCount
+    };
+
+  public:
+    static const Class class_;
+    static PromiseDebugInfo* create(JSContext* cx, Handle<PromiseObject*> promise) {
+        Rooted<PromiseDebugInfo*> debugInfo(cx, NewObjectWithClassProto<PromiseDebugInfo>(cx));
+        if (!debugInfo)
+            return nullptr;
+
+        RootedObject stack(cx);
+        if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames())))
+            return nullptr;
+        debugInfo->setFixedSlot(Slot_AllocationSite, ObjectOrNullValue(stack));
+        debugInfo->setFixedSlot(Slot_ResolutionSite, NullValue());
+        debugInfo->setFixedSlot(Slot_AllocationTime, DoubleValue(MillisecondsSinceStartup()));
+        debugInfo->setFixedSlot(Slot_ResolutionTime, NumberValue(0));
+        promise->setFixedSlot(PromiseSlot_DebugInfo, ObjectValue(*debugInfo));
+
+        return debugInfo;
+    }
+
+    static PromiseDebugInfo* FromPromise(PromiseObject* promise) {
+        Value val = promise->getFixedSlot(PromiseSlot_DebugInfo);
+        if (val.isObject())
+            return &val.toObject().as<PromiseDebugInfo>();
+        return nullptr;
+    }
+
+    /**
+     * Returns the given PromiseObject's process-unique ID.
+     * The ID is lazily assigned when first queried, and then either stored
+     * in the DebugInfo slot if no debug info was recorded for this Promise,
+     * or in the Id slot of the DebugInfo object.
+     */
+    static uint64_t id(PromiseObject* promise) {
+        Value idVal(promise->getFixedSlot(PromiseSlot_DebugInfo));
+        if (idVal.isUndefined()) {
+            idVal.setDouble(++gIDGenerator);
+            promise->setFixedSlot(PromiseSlot_DebugInfo, idVal);
+        } else if (idVal.isObject()) {
+            PromiseDebugInfo* debugInfo = FromPromise(promise);
+            idVal = debugInfo->getFixedSlot(Slot_Id);
+            if (idVal.isUndefined()) {
+                idVal.setDouble(++gIDGenerator);
+                debugInfo->setFixedSlot(Slot_Id, idVal);
+            }
+        }
+        return uint64_t(idVal.toNumber());
+    }
+
+    double allocationTime() { return getFixedSlot(Slot_AllocationTime).toNumber(); }
+    double resolutionTime() { return getFixedSlot(Slot_ResolutionTime).toNumber(); }
+    JSObject* allocationSite() { return getFixedSlot(Slot_AllocationSite).toObjectOrNull(); }
+    JSObject* resolutionSite() { return getFixedSlot(Slot_ResolutionSite).toObjectOrNull(); }
+
+    static void setResolutionInfo(JSContext* cx, Handle<PromiseObject*> promise) {
+        if (!ShouldCaptureDebugInfo(cx))
+            return;
+
+        // If async stacks weren't enabled and the Promise's global wasn't a
+        // debuggee when the Promise was created, we won't have a debugInfo
+        // object. We still want to capture the resolution stack, so we
+        // create the object now and change it's slots' values around a bit.
+        Rooted<PromiseDebugInfo*> debugInfo(cx, FromPromise(promise));
+        if (!debugInfo) {
+            RootedValue idVal(cx, promise->getFixedSlot(PromiseSlot_DebugInfo));
+            debugInfo = create(cx, promise);
+            if (!debugInfo) {
+                cx->clearPendingException();
+                return;
+            }
+
+            // The current stack was stored in the AllocationSite slot, move
+            // it to ResolutionSite as that's what it really is.
+            debugInfo->setFixedSlot(Slot_ResolutionSite,
+                                    debugInfo->getFixedSlot(Slot_AllocationSite));
+            debugInfo->setFixedSlot(Slot_AllocationSite, NullValue());
+
+            // There's no good default for a missing AllocationTime, so
+            // instead of resetting that, ensure that it's the same as
+            // ResolutionTime, so that the diff shows as 0, which isn't great,
+            // but bearable.
+            debugInfo->setFixedSlot(Slot_ResolutionTime,
+                                    debugInfo->getFixedSlot(Slot_AllocationTime));
+
+            // The Promise's ID might've been queried earlier, in which case
+            // it's stored in the DebugInfo slot. We saved that earlier, so
+            // now we can store it in the right place (or leave it as
+            // undefined if it wasn't ever initialized.)
+            debugInfo->setFixedSlot(Slot_Id, idVal);
+            return;
+        }
+
+        RootedObject stack(cx);
+        if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames()))) {
+            cx->clearPendingException();
+            return;
+        }
+
+        debugInfo->setFixedSlot(Slot_ResolutionSite, ObjectOrNullValue(stack));
+        debugInfo->setFixedSlot(Slot_ResolutionTime, DoubleValue(MillisecondsSinceStartup()));
+    }
+};
+
+const Class PromiseDebugInfo::class_ = {
+    "PromiseDebugInfo",
+    JSCLASS_HAS_RESERVED_SLOTS(SlotCount)
+};
+
+double
+PromiseObject::allocationTime()
+{
+    auto debugInfo = PromiseDebugInfo::FromPromise(this);
+    if (debugInfo)
+        return debugInfo->allocationTime();
+    return 0;
+}
+
+double
+PromiseObject::resolutionTime()
+{
+    auto debugInfo = PromiseDebugInfo::FromPromise(this);
+    if (debugInfo)
+        return debugInfo->resolutionTime();
+    return 0;
+}
+
+JSObject*
+PromiseObject::allocationSite()
+{
+    auto debugInfo = PromiseDebugInfo::FromPromise(this);
+    if (debugInfo)
+        return debugInfo->allocationSite();
+    return nullptr;
+}
+
+JSObject*
+PromiseObject::resolutionSite()
+{
+    auto debugInfo = PromiseDebugInfo::FromPromise(this);
+    if (debugInfo)
+        return debugInfo->resolutionSite();
+    return nullptr;
+}
+
 /**
  * Wrapper for GetAndClearException that handles cases where no exception is
  * pending, but an error occurred. This can be the case if an OOM was
  * encountered while throwing the error.
  */
 static bool
 MaybeGetAndClearException(JSContext* cx, MutableHandleValue rval)
 {
@@ -1285,23 +1451,21 @@ CreatePromiseObjectInternal(JSContext* c
     // Omitted, we allocate our single list of reaction records lazily.
 
     // Step 7.
     // Implicit, the handled flag is unset by default.
 
     // Store an allocation stack so we can later figure out what the
     // control flow was for some unexpected results. Frightfully expensive,
     // but oh well.
-    RootedObject stack(cx);
-    if (cx->options().asyncStack() || cx->compartment()->isDebuggee()) {
-        if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames())))
+    if (ShouldCaptureDebugInfo(cx)) {
+        PromiseDebugInfo* debugInfo = PromiseDebugInfo::create(cx, promise);
+        if (!debugInfo)
             return nullptr;
     }
-    promise->setFixedSlot(PromiseSlot_AllocationSite, ObjectOrNullValue(stack));
-    promise->setFixedSlot(PromiseSlot_AllocationTime, DoubleValue(MillisecondsSinceStartup()));
 
     // Let the Debugger know about this Promise.
     if (informDebugger)
         JS::dbg::onNewPromise(cx, promise);
 
     return promise;
 }
 
@@ -3041,38 +3205,28 @@ AddPromiseReaction(JSContext* cx, Handle
                                                                   onFulfilled, onRejected,
                                                                   resolve, reject,
                                                                   incumbentGlobal));
     if (!reaction)
         return false;
     return AddPromiseReaction(cx, promise, reaction);
 }
 
-namespace {
-// Generator used by PromiseObject::getID.
-mozilla::Atomic<uint64_t> gIDGenerator(0);
-} // namespace
+uint64_t
+PromiseObject::getID()
+{
+    return PromiseDebugInfo::id(this);
+}
 
 double
 PromiseObject::lifetime()
 {
     return MillisecondsSinceStartup() - allocationTime();
 }
 
-uint64_t
-PromiseObject::getID()
-{
-    Value idVal(getFixedSlot(PromiseSlot_Id));
-    if (idVal.isUndefined()) {
-        idVal.setDouble(++gIDGenerator);
-        setFixedSlot(PromiseSlot_Id, idVal);
-    }
-    return uint64_t(idVal.toNumber());
-}
-
 /**
  * Returns all promises that directly depend on this one. That means those
  * created by calling `then` on this promise, or the promise returned by
  * `Promise.all(iterable)` or `Promise.race(iterable)`, with this promise
  * being a member of the passed-in `iterable`.
  *
  * Per spec, we should have separate lists of reaction records for the
  * fulfill and reject cases. As an optimization, we have only one of those,
@@ -3172,25 +3326,17 @@ PromiseObject::reject(JSContext* cx, Han
 
     RootedValue dummy(cx);
     return Call(cx, funVal, UndefinedHandleValue, args, &dummy);
 }
 
 /* static */ void
 PromiseObject::onSettled(JSContext* cx, Handle<PromiseObject*> promise)
 {
-    RootedObject stack(cx);
-    if (cx->options().asyncStack() || cx->compartment()->isDebuggee()) {
-        if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames()))) {
-            cx->clearPendingException();
-            return;
-        }
-    }
-    promise->setFixedSlot(PromiseSlot_ResolutionSite, ObjectOrNullValue(stack));
-    promise->setFixedSlot(PromiseSlot_ResolutionTime, DoubleValue(MillisecondsSinceStartup()));
+    PromiseDebugInfo::setResolutionInfo(cx, promise);
 
     if (promise->state() == JS::PromiseState::Rejected && promise->isUnhandled())
         cx->runtime()->addUnhandledRejectedPromise(cx, promise);
 
     JS::dbg::onPromiseSettled(cx, promise);
 }
 
 OffThreadPromiseTask::OffThreadPromiseTask(JSContext* cx, Handle<PromiseObject*> promise)
--- a/js/src/builtin/Promise.h
+++ b/js/src/builtin/Promise.h
@@ -14,21 +14,17 @@
 
 namespace js {
 
 enum PromiseSlots {
     PromiseSlot_Flags = 0,
     PromiseSlot_ReactionsOrResult,
     PromiseSlot_RejectFunction,
     PromiseSlot_AwaitGenerator = PromiseSlot_RejectFunction,
-    PromiseSlot_AllocationSite,
-    PromiseSlot_ResolutionSite,
-    PromiseSlot_AllocationTime,
-    PromiseSlot_ResolutionTime,
-    PromiseSlot_Id,
+    PromiseSlot_DebugInfo,
     PromiseSlots,
 };
 
 #define PROMISE_FLAG_RESOLVED  0x1
 #define PROMISE_FLAG_FULFILLED 0x2
 #define PROMISE_FLAG_HANDLED   0x4
 #define PROMISE_FLAG_REPORTED  0x8
 #define PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION 0x10
@@ -72,24 +68,20 @@ class PromiseObject : public NativeObjec
 
     static MOZ_MUST_USE bool resolve(JSContext* cx, Handle<PromiseObject*> promise,
                                      HandleValue resolutionValue);
     static MOZ_MUST_USE bool reject(JSContext* cx, Handle<PromiseObject*> promise,
                                     HandleValue rejectionValue);
 
     static void onSettled(JSContext* cx, Handle<PromiseObject*> promise);
 
-    double allocationTime() { return getFixedSlot(PromiseSlot_AllocationTime).toNumber(); }
-    double resolutionTime() { return getFixedSlot(PromiseSlot_ResolutionTime).toNumber(); }
-    JSObject* allocationSite() {
-        return getFixedSlot(PromiseSlot_AllocationSite).toObjectOrNull();
-    }
-    JSObject* resolutionSite() {
-        return getFixedSlot(PromiseSlot_ResolutionSite).toObjectOrNull();
-    }
+    double allocationTime();
+    double resolutionTime();
+    JSObject* allocationSite();
+    JSObject* resolutionSite();
     double lifetime();
     double timeToResolution() {
         MOZ_ASSERT(state() != JS::PromiseState::Pending);
         return resolutionTime() - allocationTime();
     }
     MOZ_MUST_USE bool dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> values);
     uint64_t getID();
     bool isUnhandled() {
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -442,17 +442,16 @@ class BytecodeParser
         ,
         isStackDump(false)
 #endif /* DEBUG */
     {}
 
     bool parse();
 
 #ifdef DEBUG
-    bool isReachable(uint32_t offset) { return maybeCode(offset); }
     bool isReachable(const jsbytecode* pc) { return maybeCode(pc); }
 #endif /* DEBUG */
 
     uint32_t stackDepthAtPC(uint32_t offset) {
         // Sometimes the code generator in debug mode asks about the stack depth
         // of unreachable code (bug 932180 comment 22).  Assume that unreachable
         // code has no operands on the stack.
         return getCode(offset).stackDepth;
@@ -493,24 +492,16 @@ class BytecodeParser
         Bytecode& code = getCode(offset);
         if (operand < 0) {
             operand += code.stackDepthAfter;
             MOZ_ASSERT(operand >= 0);
         }
         MOZ_ASSERT(uint32_t(operand) < code.stackDepthAfter);
         return code.offsetStackAfter[operand];
     }
-    jsbytecode* pcForStackOperandAfterPC(jsbytecode* pc, int operand, uint8_t* defIndex) {
-        size_t offset = script_->pcToOffset(pc);
-        const OffsetAndDefIndex& offsetAndDefIndex = offsetForStackOperandAfterPC(offset, operand);
-        if (offsetAndDefIndex.isSpecial())
-            return nullptr;
-        *defIndex = offsetAndDefIndex.defIndex();
-        return script_->offsetToPC(offsetAndDefIndex.offset());
-    }
 
     template <typename Callback>
     bool forEachJumpOrigins(jsbytecode* pc, Callback callback) {
         Bytecode& code = getCode(script_->pcToOffset(pc));
 
         for (Bytecode::JumpInfo& info : code.jumpOrigins) {
             if (!callback(script_->offsetToPC(info.from), info.kind))
                 return false;
@@ -529,37 +520,34 @@ class BytecodeParser
         return allocScope_.alloc();
     }
 
     void reportOOM() {
         allocScope_.releaseEarly();
         ReportOutOfMemory(cx_);
     }
 
-    uint32_t numSlots() {
-        return 1 + script_->nfixed() +
-               (script_->functionNonDelazifying() ? script_->functionNonDelazifying()->nargs() : 0);
-    }
-
     uint32_t maximumStackDepth() {
         return script_->nslots() - script_->nfixed();
     }
 
     Bytecode& getCode(uint32_t offset) {
         MOZ_ASSERT(offset < script_->length());
         MOZ_ASSERT(codeArray_[offset]);
         return *codeArray_[offset];
     }
-    Bytecode& getCode(const jsbytecode* pc) { return getCode(script_->pcToOffset(pc)); }
 
     Bytecode* maybeCode(uint32_t offset) {
         MOZ_ASSERT(offset < script_->length());
         return codeArray_[offset];
     }
+
+#ifdef DEBUG
     Bytecode* maybeCode(const jsbytecode* pc) { return maybeCode(script_->pcToOffset(pc)); }
+#endif
 
     uint32_t simulateOp(JSOp op, uint32_t offset, OffsetAndDefIndex* offsetStack,
                         uint32_t stackDepth);
 
     inline bool recordBytecode(uint32_t offset, const OffsetAndDefIndex* offsetStack,
                                uint32_t stackDepth);
 
     inline bool addJump(uint32_t offset, uint32_t* currentOffset,
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -5735,50 +5735,35 @@ class BytecodeRangeWithPosition : privat
  *
  * An instruction on a given line is an entry point for that line if it can be
  * reached from (an instruction on) a different line. We distinguish between the
  * following cases:
  *   - hasNoEdges:
  *       The instruction cannot be reached, so the instruction is not an entry
  *       point for the line it is on.
  *   - hasSingleEdge:
- *   - hasMultipleEdgesFromSingleLine:
  *       The instruction can be reached from a single line. If this line is
  *       different from the line the instruction is on, the instruction is an
  *       entry point for that line.
- *   - hasMultipleEdgesFromMultipleLines:
- *       The instruction can be reached from multiple lines. At least one of
- *       these lines is guaranteed to be different from the line the instruction
- *       is on, so the instruction is an entry point for that line.
  *
  * Similarly, an instruction on a given position (line/column pair) is an
  * entry point for that position if it can be reached from (an instruction on) a
  * different position. Again, we distinguish between the following cases:
  *   - hasNoEdges:
  *       The instruction cannot be reached, so the instruction is not an entry
  *       point for the position it is on.
  *   - hasSingleEdge:
  *       The instruction can be reached from a single position. If this line is
  *       different from the position the instruction is on, the instruction is
  *       an entry point for that position.
- *   - hasMultipleEdgesFromSingleLine:
- *   - hasMultipleEdgesFromMultipleLines:
- *       The instruction can be reached from multiple positions. At least one
- *       of these positions is guaranteed to be different from the position the
- *       instruction is on, so the instruction is an entry point for that
- *       position.
  */
 class FlowGraphSummary {
   public:
     class Entry {
       public:
-        static Entry createWithNoEdges() {
-            return Entry(SIZE_MAX, 0);
-        }
-
         static Entry createWithSingleEdge(size_t lineno, size_t column) {
             return Entry(lineno, column);
         }
 
         static Entry createWithMultipleEdgesFromSingleLine(size_t lineno) {
             return Entry(lineno, SIZE_MAX);
         }
 
@@ -5791,32 +5776,16 @@ class FlowGraphSummary {
         bool hasNoEdges() const {
             return lineno_ == SIZE_MAX && column_ != SIZE_MAX;
         }
 
         bool hasSingleEdge() const {
             return lineno_ != SIZE_MAX && column_ != SIZE_MAX;
         }
 
-        bool hasMultipleEdgesFromSingleLine() const {
-            return lineno_ != SIZE_MAX && column_ == SIZE_MAX;
-        }
-
-        bool hasMultipleEdgesFromMultipleLines() const {
-            return lineno_ == SIZE_MAX && column_ == SIZE_MAX;
-        }
-
-        bool operator==(const Entry& other) const {
-            return lineno_ == other.lineno_ && column_ == other.column_;
-        }
-
-        bool operator!=(const Entry& other) const {
-            return lineno_ != other.lineno_ || column_ != other.column_;
-        }
-
         size_t lineno() const {
             return lineno_;
         }
 
         size_t column() const {
             return column_;
         }
 
--- a/testing/mochitest/tests/SimpleTest/EventUtils.js
+++ b/testing/mochitest/tests/SimpleTest/EventUtils.js
@@ -12,16 +12,19 @@
  *  synthesizePointer
  *  synthesizeWheel
  *  synthesizeWheelAtPoint
  *  synthesizeKey
  *  synthesizeNativeKey
  *  synthesizeMouseExpectEvent
  *  synthesizeKeyExpectEvent
  *  synthesizeNativeOSXClick
+ *  synthesizeDragOver
+ *  synthesizeDropAfterDragOver
+ *  synthesizeDrop
  *
  *  When adding methods to this file, please add a performance test for it.
  */
 
 // This file is used both in privileged and unprivileged contexts, so we have to
 // be careful about our access to Components.interfaces. We also want to avoid
 // naming collisions with anything that might be defined in the scope that imports
 // this script.
@@ -137,31 +140,48 @@ function sendMouseEvent(aEvent, aTarget,
   event.initMouseEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg,
                        screenXArg, screenYArg, clientXArg, clientYArg,
                        ctrlKeyArg, altKeyArg, shiftKeyArg, metaKeyArg,
                        buttonArg, relatedTargetArg);
 
   return SpecialPowers.dispatchEvent(aWindow, aTarget, event);
 }
 
+function isHidden(aElement) {
+  var box = aElement.getBoundingClientRect();
+  return box.width == 0 && box.height == 0;
+}
+
 /**
  * Send a drag event to the node aTarget (aTarget can be an id, or an
  * actual node) . The "event" passed in to aEvent is just a JavaScript
  * object with the properties set that the real drag event object should
  * have. This includes the type of the drag event.
  */
 function sendDragEvent(aEvent, aTarget, aWindow = window) {
   if (['drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave', 'drop'].indexOf(aEvent.type) == -1) {
     throw new Error("sendDragEvent doesn't know about event type '" + aEvent.type + "'");
   }
 
   if (typeof aTarget == "string") {
     aTarget = aWindow.document.getElementById(aTarget);
   }
 
+  /*
+   * Drag event cannot be performed if the element is hidden, except 'dragend'
+   * event where the element can becomes hidden after start dragging.
+   */
+  if (aEvent.type != 'dragend' && isHidden(aTarget)) {
+    var targetName = aTarget.nodeName;
+    if ("id" in aTarget && aTarget.id) {
+      targetName += "#" + aTarget.id;
+    }
+    throw new Error(`${aEvent.type} event target ${targetName} is hidden`);
+  }
+
   var event = aWindow.document.createEvent('DragEvent');
 
   var typeArg          = aEvent.type;
   var canBubbleArg     = true;
   var cancelableArg    = true;
   var viewArg          = aWindow;
   var detailArg        = aEvent.detail        || 0;
   var screenXArg       = aEvent.screenX       || 0;
--- a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
+++ b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
@@ -18,16 +18,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "Extension",
                                   "resource://gre/modules/Extension.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
                                   "resource://gre/modules/Schemas.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "TestUtils",
+                                  "resource://testing-common/TestUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "Management", () => {
   const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {});
   return Management;
 });
 
 /* exported ExtensionTestUtils */
 
@@ -136,20 +138,25 @@ class ContentPage {
 
     this.browser.loadURI(url);
     return promiseBrowserLoaded(this.browser, url, redirectUrl);
   }
 
   async close() {
     await this.browserReady;
 
+    let {messageManager} = this.browser;
+
     this.browser = null;
 
     this.windowlessBrowser.close();
     this.windowlessBrowser = null;
+
+    await TestUtils.topicObserved("message-manager-disconnect",
+                                  subject => subject === messageManager);
   }
 }
 
 class ExtensionWrapper {
   constructor(testScope, extension = null) {
     this.testScope = testScope;
 
     this.extension = null;
--- a/toolkit/components/extensions/LegacyExtensionsUtils.jsm
+++ b/toolkit/components/extensions/LegacyExtensionsUtils.jsm
@@ -12,18 +12,16 @@ this.EXPORTED_SYMBOLS = ["LegacyExtensio
  * This file exports helpers for Legacy Extensions that want to embed a webextensions
  * and exchange messages with the embedded WebExtension.
  */
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
-                                  "resource://gre/modules/AsyncShutdown.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Extension",
                                   "resource://gre/modules/Extension.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionChild",
                                   "resource://gre/modules/ExtensionChild.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
 
 Cu.import("resource://gre/modules/ExtensionCommon.jsm");
@@ -203,38 +201,26 @@ class EmbeddedExtension {
   /**
    * Shuts down the embedded webextension.
    *
    * @param {number} reason
    *   The add-on shutdown bootstrap reason received from the XPIProvider.
    *
    * @returns {Promise<void>} a promise that is resolved when the shutdown has been done
    */
-  shutdown(reason) {
+  async shutdown(reason) {
     EmbeddedExtensionManager.untrackEmbeddedExtension(this);
 
-    // If there is a pending startup,  wait to be completed and then shutdown.
-    if (this.startupPromise) {
-      let promise = this.startupPromise.then(() => {
-        return this.extension.shutdown(reason);
-      });
-
-      AsyncShutdown.profileChangeTeardown.addBlocker(
-        `Legacy Extension Shutdown: ${this.addonId}`,
-        promise.catch(() => {}));
+    if (this.extension && !this.extension.hasShutdown) {
+      let {extension} = this;
+      this.extension = null;
 
-      return promise;
+      await extension.shutdown(reason);
     }
-
-    // Run shutdown now if the embedded webextension has been correctly started
-    if (this.extension && this.started && !this.extension.hasShutdown) {
-      this.extension.shutdown(reason);
-    }
-
-    return Promise.resolve();
+    return undefined;
   }
 }
 
 // Keep track on the created EmbeddedExtension instances and destroy
 // them when their container addon is going to be disabled or uninstalled.
 EmbeddedExtensionManager = {
   // Map of the existent EmbeddedExtensions instances by addon id.
   embeddedExtensionsByAddonId: new Map(),
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js
@@ -44,17 +44,17 @@ const MAPPINGS = {
   "browserPlacesViews.js":
     "browser/components/places/content/browserPlacesViews.js",
   "panelUI.js": "browser/components/customizableui/content/panelUI.js",
   "viewSourceUtils.js":
     "toolkit/components/viewsource/content/viewSourceUtils.js"
 };
 
 const globalScriptsRegExp =
-  /<script type=\"application\/javascript\" src=\"(.*)\"\/>/;
+  /<script type=\"application\/javascript\" src=\"(.*)\"\/>|^\s*"(.*?\.js)",$/;
 
 function getGlobalScriptsIncludes() {
   let fileData;
   try {
     fileData = fs.readFileSync(helpers.globalScriptsPath, {encoding: "utf8"});
   } catch (ex) {
     // The file isn't present, so this isn't an m-c repository.
     return null;
@@ -62,18 +62,18 @@ function getGlobalScriptsIncludes() {
 
   fileData = fileData.split("\n");
 
   let result = [];
 
   for (let line of fileData) {
     let match = line.match(globalScriptsRegExp);
     if (match) {
-      let sourceFile =
-        match[1].replace("chrome://browser/content/", "browser/base/content/")
+      let sourceFile = (match[1] || match[2])
+                .replace("chrome://browser/content/", "browser/base/content/")
                 .replace("chrome://global/content/", "toolkit/content/");
 
       for (let mapping of Object.getOwnPropertyNames(MAPPINGS)) {
         if (sourceFile.includes(mapping)) {
           sourceFile = MAPPINGS[mapping];
         }
       }