Merge m-c to fx-team, a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 15 Apr 2016 15:40:17 -0700
changeset 331342 29782c3286ca0d496b16cd3a7a0edd0741641d99
parent 331341 15a81c85b9aec2df2a3fd354dee54234dd4f6b1b (current diff)
parent 331323 f5a97eb5c89a2b5133ff8bba915acba6344fa7cc (diff)
child 331343 2a95760bd9cca8d1912a14158380ce1f0d84766d
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team, a=merge MozReview-Commit-ID: 7Kut3ctlo0F
browser/base/content/test/general/browser_bug329212.js
browser/base/content/test/general/browser_bug331772_xul_tooltiptext_in_html.js
browser/base/content/test/general/browser_bug561623.js
browser/base/content/test/general/browser_bug581947.js
browser/base/content/test/general/xul_tooltiptext.xhtml
js/src/jit-test/tests/auto-regress/bug1263558.js
js/src/tests/js1_6/Array/generics.js
js/src/tests/js1_6/String/generics.js
media/ffvpx/cpu_perms.h
toolkit/content/tests/browser/browser_input_file_tooltips.js
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -218,17 +218,16 @@ pref("content.sink.perf_parse_time", 500
 // Maximum scripts runtime before showing an alert
 // Disable the watchdog thread for B2G. See bug 870043 comment 31.
 pref("dom.use_watchdog", false);
 
 // The slow script dialog can be triggered from inside the JS engine as well,
 // ensure that those calls don't accidentally trigger the dialog.
 pref("dom.max_script_run_time", 0);
 pref("dom.max_chrome_script_run_time", 0);
-pref("dom.max_child_script_run_time", 0);
 
 // plugins
 pref("plugin.disable", true);
 pref("dom.ipc.plugins.enabled", true);
 
 // product URLs
 // The breakpad report server to link to in about:crashes
 pref("breakpad.reportURL", "https://crash-stats.mozilla.com/report/index/");
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -390,16 +390,18 @@
 @RESPATH@/components/nsSetDefaultBrowser.js
 @RESPATH@/components/toolkitsearch.manifest
 @RESPATH@/components/nsTryToClose.manifest
 @RESPATH@/components/nsTryToClose.js
 @RESPATH@/components/passwordmgr.manifest
 @RESPATH@/components/nsLoginInfo.js
 @RESPATH@/components/nsLoginManager.js
 @RESPATH@/components/nsLoginManagerPrompter.js
+@RESPATH@/components/TooltipTextProvider.js
+@RESPATH@/components/TooltipTextProvider.manifest
 @RESPATH@/components/NetworkGeolocationProvider.manifest
 @RESPATH@/components/NetworkGeolocationProvider.js
 @RESPATH@/components/TVSimulatorService.js
 @RESPATH@/components/TVSimulatorService.manifest
 #ifdef MOZ_WEBRTC
 @RESPATH@/components/PeerConnection.js
 @RESPATH@/components/PeerConnection.manifest
 #endif
--- a/browser/app/moz.build
+++ b/browser/app/moz.build
@@ -18,24 +18,16 @@ JS_PREFERENCE_PP_FILES += [
 SOURCES += [
     'nsBrowserApp.cpp',
 ]
 
 FINAL_TARGET_FILES += ['blocklist.xml']
 FINAL_TARGET_FILES.defaults.profile += ['profile/prefs.js']
 FINAL_TARGET_FILES.defaults += ['permissions']
 
-if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
-    FINAL_TARGET_FILES.icons += ['!/dist/branding/mozicon128.png']
-    FINAL_TARGET_FILES.chrome.icons.default += [
-        '!/dist/branding/default16.png',
-        '!/dist/branding/default32.png',
-        '!/dist/branding/default48.png',
-    ]
-
 DEFINES['APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
 
 LOCAL_INCLUDES += [
     '!/build',
     '/toolkit/xre',
     '/xpcom/base',
     '/xpcom/build',
 ]
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4131,36 +4131,41 @@ var XULBrowserWindow = {
 
     if (gURLBar && gURLBar._mayTrimURLs /* corresponds to browser.urlbar.trimURLs */)
       url = trimURL(url);
 
     this.overLink = url;
     LinkTargetDisplay.update();
   },
 
-  showTooltip: function (x, y, tooltip) {
+  showTooltip: function (x, y, tooltip, direction) {
     if (Cc["@mozilla.org/widget/dragservice;1"].getService(Ci.nsIDragService).
         getCurrentSession()) {
       return;
     }
 
     // The x,y coordinates are relative to the <browser> element using
     // the chrome zoom level.
     let elt = document.getElementById("remoteBrowserTooltip");
     elt.label = tooltip;
+    elt.style.direction = direction;
 
     let anchor = gBrowser.selectedBrowser;
     elt.openPopupAtScreen(anchor.boxObject.screenX + x, anchor.boxObject.screenY + y, false, null);
   },
 
   hideTooltip: function () {
     let elt = document.getElementById("remoteBrowserTooltip");
     elt.hidePopup();
   },
 
+  getTabCount: function () {
+    return gBrowser.tabs.length;
+  },
+
   updateStatusField: function () {
     var text, type, types = ["overLink"];
     if (this._busyUI)
       types.push("status");
     types.push("defaultStatus");
     for (type of types) {
       text = this[type];
       if (text)
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -113,17 +113,16 @@ support-files =
   test_no_mcb_on_http_site_font.css
   test_no_mcb_on_http_site_font2.html
   test_no_mcb_on_http_site_font2.css
   test_mcb_redirect.html
   test_mcb_redirect_image.html
   test_mcb_double_redirect_image.html
   test_mcb_redirect.js
   test_mcb_redirect.sjs
-  xul_tooltiptext.xhtml
   file_bug1045809_1.html
   file_bug1045809_2.html
   file_csp_block_all_mixedcontent.html
   file_csp_block_all_mixedcontent.js
   !/toolkit/components/passwordmgr/test/browser/form_basic.html
   !/toolkit/components/passwordmgr/test/browser/insecure_test.html
   !/toolkit/components/passwordmgr/test/browser/insecure_test_subframe.html
   !/toolkit/content/tests/browser/common/mockTransfer.js
@@ -171,20 +170,16 @@ skip-if = os == "mac" # The Fitt's Law b
 [browser_blob-channelname.js]
 [browser_bookmark_popup.js]
 skip-if = (os == "linux" && debug) # mouseover not reliable on linux debug builds
 [browser_bookmark_titles.js]
 skip-if = buildapp == 'mulet' || toolkit == "windows" # Disabled on Windows due to frequent failures (bugs 825739, 841341)
 [browser_bug304198.js]
 [browser_bug321000.js]
 skip-if = true # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
-[browser_bug329212.js]
-skip-if = e10s # Bug 1236991 - Update or remove tests that use fillInPageTooltip
-[browser_bug331772_xul_tooltiptext_in_html.js]
-skip-if = e10s # Bug 1236991 - Update or remove tests that use fillInPageTooltip
 [browser_bug356571.js]
 [browser_bug380960.js]
 [browser_bug386835.js]
 [browser_bug406216.js]
 [browser_bug408415.js]
 [browser_bug409481.js]
 [browser_bug409624.js]
 [browser_bug413915.js]
@@ -227,36 +222,32 @@ skip-if = buildapp == 'mulet' || e10s # 
 [browser_bug537474.js]
 [browser_bug550565.js]
 [browser_bug553455.js]
 skip-if = buildapp == 'mulet' # Bug 1066070 - I don't think either popup notifications nor addon install stuff works on mulet?
 [browser_bug555224.js]
 [browser_bug555767.js]
 [browser_bug556061.js]
 [browser_bug559991.js]
-[browser_bug561623.js]
-skip-if = e10s # Bug 1236991 - Update or remove tests that use fillInPageTooltip
 [browser_bug561636.js]
 [browser_bug562649.js]
 [browser_bug563588.js]
 [browser_bug565575.js]
 [browser_bug565667.js]
 skip-if = toolkit != "cocoa"
 [browser_bug567306.js]
 [browser_bug575561.js]
 [browser_bug575830.js]
 [browser_bug577121.js]
 [browser_bug578534.js]
 [browser_bug579872.js]
 [browser_bug580638.js]
 [browser_bug580956.js]
 [browser_bug581242.js]
 [browser_bug581253.js]
-[browser_bug581947.js]
-skip-if = e10s # Bug 1236991 - Update or remove tests that use fillInPageTooltip
 [browser_bug585558.js]
 [browser_bug585785.js]
 [browser_bug585830.js]
 [browser_bug590206.js]
 [browser_bug592338.js]
 [browser_bug594131.js]
 [browser_bug595507.js]
 [browser_bug596687.js]
@@ -575,9 +566,9 @@ skip-if = !e10s || !crashreporter
 skip-if = !e10s || !crashreporter
 [browser_aboutTabCrashed_showForm.js]
 skip-if = !e10s || !crashreporter
 [browser_aboutTabCrashed_withoutDump.js]
 skip-if = !e10s
 [browser_csp_block_all_mixedcontent.js]
 tags = mcb
 [browser_newwindow_focus.js]
-skip-if = (os == "linux" && !e10s) # Bug 1263254 - Perma fails on Linux without e10s for some reason.
\ No newline at end of file
+skip-if = (os == "linux" && !e10s) # Bug 1263254 - Perma fails on Linux without e10s for some reason.
--- a/browser/branding/branding-common.mozbuild
+++ b/browser/branding/branding-common.mozbuild
@@ -38,8 +38,14 @@ def FirefoxBranding():
         ]
     elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
         BRANDING_FILES += [
             'default16.png',
             'default32.png',
             'default48.png',
             'mozicon128.png',
         ]
+        FINAL_TARGET_FILES.icons += ['mozicon128.png']
+        FINAL_TARGET_FILES.chrome.icons.default += [
+            'default16.png',
+            'default32.png',
+            'default48.png',
+        ]
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -382,16 +382,18 @@
 @RESPATH@/components/nsSearchSuggestions.js
 @RESPATH@/components/nsSidebar.js
 @RESPATH@/components/passwordmgr.manifest
 @RESPATH@/components/nsLoginInfo.js
 @RESPATH@/components/nsLoginManager.js
 @RESPATH@/components/nsLoginManagerPrompter.js
 @RESPATH@/components/storage-json.js
 @RESPATH@/components/crypto-SDR.js
+@RESPATH@/components/TooltipTextProvider.js
+@RESPATH@/components/TooltipTextProvider.manifest
 @RESPATH@/components/jsconsole-clhandler.manifest
 @RESPATH@/components/jsconsole-clhandler.js
 @RESPATH@/components/webvtt.xpt
 @RESPATH@/components/WebVTT.manifest
 @RESPATH@/components/WebVTTParserWrapper.js
 #ifdef MOZ_GTK
 @RESPATH@/components/nsFilePicker.manifest
 @RESPATH@/components/nsFilePicker.js
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -341,17 +341,16 @@ def old_configure_options(*options):
     # Below are the configure flags used by comm-central.
     '--enable-ldap',
     '--enable-mapi',
     '--enable-calendar',
     '--enable-incomplete-external-linkage',
 )
 @imports(_from='__builtin__', _import='compile')
 @imports(_from='__builtin__', _import='open')
-@imports(_from='__builtin__', _import='zip')
 @imports('logging')
 @imports('os')
 @imports('subprocess')
 @imports('sys')
 @imports(_from='mozbuild.shellutil', _import='quote')
 def old_configure(prepare_configure, extra_old_configure_args, all_options,
                   *options):
     cmd = prepare_configure
--- a/build/moz.configure/util.configure
+++ b/build/moz.configure/util.configure
@@ -26,25 +26,21 @@ def is_absolute_or_relative(path):
     return os.sep in path
 
 
 @imports(_import='mozpack.path', _as='mozpath')
 def normsep(path):
     return mozpath.normsep(path)
 
 
-# This unlocks the sandbox. Do not copy blindly.
-@imports(_import='__builtin__', _as='__builtins__')
+@imports(_from='which', _import='which')
+@imports(_from='which', _import='WhichError')
 def find_program(file):
     if is_absolute_or_relative(file):
         return os.path.abspath(file) if os.path.isfile(file) else None
-    # We can't use @imports here because it imports at declaration time,
-    # and the declaration of find_program happens before we ensure the
-    # which module is available in sys.path somehow.
-    from which import which, WhichError
     try:
         return normsep(which(file))
     except WhichError:
         return None
 
 
 def unique_list(l):
     result = []
@@ -95,17 +91,16 @@ def namespace(**kwargs):
 # of a @depends function in a non-immediate manner.
 #   @depends('--option')
 #   def option(value)
 #       return namespace(foo=value)
 #   set_config('FOO', delayed_getattr(option, 'foo')
 @template
 def delayed_getattr(func, key):
     @depends(func)
-    @imports(_from='__builtin__', _import='getattr')
     def result(value):
         # The @depends function we're being passed may have returned
         # None, or an object that simply doesn't have the wanted key.
         # In that case, just return None.
         return getattr(value, key, None)
     return result
 
 
--- a/client.mk
+++ b/client.mk
@@ -362,22 +362,25 @@ endif
 $(OBJDIR)/.mozconfig.json: $(call mkdir_deps,$(OBJDIR)) ;
 
 save-mozconfig: $(FOUND_MOZCONFIG)
 ifdef FOUND_MOZCONFIG
 	-cp $(FOUND_MOZCONFIG) $(OBJDIR)/.mozconfig
 endif
 
 configure:: $(configure-preqs)
+	$(call BUILDSTATUS,TIERS configure)
+	$(call BUILDSTATUS,TIER_START configure)
 	@echo cd $(OBJDIR);
 	@echo $(CONFIGURE) $(CONFIGURE_ARGS)
 	@cd $(OBJDIR) && $(BUILD_PROJECT_ARG) $(CONFIGURE_ENV_ARGS) $(CONFIGURE) $(CONFIGURE_ARGS) \
 	  || ( echo '*** Fix above errors and then restart with\
                "$(MAKE) -f client.mk build"' && exit 1 )
 	@touch $(OBJDIR)/Makefile
+	$(call BUILDSTATUS,TIER_FINISH configure)
 
 ifneq (,$(MAKEFILE))
 $(OBJDIR)/Makefile: $(OBJDIR)/config.status
 
 $(OBJDIR)/config.status: $(CONFIG_STATUS_DEPS)
 else
 $(OBJDIR)/Makefile: $(CONFIG_STATUS_DEPS)
 endif
--- a/devtools/shared/heapsnapshot/HeapSnapshot.cpp
+++ b/devtools/shared/heapsnapshot/HeapSnapshot.cpp
@@ -132,18 +132,16 @@ parseMessage(ZeroCopyInputStream& stream
 
   codedStream.PopLimit(limit);
   return true;
 }
 
 template<typename CharT, typename InternedStringSet>
 struct GetOrInternStringMatcher
 {
-  using ReturnType = const CharT*;
-
   InternedStringSet& internedStrings;
 
   explicit GetOrInternStringMatcher(InternedStringSet& strings) : internedStrings(strings) { }
 
   const CharT* match(const std::string* str) {
     MOZ_ASSERT(str);
     size_t length = str->length() / sizeof(CharT);
     auto tempString = reinterpret_cast<const CharT*>(str->data());
@@ -855,39 +853,33 @@ EstablishBoundaries(JSContext* cx,
 // A variant covering all the various two-byte strings that we can get from the
 // ubi::Node API.
 class TwoByteString : public Variant<JSAtom*, const char16_t*, JS::ubi::EdgeName>
 {
   using Base = Variant<JSAtom*, const char16_t*, JS::ubi::EdgeName>;
 
   struct AsTwoByteStringMatcher
   {
-    using ReturnType = TwoByteString;
-
     TwoByteString match(JSAtom* atom) {
       return TwoByteString(atom);
     }
 
     TwoByteString match(const char16_t* chars) {
       return TwoByteString(chars);
     }
   };
 
   struct IsNonNullMatcher
   {
-    using ReturnType = bool;
-
     template<typename T>
     bool match(const T& t) { return t != nullptr; }
   };
 
   struct LengthMatcher
   {
-    using ReturnType = size_t;
-
     size_t match(JSAtom* atom) {
       MOZ_ASSERT(atom);
       JS::ubi::AtomOrTwoByteChars s(atom);
       return s.length();
     }
 
     size_t match(const char16_t* chars) {
       MOZ_ASSERT(chars);
@@ -897,18 +889,16 @@ class TwoByteString : public Variant<JSA
     size_t match(const JS::ubi::EdgeName& ptr) {
       MOZ_ASSERT(ptr);
       return NS_strlen(ptr.get());
     }
   };
 
   struct CopyToBufferMatcher
   {
-    using ReturnType = size_t;
-
     RangedPtr<char16_t> destination;
     size_t              maxLength;
 
     CopyToBufferMatcher(RangedPtr<char16_t> destination, size_t maxLength)
       : destination(destination)
       , maxLength(maxLength)
     { }
 
@@ -980,18 +970,16 @@ public:
 // because each type is generally a different semantic thing in addition to
 // having a slightly different representation. For example, the set of edge
 // names and the set stack frames' source names naturally tend not to overlap
 // very much if at all.
 struct TwoByteString::HashPolicy {
   using Lookup = TwoByteString;
 
   struct HashingMatcher {
-    using ReturnType  = js::HashNumber;
-
     js::HashNumber match(const JSAtom* atom) {
       return js::DefaultHasher<const JSAtom*>::hash(atom);
     }
 
     js::HashNumber match(const char16_t* chars) {
       MOZ_ASSERT(chars);
       auto length = NS_strlen(chars);
       return HashString(chars, length);
@@ -1004,17 +992,16 @@ struct TwoByteString::HashPolicy {
   };
 
   static js::HashNumber hash(const Lookup& l) {
     HashingMatcher hasher;
     return l.match(hasher);
   }
 
   struct EqualityMatcher {
-    using ReturnType = bool;
     const TwoByteString& rhs;
     explicit EqualityMatcher(const TwoByteString& rhs) : rhs(rhs) { }
 
     bool match(const JSAtom* atom) {
       return rhs.is<JSAtom*>() && rhs.as<JSAtom*>() == atom;
     }
 
     bool match(const char16_t* chars) {
--- a/docshell/test/navigation/mochitest.ini
+++ b/docshell/test/navigation/mochitest.ini
@@ -42,14 +42,14 @@ skip-if = (buildapp == 'b2g' && (toolkit
 [test_grandchild.html]
 [test_not-opener.html]
 skip-if = buildapp == 'b2g'
 [test_opener.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_popup-navigates-children.html]
 skip-if = buildapp == 'b2g' # b2g(Needs multiple window.open support, also uses docshelltreenode) b2g-debug(Needs multiple window.open support, also uses docshelltreenode) b2g-desktop(Needs multiple window.open support, also uses docshelltreenode)
 [test_reserved.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || (toolkit == 'android') || (e10s && debug && os == 'win') #too slow on Android 4.3 aws only; bug 1030403
+skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || (toolkit == 'android') #too slow on Android 4.3 aws only; bug 1030403
 [test_sessionhistory.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' #RANDOM # b2g-debug(Perma-orange on debug emulator builds) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_sibling-matching-parent.html]
 [test_sibling-off-domain.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -1199,17 +1199,17 @@ Animation::IsPossiblyOrphanedPendingAnim
 
 StickyTimeDuration
 Animation::EffectEnd() const
 {
   if (!mEffect) {
     return StickyTimeDuration(0);
   }
 
-  return mEffect->GetComputedTiming().mEndTime;
+  return mEffect->SpecifiedTiming().EndTime();
 }
 
 nsIDocument*
 Animation::GetRenderedDocument() const
 {
   if (!mEffect) {
     return nullptr;
   }
--- a/dom/animation/AnimationEffectTiming.cpp
+++ b/dom/animation/AnimationEffectTiming.cpp
@@ -120,15 +120,31 @@ AnimationEffectTiming::SetDirection(cons
   }
 
   mTiming.mDirection = aDirection;
 
   PostSpecifiedTimingUpdated(mEffect);
 }
 
 void
-AnimationEffectTiming::SetEasing(const nsAString& aEasing, ErrorResult& aRv)
+AnimationEffectTiming::SetEasing(JSContext* aCx,
+                                 const nsAString& aEasing,
+                                 ErrorResult& aRv)
 {
-  // TODO: Bug 1244643 - implement AnimationEffectTiming easing
+  Maybe<ComputedTimingFunction> newFunction =
+    TimingParams::ParseEasing(aEasing,
+                              AnimationUtils::GetCurrentRealmDocument(aCx),
+                              aRv);
+  if (aRv.Failed()) {
+    return;
+  }
+
+  if (mTiming.mFunction == newFunction) {
+    return;
+  }
+
+  mTiming.mFunction = newFunction;
+
+  PostSpecifiedTimingUpdated(mEffect);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/animation/AnimationEffectTiming.h
+++ b/dom/animation/AnimationEffectTiming.h
@@ -30,17 +30,17 @@ public:
   void SetDelay(double aDelay);
   void SetEndDelay(double aEndDelay);
   void SetFill(const FillMode& aFill);
   void SetIterationStart(double aIterationStart, ErrorResult& aRv);
   void SetIterations(double aIterations, ErrorResult& aRv);
   void SetDuration(const UnrestrictedDoubleOrString& aDuration,
                    ErrorResult& aRv);
   void SetDirection(const PlaybackDirection& aDirection);
-  void SetEasing(const nsAString& aEasing, ErrorResult& aRv);
+  void SetEasing(JSContext* aCx, const nsAString& aEasing, ErrorResult& aRv);
 
 private:
   KeyframeEffect* MOZ_NON_OWNING_REF mEffect;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/animation/AnimationUtils.h
+++ b/dom/animation/AnimationUtils.h
@@ -45,24 +45,16 @@ public:
 
     return result;
   }
 
   static void LogAsyncAnimationFailure(nsCString& aMessage,
                                        const nsIContent* aContent = nullptr);
 
   /**
-   * Parses a CSS <single-transition-timing-function> value from
-   * aEasing into a ComputedTimingFunction.  If parsing fails, Nothing() will
-   * be returned.
-   */
-  static Maybe<ComputedTimingFunction>
-  ParseEasing(const nsAString& aEasing, nsIDocument* aDocument);
-
-  /**
    * Get the document from the JS context to use when parsing CSS properties.
    */
   static nsIDocument*
   GetCurrentRealmDocument(JSContext* aCx);
 };
 
 } // namespace mozilla
 
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -15,17 +15,16 @@
 #include "mozilla/KeyframeUtils.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "Layers.h" // For Layer
 #include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetStyleContextForElement
 #include "nsCSSPropertySet.h"
 #include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
 #include "nsCSSPseudoElements.h" // For CSSPseudoElementType
 #include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
-#include <algorithm> // For std::max
 
 namespace mozilla {
 
 // Helper functions for generating a ComputedTimingProperties dictionary
 static void
 GetComputedTimingDictionary(const ComputedTiming& aComputedTiming,
                             const Nullable<TimeDuration>& aLocalTime,
                             const TimingParams& aTiming,
@@ -240,24 +239,27 @@ KeyframeEffectReadOnly::GetComputedTimin
   ComputedTiming result;
 
   if (aTiming.mDuration) {
     MOZ_ASSERT(aTiming.mDuration.ref() >= zeroDuration,
                "Iteration duration should be positive");
     result.mDuration = aTiming.mDuration.ref();
   }
 
-  result.mIterations = IsNaN(aTiming.mIterations) || aTiming.mIterations < 0.0f ?
-                       1.0f :
-                       aTiming.mIterations;
-  result.mIterationStart = std::max(aTiming.mIterationStart, 0.0);
+  MOZ_ASSERT(aTiming.mIterations >= 0.0 && !IsNaN(aTiming.mIterations),
+             "mIterations should be nonnegative & finite, as ensured by "
+             "ValidateIterations or CSSParser");
+  result.mIterations = aTiming.mIterations;
+  MOZ_ASSERT(aTiming.mIterationStart >= 0.0,
+             "mIterationStart should be nonnegative, as ensured by "
+             "ValidateIterationStart");
+  result.mIterationStart = aTiming.mIterationStart;
 
-  result.mActiveDuration = ActiveDuration(result.mDuration, result.mIterations);
-  result.mEndTime = aTiming.mDelay + result.mActiveDuration +
-                    aTiming.mEndDelay;
+  result.mActiveDuration = aTiming.ActiveDuration();
+  result.mEndTime = aTiming.EndTime();
   result.mFill = aTiming.mFill == dom::FillMode::Auto ?
                  dom::FillMode::None :
                  aTiming.mFill;
 
   // The default constructor for ComputedTiming sets all other members to
   // values consistent with an animation that has not been sampled.
   if (aLocalTime.IsNull()) {
     return result;
@@ -398,33 +400,16 @@ KeyframeEffectReadOnly::GetComputedTimin
     result.mProgress.SetValue(
       aTiming.mFunction->GetValue(result.mProgress.Value(),
                                   result.mBeforeFlag));
   }
 
   return result;
 }
 
-StickyTimeDuration
-KeyframeEffectReadOnly::ActiveDuration(
-  const StickyTimeDuration& aIterationDuration,
-  double aIterationCount)
-{
-  // If either the iteration duration or iteration count is zero,
-  // Web Animations says that the active duration is zero. This is to
-  // ensure that the result is defined when the other argument is Infinity.
-  const StickyTimeDuration zeroDuration;
-  if (aIterationDuration == zeroDuration ||
-      aIterationCount == 0.0) {
-    return zeroDuration;
-  }
-
-  return aIterationDuration.MultDouble(aIterationCount);
-}
-
 // https://w3c.github.io/web-animations/#in-play
 bool
 KeyframeEffectReadOnly::IsInPlay() const
 {
   if (!mAnimation || mAnimation->PlayState() == AnimationPlayState::Finished) {
     return false;
   }
 
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -269,22 +269,16 @@ public:
   {
     return GetComputedTimingAt(GetLocalTime(),
                                aTiming ? *aTiming : SpecifiedTiming());
   }
 
   void
   GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const override;
 
-  // Return the duration of the active interval for the given duration and
-  // iteration count.
-  static StickyTimeDuration
-  ActiveDuration(const StickyTimeDuration& aIterationDuration,
-                 double aIterationCount);
-
   bool IsInPlay() const;
   bool IsCurrent() const;
   bool IsInEffect() const;
 
   void SetAnimation(Animation* aAnimation);
   Animation* GetAnimation() const { return mAnimation; }
 
   void SetFrames(nsTArray<Keyframe>&& aFrames, nsStyleContext* aStyleContext);
--- a/dom/animation/TimingParams.cpp
+++ b/dom/animation/TimingParams.cpp
@@ -156,16 +156,34 @@ TimingParams::ParseEasing(const nsAStrin
     case eCSSUnit_Unset:
     case eCSSUnit_TokenStream:
     case eCSSUnit_Null:
       break;
     default:
       MOZ_ASSERT_UNREACHABLE("unexpected animation-timing-function unit");
       break;
   }
+
+  // Bug 1247004
+  //
+  // The Web Animations polyfill had a bug that translated 'linear' into
+  // the string 'function (a){return a}'. This bug has been fixed but older
+  // versions of the polyfill are still widely used. Google are collecting
+  // usage data on this but for now we need to *not* throw on
+  // 'function (a){return a}' or else a lot of sites will break.
+  //
+  // Instead, we should treat this string as equivalent to 'linear' and
+  // return Nothing().
+  //
+  // Chromium has a similar special case path for this string.
+  // See: https://bugs.chromium.org/p/chromium/issues/detail?id=601672
+  if (aEasing == NS_LITERAL_STRING("function (a){return a}")) {
+    return Nothing();
+  }
+
   aRv.ThrowTypeError<dom::MSG_INVALID_EASING_ERROR>(aEasing);
   return Nothing();
 }
 
 bool
 TimingParams::operator==(const TimingParams& aOther) const
 {
   return mDuration == aOther.mDuration &&
--- a/dom/animation/TimingParams.h
+++ b/dom/animation/TimingParams.h
@@ -92,16 +92,36 @@ struct TimingParams
   TimeDuration mDelay;      // Initializes to zero
   TimeDuration mEndDelay;
   double mIterations = 1.0; // Can be NaN, negative, +/-Infinity
   double mIterationStart = 0.0;
   dom::PlaybackDirection mDirection = dom::PlaybackDirection::Normal;
   dom::FillMode mFill = dom::FillMode::Auto;
   Maybe<ComputedTimingFunction> mFunction;
 
+  // Return the duration of the active interval calculated by duration and
+  // iteration count.
+  StickyTimeDuration ActiveDuration() const
+  {
+    // If either the iteration duration or iteration count is zero,
+    // Web Animations says that the active duration is zero. This is to
+    // ensure that the result is defined when the other argument is Infinity.
+    static const StickyTimeDuration zeroDuration;
+    if (!mDuration || *mDuration == zeroDuration || mIterations == 0.0) {
+      return zeroDuration;
+    }
+
+    return mDuration->MultDouble(mIterations);
+  }
+
+  StickyTimeDuration EndTime() const
+  {
+    return mDelay + ActiveDuration() + mEndDelay;
+  }
+
   bool operator==(const TimingParams& aOther) const;
   bool operator!=(const TimingParams& aOther) const
   {
     return !(*this == aOther);
   }
 };
 
 } // namespace mozilla
--- a/dom/animation/test/chrome/test_animation_observers.html
+++ b/dom/animation/test/chrome/test_animation_observers.html
@@ -1664,16 +1664,39 @@ addAsyncAnimTest("change_delay",
                  "records after animation restarted");
 
   anim.cancel();
   yield await_frame();
   assert_records([{ added: [], changed: [], removed: [anim] }],
                  "records after animation end");
 });
 
+addAsyncAnimTest("change_easing",
+                 { observe: div, subtree: true }, function*() {
+  var anim = div.animate({ opacity: [ 0, 1 ] },
+                         { duration: 100 * MS_PER_SEC,
+                           easing: "steps(2, start)" });
+
+  yield await_frame();
+  assert_records([{ added: [anim], changed: [], removed: [] }],
+                 "records after animation is added");
+
+  anim.effect.timing.easing = "steps(2, end)";
+  yield await_frame();
+  assert_records([{ added: [], changed: [anim], removed: [] }],
+                 "records after easing is changed");
+
+  anim.effect.timing.easing = "steps(2, end)";
+  yield await_frame();
+  assert_records([], "records after assigning same value");
+
+  anim.cancel();
+  yield await_frame();
+});
+
 addAsyncAnimTest("negative_delay_in_constructor",
                  { observe: div, subtree: true }, function*() {
   var anim = div.animate({ opacity: [ 0, 1 ] },
                          { duration: 100, delay: -100 });
   yield await_frame();
   assert_records([], "records after assigning negative value");
 });
 
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2301,16 +2301,29 @@ nsDOMWindowUtils::AdvanceTimeAndRefresh(
       transaction->SendSetTestSampleTime(driver->MostRecentRefresh());
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDOMWindowUtils::GetLastTransactionId(uint64_t *aLastTransactionId)
+{
+  nsPresContext* presContext = GetPresContext();
+  if (!presContext) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  nsRefreshDriver* driver = presContext->GetRootPresContext()->RefreshDriver();
+  *aLastTransactionId = driver->LastTransactionId();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDOMWindowUtils::RestoreNormalRefresh()
 {
   // Kick the compositor out of test mode before the refresh driver, so that
   // the refresh driver doesn't send an update that gets ignored by the
   // compositor.
   RefPtr<LayerTransactionChild> transaction = GetLayerTransaction();
   if (transaction && transaction->IPCOpen()) {
     transaction->SendLeaveTestMode();
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -6429,23 +6429,33 @@ nsGlobalWindow::CanMoveResizeWindows(boo
       return false;
     }
 
     if (!CanSetProperty("dom.disable_window_move_resize")) {
       return false;
     }
 
     // Ignore the request if we have more than one tab in the window.
-    nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
-    if (treeOwner) {
-      uint32_t itemCount;
-      if (NS_SUCCEEDED(treeOwner->GetTargetableShellCount(&itemCount)) &&
-          itemCount > 1) {
-        return false;
-      }
+    uint32_t itemCount = 0;
+    if (XRE_IsContentProcess()) {
+      nsCOMPtr<nsIDocShell> docShell = GetDocShell();
+      if (docShell) {
+        nsCOMPtr<nsITabChild> child = docShell->GetTabChild();
+        if (child) {
+          child->SendGetTabCount(&itemCount);
+        }
+      }
+    } else {
+      nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
+      if (treeOwner) {
+        treeOwner->GetTargetableShellCount(&itemCount);
+      }
+    }
+    if (itemCount > 1) {
+      return false;
     }
   }
 
   if (mDocShell) {
     bool allow;
     nsresult rv = mDocShell->GetAllowWindowControl(&allow);
     if (NS_SUCCEEDED(rv) && !allow)
       return false;
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -746,17 +746,17 @@ skip-if = buildapp == 'b2g' || toolkit =
 [test_iframe_referrer_changing.html]
 [test_iframe_referrer_invalid.html]
 [test_caretPositionFromPoint.html]
 [test_classList.html]
 # This test fails on the Mac for some reason
 [test_copyimage.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || (toolkit != 'cocoa' && toolkit != 'gonk' && toolkit != 'gtk2' && toolkit != 'gtk3' && toolkit != 'windows') #b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_copypaste.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 904183 # b2g(clipboard undefined) b2g-debug(clipboard undefined) b2g-desktop(clipboard undefined)
+skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 904183 # b2g(clipboard undefined) b2g-debug(clipboard undefined) b2g-desktop(clipboard undefined)
 [test_copypaste.xhtml]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 904183 # b2g(bug 904183) b2g-debug(bug 904183) b2g-desktop(bug 904183)
 [test_createHTMLDocument.html]
 [test_declare_stylesheet_obsolete.html]
 [test_document_constructor.html]
 [test_document_importNode_document.html]
 [test_domparser_null_char.html]
 [test_domparsing.html]
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -83,16 +83,22 @@ DOMInterfaces = {
 'AbstractWorker': {
     'concrete': False
 },
 
 'AnimationEffectReadOnly': {
     'concrete': False
 },
 
+'AnimationEffectTiming': {
+    'implicitJSContext': {
+        'setterOnly': [ 'easing' ]
+    }
+},
+
 'AnimationTimeline': {
     'concrete': False
 },
 
 'AnonymousContent': {
     'wrapperCache': False
 },
 
--- a/dom/cache/test/mochitest/mochitest.ini
+++ b/dom/cache/test/mochitest/mochitest.ini
@@ -27,17 +27,16 @@ support-files =
 
 [test_cache.html]
 [test_cache_add.html]
 [test_cache_match_request.html]
 [test_cache_matchAll_request.html]
 [test_cache_overwrite.html]
 [test_cache_match_vary.html]
 [test_caches.html]
-skip-if = e10s && debug && os == 'win'
 [test_cache_keys.html]
 [test_cache_put.html]
 [test_cache_requestCache.html]
 [test_cache_delete.html]
 [test_cache_put_reorder.html]
 [test_cache_https.html]
   skip-if = buildapp == 'b2g' # bug 1162353
 [test_cache_restart.html]
--- a/dom/canvas/test/crossorigin/mochitest.ini
+++ b/dom/canvas/test/crossorigin/mochitest.ini
@@ -1,10 +1,9 @@
 [DEFAULT]
-skip-if = e10s && debug && os == 'mac' # Bug 1252348
 support-files =
   image-allow-credentials.png
   image-allow-credentials.png^headers^
   image-allow-star.png
   image-allow-star.png^headers^
   image.png
   video.sjs
 
--- a/dom/events/NotifyPaintEvent.cpp
+++ b/dom/events/NotifyPaintEvent.cpp
@@ -14,25 +14,28 @@
 
 namespace mozilla {
 namespace dom {
 
 NotifyPaintEvent::NotifyPaintEvent(EventTarget* aOwner,
                                    nsPresContext* aPresContext,
                                    WidgetEvent* aEvent,
                                    EventMessage aEventMessage,
-                                   nsInvalidateRequestList* aInvalidateRequests)
+                                   nsInvalidateRequestList* aInvalidateRequests,
+                                   uint64_t aTransactionId)
   : Event(aOwner, aPresContext, aEvent)
 {
   if (mEvent) {
     mEvent->mMessage = aEventMessage;
   }
   if (aInvalidateRequests) {
     mInvalidateRequests.AppendElements(Move(aInvalidateRequests->mRequests));
   }
+
+  mTransactionId = aTransactionId;
 }
 
 NS_INTERFACE_MAP_BEGIN(NotifyPaintEvent)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNotifyPaintEvent)
 NS_INTERFACE_MAP_END_INHERITING(Event)
 
 NS_IMPL_ADDREF_INHERITED(NotifyPaintEvent, Event)
 NS_IMPL_RELEASE_INHERITED(NotifyPaintEvent, Event)
@@ -149,26 +152,40 @@ NotifyPaintEvent::Deserialize(const IPC:
     NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &req.mRect), false);
     NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &req.mFlags), false);
     mInvalidateRequests.AppendElement(req);
   }
 
   return true;
 }
 
+NS_IMETHODIMP
+NotifyPaintEvent::GetTransactionId(uint64_t* aTransactionId)
+{
+  *aTransactionId = mTransactionId;
+  return NS_OK;
+}
+
+uint64_t
+NotifyPaintEvent::TransactionId()
+{
+  return mTransactionId;
+}
+
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 already_AddRefed<NotifyPaintEvent>
 NS_NewDOMNotifyPaintEvent(EventTarget* aOwner,
                           nsPresContext* aPresContext,
                           WidgetEvent* aEvent,
                           EventMessage aEventMessage,
-                          nsInvalidateRequestList* aInvalidateRequests) 
+                          nsInvalidateRequestList* aInvalidateRequests,
+                          uint64_t aTransactionId)
 {
   RefPtr<NotifyPaintEvent> it =
     new NotifyPaintEvent(aOwner, aPresContext, aEvent, aEventMessage,
-                         aInvalidateRequests);
+                         aInvalidateRequests, aTransactionId);
   return it.forget();
 }
--- a/dom/events/NotifyPaintEvent.h
+++ b/dom/events/NotifyPaintEvent.h
@@ -24,17 +24,18 @@ class NotifyPaintEvent : public Event,
                          public nsIDOMNotifyPaintEvent
 {
 
 public:
   NotifyPaintEvent(EventTarget* aOwner,
                    nsPresContext* aPresContext,
                    WidgetEvent* aEvent,
                    EventMessage aEventMessage,
-                   nsInvalidateRequestList* aInvalidateRequests);
+                   nsInvalidateRequestList* aInvalidateRequests,
+                   uint64_t aTransactionId);
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMNOTIFYPAINTEVENT
 
   // Forward to base class
   NS_FORWARD_TO_EVENT_NO_SERIALIZATION_NO_DUPLICATION
   NS_IMETHOD DuplicatePrivateData() override
@@ -50,31 +51,35 @@ public:
   }
 
   already_AddRefed<DOMRectList> ClientRects();
 
   already_AddRefed<DOMRect> BoundingClientRect();
 
   already_AddRefed<PaintRequestList> PaintRequests();
 
+  uint64_t TransactionId();
+
 protected:
   ~NotifyPaintEvent() {}
 
 private:
   nsRegion GetRegion();
 
   nsTArray<nsInvalidateRequestList::Request> mInvalidateRequests;
+  uint64_t mTransactionId;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 // This empties aInvalidateRequests.
 already_AddRefed<mozilla::dom::NotifyPaintEvent>
 NS_NewDOMNotifyPaintEvent(mozilla::dom::EventTarget* aOwner,
                           nsPresContext* aPresContext,
                           mozilla::WidgetEvent* aEvent,
                           mozilla::EventMessage aEventMessage =
                             mozilla::eVoidEvent,
                           nsInvalidateRequestList* aInvalidateRequests =
-                            nullptr);
+                            nullptr,
+                          uint64_t aTransactionId = 0);
 
 #endif // mozilla_dom_NotifyPaintEvent_h_
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -591,17 +591,17 @@ support-files = file_cookiemanager.js
 [test_bug765780.html]
 [test_bug871161.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 support-files = file_bug871161-1.html file_bug871161-2.html
 [test_bug1013316.html]
 [test_hash_encoded.html]
 [test_bug1081037.html]
 [test_window_open_close.html]
-skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # bug 1129014
+skip-if = buildapp == 'b2g' # bug 1129014
 [test_img_complete.html]
 [test_viewport_resize.html]
 [test_image_clone_load.html]
 [test_bug1203668.html]
 [test_bug1166138.html]
 [test_bug1230665.html]
 [test_filepicker_default_directory.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -102,16 +102,21 @@ interface nsIDOMWindowUtils : nsISupport
   unsigned long redraw([optional] in unsigned long aCount);
 
   /**
    * Force a synchronous layer transaction for this window if necessary.
    */
   void updateLayerTree();
 
   /**
+   * Get the last used layer transaction id for this window's refresh driver.
+   */
+  readonly attribute unsigned long long lastTransactionId;
+
+  /**
    * Information retrieved from the <meta name="viewport"> tag.
    * See nsContentUtils::GetViewportInfo for more information.
    */
   void getViewportInfo(in uint32_t aDisplayWidth, in uint32_t aDisplayHeight,
                        out double aDefaultZoom, out boolean aAllowZoom,
                        out double aMinZoom, out double aMaxZoom,
                        out uint32_t aWidth, out uint32_t aHeight,
                        out boolean aAutoSize);
--- a/dom/interfaces/base/nsITabChild.idl
+++ b/dom/interfaces/base/nsITabChild.idl
@@ -14,15 +14,17 @@ native CommandsArray(nsTArray<nsCString>
 interface nsITabChild : nsISupports
 {
   readonly attribute nsIContentFrameMessageManager messageManager;
 
   attribute nsIWebBrowserChrome3 webBrowserChrome;
 
   [notxpcom] void sendRequestFocus(in boolean canFocus);
 
+  [notxpcom] void sendGetTabCount(out uint32_t tabCount);
+
   [noscript, notxpcom] void enableDisableCommands(in AString action,
                                                   in CommandsArrayRef enabledCommands,
                                                   in CommandsArrayRef disabledCommands);
 
   readonly attribute uint64_t tabId;
 };
 
--- a/dom/interfaces/events/nsIDOMNotifyPaintEvent.idl
+++ b/dom/interfaces/events/nsIDOMNotifyPaintEvent.idl
@@ -30,10 +30,12 @@ interface nsIDOMNotifyPaintEvent : nsISu
    * is in CSS pixels relative to the viewport origin.
    * If the caller is not trusted (e.g., regular Web content) then only painting
    * caused by the current document is reported; in particular, painting in subdocuments
    * is not reported.
    */
   readonly attribute nsIDOMClientRect boundingClientRect;
 
   readonly attribute nsISupports /* PaintRequestList */ paintRequests;
+
+  readonly attribute unsigned long long transactionId;
 };
 
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -369,17 +369,17 @@ parent:
      * Nowadays this is mainly used for link locations on hover.
      */
     async SetStatus(uint32_t type, nsString status);
 
     /**
      * Show/hide a tooltip when the mouse hovers over an element in the content
      * document.
      */
-    async ShowTooltip(uint32_t x, uint32_t y, nsString tooltip);
+    async ShowTooltip(uint32_t x, uint32_t y, nsString tooltip, nsString direction);
     async HideTooltip();
 
     /**
      * Create an asynchronous color picker on the parent side,
      * but don't open it yet.
      */
     async PColorPicker(nsString title, nsString initialColor);
 
@@ -465,16 +465,18 @@ parent:
                                      ScreenIntPoint aPointerScreenPoint,
                                      double aPointerPressure,
                                      uint32_t aPointerOrientation,
                                      uint64_t aObserverId);
     async SynthesizeNativeTouchTap(ScreenIntPoint aPointerScreenPoint,
                                    bool aLongTap,
                                    uint64_t aObserverId);
     async ClearNativeTouchSequence(uint64_t aObserverId);
+
+    sync GetTabCount() returns (uint32_t value);
 child:
     async NativeSynthesisResponse(uint64_t aObserverId, nsCString aResponse);
 
 
 parent:
 
     /**
      * Child informs the parent that the graphics objects are ready for
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2723,16 +2723,22 @@ TabChild::SetWebBrowserChrome(nsIWebBrow
 
 void
 TabChild::SendRequestFocus(bool aCanFocus)
 {
   PBrowserChild::SendRequestFocus(aCanFocus);
 }
 
 void
+TabChild::SendGetTabCount(uint32_t* tabCount)
+{
+  PBrowserChild::SendGetTabCount(tabCount);
+}
+
+void
 TabChild::EnableDisableCommands(const nsAString& aAction,
                                 nsTArray<nsCString>& aEnabledCommands,
                                 nsTArray<nsCString>& aDisabledCommands)
 {
   PBrowserChild::SendEnableDisableCommands(PromiseFlatString(aAction),
                                            aEnabledCommands, aDisabledCommands);
 }
 
@@ -2889,20 +2895,22 @@ TabChild::CompositorUpdated(const Textur
   ClientLayerManager* clm = lm->AsClientLayerManager();
 
   mTextureFactoryIdentifier = aNewIdentifier;
   clm->UpdateTextureFactoryIdentifier(aNewIdentifier);
   FrameLayerBuilder::InvalidateAllLayers(clm);
 }
 
 NS_IMETHODIMP
-TabChild::OnShowTooltip(int32_t aXCoords, int32_t aYCoords, const char16_t *aTipText)
+TabChild::OnShowTooltip(int32_t aXCoords, int32_t aYCoords, const char16_t *aTipText,
+                        const char16_t *aTipDir)
 {
     nsString str(aTipText);
-    SendShowTooltip(aXCoords, aYCoords, str);
+    nsString dir(aTipDir);
+    SendShowTooltip(aXCoords, aYCoords, str, dir);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 TabChild::OnHideTooltip()
 {
     SendHideTooltip();
     return NS_OK;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1742,24 +1742,25 @@ TabParent::RecvSetStatus(const uint32_t&
    case nsIWebBrowserChrome::STATUS_LINK:
     xulBrowserWindow->SetOverLink(aStatus, nullptr);
     break;
   }
   return true;
 }
 
 bool
-TabParent::RecvShowTooltip(const uint32_t& aX, const uint32_t& aY, const nsString& aTooltip)
+TabParent::RecvShowTooltip(const uint32_t& aX, const uint32_t& aY, const nsString& aTooltip,
+                           const nsString& aDirection)
 {
   nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow = GetXULBrowserWindow();
   if (!xulBrowserWindow) {
     return true;
   }
 
-  xulBrowserWindow->ShowTooltip(aX, aY, aTooltip);
+  xulBrowserWindow->ShowTooltip(aX, aY, aTooltip, aDirection);
   return true;
 }
 
 bool
 TabParent::RecvHideTooltip()
 {
   nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow = GetXULBrowserWindow();
   if (!xulBrowserWindow) {
@@ -3238,16 +3239,30 @@ TabParent::AudioChannelChangeNotificatio
     if (window == win) {
       break;
     }
 
     window = win;
   }
 }
 
+bool
+TabParent::RecvGetTabCount(uint32_t* aValue)
+{
+  nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow = GetXULBrowserWindow();
+  NS_ENSURE_TRUE(xulBrowserWindow, false);
+
+  uint32_t tabCount;
+  nsresult rv = xulBrowserWindow->GetTabCount(&tabCount);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  *aValue = tabCount;
+  return true;
+}
+
 NS_IMETHODIMP
 FakeChannel::OnAuthAvailable(nsISupports *aContext, nsIAuthInformation *aAuthInfo)
 {
   nsAuthInformationHolder* holder =
     static_cast<nsAuthInformationHolder*>(aAuthInfo);
 
   if (!net::gNeckoChild->SendOnAuthAvailable(mCallbackId,
                                              holder->User(),
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -276,17 +276,18 @@ public:
 
   virtual bool RecvSetStatus(const uint32_t& aType,
                              const nsString& aStatus) override;
 
   virtual bool RecvIsParentWindowMainWidgetVisible(bool* aIsVisible) override;
 
   virtual bool RecvShowTooltip(const uint32_t& aX,
                                const uint32_t& aY,
-                               const nsString& aTooltip) override;
+                               const nsString& aTooltip,
+                               const nsString& aDirection) override;
 
   virtual bool RecvHideTooltip() override;
 
   virtual bool RecvGetDPI(float* aValue) override;
 
   virtual bool RecvGetDefaultScale(double* aValue) override;
 
   virtual bool RecvGetMaxTouchPoints(uint32_t* aTouchPoints) override;
@@ -576,16 +577,18 @@ protected:
   virtual bool DeallocPRenderFrameParent(PRenderFrameParent* aFrame) override;
 
   virtual bool RecvRemotePaintIsReady() override;
 
   virtual bool RecvSetDimensions(const uint32_t& aFlags,
                                  const int32_t& aX, const int32_t& aY,
                                  const int32_t& aCx, const int32_t& aCy) override;
 
+  virtual bool RecvGetTabCount(uint32_t* aValue) override;
+
   virtual bool RecvAudioChannelActivityNotification(const uint32_t& aAudioChannel,
                                                     const bool& aActive) override;
 
   bool InitBrowserConfiguration(const nsCString& aURI,
                                 BrowserConfiguration& aConfiguration);
 
   ContentCacheInParent mContentCache;
 
--- a/dom/locales/en-US/chrome/plugins.properties
+++ b/dom/locales/en-US/chrome/plugins.properties
@@ -18,17 +18,17 @@ state_enabled=Enabled
 state_disabled=Disabled
 mimetype_label=MIME Type
 description_label=Description
 suffixes_label=Suffixes
 learn_more_label=Learn More
 
 # GMP Plugins
 gmp_license_info=License information
+gmp_privacy_info=Privacy Information
 
 openH264_name=OpenH264 Video Codec provided by Cisco Systems, Inc.
 openH264_description2=This plugin is automatically installed by Mozilla to comply with the WebRTC specification and to enable WebRTC calls with devices that require the H.264 video codec. Visit http://www.openh264.org/ to view the codec source code and learn more about the implementation.
 
 eme-adobe_name=Primetime Content Decryption Module provided by Adobe Systems, Incorporated
 eme-adobe_description=Play back protected web video.
 
-widevine_name=WidevineCdm
 widevine_description=Widevine Content Decryption Module provided by Google Inc.
--- a/dom/media/DOMMediaStream.cpp
+++ b/dom/media/DOMMediaStream.cpp
@@ -1406,17 +1406,16 @@ DOMHwMediaStream::Init(MediaStream* stre
 
     RefPtr<Image> image = static_cast<Image*>(mOverlayImage.get());
     mozilla::gfx::IntSize size = image->GetSize();
 
     segment.AppendFrame(image.forget(), delta, size, mPrincipalHandle);
 #endif
     srcStream->AddTrack(TRACK_VIDEO_PRIMARY, 0, new VideoSegment());
     srcStream->AppendToTrack(TRACK_VIDEO_PRIMARY, &segment);
-    srcStream->FinishAddTracks();
     srcStream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
   }
 }
 
 int32_t
 DOMHwMediaStream::RequestOverlayId()
 {
 #ifdef MOZ_WIDGET_GONK
--- a/dom/media/MediaSegment.h
+++ b/dom/media/MediaSegment.h
@@ -66,17 +66,17 @@ typedef nsMainThreadPtrHandle<nsIPrincip
 
 inline PrincipalHandle MakePrincipalHandle(nsIPrincipal* aPrincipal)
 {
   RefPtr<nsMainThreadPtrHolder<nsIPrincipal>> holder =
     new nsMainThreadPtrHolder<nsIPrincipal>(aPrincipal);
   return PrincipalHandle(holder);
 }
 
-const PrincipalHandle PRINCIPAL_HANDLE_NONE(nullptr);
+#define PRINCIPAL_HANDLE_NONE nullptr
 
 inline nsIPrincipal* GetPrincipalFromHandle(PrincipalHandle& aPrincipalHandle)
 {
   MOZ_ASSERT(NS_IsMainThread());
   return aPrincipalHandle.get();
 }
 
 inline bool PrincipalHandleMatches(PrincipalHandle& aPrincipalHandle,
--- a/dom/media/platforms/android/AndroidDecoderModule.cpp
+++ b/dom/media/platforms/android/AndroidDecoderModule.cpp
@@ -300,19 +300,22 @@ already_AddRefed<MediaDataDecoder>
 AndroidDecoderModule::CreateAudioDecoder(
     const AudioInfo& aConfig, FlushableTaskQueue* aAudioTaskQueue,
     MediaDataDecoderCallback* aCallback)
 {
   MOZ_ASSERT(aConfig.mBitDepth == 16, "We only handle 16-bit audio!");
 
   MediaFormat::LocalRef format;
 
+  LOG("CreateAudioFormat with mimeType=%s, mRate=%d, channels=%d",
+      aConfig.mMimeType.Data(), aConfig.mRate, aConfig.mChannels);
+
   NS_ENSURE_SUCCESS(MediaFormat::CreateAudioFormat(
       aConfig.mMimeType,
-      aConfig.mBitDepth,
+      aConfig.mRate,
       aConfig.mChannels,
       &format), nullptr);
 
   RefPtr<MediaDataDecoder> decoder =
     new AudioDataDecoder(aConfig, format, aCallback);
 
   return decoder.forget();
 }
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -838,20 +838,17 @@ tags=msg capturestream
 [test_unseekable.html]
 skip-if = toolkit == 'gonk' # bug 1128845 on gonk
 [test_video_to_canvas.html]
 [test_video_in_audio_element.html]
 [test_videoDocumentTitle.html]
 [test_VideoPlaybackQuality.html]
 [test_VideoPlaybackQuality_disabled.html]
 [test_volume.html]
-skip-if = e10s && debug && os == 'win' # bug 1245574
 [test_vttparser.html]
-skip-if = e10s && debug && os == 'win'
 [test_webvtt_disabled.html]
-skip-if = e10s && debug && os == 'win'
 
 # The tests below contain backend-specific tests. Write backend independent
 # tests rather than adding to this list.
 [test_can_play_type_webm.html]
 [test_can_play_type_wave.html]
 [test_fragment_noplay.html]
 [test_fragment_play.html]
--- a/dom/media/webspeech/recognition/test/mochitest.ini
+++ b/dom/media/webspeech/recognition/test/mochitest.ini
@@ -1,11 +1,11 @@
 [DEFAULT]
 tags=msg
-skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1191270, bug 1037287, bug 967606, bug 1096400, bug 1238542 etc
+skip-if = buildapp == 'b2g' # Bug 1191270, bug 1037287, bug 967606, bug 1096400 etc
 subsuite = media
 support-files =
   head.js
   hello.ogg
   hello.ogg^headers^
   silence.ogg
   silence.ogg^headers^
 [test_abort.html]
@@ -15,9 +15,8 @@ skip-if = toolkit == 'android' # bug 103
 tags=capturestream
 skip-if = (android_version == '18' && debug) # bug 967606
 [test_nested_eventloop.html]
 skip-if = buildapp == 'mulet' || toolkit == 'android'
 [test_preference_enable.html]
 [test_recognition_service_error.html]
 [test_success_without_recognition_service.html]
 [test_timeout.html]
-skip-if = os == "win"
--- a/dom/plugins/ipc/PluginProcessParent.cpp
+++ b/dom/plugins/ipc/PluginProcessParent.cpp
@@ -91,31 +91,39 @@ AddSandboxAllowedFiles(int32_t aSandboxL
     // Higher than level 2 currently removes the users own rights.
     if (aSandboxLevel > 2) {
         AddSandboxAllowedFile(aAllowedFilesRead, dirSvc, NS_WIN_HOME_DIR);
         AddSandboxAllowedFile(aAllowedFilesRead, dirSvc, NS_WIN_HOME_DIR,
                               NS_LITERAL_STRING("\\*"));
     }
 
     // Level 2 and above is now using low integrity, so we need to give write
-    // access to the Flash directories. Access also has to be given to create
-    // the parent directories as they may not exist.
+    // access to the Flash directories.
     // This should be made Flash specific (Bug 1171396).
     AddSandboxAllowedFile(aAllowedFilesReadWrite, dirSvc, NS_WIN_APPDATA_DIR,
                           NS_LITERAL_STRING("\\Macromedia\\Flash Player\\*"));
-    AddSandboxAllowedFile(aAllowedDirectories, dirSvc, NS_WIN_APPDATA_DIR,
-                          NS_LITERAL_STRING("\\Macromedia\\Flash Player"));
+    AddSandboxAllowedFile(aAllowedFilesReadWrite, dirSvc, NS_WIN_LOCAL_APPDATA_DIR,
+                          NS_LITERAL_STRING("\\Macromedia\\Flash Player\\*"));
+    AddSandboxAllowedFile(aAllowedFilesReadWrite, dirSvc, NS_WIN_APPDATA_DIR,
+                          NS_LITERAL_STRING("\\Adobe\\Flash Player\\*"));
+
+    // Access also has to be given to create the parent directories as they may
+    // not exist.
     AddSandboxAllowedFile(aAllowedDirectories, dirSvc, NS_WIN_APPDATA_DIR,
                           NS_LITERAL_STRING("\\Macromedia"));
-    AddSandboxAllowedFile(aAllowedFilesReadWrite, dirSvc, NS_WIN_APPDATA_DIR,
-                          NS_LITERAL_STRING("\\Adobe\\Flash Player\\*"));
+    AddSandboxAllowedFile(aAllowedDirectories, dirSvc, NS_WIN_APPDATA_DIR,
+                          NS_LITERAL_STRING("\\Macromedia\\Flash Player"));
+    AddSandboxAllowedFile(aAllowedDirectories, dirSvc, NS_WIN_LOCAL_APPDATA_DIR,
+                          NS_LITERAL_STRING("\\Macromedia"));
+    AddSandboxAllowedFile(aAllowedDirectories, dirSvc, NS_WIN_LOCAL_APPDATA_DIR,
+                          NS_LITERAL_STRING("\\Macromedia\\Flash Player"));
+    AddSandboxAllowedFile(aAllowedDirectories, dirSvc, NS_WIN_APPDATA_DIR,
+                          NS_LITERAL_STRING("\\Adobe"));
     AddSandboxAllowedFile(aAllowedDirectories, dirSvc, NS_WIN_APPDATA_DIR,
                           NS_LITERAL_STRING("\\Adobe\\Flash Player"));
-    AddSandboxAllowedFile(aAllowedDirectories, dirSvc, NS_WIN_APPDATA_DIR,
-                          NS_LITERAL_STRING("\\Adobe"));
 
     // Write access to the Temp directory is needed in some mochitest crash
     // tests.
     // Bug 1171393 tracks removing this requirement.
     AddSandboxAllowedFile(aAllowedFilesReadWrite, dirSvc, NS_OS_TEMP_DIR,
                           NS_LITERAL_STRING("\\*"));
 }
 #endif
--- a/dom/tests/mochitest/fetch/mochitest.ini
+++ b/dom/tests/mochitest/fetch/mochitest.ini
@@ -28,43 +28,36 @@ support-files =
   !/dom/base/test/responseIdentical.sjs
   !/dom/html/test/form_submit_server.sjs
   !/dom/security/test/cors/file_CrossSiteXHR_server.sjs
 
 [test_headers.html]
 [test_headers_sw_reroute.html]
 skip-if = buildapp == 'b2g' # Bug 1137683
 [test_headers_mainthread.html]
-skip-if = (e10s && debug && os == 'win')
 [test_fetch_app_protocol.html]
 skip-if = (buildapp != 'b2g' && buildapp != 'mulet')
 [test_fetch_basic.html]
-skip-if = (e10s && debug && os == 'win')
 [test_fetch_basic_sw_reroute.html]
-skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683
+skip-if = buildapp == 'b2g' # Bug 1137683
 [test_fetch_basic_sw_empty_reroute.html]
 skip-if = buildapp == 'b2g'
 [test_fetch_basic_http.html]
-skip-if = (e10s && debug && os == 'win')
 [test_fetch_basic_http_sw_reroute.html]
-skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683
+skip-if = buildapp == 'b2g' # Bug 1137683
 [test_fetch_basic_http_sw_empty_reroute.html]
 skip-if = buildapp == 'b2g'
 [test_fetch_cors.html]
-skip-if = buildapp == 'b2g' || (toolkit == 'android' && debug) || (e10s && debug && os == 'win') # Bug 1210552 && 1210282
+skip-if = buildapp == 'b2g' || (toolkit == 'android' && debug) # Bug 1210552 && 1210282
 [test_fetch_cors_sw_reroute.html]
-skip-if = buildapp == 'b2g' || (toolkit == 'android' && debug) || (e10s && debug && os == 'win') # Bug 1137683 && 1210282
+skip-if = buildapp == 'b2g' || (toolkit == 'android' && debug) # Bug 1137683 && 1210282
 [test_fetch_cors_sw_empty_reroute.html]
 skip-if = buildapp == 'b2g' || (toolkit == 'android' && debug) # Bug 1210282
 [test_formdataparsing.html]
-skip-if = (e10s && debug && os == 'win')
 [test_formdataparsing_sw_reroute.html]
-skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683
+skip-if = buildapp == 'b2g' # Bug 1137683
 [test_request.html]
-skip-if = (e10s && debug && os == 'win')
 [test_request_context.html]
-skip-if = (e10s && debug && os == 'win')
 [test_request_sw_reroute.html]
-skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683
+skip-if = buildapp == 'b2g' # Bug 1137683
 [test_response.html]
-skip-if = (e10s && debug && os == 'win')
 [test_response_sw_reroute.html]
-skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683
+skip-if = buildapp == 'b2g' # Bug 1137683
--- a/dom/webidl/NotifyPaintEvent.webidl
+++ b/dom/webidl/NotifyPaintEvent.webidl
@@ -8,9 +8,11 @@
 
 interface NotifyPaintEvent : Event
 {
   readonly attribute DOMRectList clientRects;
 
   readonly attribute DOMRect boundingClientRect;
 
   readonly attribute PaintRequestList paintRequests;
+
+  readonly attribute unsigned long long transactionId;
 };
--- a/dom/wifi/WifiProxyService.cpp
+++ b/dom/wifi/WifiProxyService.cpp
@@ -24,17 +24,17 @@ using namespace mozilla;
 using namespace mozilla::dom;
 
 namespace mozilla {
 
 // The singleton Wifi service, to be used on the main thread.
 static StaticRefPtr<WifiProxyService> gWifiProxyService;
 
 // The singleton supplicant class, that can be used on any thread.
-static nsAutoPtr<WpaSupplicant> gWpaSupplicant;
+static UniquePtr<WpaSupplicant> gWpaSupplicant;
 
 // Runnable used dispatch the WaitForEvent result on the main thread.
 class WifiEventDispatcher : public nsRunnable
 {
 public:
   WifiEventDispatcher(const nsAString& aEvent, const nsACString& aInterface)
     : mEvent(aEvent)
     , mInterface(aInterface)
@@ -155,17 +155,17 @@ WifiProxyService::FactoryCreate()
   }
 
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!gWifiProxyService) {
     gWifiProxyService = new WifiProxyService();
     ClearOnShutdown(&gWifiProxyService);
 
-    gWpaSupplicant = new WpaSupplicant();
+    gWpaSupplicant = MakeUnique<WpaSupplicant>();
     ClearOnShutdown(&gWpaSupplicant);
   }
 
   RefPtr<WifiProxyService> service = gWifiProxyService.get();
   return service.forget();
 }
 
 NS_IMETHODIMP
--- a/dom/wifi/WifiUtils.cpp
+++ b/dom/wifi/WifiUtils.cpp
@@ -382,23 +382,23 @@ public:
 // Concrete class to use to access the wpa supplicant.
 WpaSupplicant::WpaSupplicant()
 {
   char propVersion[PROPERTY_VALUE_MAX];
   property_get("ro.build.version.sdk", propVersion, "0");
   mSdkVersion = strtol(propVersion, nullptr, 10);
 
   if (mSdkVersion < 16) {
-    mImpl = new ICSWpaSupplicantImpl();
+    mImpl = MakeUnique<ICSWpaSupplicantImpl>();
   } else if (mSdkVersion < 19) {
-    mImpl = new JBWpaSupplicantImpl();
+    mImpl = MakeUnique<JBWpaSupplicantImpl>();
   } else {
-    mImpl = new KKWpaSupplicantImpl();
+    mImpl = MakeUnique<KKWpaSupplicantImpl>();
   }
-  mWifiHotspotUtils = new WifiHotspotUtils();
+  mWifiHotspotUtils = MakeUnique<WifiHotspotUtils>();
 };
 
 void WpaSupplicant::WaitForEvent(nsAString& aEvent, const nsCString& aInterface)
 {
   CHECK_HWLIB()
 
   char buffer[BUFFER_SIZE];
   int32_t ret = mImpl->do_wifi_wait_for_event(aInterface.get(), buffer, BUFFER_SIZE);
--- a/dom/wifi/WifiUtils.h
+++ b/dom/wifi/WifiUtils.h
@@ -8,18 +8,18 @@
  * Abstraction on top of the wifi support from libhardware_legacy that we
  * use to talk to the wpa_supplicant.
  */
 
 #ifndef WifiUtils_h
 #define WifiUtils_h
 
 #include "nsString.h"
-#include "nsAutoPtr.h"
 #include "mozilla/dom/WifiOptionsBinding.h"
+#include "mozilla/UniquePtr.h"
 #include "WifiHotspotUtils.h"
 
 // Needed to add a copy constructor to WifiCommandOptions.
 struct CommandOptions
 {
 public:
   CommandOptions(const mozilla::dom::WifiCommandOptions& aOther) {
 
@@ -46,17 +46,17 @@ public:
 };
 
 // Abstract class that exposes libhardware_legacy functions we need for
 // wifi management.
 // We use the ICS signatures here since they are likely more future-proof.
 class WpaSupplicantImpl
 {
 public:
-  // Suppress warning from nsAutoPtr
+  // Suppress warning from |UniquePtr|
   virtual ~WpaSupplicantImpl() {}
 
   virtual int32_t
   do_wifi_wait_for_event(const char *iface, char *buf, size_t len) = 0; // KK == ICS != JB
 
   virtual int32_t
   do_wifi_command(const char* iface, const char* cmd, char* buff, size_t* len) = 0; // KK == ICS != JB
 
@@ -89,18 +89,18 @@ public:
   // null-terminated so that we can pass it to c API without
   // conversion
   void WaitForEvent(nsAString& aEvent, const nsCString& aInterface);
   bool ExecuteCommand(CommandOptions aOptions,
                       mozilla::dom::WifiResultOptions& result,
                       const nsCString& aInterface);
 
 private:
-  nsAutoPtr<WpaSupplicantImpl> mImpl;
-  nsAutoPtr<WifiHotspotUtils> mWifiHotspotUtils;
+  UniquePtr<WpaSupplicantImpl> mImpl;
+  UniquePtr<WifiHotspotUtils> mWifiHotspotUtils;
 
   uint32_t mSdkVersion;
 
 protected:
   void CheckBuffer(char* buffer, int32_t length, nsAString& aEvent);
   uint32_t MakeMask(uint32_t len);
 };
 
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -238,25 +238,25 @@ skip-if = (toolkit == 'gonk' && debug) #
 [test_throwingOnerror.html]
 [test_timeoutTracing.html]
 [test_transferable.html]
 [test_url.html]
 [test_url_exceptions.html]
 [test_urlApi.html]
 [test_urlSearchParams.html]
 [test_websocket1.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || (e10s && debug && os == 'win') #bug 982828, bug 1237470
+skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 982828
 [test_websocket2.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || (e10s && debug && os == 'win') #bug 982828, bug 1237470
+skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 982828
 [test_websocket3.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || (e10s && debug && os == 'win') #bug 982828, bug 1237470
+skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 982828
 [test_websocket4.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || (e10s && debug && os == 'win') #bug 982828, bug 1237470
+skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 982828
 [test_websocket5.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || (e10s && debug && os == 'win') #bug 982828, bug 1237470
+skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 982828
 [test_websocket_basic.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 982828
 [test_websocket_https.html]
 skip-if = buildapp == 'b2g' # no https on b2g
 [test_websocket_loadgroup.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 982828
 [test_webSocket_sharedWorker.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 982828
--- a/embedding/browser/nsCTooltipTextProvider.h
+++ b/embedding/browser/nsCTooltipTextProvider.h
@@ -6,10 +6,12 @@
 
 #ifndef NSCTOOLTIPTEXTPROVIDER_H
 #define NSCTOOLTIPTEXTPROVIDER_H
 
 #include "nsITooltipTextProvider.h"
 
 #define NS_TOOLTIPTEXTPROVIDER_CONTRACTID \
   "@mozilla.org/embedcomp/tooltiptextprovider;1"
+#define NS_DEFAULTTOOLTIPTEXTPROVIDER_CONTRACTID \
+  "@mozilla.org/embedcomp/default-tooltiptextprovider;1"
 
 #endif
--- a/embedding/browser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/nsDocShellTreeOwner.cpp
@@ -1059,223 +1059,31 @@ nsDocShellTreeOwner::GetOwnerRequestor()
   if (mWebBrowserChromeWeak) {
     req = do_QueryReferent(mWebBrowserChromeWeak);
   } else if (mOwnerRequestor) {
     req = mOwnerRequestor;
   }
   return req.forget();
 }
 
-class DefaultTooltipTextProvider final : public nsITooltipTextProvider
-{
-public:
-  DefaultTooltipTextProvider();
-
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSITOOLTIPTEXTPROVIDER
-
-protected:
-  ~DefaultTooltipTextProvider() {}
-
-  nsCOMPtr<nsIAtom> mTag_dialogHeader;
-};
-
-NS_IMPL_ISUPPORTS(DefaultTooltipTextProvider, nsITooltipTextProvider)
-
-DefaultTooltipTextProvider::DefaultTooltipTextProvider()
-{
-  // There are certain element types which we don't want to use
-  // as tool tip text.
-  mTag_dialogHeader = NS_Atomize("dialogheader");
-}
-
-// A helper routine that determines whether we're still interested in SVG
-// titles. We need to stop at the SVG root element that has a document node
-// parent.
-static bool
-UseSVGTitle(nsIDOMElement* aCurrElement)
-{
-  nsCOMPtr<dom::Element> element(do_QueryInterface(aCurrElement));
-  if (!element || !element->IsSVGElement() || !element->GetParentNode()) {
-    return false;
-  }
-
-  return element->GetParentNode()->NodeType() != nsIDOMNode::DOCUMENT_NODE;
-}
-
-NS_IMETHODIMP
-DefaultTooltipTextProvider::GetNodeText(nsIDOMNode* aNode, char16_t** aText,
-                                        bool* aResult)
-{
-  NS_ENSURE_ARG_POINTER(aNode);
-  NS_ENSURE_ARG_POINTER(aText);
-
-  nsString outText;
-
-  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
-
-  bool lookingForSVGTitle = true;
-  bool found = false;
-  nsCOMPtr<nsIDOMNode> current(aNode);
-
-  // If the element implement the constraint validation API and has no title,
-  // show the validation message, if any.
-  nsCOMPtr<nsIConstraintValidation> cvElement = do_QueryInterface(current);
-  if (cvElement) {
-    nsCOMPtr<nsIContent> content = do_QueryInterface(cvElement);
-    nsCOMPtr<nsIAtom> titleAtom = NS_Atomize("title");
-
-    nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(content);
-    bool formHasNoValidate = false;
-    mozilla::dom::Element* form = formControl->GetFormElement();
-    if (form) {
-      nsCOMPtr<nsIAtom> noValidateAtom = NS_Atomize("novalidate");
-      formHasNoValidate = form->HasAttr(kNameSpaceID_None, noValidateAtom);
-    }
-
-    if (!content->HasAttr(kNameSpaceID_None, titleAtom) && !formHasNoValidate) {
-      cvElement->GetValidationMessage(outText);
-      found = !outText.IsEmpty();
-    }
-  }
-
-  while (!found && current) {
-    nsCOMPtr<nsIDOMElement> currElement(do_QueryInterface(current));
-    if (currElement) {
-      nsCOMPtr<nsIContent> content(do_QueryInterface(currElement));
-      if (content) {
-        if (!content->IsAnyOfXULElements(nsGkAtoms::dialog,
-                                         mTag_dialogHeader,
-                                         nsGkAtoms::window)) {
-          // first try the normal title attribute...
-          if (!content->IsSVGElement()) {
-            // If the element is an <input type="file"> without a title,
-            // we should show the current file selection.
-            if (content->IsHTMLElement(nsGkAtoms::input) &&
-                content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
-                                     NS_LITERAL_STRING("file"), eIgnoreCase) &&
-                !content->HasAttr(kNameSpaceID_None, nsGkAtoms::title)) {
-              found = true;
-              nsCOMPtr<nsIDOMFileList> fileList;
-              nsCOMPtr<nsIDOMHTMLInputElement> currInputElement(do_QueryInterface(currElement));
-              nsresult rv = currInputElement->GetFiles(getter_AddRefs(fileList));
-              NS_ENSURE_SUCCESS(rv, rv);
-              if (!fileList) {
-                return NS_ERROR_FAILURE;
-              }
-
-              nsCOMPtr<nsIStringBundleService> bundleService =
-                mozilla::services::GetStringBundleService();
-              if (!bundleService) {
-                return NS_ERROR_FAILURE;
-              }
-
-              nsCOMPtr<nsIStringBundle> bundle;
-              rv = bundleService->CreateBundle("chrome://global/locale/layout/HtmlForm.properties",
-                                                        getter_AddRefs(bundle));
-              NS_ENSURE_SUCCESS(rv, rv);
-              uint32_t listLength = 0;
-              rv = fileList->GetLength(&listLength);
-              NS_ENSURE_SUCCESS(rv, rv);
-              if (listLength == 0) {
-                if (content->HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
-                  rv = bundle->GetStringFromName(MOZ_UTF16("NoFilesSelected"),
-                                                 getter_Copies(outText));
-                } else {
-                  rv = bundle->GetStringFromName(MOZ_UTF16("NoFileSelected"),
-                                                 getter_Copies(outText));
-                }
-                NS_ENSURE_SUCCESS(rv, rv);
-              } else {
-                FileList* fl = static_cast<FileList*>(fileList.get());
-                fl->Item(0)->GetName(outText);
-
-                // For UX and performance (jank) reasons we cap the number of
-                // files that we list in the tooltip to 20 plus a "and xxx more"
-                // line, or to 21 if exactly 21 files were picked.
-                const uint32_t TRUNCATED_FILE_COUNT = 20;
-                uint32_t count = std::min(listLength, TRUNCATED_FILE_COUNT);
-                for (uint32_t i = 1; i < count; ++i) {
-                  nsString fileName;
-                  fl->Item(i)->GetName(fileName);
-                  outText.Append(NS_LITERAL_STRING("\n"));
-                  outText.Append(fileName);
-                }
-              }
-            } else if (NS_SUCCEEDED(currElement->GetAttribute(NS_LITERAL_STRING("title"), outText)) &&
-                       outText.Length()) {
-              found = true;
-            }
-          }
-          if (!found) {
-            // ...ok, that didn't work, try it in the XLink namespace
-            NS_NAMED_LITERAL_STRING(xlinkNS, "http://www.w3.org/1999/xlink");
-            nsCOMPtr<mozilla::dom::Link> linkContent(
-              do_QueryInterface(currElement));
-            if (linkContent) {
-              nsCOMPtr<nsIURI> uri(linkContent->GetURIExternal());
-              if (uri) {
-                currElement->GetAttributeNS(
-                  xlinkNS, NS_LITERAL_STRING("title"), outText);
-                if (outText.Length()) {
-                  found = true;
-                }
-              }
-            } else {
-              if (lookingForSVGTitle) {
-                lookingForSVGTitle = UseSVGTitle(currElement);
-              }
-              if (lookingForSVGTitle) {
-                nsINodeList* childNodes = content->ChildNodes();
-                uint32_t childNodeCount = childNodes->Length();
-                for (uint32_t i = 0; i < childNodeCount; i++) {
-                  nsIContent* child = childNodes->Item(i);
-                  if (child->IsSVGElement(nsGkAtoms::title)) {
-                    static_cast<dom::SVGTitleElement*>(child)->GetTextContent(outText);
-                    if (outText.Length()) {
-                      found = true;
-                    }
-                    break;
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-
-    // not found here, walk up to the parent and keep trying
-    if (!found) {
-      nsCOMPtr<nsIDOMNode> temp(current);
-      temp->GetParentNode(getter_AddRefs(current));
-    }
-  }
-
-  *aResult = found;
-  *aText = (found) ? ToNewUnicode(outText) : nullptr;
-
-  return NS_OK;
-}
-
 NS_IMPL_ISUPPORTS(ChromeTooltipListener, nsIDOMEventListener)
 
 ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser* aInBrowser,
                                              nsIWebBrowserChrome* aInChrome)
   : mWebBrowser(aInBrowser)
   , mWebBrowserChrome(aInChrome)
   , mTooltipListenerInstalled(false)
   , mMouseClientX(0)
   , mMouseClientY(0)
   , mShowingTooltip(false)
   , mTooltipShownOnce(false)
 {
   mTooltipTextProvider = do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID);
   if (!mTooltipTextProvider) {
-    mTooltipTextProvider = new DefaultTooltipTextProvider();
+    mTooltipTextProvider = do_GetService(NS_DEFAULTTOOLTIPTEXTPROVIDER_CONTRACTID);
   }
 }
 
 ChromeTooltipListener::~ChromeTooltipListener()
 {
 }
 
 // Hook up things to the chrome like context menus and tooltips, if the chrome
@@ -1455,26 +1263,28 @@ ChromeTooltipListener::MouseMove(nsIDOME
   }
 
   return NS_OK;
 }
 
 // Tell the registered chrome that they should show the tooltip.
 NS_IMETHODIMP
 ChromeTooltipListener::ShowTooltip(int32_t aInXCoords, int32_t aInYCoords,
-                                   const nsAString& aInTipText)
+                                   const nsAString& aInTipText,
+                                   const nsAString& aTipDir)
 {
   nsresult rv = NS_OK;
 
   // do the work to call the client
   nsCOMPtr<nsITooltipListener> tooltipListener(
     do_QueryInterface(mWebBrowserChrome));
   if (tooltipListener) {
     rv = tooltipListener->OnShowTooltip(aInXCoords, aInYCoords,
-                                        PromiseFlatString(aInTipText).get());
+                                        PromiseFlatString(aInTipText).get(),
+                                        PromiseFlatString(aTipDir).get());
     if (NS_SUCCEEDED(rv)) {
       mShowingTooltip = true;
     }
   }
 
   return rv;
 }
 
@@ -1553,35 +1363,38 @@ ChromeTooltipListener::sTooltipCallback(
       self->mPossibleTooltipNode = nullptr;
       return;
     }
 
     // if there is text associated with the node, show the tip and fire
     // off a timer to auto-hide it.
 
     nsXPIDLString tooltipText;
+    nsXPIDLString directionText;
     if (self->mTooltipTextProvider) {
       bool textFound = false;
 
       self->mTooltipTextProvider->GetNodeText(
-        self->mPossibleTooltipNode, getter_Copies(tooltipText), &textFound);
+        self->mPossibleTooltipNode, getter_Copies(tooltipText),
+        getter_Copies(directionText), &textFound);
 
       if (textFound) {
         nsString tipText(tooltipText);
+        nsString dirText(directionText);
         LayoutDeviceIntPoint screenDot = widget->WidgetToScreenOffset();
         double scaleFactor = 1.0;
         if (shell->GetPresContext()) {
           nsDeviceContext* dc = shell->GetPresContext()->DeviceContext();
           scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel()) /
                         dc->AppUnitsPerDevPixelAtUnitFullZoom();
         }
         // ShowTooltip expects widget-relative position.
         self->ShowTooltip(self->mMouseScreenX - screenDot.x / scaleFactor,
                           self->mMouseScreenY - screenDot.y / scaleFactor,
-                          tipText);
+                          tipText, dirText);
       }
     }
 
     // release tooltip target if there is one, NO MATTER WHAT
     self->mPossibleTooltipNode = nullptr;
   }
 }
 
--- a/embedding/browser/nsDocShellTreeOwner.h
+++ b/embedding/browser/nsDocShellTreeOwner.h
@@ -166,17 +166,18 @@ private:
     kTooltipAutoHideTime = 5000,    // ms
     kTooltipMouseMoveTolerance = 7  // pixel tolerance for mousemove event
   };
 
   NS_IMETHOD AddTooltipListener();
   NS_IMETHOD RemoveTooltipListener();
 
   NS_IMETHOD ShowTooltip(int32_t aInXCoords, int32_t aInYCoords,
-                         const nsAString& aInTipText);
+                         const nsAString& aInTipText,
+                         const nsAString& aDirText);
   NS_IMETHOD HideTooltip();
 
   nsWebBrowser* mWebBrowser;
   nsCOMPtr<mozilla::dom::EventTarget> mEventTarget;
   nsCOMPtr<nsITooltipTextProvider> mTooltipTextProvider;
 
   // This must be a strong ref in order to make sure we can hide the tooltip if
   // the window goes away while we're displaying one. If we don't hold a strong
--- a/embedding/browser/nsITooltipListener.idl
+++ b/embedding/browser/nsITooltipListener.idl
@@ -20,23 +20,25 @@ interface nsITooltipListener : nsISuppor
     /**
      * Called when a tooltip should be displayed.
      *
      * @param aXCoords The tooltip left edge X coordinate.
      * @param aYCoords The tooltip top edge Y coordinate.
      * @param aTipText The text to display in the tooltip, typically obtained
      *        from the TITLE attribute of the node (or containing parent)
      *        over which the pointer has been positioned.
+     * @param aTipDir  The direction (ltr or rtl) in which to display the text
      *
      * @note
      * Coordinates are specified in pixels, relative to the top-left
      * corner of the browser area.
      *
      * @return <code>NS_OK</code> if the tooltip was displayed.
      */
-    void onShowTooltip(in long aXCoords, in long aYCoords, in wstring aTipText);
+    void onShowTooltip(in long aXCoords, in long aYCoords, in wstring aTipText,
+                       in wstring aTipDir);
   
     /**
      * Called when the tooltip should be hidden, either because the pointer
      * has moved or the tooltip has timed out.
      */
     void onHideTooltip();
 };
--- a/embedding/browser/nsITooltipTextProvider.idl
+++ b/embedding/browser/nsITooltipTextProvider.idl
@@ -27,17 +27,18 @@ interface nsIDOMNode;
  * @see nsIDOMNode
  */
 [scriptable, uuid(b128a1e6-44f3-4331-8fbe-5af360ff21ee)]
 interface nsITooltipTextProvider : nsISupports
 {
     /**
      * Called to obtain the tooltip text for a node.
      *
-     * @arg aNode The node to obtain the text from.
-     * @arg aText The tooltip text.
+     * @arg aNode      The node to obtain the text from.
+     * @arg aText      The tooltip text.
+     * @arg aDirection The text direction (ltr or rtl) to use
      *
      * @return <CODE>PR_TRUE</CODE> if tooltip text is associated
      *         with the node and was returned in the aText argument;
      *         <CODE>PR_FALSE</CODE> otherwise.
      */
-    boolean getNodeText(in nsIDOMNode aNode, out wstring aText);
+    boolean getNodeText(in nsIDOMNode aNode, out wstring aText, out wstring aDirection);
 };
--- a/gfx/layers/TransactionIdAllocator.h
+++ b/gfx/layers/TransactionIdAllocator.h
@@ -24,16 +24,23 @@ public:
    * only be called while IsInRefresh().
    *
    * If too many id's are allocated without being returned then
    * the refresh driver will suspend until they catch up.
    */
   virtual uint64_t GetTransactionId() = 0;
 
   /**
+   * Return the transaction id that for the last non-revoked transaction.
+   * This allows the caller to tell whether a composite was triggered by
+   * a paint that occurred after a call to TransactionId().
+   */
+  virtual uint64_t LastTransactionId() const = 0;
+
+  /**
    * Notify that all work (including asynchronous composites)
    * for a given transaction id has been completed.
    *
    * If the refresh driver has been suspended because
    * of having too many outstanding id's, then this may
    * resume it.
    */
   virtual void NotifyTransactionCompleted(uint64_t aTransactionId) = 0;
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -414,21 +414,21 @@ ClientLayerManager::DidComposite(uint64_
 {
   MOZ_ASSERT(mWidget);
 
   // |aTransactionId| will be > 0 if the compositor is acknowledging a shadow
   // layers transaction.
   if (aTransactionId) {
     nsIWidgetListener *listener = mWidget->GetWidgetListener();
     if (listener) {
-      listener->DidCompositeWindow(aCompositeStart, aCompositeEnd);
+      listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd);
     }
     listener = mWidget->GetAttachedWidgetListener();
     if (listener) {
-      listener->DidCompositeWindow(aCompositeStart, aCompositeEnd);
+      listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd);
     }
     mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId);
   }
 
   // These observers fire whether or not we were in a transaction.
   for (size_t i = 0; i < mDidCompositeObservers.Length(); i++) {
     mDidCompositeObservers[i]->DidComposite();
   }
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -2572,36 +2572,16 @@ gfxFontGroup::GetEllipsisTextRun(int32_t
     }
     mCachedEllipsisTextRun = textRun;
     textRun->ReleaseFontGroup(); // don't let the presence of a cached ellipsis
                                  // textrun prolong the fontgroup's life
     return textRun;
 }
 
 already_AddRefed<gfxFont>
-gfxFontGroup::FindNonItalicFaceForChar(gfxFontFamily* aFamily, uint32_t aCh)
-{
-    NS_ASSERTION(mStyle.style != NS_FONT_STYLE_NORMAL,
-                 "should only be called in the italic/oblique case");
-
-    gfxFontStyle regularStyle = mStyle;
-    regularStyle.style = NS_FONT_STYLE_NORMAL;
-    bool needsBold;
-    gfxFontEntry *fe = aFamily->FindFontForStyle(regularStyle, needsBold);
-    NS_ASSERTION(!fe->mIsUserFontContainer,
-                 "should only be searching platform fonts");
-    if (!fe->HasCharacter(aCh)) {
-        return nullptr;
-    }
-
-    RefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, needsBold);
-    return font.forget();
-}
-
-already_AddRefed<gfxFont>
 gfxFontGroup::FindFallbackFaceForChar(gfxFontFamily* aFamily, uint32_t aCh,
                                       int32_t aRunScript)
 {
     GlobalFontMatch data(aCh, aRunScript, &mStyle);
     aFamily->SearchAllFontsForChar(&data);
     gfxFontEntry* fe = data.mBestMatch;
     if (!fe) {
         return nullptr;
@@ -2672,33 +2652,39 @@ gfxFontGroup::FindFontForChar(uint32_t a
     if (!isJoinControl && !wasJoinCauser && !isVarSelector) {
         RefPtr<gfxFont> firstFont = GetFontAt(0, aCh);
         if (firstFont) {
             if (firstFont->HasCharacter(aCh)) {
                 *aMatchType = gfxTextRange::kFontGroup;
                 return firstFont.forget();
             }
 
+            RefPtr<gfxFont> font;
             if (mFonts[0].CheckForFallbackFaces()) {
-                RefPtr<gfxFont> font =
-                    FindFallbackFaceForChar(mFonts[0].Family(), aCh, aRunScript);
-                if (font) {
-                    *aMatchType = gfxTextRange::kFontGroup;
-                    return font.forget();
+                font = FindFallbackFaceForChar(mFonts[0].Family(), aCh,
+                                               aRunScript);
+            } else if (!firstFont->GetFontEntry()->IsUserFont()) {
+                // For platform fonts (but not userfonts), we may need to do
+                // fallback within the family to handle cases where some faces
+                // such as Italic or Black have reduced character sets compared
+                // to the family's Regular face.
+                gfxFontEntry* fe = firstFont->GetFontEntry();
+                if (!fe->IsUpright() ||
+                    fe->Weight() != NS_FONT_WEIGHT_NORMAL ||
+                    fe->Stretch() != NS_FONT_STRETCH_NORMAL) {
+                    // If style/weight/stretch was not Normal, see if we can
+                    // fall back to a next-best face (e.g. Arial Black -> Bold,
+                    // or Arial Narrow -> Regular).
+                    font = FindFallbackFaceForChar(mFonts[0].Family(), aCh,
+                                                   aRunScript);
                 }
-            } else if (mStyle.style != NS_FONT_STYLE_NORMAL &&
-                       !firstFont->GetFontEntry()->IsUserFont()) {
-                // If italic, test the regular face to see if it supports
-                // character. Only do this for platform fonts, not userfonts.
-                RefPtr<gfxFont> font =
-                    FindNonItalicFaceForChar(mFonts[0].Family(), aCh);
-                if (font) {
-                    *aMatchType = gfxTextRange::kFontGroup;
-                    return font.forget();
-                }
+            }
+            if (font) {
+                *aMatchType = gfxTextRange::kFontGroup;
+                return font.forget();
             }
         }
 
         // we don't need to check the first font again below
         ++nextIndex;
     }
 
     if (aPrevMatchedFont) {
@@ -2794,23 +2780,25 @@ gfxFontGroup::FindFontForChar(uint32_t a
                          !mFonts[i-1].Family()->Name().Equals(ff.Family()->Name()),
                          "should only do fallback once per font family");
             font = FindFallbackFaceForChar(ff.Family(), aCh, aRunScript);
             if (font) {
                 *aMatchType = gfxTextRange::kFontGroup;
                 return font.forget();
             }
         } else {
-            // If italic, test the regular face to see if it supports the
-            // character. Only do this for platform fonts, not userfonts.
+            // For platform fonts, but not user fonts, consider intra-family
+            // fallback to handle styles with reduced character sets (see
+            // also above).
             fe = ff.FontEntry();
-            if (mStyle.style != NS_FONT_STYLE_NORMAL &&
-                !fe->mIsUserFontContainer &&
-                !fe->IsUserFont()) {
-                font = FindNonItalicFaceForChar(ff.Family(), aCh);
+            if (!fe->mIsUserFontContainer && !fe->IsUserFont() &&
+                (!fe->IsUpright() ||
+                 fe->Weight() != NS_FONT_WEIGHT_NORMAL ||
+                 fe->Stretch() != NS_FONT_STRETCH_NORMAL)) {
+                font = FindFallbackFaceForChar(ff.Family(), aCh, aRunScript);
                 if (font) {
                     *aMatchType = gfxTextRange::kFontGroup;
                     return font.forget();
                 }
             }
         }
     }
 
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -1137,22 +1137,16 @@ protected:
                        gfxTextRun *aTextRun,
                        const T *aString,
                        uint32_t aScriptRunStart,
                        uint32_t aScriptRunEnd,
                        int32_t aRunScript,
                        gfxMissingFontRecorder *aMFR);
 
     // Helper for font-matching:
-    // When matching the italic case, allow use of the regular face
-    // if it supports a character but the italic one doesn't.
-    // Return null if regular face doesn't support aCh
-    already_AddRefed<gfxFont>
-    FindNonItalicFaceForChar(gfxFontFamily* aFamily, uint32_t aCh);
-
     // search all faces in a family for a fallback in cases where it's unclear
     // whether the family might have a font for a given character
     already_AddRefed<gfxFont>
     FindFallbackFaceForChar(gfxFontFamily* aFamily, uint32_t aCh,
                             int32_t aRunScript);
 
    // helper methods for looking up fonts
 
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -1022,65 +1022,8 @@ function ArrayConcat(arg1) {
 }
 
 function ArrayStaticConcat(arr, arg1) {
     if (arguments.length < 1)
         ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.concat');
     var args = callFunction(std_Array_slice, arguments, 1);
     return callFunction(std_Function_apply, ArrayConcat, arr, args);
 }
-
-function ArrayStaticJoin(arr, separator) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.join');
-    return callFunction(std_Array_join, arr, separator);
-}
-
-function ArrayStaticReverse(arr) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.reverse');
-    return callFunction(std_Array_reverse, arr);
-}
-
-function ArrayStaticSort(arr, comparefn) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.sort');
-    return callFunction(std_Array_sort, arr, comparefn);
-}
-
-function ArrayStaticPush(arr, arg1) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.push');
-    var args = callFunction(std_Array_slice, arguments, 1);
-    return callFunction(std_Function_apply, std_Array_push, arr, args);
-}
-
-function ArrayStaticPop(arr) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.pop');
-    return callFunction(std_Array_pop, arr);
-}
-
-function ArrayStaticShift(arr) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.shift');
-    return callFunction(std_Array_shift, arr);
-}
-
-function ArrayStaticUnshift(arr, arg1) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.unshift');
-    var args = callFunction(std_Array_slice, arguments, 1);
-    return callFunction(std_Function_apply, std_Array_unshift, arr, args);
-}
-
-function ArrayStaticSplice(arr, start, deleteCount) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.splice');
-    var args = callFunction(std_Array_slice, arguments, 1);
-    return callFunction(std_Function_apply, std_Array_splice, arr, args);
-}
-
-function ArrayStaticSlice(arr, start, end) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.slice');
-    return callFunction(std_Array_slice, arr, start, end);
-}
--- a/js/src/builtin/String.js
+++ b/js/src/builtin/String.js
@@ -717,21 +717,17 @@ function String_static_raw(callSite, ...
  * Mozilla proprietary.
  * Spec: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String#String_generic_methods
  */
 function String_static_localeCompare(str1, str2) {
     if (arguments.length < 1)
         ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "String.localeCompare");
     var locales = arguments.length > 2 ? arguments[2] : undefined;
     var options = arguments.length > 3 ? arguments[3] : undefined;
-#if EXPOSE_INTL_API
     return callFunction(String_localeCompare, str1, str2, locales, options);
-#else
-    return callFunction(std_String_localeCompare, str1, str2, locales, options);
-#endif
 }
 
 // ES6 draft 2014-04-27 B.2.3.3
 function String_big() {
     RequireObjectCoercible(this);
     return "<big>" + ToString(this) + "</big>";
 }
 
@@ -823,113 +819,8 @@ function String_fontsize(size) {
 }
 
 // ES6 draft 2014-04-27 B.2.3.10
 function String_link(url) {
     RequireObjectCoercible(this);
     var S = ToString(this);
     return '<a href="' + EscapeAttributeValue(url) + '">' + S + "</a>";
 }
-
-function String_static_toLowerCase(string) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.toLowerCase');
-    return callFunction(std_String_toLowerCase, string);
-}
-
-function String_static_toUpperCase(string) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.toUpperCase');
-    return callFunction(std_String_toUpperCase, string);
-}
-
-function String_static_charAt(string, pos) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.charAt');
-    return callFunction(std_String_charAt, string, pos);
-}
-
-function String_static_charCodeAt(string, pos) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.charCodeAt');
-    return callFunction(std_String_charCodeAt, string, pos);
-}
-
-function String_static_includes(string, searchString) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.includes');
-    var position = arguments.length > 2 ? arguments[2] : undefined;
-    return callFunction(std_String_includes, string, searchString, position);
-}
-
-function String_static_indexOf(string, searchString) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.indexOf');
-    var position = arguments.length > 2 ? arguments[2] : undefined;
-    return callFunction(std_String_indexOf, string, searchString, position);
-}
-
-function String_static_lastIndexOf(string, searchString) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.lastIndexOf');
-    var position = arguments.length > 2 ? arguments[2] : undefined;
-    return callFunction(std_String_lastIndexOf, string, searchString, position);
-}
-
-function String_static_startsWith(string, searchString) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.startsWith');
-    var position = arguments.length > 2 ? arguments[2] : undefined;
-    return callFunction(std_String_startsWith, string, searchString, position);
-}
-
-function String_static_endsWith(string, searchString) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.endsWith');
-    var endPosition = arguments.length > 2 ? arguments[2] : undefined;
-    return callFunction(std_String_endsWith, string, searchString, endPosition);
-}
-
-function String_static_trim(string) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.trim');
-    return callFunction(std_String_trim, string);
-}
-
-function String_static_trimLeft(string) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.trimLeft');
-    return callFunction(std_String_trimLeft, string);
-}
-
-function String_static_trimRight(string) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.trimRight');
-    return callFunction(std_String_trimRight, string);
-}
-
-function String_static_toLocaleLowerCase(string) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.toLocaleLowerCase');
-    return callFunction(std_String_toLocaleLowerCase, string);
-}
-
-function String_static_toLocaleUpperCase(string) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.toLocaleUpperCase');
-    return callFunction(std_String_toLocaleUpperCase, string);
-}
-
-#if EXPOSE_INTL_API
-function String_static_normalize(string) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.normalize');
-    var form = arguments.length > 1 ? arguments[1] : undefined;
-    return callFunction(std_String_normalize, string, form);
-}
-#endif
-
-function String_static_concat(string, arg1) {
-    if (arguments.length < 1)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.concat');
-    var args = callFunction(std_Array_slice, arguments, 1);
-    return callFunction(std_Function_apply, std_String_concat, string, args);
-}
deleted file mode 100644
--- a/js/src/jit-test/tests/auto-regress/bug1263558.js
+++ /dev/null
@@ -1,16 +0,0 @@
-if (!('oomTest' in this))
-    quit();
-
-evalcx(`
-    eval('\
-        var appendToActual = function(s) {};\
-        gczeal = function() {};\
-        gcslice = function() {};\
-        selectforgc = function() {};\
-        if (!("verifyprebarriers" in this)) {\
-            verifyprebarriers = function() {};\
-        }\
-    ');
-    oomTest(() => eval('Array(..."")'));
-    Intl.NumberFormat.prototype.format(0);
-`, newGlobal());
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -1015,16 +1015,20 @@ IonScript::trace(JSTracer* trc)
     for (size_t i = 0; i < numConstants(); i++)
         TraceEdge(trc, &getConstant(i), "constant");
 
     // Mark all IC stub codes hanging off the IC stub entries.
     for (size_t i = 0; i < numSharedStubs(); i++) {
         ICEntry& ent = sharedStubList()[i];
         ent.trace(trc);
     }
+
+    // Trace caches so that the JSScript pointer can be updated if moved.
+    for (size_t i = 0; i < numCaches(); i++)
+        getCacheFromIndex(i).trace(trc);
 }
 
 /* static */ void
 IonScript::writeBarrierPre(Zone* zone, IonScript* ionScript)
 {
     if (zone->needsIncrementalBarrier())
         ionScript->trace(zone->barrierTracer());
 }
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -378,16 +378,22 @@ void
 IonCache::updateBaseAddress(JitCode* code, MacroAssembler& masm)
 {
     fallbackLabel_.repoint(code, &masm);
     initialJump_.repoint(code, &masm);
     lastJump_.repoint(code, &masm);
     rejoinLabel_.repoint(code, &masm);
 }
 
+void IonCache::trace(JSTracer* trc)
+{
+    if (script_)
+        TraceManuallyBarrieredEdge(trc, &script_, "IonCache::script_");
+}
+
 static void*
 GetReturnAddressToIonCode(JSContext* cx)
 {
     JitFrameIterator iter(cx);
     MOZ_ASSERT(iter.type() == JitFrame_Exit,
                "An exit frame is expected as update functions are called with a VMFunction.");
 
     void* returnAddr = iter.returnAddress();
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -336,16 +336,18 @@ class IonCache
         pscript.set(script_);
         *ppc = pc_;
     }
 
     jsbytecode* pc() const {
         MOZ_ASSERT(pc_);
         return pc_;
     }
+
+    void trace(JSTracer* trc);
 };
 
 // Define the cache kind and pre-declare data structures used for calling inline
 // caches.
 #define CACHE_HEADER(ickind)                                        \
     Kind kind() const {                                             \
         return IonCache::Cache_##ickind;                            \
     }                                                               \
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -832,17 +832,27 @@ class MOZ_STACK_CLASS SourceBufferHolder
 #define JSPROP_INTERNAL_USE_BIT 0x80    /* internal JS engine use only */
 //                             0x100    /* Unused */
 #define JSFUN_STUB_GSOPS       0x200    /* use JS_PropertyStub getter/setter
                                            instead of defaulting to class gsops
                                            for property holding function */
 
 #define JSFUN_CONSTRUCTOR      0x400    /* native that can be called as a ctor */
 
-//                             0x800    /* Unused */
+/*
+ * Specify a generic native prototype methods, i.e., methods of a class
+ * prototype that are exposed as static methods taking an extra leading
+ * argument: the generic |this| parameter.
+ *
+ * If you set this flag in a JSFunctionSpec struct's flags initializer, then
+ * that struct must live at least as long as the native static method object
+ * created due to this flag by JS_DefineFunctions or JS_InitClass.  Typically
+ * JSFunctionSpec structs are allocated in static arrays.
+ */
+#define JSFUN_GENERIC_NATIVE   0x800
 
 #define JSFUN_HAS_REST        0x1000    /* function has ...rest parameter. */
 
 #define JSFUN_FLAGS_MASK      0x1e00    /* | of all the JSFUN_* flags */
 
 /*
  * If set, will allow redefining a non-configurable property, but only on a
  * non-DOM global.  This is a temporary hack that will need to go away in bug
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1385,18 +1385,18 @@ ArrayReverseDenseKernel(JSContext* cx, H
     }
 
     return DenseElementResult::Success;
 }
 
 DefineBoxedOrUnboxedFunctor3(ArrayReverseDenseKernel,
                              JSContext*, HandleObject, uint32_t);
 
-bool
-js::array_reverse(JSContext* cx, unsigned argc, Value* vp)
+static bool
+array_reverse(JSContext* cx, unsigned argc, Value* vp)
 {
     AutoSPSEntry pseudoFrame(cx->runtime(), "Array.prototype.reverse");
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     uint32_t len;
@@ -2376,18 +2376,18 @@ CanOptimizeForDenseStorage(HandleObject 
      * other indexed properties on the object.  (Note that non-writable length
      * is subsumed by the initializedLength comparison.)
      */
     return !ObjectMayHaveExtraIndexedProperties(arr) &&
            startingIndex + count <= GetAnyBoxedOrUnboxedInitializedLength(arr);
 }
 
 /* ES 2016 draft Mar 25, 2016 22.1.3.26. */
-bool
-js::array_splice(JSContext* cx, unsigned argc, Value* vp)
+static bool
+array_splice(JSContext* cx, unsigned argc, Value* vp)
 {
     return array_splice_impl(cx, argc, vp, true);
 }
 
 static inline bool
 ArraySpliceCopy(JSContext* cx, HandleObject arr, HandleObject obj,
                 uint32_t actualStart, uint32_t actualDeleteCount)
 {
@@ -3077,36 +3077,38 @@ array_of(JSContext* cx, unsigned argc, V
     if (!SetLengthProperty(cx, obj, args.length()))
         return false;
 
     // Step 11.
     args.rval().setObject(*obj);
     return true;
 }
 
+#define GENERIC JSFUN_GENERIC_NATIVE
+
 static const JSFunctionSpec array_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,      array_toSource,     0,0),
 #endif
     JS_SELF_HOSTED_FN(js_toString_str, "ArrayToString",      0,0),
     JS_FN(js_toLocaleString_str,       array_toLocaleString, 0,0),
 
     /* Perl-ish methods. */
-    JS_INLINABLE_FN("join",     array_join,         1,0, ArrayJoin),
-    JS_FN("reverse",            array_reverse,      0,0),
-    JS_FN("sort",               array_sort,         1,0),
-    JS_INLINABLE_FN("push",     array_push,         1,0, ArrayPush),
-    JS_INLINABLE_FN("pop",      array_pop,          0,0, ArrayPop),
-    JS_INLINABLE_FN("shift",    array_shift,        0,0, ArrayShift),
-    JS_FN("unshift",            array_unshift,      1,0),
-    JS_INLINABLE_FN("splice",   array_splice,       2,0, ArraySplice),
+    JS_INLINABLE_FN("join",     array_join,         1,JSFUN_GENERIC_NATIVE, ArrayJoin),
+    JS_FN("reverse",            array_reverse,      0,JSFUN_GENERIC_NATIVE),
+    JS_FN("sort",               array_sort,         1,JSFUN_GENERIC_NATIVE),
+    JS_INLINABLE_FN("push",     array_push,         1,JSFUN_GENERIC_NATIVE, ArrayPush),
+    JS_INLINABLE_FN("pop",      array_pop,          0,JSFUN_GENERIC_NATIVE, ArrayPop),
+    JS_INLINABLE_FN("shift",    array_shift,        0,JSFUN_GENERIC_NATIVE, ArrayShift),
+    JS_FN("unshift",            array_unshift,      1,JSFUN_GENERIC_NATIVE),
+    JS_INLINABLE_FN("splice",   array_splice,       2,JSFUN_GENERIC_NATIVE, ArraySplice),
 
     /* Pythonic sequence methods. */
     JS_SELF_HOSTED_FN("concat",      "ArrayConcat",      1,0),
-    JS_INLINABLE_FN("slice",    array_slice,        2,0, ArraySlice),
+    JS_INLINABLE_FN("slice",    array_slice,        2,JSFUN_GENERIC_NATIVE, ArraySlice),
 
     JS_SELF_HOSTED_FN("lastIndexOf", "ArrayLastIndexOf", 1,0),
     JS_SELF_HOSTED_FN("indexOf",     "ArrayIndexOf",     1,0),
     JS_SELF_HOSTED_FN("forEach",     "ArrayForEach",     1,0),
     JS_SELF_HOSTED_FN("map",         "ArrayMap",         1,0),
     JS_SELF_HOSTED_FN("filter",      "ArrayFilter",      1,0),
     JS_SELF_HOSTED_FN("reduce",      "ArrayReduce",      1,0),
     JS_SELF_HOSTED_FN("reduceRight", "ArrayReduceRight", 1,0),
@@ -3137,25 +3139,16 @@ static const JSFunctionSpec array_static
     JS_SELF_HOSTED_FN("indexOf",     "ArrayStaticIndexOf", 2,0),
     JS_SELF_HOSTED_FN("forEach",     "ArrayStaticForEach", 2,0),
     JS_SELF_HOSTED_FN("map",         "ArrayStaticMap",   2,0),
     JS_SELF_HOSTED_FN("filter",      "ArrayStaticFilter", 2,0),
     JS_SELF_HOSTED_FN("every",       "ArrayStaticEvery", 2,0),
     JS_SELF_HOSTED_FN("some",        "ArrayStaticSome",  2,0),
     JS_SELF_HOSTED_FN("reduce",      "ArrayStaticReduce", 2,0),
     JS_SELF_HOSTED_FN("reduceRight", "ArrayStaticReduceRight", 2,0),
-    JS_SELF_HOSTED_FN("join",        "ArrayStaticJoin", 2,0),
-    JS_SELF_HOSTED_FN("reverse",     "ArrayStaticReverse", 1,0),
-    JS_SELF_HOSTED_FN("sort",        "ArrayStaticSort", 2,0),
-    JS_SELF_HOSTED_FN("push",        "ArrayStaticPush", 2,0),
-    JS_SELF_HOSTED_FN("pop",         "ArrayStaticPop", 1,0),
-    JS_SELF_HOSTED_FN("shift",       "ArrayStaticShift", 1,0),
-    JS_SELF_HOSTED_FN("unshift",     "ArrayStaticUnshift", 2,0),
-    JS_SELF_HOSTED_FN("splice",      "ArrayStaticSplice", 3,0),
-    JS_SELF_HOSTED_FN("slice",       "ArrayStaticSlice", 3,0),
     JS_SELF_HOSTED_FN("from",        "ArrayFrom", 3,0),
     JS_FN("of",                 array_of,           0,0),
 
     JS_FS_END
 };
 
 const JSPropertySpec array_static_props[] = {
     JS_SELF_HOSTED_SYM_GET(species, "ArraySpecies", 0),
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -179,22 +179,16 @@ extern bool
 array_unshift(JSContext* cx, unsigned argc, js::Value* vp);
 
 extern bool
 array_slice(JSContext* cx, unsigned argc, js::Value* vp);
 
 extern JSObject*
 array_slice_dense(JSContext* cx, HandleObject obj, int32_t begin, int32_t end, HandleObject result);
 
-extern bool
-array_reverse(JSContext* cx, unsigned argc, js::Value* vp);
-
-extern bool
-array_splice(JSContext* cx, unsigned argc, js::Value* vp);
-
 /*
  * Append the given (non-hole) value to the end of an array.  The array must be
  * a newborn array -- that is, one which has not been exposed to script for
  * arbitrary manipulation.  (This method optimizes on the assumption that
  * extending the array to accommodate the element will never make the array
  * sparse, which requires that the array be completely filled.)
  */
 extern bool
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2894,16 +2894,44 @@ js::HasDataProperty(JSContext* cx, Nativ
             *vp = obj->getSlot(shape->slot());
             return true;
         }
     }
 
     return false;
 }
 
+static bool
+GenericNativeMethodDispatcher(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    const JSFunctionSpec* fs = (JSFunctionSpec*)
+        args.callee().as<JSFunction>().getExtendedSlot(0).toPrivate();
+    MOZ_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
+
+    if (argc < 1) {
+        ReportMissingArg(cx, args.calleev(), 0);
+        return false;
+    }
+
+    /*
+     * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
+     * which is almost always the class constructor object, e.g. Array.  Then
+     * call the corresponding prototype native method with our first argument
+     * passed as |this|.
+     */
+    memmove(vp + 1, vp + 2, argc * sizeof(Value));
+
+    /* Clear the last parameter in case too few arguments were passed. */
+    vp[2 + --argc].setUndefined();
+
+    return fs->call.op(cx, argc, vp);
+}
+
 extern bool
 PropertySpecNameToId(JSContext* cx, const char* name, MutableHandleId id,
                      js::PinningBehavior pin = js::DoNotPinAtom);
 
 static bool
 DefineFunctionFromSpec(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, unsigned flags,
                        DefineAsIntrinsic intrinsic)
 {
@@ -2921,16 +2949,37 @@ DefineFunctionFromSpec(JSContext* cx, Ha
         MOZ_ASSERT(gop != JS_PropertyStub);
         MOZ_ASSERT(sop != JS_StrictPropertyStub);
     }
 
     RootedId id(cx);
     if (!PropertySpecNameToId(cx, fs->name, &id))
         return false;
 
+    // Define a generic arity N+1 static method for the arity N prototype
+    // method if flags contains JSFUN_GENERIC_NATIVE.
+    if (flags & JSFUN_GENERIC_NATIVE) {
+        // We require that any consumers using JSFUN_GENERIC_NATIVE stash
+        // the prototype and constructor in the global slots before invoking
+        // JS_DefineFunctions on the proto.
+        JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
+        MOZ_ASSERT(obj == &obj->global().getPrototype(key).toObject());
+        RootedObject ctor(cx, &obj->global().getConstructor(key).toObject());
+
+        flags &= ~JSFUN_GENERIC_NATIVE;
+        JSFunction* fun = DefineFunction(cx, ctor, id,
+                                         GenericNativeMethodDispatcher,
+                                         fs->nargs + 1, flags,
+                                         gc::AllocKind::FUNCTION_EXTENDED);
+        if (!fun)
+            return false;
+
+        fun->setExtendedSlot(0, PrivateValue(const_cast<JSFunctionSpec*>(fs)));
+    }
+
     JSFunction* fun = NewFunctionFromSpec(cx, fs, id);
     if (!fun)
         return false;
 
     if (intrinsic == AsIntrinsic)
         fun->setIsIntrinsic();
 
     RootedValue funVal(cx, ObjectValue(*fun));
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1933,34 +1933,32 @@ UncompressedSourceCache::sizeOfExcluding
     return n;
 }
 
 const char16_t*
 ScriptSource::chars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder)
 {
     struct CharsMatcher
     {
-        using ReturnType = const char16_t*;
-
         JSContext* cx;
         ScriptSource& ss;
         UncompressedSourceCache::AutoHoldEntry& holder;
 
         explicit CharsMatcher(JSContext* cx, ScriptSource& ss,
                               UncompressedSourceCache::AutoHoldEntry& holder)
           : cx(cx)
           , ss(ss)
           , holder(holder)
         { }
 
-        ReturnType match(Uncompressed& u) {
+        const char16_t* match(Uncompressed& u) {
             return u.chars;
         }
 
-        ReturnType match(Compressed& c) {
+        const char16_t* match(Compressed& c) {
             if (const char16_t* decompressed = cx->runtime()->uncompressedSourceCache.lookup(&ss, holder))
                 return decompressed;
 
             const size_t nbytes = sizeof(char16_t) * (ss.length() + 1);
             char16_t* decompressed = static_cast<char16_t*>(js_malloc(nbytes));
             if (!decompressed) {
                 JS_ReportOutOfMemory(cx);
                 return nullptr;
@@ -1979,28 +1977,26 @@ ScriptSource::chars(JSContext* cx, Uncom
                 JS_ReportOutOfMemory(cx);
                 js_free(decompressed);
                 return nullptr;
             }
 
             return decompressed;
         }
 
-        ReturnType match(Parent& p) {
+        const char16_t* match(Parent& p) {
             return p.parent->chars(cx, holder);
         }
 
-        ReturnType match(Missing&) {
+        const char16_t* match(Missing&) {
             MOZ_CRASH("ScriptSource::chars() on ScriptSource with SourceType = Missing");
             return nullptr;
         }
     };
-
-    CharsMatcher cm(cx, *this, holder);
-    return data.match(cm);
+    return data.match(CharsMatcher(cx, *this, holder));
 }
 
 JSFlatString*
 ScriptSource::substring(JSContext* cx, uint32_t start, uint32_t stop)
 {
     MOZ_ASSERT(start <= stop);
     UncompressedSourceCache::AutoHoldEntry holder;
     const char16_t* chars = this->chars(cx, holder);
@@ -2187,49 +2183,46 @@ SourceCompressionTask::work()
 
     return Success;
 }
 
 ScriptSource::~ScriptSource()
 {
     struct DestroyMatcher
     {
-        using ReturnType = void;
-
         ScriptSource& ss;
 
         explicit DestroyMatcher(ScriptSource& ss)
           : ss(ss)
         { }
 
-        ReturnType match(Uncompressed& u) {
+        void match(Uncompressed& u) {
             if (u.ownsChars)
                 js_free(const_cast<char16_t*>(u.chars));
         }
 
-        ReturnType match(Compressed& c) {
+        void match(Compressed& c) {
             if (ss.inCompressedSourceSet)
                 TlsPerThreadData.get()->runtimeFromMainThread()->compressedSourceSet.remove(&ss);
             js_free(c.raw);
         }
 
-        ReturnType match(Parent& p) {
+        void match(Parent& p) {
             p.parent->decref();
         }
 
-        ReturnType match(Missing&) {
+        void match(Missing&) {
             // Nothing to do here.
         }
     };
 
     MOZ_ASSERT(refs == 0);
     MOZ_ASSERT_IF(inCompressedSourceSet, data.is<Compressed>());
 
-    DestroyMatcher dm(*this);
-    data.match(dm);
+    data.match(DestroyMatcher(*this));
 }
 
 void
 ScriptSource::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                      JS::ScriptSourceInfo* info) const
 {
     if (data.is<Uncompressed>() && ownsUncompressedChars())
         info->uncompressed += mallocSizeOf(uncompressedChars());
@@ -2242,53 +2235,49 @@ ScriptSource::addSizeOfIncludingThis(moz
 }
 
 template<XDRMode mode>
 bool
 ScriptSource::performXDR(XDRState<mode>* xdr)
 {
     struct CompressedLengthMatcher
     {
-        using ReturnType = size_t;
-
-        ReturnType match(Uncompressed&) {
+        size_t match(Uncompressed&) {
             return 0;
         }
 
-        ReturnType match(Compressed& c) {
+        size_t match(Compressed& c) {
             return c.nbytes;
         }
 
-        ReturnType match(Parent& p) {
+        size_t match(Parent& p) {
             return p.parent->data.match(*this);
         }
 
-        ReturnType match(Missing&) {
+        size_t match(Missing&) {
             MOZ_CRASH("Missing source data in ScriptSource::performXDR");
             return 0;
         }
     };
 
     struct RawDataMatcher
     {
-        using ReturnType = void*;
-
-        ReturnType match(Uncompressed& u) {
+        void* match(Uncompressed& u) {
             return (void*) u.chars;
         }
 
-        ReturnType match(Compressed& c) {
+        void* match(Compressed& c) {
             return c.raw;
         }
 
-        ReturnType match(Parent& p) {
+        void* match(Parent& p) {
             return p.parent->data.match(*this);
         }
 
-        ReturnType match(Missing&) {
+        void* match(Missing&) {
             MOZ_CRASH("Missing source data in ScriptSource::performXDR");
             return nullptr;
         }
     };
 
     uint8_t hasSource = hasSourceData();
     if (!xdr->codeUint8(&hasSource))
         return false;
@@ -2298,20 +2287,18 @@ ScriptSource::performXDR(XDRState<mode>*
         return false;
     sourceRetrievable_ = retrievable;
 
     if (hasSource && !sourceRetrievable_) {
         if (!xdr->codeUint32(&length_))
             return false;
 
         uint32_t compressedLength;
-        if (mode == XDR_ENCODE) {
-            CompressedLengthMatcher m;
-            compressedLength = data.match(m);
-        }
+        if (mode == XDR_ENCODE)
+            compressedLength = data.match(CompressedLengthMatcher());
         if (!xdr->codeUint32(&compressedLength))
             return false;
 
         {
             uint8_t argumentsNotIncluded;
             if (mode == XDR_ENCODE)
                 argumentsNotIncluded = argumentsNotIncluded_;
             if (!xdr->codeUint8(&argumentsNotIncluded))
@@ -2329,18 +2316,17 @@ ScriptSource::performXDR(XDRState<mode>*
             }
 
             if (compressedLength)
                 setCompressedSource(xdr->cx()->runtime(), p, compressedLength,
                                     CompressedSourceHasher::computeHash(p, compressedLength));
             else
                 setSource((const char16_t*) p, length_);
         } else {
-            RawDataMatcher rdm;
-            void* p = data.match(rdm);
+            void* p = data.match(RawDataMatcher());
             if (!xdr->codeBytes(p, byteLen))
                 return false;
         }
     }
 
     uint8_t haveSourceMap = hasSourceMapURL();
     if (!xdr->codeUint8(&haveSourceMap))
         return false;
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -677,18 +677,18 @@ ToLowerCaseHelper(JSContext* cx, CallRec
 }
 
 bool
 js::str_toLowerCase(JSContext* cx, unsigned argc, Value* vp)
 {
     return ToLowerCaseHelper(cx, CallArgsFromVp(argc, vp));
 }
 
-bool
-js::str_toLocaleLowerCase(JSContext* cx, unsigned argc, Value* vp)
+static bool
+str_toLocaleLowerCase(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /*
      * Forcefully ignore the first (or any) argument and return toLowerCase(),
      * ECMA has reserved that argument, presumably for defining the locale.
      */
     if (cx->runtime()->localeCallbacks && cx->runtime()->localeCallbacks->localeToLowerCase) {
@@ -828,18 +828,18 @@ ToUpperCaseHelper(JSContext* cx, CallRec
 }
 
 bool
 js::str_toUpperCase(JSContext* cx, unsigned argc, Value* vp)
 {
     return ToUpperCaseHelper(cx, CallArgsFromVp(argc, vp));
 }
 
-bool
-js::str_toLocaleUpperCase(JSContext* cx, unsigned argc, Value* vp)
+static bool
+str_toLocaleUpperCase(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /*
      * Forcefully ignore the first (or any) argument and return toUpperCase(),
      * ECMA has reserved that argument, presumably for defining the locale.
      */
     if (cx->runtime()->localeCallbacks && cx->runtime()->localeCallbacks->localeToUpperCase) {
@@ -854,18 +854,18 @@ js::str_toLocaleUpperCase(JSContext* cx,
         args.rval().set(result);
         return true;
     }
 
     return ToUpperCaseHelper(cx, args);
 }
 
 #if !EXPOSE_INTL_API
-bool
-js::str_localeCompare(JSContext* cx, unsigned argc, Value* vp)
+static bool
+str_localeCompare(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedString str(cx, ThisToStringForStringProto(cx, args));
     if (!str)
         return false;
 
     RootedString thatStr(cx, ToString<CanGC>(cx, args.get(0)));
     if (!thatStr)
@@ -886,18 +886,18 @@ js::str_localeCompare(JSContext* cx, uns
 
     args.rval().setInt32(result);
     return true;
 }
 #endif
 
 #if EXPOSE_INTL_API
 /* ES6 20140210 draft 21.1.3.12. */
-bool
-js::str_normalize(JSContext* cx, unsigned argc, Value* vp)
+static bool
+str_normalize(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Steps 1-3.
     RootedString str(cx, ThisToStringForStringProto(cx, args));
     if (!str)
         return false;
 
@@ -1815,18 +1815,18 @@ js::str_startsWith(JSContext* cx, unsign
     if (!text)
         return false;
 
     args.rval().setBoolean(HasSubstringAt(text, searchStr, start));
     return true;
 }
 
 /* ES6 draft rc3 21.1.3.6. */
-bool
-js::str_endsWith(JSContext* cx, unsigned argc, Value* vp)
+static bool
+str_endsWith(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Steps 1, 2, and 3
     RootedString str(cx, ThisToStringForStringProto(cx, args));
     if (!str)
         return false;
 
@@ -1934,30 +1934,30 @@ TrimString(JSContext* cx, Value* vp, boo
     str = NewDependentString(cx, str, begin, end - begin);
     if (!str)
         return false;
 
     call.rval().setString(str);
     return true;
 }
 
-bool
-js::str_trim(JSContext* cx, unsigned argc, Value* vp)
+static bool
+str_trim(JSContext* cx, unsigned argc, Value* vp)
 {
     return TrimString(cx, vp, true, true);
 }
 
-bool
-js::str_trimLeft(JSContext* cx, unsigned argc, Value* vp)
+static bool
+str_trimLeft(JSContext* cx, unsigned argc, Value* vp)
 {
     return TrimString(cx, vp, true, false);
 }
 
-bool
-js::str_trimRight(JSContext* cx, unsigned argc, Value* vp)
+static bool
+str_trimRight(JSContext* cx, unsigned argc, Value* vp)
 {
     return TrimString(cx, vp, false, true);
 }
 
 // Utility for building a rope (lazy concatenation) of strings.
 class RopeBuilder {
     JSContext* cx;
     RootedString res;
@@ -2481,18 +2481,18 @@ js::str_split_string(JSContext* cx, Hand
         return CharSplitHelper(cx, linearStr, limit, group);
 
     return SplitHelper(cx, linearStr, limit, linearSep, group);
 }
 
 /*
  * Python-esque sequence operations.
  */
-bool
-js::str_concat(JSContext* cx, unsigned argc, Value* vp)
+static bool
+str_concat(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     JSString* str = ThisToStringForStringProto(cx, args);
     if (!str)
         return false;
 
     for (unsigned i = 0; i < args.length(); i++) {
         JSString* argStr = ToString<NoGC>(cx, args[i]);
@@ -2522,53 +2522,53 @@ js::str_concat(JSContext* cx, unsigned a
 static const JSFunctionSpec string_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,     str_toSource,          0,0),
 #endif
 
     /* Java-like methods. */
     JS_FN(js_toString_str,     str_toString,          0,0),
     JS_FN(js_valueOf_str,      str_toString,          0,0),
-    JS_FN("toLowerCase",       str_toLowerCase,       0,0),
-    JS_FN("toUpperCase",       str_toUpperCase,       0,0),
-    JS_INLINABLE_FN("charAt",  str_charAt,            1,0, StringCharAt),
-    JS_INLINABLE_FN("charCodeAt", str_charCodeAt,     1,0, StringCharCodeAt),
+    JS_FN("toLowerCase",       str_toLowerCase,       0,JSFUN_GENERIC_NATIVE),
+    JS_FN("toUpperCase",       str_toUpperCase,       0,JSFUN_GENERIC_NATIVE),
+    JS_INLINABLE_FN("charAt",  str_charAt,            1,JSFUN_GENERIC_NATIVE, StringCharAt),
+    JS_INLINABLE_FN("charCodeAt", str_charCodeAt,     1,JSFUN_GENERIC_NATIVE, StringCharCodeAt),
     JS_SELF_HOSTED_FN("substring", "String_substring", 2,0),
     JS_SELF_HOSTED_FN("padStart", "String_pad_start", 2,0),
     JS_SELF_HOSTED_FN("padEnd", "String_pad_end", 2,0),
     JS_SELF_HOSTED_FN("codePointAt", "String_codePointAt", 1,0),
-    JS_FN("includes",          str_includes,          1,0),
-    JS_FN("indexOf",           str_indexOf,           1,0),
-    JS_FN("lastIndexOf",       str_lastIndexOf,       1,0),
-    JS_FN("startsWith",        str_startsWith,        1,0),
-    JS_FN("endsWith",          str_endsWith,          1,0),
-    JS_FN("trim",              str_trim,              0,0),
-    JS_FN("trimLeft",          str_trimLeft,          0,0),
-    JS_FN("trimRight",         str_trimRight,         0,0),
-    JS_FN("toLocaleLowerCase", str_toLocaleLowerCase, 0,0),
-    JS_FN("toLocaleUpperCase", str_toLocaleUpperCase, 0,0),
+    JS_FN("includes",          str_includes,          1,JSFUN_GENERIC_NATIVE),
+    JS_FN("indexOf",           str_indexOf,           1,JSFUN_GENERIC_NATIVE),
+    JS_FN("lastIndexOf",       str_lastIndexOf,       1,JSFUN_GENERIC_NATIVE),
+    JS_FN("startsWith",        str_startsWith,        1,JSFUN_GENERIC_NATIVE),
+    JS_FN("endsWith",          str_endsWith,          1,JSFUN_GENERIC_NATIVE),
+    JS_FN("trim",              str_trim,              0,JSFUN_GENERIC_NATIVE),
+    JS_FN("trimLeft",          str_trimLeft,          0,JSFUN_GENERIC_NATIVE),
+    JS_FN("trimRight",         str_trimRight,         0,JSFUN_GENERIC_NATIVE),
+    JS_FN("toLocaleLowerCase", str_toLocaleLowerCase, 0,JSFUN_GENERIC_NATIVE),
+    JS_FN("toLocaleUpperCase", str_toLocaleUpperCase, 0,JSFUN_GENERIC_NATIVE),
 #if EXPOSE_INTL_API
     JS_SELF_HOSTED_FN("localeCompare", "String_localeCompare", 1,0),
 #else
-    JS_FN("localeCompare",     str_localeCompare,     1,0),
+    JS_FN("localeCompare",     str_localeCompare,     1,JSFUN_GENERIC_NATIVE),
 #endif
     JS_SELF_HOSTED_FN("repeat", "String_repeat",      1,0),
 #if EXPOSE_INTL_API
-    JS_FN("normalize",         str_normalize,         0,0),
+    JS_FN("normalize",         str_normalize,         0,JSFUN_GENERIC_NATIVE),
 #endif
 
     /* Perl-ish methods (search is actually Python-esque). */
     JS_SELF_HOSTED_FN("match", "String_match",        1,0),
     JS_SELF_HOSTED_FN("search", "String_search",      1,0),
     JS_SELF_HOSTED_FN("replace", "String_replace",    2,0),
     JS_SELF_HOSTED_FN("split",  "String_split",       2,0),
     JS_SELF_HOSTED_FN("substr", "String_substr",      2,0),
 
     /* Python-esque sequence methods. */
-    JS_FN("concat",            str_concat,            1,0),
+    JS_FN("concat",            str_concat,            1,JSFUN_GENERIC_NATIVE),
     JS_SELF_HOSTED_FN("slice", "String_slice",        2,0),
 
     /* HTML string methods. */
     JS_SELF_HOSTED_FN("bold",     "String_bold",       0,0),
     JS_SELF_HOSTED_FN("italics",  "String_italics",    0,0),
     JS_SELF_HOSTED_FN("fixed",    "String_fixed",      0,0),
     JS_SELF_HOSTED_FN("strike",   "String_strike",     0,0),
     JS_SELF_HOSTED_FN("small",    "String_small",      0,0),
@@ -2711,36 +2711,21 @@ static const JSFunctionSpec string_stati
     JS_SELF_HOSTED_FN("substr",          "String_static_substr",        3,0),
     JS_SELF_HOSTED_FN("slice",           "String_static_slice",         3,0),
 
     JS_SELF_HOSTED_FN("match",           "String_generic_match",        2,0),
     JS_SELF_HOSTED_FN("replace",         "String_generic_replace",      3,0),
     JS_SELF_HOSTED_FN("search",          "String_generic_search",       2,0),
     JS_SELF_HOSTED_FN("split",           "String_generic_split",        3,0),
 
-    JS_SELF_HOSTED_FN("toLowerCase",     "String_static_toLowerCase",   1,0),
-    JS_SELF_HOSTED_FN("toUpperCase",     "String_static_toUpperCase",   1,0),
-    JS_SELF_HOSTED_FN("charAt",          "String_static_charAt",        2,0),
-    JS_SELF_HOSTED_FN("charCodeAt",      "String_static_charCodeAt",    2,0),
-    JS_SELF_HOSTED_FN("includes",        "String_static_includes",      2,0),
-    JS_SELF_HOSTED_FN("indexOf",         "String_static_indexOf",       2,0),
-    JS_SELF_HOSTED_FN("lastIndexOf",     "String_static_lastIndexOf",   2,0),
-    JS_SELF_HOSTED_FN("startsWith",      "String_static_startsWith",    2,0),
-    JS_SELF_HOSTED_FN("endsWith",        "String_static_endsWith",      2,0),
-    JS_SELF_HOSTED_FN("trim",            "String_static_trim",          1,0),
-    JS_SELF_HOSTED_FN("trimLeft",        "String_static_trimLeft",      1,0),
-    JS_SELF_HOSTED_FN("trimRight",       "String_static_trimRight",     1,0),
-    JS_SELF_HOSTED_FN("toLocaleLowerCase","String_static_toLocaleLowerCase",1,0),
-    JS_SELF_HOSTED_FN("toLocaleUpperCase","String_static_toLocaleUpperCase",1,0),
+    // This must be at the end because of bug 853075: functions listed after
+    // self-hosted methods aren't available in self-hosted code.
 #if EXPOSE_INTL_API
-    JS_SELF_HOSTED_FN("normalize",       "String_static_normalize",     1,0),
+    JS_SELF_HOSTED_FN("localeCompare",   "String_static_localeCompare", 2,0),
 #endif
-    JS_SELF_HOSTED_FN("concat",          "String_static_concat",        2,0),
-
-    JS_SELF_HOSTED_FN("localeCompare",   "String_static_localeCompare", 2,0),
     JS_FS_END
 };
 
 /* static */ Shape*
 StringObject::assignInitialShape(ExclusiveContext* cx, Handle<StringObject*> obj)
 {
     MOZ_ASSERT(obj->empty());
 
@@ -2762,35 +2747,35 @@ js::InitStringClass(JSContext* cx, Handl
 
     /* Now create the String function. */
     RootedFunction ctor(cx);
     ctor = global->createConstructor(cx, StringConstructor, cx->names().String, 1,
                                      AllocKind::FUNCTION, &jit::JitInfo_String);
     if (!ctor)
         return nullptr;
 
+    if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_String, ctor, proto))
+        return nullptr;
+
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return nullptr;
 
     if (!DefinePropertiesAndFunctions(cx, proto, nullptr, string_methods) ||
         !DefinePropertiesAndFunctions(cx, ctor, nullptr, string_static_methods))
     {
         return nullptr;
     }
 
     /*
      * Define escape/unescape, the URI encode/decode functions, and maybe
      * uneval on the global object.
      */
     if (!JS_DefineFunctions(cx, global, string_functions))
         return nullptr;
 
-    if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_String, ctor, proto))
-        return nullptr;
-
     return proto;
 }
 
 const char*
 js::ValueToPrintable(JSContext* cx, const Value& vArg, JSAutoByteString* bytes, bool asSource)
 {
     RootedValue v(cx, vArg);
     JSString* str;
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -333,49 +333,16 @@ str_toString(JSContext* cx, unsigned arg
 extern bool
 str_charAt(JSContext* cx, unsigned argc, Value* vp);
 
 extern bool
 str_charCodeAt_impl(JSContext* cx, HandleString string, HandleValue index, MutableHandleValue res);
 
 extern bool
 str_charCodeAt(JSContext* cx, unsigned argc, Value* vp);
-
-extern bool
-str_contains(JSContext *cx, unsigned argc, Value *vp);
-
-extern bool
-str_endsWith(JSContext* cx, unsigned argc, Value* vp);
-
-extern bool
-str_trim(JSContext* cx, unsigned argc, Value* vp);
-
-extern bool
-str_trimLeft(JSContext* cx, unsigned argc, Value* vp);
-
-extern bool
-str_trimRight(JSContext* cx, unsigned argc, Value* vp);
-
-extern bool
-str_toLocaleLowerCase(JSContext* cx, unsigned argc, Value* vp);
-
-extern bool
-str_toLocaleUpperCase(JSContext* cx, unsigned argc, Value* vp);
-
-#if !EXPOSE_INTL_API
-extern bool
-str_localeCompare(JSContext* cx, unsigned argc, Value* vp);
-#else
-extern bool
-str_normalize(JSContext* cx, unsigned argc, Value* vp);
-#endif
-
-extern bool
-str_concat(JSContext* cx, unsigned argc, Value* vp);
-
 /*
  * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
  * least 4 bytes long.  Return the number of UTF-8 bytes of data written.
  */
 extern uint32_t
 OneUcs4ToUtf8Char(uint8_t* utf8Buffer, uint32_t ucs4Char);
 
 extern size_t
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/ArrayBuffer/indivisible-byteLength.js
@@ -0,0 +1,40 @@
+var BUGNUMBER = 1263803;
+var summary = 'CloneArrayBuffer should allocate ArrayBuffer even with individual byteLength';
+
+print(BUGNUMBER + ": " + summary);
+
+var abuf1 = new ArrayBuffer(38);
+assertEq(abuf1.byteLength, 38);
+
+var a1 = new Float64Array(abuf1, 24, 0);
+assertEq(a1.buffer.byteLength, 38);
+assertEq(a1.byteLength, 0);
+assertEq(a1.byteOffset, 24);
+
+var a2 = new Float64Array(a1);
+// NOTE: There is a behavior difference on ArrayBuffer's byteLength, between
+//       lazily allocated case and eagerly allocated case (bug 1264941).
+//       This one is lazily allocated case, and it equals to a2.byteLength.
+assertEq(a2.buffer.byteLength, 0);
+assertEq(a2.byteLength, 0);
+assertEq(a2.byteOffset, 0);
+
+class MyArrayBuffer extends ArrayBuffer {}
+
+var abuf2 = new MyArrayBuffer(38);
+assertEq(abuf2.byteLength, 38);
+
+var a3 = new Float64Array(abuf2, 24, 0);
+assertEq(a3.buffer.byteLength, 38);
+assertEq(a3.byteLength, 0);
+assertEq(a3.byteOffset, 24);
+
+var a4 = new Float64Array(a3);
+// NOTE: This one is eagerly allocated case, and it differs from a4.byteLength.
+//       Either one should be fixed once bug 1264941 is fixed.
+assertEq(a4.buffer.byteLength, 14);
+assertEq(a4.byteLength, 0);
+assertEq(a4.byteOffset, 0);
+
+if (typeof reportCompare === 'function')
+  reportCompare(true, true);
deleted file mode 100644
--- a/js/src/tests/js1_6/Array/generics.js
+++ /dev/null
@@ -1,331 +0,0 @@
-var BUGNUMBER = 1263558;
-var summary = "Self-host all Array generics.";
-
-print(BUGNUMBER + ": " + summary);
-
-var arr, arrLike, tmp, f;
-
-function reset() {
-  arr = [5, 7, 13];
-  arrLike = {
-    length: 3,
-    0: 5,
-    1: 7,
-    2: 13,
-    toString() {
-      return "arrLike";
-    }
-  };
-  tmp = [];
-}
-function toString() {
-  return "G";
-}
-
-// Array.join (test this first to use it in remaining tests).
-reset();
-assertThrowsInstanceOf(() => Array.join(), TypeError);
-assertEq(Array.join(arr), "5,7,13");
-assertEq(Array.join(arr, "-"), "5-7-13");
-assertEq(Array.join(arrLike), "5,7,13");
-assertEq(Array.join(arrLike, "-"), "5-7-13");
-
-// Array.concat.
-reset();
-assertThrowsInstanceOf(() => Array.concat(), TypeError);
-assertEq(Array.join(Array.concat(arr), ","), "5,7,13");
-assertEq(Array.join(Array.concat(arr, 11), ","), "5,7,13,11");
-assertEq(Array.join(Array.concat(arr, 11, 17), ","), "5,7,13,11,17");
-assertEq(Array.join(Array.concat(arrLike), ","), "arrLike");
-assertEq(Array.join(Array.concat(arrLike, 11), ","), "arrLike,11");
-assertEq(Array.join(Array.concat(arrLike, 11, 17), ","), "arrLike,11,17");
-
-// Array.lastIndexOf.
-reset();
-assertThrowsInstanceOf(() => Array.lastIndexOf(), TypeError);
-assertEq(Array.lastIndexOf(arr), -1);
-assertEq(Array.lastIndexOf(arr, 1), -1);
-assertEq(Array.lastIndexOf(arr, 5), 0);
-assertEq(Array.lastIndexOf(arr, 7), 1);
-assertEq(Array.lastIndexOf(arr, 13, 1), -1);
-assertEq(Array.lastIndexOf(arrLike), -1);
-assertEq(Array.lastIndexOf(arrLike, 1), -1);
-assertEq(Array.lastIndexOf(arrLike, 5), 0);
-assertEq(Array.lastIndexOf(arrLike, 7), 1);
-assertEq(Array.lastIndexOf(arrLike, 13, 1), -1);
-
-// Array.indexOf.
-reset();
-assertThrowsInstanceOf(() => Array.indexOf(), TypeError);
-assertEq(Array.indexOf(arr), -1);
-assertEq(Array.indexOf(arr, 1), -1);
-assertEq(Array.indexOf(arr, 5), 0);
-assertEq(Array.indexOf(arr, 7), 1);
-assertEq(Array.indexOf(arr, 1, 5), -1);
-assertEq(Array.indexOf(arrLike), -1);
-assertEq(Array.indexOf(arrLike, 1), -1);
-assertEq(Array.indexOf(arrLike, 5), 0);
-assertEq(Array.indexOf(arrLike, 7), 1);
-assertEq(Array.indexOf(arrLike, 1, 5), -1);
-
-// Array.forEach.
-reset();
-assertThrowsInstanceOf(() => Array.forEach(), TypeError);
-assertThrowsInstanceOf(() => Array.forEach(arr), TypeError);
-assertThrowsInstanceOf(() => Array.forEach(arrLike), TypeError);
-f = function(...args) {
-  tmp.push(this, ...args);
-};
-tmp = [];
-Array.forEach(arr, f);
-assertEq(tmp.join(","), "G,5,0,5,7,13," + "G,7,1,5,7,13," + "G,13,2,5,7,13");
-tmp = [];
-Array.forEach(arr, f, "T");
-assertEq(tmp.join(","), "T,5,0,5,7,13," + "T,7,1,5,7,13," + "T,13,2,5,7,13");
-tmp = [];
-Array.forEach(arrLike, f);
-assertEq(tmp.join(","), "G,5,0,arrLike," + "G,7,1,arrLike," + "G,13,2,arrLike");
-tmp = [];
-Array.forEach(arrLike, f, "T");
-assertEq(tmp.join(","), "T,5,0,arrLike," + "T,7,1,arrLike," + "T,13,2,arrLike");
-
-// Array.map.
-reset();
-assertThrowsInstanceOf(() => Array.map(), TypeError);
-assertThrowsInstanceOf(() => Array.map(arr), TypeError);
-assertThrowsInstanceOf(() => Array.map(arrLike), TypeError);
-f = function(...args) {
-  tmp.push(this, ...args);
-  return args[0] * 2;
-}
-tmp = [];
-assertEq(Array.join(Array.map(arr, f), ","), "10,14,26");
-assertEq(tmp.join(","), "G,5,0,5,7,13," + "G,7,1,5,7,13," + "G,13,2,5,7,13");
-tmp = [];
-assertEq(Array.join(Array.map(arr, f, "T"), ","), "10,14,26");
-assertEq(tmp.join(","), "T,5,0,5,7,13," + "T,7,1,5,7,13," + "T,13,2,5,7,13");
-tmp = [];
-assertEq(Array.join(Array.map(arrLike, f), ","), "10,14,26");
-assertEq(tmp.join(","), "G,5,0,arrLike," + "G,7,1,arrLike," + "G,13,2,arrLike");
-tmp = [];
-assertEq(Array.join(Array.map(arrLike, f, "T"), ","), "10,14,26");
-assertEq(tmp.join(","), "T,5,0,arrLike," + "T,7,1,arrLike," + "T,13,2,arrLike");
-
-// Array.filter.
-reset();
-assertThrowsInstanceOf(() => Array.filter(), TypeError);
-assertThrowsInstanceOf(() => Array.filter(arr), TypeError);
-assertThrowsInstanceOf(() => Array.filter(arrLike), TypeError);
-f = function(...args) {
-  tmp.push(this, ...args);
-  return args[0] < 10;
-}
-tmp = [];
-assertEq(Array.join(Array.filter(arr, f), ","), "5,7");
-assertEq(tmp.join(","), "G,5,0,5,7,13," + "G,7,1,5,7,13," + "G,13,2,5,7,13");
-tmp = [];
-assertEq(Array.join(Array.filter(arr, f, "T"), ","), "5,7");
-assertEq(tmp.join(","), "T,5,0,5,7,13," + "T,7,1,5,7,13," + "T,13,2,5,7,13");
-tmp = [];
-assertEq(Array.join(Array.filter(arrLike, f), ","), "5,7");
-assertEq(tmp.join(","), "G,5,0,arrLike," + "G,7,1,arrLike," + "G,13,2,arrLike");
-tmp = [];
-assertEq(Array.join(Array.filter(arrLike, f, "T"), ","), "5,7");
-assertEq(tmp.join(","), "T,5,0,arrLike," + "T,7,1,arrLike," + "T,13,2,arrLike");
-
-// Array.every.
-reset();
-assertThrowsInstanceOf(() => Array.every(), TypeError);
-assertThrowsInstanceOf(() => Array.every(arr), TypeError);
-assertThrowsInstanceOf(() => Array.every(arrLike), TypeError);
-f = function(...args) {
-  tmp.push(this, ...args);
-  return args[0] < 6;
-}
-tmp = [];
-assertEq(Array.every(arr, f), false);
-assertEq(tmp.join(","), "G,5,0,5,7,13," + "G,7,1,5,7,13");
-tmp = [];
-assertEq(Array.every(arr, f, "T"), false);
-assertEq(tmp.join(","), "T,5,0,5,7,13," + "T,7,1,5,7,13");
-tmp = [];
-assertEq(Array.every(arrLike, f), false);
-assertEq(tmp.join(","), "G,5,0,arrLike," + "G,7,1,arrLike");
-tmp = [];
-assertEq(Array.every(arrLike, f, "T"), false);
-assertEq(tmp.join(","), "T,5,0,arrLike," + "T,7,1,arrLike");
-
-// Array.some.
-reset();
-assertThrowsInstanceOf(() => Array.some(), TypeError);
-assertThrowsInstanceOf(() => Array.some(arr), TypeError);
-assertThrowsInstanceOf(() => Array.some(arrLike), TypeError);
-f = function(...args) {
-  tmp.push(this, ...args);
-  return args[0] == 7;
-}
-tmp = [];
-assertEq(Array.some(arr, f), true);
-assertEq(tmp.join(","), "G,5,0,5,7,13," + "G,7,1,5,7,13");
-tmp = [];
-assertEq(Array.some(arr, f, "T"), true);
-assertEq(tmp.join(","), "T,5,0,5,7,13," + "T,7,1,5,7,13");
-tmp = [];
-assertEq(Array.some(arrLike, f), true);
-assertEq(tmp.join(","), "G,5,0,arrLike," + "G,7,1,arrLike");
-tmp = [];
-assertEq(Array.some(arrLike, f, "T"), true);
-assertEq(tmp.join(","), "T,5,0,arrLike," + "T,7,1,arrLike");
-
-// Array.reduce.
-reset();
-assertThrowsInstanceOf(() => Array.reduce(), TypeError);
-assertThrowsInstanceOf(() => Array.reduce(arr), TypeError);
-assertThrowsInstanceOf(() => Array.reduce(arrLike), TypeError);
-f = function(...args) {
-  tmp.push(...args);
-  return args[0] + args[1];
-}
-tmp = [];
-assertEq(Array.reduce(arr, f), 25);
-assertEq(tmp.join(","), "5,7,1,5,7,13," + "12,13,2,5,7,13");
-tmp = [];
-assertEq(Array.reduce(arr, f, 17), 42);
-assertEq(tmp.join(","), "17,5,0,5,7,13," + "22,7,1,5,7,13," + "29,13,2,5,7,13");
-tmp = [];
-assertEq(Array.reduce(arrLike, f), 25);
-assertEq(tmp.join(","), "5,7,1,arrLike," + "12,13,2,arrLike");
-tmp = [];
-assertEq(Array.reduce(arrLike, f, 17), 42);
-assertEq(tmp.join(","), "17,5,0,arrLike," + "22,7,1,arrLike," + "29,13,2,arrLike");
-
-// Array.reduceRight.
-reset();
-assertThrowsInstanceOf(() => Array.reduceRight(), TypeError);
-assertThrowsInstanceOf(() => Array.reduceRight(arr), TypeError);
-assertThrowsInstanceOf(() => Array.reduceRight(arrLike), TypeError);
-f = function(...args) {
-  tmp.push(...args);
-  return args[0] + args[1];
-}
-tmp = [];
-assertEq(Array.reduceRight(arr, f), 25);
-assertEq(tmp.join(","), "13,7,1,5,7,13," + "20,5,0,5,7,13");
-tmp = [];
-assertEq(Array.reduceRight(arr, f, 17), 42);
-assertEq(tmp.join(","), "17,13,2,5,7,13," + "30,7,1,5,7,13," + "37,5,0,5,7,13");
-tmp = [];
-assertEq(Array.reduceRight(arrLike, f), 25);
-assertEq(tmp.join(","), "13,7,1,arrLike," + "20,5,0,arrLike");
-tmp = [];
-assertEq(Array.reduceRight(arrLike, f, 17), 42);
-assertEq(tmp.join(","), "17,13,2,arrLike," + "30,7,1,arrLike," + "37,5,0,arrLike");
-
-// Array.reverse.
-reset();
-assertThrowsInstanceOf(() => Array.reverse(), TypeError);
-assertEq(Array.join(Array.reverse(arr), ","), "13,7,5");
-assertEq(Array.join(arr, ","), "13,7,5");
-assertEq(Array.join(Array.reverse(arrLike), ","), "13,7,5");
-assertEq(Array.join(arrLike, ","), "13,7,5");
-
-// Array.sort.
-reset();
-assertThrowsInstanceOf(() => Array.sort(), TypeError);
-f = function(x, y) {
-  return y - x;
-}
-assertEq(Array.join(Array.sort(arr), ","), "13,5,7");
-assertEq(Array.join(Array.sort(arr, f), ","), "13,7,5");
-assertEq(Array.join(Array.sort(arrLike), ","), "13,5,7");
-assertEq(Array.join(Array.sort(arrLike, f), ","), "13,7,5");
-
-// Array.push.
-reset();
-assertThrowsInstanceOf(() => Array.push(), TypeError);
-assertEq(Array.push(arr), 3);
-assertEq(Array.join(arr), "5,7,13");
-assertEq(Array.push(arr, 17), 4);
-assertEq(Array.join(arr), "5,7,13,17");
-assertEq(Array.push(arr, 19, 21), 6);
-assertEq(Array.join(arr), "5,7,13,17,19,21");
-assertEq(Array.push(arrLike), 3);
-assertEq(Array.join(arrLike), "5,7,13");
-assertEq(Array.push(arrLike, 17), 4);
-assertEq(Array.join(arrLike), "5,7,13,17");
-assertEq(Array.push(arrLike, 19, 21), 6);
-assertEq(Array.join(arrLike), "5,7,13,17,19,21");
-
-// Array.pop.
-reset();
-assertThrowsInstanceOf(() => Array.pop(), TypeError);
-assertEq(Array.pop(arr), 13);
-assertEq(Array.join(arr), "5,7");
-assertEq(Array.pop(arr), 7);
-assertEq(Array.join(arr), "5");
-assertEq(Array.pop(arrLike), 13);
-assertEq(Array.join(arrLike), "5,7");
-assertEq(Array.pop(arrLike), 7);
-assertEq(Array.join(arrLike), "5");
-
-// Array.shift.
-reset();
-assertThrowsInstanceOf(() => Array.shift(), TypeError);
-assertEq(Array.shift(arr), 5);
-assertEq(Array.join(arr), "7,13");
-assertEq(Array.shift(arr), 7);
-assertEq(Array.join(arr), "13");
-assertEq(Array.shift(arrLike), 5);
-assertEq(Array.join(arrLike), "7,13");
-assertEq(Array.shift(arrLike), 7);
-assertEq(Array.join(arrLike), "13");
-
-// Array.unshift.
-reset();
-assertThrowsInstanceOf(() => Array.unshift(), TypeError);
-assertEq(Array.unshift(arr), 3);
-assertEq(Array.join(arr), "5,7,13");
-assertEq(Array.unshift(arr, 17), 4);
-assertEq(Array.join(arr), "17,5,7,13");
-assertEq(Array.unshift(arr, 19, 21), 6);
-assertEq(Array.join(arr), "19,21,17,5,7,13");
-assertEq(Array.unshift(arrLike), 3);
-assertEq(Array.join(arrLike), "5,7,13");
-assertEq(Array.unshift(arrLike, 17), 4);
-assertEq(Array.join(arrLike), "17,5,7,13");
-assertEq(Array.unshift(arrLike, 19, 21), 6);
-assertEq(Array.join(arrLike), "19,21,17,5,7,13");
-
-// Array.splice.
-reset();
-assertThrowsInstanceOf(() => Array.splice(), TypeError);
-assertEq(Array.join(Array.splice(arr)), "");
-assertEq(Array.join(arr), "5,7,13");
-assertEq(Array.join(Array.splice(arr, 1)), "7,13");
-assertEq(Array.join(arr), "5");
-reset();
-assertEq(Array.join(Array.splice(arr, 1, 1)), "7");
-assertEq(Array.join(arr), "5,13");
-reset();
-assertEq(Array.join(Array.splice(arrLike)), "");
-assertEq(Array.join(arrLike), "5,7,13");
-assertEq(Array.join(Array.splice(arrLike, 1)), "7,13");
-assertEq(Array.join(arrLike), "5");
-reset();
-assertEq(Array.join(Array.splice(arrLike, 1, 1)), "7");
-assertEq(Array.join(arrLike), "5,13");
-
-// Array.slice.
-reset();
-assertThrowsInstanceOf(() => Array.slice(), TypeError);
-assertEq(Array.join(Array.slice(arr)), "5,7,13");
-assertEq(Array.join(Array.slice(arr, 1)), "7,13");
-assertEq(Array.join(Array.slice(arr, 1, 1)), "");
-assertEq(Array.join(Array.slice(arr, 1, 2)), "7");
-assertEq(Array.join(Array.slice(arrLike)), "5,7,13");
-assertEq(Array.join(Array.slice(arrLike, 1)), "7,13");
-assertEq(Array.join(Array.slice(arrLike, 1, 1)), "");
-assertEq(Array.join(Array.slice(arrLike, 1, 2)), "7");
-
-if (typeof reportCompare === "function")
-  reportCompare(true, true);
deleted file mode 100644
--- a/js/src/tests/js1_6/String/generics.js
+++ /dev/null
@@ -1,228 +0,0 @@
-var BUGNUMBER = 1263558;
-var summary = "Self-host all String generics.";
-
-print(BUGNUMBER + ": " + summary);
-
-var result;
-var str = "ABCde";
-var strObj = {
-  toString() {
-    return "ABCde";
-  }
-};
-
-// String.substring.
-assertThrowsInstanceOf(() => String.substring(), TypeError);
-assertEq(String.substring(str), "ABCde");
-assertEq(String.substring(str, 1), "BCde");
-assertEq(String.substring(str, 1, 3), "BC");
-assertEq(String.substring(strObj), "ABCde");
-assertEq(String.substring(strObj, 1), "BCde");
-assertEq(String.substring(strObj, 1, 3), "BC");
-
-// String.substr.
-assertThrowsInstanceOf(() => String.substr(), TypeError);
-assertEq(String.substr(str), "ABCde");
-assertEq(String.substr(str, 1), "BCde");
-assertEq(String.substr(str, 1, 3), "BCd");
-assertEq(String.substr(strObj), "ABCde");
-assertEq(String.substr(strObj, 1), "BCde");
-assertEq(String.substr(strObj, 1, 3), "BCd");
-
-// String.slice.
-assertThrowsInstanceOf(() => String.slice(), TypeError);
-assertEq(String.slice(str), "ABCde");
-assertEq(String.slice(str, 1), "BCde");
-assertEq(String.slice(str, 1, 3), "BC");
-assertEq(String.slice(strObj), "ABCde");
-assertEq(String.slice(strObj, 1), "BCde");
-assertEq(String.slice(strObj, 1, 3), "BC");
-
-// String.match.
-assertThrowsInstanceOf(() => String.match(), TypeError);
-result = String.match(str);
-assertEq(result.index, 0);
-assertEq(result.length, 1);
-assertEq(result[0], "");
-result = String.match(str, /c/i);
-assertEq(result.index, 2);
-assertEq(result.length, 1);
-assertEq(result[0], "C");
-result = String.match(strObj);
-assertEq(result.index, 0);
-assertEq(result.length, 1);
-assertEq(result[0], "");
-result = String.match(strObj, /c/i);
-assertEq(result.index, 2);
-assertEq(result.length, 1);
-assertEq(result[0], "C");
-
-// String.replace.
-assertThrowsInstanceOf(() => String.replace(), TypeError);
-assertEq(String.replace(str), "ABCde");
-assertEq(String.replace(str, /c/i), "ABundefinedde");
-assertEq(String.replace(str, /c/i, "x"), "ABxde");
-assertEq(String.replace(strObj), "ABCde");
-assertEq(String.replace(strObj, /c/i), "ABundefinedde");
-assertEq(String.replace(strObj, /c/i, "x"), "ABxde");
-
-// String.search.
-assertThrowsInstanceOf(() => String.search(), TypeError);
-assertEq(String.search(str), 0);
-assertEq(String.search(str, /c/i), 2);
-assertEq(String.search(strObj), 0);
-assertEq(String.search(strObj, /c/i), 2);
-
-// String.split.
-assertThrowsInstanceOf(() => String.split(), TypeError);
-assertEq(String.split(str).join(","), "ABCde");
-assertEq(String.split(str, /[bd]/i).join(","), "A,C,e");
-assertEq(String.split(str, /[bd]/i, 2).join(","), "A,C");
-assertEq(String.split(strObj).join(","), "ABCde");
-assertEq(String.split(strObj, /[bd]/i).join(","), "A,C,e");
-assertEq(String.split(strObj, /[bd]/i, 2).join(","), "A,C");
-
-// String.toLowerCase.
-assertThrowsInstanceOf(() => String.toLowerCase(), TypeError);
-assertEq(String.toLowerCase(str), "abcde");
-assertEq(String.toLowerCase(strObj), "abcde");
-
-// String.toUpperCase.
-assertThrowsInstanceOf(() => String.toUpperCase(), TypeError);
-assertEq(String.toUpperCase(str), "ABCDE");
-assertEq(String.toUpperCase(strObj), "ABCDE");
-
-// String.charAt.
-assertThrowsInstanceOf(() => String.charAt(), TypeError);
-assertEq(String.charAt(str), "A");
-assertEq(String.charAt(str, 2), "C");
-assertEq(String.charAt(strObj), "A");
-assertEq(String.charAt(strObj, 2), "C");
-
-// String.charCodeAt.
-assertThrowsInstanceOf(() => String.charCodeAt(), TypeError);
-assertEq(String.charCodeAt(str), 65);
-assertEq(String.charCodeAt(str, 2), 67);
-assertEq(String.charCodeAt(strObj), 65);
-assertEq(String.charCodeAt(strObj, 2), 67);
-
-// String.includes.
-assertThrowsInstanceOf(() => String.includes(), TypeError);
-assertEq(String.includes(str), false);
-assertEq(String.includes(str, "C"), true);
-assertEq(String.includes(str, "C", 2), true);
-assertEq(String.includes(str, "C", 3), false);
-assertEq(String.includes(strObj), false);
-assertEq(String.includes(strObj, "C"), true);
-assertEq(String.includes(strObj, "C", 2), true);
-assertEq(String.includes(strObj, "C", 3), false);
-
-// String.indexOf.
-assertThrowsInstanceOf(() => String.indexOf(), TypeError);
-assertEq(String.indexOf(str), -1);
-assertEq(String.indexOf(str, "C"), 2);
-assertEq(String.indexOf(str, "C", 2), 2);
-assertEq(String.indexOf(str, "C", 3), -1);
-assertEq(String.indexOf(strObj), -1);
-assertEq(String.indexOf(strObj, "C"), 2);
-assertEq(String.indexOf(strObj, "C", 2), 2);
-assertEq(String.indexOf(strObj, "C", 3), -1);
-
-// String.lastIndexOf.
-assertThrowsInstanceOf(() => String.lastIndexOf(), TypeError);
-assertEq(String.lastIndexOf(str), -1);
-assertEq(String.lastIndexOf(str, "C"), 2);
-assertEq(String.lastIndexOf(str, "C", 2), 2);
-assertEq(String.lastIndexOf(str, "C", 1), -1);
-assertEq(String.lastIndexOf(strObj), -1);
-assertEq(String.lastIndexOf(strObj, "C"), 2);
-assertEq(String.lastIndexOf(strObj, "C", 2), 2);
-assertEq(String.lastIndexOf(strObj, "C", 1), -1);
-
-// String.startsWith.
-assertThrowsInstanceOf(() => String.startsWith(), TypeError);
-assertEq(String.startsWith(str), false);
-assertEq(String.startsWith(str, "A"), true);
-assertEq(String.startsWith(str, "B", 0), false);
-assertEq(String.startsWith(str, "B", 1), true);
-assertEq(String.startsWith(strObj), false);
-assertEq(String.startsWith(strObj, "A"), true);
-assertEq(String.startsWith(strObj, "B", 0), false);
-assertEq(String.startsWith(strObj, "B", 1), true);
-
-// String.endsWith.
-assertThrowsInstanceOf(() => String.endsWith(), TypeError);
-assertEq(String.endsWith(str), false);
-assertEq(String.endsWith(str, "e"), true);
-assertEq(String.endsWith(str, "B", 0), false);
-assertEq(String.endsWith(str, "B", 2), true);
-assertEq(String.endsWith(strObj), false);
-assertEq(String.endsWith(strObj, "e"), true);
-assertEq(String.endsWith(strObj, "B", 0), false);
-assertEq(String.endsWith(strObj, "B", 2), true);
-
-// String.trim.
-var str2 = "  ABCde  ";
-var strObj2 = {
-  toString() {
-    return "  ABCde  ";
-  }
-};
-assertThrowsInstanceOf(() => String.trim(), TypeError);
-assertEq(String.trim(str2), "ABCde");
-assertEq(String.trim(strObj2), "ABCde");
-
-// String.trimLeft.
-assertThrowsInstanceOf(() => String.trimLeft(), TypeError);
-assertEq(String.trimLeft(str2), "ABCde  ");
-assertEq(String.trimLeft(strObj2), "ABCde  ");
-
-// String.trimRight.
-assertThrowsInstanceOf(() => String.trimRight(), TypeError);
-assertEq(String.trimRight(str2), "  ABCde");
-assertEq(String.trimRight(strObj2), "  ABCde");
-
-// String.toLocaleLowerCase.
-assertThrowsInstanceOf(() => String.toLocaleLowerCase(), TypeError);
-assertEq(String.toLocaleLowerCase(str), str.toLocaleLowerCase());
-assertEq(String.toLocaleLowerCase(strObj), str.toLocaleLowerCase());
-
-// String.toLocaleUpperCase.
-assertThrowsInstanceOf(() => String.toLocaleUpperCase(), TypeError);
-assertEq(String.toLocaleUpperCase(str), str.toLocaleUpperCase());
-assertEq(String.toLocaleUpperCase(strObj), str.toLocaleUpperCase());
-
-// String.localeCompare.
-assertThrowsInstanceOf(() => String.localeCompare(), TypeError);
-assertEq(String.localeCompare(str), str.localeCompare());
-assertEq(String.localeCompare(str, "abcde"), str.localeCompare("abcde"));
-assertEq(String.localeCompare(strObj), str.localeCompare());
-assertEq(String.localeCompare(strObj, "abcde"), str.localeCompare("abcde"));
-
-// String.normalize.
-if ("normalize" in String.prototype) {
-  var str3 = "\u3082\u3058\u3089 \u3082\u3057\u3099\u3089";
-  var strObj3 = {
-    toString() {
-      return "\u3082\u3058\u3089 \u3082\u3057\u3099\u3089";
-    }
-  };
-  assertThrowsInstanceOf(() => String.normalize(), TypeError);
-
-  assertEq(String.normalize(str3), "\u3082\u3058\u3089 \u3082\u3058\u3089");
-  assertEq(String.normalize(str3, "NFD"), "\u3082\u3057\u3099\u3089 \u3082\u3057\u3099\u3089");
-  assertEq(String.normalize(strObj3), "\u3082\u3058\u3089 \u3082\u3058\u3089");
-  assertEq(String.normalize(strObj3, "NFD"), "\u3082\u3057\u3099\u3089 \u3082\u3057\u3099\u3089");
-}
-
-// String.concat.
-assertThrowsInstanceOf(() => String.concat(), TypeError);
-assertEq(String.concat(str), "ABCde");
-assertEq(String.concat(str, "f"), "ABCdef");
-assertEq(String.concat(str, "f", "g"), "ABCdefg");
-assertEq(String.concat(strObj), "ABCde");
-assertEq(String.concat(strObj, "f"), "ABCdef");
-assertEq(String.concat(strObj, "f", "g"), "ABCdefg");
-
-if (typeof reportCompare === "function")
-  reportCompare(true, true);
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -1555,18 +1555,16 @@ ConcreteStackFrame<SavedFrame>::construc
     }
     return true;
 }
 
 // A `mozilla::Variant` matcher that converts the inner value of a
 // `JS::ubi::AtomOrTwoByteChars` string to a `JSAtom*`.
 struct MOZ_STACK_CLASS AtomizingMatcher
 {
-    using ReturnType = JSAtom*;
-
     JSContext* cx;
     size_t     length;
 
     explicit AtomizingMatcher(JSContext* cx, size_t length)
       : cx(cx)
       , length(length)
     { }
 
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2243,18 +2243,16 @@ static const JSFunctionSpec intrinsic_fu
     JS_INLINABLE_FN("std_Array",                 ArrayConstructor,             1,0, Array),
     JS_FN("std_Array_join",                      array_join,                   1,0),
     JS_INLINABLE_FN("std_Array_push",            array_push,                   1,0, ArrayPush),
     JS_INLINABLE_FN("std_Array_pop",             array_pop,                    0,0, ArrayPop),
     JS_INLINABLE_FN("std_Array_shift",           array_shift,                  0,0, ArrayShift),
     JS_FN("std_Array_unshift",                   array_unshift,                1,0),
     JS_INLINABLE_FN("std_Array_slice",           array_slice,                  2,0, ArraySlice),
     JS_FN("std_Array_sort",                      array_sort,                   1,0),
-    JS_FN("std_Array_reverse",                   array_reverse,                0,0),
-    JS_INLINABLE_FN("std_Array_splice",          array_splice,                 2,0, ArraySplice),
 
     JS_FN("std_Date_now",                        date_now,                     0,0),
     JS_FN("std_Date_valueOf",                    date_valueOf,                 0,0),
 
     JS_FN("std_Function_apply",                  fun_apply,                    2,0),
 
     JS_INLINABLE_FN("std_Math_floor",            math_floor,                   1,0, MathFloor),
     JS_INLINABLE_FN("std_Math_max",              math_max,                     2,0, MathMax),
@@ -2287,31 +2285,16 @@ static const JSFunctionSpec intrinsic_fu
     JS_INLINABLE_FN("std_String_charCodeAt",     str_charCodeAt,               1,0, StringCharCodeAt),
     JS_FN("std_String_includes",                 str_includes,                 1,0),
     JS_FN("std_String_indexOf",                  str_indexOf,                  1,0),
     JS_FN("std_String_lastIndexOf",              str_lastIndexOf,              1,0),
     JS_FN("std_String_startsWith",               str_startsWith,               1,0),
     JS_FN("std_String_toLowerCase",              str_toLowerCase,              0,0),
     JS_FN("std_String_toUpperCase",              str_toUpperCase,              0,0),
 
-    JS_INLINABLE_FN("std_String_charAt",         str_charAt,                   1,0, StringCharAt),
-    JS_FN("std_String_endsWith",                 str_endsWith,                 1,0),
-    JS_FN("std_String_trim",                     str_trim,                     0,0),
-    JS_FN("std_String_trimLeft",                 str_trimLeft,                 0,0),
-    JS_FN("std_String_trimRight",                str_trimRight,                0,0),
-    JS_FN("std_String_toLocaleLowerCase",        str_toLocaleLowerCase,        0,0),
-    JS_FN("std_String_toLocaleUpperCase",        str_toLocaleUpperCase,        0,0),
-#if !EXPOSE_INTL_API
-    JS_FN("std_String_localeCompare",            str_localeCompare,            1,0),
-#else
-    JS_FN("std_String_normalize",                str_normalize,                0,0),
-#endif
-    JS_FN("std_String_concat",                   str_concat,                   1,0),
-
-
     JS_FN("std_WeakMap_has",                     WeakMap_has,                  1,0),
     JS_FN("std_WeakMap_get",                     WeakMap_get,                  2,0),
     JS_FN("std_WeakMap_set",                     WeakMap_set,                  2,0),
     JS_FN("std_WeakMap_delete",                  WeakMap_delete,               1,0),
 
     JS_FN("std_SIMD_Int8x16_extractLane",        simd_int8x16_extractLane,     2,0),
     JS_FN("std_SIMD_Int16x8_extractLane",        simd_int16x8_extractLane,     2,0),
     JS_INLINABLE_FN("std_SIMD_Int32x4_extractLane",   simd_int32x4_extractLane,  2,0, SimdInt32x4_extractLane),
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -631,58 +631,57 @@ class TypedArrayObjectTemplate : public 
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return nullptr; // byteOffset + len is too big for the arraybuffer
         }
 
         return makeInstance(cx, buffer, byteOffset, len, proto);
     }
 
     static bool
-    maybeCreateArrayBuffer(JSContext* cx, uint32_t nelements, HandleObject nonDefaultProto,
+    maybeCreateArrayBuffer(JSContext* cx, uint32_t byteLength, HandleObject nonDefaultProto,
                            MutableHandle<ArrayBufferObject*> buffer)
     {
+        MOZ_ASSERT(byteLength < INT32_MAX);
         static_assert(INLINE_BUFFER_LIMIT % sizeof(NativeType) == 0,
                       "ArrayBuffer inline storage shouldn't waste any space");
 
-        if (!nonDefaultProto && nelements <= INLINE_BUFFER_LIMIT / sizeof(NativeType)) {
+        if (!nonDefaultProto && byteLength <= INLINE_BUFFER_LIMIT) {
             // The array's data can be inline, and the buffer created lazily.
             return true;
         }
 
-        if (nelements >= INT32_MAX / sizeof(NativeType)) {
-            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
-                                 JSMSG_NEED_DIET, "size and count");
-            return false;
-        }
-
-        ArrayBufferObject* buf = ArrayBufferObject::create(cx, nelements * sizeof(NativeType),
-                                                           nonDefaultProto);
+        ArrayBufferObject* buf = ArrayBufferObject::create(cx, byteLength, nonDefaultProto);
         if (!buf)
             return false;
 
         buffer.set(buf);
         return true;
     }
 
     static JSObject*
     fromLength(JSContext* cx, uint32_t nelements, HandleObject newTarget = nullptr)
     {
         RootedObject proto(cx);
         if (!GetPrototypeForInstance(cx, newTarget, &proto))
             return nullptr;
 
+        if (nelements >= INT32_MAX / BYTES_PER_ELEMENT) {
+            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
+                                 JSMSG_NEED_DIET, "size and count");
+            return nullptr;
+        }
         Rooted<ArrayBufferObject*> buffer(cx);
-        if (!maybeCreateArrayBuffer(cx, nelements, nullptr, &buffer))
+        if (!maybeCreateArrayBuffer(cx, nelements * BYTES_PER_ELEMENT, nullptr, &buffer))
             return nullptr;
 
         return makeInstance(cx, buffer, 0, nelements, proto);
     }
 
     static bool
-    AllocateArrayBuffer(JSContext* cx, HandleValue ctor, uint32_t elementLength,
+    AllocateArrayBuffer(JSContext* cx, HandleValue ctor, uint32_t byteLength,
                         MutableHandle<ArrayBufferObject*> buffer);
 
     static bool
     CloneArrayBufferNoCopy(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> srcBuffer,
                            bool isWrapped, uint32_t srcByteOffset,
                            MutableHandle<ArrayBufferObject*> buffer);
 
     static JSObject*
@@ -729,34 +728,40 @@ struct TypedArrayObject::OfType
 {
     typedef TypedArrayObjectTemplate<T> Type;
 };
 
 // ES 2016 draft Mar 25, 2016 24.1.1.1.
 template<typename T>
 /* static */ bool
 TypedArrayObjectTemplate<T>::AllocateArrayBuffer(JSContext* cx, HandleValue ctor,
-                                                 uint32_t elementLength,
+                                                 uint32_t byteLength,
                                                  MutableHandle<ArrayBufferObject*> buffer)
 {
     // ES 2016 draft Mar 25, 2016 24.1.1.1 step 1 (partially).
     // ES 2016 draft Mar 25, 2016 9.1.14 steps 1-2.
     MOZ_ASSERT(ctor.isObject());
     RootedObject proto(cx);
     RootedObject ctorObj(cx, &ctor.toObject());
     if (!GetPrototypeFromConstructor(cx, ctorObj, &proto))
         return false;
     JSObject* arrayBufferProto = GlobalObject::getOrCreateArrayBufferPrototype(cx, cx->global());
     if (!arrayBufferProto)
         return false;
     if (proto == arrayBufferProto)
         proto = nullptr;
 
+    if (byteLength >= INT32_MAX) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
+                             JSMSG_NEED_DIET, "size and count");
+        return false;
+    }
+
     // ES 2016 draft Mar 25, 2016 24.1.1.1 steps 1 (remaining part), 2-6.
-    if (!maybeCreateArrayBuffer(cx, elementLength, proto, buffer))
+    if (!maybeCreateArrayBuffer(cx, byteLength, proto, buffer))
         return false;
 
     return true;
 }
 
 static bool
 IsArrayBufferConstructor(const Value& v)
 {
@@ -842,18 +847,17 @@ TypedArrayObjectTemplate<T>::CloneArrayB
     MOZ_ASSERT(srcByteOffset <= srcLength);
 
     // Step 6.
     uint32_t cloneLength = srcLength - srcByteOffset;
 
     // Step 7 (skipped).
 
     // Steps 8.
-    MOZ_ASSERT(cloneLength % BYTES_PER_ELEMENT == 0);
-    if (!AllocateArrayBuffer(cx, cloneCtor, cloneLength / BYTES_PER_ELEMENT, buffer))
+    if (!AllocateArrayBuffer(cx, cloneCtor, cloneLength, buffer))
         return false;
 
     // Step 9.
     if (srcBuffer->isDetached()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
         return false;
     }
 
@@ -933,33 +937,33 @@ TypedArrayObjectTemplate<T>::fromTypedAr
     // Steps 11-12.
     Scalar::Type srcType = srcArray->type();
 
     // Step 13 (skipped).
 
     // Step 14.
     uint32_t srcByteOffset = srcArray->byteOffset();
 
-    // Steps 15-16 (skipped).
-    // Our AllocateArrayBuffer receives elementLength instead of byteLength.
+    // Steps 15-16.
+    uint32_t byteLength = BYTES_PER_ELEMENT * elementLength;
 
     // Steps 8-9, 17.
     Rooted<ArrayBufferObject*> buffer(cx);
     if (ArrayTypeID() == srcType) {
         // Step 17.a.
         if (!CloneArrayBufferNoCopy(cx, srcData, isWrapped, srcByteOffset, &buffer))
             return nullptr;
     } else {
         // Step 18.a.
         RootedValue bufferCtor(cx);
         if (!GetSpeciesConstructor(cx, srcData, isWrapped, &bufferCtor))
             return nullptr;
 
         // Step 18.b.
-        if (!AllocateArrayBuffer(cx, bufferCtor, elementLength, &buffer))
+        if (!AllocateArrayBuffer(cx, bufferCtor, byteLength, &buffer))
             return nullptr;
 
         // Step 18.c.
         if (srcArray->hasDetachedBuffer()) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
             return nullptr;
         }
     }
@@ -986,17 +990,22 @@ TypedArrayObjectTemplate<T>::fromObject(
 {
     RootedObject proto(cx);
     Rooted<ArrayBufferObject*> buffer(cx);
     uint32_t len;
     if (!GetLengthProperty(cx, other, &len))
         return nullptr;
     if (!GetPrototypeForInstance(cx, newTarget, &proto))
         return nullptr;
-    if (!maybeCreateArrayBuffer(cx, len, nullptr, &buffer))
+    if (len >= INT32_MAX / BYTES_PER_ELEMENT) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
+                             JSMSG_NEED_DIET, "size and count");
+        return nullptr;
+    }
+    if (!maybeCreateArrayBuffer(cx, len * BYTES_PER_ELEMENT, nullptr, &buffer))
         return nullptr;
 
     Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, len, proto));
     if (!obj)
         return nullptr;
 
     if (!TypedArrayMethods<TypedArrayObject>::setFromNonTypedArray(cx, obj, other, len))
         return nullptr;
--- a/js/src/vm/UbiNode.cpp
+++ b/js/src/vm/UbiNode.cpp
@@ -50,18 +50,16 @@ using JS::ubi::EdgeRange;
 using JS::ubi::Node;
 using JS::ubi::EdgeVector;
 using JS::ubi::StackFrame;
 using JS::ubi::TracerConcrete;
 using JS::ubi::TracerConcreteWithCompartment;
 
 struct CopyToBufferMatcher
 {
-    using ReturnType = size_t;
-
     RangedPtr<char16_t> destination;
     size_t              maxLength;
 
     CopyToBufferMatcher(RangedPtr<char16_t> destination, size_t maxLength)
       : destination(destination)
       , maxLength(maxLength)
     { }
 
@@ -103,18 +101,16 @@ size_t
 JS::ubi::AtomOrTwoByteChars::copyToBuffer(RangedPtr<char16_t> destination, size_t length)
 {
     CopyToBufferMatcher m(destination, length);
     return match(m);
 }
 
 struct LengthMatcher
 {
-    using ReturnType = size_t;
-
     size_t
     match(JSAtom* atom)
     {
         return atom ? atom->length() : 0;
     }
 
     size_t
     match(const char16_t* chars)
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1108,17 +1108,16 @@ class Watchdog
     bool mShuttingDown;
     mozilla::Atomic<int32_t> mMinScriptRunTimeSeconds;
 };
 
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #endif
 
-#define PREF_MAX_SCRIPT_RUN_TIME_CHILD "dom.max_child_script_run_time"
 #define PREF_MAX_SCRIPT_RUN_TIME_CONTENT "dom.max_script_run_time"
 #define PREF_MAX_SCRIPT_RUN_TIME_CHROME "dom.max_chrome_script_run_time"
 
 class WatchdogManager : public nsIObserver
 {
   public:
 
     NS_DECL_ISUPPORTS
@@ -1131,31 +1130,29 @@ class WatchdogManager : public nsIObserv
 
         // Enable the watchdog, if appropriate.
         RefreshWatchdog();
 
         // Register ourselves as an observer to get updates on the pref.
         mozilla::Preferences::AddStrongObserver(this, "dom.use_watchdog");
         mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CONTENT);
         mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHROME);
-        mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHILD);
     }
 
   protected:
 
     virtual ~WatchdogManager()
     {
         // Shutting down the watchdog requires context-switching to the watchdog
         // thread, which isn't great to do in a destructor. So we require
         // consumers to shut it down manually before releasing it.
         MOZ_ASSERT(!mWatchdog);
         mozilla::Preferences::RemoveObserver(this, "dom.use_watchdog");
         mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CONTENT);
         mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHROME);
-        mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHILD);
     }
 
   public:
 
     NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
                        const char16_t* aData) override
     {
         RefreshWatchdog();
@@ -1223,20 +1220,17 @@ class WatchdogManager : public nsIObserv
 
         if (mWatchdog) {
             int32_t contentTime = Preferences::GetInt(PREF_MAX_SCRIPT_RUN_TIME_CONTENT, 10);
             if (contentTime <= 0)
                 contentTime = INT32_MAX;
             int32_t chromeTime = Preferences::GetInt(PREF_MAX_SCRIPT_RUN_TIME_CHROME, 20);
             if (chromeTime <= 0)
                 chromeTime = INT32_MAX;
-            int32_t childTime = Preferences::GetInt(PREF_MAX_SCRIPT_RUN_TIME_CHILD, 3);
-            if (childTime <= 0)
-                childTime = INT32_MAX;
-            mWatchdog->SetMinScriptRunTimeSeconds(std::min(std::min(contentTime, chromeTime), childTime));
+            mWatchdog->SetMinScriptRunTimeSeconds(std::min(contentTime, chromeTime));
         }
     }
 
     void StartWatchdog()
     {
         MOZ_ASSERT(!mWatchdog);
         mWatchdog = new Watchdog(this);
         mWatchdog->Init();
@@ -1374,26 +1368,23 @@ XPCJSRuntime::InterruptCallback(JSContex
         return true;
     }
 
     // Sometimes we get called back during XPConnect initialization, before Gecko
     // has finished bootstrapping. Avoid crashing in nsContentUtils below.
     if (!nsContentUtils::IsInitialized())
         return true;
 
-    bool contentProcess = XRE_IsContentProcess();
-
     // This is at least the second interrupt callback we've received since
     // returning to the event loop. See how long it's been, and what the limit
     // is.
     TimeDuration duration = TimeStamp::NowLoRes() - self->mSlowScriptCheckpoint;
     bool chrome = nsContentUtils::IsCallerChrome();
-    const char* prefName = contentProcess ? PREF_MAX_SCRIPT_RUN_TIME_CHILD
-                                 : chrome ? PREF_MAX_SCRIPT_RUN_TIME_CHROME
-                                          : PREF_MAX_SCRIPT_RUN_TIME_CONTENT;
+    const char* prefName = chrome ? PREF_MAX_SCRIPT_RUN_TIME_CHROME
+                                  : PREF_MAX_SCRIPT_RUN_TIME_CONTENT;
     int32_t limit = Preferences::GetInt(prefName, chrome ? 20 : 10);
 
     // If there's no limit, or we're within the limit, let it go.
     if (limit == 0 || duration.ToSeconds() < limit / 2.0)
         return true;
 
     // In order to guard against time changes or laptops going to sleep, we
     // don't trigger the slow script warning until (limit/2) seconds have
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -534,17 +534,23 @@ https://bugzilla.mozilla.org/show_bug.cg
     // |own| data property. So we add it to the ignore list here, and check it
     // separately.
     //
     // |Symbol.unscopables| should in principle be exposed, but it is
     // inconvenient (as it's a data property, unsupported by ClassSpec) and
     // low value.
     let propsToSkip = ['length', Symbol.unscopables];
 
-    testXray('Array', new iwin.Array(20), new iwin.Array(), propsToSkip);
+    // On the constructor, we want to skip all the non-standard "generic"
+    // functions.  We're trying to remove them anyway; no point doing extra work
+    // to expose them over Xrays.
+    let ctorPropsToSkip = ["join", "reverse", "sort", "push", "pop", "shift",
+                           "unshift", "splice", "slice"];
+    testXray('Array', new iwin.Array(20), new iwin.Array(), propsToSkip,
+             ctorPropsToSkip);
 
     let symbolProps = '';
     uniqueSymbol = iwin.eval('var uniqueSymbol = Symbol("uniqueSymbol"); uniqueSymbol');
     symbolProps = `trickyArray[uniqueSymbol] = 43;
                    trickyArray[Symbol.for("registrySymbolProp")] = 44;`;
     var trickyArray =
       iwin.eval(`var trickyArray = [];
                  trickyArray.primitiveProp = 42;
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -2152,17 +2152,17 @@ nsPresContext::EnsureSafeToHandOutCSSRul
     // Nothing to do.
     return;
   }
 
   RebuildAllStyleData(nsChangeHint(0), eRestyle_Subtree);
 }
 
 void
-nsPresContext::FireDOMPaintEvent(nsInvalidateRequestList* aList)
+nsPresContext::FireDOMPaintEvent(nsInvalidateRequestList* aList, uint64_t aTransactionId)
 {
   nsPIDOMWindowInner* ourWindow = mDocument->GetInnerWindow();
   if (!ourWindow)
     return;
 
   nsCOMPtr<EventTarget> dispatchTarget = do_QueryInterface(ourWindow);
   nsCOMPtr<EventTarget> eventTarget = dispatchTarget;
   if (!IsChrome() && !mSendAfterPaintToContent) {
@@ -2177,17 +2177,17 @@ nsPresContext::FireDOMPaintEvent(nsInval
   }
   // Events sent to the window get propagated to the chrome event handler
   // automatically.
   //
   // This will empty our list in case dispatching the event causes more damage
   // (hopefully it won't, or we're likely to get an infinite loop! At least
   // it won't be blocking app execution though).
   RefPtr<NotifyPaintEvent> event =
-    NS_NewDOMNotifyPaintEvent(eventTarget, this, nullptr, eAfterPaint, aList);
+    NS_NewDOMNotifyPaintEvent(eventTarget, this, nullptr, eAfterPaint, aList, aTransactionId);
 
   // Even if we're not telling the window about the event (so eventTarget is
   // the chrome event handler, not the window), the window is still
   // logically the event target.
   event->SetTarget(eventTarget);
   event->SetTrusted(true);
   EventDispatcher::DispatchDOMEvent(dispatchTarget, nullptr,
                                     static_cast<Event*>(event), this, nullptr);
@@ -2374,62 +2374,67 @@ nsPresContext::SetNotifySubDocInvalidati
 /* static */ void
 nsPresContext::ClearNotifySubDocInvalidationData(ContainerLayer* aContainer)
 {
   aContainer->SetUserData(&gNotifySubDocInvalidationData, nullptr);
 }
 
 struct NotifyDidPaintSubdocumentCallbackClosure {
   uint32_t mFlags;
+  uint64_t mTransactionId;
   bool mNeedsAnotherDidPaintNotification;
 };
 static bool
 NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
 {
   NotifyDidPaintSubdocumentCallbackClosure* closure =
     static_cast<NotifyDidPaintSubdocumentCallbackClosure*>(aData);
   nsIPresShell* shell = aDocument->GetShell();
   if (shell) {
     nsPresContext* pc = shell->GetPresContext();
     if (pc) {
-      pc->NotifyDidPaintForSubtree(closure->mFlags);
+      pc->NotifyDidPaintForSubtree(closure->mFlags, closure->mTransactionId);
       if (pc->IsDOMPaintEventPending()) {
         closure->mNeedsAnotherDidPaintNotification = true;
       }
     }
   }
   return true;
 }
 
 class DelayedFireDOMPaintEvent : public nsRunnable {
 public:
   DelayedFireDOMPaintEvent(nsPresContext* aPresContext,
-                           nsInvalidateRequestList* aList)
+                           nsInvalidateRequestList* aList,
+                           uint64_t aTransactionId)
     : mPresContext(aPresContext)
+    , mTransactionId(aTransactionId)
   {
     MOZ_ASSERT(mPresContext->GetContainerWeak(),
                "DOMPaintEvent requested for a detached pres context");
     mList.TakeFrom(aList);
   }
   NS_IMETHOD Run() override
   {
     // The pres context might have been detached during the delay -
     // that's fine, just don't fire the event.
     if (mPresContext->GetContainerWeak()) {
-      mPresContext->FireDOMPaintEvent(&mList);
+      mPresContext->FireDOMPaintEvent(&mList, mTransactionId);
     }
     return NS_OK;
   }
 
   RefPtr<nsPresContext> mPresContext;
+  uint64_t mTransactionId;
   nsInvalidateRequestList mList;
 };
 
 void
-nsPresContext::NotifyDidPaintForSubtree(uint32_t aFlags)
+nsPresContext::NotifyDidPaintForSubtree(uint32_t aFlags, uint64_t aTransactionId,
+                                        const mozilla::TimeStamp& aTimeStamp)
 {
   if (IsRoot()) {
     static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
 
     if (!mFireAfterPaintEvents) {
       return;
     }
   }
@@ -2446,21 +2451,22 @@ nsPresContext::NotifyDidPaintForSubtree(
 
   if (aFlags & nsIPresShell::PAINT_LAYERS) {
     mUndeliveredInvalidateRequestsBeforeLastPaint.TakeFrom(
         &mInvalidateRequestsSinceLastPaint);
     mAllInvalidated = false;
   }
   if (aFlags & nsIPresShell::PAINT_COMPOSITE) {
     nsCOMPtr<nsIRunnable> ev =
-      new DelayedFireDOMPaintEvent(this, &mUndeliveredInvalidateRequestsBeforeLastPaint);
+      new DelayedFireDOMPaintEvent(this, &mUndeliveredInvalidateRequestsBeforeLastPaint,
+                                   aTransactionId);
     nsContentUtils::AddScriptRunner(ev);
   }
 
-  NotifyDidPaintSubdocumentCallbackClosure closure = { aFlags, false };
+  NotifyDidPaintSubdocumentCallbackClosure closure = { aFlags, aTransactionId, false };
   mDocument->EnumerateSubDocuments(NotifyDidPaintSubdocumentCallback, &closure);
 
   if (!closure.mNeedsAnotherDidPaintNotification &&
       mInvalidateRequestsSinceLastPaint.IsEmpty() &&
       mUndeliveredInvalidateRequestsBeforeLastPaint.IsEmpty()) {
     // Nothing more to do for the moment.
     mFireAfterPaintEvents = false;
   } else {
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -921,18 +921,19 @@ public:
   // and, if necessary, synchronously rebuilding all style data.
   void EnsureSafeToHandOutCSSRules();
 
   void NotifyInvalidation(uint32_t aFlags);
   void NotifyInvalidation(const nsRect& aRect, uint32_t aFlags);
   // aRect is in device pixels
   void NotifyInvalidation(const nsIntRect& aRect, uint32_t aFlags);
   // aFlags are nsIPresShell::PAINT_ flags
-  void NotifyDidPaintForSubtree(uint32_t aFlags);
-  void FireDOMPaintEvent(nsInvalidateRequestList* aList);
+  void NotifyDidPaintForSubtree(uint32_t aFlags, uint64_t aTransactionId = 0,
+                                const mozilla::TimeStamp& aTimeStamp = mozilla::TimeStamp());
+  void FireDOMPaintEvent(nsInvalidateRequestList* aList, uint64_t aTransactionId);
 
   // Callback for catching invalidations in ContainerLayers
   // Passed to LayerProperties::ComputeDifference
   static void NotifySubDocInvalidation(mozilla::layers::ContainerLayer* aContainer,
                                        const nsIntRegion& aRegion);
   void SetNotifySubDocInvalidationData(mozilla::layers::ContainerLayer* aContainer);
   static void ClearNotifySubDocInvalidationData(mozilla::layers::ContainerLayer* aContainer);
   bool IsDOMPaintEventPending();
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -2002,16 +2002,22 @@ nsRefreshDriver::GetTransactionId()
       !mTestControllingRefreshes) {
     mWaitingForTransaction = true;
     mSkippedPaints = false;
   }
 
   return mPendingTransaction;
 }
 
+uint64_t
+nsRefreshDriver::LastTransactionId() const
+{
+  return mPendingTransaction;
+}
+
 void
 nsRefreshDriver::RevokeTransactionId(uint64_t aTransactionId)
 {
   MOZ_ASSERT(aTransactionId == mPendingTransaction);
   if (mPendingTransaction == mCompletedTransaction + 2 &&
       mWaitingForTransaction) {
     MOZ_ASSERT(!mSkippedPaints, "How did we skip a paint when we're in the middle of one?");
     FinishedWaitingForTransaction();
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -314,17 +314,18 @@ public:
    * time.
    *
    * Return `false` if `aJank` needs to be grown to accomodate the
    * data but we didn't have enough memory.
    */
   static bool GetJankLevels(mozilla::Vector<uint64_t>& aJank);
 
   // mozilla::layers::TransactionIdAllocator
-  virtual uint64_t GetTransactionId() override;
+  uint64_t GetTransactionId() override;
+  uint64_t LastTransactionId() const override;
   void NotifyTransactionCompleted(uint64_t aTransactionId) override;
   void RevokeTransactionId(uint64_t aTransactionId) override;
   mozilla::TimeStamp GetTransactionStart() override;
 
   bool IsWaitingForPaint(mozilla::TimeStamp aTime);
 
   // nsARefreshObserver
   NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override { return TransactionIdAllocator::AddRef(); }
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -578,16 +578,19 @@ private:
     const StyleAnimation& aStyleAnimation)
   {
     TimingParams timing;
 
     timing.mDuration.emplace(StickyTimeDuration::FromMilliseconds(
 			       aStyleAnimation.GetDuration()));
     timing.mDelay = TimeDuration::FromMilliseconds(aStyleAnimation.GetDelay());
     timing.mIterations = aStyleAnimation.GetIterationCount();
+    MOZ_ASSERT(timing.mIterations >= 0.0 && !IsNaN(timing.mIterations),
+               "mIterations should be nonnegative & finite, as ensured by "
+               "CSSParser");
     timing.mDirection = aStyleAnimation.GetDirection();
     timing.mFill = aStyleAnimation.GetFillMode();
 
     return timing;
   }
 
   RefPtr<nsStyleContext> mStyleContext;
   RefPtr<dom::Element> mTarget;
--- a/layout/tools/reftest/bootstrap.js
+++ b/layout/tools/reftest/bootstrap.js
@@ -39,26 +39,31 @@ function startup(data, reason) {
   }
 
   if (Services.appinfo.OS == "Android") {
     Cm.addBootstrappedManifestLocation(data.installPath);
     Services.wm.addListener(WindowListener);
     return;
   }
 
+  let orig = Services.wm.getMostRecentWindow("navigator:browser");
+
   let ios = Cc["@mozilla.org/network/io-service;1"]
             .getService(Ci.nsIIOService2);
   ios.manageOfflineStatus = false;
   ios.offline = false;
 
   let wwatch = Cc["@mozilla.org/embedcomp/window-watcher;1"]
                 .getService(Ci.nsIWindowWatcher);
   let dummy = wwatch.openWindow(null, "about:blank", "dummy",
                                 "chrome,dialog=no,left=800,height=200,width=200,all",null);
   dummy.onload = function() {
+    // Close pre-existing window
+    orig.close();
+
     dummy.focus();
     wwatch.openWindow(null, "chrome://reftest/content/reftest.xul", "_blank",
                       "chrome,dialog=no,all", {});
   };
 }
 
 function shutdown(data, reason) {
   if (Services.appinfo.widgetToolkit == "gonk") {
--- a/media/ffvpx/ffvpxcommon.mozbuild
+++ b/media/ffvpx/ffvpxcommon.mozbuild
@@ -45,18 +45,18 @@ if CONFIG['GNU_CC']:
         '-Wno-unused-function',
         '-Wno-deprecated-declarations',
     ]
     if CONFIG['CLANG_CXX']:
         CFLAGS += [
             '-Wno-incompatible-pointer-types-discards-qualifiers',
             '-Wno-logical-op-parentheses',
         ]
-    # Force visibility of cpu symbols
-    CFLAGS += ['-include', 'cpu_perms.h']
+    # Force visibility of cpu and av_log symbols.
+    CFLAGS += ['-include', 'libavutil_visibility.h']
 elif CONFIG['_MSC_VER']:
     CFLAGS += [
         '-wd4090', # 'return' : different 'const' qualifiers
         '-wd4018', # '>' : signed/unsigned mismatch
         '-wd4305', # 'initializing' : truncation from '__int64' to 'double'
         '-wd4554', # '>>' : check operator precedence for possible error
         '-wd4307', # '+' : integral constant overflow'
         '-wd4028', # formal parameter 1 different from declaration
@@ -80,8 +80,15 @@ elif CONFIG['_MSC_VER']:
     ]
     if CONFIG['_MSC_VER'] < '1900':
         DEFINES['MSVC_2013_OR_LOWER'] = True
         DEFINES['snprintf'] = "avpriv_snprintf"
         DEFINES['_snprintf'] = "avpriv_snprintf"
         DEFINES['vsnprintf'] = "avpriv_vsnprintf"
 
 DEFINES['HAVE_AV_CONFIG_H'] = True
+
+if CONFIG['MOZ_DEBUG']:
+    # Enable all assertions in debug builds.
+    DEFINES['ASSERT_LEVEL'] = 2
+elif not CONFIG['RELEASE_BUILD']:
+    # Enable fast assertions in opt builds of Nightly and Aurora.
+    DEFINES['ASSERT_LEVEL'] = 1
rename from media/ffvpx/cpu_perms.h
rename to media/ffvpx/libavutil_visibility.h
--- a/media/ffvpx/cpu_perms.h
+++ b/media/ffvpx/libavutil_visibility.h
@@ -1,16 +1,20 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Include file for fixing symbol visibility on Linux.
 
-#ifndef MOZILLA_AVCPU_PERMS_H
-#define MOZILLA_AVCPU_PERMS_H
+#ifndef MOZILLA_AVUTIL_VISIBILITY_H
+#define MOZILLA_AVUTIL_VISIBILITY_H
 
 #pragma GCC visibility push(default)
 #include "libavutil/cpu.h"
+
+// We need av_log() to be visible so we can enable assertions in libavcodec.
+#include "libavutil/log.h"
+
 #pragma GCC visibility pop
 
-#endif // MOZILLA_AVCPU_PERMS_H
+#endif // MOZILLA_AVUTIL_VISIBILITY_H
--- a/media/libav/moz.build
+++ b/media/libav/moz.build
@@ -61,9 +61,16 @@ if CONFIG['_MSC_VER']:
 #
 # TODO: Remove header and patch libav once OS X supports system headers
 if CONFIG['OS_ARCH'] != 'WINNT':
     SOURCES['libavcodec/avfft.c'].flags += ['-include', 'avfft_perms.h']
 
 # We allow warnings for third-party code that can be updated from upstream.
 ALLOW_COMPILER_WARNINGS = True
 
+if CONFIG['MOZ_DEBUG']:
+    # Enable all assertions in debug builds.
+    DEFINES['ASSERT_LEVEL'] = 2
+elif not CONFIG['RELEASE_BUILD']:
+    # Enable fast assertions in opt builds of Nightly and Aurora.
+    DEFINES['ASSERT_LEVEL'] = 1
+
 include("libavcommon.mozbuild")
--- a/media/libstagefright/frameworks/av/include/media/stagefright/MetaData.h
+++ b/media/libstagefright/frameworks/av/include/media/stagefright/MetaData.h
@@ -132,16 +132,17 @@ enum {
     kKeyMediaLanguage     = 'lang',  // cstring
 
     // To store the timed text format data
     kKeyTextFormatData    = 'text',  // raw data
 
     kKeyRequiresSecureBuffers = 'secu',  // bool (int32_t)
 
     kKeyIsADTS            = 'adts',  // bool (int32_t)
+    kKeyAACAOT            = 'aaot',  // int32_t
 
     // If a MediaBuffer's data represents (at least partially) encrypted
     // data, the following fields aid in decryption.
     // The data can be thought of as pairs of plain and encrypted data
     // fragments, i.e. plain and encrypted data alternate.
     // The first fragment is by convention plain data (if that's not the
     // case, simply specify plain fragment size of 0).
     // kKeyEncryptedSizes and kKeyPlainSizes each map to an array of
--- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
@@ -2457,30 +2457,82 @@ status_t MPEG4Extractor::verifyTrack(Tra
         if (keysize > 16) {
             return ERROR_MALFORMED;
         }
     }
 
     return OK;
 }
 
+typedef enum {
+    //AOT_NONE             = -1,
+    //AOT_NULL_OBJECT      = 0,
+    //AOT_AAC_MAIN         = 1, /**< Main profile                              */
+    AOT_AAC_LC           = 2,   /**< Low Complexity object                     */
+    //AOT_AAC_SSR          = 3,
+    //AOT_AAC_LTP          = 4,
+    AOT_SBR              = 5,
+    //AOT_AAC_SCAL         = 6,
+    //AOT_TWIN_VQ          = 7,
+    //AOT_CELP             = 8,
+    //AOT_HVXC             = 9,
+    //AOT_RSVD_10          = 10, /**< (reserved)                                */
+    //AOT_RSVD_11          = 11, /**< (reserved)                                */
+    //AOT_TTSI             = 12, /**< TTSI Object                               */
+    //AOT_MAIN_SYNTH       = 13, /**< Main Synthetic object                     */
+    //AOT_WAV_TAB_SYNTH    = 14, /**< Wavetable Synthesis object                */
+    //AOT_GEN_MIDI         = 15, /**< General MIDI object                       */
+    //AOT_ALG_SYNTH_AUD_FX = 16, /**< Algorithmic Synthesis and Audio FX object */
+    AOT_ER_AAC_LC        = 17,   /**< Error Resilient(ER) AAC Low Complexity    */
+    //AOT_RSVD_18          = 18, /**< (reserved)                                */
+    //AOT_ER_AAC_LTP       = 19, /**< Error Resilient(ER) AAC LTP object        */
+    AOT_ER_AAC_SCAL      = 20,   /**< Error Resilient(ER) AAC Scalable object   */
+    //AOT_ER_TWIN_VQ       = 21, /**< Error Resilient(ER) TwinVQ object         */
+    AOT_ER_BSAC          = 22,   /**< Error Resilient(ER) BSAC object           */
+    AOT_ER_AAC_LD        = 23,   /**< Error Resilient(ER) AAC LowDelay object   */
+    //AOT_ER_CELP          = 24, /**< Error Resilient(ER) CELP object           */
+    //AOT_ER_HVXC          = 25, /**< Error Resilient(ER) HVXC object           */
+    //AOT_ER_HILN          = 26, /**< Error Resilient(ER) HILN object           */
+    //AOT_ER_PARA          = 27, /**< Error Resilient(ER) Parametric object     */
+    //AOT_RSVD_28          = 28, /**< might become SSC                          */
+    AOT_PS               = 29,   /**< PS, Parametric Stereo (includes SBR)      */
+    //AOT_MPEGS            = 30, /**< MPEG Surround                             */
+
+    AOT_ESCAPE           = 31,   /**< Signal AOT uses more than 5 bits          */
+
+    //AOT_MP3ONMP4_L1      = 32, /**< MPEG-Layer1 in mp4                        */
+    //AOT_MP3ONMP4_L2      = 33, /**< MPEG-Layer2 in mp4                        */
+    //AOT_MP3ONMP4_L3      = 34, /**< MPEG-Layer3 in mp4                        */
+    //AOT_RSVD_35          = 35, /**< might become DST                          */
+    //AOT_RSVD_36          = 36, /**< might become ALS                          */
+    //AOT_AAC_SLS          = 37, /**< AAC + SLS                                 */
+    //AOT_SLS              = 38, /**< SLS                                       */
+    //AOT_ER_AAC_ELD       = 39, /**< AAC Enhanced Low Delay                    */
+
+    //AOT_USAC             = 42, /**< USAC                                      */
+    //AOT_SAOC             = 43, /**< SAOC                                      */
+    //AOT_LD_MPEGS         = 44, /**< Low Delay MPEG Surround                   */
+
+    //AOT_RSVD50           = 50,  /**< Interim AOT for Rsvd50                   */
+} AUDIO_OBJECT_TYPE;
+
 status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
         const void *esds_data, size_t esds_size) {
     ESDS esds(esds_data, esds_size);
 
     uint8_t objectTypeIndication;
     if (esds.getObjectTypeIndication(&objectTypeIndication) != OK) {
         return ERROR_MALFORMED;
     }
 
     if (objectTypeIndication == 0xe1) {
         // This isn't MPEG4 audio at all, it's QCELP 14k...
-        if (!mLastTrack) {
-          return ERROR_MALFORMED;
-        }
+        if (mLastTrack == NULL)
+            return ERROR_MALFORMED;
+
         mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_QCELP);
         return OK;
     }
 
     if (objectTypeIndication  == 0x6b || objectTypeIndication  == 0x69) {
         // The media subtype is MP3 audio
         if (!mLastTrack) {
           return ERROR_MALFORMED;
@@ -2491,111 +2543,253 @@ status_t MPEG4Extractor::updateAudioTrac
     const uint8_t *csd;
     size_t csd_size;
     if (esds.getCodecSpecificInfo(
                 (const void **)&csd, &csd_size) != OK) {
         return ERROR_MALFORMED;
     }
 
 #if 0
-    printf("ESD of size %d\n", csd_size);
-    hexdump(csd, csd_size);
+    if (kUseHexDump) {
+        printf("ESD of size %zu\n", csd_size);
+        hexdump(csd, csd_size);
+    }
 #endif
 
     if (csd_size == 0) {
         // There's no further information, i.e. no codec specific data
         // Let's assume that the information provided in the mpeg4 headers
         // is accurate and hope for the best.
 
         return OK;
     }
 
     if (csd_size < 2) {
         return ERROR_MALFORMED;
     }
 
+    static uint32_t kSamplingRate[] = {
+        96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+        16000, 12000, 11025, 8000, 7350
+    };
+
     ABitReader br(csd, csd_size);
     if (br.numBitsLeft() < 5) {
         return ERROR_MALFORMED;
     }
     uint32_t objectType = br.getBits(5);
 
     if (objectType == 31) {  // AAC-ELD => additional 6 bits
         if (br.numBitsLeft() < 6) {
             return ERROR_MALFORMED;
         }
         objectType = 32 + br.getBits(6);
     }
 
+    if (mLastTrack == NULL)
+        return ERROR_MALFORMED;
+
     if (objectType >= 1 && objectType <= 4) {
-        if (!mLastTrack) {
-          return ERROR_MALFORMED;
-        }
         mLastTrack->meta->setInt32(kKeyAACProfile, objectType);
     }
 
+    //keep AOT type
+    mLastTrack->meta->setInt32(kKeyAACAOT, objectType);
+
     if (br.numBitsLeft() < 4) {
         return ERROR_MALFORMED;
     }
     uint32_t freqIndex = br.getBits(4);
 
     int32_t sampleRate = 0;
     int32_t numChannels = 0;
     if (freqIndex == 15) {
-        if (csd_size < 5) {
-            return ERROR_MALFORMED;
-        }
-        if (br.numBitsLeft() < 24 + 4) {
-            return ERROR_MALFORMED;
-        }
+        if (br.numBitsLeft() < 28) return ERROR_MALFORMED;
         sampleRate = br.getBits(24);
         numChannels = br.getBits(4);
     } else {
-        if (br.numBitsLeft() < 4) {
+        if (br.numBitsLeft() < 4) return ERROR_MALFORMED;
+        numChannels = br.getBits(4);
+
+        if (freqIndex == 13 || freqIndex == 14) {
             return ERROR_MALFORMED;
         }
-        numChannels = br.getBits(4);
-        if (objectType == 5) {
-            // SBR specific config per 14496-3 table 1.13
-            if (br.numBitsLeft() < 4) {
+
+        sampleRate = kSamplingRate[freqIndex];
+    }
+
+    if (objectType == AOT_SBR || objectType == AOT_PS) {//SBR specific config per 14496-3 table 1.13
+        if (br.numBitsLeft() < 4) return ERROR_MALFORMED;
+        uint32_t extFreqIndex = br.getBits(4);
+        int32_t extSampleRate;
+        if (extFreqIndex == 15) {
+            if (csd_size < 8) {
+                return ERROR_MALFORMED;
+            }
+            if (br.numBitsLeft() < 24) return ERROR_MALFORMED;
+            extSampleRate = br.getBits(24);
+        } else {
+            if (extFreqIndex == 13 || extFreqIndex == 14) {
                 return ERROR_MALFORMED;
             }
-            freqIndex = br.getBits(4);
-            if (freqIndex == 15) {
-                if (csd_size < 8) {
+            extSampleRate = kSamplingRate[extFreqIndex];
+        }
+        //TODO: save the extension sampling rate value in meta data =>
+        //      mLastTrack->meta->setInt32(kKeyExtSampleRate, extSampleRate);
+    }
+
+    switch (numChannels) {
+        // values defined in 14496-3_2009 amendment-4 Table 1.19 - Channel Configuration
+        case 0:
+        case 1:// FC
+        case 2:// FL FR
+        case 3:// FC, FL FR
+        case 4:// FC, FL FR, RC
+        case 5:// FC, FL FR, SL SR
+        case 6:// FC, FL FR, SL SR, LFE
+            //numChannels already contains the right value
+            break;
+        case 11:// FC, FL FR, SL SR, RC, LFE
+            numChannels = 7;
+            break;
+        case 7: // FC, FCL FCR, FL FR, SL SR, LFE
+        case 12:// FC, FL  FR,  SL SR, RL RR, LFE
+        case 14:// FC, FL  FR,  SL SR, LFE, FHL FHR
+            numChannels = 8;
+            break;
+        default:
+            return ERROR_UNSUPPORTED;
+    }
+
+    {
+        if (objectType == AOT_SBR || objectType == AOT_PS) {
+            if (br.numBitsLeft() < 5) return ERROR_MALFORMED;
+            objectType = br.getBits(5);
+
+            if (objectType == AOT_ESCAPE) {
+                if (br.numBitsLeft() < 6) return ERROR_MALFORMED;
+                objectType = 32 + br.getBits(6);
+            }
+        }
+        if (objectType == AOT_AAC_LC || objectType == AOT_ER_AAC_LC ||
+                objectType == AOT_ER_AAC_LD || objectType == AOT_ER_AAC_SCAL ||
+                objectType == AOT_ER_BSAC) {
+            if (br.numBitsLeft() < 2) return ERROR_MALFORMED;
+            const int32_t frameLengthFlag = br.getBits(1);
+
+            const int32_t dependsOnCoreCoder = br.getBits(1);
+
+            if (dependsOnCoreCoder ) {
+                if (br.numBitsLeft() < 14) return ERROR_MALFORMED;
+                const int32_t coreCoderDelay = br.getBits(14);
+            }
+
+            int32_t extensionFlag = -1;
+            if (br.numBitsLeft() > 0) {
+                extensionFlag = br.getBits(1);
+            } else {
+                switch (objectType) {
+                // 14496-3 4.5.1.1 extensionFlag
+                case AOT_AAC_LC:
+                    extensionFlag = 0;
+                    break;
+                case AOT_ER_AAC_LC:
+                case AOT_ER_AAC_SCAL:
+                case AOT_ER_BSAC:
+                case AOT_ER_AAC_LD:
+                    extensionFlag = 1;
+                    break;
+                default:
+                    return ERROR_MALFORMED;
+                    break;
+                }
+                ALOGW("csd missing extension flag; assuming %d for object type %u.",
+                        extensionFlag, objectType);
+            }
+
+            if (numChannels == 0) {
+                int32_t channelsEffectiveNum = 0;
+                int32_t channelsNum = 0;
+                if (br.numBitsLeft() < 32) {
                     return ERROR_MALFORMED;
                 }
-                if (br.numBitsLeft() < 24) {
-                    return ERROR_MALFORMED;
+                const int32_t ElementInstanceTag = br.getBits(4);
+                const int32_t Profile = br.getBits(2);
+                const int32_t SamplingFrequencyIndex = br.getBits(4);
+                const int32_t NumFrontChannelElements = br.getBits(4);
+                const int32_t NumSideChannelElements = br.getBits(4);
+                const int32_t NumBackChannelElements = br.getBits(4);
+                const int32_t NumLfeChannelElements = br.getBits(2);
+                const int32_t NumAssocDataElements = br.getBits(3);
+                const int32_t NumValidCcElements = br.getBits(4);
+
+                const int32_t MonoMixdownPresent = br.getBits(1);
+
+                if (MonoMixdownPresent != 0) {
+                    if (br.numBitsLeft() < 4) return ERROR_MALFORMED;
+                    const int32_t MonoMixdownElementNumber = br.getBits(4);
+                }
+
+                if (br.numBitsLeft() < 1) return ERROR_MALFORMED;
+                const int32_t StereoMixdownPresent = br.getBits(1);
+                if (StereoMixdownPresent != 0) {
+                    if (br.numBitsLeft() < 4) return ERROR_MALFORMED;
+                    const int32_t StereoMixdownElementNumber = br.getBits(4);
+                }
+
+                if (br.numBitsLeft() < 1) return ERROR_MALFORMED;
+                const int32_t MatrixMixdownIndexPresent = br.getBits(1);
+                if (MatrixMixdownIndexPresent != 0) {
+                    if (br.numBitsLeft() < 3) return ERROR_MALFORMED;
+                    const int32_t MatrixMixdownIndex = br.getBits(2);
+                    const int32_t PseudoSurroundEnable = br.getBits(1);
                 }
-                sampleRate = br.getBits(24);
+
+                int i;
+                for (i=0; i < NumFrontChannelElements; i++) {
+                    if (br.numBitsLeft() < 5) return ERROR_MALFORMED;
+                    const int32_t FrontElementIsCpe = br.getBits(1);
+                    const int32_t FrontElementTagSelect = br.getBits(4);
+                    channelsNum += FrontElementIsCpe ? 2 : 1;
+                }
+
+                for (i=0; i < NumSideChannelElements; i++) {
+                    if (br.numBitsLeft() < 5) return ERROR_MALFORMED;
+                    const int32_t SideElementIsCpe = br.getBits(1);
+                    const int32_t SideElementTagSelect = br.getBits(4);
+                    channelsNum += SideElementIsCpe ? 2 : 1;
+                }
+
+                for (i=0; i < NumBackChannelElements; i++) {
+                    if (br.numBitsLeft() < 5) return ERROR_MALFORMED;
+                    const int32_t BackElementIsCpe = br.getBits(1);
+                    const int32_t BackElementTagSelect = br.getBits(4);
+                    channelsNum += BackElementIsCpe ? 2 : 1;
+                }
+                channelsEffectiveNum = channelsNum;
+
+                for (i=0; i < NumLfeChannelElements; i++) {
+                    if (br.numBitsLeft() < 4) return ERROR_MALFORMED;
+                    const int32_t LfeElementTagSelect = br.getBits(4);
+                    channelsNum += 1;
+                }
+                ALOGV("mpeg4 audio channelsNum = %d", channelsNum);
+                ALOGV("mpeg4 audio channelsEffectiveNum = %d", channelsEffectiveNum);
+                numChannels = channelsNum;
             }
         }
-
-        if (sampleRate == 0) {
-            static uint32_t kSamplingRate[] = {
-                96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
-                16000, 12000, 11025, 8000, 7350
-            };
-
-            if (freqIndex == 13 || freqIndex == 14) {
-                return ERROR_MALFORMED;
-            }
-
-            sampleRate = kSamplingRate[freqIndex];
-        }
     }
 
     if (numChannels == 0) {
         return ERROR_UNSUPPORTED;
     }
 
-    if (!mLastTrack) {
-      return ERROR_MALFORMED;
-    }
+    if (mLastTrack == NULL)
+        return ERROR_MALFORMED;
+
     int32_t prevSampleRate;
     CHECK(mLastTrack->meta->findInt32(kKeySampleRate, &prevSampleRate));
 
     if (prevSampleRate != sampleRate) {
         ALOGV("mpeg4 audio sample rate different from previous setting. "
              "was: %d, now: %d", prevSampleRate, sampleRate);
     }
 
--- a/media/webrtc/signaling/test/FakeMediaStreamsImpl.h
+++ b/media/webrtc/signaling/test/FakeMediaStreamsImpl.h
@@ -116,17 +116,17 @@ void Fake_AudioStreamSource::Periodic() 
   }
 
   mozilla::AudioSegment segment;
   AutoTArray<const int16_t *,1> channels;
   channels.AppendElement(data);
   segment.AppendFrames(samples.forget(),
                        channels,
                        AUDIO_BUFFER_SIZE,
-                       mozilla::PRINCIPAL_HANDLE_NONE);
+                       PRINCIPAL_HANDLE_NONE);
 
   for(std::set<RefPtr<Fake_MediaStreamListener>>::iterator it = mListeners.begin();
        it != mListeners.end(); ++it) {
     (*it)->NotifyQueuedTrackChanges(nullptr, // Graph
                                     0, // TrackID
                                     0, // Offset TODO(ekr@rtfm.com) fix
                                     0, // ???
                                     segment,
--- a/mfbt/Variant.h
+++ b/mfbt/Variant.h
@@ -164,20 +164,21 @@ struct VariantImplementation<N, T> {
   }
 
   template<typename Variant>
   static bool
   equal(const Variant& aLhs, const Variant& aRhs) {
       return aLhs.template as<T>() == aRhs.template as<T>();
   }
 
-  template<typename Matcher, typename ConcreteVariant,
-           typename ReturnType = typename RemoveReference<Matcher>::Type::ReturnType>
-  static ReturnType
-  match(Matcher&& aMatcher, ConcreteVariant& aV) {
+  template<typename Matcher, typename ConcreteVariant>
+  static auto
+  match(Matcher&& aMatcher, ConcreteVariant& aV)
+    -> decltype(aMatcher.match(aV.template as<T>()))
+  {
     return aMatcher.match(aV.template as<T>());
   }
 };
 
 // VariantImplementation for some variant type T.
 template<size_t N, typename T, typename... Ts>
 struct VariantImplementation<N, T, Ts...>
 {
@@ -221,34 +222,34 @@ struct VariantImplementation<N, T, Ts...
     if (aLhs.template is<T>()) {
       MOZ_ASSERT(aRhs.template is<T>());
       return aLhs.template as<T>() == aRhs.template as<T>();
     } else {
       return Next::equal(aLhs, aRhs);
     }
   }
 
-  template<typename Matcher, typename ConcreteVariant,
-           typename ReturnType = typename RemoveReference<Matcher>::Type::ReturnType>
-  static ReturnType
+  template<typename Matcher, typename ConcreteVariant>
+  static auto
   match(Matcher&& aMatcher, ConcreteVariant& aV)
+    -> decltype(aMatcher.match(aV.template as<T>()))
   {
     if (aV.template is<T>()) {
       return aMatcher.match(aV.template as<T>());
     } else {
       // If you're seeing compilation errors here like "no matching
       // function for call to 'match'" then that means that the
       // Matcher doesn't exhaust all variant types. There must exist a
       // Matcher::match(T&) for every variant type T.
       //
       // If you're seeing compilation errors here like "cannot
       // initialize return object of type <...> with an rvalue of type
       // <...>" then that means that the Matcher::match(T&) overloads
       // are returning different types. They must all return the same
-      // Matcher::ReturnType type.
+      // type.
       return Next::match(aMatcher, aV);
     }
   }
 };
 
 /**
  * AsVariantTemporary stores a value of type T to allow construction of a
  * Variant value via type inference. Because T is copied and there's no
@@ -365,21 +366,21 @@ struct AsVariantTemporary
  *       } else {
  *         return doSomething(v.as<C>()); // Forgot about case D!
  *       }
  *     }
  *
  *     // Good!
  *     struct FooMatcher
  *     {
- *       using ReturnType = char*;
- *       ReturnType match(A& a) { ... }
- *       ReturnType match(B& b) { ... }
- *       ReturnType match(C& c) { ... }
- *       ReturnType match(D& d) { ... } // Compile-time error to forget D!
+ *       // The return type of all matchers must be idential.
+ *       char* match(A& a) { ... }
+ *       char* match(B& b) { ... }
+ *       char* match(C& c) { ... }
+ *       char* match(D& d) { ... } // Compile-time error to forget D!
  *     }
  *     char* foo(Variant<A, B, C, D>& v) {
  *       return v.match(FooMatcher());
  *     }
  *
  * ## Examples
  *
  * A tree is either an empty leaf, or a node with a value and two children:
@@ -553,25 +554,25 @@ public:
     MOZ_ASSERT(is<T>());
     return T(Move(as<T>()));
   }
 
   // Exhaustive matching of all variant types on the contained value.
 
   /** Match on an immutable const reference. */
   template<typename Matcher>
-  typename RemoveReference<Matcher>::Type::ReturnType
-  match(Matcher&& aMatcher) const {
+  auto
+  match(Matcher&& aMatcher) const -> decltype(Impl::match(aMatcher, *this)) {
     return Impl::match(aMatcher, *this);
   }
 
   /** Match on a mutable non-const reference. */
   template<typename Matcher>
-  typename RemoveReference<Matcher>::Type::ReturnType
-  match(Matcher&& aMatcher) {
+  auto
+  match(Matcher&& aMatcher) -> decltype(Impl::match(aMatcher, *this)) {
     return Impl::match(aMatcher, *this);
   }
 };
 
 /*
  * AsVariant() is used to construct a Variant<T,...> value containing the
  * provided T value using type inference. It can be used to construct Variant
  * values in expressions or return them from functions without specifying the
--- a/mfbt/tests/TestVariant.cpp
+++ b/mfbt/tests/TestVariant.cpp
@@ -124,18 +124,16 @@ testEquality()
 }
 
 struct Describer
 {
   static const char* little;
   static const char* medium;
   static const char* big;
 
-  using ReturnType = const char*;
-
   const char* match(const uint8_t&) { return little; }
   const char* match(const uint32_t&) { return medium; }
   const char* match(const uint64_t&) { return big; }
 };
 
 const char* Describer::little = "little";
 const char* Describer::medium = "medium";
 const char* Describer::big = "big";
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -301,16 +301,18 @@
 @BINPATH@/components/nsSearchService.js
 @BINPATH@/components/nsSidebar.js
 @BINPATH@/components/passwordmgr.manifest
 @BINPATH@/components/nsLoginInfo.js
 @BINPATH@/components/nsLoginManager.js
 @BINPATH@/components/nsLoginManagerPrompter.js
 @BINPATH@/components/storage-mozStorage.js
 @BINPATH@/components/crypto-SDR.js
+@BINPATH@/components/TooltipTextProvider.js
+@BINPATH@/components/TooltipTextProvider.manifest
 @BINPATH@/components/NetworkGeolocationProvider.manifest
 @BINPATH@/components/NetworkGeolocationProvider.js
 @BINPATH@/components/extensions.manifest
 @BINPATH@/components/utils.manifest
 @BINPATH@/components/simpleServices.js
 @BINPATH@/components/addonManager.js
 @BINPATH@/components/amContentHandler.js
 @BINPATH@/components/amInstallTrigger.js
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2416,18 +2416,22 @@ pref("layout.css.unprefixing-service.glo
 #endif
 
 // Is support for the :scope selector enabled?
 pref("layout.css.scope-pseudo.enabled", true);
 
 // Is support for background-blend-mode enabled?
 pref("layout.css.background-blend-mode.enabled", true);
 
-// Is support for background-clip:text enabled? (bug 1263516)
+// Is support for background-clip:text enabled? (bug 1264905)
+#ifdef RELEASE_BUILD
 pref("layout.css.background-clip-text.enabled", false);
+#else
+pref("layout.css.background-clip-text.enabled", true);
+#endif
 
 // Is support for CSS vertical text enabled?
 pref("layout.css.vertical-text.enabled", true);
 
 // Is support for CSS text-combine-upright (tate-chu-yoko) enabled?
 pref("layout.css.text-combine-upright.enabled", false);
 
 // Is support for object-fit and object-position enabled?
@@ -2582,17 +2586,16 @@ pref("viewmanager.do_doublebuffering", t
 // enable single finger gesture input (win7+ tablets)
 pref("gestures.enable_single_finger_input", true);
 
 pref("editor.resizing.preserve_ratio",       true);
 pref("editor.positioning.offset",            0);
 
 pref("dom.use_watchdog", true);
 pref("dom.max_chrome_script_run_time", 20);
-pref("dom.max_child_script_run_time", 10);
 pref("dom.max_script_run_time", 10);
 
 // If true, ArchiveReader will be enabled
 pref("dom.archivereader.enabled", false);
 
 // Hang monitor timeout after which we kill the browser, in seconds
 // (0 is disabled)
 // Disabled on all platforms per bug 705748 until the found issues are
--- a/moz.build
+++ b/moz.build
@@ -47,38 +47,40 @@ if not CONFIG['JS_STANDALONE']:
 
     DIRS += [
         'build',
         'probes',
     ]
 
 DIRS += [
     'config/external/fdlibm',
+    'config/external/nspr',
     'config/external/zlib',
     'memory',
     'mfbt',
     'mozglue',
 ]
 
 if not CONFIG['JS_STANDALONE']:
     DIRS += ['xpcom/xpidl']
 
+if CONFIG['USE_ICU']:
+    DIRS += ['config/external/icu']
+
 if CONFIG['COMPILE_ENVIRONMENT']:
-    DIRS += ['config/external/nspr']
 
     if not CONFIG['JS_STANDALONE']:
         DIRS += [
             'config/external',
             'config/external/nss',
         ]
 
     if CONFIG['BUILD_CTYPES']:
         DIRS += ['config/external/ffi']
-    if CONFIG['USE_ICU']:
-        DIRS += ['config/external/icu']
+
     DIRS += ['js/src']
 else:
     TEST_DIRS += ['js/src/tests']
 
 if not CONFIG['JS_STANDALONE'] and CONFIG['MOZ_BUILD_APP']:
     # Bring in the configuration for the configured application.
     include('/' + CONFIG['MOZ_BUILD_APP'] + '/app.mozbuild')
 
--- a/parser/htmlparser/tests/mochitest/mochitest.ini
+++ b/parser/htmlparser/tests/mochitest/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # bug 1233774
+skip-if = buildapp == 'b2g'
 support-files =
   bug_502091_iframe.html
   file_bug102699.sjs
   file_bug534293-slow.sjs
   file_bug534293.sjs
   file_bug543062.sjs
   file_bug594730-1.html
   file_bug594730-2.html
--- a/python/mozbuild/mozbuild/artifacts.py
+++ b/python/mozbuild/mozbuild/artifacts.py
@@ -210,17 +210,16 @@ class LinuxArtifactJob(ArtifactJob):
         'firefox/crashreporter',
         'firefox/dependentlibs.list',
         'firefox/firefox',
         'firefox/firefox-bin',
         'firefox/platform.ini',
         'firefox/plugin-container',
         'firefox/updater',
         'firefox/**/*.so',
-        mozpath.join('firefox', buildconfig.substs.get('ICU_DATA_FILE')),
     }
 
     def process_package_artifact(self, filename, processed_filename):
         added_entry = False
 
         with JarWriter(file=processed_filename, optimize=False, compress_level=5) as writer:
             with tarfile.open(filename) as reader:
                 for f in reader:
@@ -302,17 +301,16 @@ class MacArtifactJob(ArtifactJob):
             # These get copied into dist/bin with the path, so "root/a/b/c" -> "dist/bin/a/b/c".
             paths_keep_path = ('Contents/Resources', [
                 'browser/components/libbrowsercomps.dylib',
                 'dependentlibs.list',
                 # 'firefox',
                 'gmp-clearkey/0.1/libclearkey.dylib',
                 # 'gmp-fake/1.0/libfake.dylib',
                 # 'gmp-fakeopenh264/1.0/libfakeopenh264.dylib',
-                buildconfig.substs.get('ICU_DATA_FILE'),
             ])
 
             with JarWriter(file=processed_filename, optimize=False, compress_level=5) as writer:
                 root, paths = paths_no_keep_path
                 finder = FileFinder(mozpath.join(source, root))
                 for path in paths:
                     for p, f in finder.find(path):
                         self.log(logging.INFO, 'artifact',
@@ -343,17 +341,16 @@ class MacArtifactJob(ArtifactJob):
 
 class WinArtifactJob(ArtifactJob):
     package_artifact_patterns = {
         'firefox/dependentlibs.list',
         'firefox/platform.ini',
         'firefox/application.ini',
         'firefox/**/*.dll',
         'firefox/*.exe',
-        mozpath.join('firefox', buildconfig.substs.get('ICU_DATA_FILE')),
     }
     # These are a subset of TEST_HARNESS_BINS in testing/mochitest/Makefile.in.
     test_artifact_patterns = {
         ('bin/BadCertServer.exe', ('bin', 'bin')),
         ('bin/GenerateOCSPResponse.exe', ('bin', 'bin')),
         ('bin/OCSPStaplingServer.exe', ('bin', 'bin')),
         ('bin/certutil.exe', ('bin', 'bin')),
         ('bin/fileid.exe', ('bin', 'bin')),
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -23,20 +23,22 @@ from mozbuild.configure.options import (
     PositiveOptionValue,
 )
 from mozbuild.configure.help import HelpFormatter
 from mozbuild.configure.util import (
     ConfigureOutputHandler,
     LineIO,
 )
 from mozbuild.util import (
+    exec_,
     memoize,
     ReadOnlyDict,
     ReadOnlyNamespace,
 )
+
 import mozpack.path as mozpath
 
 
 class ConfigureError(Exception):
     pass
 
 
 class DependsFunction(object):
@@ -88,24 +90,26 @@ class ConfigureSandbox(dict):
         do_stuff(config)
     """
 
     # The default set of builtins. We expose unicode as str to make sandboxed
     # files more python3-ready.
     BUILTINS = ReadOnlyDict({
         b: __builtins__[b]
         for b in ('None', 'False', 'True', 'int', 'bool', 'any', 'all', 'len',
-                  'list', 'tuple', 'set', 'dict', 'isinstance')
+                  'list', 'tuple', 'set', 'dict', 'isinstance', 'getattr',
+                  'hasattr', 'enumerate', 'range', 'zip')
     }, __import__=forbidden_import, str=unicode)
 
     # Expose a limited set of functions from os.path
     OS = ReadOnlyNamespace(path=ReadOnlyNamespace(**{
         k: getattr(mozpath, k, getattr(os.path, k))
         for k in ('abspath', 'basename', 'dirname', 'exists', 'isabs', 'isdir',
-                  'isfile', 'join', 'normpath', 'realpath', 'relpath')
+                  'isfile', 'join', 'normcase', 'normpath', 'realpath',
+                  'relpath')
     }))
 
     def __init__(self, config, environ=os.environ, argv=sys.argv,
                  stdout=sys.stdout, stderr=sys.stderr, logger=None):
         dict.__setitem__(self, '__builtins__', self.BUILTINS)
 
         self._paths = []
         self._all_paths = set()
@@ -193,17 +197,17 @@ class ConfigureSandbox(dict):
                 'Cannot include `%s` because it was included already.' % path)
         self._paths.append(path)
         self._all_paths.add(path)
 
         source = open(path, 'rb').read()
 
         code = compile(source, path, 'exec')
 
-        exec(code, self)
+        exec_(code, self)
 
         self._paths.pop(-1)
 
     def run(self, path=None):
         '''Executes the given file within the sandbox, as well as everything
         pending from any other included file, and ensure the overall
         consistency of the executed script(s).'''
         if path:
@@ -490,16 +494,24 @@ class ConfigureSandbox(dict):
             # available there.
             @wraps(template)
             def wrapper(*args, **kwargs):
                 args = [maybe_prepare_function(arg) for arg in args]
                 kwargs = {k: maybe_prepare_function(v)
                           for k, v in kwargs.iteritems()}
                 ret = template(*args, **kwargs)
                 if isfunction(ret):
+                    # We can't expect the sandboxed code to think about all the
+                    # details of implementing decorators, so do some of the
+                    # work for them. If the function takes exactly one function
+                    # as argument and returns a function, it must be a
+                    # decorator, so mark the returned function as wrapping the
+                    # function passed in.
+                    if len(args) == 1 and not kwargs and isfunction(args[0]):
+                        ret = wraps(args[0])(ret)
                     return wrap_template(ret)
                 return ret
             return wrapper
 
         wrapper = wrap_template(template)
         self._templates.add(wrapper)
         return wrapper
 
@@ -555,20 +567,17 @@ class ConfigureSandbox(dict):
             # Until this proves to be a performance problem, just construct an
             # import statement and execute it.
             import_line = ''
             if _from:
                 import_line += 'from %s ' % _from
             import_line += 'import %s' % _import
             if _as:
                 import_line += ' as %s' % _as
-            # Some versions of python fail with "SyntaxError: unqualified exec
-            # is not allowed in function '_apply_imports' it contains a nested
-            # function with free variable" when using the exec function.
-            exec import_line in {}, glob
+            exec_(import_line, {}, glob)
 
     def _resolve_and_set(self, data, name, value):
         # Don't set anything when --help was on the command line
         if self._help:
             return
         name = self._resolve(name, need_help_dependency=False)
         if name is None:
             return
@@ -692,17 +701,16 @@ class ConfigureSandbox(dict):
                 inspect.isclass(v) and issubclass(v, Exception))
         )
         glob.update(
             __builtins__=self.BUILTINS,
             __file__=self._paths[-1] if self._paths else '',
             os=self.OS,
             log=self.log_impl,
         )
-        self._apply_imports(func, glob)
 
         # The execution model in the sandbox doesn't guarantee the execution
         # order will always be the same for a given function, and if it uses
         # variables from a closure that are changed after the function is
         # declared, depending when the function is executed, the value of the
         # variable can differ. For consistency, we force the function to use
         # the value from the earliest it can be run, which is at declaration.
         # Note this is not entirely bullet proof (if the value is e.g. a list,
@@ -712,17 +720,22 @@ class ConfigureSandbox(dict):
             def makecell(content):
                 def f():
                     content
                 return f.func_closure[0]
 
             closure = tuple(makecell(cell.cell_contents)
                             for cell in func.func_closure)
 
-        func = wraps(func)(types.FunctionType(
+        new_func = wraps(func)(types.FunctionType(
             func.func_code,
             glob,
             func.__name__,
             func.func_defaults,
             closure
         ))
-        self._prepared_functions.add(func)
-        return func, glob
+        @wraps(new_func)
+        def wrapped(*args, **kwargs):
+            self._apply_imports(func, glob)
+            return new_func(*args, **kwargs)
+
+        self._prepared_functions.add(wrapped)
+        return wrapped, glob
--- a/python/mozbuild/mozbuild/frontend/sandbox.py
+++ b/python/mozbuild/mozbuild/frontend/sandbox.py
@@ -18,17 +18,20 @@ user-friendly error messages in the case
 """
 
 from __future__ import absolute_import, unicode_literals
 
 import os
 import sys
 import weakref
 
-from mozbuild.util import ReadOnlyDict
+from mozbuild.util import (
+    exec_,
+    ReadOnlyDict,
+)
 from .context import Context
 from mozpack.files import FileFinder
 
 
 default_finder = FileFinder('/', find_executables=False)
 
 
 def alphabetical_sorted(iterable, cmp=None, key=lambda x: x.lower(),
@@ -169,21 +172,17 @@ class Sandbox(dict):
             # do want Unicode literals.
             code = compile(source, path, 'exec')
             # We use ourself as the global namespace for the execution. There
             # is no need for a separate local namespace as moz.build execution
             # is flat, namespace-wise.
             old_source = self._current_source
             self._current_source = source
             try:
-                # Ideally, we'd use exec(code, self), but that yield the
-                # following error:
-                # SyntaxError: unqualified exec is not allowed in function
-                # 'execute' it is a nested function.
-                exec code in self
+                exec_(code, self)
             finally:
                 self._current_source = old_source
 
         self.exec_function(execute, path=path)
 
     def exec_function(self, func, args=(), kwargs={}, path='',
                       becomes_current_path=True):
         """Execute function with the given arguments in the sandbox.
--- a/python/mozbuild/mozbuild/test/configure/data/moz.configure
+++ b/python/mozbuild/mozbuild/test/configure/data/moz.configure
@@ -155,22 +155,20 @@ def with_imports(value):
         return os.path.isfile(value[0])
 
 set_config('IS_FILE', with_imports)
 
 # It is still possible to import the full set from os.path.
 # It is also possible to cherry-pick builtins.
 @depends('--with-imports')
 @imports('os.path')
-@imports(_from='__builtin__', _import='hasattr')
 def with_imports(value):
     if len(value):
         return hasattr(os.path, 'getatime')
 
 set_config('HAS_GETATIME', with_imports)
 
 @depends('--with-imports')
-@imports(_from='__builtin__', _import='hasattr')
 def with_imports(value):
     if len(value):
         return hasattr(os.path, 'getatime')
 
 set_config('HAS_GETATIME2', with_imports)
--- a/python/mozbuild/mozbuild/util.py
+++ b/python/mozbuild/mozbuild/util.py
@@ -1,16 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # This file contains miscellaneous utility functions that don't belong anywhere
 # in particular.
 
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, unicode_literals, print_function
 
 import argparse
 import collections
 import ctypes
 import difflib
 import errno
 import functools
 import hashlib
@@ -37,16 +37,32 @@ if sys.version_info[0] == 3:
 else:
     str_type = basestring
 
 if sys.platform == 'win32':
     _kernel32 = ctypes.windll.kernel32
     _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
 
 
+def exec_(object, globals=None, locals=None):
+    """Wrapper around the exec statement to avoid bogus errors like:
+
+    SyntaxError: unqualified exec is not allowed in function ...
+    it is a nested function.
+
+    or
+
+    SyntaxError: unqualified exec is not allowed in function ...
+    it contains a nested function with free variable
+
+    which happen with older versions of python 2.7.
+    """
+    exec(object, globals, locals)
+
+
 def hash_file(path, hasher=None):
     """Hashes a file specified by the path given and returns the hex digest."""
 
     # If the default hashing function changes, this may invalidate
     # lots of cached data.  Don't change it lightly.
     h = hasher or hashlib.sha1()
 
     with open(path, 'rb') as fh:
--- a/testing/mochitest/BrowserTestUtils/ContentTask.jsm
+++ b/testing/mochitest/BrowserTestUtils/ContentTask.jsm
@@ -112,15 +112,17 @@ var ContentMessageListener = {
       } else {
         deferred.resolve(aMessage.data.result);
       }
     } else if (aMessage.name == "content-task:test-result") {
       let data = aMessage.data;
       ContentTask._testScope.ok(data.condition, data.name, null, data.stack);
     } else if (aMessage.name == "content-task:test-info") {
       ContentTask._testScope.info(aMessage.data.name);
+    } else if (aMessage.name == "content-task:test-todo") {
+      ContentTask._testScope.todo(aMessage.data.expr, aMessage.data.name);
     }
   },
 };
 
 Services.mm.addMessageListener("content-task:complete", ContentMessageListener);
 Services.mm.addMessageListener("content-task:test-result", ContentMessageListener);
 Services.mm.addMessageListener("content-task:test-info", ContentMessageListener);
--- a/testing/mochitest/BrowserTestUtils/content/content-task.js
+++ b/testing/mochitest/BrowserTestUtils/content/content-task.js
@@ -30,16 +30,20 @@ addMessageListener("content-task:spawn",
       stack: getStack(err ? err.stack : stack)
     });
   });
 
   var ok = Assert.ok.bind(Assert);
   var is = Assert.equal.bind(Assert);
   var isnot = Assert.notEqual.bind(Assert);
 
+  function todo(expr, name) {
+    sendAsyncMessage("content-task:test-todo", {id, expr, name});
+  }
+
   function info(name) {
     sendAsyncMessage("content-task:test-info", {id, name});
   }
 
   try {
     let runnablestr = `
       (() => {
         return (${source});
--- a/testing/mozharness/configs/merge_day/bump_esr.py
+++ b/testing/mozharness/configs/merge_day/bump_esr.py
@@ -1,19 +1,18 @@
 config = {
     "log_name": "bump_esr",
     "version_files": [
         {"file": "browser/config/version.txt", "suffix": ""},
-        # TODO: add the following line when ESR is 45
-        # {"file": "browser/config/version_display.txt", "suffix": ""},
+        {"file": "browser/config/version_display.txt", "suffix": ""},
         {"file": "config/milestone.txt", "suffix": ""},
     ],
     "tools_repo_url": "https://hg.mozilla.org/build/tools",
     "tools_repo_revision": "default",
-    "to_repo_url": "ssh://hg.mozilla.org/releases/mozilla-esr38",
+    "to_repo_url": "ssh://hg.mozilla.org/releases/mozilla-esr45",
 
     "migration_behavior": "bump_second_digit",
     "require_remove_locales": False,
     "requires_head_merge": False,
     "default_actions": [
         "clean-repos",
         "pull",
         "bump_second_digit"
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -9,17 +9,16 @@ user_pref("browser.ui.layout.tablet", 0)
 user_pref("dom.allow_scripts_to_close_windows", true);
 user_pref("dom.disable_open_during_load", false);
 user_pref("dom.experimental_forms", true); // on for testing
 user_pref("dom.forms.number", true); // on for testing
 user_pref("dom.forms.color", true); // on for testing
 user_pref("dom.max_script_run_time", 0); // no slow script dialogs
 user_pref("hangmonitor.timeout", 0); // no hang monitor
 user_pref("dom.max_chrome_script_run_time", 0);
-user_pref("dom.max_child_script_run_time", 0);
 user_pref("dom.ipc.reportProcessHangs", false); // process hang monitor
 user_pref("dom.popup_maximum", -1);
 user_pref("dom.send_after_paint_to_content", true);
 user_pref("dom.successive_dialog_time_limit", 0);
 user_pref("signed.applets.codebase_principal_support", true);
 user_pref("browser.shell.checkDefaultBrowser", false);
 user_pref("shell.checkDefaultClient", false);
 user_pref("browser.warnOnQuit", false);
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -28741,16 +28741,20 @@
         "path": "web-animations/animation-model/keyframes/effect-value-context.html",
         "url": "/web-animations/animation-model/keyframes/effect-value-context.html"
       },
       {
         "path": "web-animations/animation-effect-timing/duration.html",
         "url": "/web-animations/animation-effect-timing/duration.html"
       },
       {
+        "path": "web-animations/animation-effect-timing/easing.html",
+        "url": "/web-animations/animation-effect-timing/easing.html"
+      },
+      {
         "path": "web-animations/animation-effect-timing/endDelay.html",
         "url": "/web-animations/animation-effect-timing/endDelay.html"
       },
       {
         "path": "web-animations/animation-effect-timing/getAnimations.html",
         "url": "/web-animations/animation-effect-timing/getAnimations.html"
       },
       {
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/web-animations/animation-effect-timing/easing.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>easing tests</title>
+<link rel="help" href="https://w3c.github.io/web-animations/#dom-animationeffecttiming-easing">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../testcommon.js"></script>
+<script src="../resources/effect-easing-tests.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_progress(animation, currentTime, easingFunction) {
+  animation.currentTime = currentTime;
+  var portion = currentTime / animation.effect.timing.duration;
+  assert_approx_equals(animation.effect.getComputedTiming().progress,
+                       easingFunction(portion),
+                       0.01,
+                       'The progress of the animation should be approximately ' +
+                       easingFunction(portion) + ' at ' + currentTime + 'ms');
+}
+
+gEffectEasingTests.forEach(function(options) {
+  test(function(t) {
+    var target = createDiv(t);
+    var anim = target.animate([ { opacity: 0 }, { opacity: 1 } ],
+                              { duration: 1000 * MS_PER_SEC,
+                                fill: 'forwards' });
+    anim.effect.timing.easing = options.easing;
+    assert_equals(anim.effect.timing.easing, options.easing);
+
+    var easing = options.easingFunction;
+    assert_progress(anim, 0, easing);
+    assert_progress(anim, 250 * MS_PER_SEC, easing);
+    assert_progress(anim, 500 * MS_PER_SEC, easing);
+    assert_progress(anim, 750 * MS_PER_SEC, easing);
+    assert_progress(anim, 1000 * MS_PER_SEC, easing);
+  }, options.desc);
+});
+
+test(function(t) {
+  var div = createDiv(t);
+  var anim = div.animate({ opacity: [ 0, 1 ] }, 100 * MS_PER_SEC);
+  assert_throws({ name: 'TypeError' },
+                function() {
+                  anim.effect.timing.easing = '';
+                });
+  assert_throws({ name: 'TypeError' },
+                function() {
+                  anim.effect.timing.easing = 'test';
+                });
+}, 'Test invalid easing value');
+
+test(function(t) {
+  var delay = 1000 * MS_PER_SEC;
+
+  var target = createDiv(t);
+  var anim = target.animate([ { opacity: 0 }, { opacity: 1 } ],
+                            { duration: 1000 * MS_PER_SEC,
+                              fill: 'both',
+                              delay: delay,
+                              easing: 'steps(2, start)' });
+
+  anim.effect.timing.easing = 'steps(2, end)';
+  assert_equals(anim.effect.getComputedTiming().progress, 0,
+                'easing replace to steps(2, end) at before phase');
+
+  anim.currentTime = delay + 750 * MS_PER_SEC;
+  assert_equals(anim.effect.getComputedTiming().progress, 0.5,
+                'change currentTime to active phase');
+
+  anim.effect.timing.easing = 'steps(2, start)';
+  assert_equals(anim.effect.getComputedTiming().progress, 1,
+                'easing replace to steps(2, start) at active phase');
+
+  anim.currentTime = delay + 1500 * MS_PER_SEC;
+  anim.effect.timing.easing = 'steps(2, end)';
+  assert_equals(anim.effect.getComputedTiming().progress, 1,
+                'easing replace to steps(2, end) again at after phase');
+}, 'Change the easing while the animation is running');
+
+</script>
+</body>
--- a/testing/web-platform/tests/web-animations/keyframe-effect/effect-easing.html
+++ b/testing/web-platform/tests/web-animations/keyframe-effect/effect-easing.html
@@ -1,80 +1,33 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
 <title>Effect-level easing tests</title>
 <link rel="help" href="http://w3c.github.io/web-animations/#calculating-the-transformed-time">
 <link rel="author" title="Hiroyuki Ikezoe" href="mailto:hiikezoe@mozilla-japan.org">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../testcommon.js"></script>
+<script src="../resources/effect-easing-tests.js"></script>
 <body>
 <div id="log"></div>
 <div id="target"></div>
 <script>
 "use strict";
 
 function assert_style_left_at(animation, time, easingFunction) {
   animation.currentTime = time;
   var portion = time / animation.effect.timing.duration;
   assert_approx_equals(pxToNum(getComputedStyle(animation.effect.target).left),
                        easingFunction(portion) * 100,
                        0.01,
                        'The left of the animation should be approximately ' +
                        easingFunction(portion) * 100 + ' at ' + time + 'ms');
 }
 
-var gEffectEasingTests = [
-  {
-    desc: 'steps(start) function',
-    easing: 'steps(2, start)',
-    easingFunction: stepStart(2)
-  },
-  {
-    desc: 'steps(end) function',
-    easing: 'steps(2, end)',
-    easingFunction: stepEnd(2)
-  },
-  {
-    desc: 'linear function',
-    easing: 'linear', // cubic-bezier(0, 0, 1.0, 1.0)
-    easingFunction: cubicBezier(0, 0, 1.0, 1.0)
-  },
-  {
-    desc: 'ease function',
-    easing: 'ease', // cubic-bezier(0.25, 0.1, 0.25, 1.0)
-    easingFunction: cubicBezier(0.25, 0.1, 0.25, 1.0)
-  },
-  {
-    desc: 'ease-in function',
-    easing: 'ease-in', // cubic-bezier(0.42, 0, 1.0, 1.0)
-    easingFunction: cubicBezier(0.42, 0, 1.0, 1.0)
-  },
-  {
-    desc: 'ease-in-out function',
-    easing: 'ease-in-out', // cubic-bezier(0.42, 0, 0.58, 1.0)
-    easingFunction: cubicBezier(0.42, 0, 0.58, 1.0)
-  },
-  {
-    desc: 'ease-out function',
-    easing: 'ease-out', // cubic-bezier(0, 0, 0.58, 1.0)
-    easingFunction: cubicBezier(0, 0, 0.58, 1.0)
-  },
-  {
-    desc: 'easing function which produces values greater than 1',
-    easing: 'cubic-bezier(0, 1.5, 1, 1.5)',
-    easingFunction: cubicBezier(0, 1.5, 1, 1.5)
-  },
-  {
-    desc: 'easing function which produces negative values',
-    easing: 'cubic-bezier(0, -0.5 ,1, -0.5)',
-    easingFunction: cubicBezier(0, -0.5, 1, -0.5)
-  },
-];
-
 gEffectEasingTests.forEach(function(options) {
   test(function(t) {
     var target = createDiv(t);
     target.style.position = 'absolute';
     var anim = target.animate([ { left: '0px' }, { left: '100px' } ],
                               { duration: 1000,
                                 fill: 'forwards',
                                 easing: options.easing });
@@ -689,17 +642,17 @@ var gStepTimingFunctionTests = [
                   { currentTime: 1249, progress: 0.5 },
                   { currentTime: 1250, progress: 0 },
                   { currentTime: 1749, progress: 0 },
                   { currentTime: 1750, progress: 0.5 },
                   { currentTime: 2000, progress: 0.5 },
                   { currentTime: 2500, progress: 0.5 },
                 ]
   }
-]
+];
 
 gStepTimingFunctionTests.forEach(function(options) {
   test(function(t) {
     var target = createDiv(t);
     var animation = target.animate(options.keyframe, options.effect);
     options.conditions.forEach(function(condition) {
       animation.currentTime = condition.currentTime;
       if (typeof condition.progress !== 'undefined') {
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/web-animations/resources/effect-easing-tests.js
@@ -0,0 +1,42 @@
+var gEffectEasingTests = [
+  {
+    desc: 'steps(start) function',
+    easing: 'steps(2, start)',
+    easingFunction: stepStart(2)
+  },
+  {
+    desc: 'steps(end) function',
+    easing: 'steps(2, end)',
+    easingFunction: stepEnd(2)
+  },
+  {
+    desc: 'linear function',
+    easing: 'linear', // cubic-bezier(0, 0, 1.0, 1.0)
+    easingFunction: cubicBezier(0, 0, 1.0, 1.0)
+  },
+  {
+    desc: 'ease function',
+    easing: 'ease', // cubic-bezier(0.25, 0.1, 0.25, 1.0)
+    easingFunction: cubicBezier(0.25, 0.1, 0.25, 1.0)
+  },
+  {
+    desc: 'ease-in function',
+    easing: 'ease-in', // cubic-bezier(0.42, 0, 1.0, 1.0)
+    easingFunction: cubicBezier(0.42, 0, 1.0, 1.0)
+  },
+  {
+    desc: 'ease-in-out function',
+    easing: 'ease-in-out', // cubic-bezier(0.42, 0, 0.58, 1.0)
+    easingFunction: cubicBezier(0.42, 0, 0.58, 1.0)
+  },
+  {
+    desc: 'ease-out function',
+    easing: 'ease-out', // cubic-bezier(0, 0, 0.58, 1.0)
+    easingFunction: cubicBezier(0, 0, 0.58, 1.0)
+  },
+  {
+    desc: 'easing function which produces values greater than 1',
+    easing: 'cubic-bezier(0, 1.5, 1, 1.5)',
+    easingFunction: cubicBezier(0, 1.5, 1, 1.5)
+  }
+];
--- a/toolkit/components/alerts/test/mochitest.ini
+++ b/toolkit/components/alerts/test/mochitest.ini
@@ -3,9 +3,9 @@ skip-if = buildapp == 'b2g' || buildapp 
 
 # Synchronous tests like test_alerts.html must come before
 # asynchronous tests like test_alerts_noobserve.html!
 [test_alerts.html]
 skip-if = toolkit == 'android'
 [test_alerts_noobserve.html]
 [test_multiple_alerts.html]
 [test_principal.html]
-skip-if = toolkit == 'android' || (e10s && os == 'win')
+skip-if = toolkit == 'android' || (e10s && os == 'win') # Win: Bug 1264842
--- a/toolkit/components/moz.build
+++ b/toolkit/components/moz.build
@@ -53,16 +53,17 @@ DIRS += [
     'reflect',
     'securityreporter',
     'sqlite',
     'startup',
     'statusfilter',
     'telemetry',
     'thumbnails',
     'timermanager',
+    'tooltiptext',
     'typeaheadfind',
     'utils',
     'urlformatter',
     'viewconfig',
     'workerloader',
     'xulstore'
 ]
 
--- a/toolkit/components/places/nsLivemarkService.js
+++ b/toolkit/components/places/nsLivemarkService.js
@@ -530,17 +530,17 @@ Livemark.prototype = {
                       createInstance(Ci.nsILoadGroup);
       // Creating a CodeBasePrincipal and using it as the loadingPrincipal
       // is *not* desired and is only tolerated within this file.
       // TODO: Find the right OriginAttributes and pass something other
       // than {} to .createCodeBasePrincipal().
       let channel = NetUtil.newChannel({
         uri: this.feedURI,
         loadingPrincipal: Services.scriptSecurityManager.createCodebasePrincipal(this.feedURI, {}),
-        securityFlags: Ci.nsILoadInfo.SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
+        securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
         contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_XMLHTTPREQUEST
       }).QueryInterface(Ci.nsIHttpChannel);
       channel.loadGroup = loadgroup;
       channel.loadFlags |= Ci.nsIRequest.LOAD_BACKGROUND |
                            Ci.nsIRequest.LOAD_BYPASS_CACHE;
       channel.requestMethod = "GET";
       channel.setRequestHeader("X-Moz", "livebookmarks", false);
 
--- a/toolkit/components/telemetry/TelemetryEnvironment.jsm
+++ b/toolkit/components/telemetry/TelemetryEnvironment.jsm
@@ -121,16 +121,17 @@ const DEFAULT_ENVIRONMENT_PREFS = new Ma
   ["browser.urlbar.unifiedcomplete", {what: RECORD_PREF_VALUE}],
   ["browser.urlbar.userMadeSearchSuggestionsChoice", {what: RECORD_PREF_VALUE}],
   ["devtools.chrome.enabled", {what: RECORD_PREF_VALUE}],
   ["devtools.debugger.enabled", {what: RECORD_PREF_VALUE}],
   ["devtools.debugger.remote-enabled", {what: RECORD_PREF_VALUE}],
   ["dom.ipc.plugins.asyncInit.enabled", {what: RECORD_PREF_VALUE}],
   ["dom.ipc.plugins.enabled", {what: RECORD_PREF_VALUE}],
   ["dom.ipc.processCount", {what: RECORD_PREF_VALUE, requiresRestart: true}],
+  ["dom.max_script_run_time", {what: RECORD_PREF_VALUE}],
   ["experiments.manifest.uri", {what: RECORD_PREF_VALUE}],
   ["extensions.autoDisableScopes", {what: RECORD_PREF_VALUE}],
   ["extensions.enabledScopes", {what: RECORD_PREF_VALUE}],
   ["extensions.blocklist.enabled", {what: RECORD_PREF_VALUE}],
   ["extensions.blocklist.url", {what: RECORD_PREF_VALUE}],
   ["extensions.strictCompatibility", {what: RECORD_PREF_VALUE}],
   ["extensions.update.enabled", {what: RECORD_PREF_VALUE}],
   ["extensions.update.url", {what: RECORD_PREF_VALUE}],
copy from toolkit/content/widgets/popup.xml
copy to toolkit/components/tooltiptext/TooltipTextProvider.js
--- a/toolkit/content/widgets/popup.xml
+++ b/toolkit/components/tooltiptext/TooltipTextProvider.js
@@ -1,743 +1,148 @@
-<?xml version="1.0"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-
-<bindings id="popupBindings"
-   xmlns="http://www.mozilla.org/xbl"
-   xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-   xmlns:xbl="http://www.mozilla.org/xbl">
-
-  <binding id="popup-base">
-    <resources>
-      <stylesheet src="chrome://global/skin/popup.css"/>
-    </resources>
-
-    <implementation implements="nsIDOMXULPopupElement">
-      <property name="label" onget="return this.getAttribute('label');"
-                             onset="this.setAttribute('label', val); return val;"/>
-      <property name="position" onget="return this.getAttribute('position');"
-                                onset="this.setAttribute('position', val); return val;"/>
-      <property name="popupBoxObject">
-        <getter>
-          return this.boxObject;
-        </getter>
-      </property>
-
-      <property name="state" readonly="true"
-                onget="return this.popupBoxObject.popupState"/>
-
-      <property name="triggerNode" readonly="true"
-                onget="return this.popupBoxObject.triggerNode"/>
-
-      <property name="anchorNode" readonly="true"
-                onget="return this.popupBoxObject.anchorNode"/>
+/* 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/. */
 
-      <method name="openPopup">
-        <parameter name="aAnchorElement"/>
-        <parameter name="aPosition"/>
-        <parameter name="aX"/>
-        <parameter name="aY"/>
-        <parameter name="aIsContextMenu"/>
-        <parameter name="aAttributesOverride"/>
-        <parameter name="aTriggerEvent"/>
-        <body>
-        <![CDATA[
-          try {
-            var popupBox = this.popupBoxObject;
-            if (popupBox)
-              popupBox.openPopup(aAnchorElement, aPosition, aX, aY,
-                                 aIsContextMenu, aAttributesOverride, aTriggerEvent);
-          } catch(e) {}
-        ]]>
-        </body>
-      </method>
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
-      <method name="openPopupAtScreen">
-        <parameter name="aX"/>
-        <parameter name="aY"/>
-        <parameter name="aIsContextMenu"/>
-        <parameter name="aTriggerEvent"/>
-        <body>
-        <![CDATA[
-          try {
-            var popupBox = this.popupBoxObject;
-            if (popupBox)
-              popupBox.openPopupAtScreen(aX, aY, aIsContextMenu, aTriggerEvent);
-          } catch(e) {}
-        ]]>
-        </body>
-      </method>
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+function TooltipTextProvider() {}
 
-      <method name="openPopupAtScreenRect">
-        <parameter name="aPosition"/>
-        <parameter name="aX"/>
-        <parameter name="aY"/>
-        <parameter name="aWidth"/>
-        <parameter name="aHeight"/>
-        <parameter name="aIsContextMenu"/>
-        <parameter name="aAttributesOverride"/>
-        <parameter name="aTriggerEvent"/>
-        <body>
-        <![CDATA[
-          try {
-            var popupBox = this.popupBoxObject;
-            if (popupBox)
-              popupBox.openPopupAtScreenRect(aPosition, aX, aY, aWidth, aHeight,
-                                             aIsContextMenu, aAttributesOverride, aTriggerEvent);
-          } catch(e) {}
-        ]]>
-        </body>
-      </method>
-
-      <method name="showPopup">
-        <parameter name="element"/>
-        <parameter name="xpos"/>
-        <parameter name="ypos"/>
-        <parameter name="popuptype"/>
-        <parameter name="anchoralignment"/>
-        <parameter name="popupalignment"/>
-        <body>
-        <![CDATA[
-          var popupBox = null;
-          var menuBox = null;
-          try {
-            popupBox = this.popupBoxObject;
-          } catch(e) {}
-          try {
-            menuBox = this.parentNode.boxObject;
-          } catch(e) {}
-          if (menuBox instanceof MenuBoxObject)
-            menuBox.openMenu(true);
-          else if (popupBox)
-            popupBox.showPopup(element, this, xpos, ypos, popuptype, anchoralignment, popupalignment);
-        ]]>
-        </body>
-      </method>
+TooltipTextProvider.prototype = {
+  getNodeText(tipElement, textOut, directionOut) {
+    // Don't show the tooltip if the tooltip node is a document, browser, or disconnected.
+    if (!tipElement || !tipElement.ownerDocument ||
+        tipElement.localName == "browser" ||
+        (tipElement.ownerDocument.compareDocumentPosition(tipElement) &
+         tipElement.ownerDocument.DOCUMENT_POSITION_DISCONNECTED)) {
+      return false;
+    }
 
-      <method name="hidePopup">
-        <parameter name="cancel"/>
-        <body>
-        <![CDATA[
-          var popupBox = null;
-          var menuBox = null;
-          try {
-            popupBox = this.popupBoxObject;
-          } catch(e) {}
-          try {
-            menuBox = this.parentNode.boxObject;
-          } catch(e) {}
-          if (menuBox instanceof MenuBoxObject)
-            menuBox.openMenu(false);
-          else if (popupBox instanceof PopupBoxObject)
-            popupBox.hidePopup(cancel);
-        ]]>
-        </body>
-      </method>
+    var defView = tipElement.ownerDocument.defaultView;
+    // XXX Work around bug 350679:
+    // "Tooltips can be fired in documents with no view".
+    if (!defView)
+      return false;
 
-      <property name="autoPosition">
-        <getter>
-        <![CDATA[
-          return this.popupBoxObject.autoPosition;
-        ]]>
-        </getter>
-        <setter>
-        <![CDATA[
-          return this.popupBoxObject.autoPosition = val;
-        ]]>
-        </setter>
-      </property>
+    const XLinkNS = "http://www.w3.org/1999/xlink";
+    const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
-      <property name="alignmentPosition" readonly="true">
-        <getter>
-        <![CDATA[
-          return this.popupBoxObject.alignmentPosition;
-        ]]>
-        </getter>
-      </property>
-
-      <property name="alignmentOffset" readonly="true">
-        <getter>
-        <![CDATA[
-          return this.popupBoxObject.alignmentOffset;
-        ]]>
-        </getter>
-      </property>
+    var titleText = null;
+    var XLinkTitleText = null;
+    var SVGTitleText = null;
+    var XULtooltiptextText = null;
+    var lookingForSVGTitle = true;
+    var direction = tipElement.ownerDocument.dir;
 
-      <method name="enableKeyboardNavigator">
-        <parameter name="aEnableKeyboardNavigator"/>
-        <body>
-        <![CDATA[
-          this.popupBoxObject.enableKeyboardNavigator(aEnableKeyboardNavigator);
-        ]]>
-        </body>
-      </method>
-
-      <method name="enableRollup">
-        <parameter name="aEnableRollup"/>
-        <body>
-        <![CDATA[
-          this.popupBoxObject.enableRollup(aEnableRollup);
-        ]]>
-        </body>
-      </method>
-
-      <method name="sizeTo">
-        <parameter name="aWidth"/>
-        <parameter name="aHeight"/>
-        <body>
-        <![CDATA[
-          this.popupBoxObject.sizeTo(aWidth, aHeight);
-        ]]>
-        </body>
-      </method>
+    // If the element is invalid per HTML5 Forms specifications and has no title,
+    // show the constraint validation error message.
+    if ((tipElement instanceof defView.HTMLInputElement ||
+         tipElement instanceof defView.HTMLTextAreaElement ||
+         tipElement instanceof defView.HTMLSelectElement ||
+         tipElement instanceof defView.HTMLButtonElement) &&
+        !tipElement.hasAttribute('title') &&
+        (!tipElement.form || !tipElement.form.noValidate)) {
+      // If the element is barred from constraint validation or valid,
+      // the validation message will be the empty string.
+      titleText = tipElement.validationMessage || null;
+    }
 
-      <method name="moveTo">
-        <parameter name="aLeft"/>
-        <parameter name="aTop"/>
-        <body>
-        <![CDATA[
-          this.popupBoxObject.moveTo(aLeft, aTop);
-        ]]>
-        </body>
-      </method>
-
-      <method name="moveToAnchor">
-        <parameter name="aAnchorElement"/>
-        <parameter name="aPosition"/>
-        <parameter name="aX"/>
-        <parameter name="aY"/>
-        <parameter name="aAttributesOverride"/>
-        <body>
-        <![CDATA[
-          this.popupBoxObject.moveToAnchor(aAnchorElement, aPosition, aX, aY, aAttributesOverride);
-        ]]>
-        </body>
-      </method>
-
-      <method name="getOuterScreenRect">
-        <body>
-        <![CDATA[
-          return this.popupBoxObject.getOuterScreenRect();
-        ]]>
-        </body>
-      </method>
-    </implementation>
-
-  </binding>
-
-  <binding id="popup" role="xul:menupopup"
-           extends="chrome://global/content/bindings/popup.xml#popup-base">
-
-    <content>
-      <xul:arrowscrollbox class="popup-internal-box" flex="1" orient="vertical"
-                          smoothscroll="false">
-        <children/>
-      </xul:arrowscrollbox>
-    </content>
+    // If the element is an <input type='file'> without a title, we should show
+    // the current file selection.
+    if (!titleText &&
+        tipElement instanceof defView.HTMLInputElement &&
+        tipElement.type == 'file' &&
+        !tipElement.hasAttribute('title')) {
+      let files = tipElement.files;
 
-    <handlers>
-      <handler event="popupshowing" phase="target">
-        <![CDATA[
-          var array = [];
-          var width = 0;
-          for (var menuitem = this.firstChild; menuitem; menuitem = menuitem.nextSibling) {
-            if (menuitem.localName == "menuitem" && menuitem.hasAttribute("acceltext")) {
-              var accel = document.getAnonymousElementByAttribute(menuitem, "anonid", "accel");
-              if (accel && accel.boxObject) {
-                array.push(accel);
-                if (accel.boxObject.width > width)
-                  width = accel.boxObject.width;
-              }
-            }
+      try {
+        var bundle =
+          Services.strings.createBundle("chrome://global/locale/layout/HtmlForm.properties");
+        if (files.length == 0) {
+          if (tipElement.multiple) {
+            titleText = bundle.GetStringFromName("NoFilesSelected");
+          } else {
+            titleText = bundle.GetStringFromName("NoFileSelected");
           }
-          for (var i = 0; i < array.length; i++)
-            array[i].width = width;
-        ]]>
-      </handler>
-    </handlers>
-  </binding>
-
-  <binding id="panel" role="xul:panel"
-           extends="chrome://global/content/bindings/popup.xml#popup-base">
-    <implementation implements="nsIDOMXULPopupElement">
-      <field name="_prevFocus">0</field>
-      <field name="_dragBindingAlive">true</field>
-      <constructor>
-      <![CDATA[
-        if (this.getAttribute("backdrag") == "true" && !this._draggableStarted) {
-          this._draggableStarted = true;
-          try {
+        } else {
+          titleText = files[0].name;
+          // For UX and performance (jank) reasons we cap the number of
+          // files that we list in the tooltip to 20 plus a "and xxx more"
+          // line, or to 21 if exactly 21 files were picked.
+          const TRUNCATED_FILE_COUNT = 20;
+          let count = Math.min(files.length, TRUNCATED_FILE_COUNT);
+          for (let i = 1; i < count; ++i) {
+            titleText += "\n" + files[i].name;
+          }
+          if (files.length == TRUNCATED_FILE_COUNT + 1) {
+            titleText += "\n" + files[TRUNCATED_FILE_COUNT].name;
+          } else if (files.length > TRUNCATED_FILE_COUNT + 1) {
+            let xmoreStr = bundle.GetStringFromName("AndNMoreFiles");
+            let xmoreNum = files.length - TRUNCATED_FILE_COUNT;
             let tmp = {};
-            Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
-            let draghandle = new tmp.WindowDraggingElement(this);
-            draghandle.mouseDownCheck = function () {
-              return this._dragBindingAlive;
-            }
-          } catch (e) {}
-        }
-      ]]>
-      </constructor>
-    </implementation>
-
-    <handlers>
-      <handler event="popupshowing"><![CDATA[
-        // Capture the previous focus before has a chance to get set inside the panel
-        try {
-          this._prevFocus = Components.utils
-                            .getWeakReference(document.commandDispatcher.focusedElement);
-          if (this._prevFocus.get())
-            return;
-        } catch (ex) { }
-
-        this._prevFocus = Components.utils.getWeakReference(document.activeElement);
-      ]]></handler>
-      <handler event="popupshown"><![CDATA[
-        // Fire event for accessibility APIs
-        var alertEvent = document.createEvent("Events");
-        alertEvent.initEvent("AlertActive", true, true);
-        this.dispatchEvent(alertEvent);
-       ]]></handler>
-      <handler event="popuphiding"><![CDATA[
-        try {
-          this._currentFocus = document.commandDispatcher.focusedElement;
-        } catch (e) {
-          this._currentFocus = document.activeElement;
-        }
-      ]]></handler>
-      <handler event="popuphidden"><![CDATA[
-        var currentFocus = this._currentFocus;
-        var prevFocus = this._prevFocus ? this._prevFocus.get() : null;
-        this._currentFocus = null;
-        this._prevFocus = null;
-        if (prevFocus && currentFocus && this.getAttribute("norestorefocus") != "true") {
-          // Try to restore focus
-          try {
-            if (document.commandDispatcher.focusedWindow != window)
-              return; // Focus has already been set to a window outside of this panel
-          } catch(ex) {}
-          while (currentFocus) {
-            if (currentFocus == this) {
-              // Focus was set on an element inside this panel,
-              // so we need to move it back to where it was previously
-              try {
-                let fm = Components.classes["@mozilla.org/focus-manager;1"]
-                                   .getService(Components.interfaces.nsIFocusManager);
-                fm.setFocus(prevFocus, fm.FLAG_NOSCROLL);
-              } catch(e) {
-                prevFocus.focus();
-              }
-              return;
-            }
-            currentFocus = currentFocus.parentNode;
+            Cu.import("resource://gre/modules/PluralForm.jsm", tmp);
+            let andXMoreStr = tmp.PluralForm.get(xmoreNum, xmoreStr).replace("#1", xmoreNum);
+            titleText += "\n" + andXMoreStr;
           }
         }
-      ]]></handler>
-    </handlers>
-  </binding>
+      } catch(e) {}
+    }
+
+    // Check texts against null so that title="" can be used to undefine a
+    // title on a child element.
+    while (tipElement &&
+           (titleText == null) && (XLinkTitleText == null) &&
+           (SVGTitleText == null) && (XULtooltiptextText == null)) {
+
+      if (tipElement.nodeType == defView.Node.ELEMENT_NODE) {
+        if (tipElement.namespaceURI == XULNS)
+          XULtooltiptextText = tipElement.getAttribute("tooltiptext");
+        else if (!(tipElement instanceof defView.SVGElement))
+          titleText = tipElement.getAttribute("title");
 
-  <binding id="arrowpanel" extends="chrome://global/content/bindings/popup.xml#panel">
-    <content flip="both" side="top" position="bottomcenter topleft" consumeoutsideclicks="false">
-      <xul:vbox anonid="container" class="panel-arrowcontainer" flex="1"
-               xbl:inherits="side,panelopen">
-        <xul:box anonid="arrowbox" class="panel-arrowbox">
-          <xul:image anonid="arrow" class="panel-arrow" xbl:inherits="side"/>
-        </xul:box>
-        <xul:box class="panel-arrowcontent" xbl:inherits="side,align,dir,orient,pack" flex="1">
-          <children/>
-          <xul:box class="panel-inner-arrowcontentfooter" xbl:inherits="footertype" hidden="true"/>
-        </xul:box>
-      </xul:vbox>
-    </content>
-    <implementation>
-      <field name="_fadeTimer">null</field>
-      <method name="sizeTo">
-        <parameter name="aWidth"/>
-        <parameter name="aHeight"/>
-        <body>
-        <![CDATA[
-          this.popupBoxObject.sizeTo(aWidth, aHeight);
-          if (this.state == "open")
-            this.adjustArrowPosition();
-        ]]>
-        </body>
-      </method>
-      <method name="moveTo">
-        <parameter name="aLeft"/>
-        <parameter name="aTop"/>
-        <body>
-        <![CDATA[
-          this.popupBoxObject.moveTo(aLeft, aTop);
-          if (this.state == "open")
-            this.adjustArrowPosition();
-        ]]>
-        </body>
-      </method>
-      <method name="moveToAnchor">
-        <parameter name="aAnchorElement"/>
-        <parameter name="aPosition"/>
-        <parameter name="aX"/>
-        <parameter name="aY"/>
-        <parameter name="aAttributesOverride"/>
-        <body>
-        <![CDATA[
-          this.popupBoxObject.moveToAnchor(aAnchorElement, aPosition, aX, aY, aAttributesOverride);
-          if (this.state == "open")
-            this.adjustArrowPosition();
-        ]]>
-        </body>
-      </method>
-      <method name="adjustArrowPosition">
-        <body>
-        <![CDATA[
-        var arrow = document.getAnonymousElementByAttribute(this, "anonid", "arrow");
-
-        var anchor = this.anchorNode;
-        if (!anchor) {
-          arrow.hidden = true;
-          return;
+        if ((tipElement instanceof defView.HTMLAnchorElement ||
+             tipElement instanceof defView.HTMLAreaElement ||
+             tipElement instanceof defView.HTMLLinkElement ||
+             tipElement instanceof defView.SVGAElement) && tipElement.href) {
+          XLinkTitleText = tipElement.getAttributeNS(XLinkNS, "title");
         }
-
-        var container = document.getAnonymousElementByAttribute(this, "anonid", "container");
-        var arrowbox = document.getAnonymousElementByAttribute(this, "anonid", "arrowbox");
-
-        var position = this.alignmentPosition;
-        var offset = this.alignmentOffset;
-
-        this.setAttribute("arrowposition", position);
-
-        // if this panel has a "sliding" arrow, we may have previously set margins...
-        arrowbox.style.removeProperty("transform");
-        if (position.indexOf("start_") == 0 || position.indexOf("end_") == 0) {
-          container.orient = "horizontal";
-          arrowbox.orient = "vertical";
-          if (position.indexOf("_after") > 0) {
-            arrowbox.pack = "end";
-          } else {
-            arrowbox.pack = "start";
-          }
-          arrowbox.style.transform = "translate(0, " + -offset + "px)";
-
-          // The assigned side stays the same regardless of direction.
-          var isRTL = (window.getComputedStyle(this).direction == "rtl");
-
-          if (position.indexOf("start_") == 0) {
-            container.dir = "reverse";
-            this.setAttribute("side", isRTL ? "left" : "right");
-          }
-          else {
-            container.dir = "";
-            this.setAttribute("side", isRTL ? "right" : "left");
-          }
+        if (lookingForSVGTitle &&
+            (!(tipElement instanceof defView.SVGElement) ||
+             tipElement.parentNode.nodeType == defView.Node.DOCUMENT_NODE)) {
+          lookingForSVGTitle = false;
         }
-        else if (position.indexOf("before_") == 0 || position.indexOf("after_") == 0) {
-          container.orient = "";
-          arrowbox.orient = "";
-          if (position.indexOf("_end") > 0) {
-            arrowbox.pack = "end";
-          } else {
-            arrowbox.pack = "start";
-          }
-          arrowbox.style.transform = "translate(" + -offset + "px, 0)";
-
-          if (position.indexOf("before_") == 0) {
-            container.dir = "reverse";
-            this.setAttribute("side", "bottom");
-          }
-          else {
-            container.dir = "";
-            this.setAttribute("side", "top");
+        if (lookingForSVGTitle) {
+          for (let childNode of tipElement.childNodes) {
+            if (childNode instanceof defView.SVGTitleElement) {
+              SVGTitleText = childNode.textContent;
+              break;
+            }
           }
         }
 
-        arrow.hidden = false;
-        ]]>
-        </body>
-      </method>
-    </implementation>
-    <handlers>
-      <handler event="popupshowing" phase="target">
-      <![CDATA[
-        this.adjustArrowPosition();
-        if (this.getAttribute("animate") != "false") {
-          this.setAttribute("animate", "open");
-        }
-
-        // set fading
-        var fade = this.getAttribute("fade");
-        var fadeDelay = 0;
-        if (fade == "fast") {
-          fadeDelay = 1;
-        }
-        else if (fade == "slow") {
-          fadeDelay = 4000;
-        }
-        else {
-          return;
-        }
-
-        this._fadeTimer = setTimeout(() => this.hidePopup(true), fadeDelay, this);
-      ]]>
-      </handler>
-      <handler event="popuphiding" phase="target">
-        let animate = (this.getAttribute("animate") != "false");
-
-        if (this._fadeTimer) {
-          clearTimeout(this._fadeTimer);
-          if (animate) {
-            this.setAttribute("animate", "fade");
-          }
-        }
-        else if (animate) {
-          this.setAttribute("animate", "cancel");
-        }
-      </handler>
-      <handler event="popupshown" phase="target">
-        this.setAttribute("panelopen", "true");
-      </handler>
-      <handler event="popuphidden" phase="target">
-        this.removeAttribute("panelopen");
-        if (this.getAttribute("animate") != "false") {
-          this.removeAttribute("animate");
-        }
-      </handler>
-    </handlers>
-  </binding>
-
-  <binding id="tooltip" role="xul:tooltip"
-           extends="chrome://global/content/bindings/popup.xml#popup-base">
-    <content>
-      <children>
-        <xul:label class="tooltip-label" xbl:inherits="xbl:text=label" flex="1"/>
-      </children>
-    </content>
+        direction = defView.getComputedStyle(tipElement, "")
+                           .getPropertyValue("direction");
+      }
 
-    <implementation>
-      <field name="_mouseOutCount">0</field>
-      <field name="_isMouseOver">false</field>
-
-      <property name="label"
-                onget="return this.getAttribute('label');"
-                onset="this.setAttribute('label', val); return val;"/>
-
-      <property name="page" onset="if (val) this.setAttribute('page', 'true');
-                                   else this.removeAttribute('page');
-                                   return val;"
-                            onget="return this.getAttribute('page') == 'true';"/>
-
-      <!-- Given the supplied element within a page, set the tooltip's text to the text
-           for that element. Returns true if text was assigned, and false if the no text
-           is set, which normally would be used to cancel tooltip display.
-
-           Note that DefaultTooltipTextProvider::GetNodeText() from nsDocShellTreeOwner.cpp
-           also performs the same function, but for embedded clients that don't use a XUL/JS
-           layer. These two should be kept synchronized.
-        -->
-      <method name="fillInPageTooltip">
-        <parameter name="tipElement"/>
-        <body>
-        <![CDATA[
-          // Don't show the tooltip if the tooltip node is a document, browser, or disconnected.
-          if (!tipElement || !tipElement.ownerDocument ||
-              tipElement.localName == "browser" ||
-              (tipElement.ownerDocument.compareDocumentPosition(tipElement) & document.DOCUMENT_POSITION_DISCONNECTED)) {
-            return false;
-          }
-
-          var defView = tipElement.ownerDocument.defaultView;
-          // XXX Work around bug 350679:
-          // "Tooltips can be fired in documents with no view".
-          if (!defView)
-            return false;
-
-          const XLinkNS = "http://www.w3.org/1999/xlink";
-          const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-
-          var titleText = null;
-          var XLinkTitleText = null;
-          var SVGTitleText = null;
-          var XULtooltiptextText = null;
-          var lookingForSVGTitle = true;
-          var direction = tipElement.ownerDocument.dir;
-
-          // If the element is invalid per HTML5 Forms specifications and has no title,
-          // show the constraint validation error message.
-          if ((tipElement instanceof HTMLInputElement ||
-               tipElement instanceof HTMLTextAreaElement ||
-               tipElement instanceof HTMLSelectElement ||
-               tipElement instanceof HTMLButtonElement) &&
-              !tipElement.hasAttribute('title') &&
-              (!tipElement.form || !tipElement.form.noValidate)) {
-            // If the element is barred from constraint validation or valid,
-            // the validation message will be the empty string.
-            titleText = tipElement.validationMessage || null;
-          }
-
-          // If the element is an <input type='file'> without a title, we should show
-          // the current file selection.
-          if (!titleText &&
-              tipElement instanceof HTMLInputElement &&
-              tipElement.type == 'file' &&
-              !tipElement.hasAttribute('title')) {
-            let files = tipElement.files;
+      tipElement = tipElement.parentNode;
+    }
 
-            try {
-              var bundle = Components.classes['@mozilla.org/intl/stringbundle;1']
-                                     .getService(Components.interfaces.nsIStringBundleService)
-                                     .createBundle("chrome://global/locale/layout/HtmlForm.properties");
-              if (files.length == 0) {
-                if (tipElement.multiple) {
-                  titleText = bundle.GetStringFromName("NoFilesSelected");
-                } else {
-                  titleText = bundle.GetStringFromName("NoFileSelected");
-                }
-              } else {
-                titleText = files[0].name;
-                // For UX and performance (jank) reasons we cap the number of
-                // files that we list in the tooltip to 20 plus a "and xxx more"
-                // line, or to 21 if exactly 21 files were picked.
-                const TRUNCATED_FILE_COUNT = 20;
-                let count = Math.min(files.length, TRUNCATED_FILE_COUNT);
-                for (let i = 1; i < count; ++i) {
-                  titleText += "\n" + files[i].name;
-                }
-                if (files.length == TRUNCATED_FILE_COUNT + 1) {
-                  titleText += "\n" + files[TRUNCATED_FILE_COUNT].name;
-                } else if (files.length > TRUNCATED_FILE_COUNT + 1) {
-                  let xmoreStr = bundle.GetStringFromName("AndNMoreFiles");
-                  let xmoreNum = files.length - TRUNCATED_FILE_COUNT;
-                  let tmp = {};
-                  Components.utils.import("resource://gre/modules/PluralForm.jsm", tmp);
-                  let andXMoreStr = tmp.PluralForm.get(xmoreNum, xmoreStr).replace("#1", xmoreNum);
-                  titleText += "\n" + andXMoreStr;
-                }
-              }
-            } catch(e) {}
-          }
-
-          // Check texts against null so that title="" can be used to undefine a
-          // title on a child element.
-          while (tipElement &&
-                 (titleText == null) && (XLinkTitleText == null) &&
-                 (SVGTitleText == null) && (XULtooltiptextText == null)) {
-
-            if (tipElement.nodeType == Node.ELEMENT_NODE) {
-              if (tipElement.namespaceURI == XULNS)
-                XULtooltiptextText = tipElement.getAttribute("tooltiptext");
-              else if (!(tipElement instanceof SVGElement))
-                titleText = tipElement.getAttribute("title");
-
-              if ((tipElement instanceof HTMLAnchorElement ||
-                   tipElement instanceof HTMLAreaElement ||
-                   tipElement instanceof HTMLLinkElement ||
-                   tipElement instanceof SVGAElement) && tipElement.href) {
-                XLinkTitleText = tipElement.getAttributeNS(XLinkNS, "title");
-              }
-              if (lookingForSVGTitle &&
-                  (!(tipElement instanceof SVGElement) ||
-                   tipElement.parentNode.nodeType == Node.DOCUMENT_NODE)) {
-                lookingForSVGTitle = false;
-              }
-              if (lookingForSVGTitle) {
-                for (let childNode of tipElement.childNodes) {
-                  if (childNode instanceof SVGTitleElement) {
-                    SVGTitleText = childNode.textContent;
-                    break;
-                  }
-                }
-              }
-
-              direction = defView.getComputedStyle(tipElement, "")
-                                 .getPropertyValue("direction");
-            }
-
-            tipElement = tipElement.parentNode;
-          }
-
-          this.style.direction = direction;
+    return [titleText, XLinkTitleText, SVGTitleText, XULtooltiptextText].some(function (t) {
+      if (t && /\S/.test(t)) {
+        // Make CRLF and CR render one line break each.
+        textOut.value = t.replace(/\r\n?/g, '\n');
+        directionOut.value = direction;
+        return true;
+      }
 
-          return [titleText, XLinkTitleText, SVGTitleText, XULtooltiptextText].some(function (t) {
-            if (t && /\S/.test(t)) {
-              // Make CRLF and CR render one line break each.
-              this.label = t.replace(/\r\n?/g, '\n');
-              return true;
-            }
-
-            return false;
-          }, this);
-        ]]>
-        </body>
-      </method>
-    </implementation>
-
-    <handlers>
-      <handler event="mouseover"><![CDATA[
-        var rel = event.relatedTarget;
-        //dump("ENTERING " + (rel ? rel.localName : "null") + "\n");
-        if (!rel)
-          return;
-
-        // find out if the node we entered from is one of our anonymous children
-        while (rel) {
-          if (rel == this)
-            break;
-          rel = rel.parentNode;
-        }
-
-        // if the exited node is not a descendant of ours, we are entering for the first time
-        if (rel != this)
-          this._isMouseOver = true;
-      ]]></handler>
-
-      <handler event="mouseout"><![CDATA[
-        var rel = event.relatedTarget;
-        //dump("LEAVING " + (rel ? rel.localName : "null") + "\n");
+      return false;
+    });
+  },
 
-        // relatedTarget is null when the titletip is first shown: a mouseout event fires
-        // because the mouse is exiting the main window and entering the titletip "window".
-        // relatedTarget is also null when the mouse exits the main window completely,
-        // so count how many times relatedTarget was null after titletip is first shown
-        // and hide popup the 2nd time
-        if (!rel) {
-          ++this._mouseOutCount;
-          if (this._mouseOutCount > 1)
-            this.hidePopup();
-          return;
-        }
-
-        // find out if the node we are entering is one of our anonymous children
-        while (rel) {
-          if (rel == this)
-            break;
-          rel = rel.parentNode;
-        }
+  classID : Components.ID("{f376627f-0bbc-47b8-887e-fc92574cc91f}"),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsITooltipTextProvider]),
+};
 
-        // if the entered node is not a descendant of ours, hide the tooltip
-        if (rel != this && this._isMouseOver) {
-          this.hidePopup();
-        }
-      ]]></handler>
-
-      <handler event="popupshowing"><![CDATA[
-        if (this.page && !this.fillInPageTooltip(this.triggerNode)) {
-          event.preventDefault();
-        }
-      ]]></handler>
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TooltipTextProvider]);
 
-      <handler event="popuphiding"><![CDATA[
-        this._isMouseOver = false;
-        this._mouseOutCount = 0;
-      ]]></handler>
-    </handlers>
-  </binding>
-
-  <binding id="popup-scrollbars" extends="chrome://global/content/bindings/popup.xml#popup">
-    <content>
-      <xul:hbox class="popup-internal-box" flex="1" orient="vertical" style="overflow: auto;">
-        <children/>
-      </xul:hbox>
-    </content>
-  </binding>
-
-</bindings>
new file mode 100644
--- /dev/null
+++ b/toolkit/components/tooltiptext/TooltipTextProvider.manifest
@@ -0,0 +1,2 @@
+component {f376627f-0bbc-47b8-887e-fc92574cc91f} TooltipTextProvider.js
+contract @mozilla.org/embedcomp/default-tooltiptextprovider;1 {f376627f-0bbc-47b8-887e-fc92574cc91f}
new file mode 100644
--- /dev/null
+++ b/toolkit/components/tooltiptext/moz.build
@@ -0,0 +1,15 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+BROWSER_CHROME_MANIFESTS += ['tests/browser.ini']
+
+EXTRA_COMPONENTS += [
+    'TooltipTextProvider.js',
+    'TooltipTextProvider.manifest',
+]
+
+with Files('**'):
+    BUG_COMPONENT = ('Toolkit', 'General')
new file mode 100644
--- /dev/null
+++ b/toolkit/components/tooltiptext/tests/browser.ini
@@ -0,0 +1,7 @@
+[browser_bug329212.js]
+support-files = title_test.svg
+[browser_bug331772_xul_tooltiptext_in_html.js]
+support-files = xul_tooltiptext.xhtml
+[browser_bug561623.js]
+[browser_bug581947.js]
+[browser_input_file_tooltips.js]
rename from browser/base/content/test/general/browser_bug329212.js
rename to toolkit/components/tooltiptext/tests/browser_bug329212.js
--- a/browser/base/content/test/general/browser_bug329212.js
+++ b/toolkit/components/tooltiptext/tests/browser_bug329212.js
@@ -1,42 +1,35 @@
-function test () {
-
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(() => {
-    let doc = gBrowser.contentDocument;
-    let tooltip = document.getElementById("aHTMLTooltip");
-
-    ok(tooltip.fillInPageTooltip(doc.getElementById("svg1")), "should get title");
-    is(tooltip.getAttribute("label"), "This is a non-root SVG element title");
-
-    ok(tooltip.fillInPageTooltip(doc.getElementById("text1")), "should get title");
-    is(tooltip.getAttribute("label"), "\n\n\n    This            is a title\n\n    ");
-
-    ok(!tooltip.fillInPageTooltip(doc.getElementById("text2")), "should not get title");
-
-    ok(!tooltip.fillInPageTooltip(doc.getElementById("text3")), "should not get title");
+"use strict";
 
-    ok(tooltip.fillInPageTooltip(doc.getElementById("link1")), "should get title");
-    is(tooltip.getAttribute("label"), "\n      This is a title\n    ");
-    ok(tooltip.fillInPageTooltip(doc.getElementById("text4")), "should get title");
-    is(tooltip.getAttribute("label"), "\n      This is a title\n    ");
-
-    ok(!tooltip.fillInPageTooltip(doc.getElementById("link2")), "should not get title");
-
-    ok(tooltip.fillInPageTooltip(doc.getElementById("link3")), "should get title");
-    isnot(tooltip.getAttribute("label"), "");
+add_task(function*() {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: "http://mochi.test:8888/browser/toolkit/components/tooltiptext/tests/title_test.svg",
+  }, function*(browser) {
+    yield ContentTask.spawn(browser, "", function() {
+      let tttp = Cc["@mozilla.org/embedcomp/default-tooltiptextprovider;1"]
+                 .getService(Ci.nsITooltipTextProvider);
+      function checkElement(id, expectedTooltipText) {
+        let el = content.document.getElementById(id);
+        let textObj = {};
+        let shouldHaveTooltip = expectedTooltipText !== null;
+        is(tttp.getNodeText(el, textObj, {}), shouldHaveTooltip,
+           "element " + id + " should " + (shouldHaveTooltip ? "" : "not ") + "have a tooltip");
+        if (shouldHaveTooltip) {
+          is(textObj.value, expectedTooltipText,
+             "element " + id + " should have the right tooltip text");
+        }
+      }
+      checkElement("svg1", "This is a non-root SVG element title");
+      checkElement("text1", "\n\n\n    This            is a title\n\n    ");
+      checkElement("text2", null);
+      checkElement("text3", null);
+      checkElement("link1", "\n      This is a title\n    ");
+      checkElement("text4", "\n      This is a title\n    ");
+      checkElement("link2", null);
+      checkElement("link3", "This is an xlink:title attribute");
+      checkElement("link4", "This is an xlink:title attribute");
+      checkElement("text5", null);
+    });
+  });
+});
 
-    ok(tooltip.fillInPageTooltip(doc.getElementById("link4")), "should get title");
-    is(tooltip.getAttribute("label"), "This is an xlink:title attribute");
-
-    ok(!tooltip.fillInPageTooltip(doc.getElementById("text5")), "should not get title");
-
-    gBrowser.removeCurrentTab();
-    finish();
-  });
-
-  gBrowser.loadURI(
-    "http://mochi.test:8888/browser/browser/base/content/test/general/title_test.svg"
-  );
-}
-
rename from browser/base/content/test/general/browser_bug331772_xul_tooltiptext_in_html.js
rename to toolkit/components/tooltiptext/tests/browser_bug331772_xul_tooltiptext_in_html.js
--- a/browser/base/content/test/general/browser_bug331772_xul_tooltiptext_in_html.js
+++ b/toolkit/components/tooltiptext/tests/browser_bug331772_xul_tooltiptext_in_html.js
@@ -1,22 +1,19 @@
 /**
  * Tests that the tooltiptext attribute is used for XUL elements in an HTML doc.
  */
-function test () {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(() => {
-    let doc = gBrowser.contentDocument;
-    let tooltip = document.getElementById("aHTMLTooltip");
-
-    ok(tooltip.fillInPageTooltip(doc.getElementById("xulToolbarButton")), "should get tooltiptext");
-    is(tooltip.getAttribute("label"), "XUL tooltiptext");
+add_task(function*() {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: "http://mochi.test:8888/browser/toolkit/components/tooltiptext/tests/xul_tooltiptext.xhtml",
+  }, function*(browser) {
+    yield ContentTask.spawn(browser, "", function() {
+      let textObj = {};
+      let tttp = Cc["@mozilla.org/embedcomp/default-tooltiptextprovider;1"]
+                 .getService(Ci.nsITooltipTextProvider);
+      let xulToolbarButton = content.document.getElementById("xulToolbarButton");
+      ok(tttp.getNodeText(xulToolbarButton, textObj, {}), "should get tooltiptext");
+      is(textObj.value, "XUL tooltiptext");
+    });
+  });
+});
 
-    gBrowser.removeCurrentTab();
-    finish();
-  });
-
-  gBrowser.loadURI(
-    "http://mochi.test:8888/browser/browser/base/content/test/general/xul_tooltiptext.xhtml"
-  );
-}
-
rename from browser/base/content/test/general/browser_bug561623.js
rename to toolkit/components/tooltiptext/tests/browser_bug561623.js
--- a/browser/base/content/test/general/browser_bug561623.js
+++ b/toolkit/components/tooltiptext/tests/browser_bug561623.js
@@ -1,28 +1,24 @@
-function test() {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(() => {
-    let doc = gBrowser.contentDocument;
-    let tooltip = document.getElementById("aHTMLTooltip");
-    let i = doc.getElementById("i");
-
-    ok(!tooltip.fillInPageTooltip(i),
-       "No tooltip should be shown when @title is null");
+add_task(function*() {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: "data:text/html,<!DOCTYPE html><html><body><input id='i'></body></html>",
+  }, function*(browser) {
+    yield ContentTask.spawn(browser, "", function() {
+      let tttp = Cc["@mozilla.org/embedcomp/default-tooltiptextprovider;1"]
+                 .getService(Ci.nsITooltipTextProvider);
+      let i = content.document.getElementById("i");
 
-    i.title = "foo";
-    ok(tooltip.fillInPageTooltip(i),
-       "A tooltip should be shown when @title is not the empty string");
+      ok(!tttp.getNodeText(i, {}, {}),
+         "No tooltip should be shown when @title is null");
 
-    i.pattern = "bar";
-    ok(tooltip.fillInPageTooltip(i),
-       "A tooltip should be shown when @title is not the empty string");
+      i.title = "foo";
+      ok(tttp.getNodeText(i, {}, {}),
+         "A tooltip should be shown when @title is not the empty string");
 
-    gBrowser.removeCurrentTab();
-    finish();
+      i.pattern = "bar";
+      ok(tttp.getNodeText(i, {}, {}),
+         "A tooltip should be shown when @title is not the empty string");
+    });
   });
+});
 
-  gBrowser.loadURI(
-    "data:text/html,<!DOCTYPE html><html><body><input id='i'></body></html>"
-  );
-}
-
rename from browser/base/content/test/general/browser_bug581947.js
rename to toolkit/components/tooltiptext/tests/browser_bug581947.js
--- a/browser/base/content/test/general/browser_bug581947.js
+++ b/toolkit/components/tooltiptext/tests/browser_bug581947.js
@@ -1,94 +1,90 @@
-function check(aElementName, aBarred, aType) {
-  let doc = gBrowser.contentDocument;
-  let tooltip = document.getElementById("aHTMLTooltip");
-  let content = doc.getElementById('content');
+function check(aBrowser, aElementName, aBarred, aType) {
+  return ContentTask.spawn(aBrowser, [aElementName, aBarred, aType], function*([aElementName, aBarred, aType]) {
+    let doc = content.document;
+    let e = content.document.createElement(aElementName);
+    let contentElement = content.document.getElementById('content');
+    contentElement.appendChild(e);
 
-  let e = doc.createElement(aElementName);
-  content.appendChild(e);
-  
-  if (aType) {
-    e.type = aType;
-  }
+    if (aType) {
+      e.type = aType;
+    }
 
-  ok(!tooltip.fillInPageTooltip(e),
-     "No tooltip should be shown when the element is valid");
+    let tttp = Cc["@mozilla.org/embedcomp/default-tooltiptextprovider;1"]
+               .getService(Ci.nsITooltipTextProvider);
+    ok(!tttp.getNodeText(e, {}, {}),
+       "No tooltip should be shown when the element is valid");
 
-  e.setCustomValidity('foo');
-  if (aBarred) {
-    ok(!tooltip.fillInPageTooltip(e),
-       "No tooltip should be shown when the element is barred from constraint validation");
-  } else {
-    ok(tooltip.fillInPageTooltip(e),
-       e.tagName + " " +"A tooltip should be shown when the element isn't valid");
-  }
+    e.setCustomValidity('foo');
+    if (aBarred) {
+      ok(!tttp.getNodeText(e, {}, {}),
+         "No tooltip should be shown when the element is barred from constraint validation");
+    } else {
+      ok(tttp.getNodeText(e, {}, {}),
+         e.tagName + " " +"A tooltip should be shown when the element isn't valid");
+    }
 
-  e.setAttribute('title', '');
-  ok (!tooltip.fillInPageTooltip(e),
-      "No tooltip should be shown if the title attribute is set");
+    e.setAttribute('title', '');
+    ok (!tttp.getNodeText(e, {}, {}),
+        "No tooltip should be shown if the title attribute is set");
 
-  e.removeAttribute('title');
-  content.setAttribute('novalidate', '');
-  ok (!tooltip.fillInPageTooltip(e),
-      "No tooltip should be shown if the novalidate attribute is set on the form owner");
-  content.removeAttribute('novalidate');
+    e.removeAttribute('title');
+    contentElement.setAttribute('novalidate', '');
+    ok (!tttp.getNodeText(e, {}, {}),
+        "No tooltip should be shown if the novalidate attribute is set on the form owner");
+    contentElement.removeAttribute('novalidate');
 
-  content.removeChild(e);
+    e.remove();
+  });
 }
 
-function todo_check(aElementName, aBarred) {
-  let doc = gBrowser.contentDocument;
-  let tooltip = document.getElementById("aHTMLTooltip");
-  let content = doc.getElementById('content');
-
-  let e = doc.createElement(aElementName);
-  content.appendChild(e);
+function todo_check(aBrowser, aElementName, aBarred) {
+  return ContentTask.spawn(aBrowser, [aElementName, aBarred], function*([aElementName, aBarred]) {
+    let doc = content.document;
+    let e = content.document.createElement(aElementName);
+    let contentElement = content.document.getElementById('content');
+    contentElement.appendChild(e);
 
-  let cought = false;
-  try {
-    e.setCustomValidity('foo');
-  } catch (e) {
-    cought = true;
-  }
+    let caught = false;
+    try {
+      e.setCustomValidity('foo');
+    } catch (e) {
+      caught = true;
+    }
 
-  todo(!cought, "setCustomValidity should exist for " + aElementName);
+    todo(!caught, "setCustomValidity should exist for " + aElementName);
 
-  content.removeChild(e);
+    e.remove();
+  });
 }
 
-function test () {
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(() => {
+add_task(function*() {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: "data:text/html,<!DOCTYPE html><html><body><form id='content'></form></body></html>",
+  }, function*(browser) {
     let testData = [
     /* element name, barred */
       [ 'input',    false,  null],
       [ 'textarea', false,  null],
       [ 'button',   true,  'button'],
       [ 'button',   false, 'submit'],
       [ 'select',   false,  null],
       [ 'output',   true,   null],
       [ 'fieldset', true,   null],
       [ 'object',   true,   null],
     ];
 
     for (let data of testData) {
-      check(data[0], data[1], data[2]);
+      yield check(browser, data[0], data[1], data[2]);
     }
 
     let todo_testData = [
       [ 'keygen', 'false' ],
     ];
 
     for (let data of todo_testData) {
-      todo_check(data[0], data[1]);
+      yield todo_check(browser, data[0], data[1]);
     }
-
-    gBrowser.removeCurrentTab();
-    finish();
   });
+});
 
-  gBrowser.loadURI(
-    "data:text/html,<!DOCTYPE html><html><body><form id='content'></form></body></html>"
-  );
-}
-
rename from toolkit/content/tests/browser/browser_input_file_tooltips.js
rename to toolkit/components/tooltiptext/tests/browser_input_file_tooltips.js
copy from browser/base/content/test/general/title_test.svg
copy to toolkit/components/tooltiptext/tests/title_test.svg
rename from browser/base/content/test/general/xul_tooltiptext.xhtml
rename to toolkit/components/tooltiptext/tests/xul_tooltiptext.xhtml
--- a/toolkit/content/tests/browser/browser.ini
+++ b/toolkit/content/tests/browser/browser.ini
@@ -9,17 +9,16 @@ support-files =
 [browser_bug594509.js]
 [browser_bug982298.js]
 [browser_bug1198465.js]
 [browser_contentTitle.js]
 [browser_default_image_filename.js]
 [browser_f7_caret_browsing.js]
 skip-if = e10s
 [browser_findbar.js]
-[browser_input_file_tooltips.js]
 [browser_isSynthetic.js]
 support-files =
   empty.png
 [browser_keyevents_during_autoscrolling.js]
 [browser_save_resend_postdata.js]
 support-files =
   common/mockTransfer.js
   data/post_form_inner.sjs
--- a/toolkit/content/widgets/popup.xml
+++ b/toolkit/content/widgets/popup.xml
@@ -520,157 +520,45 @@
       <property name="label"
                 onget="return this.getAttribute('label');"
                 onset="this.setAttribute('label', val); return val;"/>
 
       <property name="page" onset="if (val) this.setAttribute('page', 'true');
                                    else this.removeAttribute('page');
                                    return val;"
                             onget="return this.getAttribute('page') == 'true';"/>
+      <property name="textProvider"
+                readonly="true">
+        <getter>
+        <![CDATA[
+          if (!this._textProvider) {
+            this._textProvider = Components.classes["@mozilla.org/embedcomp/default-tooltiptextprovider;1"]
+                                 .getService(Components.interfaces.nsITooltipTextProvider);
+          }
+          return this._textProvider;
+        ]]>
+        </getter>
+      </property>
 
       <!-- Given the supplied element within a page, set the tooltip's text to the text
            for that element. Returns true if text was assigned, and false if the no text
            is set, which normally would be used to cancel tooltip display.
-
-           Note that DefaultTooltipTextProvider::GetNodeText() from nsDocShellTreeOwner.cpp
-           also performs the same function, but for embedded clients that don't use a XUL/JS
-           layer. These two should be kept synchronized.
         -->
       <method name="fillInPageTooltip">
         <parameter name="tipElement"/>
         <body>
         <![CDATA[
-          // Don't show the tooltip if the tooltip node is a document, browser, or disconnected.
-          if (!tipElement || !tipElement.ownerDocument ||
-              tipElement.localName == "browser" ||
-              (tipElement.ownerDocument.compareDocumentPosition(tipElement) & document.DOCUMENT_POSITION_DISCONNECTED)) {
-            return false;
-          }
-
-          var defView = tipElement.ownerDocument.defaultView;
-          // XXX Work around bug 350679:
-          // "Tooltips can be fired in documents with no view".
-          if (!defView)
-            return false;
-
-          const XLinkNS = "http://www.w3.org/1999/xlink";
-          const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-
-          var titleText = null;
-          var XLinkTitleText = null;
-          var SVGTitleText = null;
-          var XULtooltiptextText = null;
-          var lookingForSVGTitle = true;
-          var direction = tipElement.ownerDocument.dir;
-
-          // If the element is invalid per HTML5 Forms specifications and has no title,
-          // show the constraint validation error message.
-          if ((tipElement instanceof HTMLInputElement ||
-               tipElement instanceof HTMLTextAreaElement ||
-               tipElement instanceof HTMLSelectElement ||
-               tipElement instanceof HTMLButtonElement) &&
-              !tipElement.hasAttribute('title') &&
-              (!tipElement.form || !tipElement.form.noValidate)) {
-            // If the element is barred from constraint validation or valid,
-            // the validation message will be the empty string.
-            titleText = tipElement.validationMessage || null;
+          let tttp = this.textProvider;
+          let textObj = {}, dirObj = {};
+          let shouldChangeText = tttp.getNodeText(tipElement, textObj, dirObj);
+          if (shouldChangeText) {
+            this.style.direction = dirObj.value;
+            this.label = textObj.value;
           }
-
-          // If the element is an <input type='file'> without a title, we should show
-          // the current file selection.
-          if (!titleText &&
-              tipElement instanceof HTMLInputElement &&
-              tipElement.type == 'file' &&
-              !tipElement.hasAttribute('title')) {
-            let files = tipElement.files;
-
-            try {
-              var bundle = Components.classes['@mozilla.org/intl/stringbundle;1']
-                                     .getService(Components.interfaces.nsIStringBundleService)
-                                     .createBundle("chrome://global/locale/layout/HtmlForm.properties");
-              if (files.length == 0) {
-                if (tipElement.multiple) {
-                  titleText = bundle.GetStringFromName("NoFilesSelected");
-                } else {
-                  titleText = bundle.GetStringFromName("NoFileSelected");
-                }
-              } else {
-                titleText = files[0].name;
-                // For UX and performance (jank) reasons we cap the number of
-                // files that we list in the tooltip to 20 plus a "and xxx more"
-                // line, or to 21 if exactly 21 files were picked.
-                const TRUNCATED_FILE_COUNT = 20;
-                let count = Math.min(files.length, TRUNCATED_FILE_COUNT);
-                for (let i = 1; i < count; ++i) {
-                  titleText += "\n" + files[i].name;
-                }
-                if (files.length == TRUNCATED_FILE_COUNT + 1) {
-                  titleText += "\n" + files[TRUNCATED_FILE_COUNT].name;
-                } else if (files.length > TRUNCATED_FILE_COUNT + 1) {
-                  let xmoreStr = bundle.GetStringFromName("AndNMoreFiles");
-                  let xmoreNum = files.length - TRUNCATED_FILE_COUNT;
-                  let tmp = {};
-                  Components.utils.import("resource://gre/modules/PluralForm.jsm", tmp);
-                  let andXMoreStr = tmp.PluralForm.get(xmoreNum, xmoreStr).replace("#1", xmoreNum);
-                  titleText += "\n" + andXMoreStr;
-                }
-              }
-            } catch(e) {}
-          }
-
-          // Check texts against null so that title="" can be used to undefine a
-          // title on a child element.
-          while (tipElement &&
-                 (titleText == null) && (XLinkTitleText == null) &&
-                 (SVGTitleText == null) && (XULtooltiptextText == null)) {
-
-            if (tipElement.nodeType == Node.ELEMENT_NODE) {
-              if (tipElement.namespaceURI == XULNS)
-                XULtooltiptextText = tipElement.getAttribute("tooltiptext");
-              else if (!(tipElement instanceof SVGElement))
-                titleText = tipElement.getAttribute("title");
-
-              if ((tipElement instanceof HTMLAnchorElement ||
-                   tipElement instanceof HTMLAreaElement ||
-                   tipElement instanceof HTMLLinkElement ||
-                   tipElement instanceof SVGAElement) && tipElement.href) {
-                XLinkTitleText = tipElement.getAttributeNS(XLinkNS, "title");
-              }
-              if (lookingForSVGTitle &&
-                  (!(tipElement instanceof SVGElement) ||
-                   tipElement.parentNode.nodeType == Node.DOCUMENT_NODE)) {
-                lookingForSVGTitle = false;
-              }
-              if (lookingForSVGTitle) {
-                for (let childNode of tipElement.childNodes) {
-                  if (childNode instanceof SVGTitleElement) {
-                    SVGTitleText = childNode.textContent;
-                    break;
-                  }
-                }
-              }
-
-              direction = defView.getComputedStyle(tipElement, "")
-                                 .getPropertyValue("direction");
-            }
-
-            tipElement = tipElement.parentNode;
-          }
-
-          this.style.direction = direction;
-
-          return [titleText, XLinkTitleText, SVGTitleText, XULtooltiptextText].some(function (t) {
-            if (t && /\S/.test(t)) {
-              // Make CRLF and CR render one line break each.
-              this.label = t.replace(/\r\n?/g, '\n');
-              return true;
-            }
-
-            return false;
-          }, this);
+          return shouldChangeText;
         ]]>
         </body>
       </method>
     </implementation>
 
     <handlers>
       <handler event="mouseover"><![CDATA[
         var rel = event.relatedTarget;
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -1359,16 +1359,51 @@ ChildFPEFilter(void* context, EXCEPTION_
 {
   bool result = FPEFilter(context, exinfo, assertion);
   if (result) {
     PrepareChildExceptionTimeAnnotations();
   }
   return result;
 }
 
+MINIDUMP_TYPE GetMinidumpType()
+{
+  MINIDUMP_TYPE minidump_type = MiniDumpNormal;
+
+  // Try to determine what version of dbghelp.dll we're using.
+  // MinidumpWithFullMemoryInfo is only available in 6.1.x or newer.
+
+  DWORD version_size = GetFileVersionInfoSizeW(L"dbghelp.dll", nullptr);
+  if (version_size > 0) {
+    std::vector<BYTE> buffer(version_size);
+    if (GetFileVersionInfoW(L"dbghelp.dll",
+                            0,
+                            version_size,
+                            &buffer[0])) {
+      UINT len;
+      VS_FIXEDFILEINFO* file_info;
+      VerQueryValue(&buffer[0], L"\\", (void**)&file_info, &len);
+      WORD major = HIWORD(file_info->dwFileVersionMS),
+        minor = LOWORD(file_info->dwFileVersionMS),
+        revision = HIWORD(file_info->dwFileVersionLS);
+      if (major > 6 || (major == 6 && minor > 1) ||
+          (major == 6 && minor == 1 && revision >= 7600)) {
+        minidump_type = MiniDumpWithFullMemoryInfo;
+      }
+    }
+  }
+
+  const char* e = PR_GetEnv("MOZ_CRASHREPORTER_FULLDUMP");
+  if (e && *e) {
+    minidump_type = MiniDumpWithFullMemory;
+  }
+
+  return minidump_type;
+}
+
 #endif // XP_WIN
 
 static bool ShouldReport()
 {
   // this environment variable prevents us from launching
   // the crash reporter client
   const char *envvar = PR_GetEnv("MOZ_CRASHREPORTER_NO_REPORT");
   if (envvar && *envvar) {
@@ -1516,46 +1551,16 @@ nsresult SetExceptionHandler(nsIFile* aX
       attr_ocount != attr_count) {
     posix_spawnattr_destroy(&spawnattr);
     return NS_ERROR_FAILURE;
   }
 #endif
 
 #ifdef XP_WIN32
   ReserveBreakpadVM();
-
-  MINIDUMP_TYPE minidump_type = MiniDumpNormal;
-
-  // Try to determine what version of dbghelp.dll we're using.
-  // MinidumpWithFullMemoryInfo is only available in 6.1.x or newer.
-
-  DWORD version_size = GetFileVersionInfoSizeW(L"dbghelp.dll", nullptr);
-  if (version_size > 0) {
-    std::vector<BYTE> buffer(version_size);
-    if (GetFileVersionInfoW(L"dbghelp.dll",
-                            0,
-                            version_size,
-                            &buffer[0])) {
-      UINT len;
-      VS_FIXEDFILEINFO* file_info;
-      VerQueryValue(&buffer[0], L"\\", (void**)&file_info, &len);
-      WORD major = HIWORD(file_info->dwFileVersionMS),
-           minor = LOWORD(file_info->dwFileVersionMS),
-           revision = HIWORD(file_info->dwFileVersionLS);
-      if (major > 6 || (major == 6 && minor > 1) ||
-          (major == 6 && minor == 1 && revision >= 7600)) {
-        minidump_type = MiniDumpWithFullMemoryInfo;
-      }
-    }
-  }
-
-  const char* e = PR_GetEnv("MOZ_CRASHREPORTER_FULLDUMP");
-  if (e && *e) {
-    minidump_type = MiniDumpWithFullMemory;
-  }
 #endif // XP_WIN32
 
 #ifdef MOZ_WIDGET_ANDROID
   androidUserSerial = getenv("MOZ_ANDROID_USER_SERIAL_NUMBER");
 #endif
 
   // Initialize the flag and mutex used to avoid dump processing
   // once browser termination has begun.
@@ -1589,17 +1594,17 @@ nsresult SetExceptionHandler(nsIFile* aX
                      FPEFilter,
 #else
                      Filter,
 #endif
                      MinidumpCallback,
                      nullptr,
 #ifdef XP_WIN32
                      google_breakpad::ExceptionHandler::HANDLER_ALL,
-                     minidump_type,
+                     GetMinidumpType(),
                      (const wchar_t*) nullptr,
                      nullptr);
 #else
                      true
 #ifdef XP_MACOSX
                        , nullptr
 #endif
 #ifdef XP_LINUX
@@ -3477,17 +3482,17 @@ SetRemoteExceptionHandler(const nsACStri
   MOZ_ASSERT(!gExceptionHandler, "crash client already init'd");
 
   gExceptionHandler = new google_breakpad::
     ExceptionHandler(L"",
                      ChildFPEFilter,
                      nullptr,    // no minidump callback
                      nullptr,    // no callback context
                      google_breakpad::ExceptionHandler::HANDLER_ALL,
-                     MiniDumpNormal,
+                     GetMinidumpType(),
                      NS_ConvertASCIItoUTF16(crashPipe).get(),
                      nullptr);
   gExceptionHandler->set_handle_debug_exceptions(true);
 
   mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize);
 
   // we either do remote or nothing, no fallback to regular crash reporting
   return gExceptionHandler->IsOutOfProcess();
--- a/toolkit/crashreporter/test/unit/test_crashreporter_crash.js
+++ b/toolkit/crashreporter/test/unit/test_crashreporter_crash.js
@@ -1,15 +1,10 @@
 function run_test()
 {
-  if (!("@mozilla.org/toolkit/crash-reporter;1" in Components.classes)) {
-    dump("INFO | test_crashreporter.js | Can't test crashreporter in a non-libxul build.\n");
-    return;
-  }
-
   var is_win7_or_newer = false;
   var is_windows = false;
   var ph = Components.classes["@mozilla.org/network/protocol;1?name=http"]
              .getService(Components.interfaces.nsIHttpProtocolHandler);
   var match = ph.userAgent.match(/Windows NT (\d+).(\d+)/);
   if (match) {
       is_windows = true;
   }
copy from toolkit/crashreporter/test/unit/test_crashreporter_crash.js
copy to toolkit/crashreporter/test/unit_ipc/test_content_memory_list.js
--- a/toolkit/crashreporter/test/unit/test_crashreporter_crash.js
+++ b/toolkit/crashreporter/test/unit_ipc/test_content_memory_list.js
@@ -1,56 +1,23 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+
+load("../unit/head_crashreporter.js");
+
 function run_test()
 {
-  if (!("@mozilla.org/toolkit/crash-reporter;1" in Components.classes)) {
-    dump("INFO | test_crashreporter.js | Can't test crashreporter in a non-libxul build.\n");
-    return;
-  }
-
   var is_win7_or_newer = false;
-  var is_windows = false;
   var ph = Components.classes["@mozilla.org/network/protocol;1?name=http"]
              .getService(Components.interfaces.nsIHttpProtocolHandler);
   var match = ph.userAgent.match(/Windows NT (\d+).(\d+)/);
-  if (match) {
-      is_windows = true;
-  }
   if (match && (parseInt(match[1]) > 6 ||
                 parseInt(match[1]) == 6 && parseInt(match[2]) >= 1)) {
       is_win7_or_newer = true;
   }
 
-  // try a basic crash
-  do_crash(null, function(mdump, extra) {
+  do_content_crash(null, function(mdump, extra) {
              do_check_true(mdump.exists());
              do_check_true(mdump.fileSize > 0);
-             do_check_true('StartupTime' in extra);
-             do_check_true('CrashTime' in extra);
-             do_check_true(CrashTestUtils.dumpHasStream(mdump.path, CrashTestUtils.MD_THREAD_LIST_STREAM));
-             do_check_true(CrashTestUtils.dumpHasInstructionPointerMemory(mdump.path));
-             if (is_windows) {
-               ['SystemMemoryUsePercentage', 'TotalVirtualMemory', 'AvailableVirtualMemory',
-                'AvailablePageFile', 'AvailablePhysicalMemory'].forEach(function(prop) {
-                  do_check_true(/^\d+$/.test(extra[prop].toString()));
-               });
-             }
              if (is_win7_or_newer)
                do_check_true(CrashTestUtils.dumpHasStream(mdump.path, CrashTestUtils.MD_MEMORY_INFO_LIST_STREAM));
            });
-
-  // check setting some basic data
-  do_crash(function() {
-             crashReporter.annotateCrashReport("TestKey", "TestValue");
-             crashReporter.annotateCrashReport("\u2665", "\u{1F4A9}");
-             crashReporter.appendAppNotesToCrashReport("Junk");
-             crashReporter.appendAppNotesToCrashReport("MoreJunk");
-             // TelemetrySession setup will trigger the session annotation
-             let scope = {};
-             Components.utils.import("resource://gre/modules/TelemetrySession.jsm", scope);
-             scope.TelemetrySession.setup();
-           },
-           function(mdump, extra) {
-             do_check_eq(extra.TestKey, "TestValue");
-             do_check_eq(extra["\u2665"], "\u{1F4A9}");
-             do_check_eq(extra.Notes, "JunkMoreJunk");
-             do_check_true(!("TelemetrySessionId" in extra));
-           });
 }
--- a/toolkit/crashreporter/test/unit_ipc/xpcshell.ini
+++ b/toolkit/crashreporter/test/unit_ipc/xpcshell.ini
@@ -6,8 +6,10 @@ support-files =
   !/toolkit/crashreporter/test/unit/crasher_subprocess_head.js
   !/toolkit/crashreporter/test/unit/crasher_subprocess_tail.js
   !/toolkit/crashreporter/test/unit/head_crashreporter.js
 
 [test_content_annotation.js]
 [test_content_exception_time_annotation.js]
 [test_content_oom_annotation_windows.js]
 skip-if = os != 'win'
+[test_content_memory_list.js]
+skip-if = os != 'win'
--- a/toolkit/modules/Troubleshoot.jsm
+++ b/toolkit/modules/Troubleshoot.jsm
@@ -238,17 +238,21 @@ var dataProviders = {
     done(data);
   },
 
   extensions: function extensions(done) {
     AddonManager.getAddonsByTypes(["extension"], function (extensions) {
       extensions.sort(function (a, b) {
         if (a.isActive != b.isActive)
           return b.isActive ? 1 : -1;
-        let lc = a.name.localeCompare(b.name);
+
+        // In some unfortunate cases addon names can be null.
+        let aname = a.name || null;
+        let bname = b.name || null;
+        let lc = aname.localeCompare(bname);
         if (lc != 0)
           return lc;
         if (a.version != b.version)
           return a.version > b.version ? 1 : -1;
         return 0;
       });
       let props = ["name", "version", "isActive", "id"];
       done(extensions.map(function (ext) {
--- a/toolkit/mozapps/extensions/internal/GMPProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/GMPProvider.jsm
@@ -36,16 +36,17 @@ const SEC_IN_A_DAY           = 24 * 60 *
 // How long to wait after a user enabled EME before attempting to download CDMs.
 const GMP_CHECK_DELAY        = 10 * 1000; // milliseconds
 
 const NS_GRE_DIR             = "GreD";
 const CLEARKEY_PLUGIN_ID     = "gmp-clearkey";
 const CLEARKEY_VERSION       = "0.1";
 
 const GMP_LICENSE_INFO       = "gmp_license_info";
+const GMP_PRIVACY_INFO       = "gmp_privacy_info";
 const GMP_LEARN_MORE         = "learn_more_label";
 
 const GMP_PLUGINS = [
   {
     id:              OPEN_H264_ID,
     name:            "openH264_name",
     description:     "openH264_description2",
     // The following licenseURL is part of an awful hack to include the OpenH264
@@ -70,20 +71,21 @@ const GMP_PLUGINS = [
     homepageURL:     "http://help.adobe.com/en_US/primetime/drm/HTML5_CDM",
     optionsURL:      "chrome://mozapps/content/extensions/gmpPrefs.xul",
     isEME:           true,
     missingKey:      "VIDEO_ADOBE_GMP_DISAPPEARED",
     missingFilesKey: "VIDEO_ADOBE_GMP_MISSING_FILES",
   },
   {
     id:              WIDEVINE_ID,
-    name:            "widevine_name",
-    description:     "widevine_description",
-    licenseURL:      "http://www.google.com/policies/terms/",
-    homepageURL:     "http://www.widevine.com/",
+    name:            "widevine_description",
+    // Describe the purpose of both CDMs in the same way.
+    description:     "eme-adobe_description",
+    licenseURL:      "https://www.google.com/policies/privacy/",
+    homepageURL:     "https://www.widevine.com/",
     optionsURL:      "chrome://mozapps/content/extensions/gmpPrefs.xul",
     isEME:           true
   }];
 XPCOMUtils.defineConstant(this, "GMP_PLUGINS", GMP_PLUGINS);
 
 XPCOMUtils.defineLazyGetter(this, "pluginsBundle",
   () => Services.strings.createBundle("chrome://global/locale/plugins.properties"));
 XPCOMUtils.defineLazyGetter(this, "gmpService",
@@ -672,17 +674,18 @@ var GMPProvider = {
 
   get isEnabled() {
     return GMPPrefs.get(GMPPrefs.KEY_PROVIDER_ENABLED, false);
   },
 
   generateFullDescription: function(aPlugin) {
     let rv = [];
     for (let [urlProp, labelId] of [["learnMoreURL", GMP_LEARN_MORE],
-                                    ["licenseURL", GMP_LICENSE_INFO]]) {
+                                    ["licenseURL", aPlugin.id == WIDEVINE_ID ?
+                                     GMP_PRIVACY_INFO : GMP_LICENSE_INFO]]) {
       if (aPlugin[urlProp]) {
         let label = pluginsBundle.GetStringFromName(labelId);
         rv.push(`<xhtml:a href="${aPlugin[urlProp]}" target="_blank">${label}</xhtml:a>.`);
       }
     }
     return rv.length ? rv.join("<xhtml:br /><xhtml:br />") : undefined;
   },
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
@@ -59,18 +59,22 @@ function load_blocklist(aFile, aCallback
 
     do_execute_soon(aCallback);
   }, "blocklist-updated", false);
 
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + aFile);
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
-  ok(Services.prefs.getBoolPref("services.kinto.update_enabled", false),
-                                "Kinto update should be enabled");
+  // if we're not using the blocklist.xml for certificate blocklist state,
+  // ensure that kinto update is enabled
+  if (!Services.prefs.getBoolPref("security.onecrl.via.amo")) {
+    ok(Services.prefs.getBoolPref("services.kinto.update_enabled", false),
+                                  "Kinto update should be enabled");
+  }
   blocklist.notify(null);
 }
 
 
 function end_test() {
   testserver.stop(do_test_finished);
 }
 
--- a/view/nsView.cpp
+++ b/view/nsView.cpp
@@ -1073,27 +1073,29 @@ nsView::PaintWindow(nsIWidget* aWidget, 
 void
 nsView::DidPaintWindow()
 {
   RefPtr<nsViewManager> vm = mViewManager;
   vm->DidPaintWindow();
 }
 
 void
-nsView::DidCompositeWindow(const TimeStamp& aCompositeStart,
+nsView::DidCompositeWindow(uint64_t aTransactionId,
+                           const TimeStamp& aCompositeStart,
                            const TimeStamp& aCompositeEnd)
 {
   nsIPresShell* presShell = mViewManager->GetPresShell();
   if (presShell) {
     nsAutoScriptBlocker scriptBlocker;
 
     nsPresContext* context = presShell->GetPresContext();
     nsRootPresContext* rootContext = context->GetRootPresContext();
     MOZ_ASSERT(rootContext, "rootContext must be valid.");
-    rootContext->NotifyDidPaintForSubtree(nsIPresShell::PAINT_COMPOSITE);
+    rootContext->NotifyDidPaintForSubtree(nsIPresShell::PAINT_COMPOSITE, aTransactionId,
+                                          aCompositeEnd);
 
     // If the two timestamps are identical, this was likely a fake composite
     // event which wouldn't be terribly useful to display.
     if (aCompositeStart == aCompositeEnd) {
       return;
     }
 
     nsIDocShell* docShell = context->GetDocShell();
--- a/view/nsView.h
+++ b/view/nsView.h
@@ -381,17 +381,18 @@ public:
   virtual nsView* GetView() override { return this; }
   virtual bool WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y) override;
   virtual bool WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight) override;
   virtual bool RequestWindowClose(nsIWidget* aWidget) override;
   virtual void WillPaintWindow(nsIWidget* aWidget) override;
   virtual bool PaintWindow(nsIWidget* aWidget,
                            LayoutDeviceIntRegion aRegion) override;
   virtual void DidPaintWindow() override;
-  virtual void DidCompositeWindow(const mozilla::TimeStamp& aCompositeStart,
+  virtual void DidCompositeWindow(uint64_t aTransactionId,
+                                  const mozilla::TimeStamp& aCompositeStart,
                                   const mozilla::TimeStamp& aCompositeEnd) override;
   virtual void RequestRepaint() override;
   virtual nsEventStatus HandleEvent(mozilla::WidgetGUIEvent* aEvent,
                                     bool aUseAttachedEvents) override;
 
   virtual ~nsView();
 
   nsPoint GetOffsetTo(const nsView* aOther, const int32_t aAPD) const;
--- a/widget/nsIWidgetListener.cpp
+++ b/widget/nsIWidgetListener.cpp
@@ -107,17 +107,18 @@ nsIWidgetListener::PaintWindow(nsIWidget
 }
 
 void
 nsIWidgetListener::DidPaintWindow()
 {
 }
 
 void
-nsIWidgetListener::DidCompositeWindow(const TimeStamp& aCompositeStart,
+nsIWidgetListener::DidCompositeWindow(uint64_t aTransactionId,
+                                      const TimeStamp& aCompositeStart,
                                       const TimeStamp& aCompositeEnd)
 {
 }
 
 void
 nsIWidgetListener::RequestRepaint()
 {
 }
--- a/widget/nsIWidgetListener.h
+++ b/widget/nsIWidgetListener.h
@@ -141,17 +141,18 @@ public:
   /**
    * Indicates that a paint occurred.
    * This is called at a time when it is OK to change the geometry of
    * this widget or of other widgets.
    * Must be called after every call to PaintWindow.
    */
   virtual void DidPaintWindow();
 
-  virtual void DidCompositeWindow(const mozilla::TimeStamp& aCompositeStart,
+  virtual void DidCompositeWindow(uint64_t aTransactionId,
+                                  const mozilla::TimeStamp& aCompositeStart,
                                   const mozilla::TimeStamp& aCompositeEnd);
 
   /**
    * Request that layout schedules a repaint on the next refresh driver tick.
    */
   virtual void RequestRepaint();
 
   /**
--- a/xpcom/glue/nsProxyRelease.h
+++ b/xpcom/glue/nsProxyRelease.h
@@ -219,16 +219,17 @@ private:
 
 template<class T>
 class nsMainThreadPtrHandle
 {
   RefPtr<nsMainThreadPtrHolder<T>> mPtr;
 
 public:
   nsMainThreadPtrHandle() : mPtr(nullptr) {}
+  MOZ_IMPLICIT nsMainThreadPtrHandle(decltype(nullptr)) : mPtr(nullptr) {}
   explicit nsMainThreadPtrHandle(nsMainThreadPtrHolder<T>* aHolder)
     : mPtr(aHolder)
   {
   }
   nsMainThreadPtrHandle(const nsMainThreadPtrHandle& aOther)
     : mPtr(aOther.mPtr)
   {
   }
@@ -271,14 +272,16 @@ public:
       return mPtr == aOther.mPtr;
     }
     return *mPtr == *aOther.mPtr;
   }
   bool operator!=(const nsMainThreadPtrHandle<T>& aOther) const
   {
     return !operator==(aOther);
   }
+  bool operator==(decltype(nullptr)) const { return mPtr == nullptr; }
+  bool operator!=(decltype(nullptr)) const { return mPtr != nullptr; }
   bool operator!() const {
     return !mPtr || !*mPtr;
   }
 };
 
 #endif
--- a/xpfe/appshell/nsIXULBrowserWindow.idl
+++ b/xpfe/appshell/nsIXULBrowserWindow.idl
@@ -60,12 +60,17 @@ interface nsIXULBrowserWindow : nsISuppo
    *        The referrer of the load.
    */
   bool shouldLoadURI(in nsIDocShell    aDocShell,
                      in nsIURI         aURI,
                      in nsIURI         aReferrer);
   /**
    * Show/hide a tooltip (when the user mouses over a link, say).
    */
-  void showTooltip(in long x, in long y, in AString tooltip);
+  void showTooltip(in long x, in long y, in AString tooltip, in AString direction);
   void hideTooltip();
+
+  /**
+   * Return the number of tabs in this window.
+   */
+  uint32_t getTabCount();
 };