Merge m-c to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 25 Sep 2014 15:28:31 +0200
changeset 222683 822ade44d100d8dbf3955f6d62149ef88779210d
parent 222682 3164ff8ce17cf5afc66cecd485932c1dc030d16d (current diff)
parent 222641 e9e56750ca5b4a9ac8dbcedf253e298545fe9da9 (diff)
child 222684 d64aba881c45476d110b1b5a285265ba4955b8e7
push id7107
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 17:43:31 +0000
treeherdermozilla-aurora@b4b34e0acc75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone35.0a1
Merge m-c to fx-team
layout/generic/nsObjectFrame.cpp
layout/generic/nsObjectFrame.h
--- a/accessible/base/TextAttrs.cpp
+++ b/accessible/base/TextAttrs.cpp
@@ -455,17 +455,17 @@ TextAttrsMgr::FontFamilyTextAttr::
 bool
 TextAttrsMgr::FontFamilyTextAttr::
   GetFontFamily(nsIFrame* aFrame, nsString& aFamily)
 {
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm));
 
   gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
-  gfxFont* font = fontGroup->GetFontAt(0);
+  gfxFont* font = fontGroup->GetFirstValidFont();
   gfxFontEntry* fontEntry = font->GetFontEntry();
   aFamily = fontEntry->FamilyName();
   return true;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // FontSizeTextAttr
@@ -613,17 +613,17 @@ TextAttrsMgr::FontWeightTextAttr::
   GetFontWeight(nsIFrame* aFrame)
 {
   // nsFont::width isn't suitable here because it's necessary to expose real
   // value of font weight (used font might not have some font weight values).
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm));
 
   gfxFontGroup *fontGroup = fm->GetThebesFontGroup();
-  gfxFont *font = fontGroup->GetFontAt(0);
+  gfxFont *font = fontGroup->GetFirstValidFont();
 
   // When there doesn't exist a bold font in the family and so the rendering of
   // a non-bold font face is changed so that the user sees what looks like a
   // bold font, i.e. synthetic bolding is used. IsSyntheticBold method is only
   // needed on Mac, but it is "safe" to use on all platforms.  (For non-Mac
   // platforms it always return false.)
   if (font->IsSyntheticBold())
     return 700;
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -52,17 +52,17 @@
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 #include "nsImageFrame.h"
 #include "nsIObserverService.h"
 #include "nsLayoutUtils.h"
-#include "nsObjectFrame.h"
+#include "nsPluginFrame.h"
 #include "nsSVGPathGeometryFrame.h"
 #include "nsTreeBodyFrame.h"
 #include "nsTreeColumns.h"
 #include "nsTreeUtils.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsXBLBinding.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/dom/DOMStringList.h"
@@ -258,21 +258,21 @@ public:
 private:
   nsCOMPtr<nsIContent> mContent;
 };
 
 NS_IMPL_ISUPPORTS(PluginTimerCallBack, nsITimerCallback)
 #endif
 
 already_AddRefed<Accessible>
-nsAccessibilityService::CreatePluginAccessible(nsObjectFrame* aFrame,
+nsAccessibilityService::CreatePluginAccessible(nsPluginFrame* aFrame,
                                                nsIContent* aContent,
                                                Accessible* aContext)
 {
-  // nsObjectFrame means a plugin, so we need to use the accessibility support
+  // nsPluginFrame means a plugin, so we need to use the accessibility support
   // of the plugin.
   if (aFrame->GetRect().IsEmpty())
     return nullptr;
 
 #if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK)
   nsRefPtr<nsNPAPIPluginInstance> pluginInstance;
   if (NS_SUCCEEDED(aFrame->GetPluginInstance(getter_AddRefs(pluginInstance))) &&
       pluginInstance) {
@@ -1614,18 +1614,18 @@ nsAccessibilityService::CreateAccessible
 
     case eImageType:
       newAcc = new ImageAccessibleWrap(aContent, document);
       break;
     case eOuterDocType:
       newAcc = new OuterDocAccessible(aContent, document);
       break;
     case ePluginType: {
-      nsObjectFrame* objectFrame = do_QueryFrame(aFrame);
-      newAcc = CreatePluginAccessible(objectFrame, aContent, aContext);
+      nsPluginFrame* pluginFrame = do_QueryFrame(aFrame);
+      newAcc = CreatePluginAccessible(pluginFrame, aContent, aContext);
       break;
     }
     case eTextLeafType:
       newAcc = new TextLeafAccessibleWrap(aContent, document);
       break;
     default:
       MOZ_ASSERT(false);
       break;
--- a/accessible/base/nsAccessibilityService.h
+++ b/accessible/base/nsAccessibilityService.h
@@ -10,17 +10,17 @@
 
 #include "mozilla/a11y/DocManager.h"
 #include "mozilla/a11y/FocusManager.h"
 #include "mozilla/a11y/SelectionManager.h"
 
 #include "nsIObserver.h"
 
 class nsImageFrame;
-class nsObjectFrame;
+class nsPluginFrame;
 class nsITreeView;
 
 namespace mozilla {
 namespace a11y {
 
 class ApplicationAccessible;
 
 /**
@@ -58,17 +58,17 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIACCESSIBLERETRIEVAL
   NS_DECL_NSIOBSERVER
 
   // nsIAccessibilityService
   virtual Accessible* GetRootDocumentAccessible(nsIPresShell* aPresShell,
                                                 bool aCanCreate);
   already_AddRefed<Accessible>
-    CreatePluginAccessible(nsObjectFrame* aFrame, nsIContent* aContent,
+    CreatePluginAccessible(nsPluginFrame* aFrame, nsIContent* aContent,
                            Accessible* aContext);
 
   /**
    * Adds/remove ATK root accessible for gtk+ native window to/from children
    * of the application accessible.
    */
   virtual Accessible* AddNativeRootAccessible(void* aAtkAccessible);
   virtual void RemoveNativeRootAccessible(Accessible* aRootAccessible);
--- a/accessible/interfaces/nsIAccessibilityService.h
+++ b/accessible/interfaces/nsIAccessibilityService.h
@@ -19,17 +19,17 @@ class Accessible;
 
 } // namespace a11y
 } // namespace mozilla
 
 class nsINode;
 class nsIContent;
 class nsIFrame;
 class nsIPresShell;
-class nsObjectFrame;
+class nsPluginFrame;
 
 // 10ff6dca-b219-4b64-9a4c-67a62b86edce
 #define NS_IACCESSIBILITYSERVICE_IID \
 { 0x84dd9182, 0x6639, 0x4377, \
  { 0xa4, 0x13, 0xad, 0xe1, 0xae, 0x4e, 0x52, 0xdd } }
 
 class nsIAccessibilityService : public nsIAccessibleRetrieval
 {
--- a/accessible/windows/sdn/sdnTextAccessible.cpp
+++ b/accessible/windows/sdn/sdnTextAccessible.cpp
@@ -177,17 +177,18 @@ sdnTextAccessible::get_fontFamily(BSTR _
 
   nsIFrame* frame = mAccessible->GetFrame();
   if (!frame)
     return E_FAIL;
 
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(frame, getter_AddRefs(fm));
 
-  const nsString& name = fm->GetThebesFontGroup()->GetFontAt(0)->GetName();
+  const nsString& name =
+    fm->GetThebesFontGroup()->GetFirstValidFont()->GetName();
   if (name.IsEmpty())
     return S_FALSE;
 
   *aFontFamily = ::SysAllocStringLen(name.get(), name.Length());
   return *aFontFamily ? S_OK : E_OUTOFMEMORY;
 
   A11Y_TRYBLOCK_END
 }
--- a/addon-sdk/mach_commands.py
+++ b/addon-sdk/mach_commands.py
@@ -43,24 +43,24 @@ class MachCommands(MachCommandBase):
     @Command('generate-addon-sdk-moz-build', category='misc',
         description='Generates the moz.build file for the addon-sdk/ directory.')
     def run_addon_sdk_moz_build(self, **params):
         addon_sdk_dir = mozpath.join(self.topsrcdir, 'addon-sdk')
         js_src_dir = mozpath.join(addon_sdk_dir, 'source/lib')
         dirs_to_files = {}
 
         for path, dirs, files in os.walk(js_src_dir):
-            js_files = [f for f in files if f.endswith(('.js', '.jsm'))]
+            js_files = [f for f in files if f.endswith(('.js', '.jsm', '.html'))]
             if not js_files:
                 continue
 
             relative = mozpath.relpath(path, js_src_dir)
             dirs_to_files[relative] = js_files
 
-        moz_build = """# AUTOMATICALLY GENERATED FROM moz.build.in AND mach.  DO NOT EDIT.
+        moz_build = """# AUTOMATICALLY GENERATED FROM mozbuild.template AND mach.  DO NOT EDIT.
 # 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/.
 
 %(moz-build-template)s
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk":
 %(non-b2g-modules)s
 %(always-on-modules)s"""
--- a/addon-sdk/moz.build
+++ b/addon-sdk/moz.build
@@ -394,16 +394,17 @@ EXTRA_JS_MODULES.commonjs.sdk.tab += [
 ]
 
 EXTRA_JS_MODULES.commonjs.sdk.ui.button.view += [
     'source/lib/sdk/ui/button/view/events.js',
 ]
 
 EXTRA_JS_MODULES.commonjs.sdk.ui.frame += [
     'source/lib/sdk/ui/frame/model.js',
+    'source/lib/sdk/ui/frame/view.html',
     'source/lib/sdk/ui/frame/view.js',
 ]
 
 EXTRA_JS_MODULES.commonjs.sdk.ui.state += [
     'source/lib/sdk/ui/state/events.js',
 ]
 
 EXTRA_JS_MODULES.commonjs.sdk.ui.toolbar += [
--- a/addon-sdk/mozbuild.template
+++ b/addon-sdk/mozbuild.template
@@ -3,13 +3,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 JETPACK_PACKAGE_MANIFESTS += ['source/test/jetpack-package.ini']
 JETPACK_ADDON_MANIFESTS += ['source/test/addons/jetpack-addon.ini']
 
-DIRS += ["source/modules/system"]
-
 EXTRA_JS_MODULES.sdk += [
     'source/app-extension/bootstrap.js',
 ]
+
+EXTRA_JS_MODULES.sdk.system += [
+    'source/modules/system/Startup.js',
+    'source/modules/system/XulApp.js',
+]
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -739,24 +739,24 @@ pref("hal.processPriorityManager.gonk.BA
 
 // Processes get this niceness when they have low CPU priority.
 pref("hal.processPriorityManager.gonk.LowCPUNice", 18);
 
 // By default the compositor thread on gonk runs without real-time priority.  RT
 // priority can be enabled by setting this pref to a value between 1 and 99.
 // Note that audio processing currently runs at RT priority 2 or 3 at most.
 //
-// If RT priority is disabled, then the compositor nice value is used.  The
-// code will default to ANDROID_PRIORITY_URGENT_DISPLAY which is -8.  Per gfx
-// request we are keeping the compositor at nice level 0 until we can complete
-// the investigation in bug 982972.
+// If RT priority is disabled, then the compositor nice value is used. We prefer
+// to use a nice value of -4, which matches Android's preferences. Setting a preference
+// of RT priority 1 would mean it is higher than audio, which is -16. The compositor
+// priority must be below the audio thread.
 //
 // Do not change these values without gfx team review.
 pref("hal.gonk.COMPOSITOR.rt_priority", 0);
-pref("hal.gonk.COMPOSITOR.nice", 0);
+pref("hal.gonk.COMPOSITOR.nice", -4);
 
 // Fire a memory pressure event when the system has less than Xmb of memory
 // remaining.  You should probably set this just above Y.KillUnderKB for
 // the highest priority class Y that you want to make an effort to keep alive.
 // (For example, we want BACKGROUND_PERCEIVABLE to stay alive.)  If you set
 // this too high, then we'll send out a memory pressure event every Z seconds
 // (see below), even while we have processes that we would happily kill in
 // order to free up memory.
--- a/b2g/chrome/content/payment.js
+++ b/b2g/chrome/content/payment.js
@@ -173,23 +173,25 @@ PaymentSettings.prototype = {
   },
 
   observe: function(aSubject, aTopic, aData) {
     if (aTopic != kMozSettingsChangedObserverTopic) {
       return;
     }
 
     try {
-      let setting = JSON.parse(aData);
-      if (!setting.key ||
-          (setting.key !== kRilDefaultDataServiceId &&
-           setting.key !== kRilDefaultPaymentServiceId)) {
+      if ('wrappedJSObject' in aSubject) {
+        aSubject = aSubject.wrappedJSObject;
+      }
+      if (!aSubject.key ||
+          (aSubject.key !== kRilDefaultDataServiceId &&
+           aSubject.key !== kRilDefaultPaymentServiceId)) {
         return;
       }
-      this.setServiceId(setting.key, setting.value);
+      this.setServiceId(aSubject.key, aSubject.value);
     } catch (e) {
       LOGE(e);
     }
   },
 
   cleanup: function() {
     Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
   }
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -327,16 +327,17 @@ var shell = {
 
     window.addEventListener('MozApplicationManifest', this);
     window.addEventListener('mozfullscreenchange', this);
     window.addEventListener('MozAfterPaint', this);
     window.addEventListener('sizemodechange', this);
     window.addEventListener('unload', this);
     this.contentBrowser.addEventListener('mozbrowserloadstart', this, true);
     this.contentBrowser.addEventListener('mozbrowserselectionchange', this, true);
+    this.contentBrowser.addEventListener('mozbrowserscrollviewchange', this, true);
 
     CustomEventManager.init();
     WebappsHelper.init();
     UserAgentOverrides.init();
     IndexedDBPromptHelper.init();
     CaptivePortalLoginHelper.init();
 
     this.contentBrowser.src = homeURL;
@@ -354,16 +355,17 @@ var shell = {
     window.removeEventListener('keydown', this, true);
     window.removeEventListener('keypress', this, true);
     window.removeEventListener('keyup', this, true);
     window.removeEventListener('MozApplicationManifest', this);
     window.removeEventListener('mozfullscreenchange', this);
     window.removeEventListener('sizemodechange', this);
     this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true);
     this.contentBrowser.removeEventListener('mozbrowserselectionchange', this, true);
+    this.contentBrowser.removeEventListener('mozbrowserscrollviewchange', this, true);
     ppmm.removeMessageListener("content-handler", this);
 
     UserAgentOverrides.uninit();
     IndexedDBPromptHelper.uninit();
   },
 
   // If this key event actually represents a hardware button, filter it here
   // and send a mozChromeEvent with detail.type set to xxx-button-press or
@@ -495,17 +497,22 @@ var shell = {
         break;
       case 'mozbrowserlocationchange':
         if (content.document.location == 'about:blank') {
           return;
         }
 
         this.notifyContentStart();
        break;
-
+      case 'mozbrowserscrollviewchange':
+        this.sendChromeEvent({
+          type: 'scrollviewchange',
+          detail: evt.detail,
+        });
+        break;
       case 'mozbrowserselectionchange':
         // The mozbrowserselectionchange event, may have crossed the chrome-content boundary.
         // This event always dispatch to shell.js. But the offset we got from this event is
         // based on tab's coordinate. So get the actual offsets between shell and evt.target.
         let elt = evt.target;
         let win = elt.ownerDocument.defaultView;
         let offsetX = win.mozInnerScreenX - window.mozInnerScreenX;
         let offsetY = win.mozInnerScreenY - window.mozInnerScreenY;
--- a/b2g/components/MobileIdentityUIGlue.js
+++ b/b2g/components/MobileIdentityUIGlue.js
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict"
 
 const { interfaces: Ci, utils: Cu, classes: Cc } = Components;
 
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/ContentRequestHelper.jsm");
 Cu.import("resource://gre/modules/MobileIdentityCommon.jsm");
 Cu.import("resource://gre/modules/MobileIdentityUIGlueCommon.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
                                    "@mozilla.org/uuid-generator;1",
                                    "nsIUUIDGenerator");
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="03d7bcad57ea281869976a9aed0a38849f7c8bc5"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c5d2e2f4ebf5f370d6003517057dcd47493dec90"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="837a62c581254345ad97276386757f775a5872bb"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="20a1521efdac44c8219f00c2414de031891fb464"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
   <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -10,27 +10,27 @@
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
-  <project name="platform_build" path="build" remote="b2g" revision="4d1e85908d792d9468c4da7040acd191fbb51b40">
+  <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="03d7bcad57ea281869976a9aed0a38849f7c8bc5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c5d2e2f4ebf5f370d6003517057dcd47493dec90"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="837a62c581254345ad97276386757f775a5872bb"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="20a1521efdac44c8219f00c2414de031891fb464"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="03d7bcad57ea281869976a9aed0a38849f7c8bc5"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c5d2e2f4ebf5f370d6003517057dcd47493dec90"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="837a62c581254345ad97276386757f775a5872bb"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="20a1521efdac44c8219f00c2414de031891fb464"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="03d7bcad57ea281869976a9aed0a38849f7c8bc5"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c5d2e2f4ebf5f370d6003517057dcd47493dec90"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="837a62c581254345ad97276386757f775a5872bb"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="20a1521efdac44c8219f00c2414de031891fb464"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
   <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -10,27 +10,27 @@
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
-  <project name="platform_build" path="build" remote="b2g" revision="4d1e85908d792d9468c4da7040acd191fbb51b40">
+  <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="03d7bcad57ea281869976a9aed0a38849f7c8bc5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c5d2e2f4ebf5f370d6003517057dcd47493dec90"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="837a62c581254345ad97276386757f775a5872bb"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="20a1521efdac44c8219f00c2414de031891fb464"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="03d7bcad57ea281869976a9aed0a38849f7c8bc5"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c5d2e2f4ebf5f370d6003517057dcd47493dec90"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="837a62c581254345ad97276386757f775a5872bb"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="20a1521efdac44c8219f00c2414de031891fb464"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
   <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="03d7bcad57ea281869976a9aed0a38849f7c8bc5"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c5d2e2f4ebf5f370d6003517057dcd47493dec90"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="837a62c581254345ad97276386757f775a5872bb"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="20a1521efdac44c8219f00c2414de031891fb464"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "89fc79354058663937beda2c0eb657e87354a872", 
+    "revision": "15291949ab37f96d1d1e30bb890a2604b4454894", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -8,26 +8,26 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
-  <project name="platform_build" path="build" remote="b2g" revision="4d1e85908d792d9468c4da7040acd191fbb51b40">
+  <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="03d7bcad57ea281869976a9aed0a38849f7c8bc5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c5d2e2f4ebf5f370d6003517057dcd47493dec90"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="837a62c581254345ad97276386757f775a5872bb"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="20a1521efdac44c8219f00c2414de031891fb464"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
   <project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
   <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
   <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -6,21 +6,21 @@
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
-  <project name="platform_build" path="build" remote="b2g" revision="4d1e85908d792d9468c4da7040acd191fbb51b40">
+  <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="03d7bcad57ea281869976a9aed0a38849f7c8bc5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c5d2e2f4ebf5f370d6003517057dcd47493dec90"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="03d7bcad57ea281869976a9aed0a38849f7c8bc5"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c5d2e2f4ebf5f370d6003517057dcd47493dec90"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="837a62c581254345ad97276386757f775a5872bb"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="20a1521efdac44c8219f00c2414de031891fb464"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -8,26 +8,26 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
-  <project name="platform_build" path="build" remote="b2g" revision="4d1e85908d792d9468c4da7040acd191fbb51b40">
+  <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="03d7bcad57ea281869976a9aed0a38849f7c8bc5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c5d2e2f4ebf5f370d6003517057dcd47493dec90"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="837a62c581254345ad97276386757f775a5872bb"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="20a1521efdac44c8219f00c2414de031891fb464"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
   <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
   <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
   <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/content/base/src/nsInProcessTabChildGlobal.cpp
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -300,16 +300,18 @@ nsInProcessTabChildGlobal::PreHandleEven
 #endif
 
   return NS_OK;
 }
 
 nsresult
 nsInProcessTabChildGlobal::InitTabChildGlobal()
 {
+  // If you change this, please change GetCompartmentName() in XPCJSRuntime.cpp
+  // accordingly.
   nsAutoCString id;
   id.AssignLiteral("inProcessTabChildGlobal");
   nsIURI* uri = mOwner->OwnerDoc()->GetDocumentURI();
   if (uri) {
     nsAutoCString u;
     uri->GetSpec(u);
     id.AppendLiteral("?ownedBy=");
     id.Append(u);
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -63,17 +63,17 @@
 #include "nsFrameLoader.h"
 
 #include "nsObjectLoadingContent.h"
 #include "mozAutoDocUpdate.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIChannelPolicy.h"
 #include "nsChannelPolicy.h"
 #include "GeckoProfiler.h"
-#include "nsObjectFrame.h"
+#include "nsPluginFrame.h"
 #include "nsDOMClassInfo.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsDOMJSUtils.h"
 
 #include "nsWidgetsCID.h"
 #include "nsContentCID.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/dom/BindingUtils.h"
@@ -855,17 +855,17 @@ nsObjectLoadingContent::InstantiatePlugi
 
   mInstanceOwner = newOwner;
 
   // Ensure the frame did not change during instantiation re-entry (common).
   // HasNewFrame would not have mInstanceOwner yet, so the new frame would be
   // dangling. (Bug 854082)
   nsIFrame* frame = thisContent->GetPrimaryFrame();
   if (frame && mInstanceOwner) {
-    mInstanceOwner->SetFrame(static_cast<nsObjectFrame*>(frame));
+    mInstanceOwner->SetFrame(static_cast<nsPluginFrame*>(frame));
 
     // Bug 870216 - Adobe Reader renders with incorrect dimensions until it gets
     // a second SetWindow call. This is otherwise redundant.
     mInstanceOwner->CallSetWindow();
   }
 
   // Set up scripting interfaces.
   NotifyContentObjectWrapper();
@@ -1291,17 +1291,17 @@ nsObjectLoadingContent::HasNewFrame(nsIO
     // We are successfully setup as type plugin, but have not spawned an
     // instance due to a lack of a frame.
     AsyncStartPluginInstance();
     return NS_OK;
   }
 
   // Otherwise, we're just changing frames
   // Set up relationship between instance owner and frame.
-  nsObjectFrame *objFrame = static_cast<nsObjectFrame*>(aFrame);
+  nsPluginFrame *objFrame = static_cast<nsPluginFrame*>(aFrame);
   mInstanceOwner->SetFrame(objFrame);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetPluginInstance(nsNPAPIPluginInstance** aInstance)
 {
@@ -2713,23 +2713,23 @@ nsObjectLoadingContent::GetTypeOfContent
   if (caps & eSupportPlugins && PluginExistsForType(aMIMEType.get())) {
     // ShouldPlay will handle checking for disabled plugins
     return eType_Plugin;
   }
 
   return eType_Null;
 }
 
-nsObjectFrame*
+nsPluginFrame*
 nsObjectLoadingContent::GetExistingFrame()
 {
   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   nsIFrame* frame = thisContent->GetPrimaryFrame();
   nsIObjectFrame* objFrame = do_QueryFrame(frame);
-  return static_cast<nsObjectFrame*>(objFrame);
+  return static_cast<nsPluginFrame*>(objFrame);
 }
 
 void
 nsObjectLoadingContent::CreateStaticClone(nsObjectLoadingContent* aDest) const
 {
   nsImageLoadingContent::CreateStaticImageClone(aDest);
 
   aDest->mType = mType;
@@ -3571,17 +3571,17 @@ nsObjectLoadingContent::SetupProtoChain(
 nsresult
 nsObjectLoadingContent::GetPluginJSObject(JSContext *cx,
                                           JS::Handle<JSObject*> obj,
                                           nsNPAPIPluginInstance *plugin_inst,
                                           JS::MutableHandle<JSObject*> plugin_obj,
                                           JS::MutableHandle<JSObject*> plugin_proto)
 {
   // NB: We need an AutoEnterCompartment because we can be called from
-  // nsObjectFrame when the plugin loads after the JS object for our content
+  // nsPluginFrame when the plugin loads after the JS object for our content
   // node has been created.
   JSAutoCompartment ac(cx, obj);
 
   if (plugin_inst) {
     plugin_inst->GetJSObject(cx, plugin_obj.address());
     if (plugin_obj) {
       if (!::JS_GetPrototype(cx, plugin_obj, plugin_proto)) {
         return NS_ERROR_UNEXPECTED;
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -21,17 +21,17 @@
 #include "nsIRunnable.h"
 #include "nsIThreadInternal.h"
 #include "nsIFrame.h"
 #include "nsIFrameLoader.h"
 
 class nsAsyncInstantiateEvent;
 class nsStopPluginRunnable;
 class AutoSetInstantiatingToFalse;
-class nsObjectFrame;
+class nsPluginFrame;
 class nsFrameLoader;
 class nsXULElement;
 class nsPluginInstanceOwner;
 
 namespace mozilla {
 namespace dom {
 template<typename T> class Sequence;
 struct MozPluginParameter;
@@ -497,17 +497,17 @@ class nsObjectLoadingContent : public ns
      *      click-to-play or other content policy checks
      */
     ObjectType GetTypeOfContent(const nsCString& aMIMEType);
 
     /**
      * Gets the frame that's associated with this content node.
      * Does not flush.
      */
-    nsObjectFrame* GetExistingFrame();
+    nsPluginFrame* GetExistingFrame();
 
     // Helper class for SetupProtoChain
     class SetupProtoChainRunner MOZ_FINAL : public nsIRunnable
     {
       ~SetupProtoChainRunner();
     public:
       NS_DECL_ISUPPORTS
 
--- a/content/media/fmp4/moz.build
+++ b/content/media/fmp4/moz.build
@@ -7,21 +7,21 @@
 EXPORTS += [
     'MP4Decoder.h',
     'MP4Reader.h',
     'PlatformDecoderModule.h',
 ]
 
 UNIFIED_SOURCES += [
     'BlankDecoderModule.cpp',
+    'MP4Decoder.cpp',
     'PlatformDecoderModule.cpp',
 ]
 
 SOURCES += [
-    'MP4Decoder.cpp',
     'MP4Reader.cpp',
 ]
 
 if CONFIG['MOZ_WMF']:
     DIRS += [ 'wmf' ];
 
 if CONFIG['MOZ_EME']:
     DIRS += ['eme']
--- a/content/media/omx/AudioOffloadPlayer.cpp
+++ b/content/media/omx/AudioOffloadPlayer.cpp
@@ -17,16 +17,18 @@
  * limitations under the License.
  */
 
 #include "AudioOffloadPlayer.h"
 #include "nsComponentManagerUtils.h"
 #include "nsITimer.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "VideoUtils.h"
+#include "mozilla/dom/power/PowerManagerService.h"
+#include "mozilla/dom/WakeLock.h"
 
 #include <binder/IPCThreadState.h>
 #include <stagefright/foundation/ADebug.h>
 #include <stagefright/foundation/ALooper.h>
 #include <stagefright/MediaDefs.h>
 #include <stagefright/MediaErrors.h>
 #include <stagefright/MediaSource.h>
 #include <stagefright/MetaData.h>
@@ -210,28 +212,31 @@ status_t AudioOffloadPlayer::ChangeState
     default:
       break;
   }
   return OK;
 }
 
 static void ResetCallback(nsITimer* aTimer, void* aClosure)
 {
+  AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("%s", __FUNCTION__));
   AudioOffloadPlayer* player = static_cast<AudioOffloadPlayer*>(aClosure);
   if (player) {
     player->Reset();
   }
 }
 
 void AudioOffloadPlayer::Pause(bool aPlayPendingSamples)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mStarted) {
     CHECK(mAudioSink.get());
+    WakeLockCreate();
+
     if (aPlayPendingSamples) {
       mAudioSink->Stop();
     } else {
       mAudioSink->Pause();
     }
     mPlaying = false;
   }
 
@@ -247,16 +252,17 @@ void AudioOffloadPlayer::Pause(bool aPla
 
 status_t AudioOffloadPlayer::Play()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mResetTimer) {
     mResetTimer->Cancel();
     mResetTimer = nullptr;
+    WakeLockRelease();
   }
 
   status_t err = OK;
 
   if (!mStarted) {
     // Last pause timed out and offloaded audio sink was reset. Start it again
     err = Start(false);
     if (err != OK) {
@@ -276,16 +282,17 @@ status_t AudioOffloadPlayer::Play()
     }
   }
 
   return err;
 }
 
 void AudioOffloadPlayer::Reset()
 {
+  MOZ_ASSERT(NS_IsMainThread());
   if (!mStarted) {
     return;
   }
 
   CHECK(mAudioSink.get());
 
   AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("reset: mPlaying=%d mReachedEOS=%d",
       mPlaying, mReachedEOS));
@@ -318,16 +325,18 @@ void AudioOffloadPlayer::Reset()
 
   IPCThreadState::self()->flushCommands();
   StopTimeUpdate();
 
   mReachedEOS = false;
   mStarted = false;
   mPlaying = false;
   mStartPosUs = 0;
+
+  WakeLockRelease();
 }
 
 status_t AudioOffloadPlayer::SeekTo(int64_t aTimeUs, bool aDispatchSeekEvents)
 {
   MOZ_ASSERT(NS_IsMainThread());
   CHECK(mAudioSink.get());
 
   android::Mutex::Autolock autoLock(mLock);
@@ -706,9 +715,35 @@ void AudioOffloadPlayer::SendMetaDataToH
 
 void AudioOffloadPlayer::SetVolume(double aVolume)
 {
   MOZ_ASSERT(NS_IsMainThread());
   CHECK(mAudioSink.get());
   mAudioSink->SetVolume((float) aVolume);
 }
 
+void AudioOffloadPlayer::WakeLockCreate()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("%s", __FUNCTION__));
+  if (!mWakeLock) {
+    nsRefPtr<dom::power::PowerManagerService> pmService =
+      dom::power::PowerManagerService::GetInstance();
+    NS_ENSURE_TRUE_VOID(pmService);
+
+    ErrorResult rv;
+    mWakeLock = pmService->NewWakeLock(NS_LITERAL_STRING("cpu"), nullptr, rv);
+  }
+}
+
+void AudioOffloadPlayer::WakeLockRelease()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("%s", __FUNCTION__));
+  if (mWakeLock) {
+    ErrorResult rv;
+    mWakeLock->Unlock(rv);
+    NS_WARN_IF_FALSE(!rv.Failed(), "Failed to unlock the wakelock.");
+    mWakeLock = nullptr;
+  }
+}
+
 } // namespace mozilla
--- a/content/media/omx/AudioOffloadPlayer.h
+++ b/content/media/omx/AudioOffloadPlayer.h
@@ -28,16 +28,20 @@
 
 #include "AudioOutput.h"
 #include "AudioOffloadPlayerBase.h"
 #include "MediaDecoderOwner.h"
 #include "MediaOmxCommonDecoder.h"
 
 namespace mozilla {
 
+namespace dom {
+class WakeLock;
+}
+
 /**
  * AudioOffloadPlayer adds support for audio tunneling to a digital signal
  * processor (DSP) in the device chipset. With tunneling, audio decoding is
  * off-loaded to the DSP, waking the application processor less often and using
  * less battery
  *
  * This depends on offloading capability provided by Android KK AudioTrack class
  *
@@ -188,16 +192,20 @@ private:
   // Timer to trigger position changed events
   nsCOMPtr<nsITimer> mTimeUpdateTimer;
 
   // Timer to reset AudioSink when audio is paused for OFFLOAD_PAUSE_MAX_USECS.
   // It is triggered in Pause() and canceled when there is a Play() within
   // OFFLOAD_PAUSE_MAX_USECS. Used only from main thread so no lock is needed.
   nsCOMPtr<nsITimer> mResetTimer;
 
+  // To avoid device suspend when mResetTimer is going to be triggered.
+  // Used only from main thread so no lock is needed.
+  nsRefPtr<mozilla::dom::WakeLock> mWakeLock;
+
   int64_t GetMediaTimeUs();
 
   // Provide the playback position in microseconds from total number of
   // frames played by audio track
   int64_t GetOutputPlayPositionUs_l() const;
 
   // Fill the buffer given by audio sink with data from compressed audio
   // source. Also handles the seek by seeking audio source and stop the sink in
@@ -235,16 +243,19 @@ private:
   // (>1sec) But when Player UI is visible we need to update progress bar
   // atleast once in 250ms. Start a timer when player UI becomes visible or
   // audio starts playing to send PlaybackPositionChanged events once in 250ms.
   // Stop the timer when UI goes invisible or play state is not playing.
   // Also make sure timer functions are always called from main thread
   nsresult StartTimeUpdate();
   nsresult StopTimeUpdate();
 
+  void WakeLockCreate();
+  void WakeLockRelease();
+
   // Notify end of stream by sending PlaybackEnded event to observer
   // (i.e.MediaDecoder)
   void NotifyAudioEOS();
 
   // Notify position changed event by sending PlaybackPositionChanged event to
   // observer
   void NotifyPositionChanged();
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -3051,39 +3051,39 @@ nsDocShell::AddWeakScrollObserver(nsIScr
 NS_IMETHODIMP
 nsDocShell::RemoveWeakScrollObserver(nsIScrollObserver* aObserver)
 {
     nsWeakPtr obs = do_GetWeakReference(aObserver);
     return mScrollObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 void
-nsDocShell::NotifyAsyncPanZoomStarted()
+nsDocShell::NotifyAsyncPanZoomStarted(const mozilla::CSSIntPoint aScrollPos)
 {
     nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
     while (iter.HasMore()) {
         nsWeakPtr ref = iter.GetNext();
         nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
         if (obs) {
-            obs->AsyncPanZoomStarted();
+            obs->AsyncPanZoomStarted(aScrollPos);
         } else {
             mScrollObservers.RemoveElement(ref);
         }
     }
 }
 
 void
-nsDocShell::NotifyAsyncPanZoomStopped()
+nsDocShell::NotifyAsyncPanZoomStopped(const mozilla::CSSIntPoint aScrollPos)
 {
     nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
     while (iter.HasMore()) {
         nsWeakPtr ref = iter.GetNext();
         nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
         if (obs) {
-            obs->AsyncPanZoomStopped();
+            obs->AsyncPanZoomStopped(aScrollPos);
         } else {
             mScrollObservers.RemoveElement(ref);
         }
     }
 }
 
 NS_IMETHODIMP
 nsDocShell::NotifyScrollObservers()
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -44,16 +44,17 @@
 #include "nsILoadContext.h"
 #include "nsIWebShellServices.h"
 #include "nsILinkHandler.h"
 #include "nsIClipboardCommands.h"
 #include "nsITabParent.h"
 #include "nsCRT.h"
 #include "prtime.h"
 #include "nsRect.h"
+#include "Units.h"
 
 namespace mozilla {
 namespace dom {
 class EventTarget;
 class URLSearchParams;
 }
 }
 
@@ -245,20 +246,20 @@ public:
         FireOnLocationChange(this, nullptr, mCurrentURI,
                              LOCATION_CHANGE_SAME_DOCUMENT);
     }
 
     nsresult HistoryTransactionRemoved(int32_t aIndex);
 
     // Notify Scroll observers when an async panning/zooming transform
     // has started being applied
-    void NotifyAsyncPanZoomStarted();
+    void NotifyAsyncPanZoomStarted(const mozilla::CSSIntPoint aScrollPos);
     // Notify Scroll observers when an async panning/zooming transform
     // is no longer applied
-    void NotifyAsyncPanZoomStopped();
+    void NotifyAsyncPanZoomStopped(const mozilla::CSSIntPoint aScrollPos);
 
     // Add new profile timeline markers to this docShell. This will only add
     // markers if the docShell is currently recording profile timeline markers.
     // See nsIDocShell::recordProfileTimelineMarkers
     void AddProfileTimelineMarker(const char* aName,
                                   TracingMetadata aMetaData);
     void AddProfileTimelineMarker(const char* aName,
                                   ProfilerBacktrace* aCause,
--- a/docshell/base/nsIScrollObserver.h
+++ b/docshell/base/nsIScrollObserver.h
@@ -2,37 +2,40 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsIScrollObserver_h___
 #define nsIScrollObserver_h___
 
 #include "nsISupports.h"
+#include "Units.h"
 
 #define NS_ISCROLLOBSERVER_IID \
-  { 0x03465b77, 0x9ce2, 0x4d19, \
-    { 0xb2, 0xf6, 0x82, 0xae, 0xee, 0x85, 0xc3, 0xbf } }
+  { 0x00bc10e3, 0xaa59, 0x4aa3, \
+    { 0x88, 0xe9, 0x43, 0x0a, 0x01, 0xa3, 0x88, 0x04 } }
 
 class nsIScrollObserver : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCROLLOBSERVER_IID)
 
   /**
    * Called when the scroll position of some element has changed.
    */
   virtual void ScrollPositionChanged() = 0;
 
   /**
-   * Called when an async panning/zooming transform has started being applied.
+   * Called when an async panning/zooming transform has started being applied
+   * and passed the scroll offset
    */
-  virtual void AsyncPanZoomStarted(){};
+  virtual void AsyncPanZoomStarted(const mozilla::CSSIntPoint scrollPos){};
 
   /**
-   * Called when an async panning/zooming transform is no longer applied.
+   * Called when an async panning/zooming transform is no longer applied
+   * and passed the scroll offset
    */
-  virtual void AsyncPanZoomStopped(){};
+  virtual void AsyncPanZoomStopped(const mozilla::CSSIntPoint scrollPos){};
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIScrollObserver, NS_ISCROLLOBSERVER_IID)
 
 #endif /* nsIScrollObserver_h___ */
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -109,22 +109,18 @@ Animation::GetComputedTimingAt(const Nul
   const TimeDuration& localTime = aLocalTime.Value();
 
   // When we finish exactly at the end of an iteration we need to report
   // the end of the final iteration and not the start of the next iteration
   // so we set up a flag for that case.
   bool isEndOfFinalIteration = false;
 
   // Get the normalized time within the active interval.
-  TimeDuration activeTime;
-  // FIXME: The following check that the active duration is not equal to Forever
-  // is a temporary workaround to avoid overflow and should be removed once
-  // bug 1039924 is fixed.
-  if (result.mActiveDuration != TimeDuration::Forever() &&
-      localTime >= aTiming.mDelay + result.mActiveDuration) {
+  StickyTimeDuration activeTime;
+  if (localTime >= aTiming.mDelay + result.mActiveDuration) {
     result.mPhase = ComputedTiming::AnimationPhase_After;
     if (!aTiming.FillsForwards()) {
       // The animation isn't active or filling at this time.
       result.mTimeFraction = ComputedTiming::kNullTimeFraction;
       return result;
     }
     activeTime = result.mActiveDuration;
     // Note that infinity == floor(infinity) so this will also be true when we
@@ -143,20 +139,20 @@ Animation::GetComputedTimingAt(const Nul
   } else {
     MOZ_ASSERT(result.mActiveDuration != zeroDuration,
                "How can we be in the middle of a zero-duration interval?");
     result.mPhase = ComputedTiming::AnimationPhase_Active;
     activeTime = localTime - aTiming.mDelay;
   }
 
   // Get the position within the current iteration.
-  TimeDuration iterationTime;
+  StickyTimeDuration iterationTime;
   if (aTiming.mIterationDuration != zeroDuration) {
     iterationTime = isEndOfFinalIteration
-                    ? aTiming.mIterationDuration
+                    ? StickyTimeDuration(aTiming.mIterationDuration)
                     : activeTime % aTiming.mIterationDuration;
   } /* else, iterationTime is zero */
 
   // Determine the 0-based index of the current iteration.
   if (isEndOfFinalIteration) {
     result.mCurrentIteration =
       aTiming.mIterationCount == NS_IEEEPositiveInfinity()
       ? UINT64_MAX // FIXME: When we return this via the API we'll need
@@ -210,29 +206,30 @@ Animation::GetComputedTimingAt(const Nul
   }
   if (thisIterationReverse) {
     result.mTimeFraction = 1.0 - result.mTimeFraction;
   }
 
   return result;
 }
 
-TimeDuration
+StickyTimeDuration
 Animation::ActiveDuration(const AnimationTiming& aTiming)
 {
   if (aTiming.mIterationCount == mozilla::PositiveInfinity<float>()) {
     // An animation that repeats forever has an infinite active duration
     // unless its iteration duration is zero, in which case it has a zero
     // active duration.
-    const TimeDuration zeroDuration;
+    const StickyTimeDuration zeroDuration;
     return aTiming.mIterationDuration == zeroDuration
            ? zeroDuration
-           : TimeDuration::Forever();
+           : StickyTimeDuration::Forever();
   }
-  return aTiming.mIterationDuration.MultDouble(aTiming.mIterationCount);
+  return StickyTimeDuration(
+    aTiming.mIterationDuration.MultDouble(aTiming.mIterationCount));
 }
 
 bool
 Animation::HasAnimationOfProperty(nsCSSProperty aProperty) const
 {
   for (size_t propIdx = 0, propEnd = mProperties.Length();
        propIdx != propEnd; ++propIdx) {
     if (aProperty == mProperties[propIdx].mProperty) {
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -6,16 +6,17 @@
 #ifndef mozilla_dom_Animation_h
 #define mozilla_dom_Animation_h
 
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIDocument.h"
 #include "nsWrapperCache.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/StickyTimeDuration.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/Nullable.h"
 #include "nsSMILKeySpline.h"
 #include "nsStyleStruct.h" // for nsTimingFunction
 
 struct JSContext;
 
@@ -56,18 +57,19 @@ struct ComputedTiming
     : mTimeFraction(kNullTimeFraction)
     , mCurrentIteration(0)
     , mPhase(AnimationPhase_Null)
   { }
 
   static const double kNullTimeFraction;
 
   // The total duration of the animation including all iterations.
-  // Will equal TimeDuration::Forever() if the animation repeats indefinitely.
-  TimeDuration mActiveDuration;
+  // Will equal StickyTimeDuration::Forever() if the animation repeats
+  // indefinitely.
+  StickyTimeDuration mActiveDuration;
 
   // Will be kNullTimeFraction if the animation is neither animating nor
   // filling at the sampled time.
   double mTimeFraction;
 
   // Zero-based iteration index (meaningless if mTimeFraction is
   // kNullTimeFraction).
   uint64_t mCurrentIteration;
@@ -200,17 +202,18 @@ public:
   // Shortcut for that gets the computed timing using the current local time as
   // calculated from the timeline time.
   ComputedTiming GetComputedTiming(const AnimationTiming* aTiming
                                      = nullptr) const {
     return GetComputedTimingAt(GetLocalTime(), aTiming ? *aTiming : mTiming);
   }
 
   // Return the duration of the active interval for the given timing parameters.
-  static TimeDuration ActiveDuration(const AnimationTiming& aTiming);
+  static StickyTimeDuration
+  ActiveDuration(const AnimationTiming& aTiming);
 
   // After transitions finish they need to be retained for one throttle-able
   // cycle (for reasons see explanation in
   // layout/style/nsTransitionManager.cpp).
   // In the meantime, however, they should be ignored.
   bool IsFinishedTransition() const {
     return mIsFinishedTransition;
   }
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -15,16 +15,17 @@
 
 #include "mozilla/dom/ContentParent.h"
 
 #include "nsThreadUtils.h"
 #include "nsHashPropertyBag.h"
 #include "nsComponentManagerUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
+#include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsJSUtils.h"
 #include "nsIAudioManager.h"
 #include "SpeakerManagerService.h"
 #define NS_AUDIOMANAGER_CONTRACTID "@mozilla.org/telephony/audiomanager;1"
 #endif
 
@@ -796,58 +797,43 @@ AudioChannelService::Observe(nsISupports
     } else {
       NS_WARNING("ipc:content-shutdown message without childID property");
     }
   }
 #ifdef MOZ_WIDGET_GONK
   // To process the volume control on each audio channel according to
   // change of settings
   else if (!strcmp(aTopic, "mozsettings-changed")) {
-    AutoSafeJSContext cx;
-    nsDependentString dataStr(aData);
-    JS::Rooted<JS::Value> val(cx);
-    if (!JS_ParseJSON(cx, dataStr.get(), dataStr.Length(), &val) ||
-        !val.isObject()) {
-      return NS_OK;
-    }
-
-    JS::Rooted<JSObject*> obj(cx, &val.toObject());
-    JS::Rooted<JS::Value> key(cx);
-    if (!JS_GetProperty(cx, obj, "key", &key) ||
-        !key.isString()) {
+    AutoJSAPI jsapi;
+    jsapi.Init();
+    JSContext* cx = jsapi.cx();
+    RootedDictionary<SettingChangeNotification> setting(cx);
+    if (!WrappedJSToDictionary(cx, aSubject, setting)) {
       return NS_OK;
     }
-
-    JS::Rooted<JSString*> jsKey(cx, JS::ToString(cx, key));
-    if (!jsKey) {
+    if (!StringBeginsWith(setting.mKey, NS_LITERAL_STRING("audio.volume."))) {
       return NS_OK;
     }
-    nsAutoJSString keyStr;
-    if (!keyStr.init(cx, jsKey) || keyStr.Find("audio.volume.", 0, false)) {
+    if (!setting.mValue.isNumber()) {
       return NS_OK;
     }
-
-    JS::Rooted<JS::Value> value(cx);
-    if (!JS_GetProperty(cx, obj, "value", &value) || !value.isInt32()) {
-      return NS_OK;
-    }
-
+    
     nsCOMPtr<nsIAudioManager> audioManager = do_GetService(NS_AUDIOMANAGER_CONTRACTID);
     NS_ENSURE_TRUE(audioManager, NS_OK);
 
-    int32_t index = value.toInt32();
-    if (keyStr.EqualsLiteral("audio.volume.content")) {
+    int32_t index = setting.mValue.toNumber();
+    if (setting.mKey.EqualsLiteral("audio.volume.content")) {
       audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Content, index);
-    } else if (keyStr.EqualsLiteral("audio.volume.notification")) {
+    } else if (setting.mKey.EqualsLiteral("audio.volume.notification")) {
       audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Notification, index);
-    } else if (keyStr.EqualsLiteral("audio.volume.alarm")) {
+    } else if (setting.mKey.EqualsLiteral("audio.volume.alarm")) {
       audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Alarm, index);
-    } else if (keyStr.EqualsLiteral("audio.volume.telephony")) {
+    } else if (setting.mKey.EqualsLiteral("audio.volume.telephony")) {
       audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Telephony, index);
-    } else if (!keyStr.EqualsLiteral("audio.volume.bt_sco")) {
+    } else if (!setting.mKey.EqualsLiteral("audio.volume.bt_sco")) {
       // bt_sco is not a valid audio channel so we manipulate it in
       // AudioManager.cpp. And the others should not be used.
       // We didn't use MOZ_CRASH or MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE here
       // because any web content who has permission of mozSettings can set any
       // names then it can be easy to crash the B2G.
       NS_WARNING("unexpected audio channel for volume control");
     }
   }
--- a/dom/base/nsPerformance.cpp
+++ b/dom/base/nsPerformance.cpp
@@ -36,16 +36,21 @@ nsPerformanceTiming::nsPerformanceTiming
     mChannel(aChannel),
     mFetchStart(0.0),
     mZeroTime(aZeroTime),
     mTimingAllowed(true),
     mReportCrossOriginRedirect(true)
 {
   MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
   SetIsDOMBinding();
+
+  if (!nsContentUtils::IsPerformanceTimingEnabled()) {
+    mZeroTime = 0;
+  }
+
   // The aHttpChannel argument is null if this nsPerformanceTiming object
   // is being used for the navigation timing (document) and has a non-null
   // value for the resource timing (any resources within the page).
   if (aHttpChannel) {
     mTimingAllowed = CheckAllowedOrigin(aHttpChannel);
     bool redirectsPassCheck = false;
     mChannel->GetAllRedirectsPassTimingAllowCheck(&redirectsPassCheck);
     mReportCrossOriginRedirect = mTimingAllowed && redirectsPassCheck;
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2972,35 +2972,31 @@ CallerSubsumes(JS::Handle<JS::Value> aVa
   if (!aValue.isObject()) {
     return true;
   }
   return CallerSubsumes(&aValue.toObject());
 }
 
 template<class T>
 inline bool
-WrappedJSToDictionary(nsISupports* aObject, T& aDictionary)
+WrappedJSToDictionary(JSContext* aCx, nsISupports* aObject, T& aDictionary)
 {
   nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(aObject);
   if (!wrappedObj) {
     return false;
   }
 
-  AutoJSAPI jsapi;
-  jsapi.Init();
-
-  JSContext* cx = jsapi.cx();
-  JS::Rooted<JSObject*> obj(cx, wrappedObj->GetJSObject());
+  JS::Rooted<JSObject*> obj(aCx, wrappedObj->GetJSObject());
   if (!obj) {
     return false;
   }
 
-  JSAutoCompartment ac(cx, obj);
-  JS::Rooted<JS::Value> v(cx, OBJECT_TO_JSVAL(obj));
-  return aDictionary.Init(cx, v);
+  JSAutoCompartment ac(aCx, obj);
+  JS::Rooted<JS::Value> v(aCx, JS::ObjectValue(*obj));
+  return aDictionary.Init(aCx, v);
 }
 
 
 template<class T, class S>
 inline nsRefPtr<T>
 StrongOrRawPtr(already_AddRefed<S>&& aPtr)
 {
   return aPtr.template downcast<T>();
--- a/dom/bluetooth/BluetoothService.cpp
+++ b/dom/bluetooth/BluetoothService.cpp
@@ -29,16 +29,17 @@
 #include "mozilla/ipc/UnixSocket.h"
 #include "nsContentUtils.h"
 #include "nsIObserverService.h"
 #include "nsISettingsService.h"
 #include "nsISystemMessagesInternal.h"
 #include "nsITimer.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXPCOM.h"
+#include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #if defined(MOZ_WIDGET_GONK)
 #include "cutils/properties.h"
 #endif
 
 #if defined(MOZ_B2G_BT)
 #if defined(MOZ_B2G_BT_BLUEZ)
 /**
@@ -555,101 +556,54 @@ BluetoothService::HandleStartup()
 nsresult
 BluetoothService::HandleStartupSettingsCheck(bool aEnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   return StartStopBluetooth(aEnable, true);
 }
 
 nsresult
-BluetoothService::HandleSettingsChanged(const nsAString& aData)
+BluetoothService::HandleSettingsChanged(nsISupports* aSubject)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // The string that we're interested in will be a JSON string that looks like:
   //  {"key":"bluetooth.enabled","value":true}
 
-  AutoSafeJSContext cx;
-  if (!cx) {
-    return NS_OK;
-  }
-
-  JS::Rooted<JS::Value> val(cx);
-  if (!JS_ParseJSON(cx, aData.BeginReading(), aData.Length(), &val)) {
-    return JS_ReportPendingException(cx) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  if (!val.isObject()) {
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
+  RootedDictionary<SettingChangeNotification> setting(cx);
+  if (!WrappedJSToDictionary(cx, aSubject, setting)) {
     return NS_OK;
   }
-
-  JS::Rooted<JSObject*> obj(cx, &val.toObject());
-
-  JS::Rooted<JS::Value> key(cx);
-  if (!JS_GetProperty(cx, obj, "key", &key)) {
-    MOZ_ASSERT(!JS_IsExceptionPending(cx));
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  if (!key.isString()) {
-    return NS_OK;
-  }
-
-  // First, check if the string equals to BLUETOOTH_DEBUGGING_SETTING
-  bool match;
-  if (!JS_StringEqualsAscii(cx, key.toString(), BLUETOOTH_DEBUGGING_SETTING, &match)) {
-    MOZ_ASSERT(!JS_IsExceptionPending(cx));
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  if (match) {
-    JS::Rooted<JS::Value> value(cx);
-    if (!JS_GetProperty(cx, obj, "value", &value)) {
-      MOZ_ASSERT(!JS_IsExceptionPending(cx));
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    if (!value.isBoolean()) {
+  if (setting.mKey.EqualsASCII(BLUETOOTH_DEBUGGING_SETTING)) {
+    if (!setting.mValue.isBoolean()) {
       MOZ_ASSERT(false, "Expecting a boolean for 'bluetooth.debugging.enabled'!");
       return NS_ERROR_UNEXPECTED;
     }
-
-    SWITCH_BT_DEBUG(value.toBoolean());
+  
+    SWITCH_BT_DEBUG(setting.mValue.toBoolean());
 
     return NS_OK;
   }
 
   // Second, check if the string is BLUETOOTH_ENABLED_SETTING
-  if (!JS_StringEqualsAscii(cx, key.toString(), BLUETOOTH_ENABLED_SETTING, &match)) {
-    MOZ_ASSERT(!JS_IsExceptionPending(cx));
-    return NS_ERROR_OUT_OF_MEMORY;
+  if (!setting.mKey.EqualsASCII(BLUETOOTH_ENABLED_SETTING)) {
+    return NS_OK;
+  }
+  if (!setting.mValue.isBoolean()) {
+    MOZ_ASSERT(false, "Expecting a boolean for 'bluetooth.enabled'!");
+    return NS_ERROR_UNEXPECTED;
   }
 
-  if (match) {
-    JS::Rooted<JS::Value> value(cx);
-    if (!JS_GetProperty(cx, obj, "value", &value)) {
-      MOZ_ASSERT(!JS_IsExceptionPending(cx));
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
+  sToggleInProgress = true;
 
-    if (!value.isBoolean()) {
-      MOZ_ASSERT(false, "Expecting a boolean for 'bluetooth.enabled'!");
-      return NS_ERROR_UNEXPECTED;
-    }
-
-    if (sToggleInProgress || value.toBoolean() == IsEnabled()) {
-      // Nothing to do here.
-      return NS_OK;
-    }
-
-    sToggleInProgress = true;
-
-    nsresult rv = StartStopBluetooth(value.toBoolean(), false);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
+  nsresult rv = StartStopBluetooth(setting.mValue.toBoolean(), false);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
 BluetoothService::HandleShutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -750,17 +704,17 @@ BluetoothService::Observe(nsISupports* a
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!strcmp(aTopic, "profile-after-change")) {
     return HandleStartup();
   }
 
   if (!strcmp(aTopic, MOZSETTINGS_CHANGED_ID)) {
-    return HandleSettingsChanged(nsDependentString(aData));
+    return HandleSettingsChanged(aSubject);
   }
 
   if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     return HandleShutdown();
   }
 
   MOZ_ASSERT(false, "BluetoothService got unexpected topic!");
   return NS_ERROR_UNEXPECTED;
--- a/dom/bluetooth/BluetoothService.h
+++ b/dom/bluetooth/BluetoothService.h
@@ -367,17 +367,17 @@ protected:
    */
   nsresult
   HandleStartupSettingsCheck(bool aEnable);
 
   /**
    * Called when "mozsettings-changed" observer topic fires.
    */
   nsresult
-  HandleSettingsChanged(const nsAString& aData);
+  HandleSettingsChanged(nsISupports* aSubject);
 
   /**
    * Called when XPCOM is shutting down.
    */
   virtual nsresult
   HandleShutdown();
 
   // Called by ToggleBtAck.
--- a/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp
@@ -22,16 +22,18 @@
 #include "nsIMobileConnectionService.h"
 #include "nsIMobileNetworkInfo.h"
 #include "nsIObserverService.h"
 #include "nsISettingsService.h"
 #include "nsITelephonyService.h"
 #include "nsRadioInterfaceLayer.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #define MOZSETTINGS_CHANGED_ID               "mozsettings-changed"
 #define AUDIO_VOLUME_BT_SCO_ID               "audio.volume.bt_sco"
 
 /**
  * Dispatch task with arguments to main thread.
  */
 using namespace mozilla;
@@ -457,17 +459,17 @@ BluetoothHfpManager::Get()
 }
 
 NS_IMETHODIMP
 BluetoothHfpManager::Observe(nsISupports* aSubject,
                              const char* aTopic,
                              const char16_t* aData)
 {
   if (!strcmp(aTopic, MOZSETTINGS_CHANGED_ID)) {
-    HandleVolumeChanged(nsDependentString(aData));
+    HandleVolumeChanged(aSubject);
   } else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     HandleShutdown();
   } else {
     MOZ_ASSERT(false, "BluetoothHfpManager got unexpected topic!");
     return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
@@ -556,49 +558,38 @@ public:
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
     BT_WARNING("BluetoothHandsfreeInterface::VolumeControl failed: %d",
                (int)aStatus);
   }
 };
 
 void
-BluetoothHfpManager::HandleVolumeChanged(const nsAString& aData)
+BluetoothHfpManager::HandleVolumeChanged(nsISupports* aSubject)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // The string that we're interested in will be a JSON string that looks like:
   //  {"key":"volumeup", "value":10}
   //  {"key":"volumedown", "value":2}
-  JSContext* cx = nsContentUtils::GetSafeJSContext();
-  NS_ENSURE_TRUE_VOID(cx);
-
-  JS::Rooted<JS::Value> val(cx);
-  NS_ENSURE_TRUE_VOID(JS_ParseJSON(cx, aData.BeginReading(), aData.Length(), &val));
-  NS_ENSURE_TRUE_VOID(val.isObject());
-
-  JS::Rooted<JSObject*> obj(cx, &val.toObject());
-  JS::Rooted<JS::Value> key(cx);
-  if (!JS_GetProperty(cx, obj, "key", &key) || !key.isString()) {
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
+  RootedDictionary<dom::SettingChangeNotification> setting(cx);
+  if (!WrappedJSToDictionary(cx, aSubject, setting)) {
+    return;
+  }
+  if (!setting.mKey.EqualsASCII(AUDIO_VOLUME_BT_SCO_ID)) {
+    return;
+  }
+  if (!setting.mValue.isNumber()) {
     return;
   }
 
-  bool match;
-  if (!JS_StringEqualsAscii(cx, key.toString(), AUDIO_VOLUME_BT_SCO_ID, &match) ||
-      !match) {
-    return;
-  }
-
-  JS::Rooted<JS::Value> value(cx);
-  if (!JS_GetProperty(cx, obj, "value", &value) ||
-      !value.isNumber()) {
-    return;
-  }
-
-  mCurrentVgs = value.toNumber();
+  mCurrentVgs = setting.mValue.toNumber();
 
   // Adjust volume by headset and we don't have to send volume back to headset
   if (mReceiveVgsFlag) {
     mReceiveVgsFlag = false;
     return;
   }
 
   // Only send volume back when there's a connected headset
--- a/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.h
+++ b/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.h
@@ -144,17 +144,17 @@ private:
   friend class RespondToBLDNTask;
   friend class MainThreadTask;
 
   BluetoothHfpManager();
   bool Init();
   void Cleanup();
 
   void HandleShutdown();
-  void HandleVolumeChanged(const nsAString& aData);
+  void HandleVolumeChanged(nsISupports* aSubject);
   void Notify(const hal::BatteryInformation& aBatteryInfo);
 
   void NotifyConnectionStateChanged(const nsAString& aType);
   void NotifyDialer(const nsAString& aCommand);
 
   PhoneType GetPhoneType(const nsAString& aType);
   void ResetCallArray();
   uint32_t FindFirstCall(uint16_t aState);
--- a/dom/bluetooth/bluez/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/bluez/BluetoothHfpManager.cpp
@@ -18,16 +18,18 @@
 #include "jsapi.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsContentUtils.h"
 #include "nsIObserverService.h"
 #include "nsISettingsService.h"
 #include "nsServiceManagerUtils.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #ifdef MOZ_B2G_RIL
 #include "nsIDOMIccInfo.h"
 #include "nsIIccProvider.h"
 #include "nsIMobileConnectionInfo.h"
 #include "nsIMobileConnectionService.h"
 #include "nsIMobileNetworkInfo.h"
 #include "nsITelephonyService.h"
@@ -200,17 +202,17 @@ NS_IMPL_ISUPPORTS(BluetoothHfpManager::G
                   nsISettingsServiceCallback);
 
 NS_IMETHODIMP
 BluetoothHfpManager::Observe(nsISupports* aSubject,
                              const char* aTopic,
                              const char16_t* aData)
 {
   if (!strcmp(aTopic, MOZSETTINGS_CHANGED_ID)) {
-    HandleVolumeChanged(nsDependentString(aData));
+    HandleVolumeChanged(aSubject);
   } else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     HandleShutdown();
   } else {
     MOZ_ASSERT(false, "BluetoothHfpManager got unexpected topic!");
     return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
@@ -550,50 +552,39 @@ BluetoothHfpManager::NotifyDialer(const 
 
   if (!BroadcastSystemMessage(type, parameters)) {
     BT_WARNING("Failed to broadcast system message to dialer");
   }
 }
 #endif // MOZ_B2G_RIL
 
 void
-BluetoothHfpManager::HandleVolumeChanged(const nsAString& aData)
+BluetoothHfpManager::HandleVolumeChanged(nsISupports* aSubject)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // The string that we're interested in will be a JSON string that looks like:
   //  {"key":"volumeup", "value":10}
   //  {"key":"volumedown", "value":2}
 
-  JSContext* cx = nsContentUtils::GetSafeJSContext();
-  NS_ENSURE_TRUE_VOID(cx);
-
-  JS::Rooted<JS::Value> val(cx);
-  NS_ENSURE_TRUE_VOID(JS_ParseJSON(cx, aData.BeginReading(), aData.Length(), &val));
-  NS_ENSURE_TRUE_VOID(val.isObject());
-
-  JS::Rooted<JSObject*> obj(cx, &val.toObject());
-  JS::Rooted<JS::Value> key(cx);
-  if (!JS_GetProperty(cx, obj, "key", &key) || !key.isString()) {
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
+  RootedDictionary<SettingChangeNotification> setting(cx);
+  if (!WrappedJSToDictionary(cx, aSubject, setting)) {
+    return;
+  }
+  if (!setting.mKey.EqualsASCII(AUDIO_VOLUME_BT_SCO_ID)) {
+    return;
+  }
+  if (!setting.mValue.isNumber()) {
     return;
   }
 
-  bool match;
-  if (!JS_StringEqualsAscii(cx, key.toString(), AUDIO_VOLUME_BT_SCO_ID, &match) ||
-      !match) {
-    return;
-  }
-
-  JS::Rooted<JS::Value> value(cx);
-  if (!JS_GetProperty(cx, obj, "value", &value)||
-      !value.isNumber()) {
-    return;
-  }
-
-  mCurrentVgs = value.toNumber();
+  mCurrentVgs = setting.mValue.toNumber();
 
   // Adjust volume by headset and we don't have to send volume back to headset
   if (mReceiveVgsFlag) {
     mReceiveVgsFlag = false;
     return;
   }
 
   // Only send volume back when there's a connected headset
--- a/dom/bluetooth/bluez/BluetoothHfpManager.h
+++ b/dom/bluetooth/bluez/BluetoothHfpManager.h
@@ -144,17 +144,17 @@ private:
 #ifdef MOZ_B2G_RIL
   friend class RespondToBLDNTask;
   friend class SendRingIndicatorTask;
 #endif
   friend class BluetoothHfpManagerObserver;
 
   BluetoothHfpManager();
   void HandleShutdown();
-  void HandleVolumeChanged(const nsAString& aData);
+  void HandleVolumeChanged(nsISupports* aSubject);
 
   bool Init();
   void Notify(const hal::BatteryInformation& aBatteryInfo);
 #ifdef MOZ_B2G_RIL
   void ResetCallArray();
   uint32_t FindFirstCall(uint16_t aState);
   uint32_t GetNumberOfCalls(uint16_t aState);
   uint32_t GetNumberOfConCalls();
--- a/dom/bluetooth2/BluetoothService.cpp
+++ b/dom/bluetooth2/BluetoothService.cpp
@@ -28,16 +28,17 @@
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "nsContentUtils.h"
 #include "nsIObserverService.h"
 #include "nsISettingsService.h"
 #include "nsISystemMessagesInternal.h"
 #include "nsITimer.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXPCOM.h"
+#include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #if defined(MOZ_WIDGET_GONK)
 #include "cutils/properties.h"
 #endif
 
 #if defined(MOZ_B2G_BT)
 #if defined(MOZ_B2G_BT_BLUEZ)
 /**
@@ -517,70 +518,39 @@ BluetoothService::HandleStartup()
 nsresult
 BluetoothService::HandleStartupSettingsCheck(bool aEnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   return StartStopBluetooth(aEnable, true, nullptr);
 }
 
 nsresult
-BluetoothService::HandleSettingsChanged(const nsAString& aData)
+BluetoothService::HandleSettingsChanged(nsISupports* aSubject)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // The string that we're interested in will be a JSON string that looks like:
   //  {"key":"bluetooth.enabled","value":true}
 
-  AutoSafeJSContext cx;
-  if (!cx) {
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
+  RootedDictionary<SettingChangeNotification> setting(cx);
+  if (!WrappedJSToDictionary(cx, aSubject, setting)) {
     return NS_OK;
   }
-
-  JS::Rooted<JS::Value> val(cx);
-  if (!JS_ParseJSON(cx, aData.BeginReading(), aData.Length(), &val)) {
-    return JS_ReportPendingException(cx) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  if (!val.isObject()) {
+  if (!setting.mKey.EqualsASCII(BLUETOOTH_DEBUGGING_SETTING)) {
     return NS_OK;
   }
-
-  JS::Rooted<JSObject*> obj(cx, &val.toObject());
-
-  JS::Rooted<JS::Value> key(cx);
-  if (!JS_GetProperty(cx, obj, "key", &key)) {
-    MOZ_ASSERT(!JS_IsExceptionPending(cx));
-    return NS_ERROR_OUT_OF_MEMORY;
+  if (!setting.mValue.isBoolean()) {
+    MOZ_ASSERT(false, "Expecting a boolean for 'bluetooth.debugging.enabled'!");
+    return NS_ERROR_UNEXPECTED;
   }
 
-  if (!key.isString()) {
-    return NS_OK;
-  }
-
-  // Check whether the string is BLUETOOTH_DEBUGGING_SETTING
-  bool match;
-  if (!JS_StringEqualsAscii(cx, key.toString(), BLUETOOTH_DEBUGGING_SETTING, &match)) {
-    MOZ_ASSERT(!JS_IsExceptionPending(cx));
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  if (match) {
-    JS::Rooted<JS::Value> value(cx);
-    if (!JS_GetProperty(cx, obj, "value", &value)) {
-      MOZ_ASSERT(!JS_IsExceptionPending(cx));
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    if (!value.isBoolean()) {
-      MOZ_ASSERT(false, "Expecting a boolean for 'bluetooth.debugging.enabled'!");
-      return NS_ERROR_UNEXPECTED;
-    }
-
-    SWITCH_BT_DEBUG(value.toBoolean());
-  }
+  SWITCH_BT_DEBUG(setting.mValue.toBoolean());
 
   return NS_OK;
 }
 
 nsresult
 BluetoothService::HandleShutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -681,17 +651,17 @@ BluetoothService::Observe(nsISupports* a
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!strcmp(aTopic, "profile-after-change")) {
     return HandleStartup();
   }
 
   if (!strcmp(aTopic, MOZSETTINGS_CHANGED_ID)) {
-    return HandleSettingsChanged(nsDependentString(aData));
+    return HandleSettingsChanged(aSubject);
   }
 
   if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     return HandleShutdown();
   }
 
   MOZ_ASSERT(false, "BluetoothService got unexpected topic!");
   return NS_ERROR_UNEXPECTED;
--- a/dom/bluetooth2/BluetoothService.h
+++ b/dom/bluetooth2/BluetoothService.h
@@ -366,17 +366,17 @@ protected:
    */
   nsresult
   HandleStartupSettingsCheck(bool aEnable);
 
   /**
    * Called when "mozsettings-changed" observer topic fires.
    */
   nsresult
-  HandleSettingsChanged(const nsAString& aData);
+  HandleSettingsChanged(nsISupports* aSubject);
 
   /**
    * Called when XPCOM is shutting down.
    */
   virtual nsresult
   HandleShutdown();
 
   // Called by ToggleBtAck.
--- a/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp
+++ b/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp
@@ -22,16 +22,17 @@
 #include "nsIMobileConnectionService.h"
 #include "nsIMobileNetworkInfo.h"
 #include "nsIObserverService.h"
 #include "nsISettingsService.h"
 #include "nsITelephonyService.h"
 #include "nsRadioInterfaceLayer.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
+#include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #define MOZSETTINGS_CHANGED_ID               "mozsettings-changed"
 #define AUDIO_VOLUME_BT_SCO_ID               "audio.volume.bt_sco"
 
 using namespace mozilla;
 using namespace mozilla::ipc;
 USING_BLUETOOTH_NAMESPACE
 
@@ -460,17 +461,17 @@ BluetoothHfpManager::Get()
 }
 
 NS_IMETHODIMP
 BluetoothHfpManager::Observe(nsISupports* aSubject,
                              const char* aTopic,
                              const char16_t* aData)
 {
   if (!strcmp(aTopic, MOZSETTINGS_CHANGED_ID)) {
-    HandleVolumeChanged(nsDependentString(aData));
+    HandleVolumeChanged(aSubject);
   } else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     HandleShutdown();
   } else {
     MOZ_ASSERT(false, "BluetoothHfpManager got unexpected topic!");
     return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
@@ -559,49 +560,39 @@ public:
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
     BT_WARNING("BluetoothHandsfreeInterface::VolumeControl failed: %d",
                (int)aStatus);
   }
 };
 
 void
-BluetoothHfpManager::HandleVolumeChanged(const nsAString& aData)
+BluetoothHfpManager::HandleVolumeChanged(nsISupports* aSubject)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // The string that we're interested in will be a JSON string that looks like:
   //  {"key":"volumeup", "value":10}
   //  {"key":"volumedown", "value":2}
-  JSContext* cx = nsContentUtils::GetSafeJSContext();
-  NS_ENSURE_TRUE_VOID(cx);
 
-  JS::Rooted<JS::Value> val(cx);
-  NS_ENSURE_TRUE_VOID(JS_ParseJSON(cx, aData.BeginReading(), aData.Length(), &val));
-  NS_ENSURE_TRUE_VOID(val.isObject());
-
-  JS::Rooted<JSObject*> obj(cx, &val.toObject());
-  JS::Rooted<JS::Value> key(cx);
-  if (!JS_GetProperty(cx, obj, "key", &key) || !key.isString()) {
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
+  RootedDictionary<dom::SettingChangeNotification> setting(cx);
+  if (!WrappedJSToDictionary(cx, aSubject, setting)) {
+    return;
+  }
+  if (!setting.mKey.EqualsASCII(AUDIO_VOLUME_BT_SCO_ID)) {
+    return;
+  }
+  if (!setting.mValue.isNumber()) {
     return;
   }
 
-  bool match;
-  if (!JS_StringEqualsAscii(cx, key.toString(), AUDIO_VOLUME_BT_SCO_ID, &match) ||
-      !match) {
-    return;
-  }
-
-  JS::Rooted<JS::Value> value(cx);
-  if (!JS_GetProperty(cx, obj, "value", &value) ||
-      !value.isNumber()) {
-    return;
-  }
-
-  mCurrentVgs = value.toNumber();
+  mCurrentVgs = setting.mValue.toNumber();
 
   // Adjust volume by headset and we don't have to send volume back to headset
   if (mReceiveVgsFlag) {
     mReceiveVgsFlag = false;
     return;
   }
 
   // Only send volume back when there's a connected headset
--- a/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.h
+++ b/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.h
@@ -142,17 +142,17 @@ private:
   friend class CloseScoTask;
   friend class RespondToBLDNTask;
   friend class MainThreadTask;
 
   BluetoothHfpManager();
   bool Init();
 
   void HandleShutdown();
-  void HandleVolumeChanged(const nsAString& aData);
+  void HandleVolumeChanged(nsISupports* aSubject);
   void Notify(const hal::BatteryInformation& aBatteryInfo);
 
   void NotifyConnectionStateChanged(const nsAString& aType);
   void NotifyDialer(const nsAString& aCommand);
 
   PhoneType GetPhoneType(const nsAString& aType);
   void ResetCallArray();
   uint32_t FindFirstCall(uint16_t aState);
--- a/dom/bluetooth2/bluez/BluetoothHfpManager.cpp
+++ b/dom/bluetooth2/bluez/BluetoothHfpManager.cpp
@@ -18,16 +18,17 @@
 #include "jsapi.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsContentUtils.h"
 #include "nsIObserverService.h"
 #include "nsISettingsService.h"
 #include "nsServiceManagerUtils.h"
+#include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #ifdef MOZ_B2G_RIL
 #include "nsIDOMIccInfo.h"
 #include "nsIIccProvider.h"
 #include "nsIMobileConnectionInfo.h"
 #include "nsIMobileConnectionService.h"
 #include "nsIMobileNetworkInfo.h"
 #include "nsITelephonyService.h"
@@ -200,17 +201,17 @@ NS_IMPL_ISUPPORTS(BluetoothHfpManager::G
                   nsISettingsServiceCallback);
 
 NS_IMETHODIMP
 BluetoothHfpManager::Observe(nsISupports* aSubject,
                              const char* aTopic,
                              const char16_t* aData)
 {
   if (!strcmp(aTopic, MOZSETTINGS_CHANGED_ID)) {
-    HandleVolumeChanged(nsDependentString(aData));
+    HandleVolumeChanged(aSubject);
   } else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     HandleShutdown();
   } else {
     MOZ_ASSERT(false, "BluetoothHfpManager got unexpected topic!");
     return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
@@ -550,50 +551,39 @@ BluetoothHfpManager::NotifyDialer(const 
 
   if (!BroadcastSystemMessage(type, parameters)) {
     BT_WARNING("Failed to broadcast system message to dialer");
   }
 }
 #endif // MOZ_B2G_RIL
 
 void
-BluetoothHfpManager::HandleVolumeChanged(const nsAString& aData)
+BluetoothHfpManager::HandleVolumeChanged(nsISupports* aSubject)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // The string that we're interested in will be a JSON string that looks like:
   //  {"key":"volumeup", "value":10}
   //  {"key":"volumedown", "value":2}
 
-  JSContext* cx = nsContentUtils::GetSafeJSContext();
-  NS_ENSURE_TRUE_VOID(cx);
-
-  JS::Rooted<JS::Value> val(cx);
-  NS_ENSURE_TRUE_VOID(JS_ParseJSON(cx, aData.BeginReading(), aData.Length(), &val));
-  NS_ENSURE_TRUE_VOID(val.isObject());
-
-  JS::Rooted<JSObject*> obj(cx, &val.toObject());
-  JS::Rooted<JS::Value> key(cx);
-  if (!JS_GetProperty(cx, obj, "key", &key) || !key.isString()) {
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
+  RootedDictionary<dom::SettingChangeNotification> setting(cx);
+  if (!WrappedJSToDictionary(cx, aSubject, setting)) {
+    return;
+  }
+  if (!setting.mKey.EqualsASCII(AUDIO_VOLUME_BT_SCO_ID)) {
+    return;
+  }
+  if (!setting.mValue.isNumber()) {
     return;
   }
 
-  bool match;
-  if (!JS_StringEqualsAscii(cx, key.toString(), AUDIO_VOLUME_BT_SCO_ID, &match) ||
-      !match) {
-    return;
-  }
-
-  JS::Rooted<JS::Value> value(cx);
-  if (!JS_GetProperty(cx, obj, "value", &value)||
-      !value.isNumber()) {
-    return;
-  }
-
-  mCurrentVgs = value.toNumber();
+  mCurrentVgs = setting.mValue.toNumber();
 
   // Adjust volume by headset and we don't have to send volume back to headset
   if (mReceiveVgsFlag) {
     mReceiveVgsFlag = false;
     return;
   }
 
   // Only send volume back when there's a connected headset
--- a/dom/bluetooth2/bluez/BluetoothHfpManager.h
+++ b/dom/bluetooth2/bluez/BluetoothHfpManager.h
@@ -144,17 +144,17 @@ private:
 #ifdef MOZ_B2G_RIL
   friend class RespondToBLDNTask;
   friend class SendRingIndicatorTask;
 #endif
   friend class BluetoothHfpManagerObserver;
 
   BluetoothHfpManager();
   void HandleShutdown();
-  void HandleVolumeChanged(const nsAString& aData);
+  void HandleVolumeChanged(nsISupports* aSubject);
 
   bool Init();
   void Notify(const hal::BatteryInformation& aBatteryInfo);
 #ifdef MOZ_B2G_RIL
   void ResetCallArray();
   uint32_t FindFirstCall(uint16_t aState);
   uint32_t GetNumberOfCalls(uint16_t aState);
   uint32_t GetNumberOfConCalls();
--- a/dom/browser-element/BrowserElementChildPreload.js
+++ b/dom/browser-element/BrowserElementChildPreload.js
@@ -216,16 +216,21 @@ BrowserElementChild.prototype = {
                      /* useCapture = */ true,
                      /* wantsUntrusted = */ false);
 
     addEventListener('mozselectionchange',
                      this._selectionChangeHandler.bind(this),
                      /* useCapture = */ false,
                      /* wantsUntrusted = */ false);
 
+    addEventListener('scrollviewchange',
+                     this._ScrollViewChangeHandler.bind(this),
+                     /* useCapture = */ false,
+                     /* wantsUntrusted = */ false);
+
     // This listens to unload events from our message manager, but /not/ from
     // the |content| window.  That's because the window's unload event doesn't
     // bubble, and we're not using a capturing listener.  If we'd used
     // useCapture == true, we /would/ hear unload events from the window, which
     // is not what we want!
     addEventListener('unload',
                      this._unloadHandler.bind(this),
                      /* useCapture = */ false,
@@ -621,16 +626,26 @@ BrowserElementChild.prototype = {
 
     if (lang) {
       meta.lang = lang;
     }
 
     sendAsyncMsg('metachange', meta);
   },
 
+  _ScrollViewChangeHandler: function(e) {
+    e.stopPropagation();
+    let detail = {
+      state: e.state,
+      scrollX: e.scrollX,
+      scrollY: e.scrollY,
+    };
+    sendAsyncMsg('scrollviewchange', detail);
+  },
+
   _selectionChangeHandler: function(e) {
     e.stopPropagation();
     let boundingClientRect = e.boundingClientRect;
     if (!boundingClientRect) {
       return;
     }
 
     let zoomFactor = content.screen.width / content.innerWidth;
@@ -661,17 +676,17 @@ BrowserElementChild.prototype = {
       let currentRect = currentWindow.frameElement.getBoundingClientRect();
       detail.rect.top += currentRect.top;
       detail.rect.bottom += currentRect.top;
       detail.rect.left += currentRect.left;
       detail.rect.right += currentRect.left;
       currentWindow = currentWindow.parent;
     }
 
-    sendAsyncMsg("selectionchange", detail);
+    sendAsyncMsg('selectionchange', detail);
   },
 
   _themeColorChangedHandler: function(eventType, target) {
     let meta = {
       name: 'theme-color',
       content: target.content,
       type: eventType.replace('DOMMeta', '').toLowerCase()
     };
--- a/dom/browser-element/BrowserElementParent.jsm
+++ b/dom/browser-element/BrowserElementParent.jsm
@@ -250,17 +250,18 @@ BrowserElementParent.prototype = {
       "got-can-go-back": this._gotDOMRequestResult,
       "got-can-go-forward": this._gotDOMRequestResult,
       "fullscreen-origin-change": this._remoteFullscreenOriginChange,
       "rollback-fullscreen": this._remoteFrameFullscreenReverted,
       "exit-fullscreen": this._exitFullscreen,
       "got-visible": this._gotDOMRequestResult,
       "visibilitychange": this._childVisibilityChange,
       "got-set-input-method-active": this._gotDOMRequestResult,
-      "selectionchange": this._handleSelectionChange
+      "selectionchange": this._handleSelectionChange,
+      "scrollviewchange": this._handleScrollViewChange
     };
 
     let mmSecuritySensitiveCalls = {
       "showmodalprompt": this._handleShowModalPrompt,
       "contextmenu": this._fireCtxMenuEvent,
       "securitychange": this._fireEventFromMsg,
       "locationchange": this._fireEventFromMsg,
       "iconchange": this._fireEventFromMsg,
@@ -491,16 +492,22 @@ BrowserElementParent.prototype = {
   },
 
   _handleSelectionChange: function(data) {
     let evt = this._createEvent('selectionchange', data.json,
                                 /* cancelable = */ false);
     this._frameElement.dispatchEvent(evt);
   },
 
+  _handleScrollViewChange: function(data) {
+    let evt = this._createEvent("scrollviewchange", data.json,
+                                /* cancelable = */ false);
+    this._frameElement.dispatchEvent(evt);
+  },
+
   _createEvent: function(evtName, detail, cancelable) {
     // This will have to change if we ever want to send a CustomEvent with null
     // detail.  For now, it's OK.
     if (detail !== undefined && detail !== null) {
       detail = Cu.cloneInto(detail, this._window);
       return new this._window.CustomEvent('mozbrowser' + evtName,
                                           { bubbles: true,
                                             cancelable: cancelable,
--- a/dom/camera/DOMCameraManager.cpp
+++ b/dom/camera/DOMCameraManager.cpp
@@ -46,17 +46,17 @@ GetCameraLog()
 {
   static PRLogModuleInfo *sLog;
   if (!sLog) {
     sLog = PR_NewLogModule("Camera");
   }
   return sLog;
 }
 
-WindowTable* nsDOMCameraManager::sActiveWindows = nullptr;
+::WindowTable* nsDOMCameraManager::sActiveWindows = nullptr;
 
 nsDOMCameraManager::nsDOMCameraManager(nsPIDOMWindow* aWindow)
   : mWindowId(aWindow->WindowID())
   , mPermission(nsIPermissionManager::DENY_ACTION)
   , mWindow(aWindow)
 {
   /* member initializers and constructor code */
   DOM_CAMERA_LOGT("%s:%d : this=%p, windowId=%llx\n", __func__, __LINE__, this, mWindowId);
@@ -104,17 +104,17 @@ nsDOMCameraManager::CheckPermission(nsPI
 }
 
 /* static */
 already_AddRefed<nsDOMCameraManager>
 nsDOMCameraManager::CreateInstance(nsPIDOMWindow* aWindow)
 {
   // Initialize the shared active window tracker
   if (!sActiveWindows) {
-    sActiveWindows = new WindowTable();
+    sActiveWindows = new ::WindowTable();
   }
 
   nsRefPtr<nsDOMCameraManager> cameraManager =
     new nsDOMCameraManager(aWindow);
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (!obs) {
     DOM_CAMERA_LOGE("Camera manager failed to get observer service\n");
--- a/dom/camera/moz.build
+++ b/dom/camera/moz.build
@@ -8,17 +8,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk
     MOCHITEST_MANIFESTS += ['test/mochitest.ini']
 
 EXPORTS += [
     'CameraCommon.h',
     'CameraPreferences.h',
     'DOMCameraManager.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'CameraControlImpl.cpp',
     'CameraPreferences.cpp',
     'CameraPreviewMediaStream.cpp',
     'CameraRecorderProfiles.cpp',
     'DOMCameraCapabilities.cpp',
     'DOMCameraControl.cpp',
     'DOMCameraControlListener.cpp',
     'DOMCameraDetectedFace.cpp',
@@ -33,17 +33,17 @@ if CONFIG['MOZ_B2G_CAMERA']:
         'GonkCameraParameters.cpp',
         'GonkCameraSource.cpp',
         'GonkRecorder.cpp',
         'GonkRecorderProfiles.cpp',
         'TestGonkCameraControl.cpp',
         'TestGonkCameraHardware.cpp',
     ]
 else:
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'FallbackCameraControl.cpp',
         'FallbackCameraManager.cpp',
     ]
 
 FAIL_ON_WARNINGS = True
 
 LOCAL_INCLUDES += [
     '../base',
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -3098,17 +3098,17 @@ CanvasRenderingContext2D::GetHitRegionRe
  * Used for nsBidiPresUtils::ProcessText
  */
 struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcessor
 {
   typedef CanvasRenderingContext2D::ContextState ContextState;
 
   virtual void SetText(const char16_t* text, int32_t length, nsBidiDirection direction)
   {
-    mFontgrp->UpdateFontList(); // ensure user font generation is current
+    mFontgrp->UpdateUserFonts(); // ensure user font generation is current
     mTextRun = mFontgrp->MakeTextRun(text,
                                      length,
                                      mThebes,
                                      mAppUnitsPerDevPixel,
                                      direction==NSBIDI_RTL ? gfxTextRunFactory::TEXT_IS_RTL : 0);
   }
 
   virtual nscoord GetWidth()
@@ -3450,19 +3450,19 @@ CanvasRenderingContext2D::DrawOrMeasureT
     anchorX = 0;
   } else {
     anchorX = 1;
   }
 
   processor.mPt.x -= anchorX * totalWidth;
 
   // offset pt.y based on text baseline
-  processor.mFontgrp->UpdateFontList(); // ensure user font generation is current
-  NS_ASSERTION(processor.mFontgrp->FontListLength()>0, "font group contains no fonts");
-  const gfxFont::Metrics& fontMetrics = processor.mFontgrp->GetFontAt(0)->GetMetrics();
+  processor.mFontgrp->UpdateUserFonts(); // ensure user font generation is current
+  const gfxFont::Metrics& fontMetrics =
+    processor.mFontgrp->GetFirstValidFont()->GetMetrics();
 
   gfxFloat anchorY;
 
   switch (state.textBaseline)
   {
   case TextBaseline::HANGING:
       // fall through; best we can do with the information available
   case TextBaseline::TOP:
--- a/dom/canvas/test/webgl-mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest.ini
@@ -1,13 +1,15 @@
 [DEFAULT]
 support-files =
   webgl-mochitest/driver-info.js
   webgl-mochitest/webgl-util.js
 
+[webgl-mochitest/test-backbuffer-channels.html]
+[webgl-mochitest/test-hidden-alpha.html]
 [webgl-mochitest/test_depth_readpixels.html]
 [webgl-mochitest/test_draw.html]
 [webgl-mochitest/test_fb_param.html]
 [webgl-mochitest/test_fb_param_crash.html]
 [webgl-mochitest/test_highp_fs.html]
 [webgl-mochitest/test_no_arr_points.html]
 [webgl-mochitest/test_noprog_draw.html]
 [webgl-mochitest/test_privileged_exts.html]
--- a/dom/canvas/test/webgl-mochitest/mochi-to-testcase.py
+++ b/dom/canvas/test/webgl-mochitest/mochi-to-testcase.py
@@ -4,17 +4,17 @@ import re
 
 assert len(sys.argv) == 2
 mochiPath = sys.argv[1]
 
 extDotPos = mochiPath.find('.html')
 assert extDotPos != -1, 'mochitest target must be an html doc.'
 
 testPath = mochiPath[:extDotPos] + '.solo.html'
-    
+
 def ReadLocalFile(include):
     incPath = os.path.dirname(mochiPath)
     filePath = os.path.join(incPath, include)
 
     data = None
     try:
         f = open(filePath, 'r')
         data = f.read()
@@ -26,61 +26,68 @@ def ReadLocalFile(include):
     except:
         pass
 
     return data
 
 kSimpleTestReplacement = '''\n
 <script>
 // SimpleTest.js replacement
+
+function debug(text) {
+  var elem = document.getElementById('mochi-to-testcase-output');
+  elem.innerHTML += '\\n<br/>\\n' + text;
+}
+
 function ok(val, text) {
-  var elem = document.getElementById('mochi-to-testcase-output');
   var status = val ? 'Test <font color=\\'green\\'>passed</font>: '
                    : 'Test <font color=\\'red\\'  >FAILED</font>: ';
-  elem.innerHTML += '\\n<br/>\\n' + status + text;
+  debug(status + text);
 }
 
 function todo(val, text) {
-  ok(!val, 'Todo: ' + text);
+  var status = val ? 'Test <font color=\\'orange\\'>UNEXPECTED PASS</font>: '
+                   : 'Test <font color=\\'blue\\'  >todo</font>: ';
+  debug(status + text);
 }
 </script>
 <div id='mochi-to-testcase-output'></div>
 \n'''
 
-fin = open(mochiPath, 'r')
-fout = open(testPath, 'w')
+fin = open(mochiPath, 'rb')
+fout = open(testPath, 'wb')
 includePattern = re.compile('<script\\s*src=[\'"](.*)\\.js[\'"]>\\s*</script>')
 cssPattern = re.compile('<link\\s*rel=[\'"]stylesheet[\'"]\\s*href=[\'"]([^=>]*)[\'"]>')
 for line in fin:
     skipLine = False
     for css in cssPattern.findall(line):
         skipLine = True
         print('Ignoring stylesheet: ' + css)
-    
+
     for inc in includePattern.findall(line):
         skipLine = True
         if inc == '/MochiKit/MochiKit':
             continue
 
         if inc == '/tests/SimpleTest/SimpleTest':
             print('Injecting SimpleTest replacement')
             fout.write(kSimpleTestReplacement);
             continue
-            
+
         incData = ReadLocalFile(inc + '.js')
         if not incData:
             print('Warning: Unknown JS file ignored: ' + inc + '.js')
             continue
 
         print('Injecting include: ' + inc + '.js')
         fout.write('\n<script>\n// Imported from: ' + inc + '.js\n');
         fout.write(incData);
         fout.write('\n</script>\n');
         continue
 
     if skipLine:
         continue
-    
+
     fout.write(line)
     continue
 
 fin.close()
 fout.close()
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-mochitest/test-backbuffer-channels.html
@@ -0,0 +1,111 @@
+<!DOCTYPE HTML>
+<title>WebGL test: bug 958723</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script src="driver-info.js"></script>
+<script src="webgl-util.js"></script>
+<body>
+<script>
+
+function TestAttribs(attribs) {
+  debug('Testing attribs: ' + JSON.stringify(attribs));
+  var canvas = document.createElement('canvas');
+  var gl = canvas.getContext('experimental-webgl', attribs);
+  ok(gl, 'No tested attribs should result in failure to create a context');
+  if (!gl)
+    return;
+
+  var actual = gl.getContextAttributes();
+
+  ok(actual.alpha == attribs.alpha,
+     'Resulting `alpha` should match request.');
+  ok(actual.premultipliedAlpha == attribs.premultipliedAlpha,
+     'Resulting `premultipliedAlpha` should match request.');
+  ok(actual.preserveDrawingBuffer == attribs.preserveDrawingBuffer,
+     'Resulting `preserveDrawingBuffer` should match request.');
+
+  // "The depth, stencil and antialias attributes, when set to true, are
+  // requests, not requirements."
+  if (!attribs.antialias) {
+    ok(!actual.antialias, 'No `antialias` if not requested.');
+  }
+  if (!attribs.depth) {
+    ok(!actual.depth, 'No `depth` if not requested.');
+  }
+  if (!attribs.stencil) {
+    ok(!actual.stencil, 'No `stencil` if not requested.');
+  }
+
+  var hasAlpha = !!gl.getParameter(gl.ALPHA_BITS);
+  var hasDepth = !!gl.getParameter(gl.DEPTH_BITS);
+  var hasStencil = !!gl.getParameter(gl.STENCIL_BITS);
+  var hasAntialias = !!gl.getParameter(gl.SAMPLES);
+
+  ok(hasAlpha == actual.alpha, 'Bits should match `alpha` attrib.');
+  ok(hasAntialias == actual.antialias, 'Bits should match `antialias` attrib.');
+  ok(hasDepth == actual.depth, 'Bits should match `depth` attrib.');
+  ok(hasStencil == actual.stencil, 'Bits should match `stencil` attrib.');
+}
+
+function CloneAttribs(attribs) {
+  return {
+    alpha: attribs.alpha,
+    antialias: attribs.antialias,
+    depth: attribs.depth,
+    premultipliedAlpha: attribs.premultipliedAlpha,
+    preserveDrawingBuffer: attribs.preserveDrawingBuffer,
+    stencil: attribs.stencil,
+  };
+}
+
+function SplitForAttrib(list, attrib) {
+  var ret = [];
+
+  for (var i in list) {
+    var cur = list[i];
+    if (cur[attrib])
+      throw 'Attrib is already true.';
+
+    var clone = CloneAttribs(cur);
+    clone[attrib] = true;
+
+    ret.push(cur);
+    ret.push(clone);
+  }
+
+  return ret;
+}
+
+function GenAttribList() {
+  var base = {
+    alpha: false,
+    antialias: false,
+    depth: false,
+    premultipliedAlpha: false,
+    preserveDrawingBuffer: false,
+    stencil: false,
+  };
+  var list = [base];
+  list = SplitForAttrib(list, 'alpha');
+  list = SplitForAttrib(list, 'antialias');
+  list = SplitForAttrib(list, 'depth');
+  list = SplitForAttrib(list, 'premultipliedAlpha');
+  list = SplitForAttrib(list, 'preserveDrawingBuffer');
+  list = SplitForAttrib(list, 'stencil');
+
+  if (list.length != 1<<6)
+    throw 'Attribs list length wrong: ' + list.length;
+
+  return list;
+}
+
+var list = GenAttribList();
+for (var i in list) {
+  var attribs = list[i];
+  TestAttribs(attribs);
+}
+
+ok(true, 'Test complete.');
+
+</script>
+
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-mochitest/test-hidden-alpha.html
@@ -0,0 +1,153 @@
+<!DOCTYPE HTML>
+<title>WebGL test: Hidden alpha on no-alpha contexts</title>
+<script src='/tests/SimpleTest/SimpleTest.js'></script>
+<link rel='stylesheet' href='/tests/SimpleTest/test.css'>
+<script src='driver-info.js'></script>
+<script src='webgl-util.js'></script>
+<body>
+<script id='vs' type='x-shader/x-vertex'>
+  attribute vec2 aPosCoord;
+
+  void main(void) {
+    gl_Position = vec4(aPosCoord, 0.0, 1.0);
+  }
+</script>
+
+<script id='fs' type='x-shader/x-fragment'>
+  precision mediump float;
+
+  void main(void) {
+    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+  }
+</script>
+<canvas id='canvas' style='border: none;' width='100' height='100'></canvas>
+<script>
+
+var posCoords_arr = new Float32Array(2 * 4);
+var posCoords_buff = null;
+function DrawQuad(gl, prog, x0, y0, x1, y1) {
+  gl.useProgram(prog);
+
+  if (!posCoords_buff) {
+    posCoords_buff = gl.createBuffer();
+  }
+  gl.bindBuffer(gl.ARRAY_BUFFER, posCoords_buff);
+  posCoords_arr[0] = x0;
+  posCoords_arr[1] = y0;
+
+  posCoords_arr[2] = x1;
+  posCoords_arr[3] = y0;
+
+  posCoords_arr[4] = x0;
+  posCoords_arr[5] = y1;
+
+  posCoords_arr[6] = x1;
+  posCoords_arr[7] = y1;
+  gl.bufferData(gl.ARRAY_BUFFER, posCoords_arr, gl.STREAM_DRAW);
+
+  gl.enableVertexAttribArray(prog.aPosCoord);
+  gl.vertexAttribPointer(prog.aPosCoord, 2, gl.FLOAT, false, 0, 0);
+
+  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+}
+
+function DrawSquare(gl, prog, size) {
+  DrawQuad(gl, prog, -size, -size, size, size);
+}
+
+function Reset(gl) {
+  gl.canvas.width += 1;
+  gl.canvas.width -= 1;
+}
+
+function ReadCenterPixel(gl) {
+  var w = gl.drawingbufferWidth;
+  var h = gl.drawingbufferHeight;
+  var ret = new Uint8Array(4);
+  gl.readPixels(w/2, h/2, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, ret);
+  return ret;
+}
+
+function Test(gl, prog) {
+  gl.enable(gl.BLEND);
+  gl.blendFunc(gl.ZERO, gl.DST_ALPHA);
+
+  var iColor = 64;
+  var fColor = iColor / 255.0;
+
+  //////////////////
+
+  debug('clear(R,G,B,0)');
+
+  Reset(gl);
+
+  gl.clearColor(fColor, fColor, fColor, 0.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+
+  var dataURL_pre = gl.canvas.toDataURL();
+  //console.log('Before blending: ' + dataURL_pre);
+
+  DrawSquare(gl, prog, 0.7);
+
+  var pixel = ReadCenterPixel(gl);
+  ok(pixel[0] == iColor &&
+     pixel[1] == iColor &&
+     pixel[2] == iColor, 'Color should be the same.');
+  ok(pixel[3] == 255, 'No-alpha should always readback as 1.0 alpha.');
+
+  var dataURL_post = gl.canvas.toDataURL();
+  //console.log('After blending: ' + dataURL_post);
+  ok(dataURL_post == dataURL_pre,
+     'toDataURL should be unchanged after blending.');
+
+  //////////////////
+
+  debug('mask(R,G,B,0), clear(R,G,B,1)');
+
+  Reset(gl);
+
+  gl.colorMask(true, true, true, false);
+  gl.clearColor(fColor, fColor, fColor, 1.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+  gl.colorMask(true, true, true, true);
+
+  dataURL_pre = gl.canvas.toDataURL();
+  //console.log('Before blending: ' + dataURL_pre);
+
+  DrawSquare(gl, prog, 0.7);
+
+  var pixel = ReadCenterPixel(gl);
+  ok(pixel[0] == iColor &&
+     pixel[1] == iColor &&
+     pixel[2] == iColor, 'Color should be the same.');
+  ok(pixel[3] == 255, 'No-alpha should always readback as 1.0 alpha.');
+  ok(gl.getError() == 0, 'Should have no errors.');
+
+  dataURL_post = gl.canvas.toDataURL();
+  //console.log('After blending: ' + dataURL_post);
+  ok(dataURL_post == dataURL_pre,
+     'toDataURL should be unchanged after blending.');
+
+  ok(true, 'Test complete.');
+}
+
+(function(){
+  var canvas = document.getElementById('canvas');
+  var attribs = {
+    alpha: false,
+    antialias: false,
+    premultipliedAlpha: false,
+  };
+  var gl = canvas.getContext('experimental-webgl', attribs);
+  ok(gl, 'WebGL should work.');
+  ok(gl.getParameter(gl.ALPHA_BITS) == 0, 'Shouldn\'t have alpha bits.');
+
+  var prog = WebGLUtil.createProgramByIds(gl, 'vs', 'fs');
+  ok(prog, 'Program should link.');
+  prog.aPosCoord = gl.getAttribLocation(prog, 'aPosCoord');
+
+  setTimeout(function(){ Test(gl, prog); }, 500);
+})();
+
+</script>
+</body>
--- a/dom/fmradio/FMRadioService.cpp
+++ b/dom/fmradio/FMRadioService.cpp
@@ -11,16 +11,18 @@
 #include "AudioManager.h"
 #include "nsDOMClassInfo.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/FMRadioChild.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "nsIObserverService.h"
 #include "nsISettingsService.h"
 #include "nsJSUtils.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #define BAND_87500_108000_kHz 1
 #define BAND_76000_108000_kHz 2
 #define BAND_76000_90000_kHz  3
 
 #define MOZSETTINGS_CHANGED_ID "mozsettings-changed"
 #define SETTING_KEY_AIRPLANEMODE_ENABLED "airplaneMode.enabled"
 
@@ -673,70 +675,49 @@ FMRadioService::CancelSeek(FMRadioReplyR
   TransitionState(
     ErrorResponse(NS_LITERAL_STRING("Seek action is cancelled")), Enabled);
 
   aReplyRunnable->SetReply(SuccessResponse());
   NS_DispatchToMainThread(aReplyRunnable);
 }
 
 NS_IMETHODIMP
-FMRadioService::Observe(nsISupports * aSubject,
-                        const char * aTopic,
-                        const char16_t * aData)
+FMRadioService::Observe(nsISupports* aSubject,
+                        const char* aTopic,
+                        const char16_t* aData)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(sFMRadioService);
 
   if (strcmp(aTopic, MOZSETTINGS_CHANGED_ID) != 0) {
     return NS_OK;
   }
 
   // The string that we're interested in will be a JSON string looks like:
   //  {"key":"airplaneMode.enabled","value":true}
-  AutoSafeJSContext cx;
-  const nsDependentString dataStr(aData);
-  JS::Rooted<JS::Value> val(cx);
-  if (!JS_ParseJSON(cx, dataStr.get(), dataStr.Length(), &val) ||
-      !val.isObject()) {
-    NS_WARNING("Bad JSON string format.");
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
+  RootedDictionary<dom::SettingChangeNotification> setting(cx);
+  if (!WrappedJSToDictionary(cx, aSubject, setting)) {
     return NS_OK;
   }
-
-  JS::Rooted<JSObject*> obj(cx, &val.toObject());
-  JS::Rooted<JS::Value> key(cx);
-  if (!JS_GetProperty(cx, obj, "key", &key) ||
-      !key.isString()) {
-    NS_WARNING("Failed to get string property `key`.");
+  if (!setting.mKey.EqualsASCII(SETTING_KEY_AIRPLANEMODE_ENABLED)) {
+    return NS_OK;
+  }
+  if (!setting.mValue.isBoolean()) {
     return NS_OK;
   }
 
-  JS::Rooted<JSString*> jsKey(cx, key.toString());
-  nsAutoJSString keyStr;
-  if (!keyStr.init(cx, jsKey)) {
-    return NS_OK;
-  }
+  mAirplaneModeEnabled = setting.mValue.toBoolean();
+  mHasReadAirplaneModeSetting = true;
 
-  if (keyStr.EqualsLiteral(SETTING_KEY_AIRPLANEMODE_ENABLED)) {
-    JS::Rooted<JS::Value> value(cx);
-    if (!JS_GetProperty(cx, obj, "value", &value)) {
-      NS_WARNING("Failed to get property `value`.");
-      return NS_OK;
-    }
-
-    if (!value.isBoolean()) {
-      return NS_OK;
-    }
-
-    mAirplaneModeEnabled = value.toBoolean();
-    mHasReadAirplaneModeSetting = true;
-
-    // Disable the FM radio HW if Airplane mode is enabled.
-    if (mAirplaneModeEnabled) {
-      Disable(nullptr);
-    }
+  // Disable the FM radio HW if Airplane mode is enabled.
+  if (mAirplaneModeEnabled) {
+    Disable(nullptr);
   }
 
   return NS_OK;
 }
 
 void
 FMRadioService::NotifyFMRadioEvent(FMRadioEventType aType)
 {
--- a/dom/geolocation/nsGeolocation.cpp
+++ b/dom/geolocation/nsGeolocation.cpp
@@ -19,16 +19,17 @@
 #include "nsIObserverService.h"
 #include "nsPIDOMWindow.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Services.h"
 #include "mozilla/unused.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
+#include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 class nsIPrincipal;
 
 #ifdef MOZ_ENABLE_QT5GEOPOSITION
 #include "QTMLocationProvider.h"
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
@@ -707,46 +708,36 @@ nsresult nsGeolocationService::Init()
   return NS_OK;
 }
 
 nsGeolocationService::~nsGeolocationService()
 {
 }
 
 void
-nsGeolocationService::HandleMozsettingChanged(const char16_t* aData)
+nsGeolocationService::HandleMozsettingChanged(nsISupports* aSubject)
 {
     // The string that we're interested in will be a JSON string that looks like:
     //  {"key":"gelocation.enabled","value":true}
 
-    AutoSafeJSContext cx;
-
-    nsDependentString dataStr(aData);
-    JS::Rooted<JS::Value> val(cx);
-    if (!JS_ParseJSON(cx, dataStr.get(), dataStr.Length(), &val) || !val.isObject()) {
+    AutoJSAPI jsapi;
+    jsapi.Init();
+    JSContext* cx = jsapi.cx();
+    RootedDictionary<SettingChangeNotification> setting(cx);
+    if (!WrappedJSToDictionary(cx, aSubject, setting)) {
+      return;
+    }
+    if (!setting.mKey.EqualsASCII(GEO_SETINGS_ENABLED)) {
+      return;
+    }
+    if (!setting.mValue.isBoolean()) {
       return;
     }
 
-    JS::Rooted<JSObject*> obj(cx, &val.toObject());
-    JS::Rooted<JS::Value> key(cx);
-    if (!JS_GetProperty(cx, obj, "key", &key) || !key.isString()) {
-      return;
-    }
-
-    bool match;
-    if (!JS_StringEqualsAscii(cx, key.toString(), GEO_SETINGS_ENABLED, &match) || !match) {
-      return;
-    }
-
-    JS::Rooted<JS::Value> value(cx);
-    if (!JS_GetProperty(cx, obj, "value", &value) || !value.isBoolean()) {
-      return;
-    }
-
-    HandleMozsettingValue(value.toBoolean());
+    HandleMozsettingValue(setting.mValue.toBoolean());
 }
 
 void
 nsGeolocationService::HandleMozsettingValue(const bool aValue)
 {
     if (!aValue) {
       // turn things off
       StopDevice();
@@ -781,17 +772,17 @@ nsGeolocationService::Observe(nsISupport
       mGeolocators[i]->Shutdown();
     }
     StopDevice();
 
     return NS_OK;
   }
 
   if (!strcmp("mozsettings-changed", aTopic)) {
-    HandleMozsettingChanged(aData);
+    HandleMozsettingChanged(aSubject);
     return NS_OK;
   }
 
   if (!strcmp("timer-callback", aTopic)) {
     // decide if we can close down the service.
     for (uint32_t i = 0; i< mGeolocators.Length(); i++)
       if (mGeolocators[i]->HasActiveCallbacks()) {
         SetDisconnectTimer();
--- a/dom/geolocation/nsGeolocation.h
+++ b/dom/geolocation/nsGeolocation.h
@@ -65,17 +65,17 @@ public:
   NS_DECL_NSIOBSERVER
 
   nsGeolocationService() {
       mHigherAccuracy = false;
   }
 
   nsresult Init();
 
-  void HandleMozsettingChanged(const char16_t* aData);
+  void HandleMozsettingChanged(nsISupports* aSubject);
   void HandleMozsettingValue(const bool aValue);
 
   // Management of the Geolocation objects
   void AddLocator(mozilla::dom::Geolocation* locator);
   void RemoveLocator(mozilla::dom::Geolocation* locator);
 
   void SetCachedPosition(nsIDOMGeoPosition* aPosition);
   CachedPositionAndAccuracy GetCachedPosition();
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1995,37 +1995,37 @@ TabChild::RecvNotifyAPZStateChange(const
     nsIScrollbarMediator* scrollbarMediator = do_QueryFrame(sf);
     if (scrollbarMediator) {
       scrollbarMediator->ScrollbarActivityStarted();
     }
 
     nsCOMPtr<nsIDocument> doc = GetDocument();
     if (doc) {
       nsCOMPtr<nsIDocShell> docshell(doc->GetDocShell());
-      if (docshell) {
+      if (docshell && sf) {
         nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
-        nsdocshell->NotifyAsyncPanZoomStarted();
+        nsdocshell->NotifyAsyncPanZoomStarted(sf->GetScrollPositionCSSPixels());
       }
     }
     break;
   }
   case APZStateChange::TransformEnd:
   {
     nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aViewId);
     nsIScrollbarMediator* scrollbarMediator = do_QueryFrame(sf);
     if (scrollbarMediator) {
       scrollbarMediator->ScrollbarActivityStopped();
     }
 
     nsCOMPtr<nsIDocument> doc = GetDocument();
     if (doc) {
       nsCOMPtr<nsIDocShell> docshell(doc->GetDocShell());
-      if (docshell) {
+      if (docshell && sf) {
         nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
-        nsdocshell->NotifyAsyncPanZoomStopped();
+        nsdocshell->NotifyAsyncPanZoomStopped(sf->GetScrollPositionCSSPixels());
       }
     }
     break;
   }
   case APZStateChange::StartTouch:
   {
     mActiveElementManager->HandleTouchStart(aArg);
     break;
--- a/dom/nfc/gonk/Nfc.js
+++ b/dom/nfc/gonk/Nfc.js
@@ -183,46 +183,44 @@ XPCOMUtils.defineLazyGetter(this, "gMess
 
       target.sendAsyncMessage("NFC:PeerEvent", {
         event: event,
         sessionToken: sessionToken
       });
     },
 
     checkP2PRegistration: function checkP2PRegistration(message) {
-      // Check if the session and application id yeild a valid registered
-      // target.  It should have registered for NFC_PEER_EVENT_READY
-      let isValid = (this.nfc._currentSessionId != null) &&
-                    (this.peerTargets[message.data.appId] != null);
-
+      let target = this.peerTargets[message.data.appId];
+      let sessionToken = SessionHelper.getCurrentP2PToken();
+      let isValid = (sessionToken != null) && (target != null);
       let respMsg = { requestId: message.data.requestId };
       if (!isValid) {
         respMsg.errorMsg = this.nfc.getErrorMessage(NFC.NFC_GECKO_ERROR_P2P_REG_INVALID);
       }
       // Notify the content process immediately of the status
       message.target.sendAsyncMessage(message.name + "Response", respMsg);
     },
 
     notifyUserAcceptedP2P: function notifyUserAcceptedP2P(appId) {
       let target = this.peerTargets[appId];
-      let sessionToken = this.nfc.sessionTokenMap[this.nfc._currentSessionId];
+      let sessionToken = SessionHelper.getCurrentP2PToken();
       let isValid = (sessionToken != null) && (target != null);
       if (!isValid) {
         debug("Peer already lost or " + appId + " is not a registered PeerReadytarget");
         return;
       }
 
       // Remember the target that receives onpeerready.
       this.currentPeer = target;
       this.notifyPeerEvent(target, NFC.NFC_PEER_EVENT_READY, sessionToken);
     },
 
     onPeerLost: function onPeerLost(sessionToken) {
       if (!this.currentPeer) {
-        // not a P2P session or the target is already killed.
+        // The target is already killed.
         return;
       }
 
       // For peerlost, the message is delievered to the target which
       // onpeerready has been called before.
       this.notifyPeerEvent(this.currentPeer, NFC.NFC_PEER_EVENT_LOST, sessionToken);
       this.currentPeer = null;
     },
@@ -262,19 +260,18 @@ XPCOMUtils.defineLazyGetter(this, "gMess
         }
       } else {
         debug("Ignoring unknown message type: " + message.name);
         return null;
       }
 
       switch (message.name) {
         case "NFC:CheckSessionToken":
-          if (message.data.sessionToken !== this.nfc.sessionTokenMap[this.nfc._currentSessionId]) {
-            debug("Received invalid Session Token: " + message.data.sessionToken +
-                  ", current SessionToken: " + this.nfc.sessionTokenMap[this.nfc._currentSessionId]);
+          if (!SessionHelper.isValidToken(message.data.sessionToken)) {
+            debug("Received invalid Session Token: " + message.data.sessionToken);
             return NFC.NFC_ERROR_BAD_SESSION_ID;
           }
           return NFC.NFC_SUCCESS;
         case "NFC:RegisterPeerReadyTarget":
           this.registerPeerReadyTarget(message.target, message.data.appId);
           return null;
         case "NFC:UnregisterPeerReadyTarget":
           this.unregisterPeerReadyTarget(message.data.appId);
@@ -309,47 +306,107 @@ XPCOMUtils.defineLazyGetter(this, "gMess
         case NFC.TOPIC_XPCOM_SHUTDOWN:
           this._shutdown();
           break;
       }
     },
   };
 });
 
+let SessionHelper = {
+  tokenMap: {},
+
+  registerSession: function registerSession(id, techList) {
+    if (this.tokenMap[id]) {
+      return this.tokenMap[id].token;
+    }
+
+    this.tokenMap[id] = {
+      token: UUIDGenerator.generateUUID().toString(),
+      isP2P: techList.indexOf("P2P") != -1
+    };
+
+    return this.tokenMap[id].token;
+  },
+
+  unregisterSession: function unregisterSession(id) {
+    if (this.tokenMap[id]) {
+      delete this.tokenMap[id];
+    }
+  },
+
+  getToken: function getToken(id) {
+    return this.tokenMap[id] ? this.tokenMap[id].token : null;
+  },
+
+  getCurrentP2PToken: function getCurrentP2PToken() {
+    for (let id in this.tokenMap) {
+      if (this.tokenMap[id] && this.tokenMap[id].isP2P) {
+        return this.tokenMap[id].token;
+      }
+    }
+    return null;
+  },
+
+  getId: function getId(token) {
+    for (let id in this.tokenMap) {
+      if (this.tokenMap[id].token == token) {
+        return id;
+      }
+    }
+
+    return 0;
+  },
+
+  isP2PSession: function isP2PSession(id) {
+    return (this.tokenMap[id] != null) && this.tokenMap[id].isP2P;
+  },
+
+  isValidToken: function isValidToken(token) {
+    for (let id in this.tokenMap) {
+      if (this.tokenMap[id].token == token) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+};
+
 function Nfc() {
   debug("Starting Nfc Service");
 
   let nfcService = Cc["@mozilla.org/nfc/service;1"].getService(Ci.nsINfcService);
   if (!nfcService) {
     debug("No nfc service component available!");
     return;
   }
 
   nfcService.start(this);
   this.nfcService = nfcService;
 
   gMessageManager.init(this);
 
-  // Maps sessionId (that are generated from nfcd) with a unique guid : 'SessionToken'
-  this.sessionTokenMap = {};
   this.targetsByRequestId = {};
 }
 
 Nfc.prototype = {
 
   classID:   NFC_CID,
   classInfo: XPCOMUtils.generateCI({classID: NFC_CID,
                                     classDescription: "Nfc",
                                     interfaces: [Ci.nsINfcService]}),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsINfcEventListener]),
 
-  _currentSessionId: null,
+  powerLevel: NFC.NFC_POWER_LEVEL_UNKNOWN,
 
-  powerLevel: NFC.NFC_POWER_LEVEL_UNKNOWN,
+  nfcService: null,
+
+  targetsByRequestId: null,
 
   /**
    * Send arbitrary message to Nfc service.
    *
    * @param nfcMessageType
    *        A text message type.
    * @param message [optional]
    *        An optional message object to send.
@@ -407,44 +464,38 @@ Nfc.prototype = {
     }
 
     switch (message.type) {
       case "InitializedNotification":
         // Do nothing.
         break;
       case "TechDiscoveredNotification":
         message.type = "techDiscovered";
-        this._currentSessionId = message.sessionId;
-
-        // Check if the session token already exists. If exists, continue to use the same one.
-        // If not, generate a new token.
-        if (!this.sessionTokenMap[this._currentSessionId]) {
-          this.sessionTokenMap[this._currentSessionId] = UUIDGenerator.generateUUID().toString();
-        }
         // Update the upper layers with a session token (alias)
-        message.sessionToken = this.sessionTokenMap[this._currentSessionId];
+        message.sessionToken =
+          SessionHelper.registerSession(message.sessionId, message.techList);
         // Do not expose the actual session to the content
         delete message.sessionId;
 
         gSystemMessenger.broadcastMessage("nfc-manager-tech-discovered", message);
         break;
       case "TechLostNotification":
         message.type = "techLost";
 
         // Update the upper layers with a session token (alias)
-        message.sessionToken = this.sessionTokenMap[this._currentSessionId];
+        message.sessionToken = SessionHelper.getToken(message.sessionId);
+        if (SessionHelper.isP2PSession(message.sessionId)) {
+          gMessageManager.onPeerLost(message.sessionToken);
+        }
+
+        SessionHelper.unregisterSession(message.sessionId);
         // Do not expose the actual session to the content
         delete message.sessionId;
 
         gSystemMessenger.broadcastMessage("nfc-manager-tech-lost", message);
-        gMessageManager.onPeerLost(this.sessionTokenMap[this._currentSessionId]);
-
-        delete this.sessionTokenMap[this._currentSessionId];
-        this._currentSessionId = null;
-
         break;
      case "HCIEventTransactionNotification":
         this.notifyHCIEventTransaction(message);
         break;
      case "ConfigResponse":
         if (message.status === NFC.NFC_SUCCESS) {
           this.powerLevel = message.powerLevel;
         }
@@ -479,48 +530,40 @@ Nfc.prototype = {
      *     - SEName reflects the originating SE. It must be compliant with
      *       SIMAlliance Open Mobile APIs
      *     - AID reflects the originating UICC applet identifier
      * 3) Data - Data payload of the transaction notification, if any.
      */
     gSystemMessenger.broadcastMessage("nfc-hci-event-transaction", message);
   },
 
-  nfcService: null,
-
-  sessionTokenMap: null,
-
-  targetsByRequestId: null,
-
   /**
    * Process a message from the gMessageManager.
    */
   receiveMessage: function receiveMessage(message) {
     let isPowerAPI = message.name == "NFC:StartPoll" ||
                      message.name == "NFC:StopPoll"  ||
                      message.name == "NFC:PowerOff";
 
     if (!isPowerAPI) {
       if (this.powerLevel != NFC.NFC_POWER_LEVEL_ENABLED) {
         debug("NFC is not enabled. current powerLevel:" + this.powerLevel);
         this.sendNfcErrorResponse(message, NFC.NFC_GECKO_ERROR_NOT_ENABLED);
         return null;
       }
 
-      // Update the current sessionId before sending to the NFC service.
-      message.data.sessionId = this._currentSessionId;
-    }
+      // Sanity check on sessionToken.
+      if (!SessionHelper.isValidToken(message.data.sessionToken)) {
+        debug("Invalid Session Token: " + message.data.sessionToken);
+        this.sendNfcErrorResponse(message, NFC.NFC_ERROR_BAD_SESSION_ID);
+        return null;
+      }
 
-    // Sanity check on sessionId
-    let sessionToken = this.sessionTokenMap[this._currentSessionId];
-    if (message.data.sessionToken && (message.data.sessionToken !== sessionToken)) {
-      debug("Invalid Session Token: " + message.data.sessionToken +
-            " Expected Session Token: " + sessionToken);
-      this.sendNfcErrorResponse(message, NFC.NFC_ERROR_BAD_SESSION_ID);
-      return null;
+      // Update the current sessionId before sending to the NFC service.
+      message.data.sessionId = SessionHelper.getId(message.data.sessionToken);
     }
 
     switch (message.name) {
       case "NFC:StartPoll":
         this.setConfig({powerLevel: NFC.NFC_POWER_LEVEL_ENABLED,
                         requestId: message.data.requestId});
         break;
       case "NFC:StopPoll":
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -18,17 +18,17 @@ using mozilla::DefaultXDisplay;
 #include "gfxUtils.h"
 #include "nsIRunnable.h"
 #include "nsContentUtils.h"
 #include "nsRect.h"
 #include "nsSize.h"
 #include "nsDisplayList.h"
 #include "ImageLayers.h"
 #include "GLImages.h"
-#include "nsObjectFrame.h"
+#include "nsPluginFrame.h"
 #include "nsIPluginDocument.h"
 #include "nsIStringStream.h"
 #include "nsNetUtil.h"
 #include "mozilla/Preferences.h"
 #include "nsILinkHandler.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsLayoutUtils.h"
@@ -217,17 +217,17 @@ nsPluginInstanceOwner::GetImageContainer
   // for what we do on other versions.
   if (AndroidBridge::Bridge()->GetAPIVersion() < 11)
     return nullptr;
 
   LayoutDeviceRect r = GetPluginRect();
 
   // NotifySize() causes Flash to do a bunch of stuff like ask for surfaces to render
   // into, set y-flip flags, etc, so we do this at the beginning.
-  gfxSize resolution = mObjectFrame->PresContext()->PresShell()->GetCumulativeResolution();
+  gfxSize resolution = mPluginFrame->PresContext()->PresShell()->GetCumulativeResolution();
   ScreenSize screenSize = (r * LayoutDeviceToScreenScale(resolution.width, resolution.height)).Size();
   mInstance->NotifySize(nsIntSize(screenSize.width, screenSize.height));
 
   container = LayerManager::CreateImageContainer();
 
   // Try to get it as an EGLImage first.
   nsRefPtr<Image> img;
   AttachToContainerAsEGLImage(container, mInstance, r, &img);
@@ -317,17 +317,17 @@ nsPluginInstanceOwner::nsPluginInstanceO
   // struct and allows to manipulate native window procedure
   nsCOMPtr<nsIPluginHost> pluginHostCOM = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
   mPluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
   if (mPluginHost)
     mPluginHost->NewPluginNativeWindow(&mPluginWindow);
   else
     mPluginWindow = nullptr;
 
-  mObjectFrame = nullptr;
+  mPluginFrame = nullptr;
   mContent = nullptr;
   mWidgetCreationComplete = false;
 #ifdef XP_MACOSX
   memset(&mCGPluginPortCopy, 0, sizeof(NP_CGContext));
   mInCGPaintLevel = 0;
   mSentInitialTopLevelWindowEvent = false;
   mColorProfile = nullptr;
   mPluginPortChanged = false;
@@ -360,17 +360,17 @@ nsPluginInstanceOwner::~nsPluginInstance
 {
   if (mWaitingForPaint) {
     // We don't care when the event is dispatched as long as it's "soon",
     // since whoever needs it will be waiting for it.
     nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(mContent, true);
     NS_DispatchToMainThread(event);
   }
 
-  mObjectFrame = nullptr;
+  mPluginFrame = nullptr;
 
   PLUG_DeletePluginNativeWindow(mPluginWindow);
   mPluginWindow = nullptr;
 
 #ifdef MOZ_WIDGET_ANDROID
   RemovePluginView();
 #endif
 
@@ -538,20 +538,20 @@ NS_IMETHODIMP nsPluginInstanceOwner::Sho
 
   return rv;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const char16_t *aStatusMsg)
 {
   nsresult  rv = NS_ERROR_FAILURE;
 
-  if (!mObjectFrame) {
+  if (!mPluginFrame) {
     return rv;
   }
-  nsCOMPtr<nsIDocShellTreeItem> docShellItem = mObjectFrame->PresContext()->GetDocShell();
+  nsCOMPtr<nsIDocShellTreeItem> docShellItem = mPluginFrame->PresContext()->GetDocShell();
   if (NS_FAILED(rv) || !docShellItem) {
     return rv;
   }
 
   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
   rv = docShellItem->GetTreeOwner(getter_AddRefs(treeOwner));
   if (NS_FAILED(rv) || !treeOwner) {
     return rv;
@@ -577,25 +577,25 @@ NS_IMETHODIMP nsPluginInstanceOwner::Get
   NS_IF_ADDREF(*aDocument = mContent->OwnerDoc());
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(NPRect *invalidRect)
 {
   // If our object frame has gone away, we won't be able to determine
   // up-to-date-ness, so just fire off the event.
-  if (mWaitingForPaint && (!mObjectFrame || IsUpToDate())) {
+  if (mWaitingForPaint && (!mPluginFrame || IsUpToDate())) {
     // We don't care when the event is dispatched as long as it's "soon",
     // since whoever needs it will be waiting for it.
     nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(mContent, true);
     NS_DispatchToMainThread(event);
     mWaitingForPaint = false;
   }
 
-  if (!mObjectFrame || !invalidRect || !mWidgetVisible)
+  if (!mPluginFrame || !invalidRect || !mWidgetVisible)
     return NS_ERROR_FAILURE;
 
 #if defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID)
   // Each time an asynchronously-drawing plugin sends a new surface to display,
   // the image in the ImageContainer is updated and InvalidateRect is called.
   // There are different side effects for (sync) Android plugins.
   nsRefPtr<ImageContainer> container;
   mInstance->GetImageContainer(getter_AddRefs(container));
@@ -616,44 +616,44 @@ NS_IMETHODIMP nsPluginInstanceOwner::Inv
                  invalidRect->right - invalidRect->left,
                  invalidRect->bottom - invalidRect->top);
   // invalidRect is in "display pixels".  In non-HiDPI modes "display pixels"
   // are device pixels.  But in HiDPI modes each display pixel corresponds
   // to more than one device pixel.
   double scaleFactor = 1.0;
   GetContentsScaleFactor(&scaleFactor);
   rect.ScaleRoundOut(scaleFactor);
-  mObjectFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN, &rect);
+  mPluginFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN, &rect);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(NPRegion invalidRegion)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsPluginInstanceOwner::RedrawPlugin()
 {
-  if (mObjectFrame) {
-    mObjectFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN);
+  if (mPluginFrame) {
+    mPluginFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value)
 {
-  if (!mObjectFrame) {
+  if (!mPluginFrame) {
     NS_WARNING("plugin owner has no owner in getting doc's window handle");
     return NS_ERROR_FAILURE;
   }
 
 #if defined(XP_WIN)
   void** pvalue = (void**)value;
-  nsViewManager* vm = mObjectFrame->PresContext()->GetPresShell()->GetViewManager();
+  nsViewManager* vm = mPluginFrame->PresContext()->GetPresShell()->GetViewManager();
   if (!vm)
     return NS_ERROR_FAILURE;
 #if defined(XP_WIN)
   // This property is provided to allow a "windowless" plugin to determine the window it is drawing
   // in, so it can translate mouse coordinates it receives directly from the operating system
   // to coordinates relative to itself.
 
   // The original code (outside this #if) returns the document's window, which is OK if the window the "windowless" plugin
@@ -675,17 +675,17 @@ NS_IMETHODIMP nsPluginInstanceOwner::Get
     // unable to show a caret correctly if we return the enclosing window. Therefore for
     // now we only return the enclosing window when there is an actual offset which
     // would otherwise cause coordinates to be offset incorrectly. (i.e.
     // if the enclosing window if offset from the document window)
     //
     // fixing both the caret and ability to interact issues for a windowless control in a non document aligned windw
     // does not seem to be possible without a change to the flash plugin
 
-    nsIWidget* win = mObjectFrame->GetNearestWidget();
+    nsIWidget* win = mPluginFrame->GetNearestWidget();
     if (win) {
       nsView *view = nsView::GetViewFor(win);
       NS_ASSERTION(view, "No view for widget");
       nsPoint offset = view->GetOffsetTo(nullptr);
 
       if (offset.x || offset.y) {
         // in the case the two windows are offset from eachother, we do go ahead and return the correct enclosing window
         // so that mouse co-ordinates are not messed up.
@@ -703,17 +703,17 @@ NS_IMETHODIMP nsPluginInstanceOwner::Get
     *pvalue = (void*)widget->GetNativeData(NS_NATIVE_WINDOW);
   } else {
     NS_ASSERTION(widget, "couldn't get doc's widget in getting doc's window handle");
   }
 
   return NS_OK;
 #elif (defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)) && defined(MOZ_X11)
   // X11 window managers want the toplevel window for WM_TRANSIENT_FOR.
-  nsIWidget* win = mObjectFrame->GetNearestWidget();
+  nsIWidget* win = mPluginFrame->GetNearestWidget();
   if (!win)
     return NS_ERROR_FAILURE;
   *static_cast<Window*>(value) = (long unsigned int)win->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW);
   return NS_OK;
 #else
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif
 }
@@ -1122,18 +1122,18 @@ GetOffsetRootContent(nsIFrame* aFrame)
   offset += docOffset.ConvertAppUnits(currAPD, apd);
 
   return offset;
 }
 
 LayoutDeviceRect nsPluginInstanceOwner::GetPluginRect()
 {
   // Get the offset of the content relative to the page
-  nsRect bounds = mObjectFrame->GetContentRectRelativeToSelf() + GetOffsetRootContent(mObjectFrame);
-  LayoutDeviceIntRect rect = LayoutDeviceIntRect::FromAppUnitsToNearest(bounds, mObjectFrame->PresContext()->AppUnitsPerDevPixel());
+  nsRect bounds = mPluginFrame->GetContentRectRelativeToSelf() + GetOffsetRootContent(mPluginFrame);
+  LayoutDeviceIntRect rect = LayoutDeviceIntRect::FromAppUnitsToNearest(bounds, mPluginFrame->PresContext()->AppUnitsPerDevPixel());
   return LayoutDeviceRect(rect);
 }
 
 bool nsPluginInstanceOwner::AddPluginView(const LayoutDeviceRect& aRect /* = LayoutDeviceRect(0, 0, 0, 0) */)
 {
   if (!mJavaView) {
     mJavaView = mInstance->GetJavaSurface();
 
@@ -1345,17 +1345,17 @@ nsPluginInstanceOwner::ProcessMouseDown(
 #if !defined(XP_MACOSX)
   if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
     return aMouseEvent->PreventDefault(); // consume event
   // continue only for cases without child window
 #endif
 
   // if the plugin is windowless, we need to set focus ourselves
   // otherwise, we might not get key events
-  if (mObjectFrame && mPluginWindow &&
+  if (mPluginFrame && mPluginWindow &&
       mPluginWindow->type == NPWindowTypeDrawable) {
 
     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
     if (fm) {
       nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(mContent);
       fm->SetFocus(elem, 0);
     }
   }
@@ -1477,17 +1477,17 @@ static unsigned int XInputEventState(con
   return state;
 }
 #endif
 
 nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
 {
   nsEventStatus rv = nsEventStatus_eIgnore;
 
-  if (!mInstance || !mObjectFrame)   // if mInstance is null, we shouldn't be here
+  if (!mInstance || !mPluginFrame)   // if mInstance is null, we shouldn't be here
     return nsEventStatus_eIgnore;
 
 #ifdef XP_MACOSX
   if (!mWidget)
     return nsEventStatus_eIgnore;
 
   // we never care about synthesized mouse enter
   if (anEvent.message == NS_MOUSE_ENTER_SYNTH)
@@ -1498,37 +1498,37 @@ nsEventStatus nsPluginInstanceOwner::Pro
     return nsEventStatus_eIgnore;
 
   NPEventModel eventModel = GetEventModel();
 
   // If we have to synthesize an event we'll use one of these.
   NPCocoaEvent synthCocoaEvent;
   const NPCocoaEvent* event = static_cast<const NPCocoaEvent*>(anEvent.mPluginEvent);
   nsPoint pt =
-  nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
-  mObjectFrame->GetContentRectRelativeToSelf().TopLeft();
-  nsPresContext* presContext = mObjectFrame->PresContext();
+  nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -
+  mPluginFrame->GetContentRectRelativeToSelf().TopLeft();
+  nsPresContext* presContext = mPluginFrame->PresContext();
   // Plugin event coordinates need to be translated from device pixels
   // into "display pixels" in HiDPI modes.
   double scaleFactor = 1.0;
   GetContentsScaleFactor(&scaleFactor);
   size_t intScaleFactor = ceil(scaleFactor);
   nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x) / intScaleFactor,
                   presContext->AppUnitsToDevPixels(pt.y) / intScaleFactor);
 
   if (!event) {
     InitializeNPCocoaEvent(&synthCocoaEvent);
     switch (anEvent.message) {
       case NS_MOUSE_MOVE:
       {
         // Ignore mouse-moved events that happen as part of a dragging
         // operation that started over another frame.  See bug 525078.
-        nsRefPtr<nsFrameSelection> frameselection = mObjectFrame->GetFrameSelection();
+        nsRefPtr<nsFrameSelection> frameselection = mPluginFrame->GetFrameSelection();
         if (!frameselection->GetDragState() ||
-          (nsIPresShell::GetCapturingContent() == mObjectFrame->GetContent())) {
+          (nsIPresShell::GetCapturingContent() == mPluginFrame->GetContent())) {
           synthCocoaEvent.type = NPCocoaEventMouseMoved;
           synthCocoaEvent.data.mouse.pluginX = static_cast<double>(ptPx.x);
           synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
           event = &synthCocoaEvent;
         }
       }
         break;
       case NS_MOUSE_BUTTON_DOWN:
@@ -1537,17 +1537,17 @@ nsEventStatus nsPluginInstanceOwner::Pro
         synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
         event = &synthCocoaEvent;
         break;
       case NS_MOUSE_BUTTON_UP:
         // If we're in a dragging operation that started over another frame,
         // convert it into a mouse-entered event (in the Cocoa Event Model).
         // See bug 525078.
         if (anEvent.AsMouseEvent()->button == WidgetMouseEvent::eLeftButton &&
-            (nsIPresShell::GetCapturingContent() != mObjectFrame->GetContent())) {
+            (nsIPresShell::GetCapturingContent() != mPluginFrame->GetContent())) {
           synthCocoaEvent.type = NPCocoaEventMouseEntered;
           synthCocoaEvent.data.mouse.pluginX = static_cast<double>(ptPx.x);
           synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
           event = &synthCocoaEvent;
         } else {
           synthCocoaEvent.type = NPCocoaEventMouseUp;
           synthCocoaEvent.data.mouse.pluginX = static_cast<double>(ptPx.x);
           synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
@@ -1647,22 +1647,22 @@ nsEventStatus nsPluginInstanceOwner::Pro
       NS_ASSERTION(anEvent.message == NS_MOUSE_BUTTON_DOWN ||
                    anEvent.message == NS_MOUSE_BUTTON_UP ||
                    anEvent.message == NS_MOUSE_DOUBLECLICK ||
                    anEvent.message == NS_MOUSE_ENTER_SYNTH ||
                    anEvent.message == NS_MOUSE_EXIT_SYNTH ||
                    anEvent.message == NS_MOUSE_MOVE,
                    "Incorrect event type for coordinate translation");
       nsPoint pt =
-        nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
-        mObjectFrame->GetContentRectRelativeToSelf().TopLeft();
-      nsPresContext* presContext = mObjectFrame->PresContext();
+        nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -
+        mPluginFrame->GetContentRectRelativeToSelf().TopLeft();
+      nsPresContext* presContext = mPluginFrame->PresContext();
       nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x),
                       presContext->AppUnitsToDevPixels(pt.y));
-      nsIntPoint widgetPtPx = ptPx + mObjectFrame->GetWindowOriginInPixels(true);
+      nsIntPoint widgetPtPx = ptPx + mPluginFrame->GetWindowOriginInPixels(true);
       const_cast<NPEvent*>(pPluginEvent)->lParam = MAKELPARAM(widgetPtPx.x, widgetPtPx.y);
     }
   }
   else if (!pPluginEvent) {
     switch (anEvent.message) {
       case NS_FOCUS_CONTENT:
         pluginEvent.event = WM_SETFOCUS;
         pluginEvent.wParam = 0;
@@ -1675,17 +1675,17 @@ nsEventStatus nsPluginInstanceOwner::Pro
         pluginEvent.lParam = 0;
         pPluginEvent = &pluginEvent;
         break;
     }
   }
 
   if (pPluginEvent && !pPluginEvent->event) {
     // Don't send null events to plugins.
-    NS_WARNING("nsObjectFrame ProcessEvent: trying to send null event to plugin.");
+    NS_WARNING("nsPluginFrame ProcessEvent: trying to send null event to plugin.");
     return rv;
   }
 
   if (pPluginEvent) {
     int16_t response = kNPEventNotHandled;
     mInstance->HandleEvent(const_cast<NPEvent*>(pPluginEvent),
                            &response,
                            NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
@@ -1707,20 +1707,20 @@ nsEventStatus nsPluginInstanceOwner::Pro
           {
           case NS_MOUSE_CLICK:
           case NS_MOUSE_DOUBLECLICK:
             // Button up/down events sent instead.
             return rv;
           }
 
         // Get reference point relative to plugin origin.
-        const nsPresContext* presContext = mObjectFrame->PresContext();
+        const nsPresContext* presContext = mPluginFrame->PresContext();
         nsPoint appPoint =
-          nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
-          mObjectFrame->GetContentRectRelativeToSelf().TopLeft();
+          nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -
+          mPluginFrame->GetContentRectRelativeToSelf().TopLeft();
         nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x),
                                presContext->AppUnitsToDevPixels(appPoint.y));
         const WidgetMouseEvent& mouseEvent = *anEvent.AsMouseEvent();
         // Get reference point relative to screen:
         LayoutDeviceIntPoint rootPoint(-1, -1);
         if (widget)
           rootPoint = anEvent.refPoint +
             LayoutDeviceIntPoint::FromUntyped(widget->WidgetToScreenOffset());
@@ -1908,20 +1908,20 @@ nsEventStatus nsPluginInstanceOwner::Pro
           {
           case NS_MOUSE_CLICK:
           case NS_MOUSE_DOUBLECLICK:
             // Button up/down events sent instead.
             return rv;
           }
 
         // Get reference point relative to plugin origin.
-        const nsPresContext* presContext = mObjectFrame->PresContext();
+        const nsPresContext* presContext = mPluginFrame->PresContext();
         nsPoint appPoint =
-          nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
-          mObjectFrame->GetContentRectRelativeToSelf().TopLeft();
+          nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -
+          mPluginFrame->GetContentRectRelativeToSelf().TopLeft();
         nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x),
                                presContext->AppUnitsToDevPixels(appPoint.y));
 
         switch (anEvent.message)
           {
           case NS_MOUSE_MOVE:
             {
               // are these going to be touch events?
@@ -2040,17 +2040,17 @@ nsPluginInstanceOwner::Destroy()
   return NS_OK;
 }
 
 // Paints are handled differently, so we just simulate an update event.
 
 #ifdef XP_MACOSX
 void nsPluginInstanceOwner::Paint(const gfxRect& aDirtyRect, CGContextRef cgContext)
 {
-  if (!mInstance || !mObjectFrame)
+  if (!mInstance || !mPluginFrame)
     return;
 
   gfxRect dirtyRectCopy = aDirtyRect;
   double scaleFactor = 1.0;
   GetContentsScaleFactor(&scaleFactor);
   if (scaleFactor != 1.0) {
     ::CGContextScaleCTM(cgContext, scaleFactor, scaleFactor);
     // Convert aDirtyRect from device pixels to "display pixels"
@@ -2062,17 +2062,17 @@ void nsPluginInstanceOwner::Paint(const 
   if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
     DoCocoaEventDrawRect(dirtyRectCopy, cgContext);
     pluginWidget->EndDrawPlugin();
   }
 }
 
 void nsPluginInstanceOwner::DoCocoaEventDrawRect(const gfxRect& aDrawRect, CGContextRef cgContext)
 {
-  if (!mInstance || !mObjectFrame)
+  if (!mInstance || !mPluginFrame)
     return;
 
   // The context given here is only valid during the HandleEvent call.
   NPCocoaEvent updateEvent;
   InitializeNPCocoaEvent(&updateEvent);
   updateEvent.type = NPCocoaEventDrawRect;
   updateEvent.data.draw.context = cgContext;
   updateEvent.data.draw.x = aDrawRect.X();
@@ -2082,34 +2082,34 @@ void nsPluginInstanceOwner::DoCocoaEvent
 
   mInstance->HandleEvent(&updateEvent, nullptr);
 }
 #endif
 
 #ifdef XP_WIN
 void nsPluginInstanceOwner::Paint(const RECT& aDirty, HDC aDC)
 {
-  if (!mInstance || !mObjectFrame)
+  if (!mInstance || !mPluginFrame)
     return;
 
   NPEvent pluginEvent;
   pluginEvent.event = WM_PAINT;
   pluginEvent.wParam = WPARAM(aDC);
   pluginEvent.lParam = LPARAM(&aDirty);
   mInstance->HandleEvent(&pluginEvent, nullptr);
 }
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
 
 void nsPluginInstanceOwner::Paint(gfxContext* aContext,
                                   const gfxRect& aFrameRect,
                                   const gfxRect& aDirtyRect)
 {
-  if (!mInstance || !mObjectFrame || !mPluginDocumentActiveState || mFullScreen)
+  if (!mInstance || !mPluginFrame || !mPluginDocumentActiveState || mFullScreen)
     return;
 
   int32_t model = mInstance->GetANPDrawingModel();
 
   if (model == kSurface_ANPDrawingModel) {
     if (!AddPluginView(GetPluginRect())) {
       Invalidate();
     }
@@ -2164,17 +2164,17 @@ void nsPluginInstanceOwner::Paint(gfxCon
 }
 #endif
 
 #if defined(MOZ_X11)
 void nsPluginInstanceOwner::Paint(gfxContext* aContext,
                                   const gfxRect& aFrameRect,
                                   const gfxRect& aDirtyRect)
 {
-  if (!mInstance || !mObjectFrame)
+  if (!mInstance || !mPluginFrame)
     return;
 
   // to provide crisper and faster drawing.
   gfxRect pluginRect = aFrameRect;
   if (aContext->UserToDevicePixelSnapped(pluginRect)) {
     pluginRect = aContext->DeviceToUser(pluginRect);
   }
 
@@ -2367,17 +2367,17 @@ nsresult nsPluginInstanceOwner::Init(nsI
   mLastEventloopNestingLevel = GetEventloopNestingLevel();
 
   mContent = aContent;
 
   // Get a frame, don't reflow. If a reflow was necessary it should have been
   // done at a higher level than this (content).
   nsIFrame* frame = aContent->GetPrimaryFrame();
   nsIObjectFrame* iObjFrame = do_QueryFrame(frame);
-  nsObjectFrame* objFrame =  static_cast<nsObjectFrame*>(iObjFrame);
+  nsPluginFrame* objFrame =  static_cast<nsPluginFrame*>(iObjFrame);
   if (objFrame) {
     SetFrame(objFrame);
     // Some plugins require a specific sequence of shutdown and startup when
     // a page is reloaded. Shutdown happens usually when the last instance
     // is destroyed. Here we make sure the plugin instance in the old
     // document is destroyed before we try to create the new one.
     objFrame->PresContext()->EnsureVisible();
   } else {
@@ -2519,19 +2519,19 @@ NS_IMETHODIMP nsPluginInstanceOwner::Cre
     pluginWidget->SetPluginDrawingModel(GetDrawingModel());
 
     if (GetDrawingModel() == NPDrawingModelCoreAnimation) {
       AddToCARefreshTimer();
     }
 #endif
   }
 
-  if (mObjectFrame) {
+  if (mPluginFrame) {
     // nullptr widget is fine, will result in windowless setup.
-    mObjectFrame->PrepForDrawing(mWidget);
+    mPluginFrame->PrepForDrawing(mWidget);
   }
 
   if (windowless) {
     mPluginWindow->type = NPWindowTypeDrawable;
 
     // this needs to be a HDC according to the spec, but I do
     // not see the right way to release it so let's postpone
     // passing HDC till paint event when it is really
@@ -2568,31 +2568,31 @@ NS_IMETHODIMP nsPluginInstanceOwner::Cre
   return NS_OK;
 }
 
 // Mac specific code to fix up the port location and clipping region
 #ifdef XP_MACOSX
 
 void* nsPluginInstanceOwner::FixUpPluginWindow(int32_t inPaintState)
 {
-  if (!mWidget || !mPluginWindow || !mInstance || !mObjectFrame)
+  if (!mWidget || !mPluginWindow || !mInstance || !mPluginFrame)
     return nullptr;
 
   nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
   if (!pluginWidget)
     return nullptr;
 
-  // If we've already set up a CGContext in nsObjectFrame::PaintPlugin(), we
+  // If we've already set up a CGContext in nsPluginFrame::PaintPlugin(), we
   // don't want calls to SetPluginPortAndDetectChange() to step on our work.
   if (mInCGPaintLevel < 1) {
     SetPluginPortAndDetectChange();
   }
 
   // We'll need the top-level Cocoa window for the Cocoa event model.
-  nsIWidget* widget = mObjectFrame->GetNearestWidget();
+  nsIWidget* widget = mPluginFrame->GetNearestWidget();
   if (!widget)
     return nullptr;
   void *cocoaTopLevelWindow = widget->GetNativeData(NS_NATIVE_WINDOW);
   // We don't expect to have a top level window in a content process
   if (!cocoaTopLevelWindow && XRE_GetProcessType() == GeckoProcessType_Default) {
     return nullptr;
   }
 
@@ -2717,17 +2717,17 @@ void nsPluginInstanceOwner::UpdateWindow
   // passed to the plugin during paint, an additional update
   // of the the clip rectangle here is not required
   if (aSetWindow && !mWidget && mPluginWindowVisible && !UseAsyncRendering())
     return;
 
   const NPWindow oldWindow = *mPluginWindow;
 
   bool windowless = (mPluginWindow->type == NPWindowTypeDrawable);
-  nsIntPoint origin = mObjectFrame->GetWindowOriginInPixels(windowless);
+  nsIntPoint origin = mPluginFrame->GetWindowOriginInPixels(windowless);
 
   mPluginWindow->x = origin.x;
   mPluginWindow->y = origin.y;
 
   mPluginWindow->clipRect.left = 0;
   mPluginWindow->clipRect.top = 0;
 
   if (mPluginWindowVisible && mPluginDocumentActiveState) {
@@ -2781,18 +2781,18 @@ nsPluginInstanceOwner::UpdateDocumentAct
   }
 #endif
 }
 #endif // XP_MACOSX
 
 NS_IMETHODIMP
 nsPluginInstanceOwner::CallSetWindow()
 {
-  if (mObjectFrame) {
-    mObjectFrame->CallSetWindow(false);
+  if (mPluginFrame) {
+    mPluginFrame->CallSetWindow(false);
   } else if (mInstance) {
     if (UseAsyncRendering()) {
       mInstance->AsyncSetWindow(mPluginWindow);
     } else {
       mInstance->SetWindow(mPluginWindow);
     }
   }
 
@@ -2813,54 +2813,54 @@ nsPluginInstanceOwner::GetContentsScaleF
     scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
       presShell->GetPresContext()->DeviceContext()->UnscaledAppUnitsPerDevPixel();
   }
 #endif
   *result = scaleFactor;
   return NS_OK;
 }
 
-void nsPluginInstanceOwner::SetFrame(nsObjectFrame *aFrame)
+void nsPluginInstanceOwner::SetFrame(nsPluginFrame *aFrame)
 {
   // Don't do anything if the frame situation hasn't changed.
-  if (mObjectFrame == aFrame) {
+  if (mPluginFrame == aFrame) {
     return;
   }
 
   // If we already have a frame that is changing or going away...
-  if (mObjectFrame) {
+  if (mPluginFrame) {
     // Make sure the old frame isn't holding a reference to us.
-    mObjectFrame->SetInstanceOwner(nullptr);
+    mPluginFrame->SetInstanceOwner(nullptr);
   }
 
   // Swap in the new frame (or no frame)
-  mObjectFrame = aFrame;
+  mPluginFrame = aFrame;
 
   // Set up a new frame
-  if (mObjectFrame) {
-    mObjectFrame->SetInstanceOwner(this);
+  if (mPluginFrame) {
+    mPluginFrame->SetInstanceOwner(this);
     // Can only call PrepForDrawing on an object frame once. Don't do it here unless
     // widget creation is complete. Doesn't matter if we actually have a widget.
     if (mWidgetCreationComplete) {
-      mObjectFrame->PrepForDrawing(mWidget);
+      mPluginFrame->PrepForDrawing(mWidget);
     }
-    mObjectFrame->FixupWindow(mObjectFrame->GetContentRectRelativeToSelf().Size());
-    mObjectFrame->InvalidateFrame();
+    mPluginFrame->FixupWindow(mPluginFrame->GetContentRectRelativeToSelf().Size());
+    mPluginFrame->InvalidateFrame();
 
     nsFocusManager* fm = nsFocusManager::GetFocusManager();
     const nsIContent* content = aFrame->GetContent();
     if (fm && content) {
       mContentFocused = (content == fm->GetFocusedContent());
     }
   }
 }
 
-nsObjectFrame* nsPluginInstanceOwner::GetFrame()
+nsPluginFrame* nsPluginInstanceOwner::GetFrame()
 {
-  return mObjectFrame;
+  return mPluginFrame;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::PrivateModeChanged(bool aEnabled)
 {
   return mInstance ? mInstance->PrivateModeStateChanged(aEnabled) : NS_OK;
 }
 
 already_AddRefed<nsIURI> nsPluginInstanceOwner::GetBaseURI() const
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -21,17 +21,17 @@
 #ifdef XP_MACOSX
 #include "mozilla/gfx/QuartzSupport.h"
 #include <ApplicationServices/ApplicationServices.h>
 #endif
 
 class nsIInputStream;
 struct nsIntRect;
 class nsPluginDOMContextMenuListener;
-class nsObjectFrame;
+class nsPluginFrame;
 class nsDisplayListBuilder;
 
 namespace mozilla {
 namespace dom {
 struct MozPluginParameter;
 }
 }
 
@@ -138,30 +138,30 @@ public:
   // store a copy of plugin port info and to detect when it's been changed.
   void* GetPluginPortCopy();
   // Set plugin port info in the plugin (in the 'window' member of the
   // NPWindow structure passed to the plugin by SetWindow()) and set a
   // flag (mPluginPortChanged) to indicate whether or not this info has
   // changed, and SetWindow() needs to be called again.
   void* SetPluginPortAndDetectChange();
   // Flag when we've set up a Thebes (and CoreGraphics) context in
-  // nsObjectFrame::PaintPlugin().  We need to know this in
+  // nsPluginFrame::PaintPlugin().  We need to know this in
   // FixUpPluginWindow() (i.e. we need to know when FixUpPluginWindow() has
-  // been called from nsObjectFrame::PaintPlugin() when we're using the
+  // been called from nsPluginFrame::PaintPlugin() when we're using the
   // CoreGraphics drawing model).
   void BeginCGPaint();
   void EndCGPaint();
 #else // XP_MACOSX
   void UpdateWindowPositionAndClipRect(bool aSetWindow);
   void UpdateWindowVisibility(bool aVisible);
   void UpdateDocumentActiveState(bool aIsActive);
 #endif // XP_MACOSX
 
-  void SetFrame(nsObjectFrame *aFrame);
-  nsObjectFrame* GetFrame();
+  void SetFrame(nsPluginFrame *aFrame);
+  nsPluginFrame* GetFrame();
 
   uint32_t GetLastEventloopNestingLevel() const {
     return mLastEventloopNestingLevel; 
   }
   
   static uint32_t GetEventloopNestingLevel();
   
   void ConsiderNewEventloopNestingLevel() {
@@ -271,17 +271,17 @@ private:
   void RemovePluginView();
 
   bool mFullScreen;
   void* mJavaView;
 #endif 
  
   nsPluginNativeWindow       *mPluginWindow;
   nsRefPtr<nsNPAPIPluginInstance> mInstance;
-  nsObjectFrame              *mObjectFrame;
+  nsPluginFrame              *mPluginFrame;
   nsIContent                 *mContent; // WEAK, content owns us
   nsCString                   mDocumentBase;
   bool                        mWidgetCreationComplete;
   nsCOMPtr<nsIWidget>         mWidget;
   nsRefPtr<nsPluginHost>      mPluginHost;
   
 #ifdef XP_MACOSX
   NP_CGContext                              mCGPluginPortCopy;
--- a/dom/plugins/base/nsPluginNativeWindowGtk.cpp
+++ b/dom/plugins/base/nsPluginNativeWindowGtk.cpp
@@ -140,17 +140,17 @@ nsresult nsPluginNativeWindowGtk::CallSe
       }
 
       if (!mSocketWidget) {
         return NS_ERROR_FAILURE;
       }
 
       // Make sure to resize and re-place the window if required.
       SetAllocation();
-      // Need to reset "window" each time as nsObjectFrame::DidReflow sets it
+      // Need to reset "window" each time as nsPluginFrame::DidReflow sets it
       // to the ancestor window.
 #if (MOZ_WIDGET_GTK == 2)
       if (GTK_IS_XTBIN(mSocketWidget)) {
         // Point the NPWindow structures window to the actual X window
         SetWindow(GTK_XTBIN(mSocketWidget)->xtwindow);
       }
       else { // XEmbed or OOP&Xt
         SetWindow(gtk_socket_get_id(GTK_SOCKET(mSocketWidget)));
@@ -220,17 +220,17 @@ nsresult nsPluginNativeWindowGtk::Create
   SetAllocation();
 
   gtk_widget_show(mSocketWidget);
 
   gdk_flush();
   SetWindow(gtk_socket_get_id(GTK_SOCKET(mSocketWidget)));
 
   // Fill out the ws_info structure.
-  // (The windowless case is done in nsObjectFrame.cpp.)
+  // (The windowless case is done in nsPluginFrame.cpp.)
   GdkWindow *gdkWindow = gdk_x11_window_lookup_for_display(display, GetWindow());
   if(!gdkWindow)
     return NS_ERROR_FAILURE;
 
   mWsInfo.display = GDK_WINDOW_XDISPLAY(gdkWindow);
 #if (MOZ_WIDGET_GTK == 2)
   mWsInfo.colormap = GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(gdkWindow));
   GdkVisual* gdkVisual = gdk_drawable_get_visual(gdkWindow);
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -1943,17 +1943,17 @@ PluginInstanceChild::SharedSurfacePaint(
         case RENDER_NATIVE:
             // pass the internal hdc to the plugin
             UpdatePaintClipRect(pRect);
             evcopy.wParam = WPARAM(mSharedSurfaceDib.GetHDC());
             return mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy));
         break;
         case RENDER_BACK_ONE:
               // Handle a double pass render used in alpha extraction for transparent
-              // plugins. (See nsObjectFrame and gfxWindowsNativeDrawing for details.)
+              // plugins. (See nsPluginFrame and gfxWindowsNativeDrawing for details.)
               // We render twice, once to the shared dib, and once to a cache which
               // we copy back on a second paint. These paints can't be spread across
               // multiple rpc messages as delays cause animation frame changes.
               if (!mAlphaExtract.bmp && !AlphaExtractCacheSetup()) {
                   mAlphaExtract.doublePass = RENDER_NATIVE;
                   return false;
               }
 
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -362,17 +362,17 @@ PluginInstanceParent::AnswerNPN_SetValue
     const int& drawingModel, OptionalShmem *shmem, CrossProcessMutexHandle *mutex, NPError* result)
 {
     *shmem = null_t();
 
 #ifdef XP_MACOSX
     if (drawingModel == NPDrawingModelCoreAnimation ||
         drawingModel == NPDrawingModelInvalidatingCoreAnimation) {
         // We need to request CoreGraphics otherwise
-        // the nsObjectFrame will try to draw a CALayer
+        // the nsPluginFrame will try to draw a CALayer
         // that can not be shared across process.
         mDrawingModel = drawingModel;
         *result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
                                   (void*)NPDrawingModelCoreGraphics);
     } else
 #endif
     if (drawingModel == NPDrawingModelAsyncBitmapSurface
 #ifdef XP_WIN
@@ -1226,17 +1226,17 @@ PluginInstanceParent::NPP_HandleEvent(vo
                   !wcscmp(szClass, kFlashFullscreenClass)) {
                   return 0;
               }
             }
             break;
 
             case WM_WINDOWPOSCHANGED:
             {
-                // We send this in nsObjectFrame just before painting
+                // We send this in nsPluginFrame just before painting
                 return SendWindowPosChanged(npremoteevent);
             }
             break;
         }
     }
 #endif
 
 #if defined(MOZ_X11)
--- a/dom/plugins/test/testplugin/nptest_macosx.mm
+++ b/dom/plugins/test/testplugin/nptest_macosx.mm
@@ -95,17 +95,17 @@ RectEquals(const NPRect& r1, const NPRec
          r1.right == r2.right && r1.bottom == r2.bottom;
 }
 
 void
 pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow)
 {
   // Ugh. Due to a terrible Gecko bug, we have to ignore position changes
   // when the clip rect doesn't change; the position can be wrong
-  // when set by a path other than nsObjectFrame::FixUpPluginWindow.
+  // when set by a path other than nsPluginFrame::FixUpPluginWindow.
   int32_t oldX = instanceData->window.x;
   int32_t oldY = instanceData->window.y;
   bool clipChanged =
     !RectEquals(instanceData->window.clipRect, newWindow->clipRect);
   instanceData->window = *newWindow;
   if (!clipChanged) {
     instanceData->window.x = oldX;
     instanceData->window.y = oldY;
--- a/dom/settings/SettingsRequestManager.jsm
+++ b/dom/settings/SettingsRequestManager.jsm
@@ -661,22 +661,23 @@ let SettingsRequestManager = {
         if (DEBUG) debug("Wrong observer topic: " + aTopic);
         break;
     }
   },
 
   sendSettingsChange: function(aKey, aValue, aIsServiceLock) {
     this.broadcastMessage("Settings:Change:Return:OK",
       { key: aKey, value: aValue });
-    Services.obs.notifyObservers(this, kMozSettingsChangedObserverTopic,
-      JSON.stringify({
-        key: aKey,
-        value: aValue,
-        isInternalChange: aIsServiceLock
-      }));
+    var setting = {
+      key: aKey,
+      value: aValue,
+      isInternalChange: aIsServiceLock
+    };
+    setting.wrappedJSObject = setting;
+    Services.obs.notifyObservers(setting, kMozSettingsChangedObserverTopic, "");
   },
 
   broadcastMessage: function broadcastMessage(aMsgName, aContent) {
     if (DEBUG) debug("Broadcast");
     this.children.forEach(function(msgMgr) {
       let principal = this.mmPrincipals.get(msgMgr);
       if (!principal) {
         if (DEBUG) debug("Cannot find principal for message manager to check permissions");
--- a/dom/system/NetworkGeolocationProvider.js
+++ b/dom/system/NetworkGeolocationProvider.js
@@ -259,21 +259,23 @@ WifiGeoPositionProvider.prototype = {
   listener: null,
 
   observe: function(aSubject, aTopic, aData) {
     if (aTopic != SETTINGS_CHANGED_TOPIC) {
       return;
     }
 
     try {
-      let setting = JSON.parse(aData);
-      if (setting.key == SETTINGS_DEBUG_ENABLED) {
-        gLoggingEnabled = setting.value;
-      } else if (setting.key == SETTINGS_WIFI_ENABLED) {
-        gWifiScanningEnabled = setting.value;
+      if ("wrappedJSObject" in aSubject) {
+        aSubject = aSubject.wrappedJSObject;
+      }
+      if (aSubject.key == SETTINGS_DEBUG_ENABLED) {
+        gLoggingEnabled = aSubject.value;
+      } else if (aSubject.key == SETTINGS_WIFI_ENABLED) {
+        gWifiScanningEnabled = aSubject.value;
       }
     } catch (e) {
     }
   },
 
   resetTimer: function() {
     if (this.timer) {
       this.timer.cancel();
--- a/dom/system/gonk/AudioManager.cpp
+++ b/dom/system/gonk/AudioManager.cpp
@@ -36,16 +36,18 @@
 #include "BluetoothCommon.h"
 #include "BluetoothHfpManagerBase.h"
 
 #include "nsJSUtils.h"
 #include "nsThreadUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsXULAppAPI.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 using namespace mozilla::dom::gonk;
 using namespace android;
 using namespace mozilla::hal;
 using namespace mozilla;
 using namespace mozilla::dom::bluetooth;
 
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "AudioManager" , ## args)
@@ -345,46 +347,31 @@ AudioManager::Observe(nsISupports* aSubj
   else if (!strcmp(aTopic, AUDIO_CHANNEL_PROCESS_CHANGED)) {
     HandleAudioChannelProcessChanged();
     return NS_OK;
   }
 
   // To process the volume control on each audio channel according to
   // change of settings
   else if (!strcmp(aTopic, MOZ_SETTINGS_CHANGE_ID)) {
-    AutoSafeJSContext cx;
-    nsDependentString dataStr(aData);
-    JS::Rooted<JS::Value> val(cx);
-    if (!JS_ParseJSON(cx, dataStr.get(), dataStr.Length(), &val) ||
-        !val.isObject()) {
+    AutoJSAPI jsapi;
+    jsapi.Init();
+    JSContext* cx = jsapi.cx();
+    RootedDictionary<dom::SettingChangeNotification> setting(cx);
+    if (!WrappedJSToDictionary(cx, aSubject, setting)) {
       return NS_OK;
     }
-
-    JS::Rooted<JSObject*> obj(cx, &val.toObject());
-    JS::Rooted<JS::Value> key(cx);
-    if (!JS_GetProperty(cx, obj, "key", &key) ||
-        !key.isString()) {
+    if (!setting.mKey.EqualsASCII("audio.volume.bt_sco")) {
+      return NS_OK;
+    }
+    if (!setting.mValue.isNumber()) {
       return NS_OK;
     }
 
-    JS::Rooted<JSString*> jsKey(cx, JS::ToString(cx, key));
-    if (!jsKey) {
-      return NS_OK;
-    }
-    nsAutoJSString keyStr;
-    if (!keyStr.init(cx, jsKey) || !keyStr.EqualsLiteral("audio.volume.bt_sco")) {
-      return NS_OK;
-    }
-
-    JS::Rooted<JS::Value> value(cx);
-    if (!JS_GetProperty(cx, obj, "value", &value) || !value.isInt32()) {
-      return NS_OK;
-    }
-
-    int32_t index = value.toInt32();
+    int32_t index = setting.mValue.toNumber();
     SetStreamVolumeIndex(AUDIO_STREAM_BLUETOOTH_SCO, index);
 
     return NS_OK;
   }
 
   NS_WARNING("Unexpected topic in AudioManager");
   return NS_ERROR_FAILURE;
 }
--- a/dom/system/gonk/AutoMounterSetting.cpp
+++ b/dom/system/gonk/AutoMounterSetting.cpp
@@ -15,27 +15,31 @@
 #include "nsJSUtils.h"
 #include "nsPrintfCString.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsThreadUtils.h"
 #include "xpcpublic.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #undef LOG
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "AutoMounterSetting" , ## args)
 #define ERR(args...)  __android_log_print(ANDROID_LOG_ERROR, "AutoMounterSetting" , ## args)
 
 #define UMS_MODE                  "ums.mode"
 #define UMS_STATUS                "ums.status"
 #define UMS_VOLUME_ENABLED_PREFIX "ums.volume."
 #define UMS_VOLUME_ENABLED_SUFFIX ".enabled"
 #define MOZSETTINGS_CHANGED       "mozsettings-changed"
 
+using namespace mozilla::dom;
+
 namespace mozilla {
 namespace system {
 
 class SettingsServiceCallback MOZ_FINAL : public nsISettingsServiceCallback
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
@@ -230,62 +234,45 @@ AutoMounterSetting::Observe(nsISupports*
   }
 
   // Note that this function gets called for any and all settings changes,
   // so we need to carefully check if we have the one we're interested in.
   //
   // The string that we're interested in will be a JSON string that looks like:
   //  {"key":"ums.autoMount","value":true}
 
-  mozilla::AutoSafeJSContext cx;
-  nsDependentString dataStr(aData);
-  JS::Rooted<JS::Value> val(cx);
-  if (!JS_ParseJSON(cx, dataStr.get(), dataStr.Length(), &val) ||
-      !val.isObject()) {
-    return NS_OK;
-  }
-  JS::Rooted<JSObject*> obj(cx, &val.toObject());
-  JS::Rooted<JS::Value> key(cx);
-  if (!JS_GetProperty(cx, obj, "key", &key) ||
-      !key.isString()) {
-    return NS_OK;
-  }
-
-  JSString *jsKey = JS::ToString(cx, key);
-  nsAutoJSString keyStr;
-  if (!keyStr.init(cx, jsKey)) {
-    return NS_OK;
-  }
-
-  JS::Rooted<JS::Value> value(cx);
-  if (!JS_GetProperty(cx, obj, "value", &value)) {
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
+  RootedDictionary<SettingChangeNotification> setting(cx);
+  if (!WrappedJSToDictionary(cx, aSubject, setting)) {
     return NS_OK;
   }
 
   // Check for ums.mode changes
-  if (keyStr.EqualsLiteral(UMS_MODE)) {
-    if (!value.isInt32()) {
+  if (setting.mKey.EqualsASCII(UMS_MODE)) {
+    if (!setting.mValue.isInt32()) {
       return NS_OK;
     }
-    int32_t mode = value.toInt32();
+    int32_t mode = setting.mValue.toInt32();
     SetAutoMounterMode(mode);
     return NS_OK;
   }
 
   // Check for ums.volume.NAME.enabled
-  if (StringBeginsWith(keyStr, NS_LITERAL_STRING(UMS_VOLUME_ENABLED_PREFIX)) &&
-      StringEndsWith(keyStr, NS_LITERAL_STRING(UMS_VOLUME_ENABLED_SUFFIX))) {
-    if (!value.isBoolean()) {
+  if (StringBeginsWith(setting.mKey, NS_LITERAL_STRING(UMS_VOLUME_ENABLED_PREFIX)) &&
+      StringEndsWith(setting.mKey, NS_LITERAL_STRING(UMS_VOLUME_ENABLED_SUFFIX))) {
+    if (!setting.mValue.isBoolean()) {
       return NS_OK;
     }
     const size_t prefixLen = sizeof(UMS_VOLUME_ENABLED_PREFIX) - 1;
     const size_t suffixLen = sizeof(UMS_VOLUME_ENABLED_SUFFIX) - 1;
     nsDependentSubstring volumeName =
-      Substring(keyStr, prefixLen, keyStr.Length() - prefixLen - suffixLen);
-    bool isSharingEnabled = value.toBoolean();
+      Substring(setting.mKey, prefixLen, setting.mKey.Length() - prefixLen - suffixLen);
+    bool isSharingEnabled = setting.mValue.toBoolean();
     SetAutoMounterSharingMode(NS_LossyConvertUTF16toASCII(volumeName), isSharingEnabled);
     return NS_OK;
   }
 
   return NS_OK;
 }
 
 }   // namespace system
--- a/dom/system/gonk/NetworkManager.js
+++ b/dom/system/gonk/NetworkManager.js
@@ -215,18 +215,20 @@ NetworkManager.prototype = {
                                          Ci.nsIObserver,
                                          Ci.nsISettingsServiceCallback]),
 
   // nsIObserver
 
   observe: function(subject, topic, data) {
     switch (topic) {
       case TOPIC_MOZSETTINGS_CHANGED:
-        let setting = JSON.parse(data);
-        this.handle(setting.key, setting.value);
+        if ("wrappedJSObject" in subject) {
+          subject = subject.wrappedJSObject;
+        }
+        this.handle(subject.key, subject.value);
         break;
       case TOPIC_PREF_CHANGED:
         this._manageOfflineStatus =
           Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS);
         debug(PREF_MANAGE_OFFLINE_STATUS + " has changed to " + this._manageOfflineStatus);
         break;
       case TOPIC_XPCOM_SHUTDOWN:
         Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN);
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -955,18 +955,20 @@ XPCOMUtils.defineLazyGetter(this, "gData
     },
 
     /**
      * nsIObserver interface methods.
      */
     observe: function(subject, topic, data) {
       switch (topic) {
         case kMozSettingsChangedObserverTopic:
-          let setting = JSON.parse(data);
-          this.handle(setting.key, setting.value);
+          if ("wrappedJSObject" in subject) {
+            subject = subject.wrappedJSObject;
+          }
+          this.handle(subject.key, subject.value);
           break;
         case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
           this._shutdown();
           break;
       }
     },
   };
 });
@@ -3047,18 +3049,20 @@ RadioInterface.prototype = {
     gMessageManager.sendIccMessage("RIL:StkCommand", this.clientId, message);
   },
 
   // nsIObserver
 
   observe: function(subject, topic, data) {
     switch (topic) {
       case kMozSettingsChangedObserverTopic:
-        let setting = JSON.parse(data);
-        this.handleSettingsChange(setting.key, setting.value, setting.isInternalChange);
+        if ("wrappedJSObject" in subject) {
+          subject = subject.wrappedJSObject;
+        }
+        this.handleSettingsChange(subject.key, subject.value, subject.isInternalChange);
         break;
       case kSysClockChangeObserverTopic:
         let offset = parseInt(data, 10);
         if (this._lastNitzMessage) {
           this._lastNitzMessage.receiveTimeInMS += offset;
         }
         this._sntp.updateOffset(offset);
         break;
--- a/dom/system/gonk/TimeZoneSettingObserver.cpp
+++ b/dom/system/gonk/TimeZoneSettingObserver.cpp
@@ -17,25 +17,28 @@
 #include "nsISettingsService.h"
 #include "nsJSUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "TimeZoneSettingObserver.h"
 #include "xpcpublic.h"
 #include "nsContentUtils.h"
 #include "nsPrintfCString.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #undef LOG
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Time Zone Setting" , ## args)
 #define ERR(args...)  __android_log_print(ANDROID_LOG_ERROR, "Time Zone Setting" , ## args)
 
 #define TIME_TIMEZONE       "time.timezone"
 #define MOZSETTINGS_CHANGED "mozsettings-changed"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 namespace {
 
 class TimeZoneSettingObserver : public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
@@ -179,62 +182,44 @@ TimeZoneSettingObserver::~TimeZoneSettin
     observerService->RemoveObserver(this, MOZSETTINGS_CHANGED);
   }
 }
 
 NS_IMPL_ISUPPORTS(TimeZoneSettingObserver, nsIObserver)
 
 NS_IMETHODIMP
 TimeZoneSettingObserver::Observe(nsISupports *aSubject,
-                     const char *aTopic,
-                     const char16_t *aData)
+                                 const char *aTopic,
+                                 const char16_t *aData)
 {
   if (strcmp(aTopic, MOZSETTINGS_CHANGED) != 0) {
     return NS_OK;
   }
 
   // Note that this function gets called for any and all settings changes,
   // so we need to carefully check if we have the one we're interested in.
   //
   // The string that we're interested in will be a JSON string that looks like:
   // {"key":"time.timezone","value":"America/Chicago"} or
   // {"key":"time.timezone","value":"UTC-05:00"}
 
   AutoSafeJSContext cx;
-
-  // Parse the JSON value.
-  nsDependentString dataStr(aData);
-  JS::Rooted<JS::Value> val(cx);
-  if (!JS_ParseJSON(cx, dataStr.get(), dataStr.Length(), &val) ||
-      !val.isObject()) {
+  RootedDictionary<SettingChangeNotification> setting(cx);
+  if (!WrappedJSToDictionary(cx, aSubject, setting)) {
     return NS_OK;
   }
-
-  // Get the key, which should be the JS string "time.timezone".
-  JS::Rooted<JSObject*> obj(cx, &val.toObject());
-  JS::Rooted<JS::Value> key(cx);
-  if (!JS_GetProperty(cx, obj, "key", &key) ||
-      !key.isString()) {
+  if (!setting.mKey.EqualsASCII(TIME_TIMEZONE)) {
     return NS_OK;
   }
-  bool match;
-  if (!JS_StringEqualsAscii(cx, key.toString(), TIME_TIMEZONE, &match) ||
-      !match) {
-    return NS_OK;
-  }
-
-  // Get the value, which should be a JS string like "America/Chicago".
-  JS::Rooted<JS::Value> value(cx);
-  if (!JS_GetProperty(cx, obj, "value", &value) ||
-      !value.isString()) {
+  if (!setting.mValue.isString()) {
     return NS_OK;
   }
 
   // Set the system timezone.
-  return SetTimeZone(value, cx);
+  return SetTimeZone(setting.mValue, cx);
 }
 
 } // anonymous namespace
 
 static mozilla::StaticRefPtr<TimeZoneSettingObserver> sTimeZoneSettingObserver;
 namespace mozilla {
 namespace system {
 void
--- a/dom/tests/mochitest/general/mochitest.ini
+++ b/dom/tests/mochitest/general/mochitest.ini
@@ -27,16 +27,17 @@ support-files =
   res5.resource
   res5.resource^headers^
   res6.resource
   res6.resource^headers^
   res7.resource
   res7.resource^headers^
   res8.resource
   res8.resource^headers^
+  resource_timing.js
 
 [test_497898.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || toolkit == 'android' #Bug 931116, b2g desktop specific, initial triage
 [test_bug504220.html]
 [test_bug628069_1.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug628069_2.html]
 [test_bug631440.html]
new file mode 100644
--- a/dom/tests/mochitest/general/resource_timing_cross_origin.html
+++ b/dom/tests/mochitest/general/resource_timing_cross_origin.html
@@ -81,16 +81,20 @@ function firstCheck() {
   entries = window.performance.getEntriesByName("http://test1.example.com/tests/dom/tests/mochitest/general/res7.resource");
   ok(!!entries[0], "cross origin res7.resource is missing from entries");
   checkCrossOrigin(entries[0]);
 
   entries = window.performance.getEntriesByName("http://test1.example.com/tests/dom/tests/mochitest/general/res8.resource");
   ok(!!entries[0], "redirected res8.resource is missing from entries");
   checkRedirectCrossOriginResourceSameOrigin(entries[0]);
 
+  entries = window.performance.getEntriesByName("http://mochi.test:8888/tests/dom/tests/mochitest/general/resource_timing.js");
+  ok(!!entries[0], "same origin resource_timing.js is missing from entries");
+  checkSameOrigin(entries[0]);
+
   is(bufferFullCounter, expectedBufferFullEvents, "Buffer full was called");
   finishTests();
 }
 
 function checkEntry(entry, checks) {
   // If the entry is undefined, we return early so we don't get a JS error
   if (entry == undefined)
     return;
@@ -171,12 +175,13 @@ function finishTests() {
     <object data="http://test1.example.com/tests/dom/tests/mochitest/general/res1.resource"> <!-- cross origin, Timing-Allow-Origin: * header -->
     <object data="http://test1.example.com/tests/dom/tests/mochitest/general/res2.resource"> <!-- cross origin redirect to test2.example.com, no header -->
     <object data="http://test1.example.com/tests/dom/tests/mochitest/general/res3.resource"> <!-- cross origin, Timing-Allow-Origin: http://mochi.test:8888 header -->
     <object data="http://test1.example.com/tests/dom/tests/mochitest/general/res4.resource"> <!-- cross origin redirect to mochi.test:8888/.../res1.resource, Timing-Allow-Origin: * -->
     <object data="http://test1.example.com/tests/dom/tests/mochitest/general/res5.resource"> <!-- cross origin, Timing-Allow-Origin: http://mochi.test:8889 -->
     <object data="http://test1.example.com/tests/dom/tests/mochitest/general/res6.resource"> <!-- cross origin, Timing-Allow-Origin: "" (empty string) -->
     <object data="http://test1.example.com/tests/dom/tests/mochitest/general/res7.resource"> <!-- cross origin, Timing-Allow-Origin: http://mochi.test:8888 http://test1.com header -->
     <object data="http://test1.example.com/tests/dom/tests/mochitest/general/res8.resource"> <!-- double cross origin redirect -->
+    <script type="text/javascript" src="http://mochi.test:8888/tests/dom/tests/mochitest/general/resource_timing.js"></script> <!-- same origin script -->
   </div>
 </body>
 
 </html>
--- a/dom/tests/mochitest/notification/mochitest.ini
+++ b/dom/tests/mochitest/notification/mochitest.ini
@@ -1,12 +1,12 @@
 [DEFAULT]
 skip-if = e10s || buildapp == 'mulet'
 support-files =
   MockServices.js
   NotificationTest.js
 
 [test_notification_basics.html]
 [test_notification_storage.html]
-skip-if = (toolkit == 'gonk' && debug) #debug-only timeout
+skip-if = (toolkit == 'gonk')
 [test_bug931307.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only timeout
 [test_notification_resend.html]
new file mode 100644
--- /dev/null
+++ b/dom/webidl/ScrollViewChangeEvent.webidl
@@ -0,0 +1,21 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+enum ScrollState {"started", "stopped"};
+
+dictionary ScrollViewChangeEventInit : EventInit {
+  ScrollState state = "started";
+  float scrollX = 0;
+  float scrollY = 0;
+};
+
+[Constructor(DOMString type, optional ScrollViewChangeEventInit eventInit),
+ ChromeOnly]
+interface ScrollViewChangeEvent : Event {
+  readonly attribute ScrollState state;
+  readonly attribute float scrollX;
+  readonly attribute float scrollY;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/SettingChangeNotification.webidl
@@ -0,0 +1,12 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+// Used internally by Gecko
+dictionary SettingChangeNotification {
+  DOMString key   = "";
+  any       value;
+  boolean   isInternalChange = false;
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -332,16 +332,17 @@ WEBIDL_FILES = [
     'Screen.webidl',
     'ScriptProcessorNode.webidl',
     'ScrollAreaEvent.webidl',
     'Selection.webidl',
     'ServiceWorker.webidl',
     'ServiceWorkerContainer.webidl',
     'ServiceWorkerGlobalScope.webidl',
     'ServiceWorkerRegistration.webidl',
+    'SettingChangeNotification.webidl',
     'SettingsManager.webidl',
     'ShadowRoot.webidl',
     'SharedWorker.webidl',
     'SharedWorkerGlobalScope.webidl',
     'SimpleGestureEvent.webidl',
     'SocketCommon.webidl',
     'SourceBuffer.webidl',
     'SourceBufferList.webidl',
@@ -674,16 +675,17 @@ GENERATED_EVENTS_WEBIDL_FILES = [
     'PopStateEvent.webidl',
     'PopupBlockedEvent.webidl',
     'ProgressEvent.webidl',
     'RecordErrorEvent.webidl',
     'RTCDataChannelEvent.webidl',
     'RTCPeerConnectionIceEvent.webidl',
     'RTCPeerConnectionIdentityErrorEvent.webidl',
     'RTCPeerConnectionIdentityEvent.webidl',
+    'ScrollViewChangeEvent.webidl',
     'SelectionChangeEvent.webidl',
     'StyleRuleChangeEvent.webidl',
     'StyleSheetApplicableStateChangeEvent.webidl',
     'StyleSheetChangeEvent.webidl',
     'TrackEvent.webidl',
     'UDPMessageEvent.webidl',
     'UserProximityEvent.webidl',
     'USSDReceivedEvent.webidl',
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -3637,27 +3637,26 @@ WifiWorker.prototype = {
       }.bind(this));
     }
   },
 
   // nsIObserver implementation
   observe: function observe(subject, topic, data) {
     switch (topic) {
     case kMozSettingsChangedObserverTopic:
-      // The string we're interested in will be a JSON string that looks like:
-      // {"key":"wifi.enabled","value":"true"}.
-
-      let setting = JSON.parse(data);
       // To avoid WifiWorker setting the wifi again, don't need to deal with
       // the "mozsettings-changed" event fired from internal setting.
-      if (setting.isInternalChange) {
+      if ("wrappedJSObject" in subject) {
+        subject = subject.wrappedJSObject;
+      }
+      if (subject.isInternalChange) {
         return;
       }
 
-      this.handle(setting.key, setting.value);
+      this.handle(subject.key, subject.value);
       break;
 
     case "xpcom-shutdown":
       let wifiService = Cc["@mozilla.org/wifi/service;1"].getService(Ci.nsIWifiProxyService);
       wifiService.shutdown();
       let wifiCertService = Cc["@mozilla.org/wifi/certservice;1"].getService(Ci.nsIWifiCertService);
       wifiCertService.shutdown();
       break;
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -90,16 +90,17 @@ static const char *sExtensionNames[] = {
     "GL_ARB_pixel_buffer_object",
     "GL_ARB_robustness",
     "GL_ARB_sampler_objects",
     "GL_ARB_sync",
     "GL_ARB_texture_compression",
     "GL_ARB_texture_float",
     "GL_ARB_texture_non_power_of_two",
     "GL_ARB_texture_rectangle",
+    "GL_ARB_texture_storage",
     "GL_ARB_transform_feedback2",
     "GL_ARB_uniform_buffer_object",
     "GL_ARB_vertex_array_object",
     "GL_EXT_bgra",
     "GL_EXT_blend_minmax",
     "GL_EXT_color_buffer_float",
     "GL_EXT_color_buffer_half_float",
     "GL_EXT_copy_texture",
@@ -925,16 +926,32 @@ GLContext::InitWithPrefix(const char *pr
             if (!LoadSymbols(samplerObjectsSymbols, trygl, prefix)) {
                 NS_ERROR("GL supports sampler objects without supplying its functions.");
 
                 MarkUnsupported(GLFeature::sampler_objects);
                 ClearSymbols(samplerObjectsSymbols);
             }
         }
 
+        if (IsSupported(GLFeature::texture_storage)) {
+            SymLoadStruct coreSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fTexStorage2D, { "TexStorage2D", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fTexStorage3D, { "TexStorage3D", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(coreSymbols, trygl, prefix)) {
+                NS_ERROR("GL supports texture storage without supplying its functions.");
+
+                MarkUnsupported(GLFeature::texture_storage);
+                MarkExtensionUnsupported(ARB_texture_storage);
+                ClearSymbols(coreSymbols);
+            }
+        }
+
         // ARB_transform_feedback2/NV_transform_feedback2 is a
         // superset of EXT_transform_feedback/NV_transform_feedback
         // and adds glPauseTransformFeedback &
         // glResumeTransformFeedback, which are required for WebGL2.
         if (IsSupported(GLFeature::transform_feedback2)) {
             SymLoadStruct coreSymbols[] = {
                 { (PRFuncPtr*) &mSymbols.fBindBufferBase, { "BindBufferBase", nullptr } },
                 { (PRFuncPtr*) &mSymbols.fBindBufferRange, { "BindBufferRange", nullptr } },
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -113,16 +113,17 @@ MOZ_BEGIN_ENUM_CLASS(GLFeature)
     texture_3D,
     texture_3D_compressed,
     texture_3D_copy,
     texture_float,
     texture_float_linear,
     texture_half_float,
     texture_half_float_linear,
     texture_non_power_of_two,
+    texture_storage,
     transform_feedback2,
     uniform_buffer_object,
     uniform_matrix_nonsquare,
     vertex_array_object,
     EnumMax
 MOZ_END_ENUM_CLASS(GLFeature)
 
 MOZ_BEGIN_ENUM_CLASS(ContextProfile, uint8_t)
@@ -369,16 +370,17 @@ public:
         ARB_pixel_buffer_object,
         ARB_robustness,
         ARB_sampler_objects,
         ARB_sync,
         ARB_texture_compression,
         ARB_texture_float,
         ARB_texture_non_power_of_two,
         ARB_texture_rectangle,
+        ARB_texture_storage,
         ARB_transform_feedback2,
         ARB_uniform_buffer_object,
         ARB_vertex_array_object,
         EXT_bgra,
         EXT_blend_minmax,
         EXT_color_buffer_float,
         EXT_color_buffer_half_float,
         EXT_copy_texture,
@@ -3061,16 +3063,33 @@ public:
 
     void fUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) {
         ASSERT_SYMBOL_PRESENT(fUniformBlockBinding);
         BEFORE_GL_CALL;
         mSymbols.fUniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding);
         AFTER_GL_CALL;
     }
 
+// -----------------------------------------------------------------------------
+// Core GL 4.2, GL ES 3.0 & Extension ARB_texture_storage/EXT_texture_storage
+    void fTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
+    {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fTexStorage2D);
+        mSymbols.fTexStorage2D(target, levels, internalformat, width, height);
+        AFTER_GL_CALL;
+    }
+
+    void fTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
+    {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fTexStorage3D);
+        mSymbols.fTexStorage3D(target, levels, internalformat, width, height, depth);
+        AFTER_GL_CALL;
+    }
 
 // -----------------------------------------------------------------------------
 // 3D Textures
     void fTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                         GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                         GLenum format, GLenum type, const GLvoid* pixels)
     {
         BEFORE_GL_CALL;
--- a/gfx/gl/GLContextFeatures.cpp
+++ b/gfx/gl/GLContextFeatures.cpp
@@ -504,16 +504,30 @@ static const FeatureInfo sFeatureInfoArr
         GLContext::Extension_None,
         {
             GLContext::ARB_texture_non_power_of_two,
             GLContext::OES_texture_npot,
             GLContext::Extensions_End
         }
     },
     {
+        "texture_storage",
+        420, // OpenGL version
+        300, // OpenGL ES version
+        GLContext::ARB_texture_storage,
+        {
+            /*
+             * Not including GL_EXT_texture_storage here because it
+             * doesn't guarantee glTexStorage3D, which is required for
+             * WebGL 2.
+             */
+            GLContext::Extensions_End
+        }
+    },
+    {
         "transform_feedback2",
         400, // OpenGL version
         300, // OpenGL ES version
         GLContext::Extension_None,
         {
             GLContext::ARB_transform_feedback2,
             GLContext::NV_transform_feedback2,
             GLContext::Extensions_End
--- a/gfx/gl/GLContextSymbols.h
+++ b/gfx/gl/GLContextSymbols.h
@@ -575,16 +575,22 @@ struct GLContextSymbols
     PFNGLSAMPLERPARAMETERFPROC fSamplerParameterf;
     typedef void (GLAPIENTRY * PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param);
     PFNGLSAMPLERPARAMETERFVPROC fSamplerParameterfv;
     typedef void (GLAPIENTRY * PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params);
     PFNGLGETSAMPLERPARAMETERIVPROC fGetSamplerParameteriv;
     typedef void (GLAPIENTRY * PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params);
     PFNGLGETSAMPLERPARAMETERFVPROC fGetSamplerParameterfv;
 
+    // texture_storage
+    typedef void (GLAPIENTRY * PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+    PFNGLTEXSTORAGE2DPROC fTexStorage2D;
+    typedef void (GLAPIENTRY * PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+    PFNGLTEXSTORAGE3DPROC fTexStorage3D;
+
     // uniform_buffer_object
     typedef void (GLAPIENTRY * PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount,
                                                             const GLchar* const* uniformNames, GLuint* uniformIndices);
     PFNGLGETUNIFORMINDICESPROC fGetUniformIndices;
     typedef void (GLAPIENTRY * PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint* uniformIndices,
                                                              GLenum pname, GLint* params);
     PFNGLGETACTIVEUNIFORMSIVPROC fGetActiveUniformsiv;
     typedef void (GLAPIENTRY * PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIdex, GLsizei bufSize, GLsizei* length, GLchar* uniformName);
--- a/gfx/gl/SharedSurfaceANGLE.cpp
+++ b/gfx/gl/SharedSurfaceANGLE.cpp
@@ -6,16 +6,83 @@
 #include "SharedSurfaceANGLE.h"
 
 #include "GLContextEGL.h"
 #include "GLLibraryEGL.h"
 
 namespace mozilla {
 namespace gl {
 
+// Returns `EGL_NO_SURFACE` (`0`) on error.
+static EGLSurface
+CreatePBufferSurface(GLLibraryEGL* egl,
+                     EGLDisplay display,
+                     EGLConfig config,
+                     const gfx::IntSize& size)
+{
+    auto width = size.width;
+    auto height = size.height;
+
+    EGLint attribs[] = {
+        LOCAL_EGL_WIDTH, width,
+        LOCAL_EGL_HEIGHT, height,
+        LOCAL_EGL_NONE
+    };
+
+    DebugOnly<EGLint> preCallErr = egl->fGetError();
+    MOZ_ASSERT(preCallErr == LOCAL_EGL_SUCCESS);
+    EGLSurface surface = egl->fCreatePbufferSurface(display, config, attribs);
+    EGLint err = egl->fGetError();
+    if (err != LOCAL_EGL_SUCCESS)
+        return 0;
+
+    return surface;
+}
+
+/*static*/ UniquePtr<SharedSurface_ANGLEShareHandle>
+SharedSurface_ANGLEShareHandle::Create(GLContext* gl,
+                                       EGLContext context, EGLConfig config,
+                                       const gfx::IntSize& size, bool hasAlpha)
+{
+    GLLibraryEGL* egl = &sEGLLibrary;
+    MOZ_ASSERT(egl);
+    MOZ_ASSERT(egl->IsExtensionSupported(
+               GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle));
+
+    if (!context || !config)
+        return nullptr;
+
+    EGLDisplay display = egl->Display();
+    EGLSurface pbuffer = CreatePBufferSurface(egl, display, config, size);
+    if (!pbuffer)
+        return nullptr;
+
+    // Declare everything before 'goto's.
+    HANDLE shareHandle = nullptr;
+    bool ok = egl->fQuerySurfacePointerANGLE(display,
+                                             pbuffer,
+                                             LOCAL_EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
+                                             &shareHandle);
+    if (!ok) {
+        egl->fDestroySurface(egl->Display(), pbuffer);
+        return nullptr;
+    }
+
+    GLuint fence = 0;
+    if (gl->IsExtensionSupported(GLContext::NV_fence)) {
+        gl->MakeCurrent();
+        gl->fGenFences(1, &fence);
+    }
+
+    typedef SharedSurface_ANGLEShareHandle ptrT;
+    UniquePtr<ptrT> ret( new ptrT(gl, egl, size, hasAlpha, context,
+                                  pbuffer, shareHandle, fence) );
+    return Move(ret);
+}
+
 EGLDisplay
 SharedSurface_ANGLEShareHandle::Display()
 {
     return mEGL->Display();
 }
 
 SharedSurface_ANGLEShareHandle::SharedSurface_ANGLEShareHandle(GLContext* gl,
                                                                GLLibraryEGL* egl,
@@ -109,16 +176,19 @@ SharedSurface_ANGLEShareHandle::PollSync
     if (mFence) {
         mGL->MakeCurrent();
         return mGL->fTestFence(mFence);
     }
 
     return PollSync();
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// Factory
+
 static void
 FillPBufferAttribs_ByBits(nsTArray<EGLint>& aAttrs,
                           int redBits, int greenBits,
                           int blueBits, int alphaBits,
                           int depthBits, int stencilBits)
 {
     aAttrs.Clear();
 
@@ -164,157 +234,126 @@ FillPBufferAttribs_BySizes(nsTArray<EGLi
             blue = 5;
         }
     } else {
         red = green = blue = 8;
         if (hasAlpha)
             alpha = 8;
     }
 
-    FillPBufferAttribs_ByBits(attribs,
-                              red, green, blue, alpha,
-                              depthBits, stencilBits);
+    FillPBufferAttribs_ByBits(attribs, red, green, blue, alpha, depthBits,
+                              stencilBits);
+}
+
+static bool
+DoesAttribBitsMatchCapBool(GLLibraryEGL* egl, EGLConfig config, EGLint attrib,
+                           bool capBool)
+{
+    EGLint bits = 0;
+    egl->fGetConfigAttrib(egl->Display(), config, attrib, &bits);
+    MOZ_ASSERT(egl->fGetError() == LOCAL_EGL_SUCCESS);
+
+    bool hasBits = !!bits;
+
+    return hasBits == capBool;
 }
 
 static EGLConfig
-ChooseConfig(GLContext* gl,
-             GLLibraryEGL* egl,
-             const SurfaceCaps& caps)
+ChooseConfig(GLContext* gl, GLLibraryEGL* egl, const SurfaceCaps& caps)
 {
     MOZ_ASSERT(egl);
     MOZ_ASSERT(caps.color);
 
     // We might want 24-bit depth, but we're only (fairly) sure to get 16-bit.
     int depthBits = caps.depth ? 16 : 0;
     int stencilBits = caps.stencil ? 8 : 0;
 
     // Ok, now we have everything.
     nsTArray<EGLint> attribs(32);
-    FillPBufferAttribs_BySizes(attribs,
-                               caps.bpp16, caps.alpha,
-                               depthBits, stencilBits);
+    FillPBufferAttribs_BySizes(attribs, caps.bpp16, caps.alpha, depthBits,
+                               stencilBits);
 
     // Time to try to get this config:
     EGLConfig configs[64];
     int numConfigs = sizeof(configs)/sizeof(EGLConfig);
     int foundConfigs = 0;
 
-    if (!egl->fChooseConfig(egl->Display(),
-                            attribs.Elements(),
-                            configs, numConfigs,
-                            &foundConfigs) ||
+    if (!egl->fChooseConfig(egl->Display(), attribs.Elements(), configs,
+                            numConfigs, &foundConfigs) ||
         !foundConfigs)
     {
         NS_WARNING("No configs found for the requested formats.");
         return EGL_NO_CONFIG;
     }
 
-    // TODO: Pick a config progamatically instead of hoping that
-    // the first config will be minimally matching our request.
-    EGLConfig config = configs[0];
+    // The requests passed to ChooseConfig are treated as minimums. If you ask
+    // for 0 bits of alpha, we might still get 8 bits.
+    EGLConfig config = EGL_NO_CONFIG;
+    for (int i = 0; i < foundConfigs; i++) {
+        EGLConfig cur = configs[0];
+        if (DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_ALPHA_SIZE,
+                                       caps.alpha) &&
+            DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_DEPTH_SIZE,
+                                       caps.depth) &&
+            DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_STENCIL_SIZE,
+                                       caps.stencil))
+        {
+            config = cur;
+            break;
+        }
+    }
+
+    if (config == EGL_NO_CONFIG) {
+        NS_WARNING("No acceptable EGLConfig found.");
+        return EGL_NO_CONFIG;
+    }
 
     if (gl->DebugMode()) {
         egl->DumpEGLConfig(config);
     }
 
     return config;
 }
 
-// Returns `EGL_NO_SURFACE` (`0`) on error.
-static EGLSurface
-CreatePBufferSurface(GLLibraryEGL* egl,
-                     EGLDisplay display,
-                     EGLConfig config,
-                     const gfx::IntSize& size)
-{
-    auto width = size.width;
-    auto height = size.height;
-
-    EGLint attribs[] = {
-        LOCAL_EGL_WIDTH, width,
-        LOCAL_EGL_HEIGHT, height,
-        LOCAL_EGL_NONE
-    };
-
-    DebugOnly<EGLint> preCallErr = egl->fGetError();
-    MOZ_ASSERT(preCallErr == LOCAL_EGL_SUCCESS);
-    EGLSurface surface = egl->fCreatePbufferSurface(display, config, attribs);
-    EGLint err = egl->fGetError();
-    if (err != LOCAL_EGL_SUCCESS)
-        return 0;
-
-    return surface;
-}
-
-/*static*/ UniquePtr<SharedSurface_ANGLEShareHandle>
-SharedSurface_ANGLEShareHandle::Create(GLContext* gl,
-                                       EGLContext context, EGLConfig config,
-                                       const gfx::IntSize& size, bool hasAlpha)
-{
-    GLLibraryEGL* egl = &sEGLLibrary;
-    MOZ_ASSERT(egl);
-    MOZ_ASSERT(egl->IsExtensionSupported(
-               GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle));
-
-    if (!context || !config)
-        return nullptr;
-
-    EGLDisplay display = egl->Display();
-    EGLSurface pbuffer = CreatePBufferSurface(egl, display, config, size);
-    if (!pbuffer)
-        return nullptr;
-
-    // Declare everything before 'goto's.
-    HANDLE shareHandle = nullptr;
-    bool ok = egl->fQuerySurfacePointerANGLE(display,
-                                             pbuffer,
-                                             LOCAL_EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
-                                             &shareHandle);
-    if (!ok) {
-        egl->fDestroySurface(egl->Display(), pbuffer);
-        return nullptr;
-    }
-
-    GLuint fence = 0;
-    if (gl->IsExtensionSupported(GLContext::NV_fence)) {
-        gl->MakeCurrent();
-        gl->fGenFences(1, &fence);
-    }
-
-    typedef SharedSurface_ANGLEShareHandle ptrT;
-    UniquePtr<ptrT> ret( new ptrT(gl, egl, size, hasAlpha, context,
-                                  pbuffer, shareHandle, fence) );
-    return Move(ret);
-}
-
 /*static*/ UniquePtr<SurfaceFactory_ANGLEShareHandle>
 SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl,
                                         const SurfaceCaps& caps)
 {
     GLLibraryEGL* egl = &sEGLLibrary;
     if (!egl)
         return nullptr;
 
     auto ext = GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle;
     if (!egl->IsExtensionSupported(ext))
-    {
         return nullptr;
-    }
 
+    bool success;
     typedef SurfaceFactory_ANGLEShareHandle ptrT;
-    UniquePtr<ptrT> ret( new ptrT(gl, egl, caps) );
+    UniquePtr<ptrT> ret( new ptrT(gl, egl, caps, &success) );
+
+    if (!success)
+        return nullptr;
+
     return Move(ret);
 }
 
 SurfaceFactory_ANGLEShareHandle::SurfaceFactory_ANGLEShareHandle(GLContext* gl,
                                                                  GLLibraryEGL* egl,
-                                                                 const SurfaceCaps& caps)
+                                                                 const SurfaceCaps& caps,
+                                                                 bool* const out_success)
     : SurfaceFactory(gl, SharedSurfaceType::EGLSurfaceANGLE, caps)
     , mProdGL(gl)
     , mEGL(egl)
 {
-    mConfig = ChooseConfig(mProdGL, mEGL, mReadCaps);
+    MOZ_ASSERT(out_success);
+    *out_success = false;
+
     mContext = GLContextEGL::Cast(mProdGL)->GetEGLContext();
+    mConfig = ChooseConfig(mProdGL, mEGL, mReadCaps);
+    if (mConfig == EGL_NO_CONFIG)
+        return;
+
     MOZ_ASSERT(mConfig && mContext);
+    *out_success = true;
 }
 
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/gl/SharedSurfaceANGLE.h
+++ b/gfx/gl/SharedSurfaceANGLE.h
@@ -83,17 +83,18 @@ protected:
 
 public:
     static UniquePtr<SurfaceFactory_ANGLEShareHandle> Create(GLContext* gl,
                                                              const SurfaceCaps& caps);
 
 protected:
     SurfaceFactory_ANGLEShareHandle(GLContext* gl,
                                     GLLibraryEGL* egl,
-                                    const SurfaceCaps& caps);
+                                    const SurfaceCaps& caps,
+                                    bool* const out_success);
 
     virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) MOZ_OVERRIDE {
         bool hasAlpha = mReadCaps.alpha;
         return SharedSurface_ANGLEShareHandle::Create(mProdGL,
                                                       mContext, mConfig,
                                                       size, hasAlpha);
     }
 };
--- a/gfx/src/nsDeviceContext.cpp
+++ b/gfx/src/nsDeviceContext.cpp
@@ -138,17 +138,17 @@ nsFontCache::GetMetricsFor(const nsFont&
         fm = mFontMetrics[i];
         if (fm->Font().Equals(aFont) && fm->GetUserFontSet() == aUserFontSet &&
             fm->Language() == aLanguage) {
             if (i != n) {
                 // promote it to the end of the cache
                 mFontMetrics.RemoveElementAt(i);
                 mFontMetrics.AppendElement(fm);
             }
-            fm->GetThebesFontGroup()->UpdateFontList();
+            fm->GetThebesFontGroup()->UpdateUserFonts();
             NS_ADDREF(aMetrics = fm);
             return NS_OK;
         }
     }
 
     // It's not in the cache. Get font metrics and then cache them.
 
     fm = new nsFontMetrics();
--- a/gfx/src/nsFontMetrics.cpp
+++ b/gfx/src/nsFontMetrics.cpp
@@ -127,35 +127,32 @@ nsFontMetrics::Init(const nsFont& aFont,
                        aFont.synthesis & NS_FONT_SYNTHESIS_STYLE,
                        aFont.languageOverride);
 
     aFont.AddFontFeaturesToStyle(&style);
 
     mFontGroup = gfxPlatform::GetPlatform()->
         CreateFontGroup(aFont.fontlist, &style, aUserFontSet);
     mFontGroup->SetTextPerfMetrics(aTextPerf);
-    if (mFontGroup->FontListLength() < 1)
-        return NS_ERROR_UNEXPECTED;
-
     return NS_OK;
 }
 
 void
 nsFontMetrics::Destroy()
 {
     mDeviceContext = nullptr;
 }
 
 // XXXTODO get rid of this macro
 #define ROUND_TO_TWIPS(x) (nscoord)floor(((x) * mP2A) + 0.5)
 #define CEIL_TO_TWIPS(x) (nscoord)ceil((x) * mP2A)
 
 const gfxFont::Metrics& nsFontMetrics::GetMetrics() const
 {
-    return mFontGroup->GetFontAt(0)->GetMetrics();
+    return mFontGroup->GetFirstValidFont()->GetMetrics();
 }
 
 nscoord
 nsFontMetrics::XHeight()
 {
     return ROUND_TO_TWIPS(GetMetrics().xHeight);
 }
 
--- a/gfx/thebes/gfxASurface.h
+++ b/gfx/thebes/gfxASurface.h
@@ -121,22 +121,16 @@ public:
      */
     static bool CheckSurfaceSize(const nsIntSize& sz, int32_t limit = 0);
 
     /* Provide a stride value that will respect all alignment requirements of
      * the accelerated image-rendering code.
      */
     static int32_t FormatStrideForWidth(gfxImageFormat format, int32_t width);
 
-    /* Return the default set of context flags for this surface; these are
-     * hints to the context about any special rendering considerations.  See
-     * gfxContext::SetFlag for documentation.
-     */
-    virtual int32_t GetDefaultContextFlags() const { return 0; }
-
     static gfxContentType ContentFromFormat(gfxImageFormat format);
 
     void SetSubpixelAntialiasingEnabled(bool aEnabled);
     bool GetSubpixelAntialiasingEnabled();
 
     /**
      * Record number of bytes for given surface type.  Use positive bytes
      * for allocations and negative bytes for deallocations.
--- a/gfx/thebes/gfxPDFSurface.h
+++ b/gfx/thebes/gfxPDFSurface.h
@@ -29,23 +29,16 @@ public:
     void GetDPI(double *xDPI, double *yDPI);
 
     // this is in points!
     virtual const gfxIntSize GetSize() const
     {
         return gfxIntSize(mSize.width, mSize.height);
     }
 
-    virtual int32_t GetDefaultContextFlags() const
-    {
-        return gfxContext::FLAG_SIMPLIFY_OPERATORS |
-               gfxContext::FLAG_DISABLE_SNAPPING |
-               gfxContext::FLAG_DISABLE_COPY_BACKGROUND;
-    }
-
 private:
     nsCOMPtr<nsIOutputStream> mStream;
     double mXDPI;
     double mYDPI;
     gfxSize mSize;
 };
 
 #endif /* GFX_PDFSURFACE_H */
--- a/gfx/thebes/gfxPSSurface.h
+++ b/gfx/thebes/gfxPSSurface.h
@@ -36,22 +36,16 @@ public:
     virtual bool GetRotateForLandscape() { return (mOrientation == LANDSCAPE); }
 
     // this is in points!
     virtual const gfxIntSize GetSize() const
     {
         return mSize;
     }
 
-    virtual int32_t GetDefaultContextFlags() const
-    {
-        return gfxContext::FLAG_SIMPLIFY_OPERATORS |
-               gfxContext::FLAG_DISABLE_SNAPPING;
-    }
-
 private:
     nsCOMPtr<nsIOutputStream> mStream;
     double mXDPI;
     double mYDPI;
     gfxIntSize mSize;
     PageOrientation mOrientation;
 };
 
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -808,32 +808,33 @@ FindFontPatterns(gfxUserFontSet *mUserFo
     style.style = aStyle;
     style.weight = aWeight;
     style.stretch = aStretch;
 
     gfxUserFcFontEntry *fontEntry = nullptr;
     gfxFontFamily *family = mUserFontSet->LookupFamily(utf16Family);
     if (family) {
         gfxUserFontEntry* userFontEntry =
-            mUserFontSet->FindUserFontEntry(family, style, needsBold,
-                                            aWaitForUserFont);
+            mUserFontSet->FindUserFontEntryAndLoad(family, style, needsBold,
+                                                   aWaitForUserFont);
         if (userFontEntry) {
             fontEntry = static_cast<gfxUserFcFontEntry*>
                 (userFontEntry->GetPlatformFontEntry());
         }
 
         // Accept synthetic oblique for italic and oblique.
         // xxx - this isn't really ideal behavior, for docs that only use a
         //       single italic face it will also pull down the normal face
         //       and probably never use it
         if (!fontEntry && aStyle != NS_FONT_STYLE_NORMAL) {
             style.style = NS_FONT_STYLE_NORMAL;
-            userFontEntry = mUserFontSet->FindUserFontEntry(family, style,
-                                                            needsBold,
-                                                            aWaitForUserFont);
+            userFontEntry =
+                mUserFontSet->FindUserFontEntryAndLoad(family, style,
+                                                       needsBold,
+                                                       aWaitForUserFont);
             if (userFontEntry) {
                 fontEntry = static_cast<gfxUserFcFontEntry*>
                     (userFontEntry->GetPlatformFontEntry());
             }
         }
     }
 
     if (!fontEntry) {
@@ -1303,34 +1304,40 @@ gfxPangoFontGroup::GetBaseFont()
     if (mFonts[0].Font() == nullptr) {
         gfxFont* font = GetBaseFontSet()->GetFontAt(0, GetStyle());
         mFonts[0] = FamilyFace(nullptr, font);
     }
 
     return static_cast<gfxFcFont*>(mFonts[0].Font());
 }
 
+gfxFont*
+gfxPangoFontGroup::GetFirstValidFont()
+{
+    return GetFontAt(0);
+}
+
 gfxFont *
 gfxPangoFontGroup::GetFontAt(int32_t i)
 {
     // If it turns out to be hard for all clients that cache font
-    // groups to call UpdateFontList at appropriate times, we could
-    // instead consider just calling UpdateFontList from someplace
+    // groups to call UpdateUserFonts at appropriate times, we could
+    // instead consider just calling UpdateUserFonts from someplace
     // more central (such as here).
     NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
                  "Whoever was caching this font group should have "
-                 "called UpdateFontList on it");
+                 "called UpdateUserFonts on it");
 
     NS_PRECONDITION(i == 0, "Only have one font");
 
     return GetBaseFont();
 }
 
 void
-gfxPangoFontGroup::UpdateFontList()
+gfxPangoFontGroup::UpdateUserFonts()
 {
     uint64_t newGeneration = GetGeneration();
     if (newGeneration == mCurrGeneration)
         return;
 
     mFonts[0] = FamilyFace();
     mFontSets.Clear();
     mCachedEllipsisTextRun = nullptr;
--- a/gfx/thebes/gfxPangoFonts.h
+++ b/gfx/thebes/gfxPangoFonts.h
@@ -25,19 +25,21 @@ class gfxPangoFontGroup : public gfxFont
 public:
     gfxPangoFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
                       const gfxFontStyle *aStyle,
                       gfxUserFontSet *aUserFontSet);
     virtual ~gfxPangoFontGroup();
 
     virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
 
+    virtual gfxFont* GetFirstValidFont();
+
     virtual gfxFont *GetFontAt(int32_t i);
 
-    virtual void UpdateFontList();
+    virtual void UpdateUserFonts();
 
     virtual already_AddRefed<gfxFont>
         FindFontForChar(uint32_t aCh, uint32_t aPrevCh, int32_t aRunScript,
                         gfxFont *aPrevMatchedFont,
                         uint8_t *aMatchType);
 
     static void Shutdown();
 
--- a/gfx/thebes/gfxQuartzSurface.cpp
+++ b/gfx/thebes/gfxQuartzSurface.cpp
@@ -10,19 +10,18 @@
 #include "cairo-quartz.h"
 
 void
 gfxQuartzSurface::MakeInvalid()
 {
     mSize = gfxIntSize(-1, -1);    
 }
 
-gfxQuartzSurface::gfxQuartzSurface(const gfxSize& desiredSize, gfxImageFormat format,
-                                   bool aForPrinting)
-    : mCGContext(nullptr), mSize(desiredSize), mForPrinting(aForPrinting)
+gfxQuartzSurface::gfxQuartzSurface(const gfxSize& desiredSize, gfxImageFormat format)
+    : mCGContext(nullptr), mSize(desiredSize)
 {
     gfxIntSize size((unsigned int) floor(desiredSize.width),
                     (unsigned int) floor(desiredSize.height));
     if (!CheckSurfaceSize(size))
         MakeInvalid();
 
     unsigned int width = static_cast<unsigned int>(mSize.width);
     unsigned int height = static_cast<unsigned int>(mSize.height);
@@ -36,19 +35,18 @@ gfxQuartzSurface::gfxQuartzSurface(const
 
     Init(surf);
     if (mSurfaceValid) {
       RecordMemoryUsed(mSize.height * 4 + sizeof(gfxQuartzSurface));
     }
 }
 
 gfxQuartzSurface::gfxQuartzSurface(CGContextRef context,
-                                   const gfxSize& desiredSize,
-                                   bool aForPrinting)
-    : mCGContext(context), mSize(desiredSize), mForPrinting(aForPrinting)
+                                   const gfxSize& desiredSize)
+    : mCGContext(context), mSize(desiredSize)
 {
     gfxIntSize size((unsigned int) floor(desiredSize.width),
                     (unsigned int) floor(desiredSize.height));
     if (!CheckSurfaceSize(size))
         MakeInvalid();
 
     unsigned int width = static_cast<unsigned int>(mSize.width);
     unsigned int height = static_cast<unsigned int>(mSize.height);
@@ -61,19 +59,18 @@ gfxQuartzSurface::gfxQuartzSurface(CGCon
 
     Init(surf);
     if (mSurfaceValid) {
       RecordMemoryUsed(mSize.height * 4 + sizeof(gfxQuartzSurface));
     }
 }
 
 gfxQuartzSurface::gfxQuartzSurface(CGContextRef context,
-                                   const gfxIntSize& size,
-                                   bool aForPrinting)
-    : mCGContext(context), mSize(size), mForPrinting(aForPrinting)
+                                   const gfxIntSize& size)
+    : mCGContext(context), mSize(size)
 {
     if (!CheckSurfaceSize(size))
         MakeInvalid();
 
     unsigned int width = static_cast<unsigned int>(mSize.width);
     unsigned int height = static_cast<unsigned int>(mSize.height);
 
     cairo_surface_t *surf = 
@@ -84,32 +81,30 @@ gfxQuartzSurface::gfxQuartzSurface(CGCon
 
     Init(surf);
     if (mSurfaceValid) {
       RecordMemoryUsed(mSize.height * 4 + sizeof(gfxQuartzSurface));
     }
 }
 
 gfxQuartzSurface::gfxQuartzSurface(cairo_surface_t *csurf,
-                                   const gfxIntSize& aSize,
-                                   bool aForPrinting) :
-    mSize(aSize), mForPrinting(aForPrinting)
+                                   const gfxIntSize& aSize) :
+    mSize(aSize)
 {
     mCGContext = cairo_quartz_surface_get_cg_context (csurf);
     CGContextRetain (mCGContext);
 
     Init(csurf, true);
 }
 
 gfxQuartzSurface::gfxQuartzSurface(unsigned char *data,
                                    const gfxSize& desiredSize,
                                    long stride,
-                                   gfxImageFormat format,
-                                   bool aForPrinting)
-    : mCGContext(nullptr), mSize(desiredSize), mForPrinting(aForPrinting)
+                                   gfxImageFormat format)
+    : mCGContext(nullptr), mSize(desiredSize)
 {
     gfxIntSize size((unsigned int) floor(desiredSize.width),
                     (unsigned int) floor(desiredSize.height));
     if (!CheckSurfaceSize(size))
         MakeInvalid();
 
     unsigned int width = static_cast<unsigned int>(mSize.width);
     unsigned int height = static_cast<unsigned int>(mSize.height);
@@ -125,19 +120,18 @@ gfxQuartzSurface::gfxQuartzSurface(unsig
     if (mSurfaceValid) {
       RecordMemoryUsed(mSize.height * stride + sizeof(gfxQuartzSurface));
     }
 }
 
 gfxQuartzSurface::gfxQuartzSurface(unsigned char *data,
                                    const gfxIntSize& aSize,
                                    long stride,
-                                   gfxImageFormat format,
-                                   bool aForPrinting)
-    : mCGContext(nullptr), mSize(aSize.width, aSize.height), mForPrinting(aForPrinting)
+                                   gfxImageFormat format)
+    : mCGContext(nullptr), mSize(aSize.width, aSize.height)
 {
     if (!CheckSurfaceSize(aSize))
         MakeInvalid();
 
     cairo_surface_t *surf = cairo_quartz_surface_create_for_data
         (data, (cairo_format_t) format, aSize.width, aSize.height, stride);
 
     mCGContext = cairo_quartz_surface_get_cg_context (surf);
@@ -168,25 +162,16 @@ gfxQuartzSurface::CreateSimilarSurface(g
 }
 
 CGContextRef
 gfxQuartzSurface::GetCGContextWithClip(gfxContext *ctx)
 {
     return cairo_quartz_get_cg_context_with_clip(ctx->GetCairo());
 }
 
-int32_t gfxQuartzSurface::GetDefaultContextFlags() const
-{
-    if (mForPrinting)
-        return gfxContext::FLAG_DISABLE_SNAPPING |
-               gfxContext::FLAG_DISABLE_COPY_BACKGROUND;
-
-    return 0;
-}
-
 already_AddRefed<gfxImageSurface> gfxQuartzSurface::GetAsImageSurface()
 {
     cairo_surface_t *surface = cairo_quartz_surface_get_image(mSurface);
     if (!surface || cairo_surface_status(surface))
         return nullptr;
 
     nsRefPtr<gfxASurface> img = Wrap(surface);
 
--- a/gfx/thebes/gfxQuartzSurface.h
+++ b/gfx/thebes/gfxQuartzSurface.h
@@ -12,39 +12,36 @@
 
 #include <Carbon/Carbon.h>
 
 class gfxContext;
 class gfxImageSurface;
 
 class gfxQuartzSurface : public gfxASurface {
 public:
-    gfxQuartzSurface(const gfxSize& size, gfxImageFormat format, bool aForPrinting = false);
-    gfxQuartzSurface(CGContextRef context, const gfxSize& size, bool aForPrinting = false);
-    gfxQuartzSurface(CGContextRef context, const gfxIntSize& size, bool aForPrinting = false);
-    gfxQuartzSurface(cairo_surface_t *csurf, const gfxIntSize& aSize, bool aForPrinting = false);
-    gfxQuartzSurface(unsigned char *data, const gfxSize& size, long stride, gfxImageFormat format, bool aForPrinting = false);
-    gfxQuartzSurface(unsigned char *data, const gfxIntSize& size, long stride, gfxImageFormat format, bool aForPrinting = false);
+    gfxQuartzSurface(const gfxSize& size, gfxImageFormat format);
+    gfxQuartzSurface(CGContextRef context, const gfxSize& size);
+    gfxQuartzSurface(CGContextRef context, const gfxIntSize& size);
+    gfxQuartzSurface(cairo_surface_t *csurf, const gfxIntSize& aSize);
+    gfxQuartzSurface(unsigned char *data, const gfxSize& size, long stride, gfxImageFormat format);
+    gfxQuartzSurface(unsigned char *data, const gfxIntSize& size, long stride, gfxImageFormat format);
 
     virtual ~gfxQuartzSurface();
 
     virtual already_AddRefed<gfxASurface> CreateSimilarSurface(gfxContentType aType,
                                                                const gfxIntSize& aSize);
 
     virtual const gfxIntSize GetSize() const { return gfxIntSize(mSize.width, mSize.height); }
 
     CGContextRef GetCGContext() { return mCGContext; }
 
     CGContextRef GetCGContextWithClip(gfxContext *ctx);
 
-    virtual int32_t GetDefaultContextFlags() const;
-
     already_AddRefed<gfxImageSurface> GetAsImageSurface();
 
 protected:
     void MakeInvalid();
 
     CGContextRef mCGContext;
     gfxSize      mSize;
-    bool mForPrinting;
 };
 
 #endif /* GFX_QUARTZSURFACE_H */
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -1464,21 +1464,25 @@ gfxFontGroup::gfxFontGroup(const FontFam
     , mUnderlineOffset(UNDERLINE_OFFSET_NOT_SET)
     , mHyphenWidth(-1)
     , mUserFontSet(aUserFontSet)
     , mTextPerf(nullptr)
     , mPageLang(gfxPlatform::GetFontPrefLangFor(aStyle->language))
     , mSkipDrawing(false)
 {
     // We don't use SetUserFontSet() here, as we want to unconditionally call
-    // BuildFontList() rather than only do UpdateFontList() if it changed.
+    // BuildFontList() rather than only do UpdateUserFonts() if it changed.
     mCurrGeneration = GetGeneration();
     BuildFontList();
 }
 
+gfxFontGroup::~gfxFontGroup()
+{
+}
+
 void
 gfxFontGroup::FindGenericFonts(FontFamilyType aGenericType,
                                nsIAtom *aLanguage,
                                void *aClosure)
 {
     nsAutoTArray<nsString, 5> resolvedGenerics;
     ResolveGenericFontNames(aGenericType, aLanguage, resolvedGenerics);
     uint32_t g = 0, numGenerics = resolvedGenerics.Length();
@@ -1606,87 +1610,17 @@ void gfxFontGroup::EnumerateFontList(nsI
     }
 }
 
 void
 gfxFontGroup::BuildFontList()
 {
 // gfxPangoFontGroup behaves differently, so this method is a no-op on that platform
 #if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID)
-
     EnumerateFontList(mStyle.language);
-
-    // at this point, fontlist should have been filled in
-    // get a default font if none exists
-    if (mFonts.Length() == 0) {
-        bool needsBold;
-        gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
-        gfxFontFamily *defaultFamily = pfl->GetDefaultFont(&mStyle);
-        NS_ASSERTION(defaultFamily,
-                     "invalid default font returned by GetDefaultFont");
-
-        if (defaultFamily) {
-            gfxFontEntry *fe = defaultFamily->FindFontForStyle(mStyle,
-                                                               needsBold);
-            if (fe) {
-                nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle,
-                                                            needsBold);
-                if (font) {
-                    mFonts.AppendElement(FamilyFace(defaultFamily, font));
-                }
-            }
-        }
-
-        if (mFonts.Length() == 0) {
-            // Try for a "font of last resort...."
-            // Because an empty font list would be Really Bad for later code
-            // that assumes it will be able to get valid metrics for layout,
-            // just look for the first usable font and put in the list.
-            // (see bug 554544)
-            nsAutoTArray<nsRefPtr<gfxFontFamily>,200> families;
-            pfl->GetFontFamilyList(families);
-            uint32_t count = families.Length();
-            for (uint32_t i = 0; i < count; ++i) {
-                gfxFontEntry *fe = families[i]->FindFontForStyle(mStyle,
-                                                                 needsBold);
-                if (fe) {
-                    nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle,
-                                                                needsBold);
-                    if (font) {
-                        mFonts.AppendElement(FamilyFace(families[i], font));
-                        break;
-                    }
-                }
-            }
-        }
-
-        if (mFonts.Length() == 0) {
-            // an empty font list at this point is fatal; we're not going to
-            // be able to do even the most basic layout operations
-            char msg[256]; // CHECK buffer length if revising message below
-            nsAutoString families;
-            mFamilyList.ToString(families);
-            sprintf(msg, "unable to find a usable font (%.220s)",
-                    NS_ConvertUTF16toUTF8(families).get());
-            NS_RUNTIMEABORT(msg);
-        }
-    }
-
-    if (!mStyle.systemFont) {
-        uint32_t count = mFonts.Length();
-        for (uint32_t i = 0; i < count; ++i) {
-            gfxFont* font = mFonts[i].Font();
-            if (font->GetFontEntry()->mIsBadUnderlineFont) {
-                gfxFloat first = mFonts[0].Font()->GetMetrics().underlineOffset;
-                gfxFloat bad = font->GetMetrics().underlineOffset;
-                mUnderlineOffset = std::min(first, bad);
-                break;
-            }
-        }
-    }
 #endif
 }
 
 void
 gfxFontGroup::FindPlatformFont(const nsAString& aName,
                                bool aUseFontSet,
                                void *aClosure)
 {
@@ -1695,76 +1629,190 @@ gfxFontGroup::FindPlatformFont(const nsA
     gfxFontEntry *fe = nullptr;
 
     if (aUseFontSet) {
         // First, look up in the user font set...
         // If the fontSet matches the family, we must not look for a platform
         // font of the same name, even if we fail to actually get a fontEntry
         // here; we'll fall back to the next name in the CSS font-family list.
         if (mUserFontSet) {
-            // If the fontSet matches the family, but the font has not yet finished
-            // loading (nor has its load timeout fired), the fontGroup should wait
-            // for the download, and not actually draw its text yet.
+            // add the userfont to the fontlist whether it's already been loaded
+            // or not. loading is initiated during font matching.
             family = mUserFontSet->LookupFamily(aName);
             if (family) {
-                bool waitForUserFont = false;
-                gfxUserFontEntry* userFontEntry =
-                    mUserFontSet->FindUserFontEntry(family, mStyle, needsBold,
-                                                    waitForUserFont);
-                if (userFontEntry) {
-                    fe = userFontEntry->GetPlatformFontEntry();
-                }
-                if (!fe && waitForUserFont) {
-                    mSkipDrawing = true;
-                }
+                fe = mUserFontSet->FindUserFontEntry(family, mStyle, needsBold);
             }
         }
     }
 
     // Not known in the user font set ==> check system fonts
     if (!family) {
         gfxPlatformFontList *fontList = gfxPlatformFontList::PlatformFontList();
         family = fontList->FindFamily(aName, mStyle.systemFont);
         if (family) {
             fe = family->FindFontForStyle(mStyle, needsBold);
         }
     }
 
     // add to the font group, unless it's already there
     if (fe && !HasFont(fe)) {
-        nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, needsBold);
-        if (font) {
-            mFonts.AppendElement(FamilyFace(family, font));
-        }
+        mFonts.AppendElement(FamilyFace(family, fe, needsBold));
     }
 }
 
 bool
 gfxFontGroup::HasFont(const gfxFontEntry *aFontEntry)
 {
     uint32_t count = mFonts.Length();
     for (uint32_t i = 0; i < count; ++i) {
-        if (mFonts[i].Font()->GetFontEntry() == aFontEntry)
+        if (mFonts[i].FontEntry() == aFontEntry) {
             return true;
+        }
     }
     return false;
 }
 
-gfxFontGroup::~gfxFontGroup()
+gfxFont*
+gfxFontGroup::GetFontAt(int32_t i)
+{
+    if (uint32_t(i) >= mFonts.Length()) {
+        return nullptr;
+    }
+
+    FamilyFace& ff = mFonts[i];
+    if (ff.IsInvalid() || ff.IsLoading()) {
+        return nullptr;
+    }
+
+    nsRefPtr<gfxFont> font = ff.Font();
+    if (!font) {
+        gfxFontEntry *fe = mFonts[i].FontEntry();
+        if (fe->mIsUserFontContainer) {
+            gfxUserFontEntry* ufe = static_cast<gfxUserFontEntry*>(fe);
+            if (ufe->LoadState() == gfxUserFontEntry::STATUS_NOT_LOADED) {
+                ufe->Load();
+                if (ufe->WaitForUserFont()) {
+                    mSkipDrawing = true;
+                }
+            }
+            fe = ufe->GetPlatformFontEntry();
+            if (!fe) {
+                return nullptr;
+            }
+        }
+        font = fe->FindOrMakeFont(&mStyle, mFonts[i].NeedsBold());
+        if (font && !font->Valid()) {
+            ff.SetInvalid();
+            return nullptr;
+        }
+        mFonts[i].SetFont(font);
+    }
+    return font.get();
+}
+
+gfxFont*
+gfxFontGroup::GetDefaultFont()
 {
-    mFonts.Clear();
+    if (mDefaultFont) {
+        return mDefaultFont.get();
+    }
+
+    bool needsBold;
+    gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
+    gfxFontFamily *defaultFamily = pfl->GetDefaultFont(&mStyle);
+    NS_ASSERTION(defaultFamily,
+                 "invalid default font returned by GetDefaultFont");
+
+    if (defaultFamily) {
+        gfxFontEntry *fe = defaultFamily->FindFontForStyle(mStyle,
+                                                           needsBold);
+        if (fe) {
+            mDefaultFont = fe->FindOrMakeFont(&mStyle, needsBold);
+        }
+    }
+
+    if (!mDefaultFont) {
+        // Try for a "font of last resort...."
+        // Because an empty font list would be Really Bad for later code
+        // that assumes it will be able to get valid metrics for layout,
+        // just look for the first usable font and put in the list.
+        // (see bug 554544)
+        nsAutoTArray<nsRefPtr<gfxFontFamily>,200> families;
+        pfl->GetFontFamilyList(families);
+        uint32_t count = families.Length();
+        for (uint32_t i = 0; i < count; ++i) {
+            gfxFontEntry *fe = families[i]->FindFontForStyle(mStyle,
+                                                             needsBold);
+            if (fe) {
+                mDefaultFont = fe->FindOrMakeFont(&mStyle, needsBold);
+            }
+        }
+    }
+
+    if (!mDefaultFont) {
+        // an empty font list at this point is fatal; we're not going to
+        // be able to do even the most basic layout operations
+        char msg[256]; // CHECK buffer length if revising message below
+        nsAutoString families;
+        mFamilyList.ToString(families);
+        sprintf(msg, "unable to find a usable font (%.220s)",
+                NS_ConvertUTF16toUTF8(families).get());
+        NS_RUNTIMEABORT(msg);
+    }
+
+    return mDefaultFont.get();
+}
+
+
+gfxFont*
+gfxFontGroup::GetFirstValidFont()
+{
+    uint32_t count = mFonts.Length();
+    for (uint32_t i = 0; i < count; ++i) {
+        FamilyFace& ff = mFonts[i];
+        if (ff.IsInvalid()) {
+            continue;
+        }
+
+        // already have a font?
+        gfxFont* font = ff.Font();
+        if (font) {
+            return font;
+        }
+
+        // need to build a font, loading userfont if not loaded
+        if (ff.IsUserFont()) {
+            gfxUserFontEntry* ufe =
+                static_cast<gfxUserFontEntry*>(mFonts[i].FontEntry());
+            if (ufe->LoadState() == gfxUserFontEntry::STATUS_NOT_LOADED) {
+                ufe->Load();
+                if (ufe->WaitForUserFont()) {
+                    mSkipDrawing = true;
+                }
+            }
+            if (ufe->LoadState() != gfxUserFontEntry::STATUS_LOADED) {
+                continue;
+            }
+        }
+
+        font = GetFontAt(i);
+        if (font) {
+            return font;
+        }
+    }
+    return GetDefaultFont();
 }
 
 gfxFont *
 gfxFontGroup::GetFirstMathFont()
 {
     uint32_t count = mFonts.Length();
     for (uint32_t i = 0; i < count; ++i) {
         gfxFont* font = GetFontAt(i);
-        if (font->GetFontEntry()->TryGetMathTable()) {
+        if (font && font->GetFontEntry()->TryGetMathTable()) {
             return font;
         }
     }
     return nullptr;
 }
 
 gfxFontGroup *
 gfxFontGroup::Copy(const gfxFontStyle *aStyle)
@@ -1813,17 +1861,17 @@ gfxFontGroup::MakeSpaceTextRun(const Par
         return nullptr;
     }
 
     uint16_t orientation = aFlags & TEXT_ORIENT_MASK;
     if (orientation == TEXT_ORIENT_VERTICAL_MIXED) {
         orientation = TEXT_ORIENT_VERTICAL_UPRIGHT;
     }
 
-    gfxFont *font = GetFontAt(0);
+    gfxFont *font = GetFirstValidFont();
     if (MOZ_UNLIKELY(GetStyle()->size == 0)) {
         // Short-circuit for size-0 fonts, as Windows and ATSUI can't handle
         // them, and always create at least size 1 fonts, i.e. they still
         // render something for size 0 fonts.
         textRun->AddGlyphRun(font, gfxTextRange::kFontGroup, 0, false,
                              orientation);
     }
     else {
@@ -1859,30 +1907,30 @@ gfxFontGroup::MakeBlankTextRun(uint32_t 
     if (!textRun) {
         return nullptr;
     }
 
     uint16_t orientation = aFlags & TEXT_ORIENT_MASK;
     if (orientation == TEXT_ORIENT_VERTICAL_MIXED) {
         orientation = TEXT_ORIENT_VERTICAL_UPRIGHT;
     }
-    textRun->AddGlyphRun(GetFontAt(0), gfxTextRange::kFontGroup, 0, false,
+    textRun->AddGlyphRun(GetFirstValidFont(), gfxTextRange::kFontGroup, 0, false,
                          orientation);
     return textRun;
 }
 
 gfxTextRun *
 gfxFontGroup::MakeHyphenTextRun(gfxContext *aCtx, uint32_t aAppUnitsPerDevUnit)
 {
     // only use U+2010 if it is supported by the first font in the group;
     // it's better to use ASCII '-' from the primary font than to fall back to
     // U+2010 from some other, possibly poorly-matching face
     static const char16_t hyphen = 0x2010;
-    gfxFont *font = GetFontAt(0);
-    if (font && font->HasCharacter(hyphen)) {
+    gfxFont *font = GetFirstValidFont();
+    if (font->HasCharacter(hyphen)) {
         return MakeTextRun(&hyphen, 1, aCtx, aAppUnitsPerDevUnit,
                            gfxFontGroup::TEXT_IS_PERSISTENT);
     }
 
     static const uint8_t dash = '-';
     return MakeTextRun(&dash, 1, aCtx, aAppUnitsPerDevUnit,
                        gfxFontGroup::TEXT_IS_PERSISTENT);
 }
@@ -2142,17 +2190,25 @@ gfxFontGroup::InitScriptRun(gfxContext *
                                               // within the textrun
                             uint32_t aLength, // length of the script run
                             int32_t aRunScript)
 {
     NS_ASSERTION(aLength > 0, "don't call InitScriptRun for a 0-length run");
     NS_ASSERTION(aTextRun->GetShapingState() != gfxTextRun::eShapingState_Aborted,
                  "don't call InitScriptRun with aborted shaping state");
 
-    gfxFont *mainFont = GetFontAt(0);
+#if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID)
+    // non-linux platforms build the fontlist lazily and include userfonts
+    // so need to confirm the load state of userfonts in the list
+    if (mUserFontSet && mCurrGeneration != mUserFontSet->GetGeneration()) {
+        UpdateUserFonts();
+    }
+#endif
+
+    gfxFont *mainFont = GetFirstValidFont();
 
     uint32_t runStart = 0;
     nsAutoTArray<gfxTextRange,3> fontRanges;
     ComputeRanges(fontRanges, aString, aLength, aRunScript,
                   aTextRun->GetFlags() & gfxTextRunFactory::TEXT_ORIENT_MASK);
     uint32_t numRanges = fontRanges.Length();
 
     for (uint32_t r = 0; r < numRanges; r++) {
@@ -2348,17 +2404,17 @@ gfxFontGroup::GetEllipsisTextRun(int32_t
 {
     if (mCachedEllipsisTextRun &&
         mCachedEllipsisTextRun->GetAppUnitsPerDevUnit() == aAppUnitsPerDevPixel) {
         return mCachedEllipsisTextRun;
     }
 
     // Use a Unicode ellipsis if the font supports it,
     // otherwise use three ASCII periods as fallback.
-    gfxFont* firstFont = GetFontAt(0);
+    gfxFont* firstFont = GetFirstValidFont();
     nsString ellipsis = firstFont->HasCharacter(kEllipsisChar[0])
         ? nsDependentString(kEllipsisChar,
                             ArrayLength(kEllipsisChar) - 1)
         : nsDependentString(kASCIIPeriodsChar,
                             ArrayLength(kASCIIPeriodsChar) - 1);
 
     nsRefPtr<gfxContext> refCtx = aRefContextGetter.GetRefContext();
     Parameters params = {
@@ -2371,62 +2427,105 @@ 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::TryAllFamilyMembers(gfxFontFamily* aFamily, uint32_t aCh)
+gfxFontGroup::FindNonItalicFaceForChar(gfxFontFamily* aFamily, uint32_t aCh)
 {
+    NS_ASSERTION(mStyle.style != NS_FONT_STYLE_NORMAL,
+                 "should only be called in the italic/oblique case");
+
     if (!aFamily->TestCharacterMap(aCh)) {
         return nullptr;
     }
 
-    // Note that we don't need the actual runScript in matchData for
-    // gfxFontFamily::SearchAllFontsForChar, it's only used for the
-    // system-fallback case. So we can just set it to 0 here.
-    GlobalFontMatch matchData(aCh, 0, &mStyle);
-    aFamily->SearchAllFontsForChar(&matchData);
-    gfxFontEntry *fe = matchData.mBestMatch;
-    if (!fe) {
+    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;
     }
 
-    bool needsBold = mStyle.weight >= 600 && !fe->IsBold();
     nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, needsBold);
+    if (!font->Valid()) {
+        return nullptr;
+    }
     return font.forget();
 }
 
+gfxFloat
+gfxFontGroup::GetUnderlineOffset()
+{
+    if (mUnderlineOffset == UNDERLINE_OFFSET_NOT_SET) {
+        // if the fontlist contains a bad underline font, make the underline
+        // offset the min of the first valid font and bad font underline offsets
+        uint32_t len = mFonts.Length();
+        for (uint32_t i = 0; i < len; i++) {
+            FamilyFace& ff = mFonts[i];
+            if (!ff.IsUserFont() && ff.Family() &&
+                ff.Family()->IsBadUnderlineFamily()) {
+                nsRefPtr<gfxFont> font = GetFontAt(i);
+                if (!font) {
+                    continue;
+                }
+                gfxFloat bad = font->GetMetrics().underlineOffset;
+                gfxFloat first =
+                    GetFirstValidFont()->GetMetrics().underlineOffset;
+                mUnderlineOffset = std::min(first, bad);
+                return mUnderlineOffset;
+            }
+        }
+
+        // no bad underline fonts, use the first valid font's metric
+        mUnderlineOffset = GetFirstValidFont()->GetMetrics().underlineOffset;
+    }
+
+    return mUnderlineOffset;
+}
+
 already_AddRefed<gfxFont>
 gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh,
                               int32_t aRunScript, gfxFont *aPrevMatchedFont,
                               uint8_t *aMatchType)
 {
     // To optimize common cases, try the first font in the font-group
     // before going into the more detailed checks below
     uint32_t nextIndex = 0;
     bool isJoinControl = gfxFontUtils::IsJoinControl(aCh);
     bool wasJoinCauser = gfxFontUtils::IsJoinCauser(aPrevCh);
     bool isVarSelector = gfxFontUtils::IsVarSelector(aCh);
 
     if (!isJoinControl && !wasJoinCauser && !isVarSelector) {
-        nsRefPtr<gfxFont> firstFont = mFonts[0].Font();
-        if (firstFont->HasCharacter(aCh)) {
-            *aMatchType = gfxTextRange::kFontGroup;
-            return firstFont.forget();
+        nsRefPtr<gfxFont> firstFont = GetFontAt(0);
+        if (firstFont) {
+            if (firstFont->HasCharacter(aCh)) {
+                *aMatchType = gfxTextRange::kFontGroup;
+                return firstFont.forget();
+            }
+
+            // If italic, test the regular face to see if it supports character.
+            // Only do this for platform fonts, not userfonts.
+            if (mStyle.style != NS_FONT_STYLE_NORMAL &&
+                !firstFont->GetFontEntry()->IsUserFont()) {
+                nsRefPtr<gfxFont> font =
+                    FindNonItalicFaceForChar(mFonts[0].Family(), aCh);
+                if (font) {
+                    *aMatchType = gfxTextRange::kFontGroup;
+                    return font.forget();
+                }
+            }
         }
-        // It's possible that another font in the family (e.g. regular face,
-        // where the requested style was italic) will support the character
-        nsRefPtr<gfxFont> font = TryAllFamilyMembers(mFonts[0].Family(), aCh);
-        if (font) {
-            *aMatchType = gfxTextRange::kFontGroup;
-            return font.forget();
-        }
+
         // we don't need to check the first font again below
         ++nextIndex;
     }
 
     if (aPrevMatchedFont) {
         // Don't switch fonts for control characters, regardless of
         // whether they are present in the current font, as they won't
         // actually be rendered (see bug 716229)
@@ -2454,28 +2553,69 @@ gfxFontGroup::FindFontForChar(uint32_t a
             nsRefPtr<gfxFont> ret = aPrevMatchedFont;
             return ret.forget();
         }
         // VS alone. it's meaningless to search different fonts
         return nullptr;
     }
 
     // 1. check remaining fonts in the font group
-    uint32_t fontListLength = FontListLength();
+    uint32_t fontListLength = mFonts.Length();
     for (uint32_t i = nextIndex; i < fontListLength; i++) {
-        nsRefPtr<gfxFont> font = mFonts[i].Font();
-        if (font->HasCharacter(aCh)) {
-            *aMatchType = gfxTextRange::kFontGroup;
-            return font.forget();
+        FamilyFace& ff = mFonts[i];
+        if (ff.IsInvalid() || ff.IsLoading()) {
+            continue;
         }
 
-        font = TryAllFamilyMembers(mFonts[i].Family(), aCh);
-        if (font) {
+        nsRefPtr<gfxFont> font;
+
+        // test the font entry, build font if needed
+        gfxFontEntry *fe = ff.FontEntry();
+
+        if (fe->mIsUserFontContainer) {
+            // for userfonts, need to test the cmap of the platform font entry
+            gfxUserFontEntry* ufe = static_cast<gfxUserFontEntry*>(fe);
+            if (ufe->LoadState() == gfxUserFontEntry::STATUS_NOT_LOADED) {
+                ufe->Load();
+                if (ufe->WaitForUserFont()) {
+                    mSkipDrawing = true;
+                }
+            }
+            gfxFontEntry* pfe = ufe->GetPlatformFontEntry();
+            if (pfe && pfe->HasCharacter(aCh)) {
+                font = GetFontAt(i);
+                if (font) {
+                    *aMatchType = gfxTextRange::kFontGroup;
+                    return font.forget();
+                }
+            }
+        } else if (fe->HasCharacter(aCh)) {
+            font = GetFontAt(i);
+            if (font) {
+                *aMatchType = gfxTextRange::kFontGroup;
+                return font.forget();
+            }
+        }
+
+        // If italic, test the regular face to see if it supports the character.
+        // Only do this for platform fonts, not userfonts.
+        if (mStyle.style != NS_FONT_STYLE_NORMAL && !ff.IsUserFont()) {
+            font = FindNonItalicFaceForChar(mFonts[i].Family(), aCh);
+            if (font) {
+                *aMatchType = gfxTextRange::kFontGroup;
+                return font.forget();
+            }
+        }
+    }
+
+    if (fontListLength == 0) {
+        nsRefPtr<gfxFont> defaultFont = GetDefaultFont();
+        if (defaultFont->HasCharacter(aCh)) {
             *aMatchType = gfxTextRange::kFontGroup;
-            return font.forget();
+            return defaultFont.forget();
         }
     }
 
     // if character is in Private Use Area, don't do matching against pref or system fonts
     if ((aCh >= 0xE000  && aCh <= 0xF8FF) || (aCh >= 0xF0000 && aCh <= 0x10FFFD))
         return nullptr;
 
     // 2. search pref fonts
@@ -2497,17 +2637,17 @@ gfxFontGroup::FindFontForChar(uint32_t a
     if (aRunScript == HB_SCRIPT_UNKNOWN) {
         return nullptr;
     }
 
     // for known "space" characters, don't do a full system-fallback search;
     // we'll synthesize appropriate-width spaces instead of missing-glyph boxes
     if (GetGeneralCategory(aCh) ==
             HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR &&
-        GetFontAt(0)->SynthesizeSpaceWidth(aCh) >= 0.0)
+        GetFirstValidFont()->SynthesizeSpaceWidth(aCh) >= 0.0)
     {
         return nullptr;
     }
 
     // -- otherwise look for other stuff
     *aMatchType = gfxTextRange::kSystemFallback;
     font = WhichSystemFontSupportsChar(aCh, aRunScript);
     return font.forget();
@@ -2522,17 +2662,17 @@ void gfxFontGroup::ComputeRanges(nsTArra
     NS_ASSERTION(aLength > 0, "don't call ComputeRanges for zero-length text");
 
     uint32_t prevCh = 0;
     int32_t lastRangeIndex = -1;
 
     // initialize prevFont to the group's primary font, so that this will be
     // used for string-initial control chars, etc rather than risk hitting font
     // fallback for these (bug 716229)
-    gfxFont *prevFont = GetFontAt(0);
+    gfxFont *prevFont = GetFirstValidFont();
 
     // if we use the initial value of prevFont, we treat this as a match from
     // the font group; fixes bug 978313
     uint8_t matchType = gfxTextRange::kFontGroup;
 
     for (uint32_t i = 0; i < aLength; i++) {
 
         const uint32_t origI = i; // save off in case we increase for surrogate
@@ -2625,40 +2765,81 @@ gfxFontGroup::GetUserFontSet()
 void 
 gfxFontGroup::SetUserFontSet(gfxUserFontSet *aUserFontSet)
 {
     if (aUserFontSet == mUserFontSet) {
         return;
     }
     mUserFontSet = aUserFontSet;
     mCurrGeneration = GetGeneration() - 1;
-    UpdateFontList();
+    UpdateUserFonts();
 }
 
 uint64_t
 gfxFontGroup::GetGeneration()
 {
     if (!mUserFontSet)
         return 0;
     return mUserFontSet->GetGeneration();
 }
 
-// note: gfxPangoFontGroup overrides UpdateFontList, such that
+uint64_t
+gfxFontGroup::GetRebuildGeneration()
+{
+    if (!mUserFontSet)
+        return 0;
+    return mUserFontSet->GetRebuildGeneration();
+}
+
+// note: gfxPangoFontGroup overrides UpdateUserFonts, such that
 //       BuildFontList is never used
 void
-gfxFontGroup::UpdateFontList()
+gfxFontGroup::UpdateUserFonts()
 {
-    if (mCurrGeneration != GetGeneration()) {
-        // xxx - can probably improve this to detect when all fonts were found, so no need to update list
+    if (mCurrGeneration < GetRebuildGeneration()) {
+        // fonts in userfont set changed, need to redo the fontlist
         mFonts.Clear();
         mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET;
         mSkipDrawing = false;
         BuildFontList();
         mCurrGeneration = GetGeneration();
         mCachedEllipsisTextRun = nullptr;
+    } else if (mCurrGeneration != GetGeneration()) {
+        // load state change occurred, verify load state and validity of fonts
+        mSkipDrawing = false;
+        mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET;
+        mCachedEllipsisTextRun = nullptr;
+
+        uint32_t len = mFonts.Length();
+        for (uint32_t i = 0; i < len; i++) {
+            FamilyFace& ff = mFonts[i];
+            if (ff.Font() || !ff.IsUserFont()) {
+                continue;
+            }
+
+            // confirm status
+            gfxUserFontEntry *ufe =
+                static_cast<gfxUserFontEntry*>(mFonts[i].FontEntry());
+            gfxUserFontEntry::UserFontLoadState state = ufe->LoadState();
+            switch (state) {
+                case gfxUserFontEntry::STATUS_LOADING:
+                    ff.SetLoading(true);
+                    break;
+                case gfxUserFontEntry::STATUS_FAILED:
+                    ff.SetInvalid();
+                    // fall-thru to the default case
+                default:
+                    ff.SetLoading(false);
+            }
+            if (ufe->WaitForUserFont()) {
+                mSkipDrawing = true;
+            }
+        }
+
+        mCurrGeneration = GetGeneration();
     }
 }
 
 struct PrefFontCallbackData {
     explicit PrefFontCallbackData(nsTArray<nsRefPtr<gfxFontFamily> >& aFamiliesArray)
         : mPrefFamilies(aFamiliesArray)
     {}
 
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -718,68 +718,33 @@ private:
 
     // shaping state for handling variant fallback features
     // such as subscript/superscript variant glyphs
     ShapingState      mShapingState;
 };
 
 class gfxFontGroup : public gfxTextRunFactory {
 public:
-    class FamilyFace {
-    public:
-        FamilyFace() { }
-
-        FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont)
-            : mFamily(aFamily), mFont(aFont)
-        {
-            NS_ASSERTION(aFont, "font pointer must not be null");
-            NS_ASSERTION(!aFamily ||
-                         aFamily->ContainsFace(aFont->GetFontEntry()),
-                         "font is not a member of the given family");
-        }
-
-        gfxFontFamily* Family() const { return mFamily.get(); }
-        gfxFont* Font() const { return mFont.get(); }
-
-    private:
-        nsRefPtr<gfxFontFamily> mFamily;
-        nsRefPtr<gfxFont>       mFont;
-    };
-
     static void Shutdown(); // platform must call this to release the languageAtomService
 
     gfxFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
                  const gfxFontStyle *aStyle,
                  gfxUserFontSet *aUserFontSet = nullptr);
 
     virtual ~gfxFontGroup();
 
-    virtual gfxFont *GetFontAt(int32_t i) {
-        // If it turns out to be hard for all clients that cache font
-        // groups to call UpdateFontList at appropriate times, we could
-        // instead consider just calling UpdateFontList from someplace
-        // more central (such as here).
-        NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
-                     "Whoever was caching this font group should have "
-                     "called UpdateFontList on it");
-        NS_ASSERTION(mFonts.Length() > uint32_t(i) && mFonts[i].Font(), 
-                     "Requesting a font index that doesn't exist");
-
-        return mFonts[i].Font();
-    }
+    // Returns first valid font in the fontlist or default font.
+    // Initiates userfont loads if userfont not loaded
+    virtual gfxFont* GetFirstValidFont();
 
     // Returns the first font in the font-group that has an OpenType MATH table,
     // or null if no such font is available. The GetMathConstant methods may be
     // called on the returned font.
     gfxFont *GetFirstMathFont();
 
-    uint32_t FontListLength() const {
-        return mFonts.Length();
-    }
-
     const gfxFontStyle *GetStyle() const { return &mStyle; }
 
     virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
 
     /**
      * The listed characters should be treated as invisible and zero-width
      * when creating textruns.
      */
@@ -840,25 +805,22 @@ public:
     /**
      * Check whether a given font (specified by its gfxFontEntry)
      * is already in the fontgroup's list of actual fonts
      */
     bool HasFont(const gfxFontEntry *aFontEntry);
 
     // This returns the preferred underline for this font group.
     // Some CJK fonts have wrong underline offset in its metrics.
-    // If this group has such "bad" font, each platform's gfxFontGroup initialized mUnderlineOffset.
-    // The value should be lower value of first font's metrics and the bad font's metrics.
-    // Otherwise, this returns from first font's metrics.
+    // If this group has such "bad" font, each platform's gfxFontGroup
+    // initialized mUnderlineOffset. The value should be lower value of
+    // first font's metrics and the bad font's metrics. Otherwise, this
+    // returns from first font's metrics.
     enum { UNDERLINE_OFFSET_NOT_SET = INT16_MAX };
-    virtual gfxFloat GetUnderlineOffset() {
-        if (mUnderlineOffset == UNDERLINE_OFFSET_NOT_SET)
-            mUnderlineOffset = GetFontAt(0)->GetMetrics().underlineOffset;
-        return mUnderlineOffset;
-    }
+    virtual gfxFloat GetUnderlineOffset();
 
     virtual already_AddRefed<gfxFont>
         FindFontForChar(uint32_t ch, uint32_t prevCh, int32_t aRunScript,
                         gfxFont *aPrevMatchedFont,
                         uint8_t *aMatchType);
 
     // search through pref fonts for a character, return nullptr if no matching pref font
     virtual already_AddRefed<gfxFont> WhichPrefFontSupportsChar(uint32_t aCh);
@@ -874,53 +836,191 @@ public:
     gfxUserFontSet* GetUserFontSet();
 
     // With downloadable fonts, the composition of the font group can change as fonts are downloaded
     // for each change in state of the user font set, the generation value is bumped to avoid picking up
     // previously created text runs in the text run word cache.  For font groups based on stylesheets
     // with no @font-face rule, this always returns 0.
     uint64_t GetGeneration();
 
+    // generation of the latest fontset rebuild, 0 when no fontset present
+    uint64_t GetRebuildGeneration();
+
     // used when logging text performance
     gfxTextPerfMetrics *GetTextPerfMetrics() { return mTextPerf; }
     void SetTextPerfMetrics(gfxTextPerfMetrics *aTextPerf) { mTextPerf = aTextPerf; }
 
-    // This will call UpdateFontList() if the user font set is changed.
+    // This will call UpdateUserFonts() if the user font set is changed.
     void SetUserFontSet(gfxUserFontSet *aUserFontSet);
 
     // If there is a user font set, check to see whether the font list or any
     // caches need updating.
-    virtual void UpdateFontList();
+    virtual void UpdateUserFonts();
 
     bool ShouldSkipDrawing() const {
         return mSkipDrawing;
     }
 
     class LazyReferenceContextGetter {
     public:
       virtual already_AddRefed<gfxContext> GetRefContext() = 0;
     };
     // The gfxFontGroup keeps ownership of this textrun.
     // It is only guaranteed to exist until the next call to GetEllipsisTextRun
     // (which might use a different appUnitsPerDev value) for the font group,
-    // or until UpdateFontList is called, or the fontgroup is destroyed.
+    // or until UpdateUserFonts is called, or the fontgroup is destroyed.
     // Get it/use it/forget it :) - don't keep a reference that might go stale.
     gfxTextRun* GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel,
                                    LazyReferenceContextGetter& aRefContextGetter);
 
     // helper method for resolving generic font families
     static void
     ResolveGenericFontNames(mozilla::FontFamilyType aGenericType,
                             nsIAtom *aLanguage,
                             nsTArray<nsString>& aGenericFamilies);
 
 protected:
+    class FamilyFace {
+    public:
+        FamilyFace() : mFamily(nullptr), mFontEntry(nullptr),
+                       mNeedsBold(false), mFontCreated(false),
+                       mLoading(false), mInvalid(false)
+        { }
+
+        FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont)
+            : mFamily(aFamily), mNeedsBold(false), mFontCreated(true),
+              mLoading(false), mInvalid(false)
+        {
+            NS_ASSERTION(aFont, "font pointer must not be null");
+            NS_ASSERTION(!aFamily ||
+                         aFamily->ContainsFace(aFont->GetFontEntry()),
+                         "font is not a member of the given family");
+            mFont = aFont;
+            NS_ADDREF(aFont);
+        }
+
+        FamilyFace(gfxFontFamily* aFamily, gfxFontEntry* aFontEntry,
+                   bool aNeedsBold)
+            : mFamily(aFamily), mNeedsBold(aNeedsBold), mFontCreated(false),
+              mLoading(false), mInvalid(false)
+        {
+            NS_ASSERTION(aFontEntry, "font entry pointer must not be null");
+            NS_ASSERTION(!aFamily ||
+                         aFamily->ContainsFace(aFontEntry),
+                         "font is not a member of the given family");
+            mFontEntry = aFontEntry;
+            NS_ADDREF(aFontEntry);
+        }
+
+        FamilyFace(const FamilyFace& aOtherFamilyFace)
+            : mFamily(aOtherFamilyFace.mFamily),
+              mNeedsBold(aOtherFamilyFace.mNeedsBold),
+              mFontCreated(aOtherFamilyFace.mFontCreated),
+              mLoading(aOtherFamilyFace.mLoading),
+              mInvalid(aOtherFamilyFace.mInvalid)
+        {
+            if (mFontCreated) {
+                mFont = aOtherFamilyFace.mFont;
+                NS_ADDREF(mFont);
+            } else {
+                mFontEntry = aOtherFamilyFace.mFontEntry;
+                NS_IF_ADDREF(mFontEntry);
+            }
+        }
+
+        ~FamilyFace()
+        {
+            if (mFontCreated) {
+                NS_RELEASE(mFont);
+            } else {
+                NS_IF_RELEASE(mFontEntry);
+            }
+        }
+
+        FamilyFace& operator=(const FamilyFace& aOther)
+        {
+            if (mFontCreated) {
+                NS_RELEASE(mFont);
+            } else {
+                NS_IF_RELEASE(mFontEntry);
+            }
+
+            mFamily = aOther.mFamily;
+            mNeedsBold = aOther.mNeedsBold;
+            mFontCreated = aOther.mFontCreated;
+            mLoading = aOther.mLoading;
+            mInvalid = aOther.mInvalid;
+
+            if (mFontCreated) {
+                mFont = aOther.mFont;
+                NS_ADDREF(mFont);
+            } else {
+                mFontEntry = aOther.mFontEntry;
+                NS_IF_ADDREF(mFontEntry);
+            }
+
+            return *this;
+        }
+
+        gfxFontFamily* Family() const { return mFamily.get(); }
+        gfxFont* Font() const {
+            return mFontCreated ? mFont : nullptr;
+        }
+
+        gfxFontEntry* FontEntry() const {
+            return mFontCreated ? mFont->GetFontEntry() : mFontEntry;
+        }
+
+        bool NeedsBold() const { return mNeedsBold; }
+        bool IsUserFont() const {
+            return FontEntry()->mIsUserFontContainer;
+        }
+        bool IsLoading() const { return mLoading; }
+        bool IsInvalid() const { return mInvalid; }
+        void SetLoading(bool aIsLoading) { mLoading = aIsLoading; }
+        void SetInvalid() { mInvalid = true; }
+
+        void SetFont(gfxFont* aFont)
+        {
+            NS_ASSERTION(aFont, "font pointer must not be null");
+            NS_ADDREF(aFont);
+            if (mFontCreated) {
+                NS_RELEASE(mFont);
+            } else {
+                NS_IF_RELEASE(mFontEntry);
+            }
+            mFont = aFont;
+            mFontCreated = true;
+        }
+
+    private:
+        nsRefPtr<gfxFontFamily> mFamily;
+        // either a font or a font entry exists
+        union {
+            gfxFont*            mFont;
+            gfxFontEntry*       mFontEntry;
+        };
+        bool                    mNeedsBold   : 1;
+        bool                    mFontCreated : 1;
+        bool                    mLoading     : 1;
+        bool                    mInvalid     : 1;
+    };
+
+    // List of font families, either named or generic.
+    // Generic names map to system pref fonts based on language.
     mozilla::FontFamilyList mFamilyList;
+
+    // Fontlist containing a font entry for each family found. gfxFont objects
+    // are created as needed and userfont loads are initiated when needed.
+    // Code should be careful about addressing this array directly.
+    nsTArray<FamilyFace> mFonts;
+
+    nsRefPtr<gfxFont> mDefaultFont;
     gfxFontStyle mStyle;
-    nsTArray<FamilyFace> mFonts;
+
     gfxFloat mUnderlineOffset;
     gfxFloat mHyphenWidth;
 
     nsRefPtr<gfxUserFontSet> mUserFontSet;
     uint64_t mCurrGeneration;  // track the current user font set generation, rebuild font list if needed
 
     gfxTextPerfMetrics *mTextPerf;
 
@@ -946,16 +1046,24 @@ protected:
     gfxTextRun *MakeEmptyTextRun(const Parameters *aParams, uint32_t aFlags);
     gfxTextRun *MakeSpaceTextRun(const Parameters *aParams, uint32_t aFlags);
     gfxTextRun *MakeBlankTextRun(uint32_t aLength,
                                  const Parameters *aParams, uint32_t aFlags);
 
     // Initialize the list of fonts
     void BuildFontList();
 
+    // Get the font at index i within the fontlist.
+    // Will initiate userfont load if not already loaded.
+    // May return null if userfont not loaded or if font invalid
+    virtual gfxFont* GetFontAt(int32_t i);
+
+    // will always return a font or force a shutdown
+    gfxFont* GetDefaultFont();
+
     // Init this font group's font metrics. If there no bad fonts, you don't need to call this.
     // But if there are one or more bad fonts which have bad underline offset,
     // you should call this with the *first* bad font.
     void InitMetricsForBadFont(gfxFont* aBadFont);
 
     // Set up the textrun glyphs for an entire text run:
     // find script runs, and then call InitScriptRun for each
     template<typename T>
@@ -970,20 +1078,21 @@ protected:
     void InitScriptRun(gfxContext *aContext,
                        gfxTextRun *aTextRun,
                        const T *aString,
                        uint32_t aScriptRunStart,
                        uint32_t aScriptRunEnd,
                        int32_t aRunScript);
 
     // Helper for font-matching:
-    // see if aCh is supported in any of the faces from aFamily;
-    // if so return the best style match, else return null.
-    already_AddRefed<gfxFont> TryAllFamilyMembers(gfxFontFamily* aFamily,
-                                                  uint32_t aCh);
+    // 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);
 
     // helper methods for looking up fonts
 
     // iterate over the fontlist, lookup names and expand generics
     void EnumerateFontList(nsIAtom *aLanguage, void *aClosure = nullptr);
 
     // expand a generic to a list of specific names based on prefs
     void FindGenericFonts(mozilla::FontFamilyType aGenericType,
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -115,17 +115,18 @@ gfxUserFontEntry::gfxUserFontEntry(gfxUs
              const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
              uint32_t aWeight,
              int32_t aStretch,
              uint32_t aItalicStyle,
              const nsTArray<gfxFontFeature>& aFeatureSettings,
              uint32_t aLanguageOverride,
              gfxSparseBitSet* aUnicodeRanges)
     : gfxFontEntry(NS_LITERAL_STRING("userfont")),
-      mLoadingState(NOT_LOADING),
+      mUserFontLoadState(STATUS_NOT_LOADED),
+      mFontDataLoadingState(NOT_LOADING),
       mUnsupportedFormat(false),
       mLoader(nullptr),
       mFontSet(aFontSet)
 {
     mIsUserFontContainer = true;
     mSrcList = aFontFaceSrcList;
     mSrcIndex = 0;
     mWeight = aWeight;
@@ -305,26 +306,31 @@ CopyWOFFMetadata(const uint8_t* aFontDat
     }
     if (!aMetadata->SetLength(woff->metaCompLen)) {
         return;
     }
     memcpy(aMetadata->Elements(), aFontData + metaOffset, metaCompLen);
     *aMetaOrigLen = woff->metaOrigLen;
 }
 
-gfxUserFontEntry::LoadStatus
-gfxUserFontEntry::LoadNext()
+void
+gfxUserFontEntry::LoadNextSrc()
 {
     uint32_t numSrc = mSrcList.Length();
 
     NS_ASSERTION(mSrcIndex < numSrc,
                  "already at the end of the src list for user font");
+    NS_ASSERTION((mUserFontLoadState == STATUS_NOT_LOADED ||
+                  mUserFontLoadState == STATUS_LOADING) &&
+                 mFontDataLoadingState < LOADING_FAILED,
+                 "attempting to load a font that has either completed or failed");
 
-    if (mLoadingState == NOT_LOADING) {
-        mLoadingState = LOADING_STARTED;
+    if (mUserFontLoadState == STATUS_NOT_LOADED) {
+        SetLoadState(STATUS_LOADING);
+        mFontDataLoadingState = LOADING_STARTED;
         mUnsupportedFormat = false;
     } else {
         // we were already loading; move to the next source,
         // but don't reset state - if we've already timed out,
         // that counts against the new download
         mSrcIndex++;
     }
 
@@ -351,17 +357,18 @@ gfxUserFontEntry::LoadNext()
                 fe->mFeatureSettings.AppendElements(mFeatureSettings);
                 fe->mLanguageOverride = mLanguageOverride;
                 fe->mFamilyName = mFamilyName;
                 // For src:local(), we don't care whether the request is from
                 // a private window as there's no issue of caching resources;
                 // local fonts are just available all the time.
                 StoreUserFontData(fe, false, nsString(), nullptr, 0);
                 mPlatformFontEntry = fe;
-                return STATUS_LOADED;
+                SetLoadState(STATUS_LOADED);
+                return;
             } else {
                 LOG(("fontset (%p) [src %d] failed local: (%s) for (%s)\n",
                      mFontSet, mSrcIndex,
                      NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
                      NS_ConvertUTF16toUTF8(mFamilyName).get()));
             }
         }
 
@@ -380,17 +387,18 @@ gfxUserFontEntry::LoadNext()
                         // see if we have an existing entry for this source
                         gfxFontEntry* fe = gfxUserFontSet::
                             UserFontCache::GetFont(currSrc.mURI,
                                                    principal,
                                                    this,
                                                    mFontSet->GetPrivateBrowsing());
                         if (fe) {
                             mPlatformFontEntry = fe;
-                            return STATUS_LOADED;
+                            SetLoadState(STATUS_LOADED);
+                            return;
                         }
                     }
 
                     // record the principal returned by CheckFontLoad,
                     // for use when creating a channel
                     // and when caching the loaded entry
                     mPrincipal = principal;
 
@@ -403,18 +411,19 @@ gfxUserFontEntry::LoadNext()
                         uint8_t* buffer = nullptr;
                         uint32_t bufferLength = 0;
 
                         // sync load font immediately
                         rv = mFontSet->SyncLoadFontData(this, &currSrc, buffer,
                                                         bufferLength);
 
                         if (NS_SUCCEEDED(rv) &&
-                            LoadFont(buffer, bufferLength)) {
-                            return STATUS_LOADED;
+                            LoadPlatformFont(buffer, bufferLength)) {
+                            SetLoadState(STATUS_LOADED);
+                            return;
                         } else {
                             mFontSet->LogMessage(this,
                                                  "font load failed",
                                                  nsIScriptError::errorFlag,
                                                  rv);
                         }
 
                     } else {
@@ -427,17 +436,17 @@ gfxUserFontEntry::LoadNext()
                             if (LOG_ENABLED()) {
                                 nsAutoCString fontURI;
                                 currSrc.mURI->GetSpec(fontURI);
                                 LOG(("userfonts (%p) [src %d] loading uri: (%s) for (%s)\n",
                                      mFontSet, mSrcIndex, fontURI.get(),
                                      NS_ConvertUTF16toUTF8(mFamilyName).get()));
                             }
 #endif
-                            return STATUS_LOADING;
+                            return;
                         } else {
                             mFontSet->LogMessage(this,
                                                  "download failed",
                                                  nsIScriptError::errorFlag,
                                                  rv);
                         }
                     }
                 } else {
@@ -457,24 +466,34 @@ gfxUserFontEntry::LoadNext()
     if (mUnsupportedFormat) {
         mFontSet->LogMessage(this, "no supported format found",
                              nsIScriptError::warningFlag);
     }
 
     // all src's failed; mark this entry as unusable (so fallback will occur)
     LOG(("userfonts (%p) failed all src for (%s)\n",
         mFontSet, NS_ConvertUTF16toUTF8(mFamilyName).get()));
-    mLoadingState = LOADING_FAILED;
+    mFontDataLoadingState = LOADING_FAILED;
+    SetLoadState(STATUS_FAILED);
+}
 
-    return STATUS_END_OF_LIST;
+void
+gfxUserFontEntry::SetLoadState(UserFontLoadState aLoadState)
+{
+    mUserFontLoadState = aLoadState;
 }
 
 bool
-gfxUserFontEntry::LoadFont(const uint8_t* aFontData, uint32_t &aLength)
+gfxUserFontEntry::LoadPlatformFont(const uint8_t* aFontData, uint32_t& aLength)
 {
+    NS_ASSERTION((mUserFontLoadState == STATUS_NOT_LOADED ||
+                  mUserFontLoadState == STATUS_LOADING) &&
+                 mFontDataLoadingState < LOADING_FAILED,
+                 "attempting to load a font that has either completed or failed");
+
     gfxFontEntry* fe = nullptr;
 
     gfxUserFontType fontType =
         gfxFontUtils::DetermineFontDataType(aFontData, aLength);
 
     // Unwrap/decompress/sanitize or otherwise munge the downloaded data
     // to make a usable sfnt structure.
 
@@ -536,16 +555,17 @@ gfxUserFontEntry::LoadFont(const uint8_t
             mSrcList[mSrcIndex].mURI->GetSpec(fontURI);
             LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n",
                  this, mSrcIndex, fontURI.get(),
                  NS_ConvertUTF16toUTF8(mFamilyName).get(),
                  uint32_t(mFontSet->mGeneration)));
         }
 #endif
         mPlatformFontEntry = fe;
+        SetLoadState(STATUS_LOADED);
         gfxUserFontSet::UserFontCache::CacheFont(fe);
     } else {
 #ifdef PR_LOGGING
         if (LOG_ENABLED()) {
             nsAutoCString fontURI;
             mSrcList[mSrcIndex].mURI->GetSpec(fontURI);
             LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s)"
                  " error making platform font\n",
@@ -557,30 +577,39 @@ gfxUserFontEntry::LoadFont(const uint8_t
 
     // The downloaded data can now be discarded; the font entry is using the
     // sanitized copy
     NS_Free((void*)aFontData);
 
     return fe != nullptr;
 }
 
+void
+gfxUserFontEntry::Load()
+{
+    if (mUserFontLoadState == STATUS_NOT_LOADED) {
+        LoadNextSrc();
+    }
+}
+
 // This is called when a font download finishes.
 // Ownership of aFontData passes in here, and the font set must
 // ensure that it is eventually deleted via NS_Free().
 bool
-gfxUserFontEntry::OnLoadComplete(const uint8_t* aFontData, uint32_t aLength,
-                                 nsresult aDownloadStatus)
+gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData,
+                                           uint32_t aLength,
+                                           nsresult aDownloadStatus)
 {
     // forget about the loader, as we no longer potentially need to cancel it
     // if the entry is obsoleted
     mLoader = nullptr;
 
     // download successful, make platform font using font data
     if (NS_SUCCEEDED(aDownloadStatus)) {
-        bool loaded = LoadFont(aFontData, aLength);
+        bool loaded = LoadPlatformFont(aFontData, aLength);
         aFontData = nullptr;
 
         if (loaded) {
             mFontSet->IncrementGeneration();
             return true;
         }
 
     } else {
@@ -590,30 +619,30 @@ gfxUserFontEntry::OnLoadComplete(const u
                              aDownloadStatus);
     }
 
     if (aFontData) {
         moz_free((void*)aFontData);
     }
 
     // error occurred, load next src
-    LoadNext();
+    LoadNextSrc();
 
     // We ignore the status returned by LoadNext();
     // even if loading failed, we need to bump the font-set generation
     // and return true in order to trigger reflow, so that fallback
     // will be used where the text was "masked" by the pending download
     mFontSet->IncrementGeneration();
     return true;
 }
 
 gfxUserFontSet::gfxUserFontSet()
     : mFontFamilies(4), mLocalRulesUsed(false)
 {
-    IncrementGeneration();
+    IncrementGeneration(true);
     gfxPlatformFontList* fp = gfxPlatformFontList::PlatformFontList();
     if (fp) {
         fp->AddUserFontSet(this);
     }
 }
 
 gfxUserFontSet::~gfxUserFontSet()
 {
@@ -739,74 +768,67 @@ gfxUserFontSet::AddFontFace(const nsAStr
              this, NS_ConvertUTF16toUTF8(aFamilyName).get(), aUserFontEntry));
     }
 #endif
 }
 
 gfxUserFontEntry*
 gfxUserFontSet::FindUserFontEntry(gfxFontFamily* aFamily,
                                   const gfxFontStyle& aFontStyle,
-                                  bool& aNeedsBold,
-                                  bool& aWaitForUserFont)
+                                  bool& aNeedsBold)
 {
-    aWaitForUserFont = false;
     gfxUserFontFamily* family = static_cast<gfxUserFontFamily*>(aFamily);
-
     gfxFontEntry* fe = family->FindFontForStyle(aFontStyle, aNeedsBold);
 
     NS_ASSERTION(!fe || fe->mIsUserFontContainer,
                  "should only have userfont entries in userfont families");
 
-    // if not a userfont entry, font has already been loaded
     if (!fe || !fe->mIsUserFontContainer) {
         return nullptr;
     }
 
     gfxUserFontEntry* userFontEntry = static_cast<gfxUserFontEntry*> (fe);
+    return userFontEntry;
+}
 
+gfxUserFontEntry*
+gfxUserFontSet::FindUserFontEntryAndLoad(gfxFontFamily* aFamily,
+                                         const gfxFontStyle& aFontStyle,
+                                         bool& aNeedsBold,
+                                         bool& aWaitForUserFont)
+{
+    aWaitForUserFont = false;
+    gfxUserFontEntry* userFontEntry =
+        FindUserFontEntry(aFamily, aFontStyle, aNeedsBold);
+
+    if (!userFontEntry) {
+        return nullptr;
+    }
+
+    // start the load if it hasn't been loaded
+    userFontEntry->Load();
     if (userFontEntry->GetPlatformFontEntry()) {
         return userFontEntry;
     }
 
-    // if currently loading, return null for now
-    if (userFontEntry->mLoadingState > gfxUserFontEntry::NOT_LOADING) {
-        aWaitForUserFont =
-            (userFontEntry->mLoadingState < gfxUserFontEntry::LOADING_SLOWLY);
-        return nullptr;
-    }
-
-    // hasn't been loaded yet, start the load process
-    gfxUserFontEntry::LoadStatus status;
-
-    // NOTE that if all sources in the entry fail, this will delete userFontEntry,
-    // so we cannot use it again if status==STATUS_END_OF_LIST
-    status = userFontEntry->LoadNext();
-
-    // if the load succeeded immediately, return
-    if (status == gfxUserFontEntry::STATUS_LOADED) {
-        return userFontEntry;
-    }
-
-    // check whether we should wait for load to complete before painting
-    // a fallback font -- but not if all sources failed (bug 633500)
-    aWaitForUserFont = (status != gfxUserFontEntry::STATUS_END_OF_LIST) &&
-        (userFontEntry->mLoadingState < gfxUserFontEntry::LOADING_SLOWLY);
-
-    // if either loading or an error occurred, return null
+    aWaitForUserFont = userFontEntry->WaitForUserFont();
     return nullptr;
 }
 
 void
-gfxUserFontSet::IncrementGeneration()
+gfxUserFontSet::IncrementGeneration(bool aIsRebuild)
 {
     // add one, increment again if zero
     ++sFontSetGeneration;
     if (sFontSetGeneration == 0)
        ++sFontSetGeneration;
     mGeneration = sFontSetGeneration;
+    if (aIsRebuild) {
+        mRebuildGeneration = mGeneration;
+    }
 }
 
 void
 gfxUserFontSet::RebuildLocalRules()
 {
     if (mLocalRulesUsed) {
         DoRebuildUserFontSet();
     }
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -184,41 +184,54 @@ public:
     {
         return LookupFamily(aFamilyName) != nullptr;
     }
 
     // Look up and return the gfxUserFontFamily in mFontFamilies with
     // the given name
     gfxUserFontFamily* LookupFamily(const nsAString& aName) const;
 
+    // Lookup a userfont entry for a given style, loaded or not.
+    // aFamily must be a family returned by our LookupFamily method.
+    // If only invalid fonts in family, returns null.
+    gfxUserFontEntry* FindUserFontEntry(gfxFontFamily* aFamily,
+                                        const gfxFontStyle& aFontStyle,
+                                        bool& aNeedsBold);
+
     // Lookup a font entry for a given style, returns null if not loaded.
     // aFamily must be a family returned by our LookupFamily method.
-    gfxUserFontEntry* FindUserFontEntry(gfxFontFamily* aFamily,
-                                        const gfxFontStyle& aFontStyle,
-                                        bool& aNeedsBold,
-                                        bool& aWaitForUserFont);
+    // (only used by gfxPangoFontGroup for now)
+    gfxUserFontEntry* FindUserFontEntryAndLoad(gfxFontFamily* aFamily,
+                                               const gfxFontStyle& aFontStyle,
+                                               bool& aNeedsBold,
+                                               bool& aWaitForUserFont);
 
     // check whether the given source is allowed to be loaded;
     // returns the Principal (for use in the key when caching the loaded font),
     // and whether the load should bypass the cache (force-reload).
     virtual nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
                                    nsIPrincipal** aPrincipal,
                                    bool* aBypassCache) = 0;
 
-    // initialize the process that loads external font data, which upon 
-    // completion will call OnLoadComplete method
+    // initialize the process that loads external font data, which upon
+    // completion will call FontDataDownloadComplete method
     virtual nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
                                const gfxFontFaceSrc* aFontFaceSrc) = 0;
 
     // generation - each time a face is loaded, generation is
-    // incremented so that the change can be recognized 
+    // incremented so that the change can be recognized
     uint64_t GetGeneration() { return mGeneration; }
 
     // increment the generation on font load
-    void IncrementGeneration();
+    void IncrementGeneration(bool aIsRebuild = false);
+
+    // Generation is bumped on font loads but that doesn't affect name-style
+    // mappings. Rebuilds do however affect name-style mappings so need to
+    // lookup fontlists again when that happens.
+    uint64_t GetRebuildGeneration() { return mRebuildGeneration; }
 
     // rebuild if local rules have been used
     void RebuildLocalRules();
 
     class UserFontCache {
     public:
         // Flag passed when caching a font entry, to specify whether the entry
         // should persist in the cache or be discardable.
@@ -443,39 +456,39 @@ protected:
 
     // creates a new gfxUserFontFamily in mFontFamilies, or returns an existing
     // family if there is one
     gfxUserFontFamily* GetFamily(const nsAString& aFamilyName);
 
     // font families defined by @font-face rules
     nsRefPtrHashtable<nsStringHashKey, gfxUserFontFamily> mFontFamilies;
 
-    uint64_t        mGeneration;
+    uint64_t        mGeneration;        // bumped on any font load change
+    uint64_t        mRebuildGeneration; // only bumped on rebuilds
 
     // true when local names have been looked up, false otherwise
     bool mLocalRulesUsed;
 
     static PRLogModuleInfo* GetUserFontsLog();
 };
 
 // acts a placeholder until the real font is downloaded
 
 class gfxUserFontEntry : public gfxFontEntry {
     friend class gfxUserFontSet;
     friend class nsUserFontSet;
     friend class nsFontFaceLoader;
     friend class gfxOTSContext;
 
 public:
-    enum LoadStatus {
-        STATUS_LOADING = 0,
+    enum UserFontLoadState {
+        STATUS_NOT_LOADED = 0,
+        STATUS_LOADING,
         STATUS_LOADED,
-        STATUS_FORMAT_NOT_SUPPORTED,
-        STATUS_ERROR,
-        STATUS_END_OF_LIST
+        STATUS_FAILED
     };
 
     gfxUserFontEntry(gfxUserFontSet* aFontSet,
                      const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                      uint32_t aWeight,
                      int32_t aStretch,
                      uint32_t aItalicStyle,
                      const nsTArray<gfxFontFeature>& aFeatureSettings,
@@ -488,62 +501,85 @@ public:
     bool Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                  uint32_t aWeight,
                  int32_t aStretch,
                  uint32_t aItalicStyle,
                  const nsTArray<gfxFontFeature>& aFeatureSettings,
                  uint32_t aLanguageOverride,
                  gfxSparseBitSet* aUnicodeRanges);
 
-    virtual gfxFont* CreateFontInstance(const gfxFontStyle* aFontStyle, bool aNeedsBold);
+    virtual gfxFont* CreateFontInstance(const gfxFontStyle* aFontStyle,
+                                        bool aNeedsBold);
 
     gfxFontEntry* GetPlatformFontEntry() { return mPlatformFontEntry; }
 
+    // is the font loading or loaded, or did it fail?
+    UserFontLoadState LoadState() const { return mUserFontLoadState; }
+
+    // whether to wait before using fallback font or not
+    bool WaitForUserFont() const {
+        return mUserFontLoadState == STATUS_LOADING &&
+               mFontDataLoadingState < LOADING_SLOWLY;
+    }
+
+    // load the font - starts the loading of sources which continues until
+    // a valid font resource is found or all sources fail
+    void Load();
+
+protected:
+    const uint8_t* SanitizeOpenTypeData(const uint8_t* aData,
+                                        uint32_t aLength,
+                                        uint32_t& aSaneLength,
+                                        bool aIsCompressed);
+
+    // attempt to load the next resource in the src list.
+    void LoadNextSrc();
+
+    // change the load state
+    void SetLoadState(UserFontLoadState aLoadState);
+
     // when download has been completed, pass back data here
     // aDownloadStatus == NS_OK ==> download succeeded, error otherwise
     // returns true if platform font creation sucessful (or local()
     // reference was next in line)
     // Ownership of aFontData is passed in here; the font set must
     // ensure that it is eventually deleted with NS_Free().
-    bool OnLoadComplete(const uint8_t* aFontData, uint32_t aLength,
-                        nsresult aDownloadStatus);
-
-protected:
-    const uint8_t* SanitizeOpenTypeData(const uint8_t* aData,
-                                        uint32_t aLength,
-                                        uint32_t& aSaneLength,
-                                        bool aIsCompressed);
-
-    // Attempt to load the next resource in the src list.
-    LoadStatus LoadNext();
+    bool FontDataDownloadComplete(const uint8_t* aFontData, uint32_t aLength,
+                                  nsresult aDownloadStatus);
 
     // helper method for creating a platform font
     // returns true if platform font creation successful
     // Ownership of aFontData is passed in here; the font must
     // ensure that it is eventually deleted with NS_Free().
-    bool LoadFont(const uint8_t* aFontData, uint32_t &aLength);
+    bool LoadPlatformFont(const uint8_t* aFontData, uint32_t& aLength);
 
     // store metadata and src details for current src into aFontEntry
     void StoreUserFontData(gfxFontEntry*      aFontEntry,
                            bool               aPrivate,
                            const nsAString&   aOriginalName,
                            FallibleTArray<uint8_t>* aMetadata,
                            uint32_t           aMetaOrigLen);
 
+    // general load state
+    UserFontLoadState        mUserFontLoadState;
+
+    // detailed load state while font data is loading
+    // used to determine whether to use fallback font or not
     // note that code depends on the ordering of these values!
-    enum LoadingState {
+    enum FontDataLoadingState {
         NOT_LOADING = 0,     // not started to load any font resources yet
         LOADING_STARTED,     // loading has started; hide fallback font
         LOADING_ALMOST_DONE, // timeout happened but we're nearly done,
                              // so keep hiding fallback font
         LOADING_SLOWLY,      // timeout happened and we're not nearly done,
                              // so use the fallback font
         LOADING_FAILED       // failed to load any source: use fallback
     };
-    LoadingState             mLoadingState;
+    FontDataLoadingState     mFontDataLoadingState;
+
     bool                     mUnsupportedFormat;
 
     nsRefPtr<gfxFontEntry>   mPlatformFontEntry;
     nsTArray<gfxFontFaceSrc> mSrcList;
     uint32_t                 mSrcIndex; // index of loading src item
     nsFontFaceLoader*        mLoader; // current loader for this entry, if any
     gfxUserFontSet*          mFontSet; // font-set to which the userfont entry belongs
     nsCOMPtr<nsIPrincipal>   mPrincipal;
--- a/gfx/thebes/gfxWindowsSurface.cpp
+++ b/gfx/thebes/gfxWindowsSurface.cpp
@@ -278,27 +278,16 @@ gfxWindowsSurface::EndPage()
     if (result <= 0)
         return NS_ERROR_FAILURE;
     return NS_OK;
 #else
     return NS_ERROR_FAILURE;
 #endif
 }
 
-int32_t
-gfxWindowsSurface::GetDefaultContextFlags() const
-{
-    if (mForPrinting)
-        return gfxContext::FLAG_SIMPLIFY_OPERATORS |
-               gfxContext::FLAG_DISABLE_SNAPPING |
-               gfxContext::FLAG_DISABLE_COPY_BACKGROUND;
-
-    return 0;
-}
-
 const gfxIntSize 
 gfxWindowsSurface::GetSize() const
 {
     if (!mSurfaceValid) {
         NS_WARNING ("GetImageSurface on an invalid (null) surface; who's calling this without checking for surface errors?");
         return gfxIntSize(-1, -1);
     }
 
--- a/gfx/thebes/gfxWindowsSurface.h
+++ b/gfx/thebes/gfxWindowsSurface.h
@@ -58,18 +58,16 @@ public:
     already_AddRefed<gfxImageSurface> GetAsImageSurface();
 
     nsresult BeginPrinting(const nsAString& aTitle, const nsAString& aPrintToFileName);
     nsresult EndPrinting();
     nsresult AbortPrinting();
     nsresult BeginPage();
     nsresult EndPage();
 
-    virtual int32_t GetDefaultContextFlags() const;
-
     const gfxIntSize GetSize() const;
 
     // The memory used by this surface lives in this process's address space,
     // but not in the heap.
     virtual gfxMemoryLocation GetMemoryLocation() const;
 
 private:
     void MakeInvalid(gfxIntSize& size);
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -607,18 +607,20 @@ RasterImage::GetFrame(uint32_t aFrameNum
   if (!frame) {
     return DrawableFrameRef();
   }
 
   DrawableFrameRef ref = frame->DrawableRef();
   if (!ref) {
     // The OS threw this frame away. We need to discard and redecode.
     MOZ_ASSERT(!mAnim, "Animated frames should be locked");
-    ForceDiscard();
-    WantDecodedFrames();
+    if (CanForciblyDiscardAndRedecode()) {
+      ForceDiscard();
+      WantDecodedFrames();
+    }
     return DrawableFrameRef();
   }
 
   // We will return a paletted frame if it's not marked as compositing failed
   // so we can catch crashes for reasons we haven't investigated.
   if (ref->GetCompositingFailed()) {
     return DrawableFrameRef();
   }
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1703,17 +1703,17 @@ ObjectAddress(JSContext *cx, unsigned ar
     }
     if (!args[0].isObject()) {
         RootedObject callee(cx, &args.callee());
         ReportUsageError(cx, callee, "Expected object");
         return false;
     }
 
 #ifdef JS_MORE_DETERMINISTIC
-    args.rval().setInt(0);
+    args.rval().setInt32(0);
 #else
     char buffer[64];
     JS_snprintf(buffer, sizeof(buffer), "%p", &args[0].toObject());
 
     JSString *str = JS_NewStringCopyZ(cx, buffer);
     if (!str)
         return false;
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1634,19 +1634,19 @@ GetCompartmentName(JSCompartment *c, nsC
         if (compartmentPrivate) {
             const nsACString& location = compartmentPrivate->GetLocation();
             if (!location.IsEmpty() && !location.Equals(name)) {
                 name.AppendLiteral(", ");
                 name.Append(location);
             }
         }
 
-        // We might have a file:// URL that includes paths from the local
-        // filesystem, which should be omitted if we're anonymizing.
         if (*anonymizeID) {
+            // We might have a file:// URL that includes a path from the local
+            // filesystem, which should be omitted if we're anonymizing.
             static const char *filePrefix = "file://";
             int filePos = name.Find(filePrefix);
             if (filePos >= 0) {
                 int pathPos = filePos + strlen(filePrefix);
                 int lastSlashPos = -1;
                 for (int i = pathPos; i < int(name.Length()); i++) {
                     if (name[i] == '/' || name[i] == '\\') {
                         lastSlashPos = i;
@@ -1657,16 +1657,34 @@ GetCompartmentName(JSCompartment *c, nsC
                                       "<anonymized>");
                 } else {
                     // Something went wrong. Anonymize the entire path to be
                     // safe.
                     name.Truncate(pathPos);
                     name += "<anonymized?!>";
                 }
             }
+
+            // We might have a location like this:
+            //   inProcessTabChildGlobal?ownedBy=http://www.example.com/
+            // The owner should be omitted if it's not a chrome: URI and we're
+            // anonymizing.
+            static const char *ownedByPrefix =
+                "inProcessTabChildGlobal?ownedBy=";
+            int ownedByPos = name.Find(ownedByPrefix);
+            if (ownedByPos >= 0) {
+                const char *chrome = "chrome:";
+                int ownerPos = ownedByPos + strlen(ownedByPrefix);
+                const nsDependentCSubstring& ownerFirstPart =
+                    Substring(name, ownerPos, strlen(chrome));
+                if (!ownerFirstPart.EqualsASCII(chrome)) {
+                    name.Truncate(ownerPos);
+                    name += "<anonymized>";
+                }
+            }
         }
 
         // A hack: replace forward slashes with '\\' so they aren't
         // treated as path separators.  Users of the reporters
         // (such as about:memory) have to undo this change.
         if (replaceSlashes)
             name.ReplaceChar('/', '\\');
     } else {
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -1696,19 +1696,24 @@ XrayToString(JSContext *cx, unsigned arg
         wrapper = xpc::SandboxCallableProxyHandler::wrappedObject(wrapper);
     }
     if (!IsWrapper(wrapper) || !WrapperFactory::IsXrayWrapper(wrapper)) {
         JS_ReportError(cx, "XrayToString called on an incompatible object");
         return false;
     }
 
     RootedObject obj(cx, XrayTraits::getTargetObject(wrapper));
+    XrayType type = GetXrayType(obj);
+    if (type == XrayForDOMObject)
+        return NativeToString(cx, wrapper, obj, args.rval());
 
-    if (UseDOMXray(obj))
-        return NativeToString(cx, wrapper, obj, args.rval());
+    if (type != XrayForWrappedNative) {
+        JS_ReportError(cx, "XrayToString called on an incompatible object");
+        return false;
+    }
 
     static const char start[] = "[object XrayWrapper ";
     static const char end[] = "]";
     nsAutoString result;
     result.AppendASCII(start);
 
     XPCCallContext ccx(JS_CALLER, cx, obj);
     XPCWrappedNative *wn = XPCWrappedNativeXrayTraits::getWN(wrapper);
@@ -2299,22 +2304,23 @@ template class PermissiveXrayOpaque;
 
 template<>
 const SCSecurityXrayXPCWN SCSecurityXrayXPCWN::singleton(0);
 template class SCSecurityXrayXPCWN;
 
 static nsQueryInterface
 do_QueryInterfaceNative(JSContext* cx, HandleObject wrapper)
 {
-    nsISupports* nativeSupports;
+    nsISupports* nativeSupports = nullptr;
     if (IsWrapper(wrapper) && WrapperFactory::IsXrayWrapper(wrapper)) {
         RootedObject target(cx, XrayTraits::getTargetObject(wrapper));
-        if (GetXrayType(target) == XrayForDOMObject) {
+        XrayType type = GetXrayType(target);
+        if (type == XrayForDOMObject) {
             nativeSupports = UnwrapDOMObjectToISupports(target);
-        } else {
+        } else if (type == XrayForWrappedNative) {
             XPCWrappedNative *wn = XPCWrappedNative::Get(target);
             nativeSupports = wn->Native();
         }
     } else {
         nsIXPConnect *xpc = nsXPConnect::XPConnect();
         nativeSupports = xpc->GetNativeOfWrapper(cx, wrapper);
     }
 
new file mode 100644
--- /dev/null
+++ b/layout/base/RestyleLogging.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Macros used to log restyle events.
+ */
+
+#ifndef mozilla_RestyleLogging_h
+#define mozilla_RestyleLogging_h
+
+#include "mozilla/AutoRestore.h"
+
+#ifdef DEBUG
+#define RESTYLE_LOGGING
+#endif
+
+#ifdef RESTYLE_LOGGING
+#define LOG_RESTYLE_IF(object_, cond_, message_, ...)                         \
+  PR_BEGIN_MACRO                                                              \
+    if (object_->ShouldLogRestyle() && (cond_)) {                             \
+      nsCString line;                                                         \
+      for (int32_t restyle_depth_##__LINE__ = 0;                              \
+           restyle_depth_##__LINE__ < object_->LoggingDepth();                \
+           restyle_depth_##__LINE__++) {                                      \
+        line.AppendLiteral("  ");                                             \
+      }                                                                       \
+      line.AppendPrintf(message_, ##__VA_ARGS__);                             \
+      printf_stderr("%s\n", line.get());                                      \
+    }                                                                         \
+  PR_END_MACRO
+#define LOG_RESTYLE(message_, ...)                                            \
+  LOG_RESTYLE_IF(this, true, message_, ##__VA_ARGS__)
+// Beware that LOG_RESTYLE_INDENT is two statements not wrapped in a block.
+#define LOG_RESTYLE_INDENT()                                                  \
+  AutoRestore<int32_t> ar_depth_##__LINE__(LoggingDepth());                   \
+  ++LoggingDepth();
+#else
+#define LOG_RESTYLE_IF(cond_, message_, ...) /* nothing */
+#define LOG_RESTYLE(message_, ...) /* nothing */
+#define LOG_RESTYLE_INDENT() /* nothing */
+#endif
+
+#endif /* mozilla_RestyleLogging_h */
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -31,40 +31,57 @@
 #include "SVGTextFrame.h"
 #include "StickyScrollContainer.h"
 #include "nsIRootBox.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsContentUtils.h"
 #include "nsIFrameInlines.h"
 #include "ActiveLayerTracker.h"
 #include "nsDisplayList.h"
+#include "RestyleTrackerInlines.h"
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
 namespace mozilla {
 
 using namespace layers;
 
+#define LOG_RESTYLE_CONTINUE(reason_, ...) \
+  LOG_RESTYLE("continuing restyle since " reason_, ##__VA_ARGS__)
+
+#ifdef RESTYLE_LOGGING
+static nsCString
+FrameTagToString(const nsIFrame* aFrame)
+{
+  nsCString result;
+  aFrame->ListTag(result);
+  return result;
+}
+#endif
+
 RestyleManager::RestyleManager(nsPresContext* aPresContext)
   : mPresContext(aPresContext)
   , mRebuildAllStyleData(false)
   , mObservingRefreshDriver(false)
   , mInStyleRefresh(false)
   , mHoverGeneration(0)
   , mRebuildAllExtraHint(nsChangeHint(0))
   , mLastUpdateForThrottledAnimations(aPresContext->RefreshDriver()->
                                         MostRecentRefresh())
   , mAnimationGeneration(0)
   , mReframingStyleContexts(nullptr)
   , mPendingRestyles(ELEMENT_HAS_PENDING_RESTYLE |
                      ELEMENT_IS_POTENTIAL_RESTYLE_ROOT)
   , mPendingAnimationRestyles(ELEMENT_HAS_PENDING_ANIMATION_RESTYLE |
                               ELEMENT_IS_POTENTIAL_ANIMATION_RESTYLE_ROOT)
+#ifdef RESTYLE_LOGGING
+  , mLoggingDepth(0)
+#endif
 {
   mPendingRestyles.Init(this);
   mPendingAnimationRestyles.Init(this);
 }
 
 void
 RestyleManager::NotifyDestroyingFrame(nsIFrame* aFrame)
 {
@@ -2252,16 +2269,19 @@ ElementRestyler::ElementRestyler(nsPresC
   , mTreeMatchContext(aTreeMatchContext)
   , mResolvedChild(nullptr)
 #ifdef ACCESSIBILITY
   , mDesiredA11yNotifications(eSendAllNotifications)
   , mKidsDesiredA11yNotifications(mDesiredA11yNotifications)
   , mOurA11yNotification(eDontNotify)
   , mVisibleKidsOfHiddenElement(aVisibleKidsOfHiddenElement)
 #endif
+#ifdef RESTYLE_LOGGING
+  , mLoggingDepth(aRestyleTracker.LoggingDepth() + 1)
+#endif
 {
 }
 
 ElementRestyler::ElementRestyler(const ElementRestyler& aParentRestyler,
                                  nsIFrame* aFrame,
                                  uint32_t aConstructorFlags)
   : mPresContext(aParentRestyler.mPresContext)
   , mFrame(aFrame)
@@ -2279,16 +2299,19 @@ ElementRestyler::ElementRestyler(const E
   , mTreeMatchContext(aParentRestyler.mTreeMatchContext)
   , mResolvedChild(nullptr)
 #ifdef ACCESSIBILITY
   , mDesiredA11yNotifications(aParentRestyler.mKidsDesiredA11yNotifications)
   , mKidsDesiredA11yNotifications(mDesiredA11yNotifications)
   , mOurA11yNotification(eDontNotify)
   , mVisibleKidsOfHiddenElement(aParentRestyler.mVisibleKidsOfHiddenElement)
 #endif
+#ifdef RESTYLE_LOGGING
+  , mLoggingDepth(aParentRestyler.mLoggingDepth + 1)
+#endif
 {
   if (aConstructorFlags & FOR_OUT_OF_FLOW_CHILD) {
     // Note that the out-of-flow may not be a geometric descendant of
     // the frame where we started the reresolve.  Therefore, even if
     // mHintsHandled already includes nsChangeHint_AllReflowHints we
     // don't want to pass that on to the out-of-flow reresolve, since
     // that can lead to the out-of-flow not getting reflowed when it
     // should be (eg a reresolve starting at <body> that involves
@@ -2320,16 +2343,19 @@ ElementRestyler::ElementRestyler(ParentC
   , mTreeMatchContext(aParentRestyler.mTreeMatchContext)
   , mResolvedChild(nullptr)
 #ifdef ACCESSIBILITY
   , mDesiredA11yNotifications(aParentRestyler.mDesiredA11yNotifications)
   , mKidsDesiredA11yNotifications(mDesiredA11yNotifications)
   , mOurA11yNotification(eDontNotify)
   , mVisibleKidsOfHiddenElement(aParentRestyler.mVisibleKidsOfHiddenElement)
 #endif
+#ifdef RESTYLE_LOGGING
+  , mLoggingDepth(aParentRestyler.mLoggingDepth + 1)
+#endif
 {
 }
 
 void
 ElementRestyler::CaptureChange(nsStyleContext* aOldContext,
                                nsStyleContext* aNewContext,
                                nsChangeHint aChangeToAssume,
                                uint32_t* aEqualStructs)
@@ -2346,32 +2372,43 @@ ElementRestyler::CaptureChange(nsStyleCo
   nsChangeHint ourChange =
     aOldContext->CalcStyleDifference(aNewContext,
                                      mParentFrameHintsNotHandledForDescendants,
                                      aEqualStructs);
   NS_ASSERTION(!(ourChange & nsChangeHint_AllReflowHints) ||
                (ourChange & nsChangeHint_NeedReflow),
                "Reflow hint bits set without actually asking for a reflow");
 
+  LOG_RESTYLE("CaptureChange, ourChange = %s, aChangeToAssume = %s",
+              RestyleManager::ChangeHintToString(ourChange).get(),
+              RestyleManager::ChangeHintToString(aChangeToAssume).get());
+  LOG_RESTYLE_INDENT();
+
   // nsChangeHint_UpdateEffects is inherited, but it can be set due to changes
   // in inherited properties (fill and stroke).  Avoid propagating it into
   // text nodes.
   if ((ourChange & nsChangeHint_UpdateEffects) &&
       mContent && !mContent->IsElement()) {
     ourChange = NS_SubtractHint(ourChange, nsChangeHint_UpdateEffects);
   }
 
   NS_UpdateHint(ourChange, aChangeToAssume);
   if (NS_UpdateHint(mHintsHandled, ourChange)) {
     if (!(ourChange & nsChangeHint_ReconstructFrame) || mContent) {
+      LOG_RESTYLE("appending change %s",
+                  RestyleManager::ChangeHintToString(ourChange).get());
       mChangeList->AppendChange(mFrame, mContent, ourChange);
+    } else {
+      LOG_RESTYLE("change has already been handled");
     }
   }
   NS_UpdateHint(mHintsNotHandledForDescendants,
                 NS_HintsNotHandledForDescendantsIn(ourChange));
+  LOG_RESTYLE("mHintsNotHandledForDescendants = %s",
+              RestyleManager::ChangeHintToString(mHintsNotHandledForDescendants).get());
 }
 
 /**
  * Recompute style for mFrame (which should not have a prev continuation
  * with the same style), all of its next continuations with the same
  * style, and all ib-split siblings of the same type (either block or
  * inline, skipping the intermediates of the other type) and accumulate
  * changes into mChangeList given that mHintsHandled is already accumulated
@@ -2444,24 +2481,22 @@ ElementRestyler::Restyle(nsRestyleHint a
   // continuation or block-in-inline sibling.
 
   // We must make a single decision on how to process this frame and
   // its descendants, yet RestyleSelf might return different RestyleResult
   // values for the different same-style continuations.  |result| is our
   // overall decision.
   RestyleResult result = RestyleResult(0);
   uint32_t swappedStructs = 0;
-  nsIFrame* providerFrame = nullptr;
 
   nsRestyleHint thisRestyleHint = aRestyleHint;
 
   bool haveMoreContinuations = false;
   for (nsIFrame* f = mFrame; f; ) {
-    RestyleResult thisResult =
-      RestyleSelf(f, thisRestyleHint, &swappedStructs, &providerFrame);
+    RestyleResult thisResult = RestyleSelf(f, thisRestyleHint, &swappedStructs);
 
     if (thisResult != eRestyleResult_Stop) {
       // Calls to RestyleSelf for later same-style continuations must not
       // return eRestyleResult_Stop, so pass eRestyle_Force in to them.
       thisRestyleHint = nsRestyleHint(thisRestyleHint | eRestyle_Force);
 
       if (result == eRestyleResult_Stop) {
         // We received eRestyleResult_Stop for earlier same-style
@@ -2490,25 +2525,25 @@ ElementRestyler::Restyle(nsRestyleHint a
     mRestyleTracker.AddPendingRestyleToTable(mContent->AsElement(),
                                              hintToRestore, nsChangeHint(0));
   }
 
   if (result == eRestyleResult_Stop) {
     MOZ_ASSERT(mFrame->StyleContext() == oldContext,
                "frame should have been left with its old style context");
 
-    MOZ_ASSERT(providerFrame, "RestyleSelf should have supplied a providerFrame "
-                              "if it returned eRestyleResult_Stop");
-
-    nsStyleContext* newParent = providerFrame->StyleContext();
+    nsStyleContext* newParent =
+      mFrame->GetParentStyleContextFrame()->StyleContext();
 
     if (oldContext->GetParent() != newParent) {
       // If we received eRestyleResult_Stop, then the old style context was
       // left on mFrame.  Since we ended up restyling our parent, change
       // this old style context to point to its new parent.
+      LOG_RESTYLE("moving style context %p from old parent %p to new parent %p",
+                  oldContext.get(), oldContext->GetParent(), newParent);
       oldContext->MoveTo(newParent);
     }
 
     // Send the accessibility notifications that RestyleChildren otherwise
     // would have sent.
     if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
       InitializeAccessibilityNotifications();
       SendAccessibilityNotifications();
@@ -2563,130 +2598,157 @@ ElementRestyler::Restyle(nsRestyleHint a
 ElementRestyler::RestyleResult
 ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf)
 {
   // We can't handle situations where the primary style context of a frame
   // has not had any style data changes, but its additional style contexts
   // have, so we don't considering stopping if this frame has any additional
   // style contexts.
   if (aSelf->GetAdditionalStyleContext(0)) {
+    LOG_RESTYLE_CONTINUE("there are additional style contexts");
     return eRestyleResult_Continue;
   }
 
   // Style changes might have moved children between the two nsLetterFrames
   // (the one matching ::first-letter and the one containing the rest of the
   // content).  Continue restyling to the children of the nsLetterFrame so
   // that they get the correct style context parent.  Similarly for
   // nsLineFrames.
   nsIAtom* type = aSelf->GetType();
-  if (type == nsGkAtoms::letterFrame || type == nsGkAtoms::lineFrame) {
+
+  if (type == nsGkAtoms::letterFrame) {
+    LOG_RESTYLE_CONTINUE("frame is a letter frame");
+    return eRestyleResult_Continue;
+  }
+
+  if (type == nsGkAtoms::lineFrame) {
+    LOG_RESTYLE_CONTINUE("frame is a line frame");
     return eRestyleResult_Continue;
   }
 
   // Some style computations depend not on the parent's style, but a grandparent
   // or one the grandparent's ancestors.  An example is an explicit 'inherit'
   // value for align-self, where if the parent frame's value for the property is
   // 'auto' we end up inheriting the computed value from the grandparent.  We
   // can't stop the restyling process on this frame (the one with 'auto', in
   // this example), as the grandparent's computed value might have changed
   // and we need to recompute the child's 'inherit' to that new value.
   nsStyleContext* oldContext = aSelf->StyleContext();
   if (oldContext->HasChildThatUsesGrandancestorStyle()) {
+    LOG_RESTYLE_CONTINUE("the old context uses grandancestor style");
     return eRestyleResult_Continue;
   }
 
   // We ignore all situations that involve :visited style.
   if (oldContext->GetStyleIfVisited()) {
+    LOG_RESTYLE_CONTINUE("the old style context has StyleIfVisited");
     return eRestyleResult_Continue;
   }
 
   nsStyleContext* parentContext = oldContext->GetParent();
   if (parentContext && parentContext->GetStyleIfVisited()) {
+    LOG_RESTYLE_CONTINUE("the old style context's parent has StyleIfVisited");
     return eRestyleResult_Continue;
   }
 
   // We also ignore frames for pseudos, as their style contexts have
   // inheritance structures that do not match the frame inheritance
   // structure.  To avoid enumerating and checking all of the cases
   // where we have this kind of inheritance, we keep restyling past
   // pseudos.
   nsIAtom* pseudoTag = oldContext->GetPseudo();
   if (pseudoTag && pseudoTag != nsCSSAnonBoxes::mozNonElement) {
+    LOG_RESTYLE_CONTINUE("the old style context is for a pseudo");
     return eRestyleResult_Continue;
   }
 
   nsIFrame* parent = mFrame->GetParent();
 
   if (parent) {
     // Also if the parent has a pseudo, as this frame's style context will
     // be inheriting from a grandparent frame's style context (or a further
     // ancestor).
     nsIAtom* parentPseudoTag = parent->StyleContext()->GetPseudo();
     if (parentPseudoTag && parentPseudoTag != nsCSSAnonBoxes::mozNonElement) {
+      LOG_RESTYLE_CONTINUE("the old style context's parent is for a pseudo");
       return eRestyleResult_Continue;
     }
   }
 
   return eRestyleResult_Stop;
 }
 
 ElementRestyler::RestyleResult
 ElementRestyler::ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
                                                     nsStyleContext* aNewContext)
 {
   // Keep restyling if the new style context has any style-if-visted style, so
   // that we can avoid the style context tree surgery having to deal to deal
   // with visited styles.
   if (aNewContext->GetStyleIfVisited()) {
+    LOG_RESTYLE_CONTINUE("the new style context has StyleIfVisited");
     return eRestyleResult_Continue;
   }
 
   // If link-related information has changed, or the pseudo for the frame has
   // changed, or the new style context points to a different rule node, we can't
   // leave the old style context on the frame.
   nsStyleContext* oldContext = aSelf->StyleContext();
   if (oldContext->IsLinkContext() != aNewContext->IsLinkContext() ||
       oldContext->RelevantLinkVisited() != aNewContext->RelevantLinkVisited() ||
       oldContext->GetPseudo() != aNewContext->GetPseudo() ||
       oldContext->GetPseudoType() != aNewContext->GetPseudoType() ||
       oldContext->RuleNode() != aNewContext->RuleNode()) {
+    LOG_RESTYLE_CONTINUE("the old and new style contexts have different link/"
+                         "visited/pseudo/rulenodes");
     return eRestyleResult_Continue;
   }
 
   // If the old and new style contexts differ in their
   // NS_STYLE_HAS_TEXT_DECORATION_LINES or NS_STYLE_HAS_PSEUDO_ELEMENT_DATA
   // bits, then we must keep restyling so that those new bit values are
   // propagated.
   if (oldContext->HasTextDecorationLines() !=
-        aNewContext->HasTextDecorationLines() ||
-      oldContext->HasPseudoElementData() !=
+        aNewContext->HasTextDecorationLines()) {
+    LOG_RESTYLE_CONTINUE("NS_STYLE_HAS_TEXT_DECORATION_LINES differs between old"
+                         " and new style contexts");
+    return eRestyleResult_Continue;
+  }
+
+  if (oldContext->HasPseudoElementData() !=
         aNewContext->HasPseudoElementData()) {
+    LOG_RESTYLE_CONTINUE("NS_STYLE_HAS_PSEUDO_ELEMENT_DATA differs between old"
+                         " and new style contexts");
     return eRestyleResult_Continue;
   }
 
   return eRestyleResult_Stop;
 }
 
 ElementRestyler::RestyleResult
 ElementRestyler::RestyleSelf(nsIFrame* aSelf,
                              nsRestyleHint aRestyleHint,
-                             uint32_t* aSwappedStructs,
-                             nsIFrame** aProviderFrame)
+                             uint32_t* aSwappedStructs)
 {
   MOZ_ASSERT(!(aRestyleHint & eRestyle_LaterSiblings),
              "eRestyle_LaterSiblings must not be part of aRestyleHint");
 
   // XXXldb get new context from prev-in-flow if possible, to avoid
   // duplication.  (Or should we just let |GetContext| handle that?)
   // Getting the hint would be nice too, but that's harder.
 
   // XXXbryner we may be able to avoid some of the refcounting goop here.
   // We do need a reference to oldContext for the lifetime of this function, and it's possible
   // that the frame has the last reference to it, so AddRef it here.
 
+  LOG_RESTYLE("RestyleSelf %s, aRestyleHint = %s",
+              FrameTagToString(aSelf).get(),
+              RestyleManager::RestyleHintToString(aRestyleHint).get());
+  LOG_RESTYLE_INDENT();
+
   RestyleResult result;
 
   if (aRestyleHint & eRestyle_ForceDescendants) {
     result = eRestyleResult_ContinueAndForceDescendants;
   } else if (aRestyleHint) {
     result = eRestyleResult_Continue;
   } else {
     result = ComputeRestyleResultFromFrame(aSelf);
@@ -2702,31 +2764,32 @@ ElementRestyler::RestyleSelf(nsIFrame* a
 #endif
 
   nsIAtom* const pseudoTag = oldContext->GetPseudo();
   const nsCSSPseudoElements::Type pseudoType = oldContext->GetPseudoType();
 
   nsStyleContext* parentContext;
   // Get the frame providing the parent style context.  If it is a
   // child, then resolve the provider first.
-  nsIFrame* const providerFrame = aSelf->GetParentStyleContextFrame();
+  nsIFrame* providerFrame = aSelf->GetParentStyleContextFrame();
   bool isChild = providerFrame && providerFrame->GetParent() == aSelf;
   if (!isChild) {
     if (providerFrame)
       parentContext = providerFrame->StyleContext();
     else
       parentContext = nullptr;
   }
   else {
     MOZ_ASSERT(providerFrame->GetContent() == aSelf->GetContent(),
                "Postcondition for GetParentStyleContextFrame() violated. "
                "That means we need to add the current element to the "
                "ancestor filter.");
 
     // resolve the provider here (before aSelf below).
+    LOG_RESTYLE("resolving child provider frame");
 
     // assumeDifferenceHint forces the parent's change to be also
     // applied to this frame, no matter what
     // nsStyleContext::CalcStyleDifference says. CalcStyleDifference
     // can't be trusted because it assumes any changes to the parent
     // style context provider will be automatically propagated to
     // the frame(s) with child style contexts.
 
@@ -2736,80 +2799,79 @@ ElementRestyler::RestyleSelf(nsIFrame* a
     assumeDifferenceHint = providerRestyler.HintsHandledForFrame();
 
     // The provider's new context becomes the parent context of
     // aSelf's context.
     parentContext = providerFrame->StyleContext();
     // Set |mResolvedChild| so we don't bother resolving the
     // provider again.
     mResolvedChild = providerFrame;
+    LOG_RESTYLE_CONTINUE("we had a provider frame");
     // Continue restyling past the odd style context inheritance.
     result = eRestyleResult_Continue;
   }
 
   if (providerFrame != aSelf->GetParent()) {
     // We don't actually know what the parent style context's
     // non-inherited hints were, so assume the worst.
     mParentFrameHintsNotHandledForDescendants =
       nsChangeHint_Hints_NotHandledForDescendants;
   }
 
-  if (*aProviderFrame && *aProviderFrame != providerFrame) {
-    // XXX Uncomment when bug 979133 (restyle logging) lands.
-    // LOG_RESTYLE_CONTINUE("we had different provider frame from the previous "
-    //                      "same-style continuation");
-    result = eRestyleResult_Continue;
-  }
-
   // We don't support using eRestyle_StyleAttribute when pseudo-elements
   // are involved.  This is mostly irrelevant since style attribute
   // changes on pseudo-elements are very rare, though it does mean we
   // don't get the optimization for table elements.
   if (pseudoType != nsCSSPseudoElements::ePseudo_NotPseudoElement &&
       (aRestyleHint & eRestyle_StyleAttribute)) {
     aRestyleHint = (aRestyleHint & ~eRestyle_StyleAttribute) | eRestyle_Self;
   }
 
+  LOG_RESTYLE("parentContext = %p", parentContext);
+
   // do primary context
   nsRefPtr<nsStyleContext> newContext;
   nsIFrame *prevContinuation =
     GetPrevContinuationWithPossiblySameStyle(aSelf);
   nsStyleContext *prevContinuationContext;
   bool copyFromContinuation =
     prevContinuation &&
     (prevContinuationContext = prevContinuation->StyleContext())
       ->GetPseudo() == oldContext->GetPseudo() &&
      prevContinuationContext->GetParent() == parentContext;
   if (copyFromContinuation) {
     // Just use the style context from the frame's previous
     // continuation.
+    LOG_RESTYLE("using previous continuation's context");
     newContext = prevContinuationContext;
   }
   else if (pseudoTag == nsCSSAnonBoxes::mozNonElement) {
     NS_ASSERTION(aSelf->GetContent(),
                  "non pseudo-element frame without content node");
     newContext = styleSet->ResolveStyleForNonElement(parentContext);
   }
   else if (!(aRestyleHint & (eRestyle_Self | eRestyle_Subtree))) {
     Element* element = ElementForStyleContext(mParentContent, aSelf, pseudoType);
     if (!(aRestyleHint & ~(eRestyle_Force | eRestyle_ForceDescendants)) &&
         !styleSet->IsInRuleTreeReconstruct()) {
       nsIContent* pseudoElementContent = aSelf->GetContent();
       Element* pseudoElement =
         (pseudoElementContent && pseudoElementContent->IsElement())
           ? pseudoElementContent->AsElement() : nullptr;
+      LOG_RESTYLE("reparenting style context");
       newContext =
         styleSet->ReparentStyleContext(oldContext, parentContext, element,
                                        pseudoElement);
     } else {
       // Use ResolveStyleWithReplacement either for actual replacements
       // or, with no replacements, as a substitute for
       // ReparentStyleContext that rebuilds the path in the rule tree
       // rather than reusing the rule node, as we need to do during a
       // rule tree reconstruct.
+      LOG_RESTYLE("resolving style with replacement");
       newContext =
         styleSet->ResolveStyleWithReplacement(element, parentContext, oldContext,
                                               aRestyleHint);
     }
   } else if (pseudoType == nsCSSPseudoElements::ePseudo_AnonBox) {
     newContext = styleSet->ResolveAnonymousBoxStyle(pseudoTag,
                                                     parentContext);
   }
@@ -2877,29 +2939,38 @@ ElementRestyler::RestyleSelf(nsIFrame* a
         oldContext->IsLinkContext() == newContext->IsLinkContext() &&
         oldContext->RelevantLinkVisited() ==
           newContext->RelevantLinkVisited()) {
       // We're the root of the style context tree and the new style
       // context returned has the same rule node.  This means that
       // we can use FindChildWithRules to keep a lot of the old
       // style contexts around.  However, we need to start from the
       // same root.
+      LOG_RESTYLE("restyling root and keeping old context");
+      LOG_RESTYLE_IF(this, result != eRestyleResult_Continue,
+                     "continuing restyle since this is the root");
       newContext = oldContext;
       // Never consider stopping restyling at the root.
       result = eRestyleResult_Continue;
     }
   }
 
+  LOG_RESTYLE("oldContext = %p, newContext = %p%s",
+              oldContext.get(), newContext.get(),
+              oldContext == newContext ? (const char*) " (same)" :
+                                         (const char*) "");
+
   if (newContext != oldContext) {
     if (result == eRestyleResult_Stop) {
       if (oldContext->IsShared()) {
         // If the old style context was shared, then we can't return
         // eRestyleResult_Stop and patch its parent to point to the
         // new parent style context, as that change might not be valid
         // for the other frames sharing the style context.
+        LOG_RESTYLE_CONTINUE("the old style context is shared");
         result = eRestyleResult_Continue;
       } else {
         // Look at some details of the new style context to see if it would
         // be safe to stop restyling, if we discover it has the same style
         // data as the old style context.
         result = ComputeRestyleResultFromNewContext(aSelf, newContext);
       }
     }
@@ -2913,28 +2984,34 @@ ElementRestyler::RestyleSelf(nsIFrame* a
       // same-style continuations (bug 918064), we need to check again here to
       // determine whether it is safe to stop restyling.
       if (result == eRestyleResult_Stop) {
         oldContext->CalcStyleDifference(newContext, nsChangeHint(0),
                                         &equalStructs);
         if (equalStructs != NS_STYLE_INHERIT_MASK) {
           // At least one struct had different data in it, so we must
           // continue restyling children.
+          LOG_RESTYLE_CONTINUE("there is different style data: %s",
+                      RestyleManager::StructNamesToString(
+                        ~equalStructs & NS_STYLE_INHERIT_MASK).get());
           result = eRestyleResult_Continue;
         }
       }
     } else {
       RestyleManager::TryStartingTransition(mPresContext, aSelf->GetContent(),
                                             oldContext, &newContext);
 
       CaptureChange(oldContext, newContext, assumeDifferenceHint,
                     &equalStructs);
       if (equalStructs != NS_STYLE_INHERIT_MASK) {
         // At least one struct had different data in it, so we must
         // continue restyling children.
+        LOG_RESTYLE_CONTINUE("there is different style data: %s",
+                    RestyleManager::StructNamesToString(
+                      ~equalStructs & NS_STYLE_INHERIT_MASK).get());
         result = eRestyleResult_Continue;
       }
     }
 
     if (result == eRestyleResult_Stop) {
       // Since we currently have eRestyleResult_Stop, we know at this
       // point that all of our style structs are equal in terms of styles.
       // However, some of them might be different pointers.  Since our
@@ -2953,49 +3030,69 @@ ElementRestyler::RestyleSelf(nsIFrame* a
       //
       // (b) when we were unable to swap the structs on the parent because
       //     either or both of the old parent and new parent are shared.
       for (nsStyleStructID sid = nsStyleStructID(0);
            sid < nsStyleStructID_Length;
            sid = nsStyleStructID(sid + 1)) {
         if (oldContext->HasCachedInheritedStyleData(sid) &&
             !oldContext->HasSameCachedStyleData(newContext, sid)) {
+          LOG_RESTYLE_CONTINUE("there are different struct pointers");
           result = eRestyleResult_Continue;
           break;
         }
       }
     }
 
     if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
       // If the frame gets regenerated, let it keep its old context,
       // which is important to maintain various invariants about
       // frame types matching their style contexts.
       // Note that this check even makes sense if we didn't call
       // CaptureChange because of copyFromContinuation being true,
       // since we'll have copied the existing context from the
       // previous continuation, so newContext == oldContext.
 
       if (result != eRestyleResult_Stop) {
-        if (!oldContext->IsShared() && !newContext->IsShared()) {
+        if (copyFromContinuation) {
+          LOG_RESTYLE("not swapping style structs, since we copied from a "
+                      "continuation");
+        } else if (oldContext->IsShared() && newContext->IsShared()) {
+          LOG_RESTYLE("not swapping style structs, since both old and contexts "
+                      "are shared");
+        } else if (oldContext->IsShared()) {
+          LOG_RESTYLE("not swapping style structs, since the old context is "
+                      "shared");
+        } else if (newContext->IsShared()) {
+          LOG_RESTYLE("not swapping style structs, since the new context is "
+                      "shared");
+        } else {
+          LOG_RESTYLE("swapping style structs between %p and %p",
+                      oldContext.get(), newContext.get());
           oldContext->SwapStyleData(newContext, equalStructs);
           *aSwappedStructs |= equalStructs;
         }
+        LOG_RESTYLE("setting new style context");
         aSelf->SetStyleContext(newContext);
       }
+    } else {
+      LOG_RESTYLE("not setting new style context, since we'll reframe");
     }
   }
   oldContext = nullptr;
 
   // do additional contexts
   // XXXbz might be able to avoid selector matching here in some
   // cases; won't worry about it for now.
   int32_t contextIndex = 0;
   for (nsStyleContext* oldExtraContext;
        (oldExtraContext = aSelf->GetAdditionalStyleContext(contextIndex));
        ++contextIndex) {
+    LOG_RESTYLE("extra context %d", contextIndex);
+    LOG_RESTYLE_INDENT();
     nsRefPtr<nsStyleContext> newExtraContext;
     nsIAtom* const extraPseudoTag = oldExtraContext->GetPseudo();
     const nsCSSPseudoElements::Type extraPseudoType =
       oldExtraContext->GetPseudoType();
     NS_ASSERTION(extraPseudoTag &&
                  extraPseudoTag != nsCSSAnonBoxes::mozNonElement,
                  "extra style context is not pseudo element");
     if (!(aRestyleHint & (eRestyle_Self | eRestyle_Subtree))) {
@@ -3031,29 +3128,32 @@ ElementRestyler::RestyleSelf(nsIFrame* a
       newExtraContext = styleSet->ResolvePseudoElementStyle(mContent->AsElement(),
                                                             extraPseudoType,
                                                             newContext,
                                                             nullptr);
     }
 
     MOZ_ASSERT(newExtraContext);
 
+    LOG_RESTYLE("newExtraContext = %p", newExtraContext.get());
+
     if (oldExtraContext != newExtraContext) {
       uint32_t equalStructs;
       CaptureChange(oldExtraContext, newExtraContext, assumeDifferenceHint,
                     &equalStructs);
       if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
+        LOG_RESTYLE("setting new extra style context");
         aSelf->SetAdditionalStyleContext(contextIndex, newExtraContext);
+      } else {
+        LOG_RESTYLE("not setting new extra style context, since we'll reframe");
       }
     }
   }
 
-  if (result == eRestyleResult_Stop) {
-    *aProviderFrame = providerFrame;
-  }
+  LOG_RESTYLE("returning %s", RestyleResultToString(result).get());
 
   return result;
 }
 
 void
 ElementRestyler::RestyleChildren(nsRestyleHint aChildRestyleHint)
 {
   // We'd like style resolution to be exact in the sense that an
@@ -3148,16 +3248,19 @@ ElementRestyler::RestyleUndisplayedChild
       NS_ASSERTION(undisplayedParent ||
                    undisplayed->mContent ==
                      mPresContext->Document()->GetRootElement(),
                    "undisplayed node child of null must be root");
       NS_ASSERTION(!undisplayed->mStyle->GetPseudo(),
                    "Shouldn't have random pseudo style contexts in the "
                    "undisplayed map");
 
+      LOG_RESTYLE("RestyleUndisplayedChildren: undisplayed->mContent = %p",
+                  undisplayed->mContent.get());
+
       // Get the parent of the undisplayed content and check if it is a XBL
       // children element. Push the children element as an ancestor here because it does
       // not have a frame and would not otherwise be pushed as an ancestor.
       nsIContent* parent = undisplayed->mContent->GetParent();
       TreeMatchContext::AutoAncestorPusher insertionPointPusher(mTreeMatchContext);
       if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
         insertionPointPusher.PushAncestorAndStyleScope(parent);
       }
@@ -3229,16 +3332,18 @@ ElementRestyler::MaybeReframeForBeforePs
       // Checking for a :before frame is cheaper than getting the
       // :before style context.
       if (!nsLayoutUtils::GetBeforeFrame(mFrame) &&
           nsLayoutUtils::HasPseudoStyle(mFrame->GetContent(),
                                         mFrame->StyleContext(),
                                         nsCSSPseudoElements::ePseudo_before,
                                         mPresContext)) {
         // Have to create the new :before frame
+        LOG_RESTYLE("MaybeReframeForBeforePseudo, appending "
+                    "nsChangeHint_ReconstructFrame");
         NS_UpdateHint(mHintsHandled, nsChangeHint_ReconstructFrame);
         mChangeList->AppendChange(mFrame, mContent,
                                   nsChangeHint_ReconstructFrame);
       }
     }
   }
 }
 
@@ -3265,16 +3370,18 @@ ElementRestyler::MaybeReframeForAfterPse
       // Getting the :after frame is more expensive than getting the pseudo
       // context, so get the pseudo context first.
       if (nsLayoutUtils::HasPseudoStyle(aFrame->GetContent(),
                                         aFrame->StyleContext(),
                                         nsCSSPseudoElements::ePseudo_after,
                                         mPresContext) &&
           !nsLayoutUtils::GetAfterFrame(aFrame)) {
         // have to create the new :after frame
+        LOG_RESTYLE("MaybeReframeForAfterPseudo, appending "
+                    "nsChangeHint_ReconstructFrame");
         NS_UpdateHint(mHintsHandled, nsChangeHint_ReconstructFrame);
         mChangeList->AppendChange(aFrame, mContent,
                                   nsChangeHint_ReconstructFrame);
       }
     }
   }
 }
 
@@ -3317,16 +3424,18 @@ ElementRestyler::InitializeAccessibility
   }
 #endif
 }
 
 void
 ElementRestyler::RestyleContentChildren(nsIFrame* aParent,
                                         nsRestyleHint aChildRestyleHint)
 {
+  LOG_RESTYLE("RestyleContentChildren");
+
   nsIFrame::ChildListIterator lists(aParent);
   TreeMatchContext::AutoAncestorPusher ancestorPusher(mTreeMatchContext);
   if (!lists.IsDone()) {
     ancestorPusher.PushAncestorAndStyleScope(mContent);
   }
   for (; !lists.IsDone(); lists.Next()) {
     nsFrameList::Enumerator childFrames(lists.CurrentList());
     for (; !childFrames.AtEnd(); childFrames.Next()) {
@@ -3522,9 +3631,143 @@ RestyleManager::ComputeStyleChangeFor(ns
         NS_ASSERTION(!cont->GetPrevContinuation(),
                      "continuing frame had more severe impact than first-in-flow");
         return;
       }
     }
   }
 }
 
+#ifdef DEBUG
+/* static */ nsCString
+RestyleManager::RestyleHintToString(nsRestyleHint aHint)
+{
+  nsCString result;
+  bool any = false;
+  const char* names[] = { "Self", "Subtree", "LaterSiblings", "CSSTransitions",
+                          "CSSAnimations", "SVGAttrAnimations", "StyleAttribute",
+                          "ChangeAnimationPhase", "Force", "ForceDescendants" };
+  uint32_t hint = aHint & ((1 << ArrayLength(names)) - 1);
+  uint32_t rest = aHint & ~((1 << ArrayLength(names)) - 1);
+  for (uint32_t i = 0; i < ArrayLength(names); i++) {
+    if (hint & (1 << i)) {
+      if (any) {
+        result.AppendLiteral(" | ");
+      }
+      result.AppendPrintf("eRestyle_%s", names[i]);
+      any = true;
+    }
+  }
+  if (rest) {
+    if (any) {
+      result.AppendLiteral(" | ");
+    }
+    result.AppendPrintf("0x%0x", rest);
+  } else {
+    if (!any) {
+      result.AppendLiteral("0");
+    }
+  }
+  return result;
+}
+
+/* static */ nsCString
+RestyleManager::ChangeHintToString(nsChangeHint aHint)
+{
+  nsCString result;
+  bool any = false;
+  const char* names[] = {
+    "RepaintFrame", "NeedReflow", "ClearAncestorIntrinsics",
+    "ClearDescendantIntrinsics", "NeedDirtyReflow", "SyncFrameView",
+    "UpdateCursor", "UpdateEffects", "UpdateOpacityLayer",
+    "UpdateTransformLayer", "ReconstructFrame", "UpdateOverflow",
+    "UpdateSubtreeOverflow", "UpdatePostTransformOverflow",
+    "ChildrenOnlyTransform", "RecomputePosition", "AddOrRemoveTransform",
+    "BorderStyleNoneChange", "UpdateTextPath", "NeutralChange"
+  };
+  uint32_t hint = aHint & ((1 << ArrayLength(names)) - 1);
+  uint32_t rest = aHint & ~((1 << ArrayLength(names)) - 1);
+  if (hint == nsChangeHint_Hints_NotHandledForDescendants) {
+    result.AppendLiteral("nsChangeHint_Hints_NotHandledForDescendants");
+    hint = 0;
+    any = true;
+  } else {
+    if ((hint & NS_STYLE_HINT_FRAMECHANGE) == NS_STYLE_HINT_FRAMECHANGE) {
+      result.AppendLiteral("NS_STYLE_HINT_FRAMECHANGE");
+      hint = hint & ~NS_STYLE_HINT_FRAMECHANGE;
+      any = true;
+    } else if ((hint & NS_STYLE_HINT_REFLOW) == NS_STYLE_HINT_REFLOW) {
+      result.AppendLiteral("NS_STYLE_HINT_REFLOW");
+      hint = hint & ~NS_STYLE_HINT_REFLOW;
+      any = true;
+    } else if ((hint & nsChangeHint_AllReflowHints) == nsChangeHint_AllReflowHints) {
+      result.AppendLiteral("nsChangeHint_AllReflowHints");
+      hint = hint & ~nsChangeHint_AllReflowHints;
+      any = true;
+    } else if ((hint & NS_STYLE_HINT_VISUAL) == NS_STYLE_HINT_VISUAL) {
+      result.AppendLiteral("NS_STYLE_HINT_VISUAL");
+      hint = hint & ~NS_STYLE_HINT_VISUAL;
+      any = true;
+    }
+  }
+  for (uint32_t i = 0; i < ArrayLength(names); i++) {
+    if (hint & (1 << i)) {
+      if (any) {
+        result.AppendLiteral(" | ");
+      }
+      result.AppendPrintf("nsChangeHint_%s", names[i]);
+      any = true;
+    }
+  }
+  if (rest) {
+    if (any) {
+      result.AppendLiteral(" | ");
+    }
+    result.AppendPrintf("0x%0x", rest);
+  } else {
+    if (!any) {
+      result.AppendLiteral("NS_STYLE_HINT_NONE");
+    }
+  }
+  return result;
+}
+
+/* static */ nsCString
+RestyleManager::StructNamesToString(uint32_t aSIDs)
+{
+  nsCString result;
+  bool any = false;
+  for (nsStyleStructID sid = nsStyleStructID(0);
+       sid < nsStyleStructID_Length;
+       sid = nsStyleStructID(sid + 1)) {
+    if (aSIDs & nsCachedStyleData::GetBitForSID(sid)) {
+      if (any) {
+        result.AppendLiteral(",");
+      }
+      result.AppendPrintf("%s", nsStyleContext::StructName(sid));
+      any = true;
+    }
+  }
+  return result;
+}
+
+/* static */ nsCString
+ElementRestyler::RestyleResultToString(RestyleResult aRestyleResult)
+{
+  nsCString result;
+  switch (aRestyleResult) {
+    case eRestyleResult_Stop:
+      result.AssignLiteral("eRestyleResult_Stop");
+      break;
+    case eRestyleResult_Continue:
+      result.AssignLiteral("eRestyleResult_Continue");
+      break;
+    case eRestyleResult_ContinueAndForceDescendants:
+      result.AssignLiteral("eRestyleResult_ContinueAndForceDescendants");
+      break;
+    default:
+      result.AppendPrintf("RestyleResult(%d)", aRestyleResult);
+  }
+  return result;
+}
+#endif
+
 } // namespace mozilla
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -6,16 +6,17 @@
 /**
  * Code responsible for managing style changes: tracking what style
  * changes need to happen, scheduling them, and doing them.
  */
 
 #ifndef mozilla_RestyleManager_h
 #define mozilla_RestyleManager_h
 
+#include "mozilla/RestyleLogging.h"
 #include "nsISupportsImpl.h"
 #include "nsChangeHint.h"
 #include "RestyleTracker.h"
 #include "nsPresContext.h"
 #include "nsRefreshDriver.h"
 #include "nsRefPtrHashtable.h"
 #include "nsCSSPseudoElements.h"
 
@@ -311,16 +312,21 @@ public:
     PostRestyleEventInternal(true);
   }
 
   void FlushOverflowChangedTracker()
   {
     mOverflowChangedTracker.Flush();
   }
 
+#ifdef DEBUG
+  static nsCString RestyleHintToString(nsRestyleHint aHint);
+  static nsCString ChangeHintToString(nsChangeHint aHint);
+#endif
+
 private:
   /**
    * Notify the frame constructor that an element needs to have its
    * style recomputed.
    * @param aElement: The element to be restyled.
    * @param aRestyleHint: Which nodes need to have selector matching run
    *                      on them.
    * @param aMinChangeHint: A minimum change hint for aContent and its
@@ -346,16 +352,49 @@ public:
    * This method is used to recompute the style data when some change happens
    * outside of any style rules, like a color preference change or a change
    * in a system font size, or to fix things up when an optimization in the
    * style data has become invalid. We assume that the root frame will not
    * need to be reframed.
    */
   void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint);
 
+#ifdef RESTYLE_LOGGING
+  /**
+   * Returns whether a restyle event currently being processed by this
+   * RestyleManager should be logged.
+   */
+  bool ShouldLogRestyle() {
+    return ShouldLogRestyle(mPresContext);
+  }
+
+  /**
+   * Returns whether a restyle event currently being processed for the
+   * document with the specified nsPresContext should be logged.
+   */
+  static bool ShouldLogRestyle(nsPresContext* aPresContext) {
+    return aPresContext->RestyleLoggingEnabled() &&
+           (!aPresContext->IsProcessingAnimationStyleChange() ||
+            AnimationRestyleLoggingEnabled());
+  }
+
+  static bool RestyleLoggingInitiallyEnabled() {
+    static bool enabled = getenv("MOZ_DEBUG_RESTYLE") != 0;
+    return enabled;
+  }
+
+  static bool AnimationRestyleLoggingEnabled() {
+    static bool animations = getenv("MOZ_DEBUG_RESTYLE_ANIMATIONS") != 0;
+    return animations;
+  }
+
+  static nsCString StructNamesToString(uint32_t aSIDs);
+  int32_t& LoggingDepth() { return mLoggingDepth; }
+#endif
+
 private:
   /* aMinHint is the minimal change that should be made to the element */
   // XXXbz do we really need the aPrimaryFrame argument here?
   void RestyleElement(Element*        aElement,
                       nsIFrame*       aPrimaryFrame,
                       nsChangeHint    aMinHint,
                       RestyleTracker& aRestyleTracker,
                       nsRestyleHint   aRestyleHint);
@@ -388,16 +427,20 @@ private:
   // The total number of animation flushes by this frame constructor.
   // Used to keep the layer and animation manager in sync.
   uint64_t mAnimationGeneration;
 
   ReframingStyleContexts* mReframingStyleContexts;
 
   RestyleTracker mPendingRestyles;
   RestyleTracker mPendingAnimationRestyles;
+
+#ifdef RESTYLE_LOGGING
+  int32_t mLoggingDepth;
+#endif
 };
 
 /**
  * An ElementRestyler is created for *each* element in a subtree that we
  * recompute styles for.
  */
 class ElementRestyler MOZ_FINAL {
 public:
@@ -446,16 +489,22 @@ public:
    * mHintsHandled changes over time; it starts off as the hints that
    * have been handled by ancestors, and by the end of Restyle it
    * represents the hints that have been handled for this frame.  This
    * method is intended to be called after Restyle, to find out what
    * hints have been handled for this frame.
    */
   nsChangeHint HintsHandledForFrame() { return mHintsHandled; }
 
+#ifdef RESTYLE_LOGGING
+  bool ShouldLogRestyle() {
+    return RestyleManager::ShouldLogRestyle(mPresContext);
+  }
+#endif
+
 private:
   // Enum for the result of RestyleSelf, which indicates whether the
   // restyle procedure should continue to the children, and how.
   //
   // These values must be ordered so that later values imply that all
   // the work of the earlier values is also done.
   enum RestyleResult {
 
@@ -469,18 +518,17 @@ private:
     eRestyleResult_ContinueAndForceDescendants
   };
 
   /**
    * First half of Restyle().
    */
   RestyleResult RestyleSelf(nsIFrame* aSelf,
                             nsRestyleHint aRestyleHint,
-                            uint32_t* aSwappedStructs,
-                            nsIFrame** aProviderFrame);
+                            uint32_t* aSwappedStructs);
 
   /**
    * Restyle the children of this frame (and, in turn, their children).
    *
    * Second half of Restyle().
    */
   void RestyleChildren(nsRestyleHint aChildRestyleHint);
 
@@ -513,16 +561,24 @@ private:
   };
 
   enum A11yNotificationType {
     eDontNotify,
     eNotifyShown,
     eNotifyHidden
   };
 
+#ifdef RESTYLE_LOGGING
+  int32_t& LoggingDepth() { return mLoggingDepth; }
+#endif
+
+#ifdef DEBUG
+  static nsCString RestyleResultToString(RestyleResult aRestyleResult);
+#endif
+
 private:
   nsPresContext* const mPresContext;
   nsIFrame* const mFrame;
   nsIContent* const mParentContent;
   // |mContent| is the node that we used for rule matching of
   // normal elements (not pseudo-elements) and for which we generate
   // framechange hints if we need them.
   nsIContent* const mContent;
@@ -542,13 +598,17 @@ private:
 
 #ifdef ACCESSIBILITY
   const DesiredA11yNotifications mDesiredA11yNotifications;
   DesiredA11yNotifications mKidsDesiredA11yNotifications;
   A11yNotificationType mOurA11yNotification;
   nsTArray<nsIContent*>& mVisibleKidsOfHiddenElement;
   bool mWasFrameVisible;
 #endif
+
+#ifdef RESTYLE_LOGGING
+  int32_t mLoggingDepth;
+#endif
 };
 
 } // namespace mozilla
 
 #endif /* mozilla_RestyleManager_h */
--- a/layout/base/RestyleTracker.cpp
+++ b/layout/base/RestyleTracker.cpp
@@ -7,19 +7,48 @@
  * A class which manages pending restyles.  This handles keeping track
  * of what nodes restyles need to happen on and so forth.
  */
 
 #include "RestyleTracker.h"
 #include "nsStyleChangeList.h"
 #include "RestyleManager.h"
 #include "GeckoProfiler.h"
+#include "nsIDocument.h"
+#include "RestyleTrackerInlines.h"
 
 namespace mozilla {
 
+#ifdef RESTYLE_LOGGING
+static nsCString
+GetDocumentURI(nsIDocument* aDocument)
+{
+  nsCString result;
+  nsString url;
+  aDocument->GetDocumentURI(url);
+  result.Append(NS_ConvertUTF16toUTF8(url).get());
+  return result;
+}
+
+static nsCString
+FrameTagToString(dom::Element* aElement)
+{
+  nsCString result;
+  nsIFrame* frame = aElement->GetPrimaryFrame();
+  if (frame) {
+    nsFrame::ListTag(result, frame);
+  } else {
+    nsAutoString buf;
+    aElement->Tag()->ToString(buf);
+    result.AppendPrintf("(%s@%p)", NS_ConvertUTF16toUTF8(buf).get(), aElement);
+  }
+  return result;
+}
+#endif
+
 inline nsIDocument*
 RestyleTracker::Document() const {
   return mRestyleManager->PresContext()->Document();
 }
 
 #define RESTYLE_ARRAY_STACKSIZE 128
 
 struct LaterSiblingCollector {
@@ -51,16 +80,19 @@ CollectLaterSiblings(nsISupports* aEleme
 
 struct RestyleEnumerateData : RestyleTracker::Hints {
   nsRefPtr<dom::Element> mElement;
 };
 
 struct RestyleCollector {
   RestyleTracker* tracker;
   RestyleEnumerateData** restyleArrayPtr;
+#ifdef RESTYLE_LOGGING
+  uint32_t count;
+#endif
 };
 
 static PLDHashOperator
 CollectRestyles(nsISupports* aElement,
                 nsAutoPtr<RestyleTracker::RestyleData>& aData,
                 void* aRestyleCollector)
 {
   dom::Element* element =
@@ -68,16 +100,19 @@ CollectRestyles(nsISupports* aElement,
   RestyleCollector* collector =
     static_cast<RestyleCollector*>(aRestyleCollector);
   // Only collect the entries that actually need restyling by us (and
   // haven't, for example, already been restyled).
   // It's important to not mess with the flags on entries not in our
   // document.
   if (element->GetCrossShadowCurrentDoc() != collector->tracker->Document() ||
       !element->HasFlag(collector->tracker->RestyleBit())) {
+    LOG_RESTYLE_IF(collector->tracker, true,
+                   "skipping pending restyle %s, already restyled or no longer "
+                   "in the document", FrameTagToString(element).get());
     return PL_DHASH_NEXT;
   }
 
   NS_ASSERTION(!element->HasFlag(collector->tracker->RootBit()) ||
                // Maybe we're just not reachable via the frame tree?
                (element->GetFlattenedTreeParent() &&
                 (!element->GetFlattenedTreeParent()->GetPrimaryFrame()||
                  element->GetFlattenedTreeParent()->GetPrimaryFrame()->IsLeaf())) ||
@@ -96,16 +131,20 @@ CollectRestyles(nsISupports* aElement,
                       collector->tracker->RootBit());
 
   RestyleEnumerateData** restyleArrayPtr = collector->restyleArrayPtr;
   RestyleEnumerateData* currentRestyle = *restyleArrayPtr;
   currentRestyle->mElement = element;
   currentRestyle->mRestyleHint = aData->mRestyleHint;
   currentRestyle->mChangeHint = aData->mChangeHint;
 
+#ifdef RESTYLE_LOGGING
+  collector->count++;
+#endif
+
   // Increment to the next slot in the array
   *restyleArrayPtr = currentRestyle + 1;
 
   return PL_DHASH_NEXT;
 }
 
 inline void
 RestyleTracker::ProcessOneRestyle(Element* aElement,
@@ -113,16 +152,20 @@ RestyleTracker::ProcessOneRestyle(Elemen
                                   nsChangeHint aChangeHint)
 {
   NS_PRECONDITION((aRestyleHint & eRestyle_LaterSiblings) == 0,
                   "Someone should have handled this before calling us");
   NS_PRECONDITION(Document(), "Must have a document");
   NS_PRECONDITION(aElement->GetCrossShadowCurrentDoc() == Document(),
                   "Element has unexpected document");
 
+  LOG_RESTYLE("aRestyleHint = %s, aChangeHint = %s",
+              RestyleManager::RestyleHintToString(aRestyleHint).get(),
+              RestyleManager::ChangeHintToString(aChangeHint).get());
+
   nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
   if (aRestyleHint & ~eRestyle_LaterSiblings) {
     mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint,
                                     *this, aRestyleHint);
   } else if (aChangeHint &&
              (primaryFrame ||
               (aChangeHint & nsChangeHint_ReconstructFrame))) {
     // Don't need to recompute style; just apply the hint
@@ -135,34 +178,47 @@ RestyleTracker::ProcessOneRestyle(Elemen
 void
 RestyleTracker::DoProcessRestyles()
 {
   PROFILER_LABEL("RestyleTracker", "ProcessRestyles",
     js::ProfileEntry::Category::CSS);
 
   mRestyleManager->BeginProcessingRestyles();
 
+  LOG_RESTYLE("Processing %d pending %srestyles with %d restyle roots for %s",
+              mPendingRestyles.Count(),
+              mRestyleManager->PresContext()->IsProcessingAnimationStyleChange()
+                ? (const char*) "animation " : (const char*) "",
+              static_cast<int>(mRestyleRoots.Length()),
+              GetDocumentURI(Document()).get());
+  LOG_RESTYLE_INDENT();
+
   // loop so that we process any restyle events generated by processing
   while (mPendingRestyles.Count()) {
     if (mHaveLaterSiblingRestyles) {
       // Convert them to individual restyles on all the later siblings
       nsAutoTArray<nsRefPtr<Element>, RESTYLE_ARRAY_STACKSIZE> laterSiblingArr;
       LaterSiblingCollector siblingCollector = { this, &laterSiblingArr };
       mPendingRestyles.Enumerate(CollectLaterSiblings, &siblingCollector);
       for (uint32_t i = 0; i < laterSiblingArr.Length(); ++i) {
         Element* element = laterSiblingArr[i];
         for (nsIContent* sibling = element->GetNextSibling();
              sibling;
              sibling = sibling->GetNextSibling()) {
-          if (sibling->IsElement() &&
-              AddPendingRestyle(sibling->AsElement(), eRestyle_Subtree,
-                                NS_STYLE_HINT_NONE)) {
-              // Nothing else to do here; we'll handle the following
-              // siblings when we get to |sibling| in laterSiblingArr.
-            break;
+          if (sibling->IsElement()) {
+            LOG_RESTYLE("adding pending restyle for %s due to "
+                        "eRestyle_LaterSiblings hint on %s",
+                        FrameTagToString(sibling->AsElement()).get(),
+                        FrameTagToString(element->AsElement()).get());
+            if (AddPendingRestyle(sibling->AsElement(), eRestyle_Subtree,
+                                  NS_STYLE_HINT_NONE)) {
+                // Nothing else to do here; we'll handle the following
+                // siblings when we get to |sibling| in laterSiblingArr.
+              break;
+            }
           }
         }
       }
 
       // Now remove all those eRestyle_LaterSiblings bits
       for (uint32_t i = 0; i < laterSiblingArr.Length(); ++i) {
         Element* element = laterSiblingArr[i];
         NS_ASSERTION(element->HasFlag(RestyleBit()), "How did that happen?");
@@ -171,39 +227,48 @@ RestyleTracker::DoProcessRestyles()
         bool found =
 #endif
           mPendingRestyles.Get(element, &data);
         NS_ASSERTION(found, "Where did our entry go?");
         data->mRestyleHint =
           nsRestyleHint(data->mRestyleHint & ~eRestyle_LaterSiblings);
       }
 
+      LOG_RESTYLE("%d pending restyles after expanding out "
+                  "eRestyle_LaterSiblings", mPendingRestyles.Count());
+
       mHaveLaterSiblingRestyles = false;
     }
 
     uint32_t rootCount;
     while ((rootCount = mRestyleRoots.Length())) {
       // Make sure to pop the element off our restyle root array, so
       // that we can freely append to the array as we process this
       // element.
       nsRefPtr<Element> element;
       element.swap(mRestyleRoots[rootCount - 1]);
       mRestyleRoots.RemoveElementAt(rootCount - 1);
 
+      LOG_RESTYLE("processing style root %s at index %d",
+                  FrameTagToString(element).get(), rootCount - 1);
+      LOG_RESTYLE_INDENT();
+
       // Do the document check before calling GetRestyleData, since we
       // don't want to do the sibling-processing GetRestyleData does if
       // the node is no longer relevant.
       if (element->GetCrossShadowCurrentDoc() != Document()) {
         // Content node has been removed from our document; nothing else
         // to do here
+        LOG_RESTYLE("skipping, no longer in the document");
         continue;
       }
 
       nsAutoPtr<RestyleData> data;
       if (!GetRestyleData(element, data)) {
+        LOG_RESTYLE("skipping, already restyled");
         continue;
       }
 
       ProcessOneRestyle(element, data->mRestyleHint, data->mChangeHint);
       AddRestyleRootsIfAwaitingRestyle(data->mDescendants);
     }
 
     if (mHaveLaterSiblingRestyles) {
@@ -222,19 +287,26 @@ RestyleTracker::DoProcessRestyles()
     if (restylesToProcess) {
       RestyleEnumerateData* lastRestyle = restylesToProcess;
       RestyleCollector collector = { this, &lastRestyle };
       mPendingRestyles.Enumerate(CollectRestyles, &collector);
 
       // Clear the hashtable now that we don't need it anymore
       mPendingRestyles.Clear();
 
+#ifdef RESTYLE_LOGGING
+      uint32_t index = 0;
+#endif
       for (RestyleEnumerateData* currentRestyle = restylesToProcess;
            currentRestyle != lastRestyle;
            ++currentRestyle) {
+        LOG_RESTYLE("processing pending restyle %s at index %d/%d",
+                    FrameTagToString(currentRestyle->mElement).get(),
+                    index++, collector.count);
+        LOG_RESTYLE_INDENT();
         ProcessOneRestyle(currentRestyle->mElement,
                           currentRestyle->mRestyleHint,
                           currentRestyle->mChangeHint);
       }
     }
   }
 
   mRestyleManager->EndProcessingRestyles();
--- a/layout/base/RestyleTracker.h
+++ b/layout/base/RestyleTracker.h
@@ -10,16 +10,17 @@
 
 #ifndef mozilla_RestyleTracker_h
 #define mozilla_RestyleTracker_h
 
 #include "mozilla/dom/Element.h"
 #include "nsClassHashtable.h"
 #include "nsContainerFrame.h"
 #include "mozilla/SplayTree.h"
+#include "mozilla/RestyleLogging.h"
 
 namespace mozilla {
 
 class RestyleManager;
 class ElementRestyler;
 
 /** 
  * Helper class that collects a list of frames that need
@@ -228,19 +229,19 @@ private:
 };
 
 class RestyleTracker {
 public:
   typedef mozilla::dom::Element Element;
 
   friend class ElementRestyler; // for AddPendingRestyleToTable
 
-  explicit RestyleTracker(Element::FlagsType aRestyleBits) :
-    mRestyleBits(aRestyleBits),
-    mHaveLaterSiblingRestyles(false)
+  explicit RestyleTracker(Element::FlagsType aRestyleBits)
+    : mRestyleBits(aRestyleBits)
+    , mHaveLaterSiblingRestyles(false)
   {
     NS_PRECONDITION((mRestyleBits & ~ELEMENT_ALL_RESTYLE_FLAGS) == 0,
                     "Why do we have these bits set?");
     NS_PRECONDITION((mRestyleBits & ELEMENT_PENDING_RESTYLE_FLAGS) != 0,
                     "Must have a restyle flag");
     NS_PRECONDITION((mRestyleBits & ELEMENT_PENDING_RESTYLE_FLAGS) !=
                       ELEMENT_PENDING_RESTYLE_FLAGS,
                     "Shouldn't have both restyle flags set");
@@ -337,16 +338,22 @@ public:
   void AddRestyleRootsIfAwaitingRestyle(
                                   const nsTArray<nsRefPtr<Element>>& aElements);
 
   /**
    * The document we're associated with.
    */
   inline nsIDocument* Document() const;
 
+#ifdef RESTYLE_LOGGING
+  // Defined in RestyleTrackerInlines.h.
+  inline bool ShouldLogRestyle();
+  inline int32_t& LoggingDepth();
+#endif
+
 private:
   bool AddPendingRestyleToTable(Element* aElement, nsRestyleHint aRestyleHint,
                                 nsChangeHint aMinChangeHint);
 
   /**
    * Handle a single mPendingRestyles entry.  aRestyleHint must not
    * include eRestyle_LaterSiblings; that needs to be dealt with
    * before calling this function.
new file mode 100644
--- /dev/null
+++ b/layout/base/RestyleTrackerInlines.h
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_RestyleTrackerInlines_h
+#define mozilla_RestyleTrackerInlines_h
+
+#ifdef RESTYLE_LOGGING
+bool
+mozilla::RestyleTracker::ShouldLogRestyle()
+{
+  return mRestyleManager->ShouldLogRestyle();
+}
+
+int32_t&
+mozilla::RestyleTracker::LoggingDepth()
+{
+  return mRestyleManager->LoggingDepth();
+}
+#endif
+
+#endif // !defined(mozilla_RestyleTrackerInlines_h)
--- a/layout/base/SelectionCarets.cpp
+++ b/layout/base/SelectionCarets.cpp
@@ -19,24 +19,26 @@
 #include "nsIDOMDocument.h"
 #include "nsIDOMNodeFilter.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsRect.h"
 #include "nsView.h"
 #include "mozilla/dom/DOMRect.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/ScrollViewChangeEvent.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/dom/TreeWalker.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TouchEvents.h"
 #include "TouchCaret.h"
 #include "nsFrameSelection.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 // We treat mouse/touch move as "REAL" move event once its move distance
 // exceed this value, in CSS pixel.
 static const int32_t kMoveStartTolerancePx = 5;
 // Time for trigger scroll end event, in miliseconds.
 static const int32_t kScrollEndTimerDelay = 300;
 
 NS_IMPL_ISUPPORTS(SelectionCarets,
@@ -45,19 +47,20 @@ NS_IMPL_ISUPPORTS(SelectionCarets,
                   nsISupportsWeakReference)
 
 /*static*/ int32_t SelectionCarets::sSelectionCaretsInflateSize = 0;
 
 SelectionCarets::SelectionCarets(nsIPresShell *aPresShell)
   : mActiveTouchId(-1)
   , mCaretCenterToDownPointOffsetY(0)
   , mDragMode(NONE)
-  , mVisible(false)
+  , mAPZenabled(false)
+  , mEndCaretVisible(false)
   , mStartCaretVisible(false)
-  , mEndCaretVisible(false)
+  , mVisible(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   static bool addedPref = false;
   if (!addedPref) {
     Preferences::AddIntVarCache(&sSelectionCaretsInflateSize,
                                 "selectioncaret.inflatesize.threshold");
     addedPref = true;
@@ -856,21 +859,62 @@ SelectionCarets::NotifySelectionChanged(
   if (aReason & nsISelectionListener::KEYPRESS_REASON) {
     SetVisibility(false);
   } else {
     UpdateSelectionCarets();
   }
   return NS_OK;
 }
 
+static void
+DispatchScrollViewChangeEvent(nsIPresShell *aPresShell, const dom::ScrollState aState, const mozilla::CSSIntPoint aScrollPos)
+{
+  nsCOMPtr<nsIDocument> doc = aPresShell->GetDocument();
+  if (doc) {
+    bool ret;
+    ScrollViewChangeEventInit detail;
+    detail.mBubbles = true;
+    detail.mCancelable = false;
+    detail.mState = aState;
+    detail.mScrollX = aScrollPos.x;
+    detail.mScrollY = aScrollPos.y;
+    nsRefPtr<ScrollViewChangeEvent> event =
+      ScrollViewChangeEvent::Constructor(doc, NS_LITERAL_STRING("scrollviewchange"), detail);
+
+    event->SetTrusted(true);
+    event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+    doc->DispatchEvent(event, &ret);
+  }
+}
+
+void
+SelectionCarets::AsyncPanZoomStarted(const mozilla::CSSIntPoint aScrollPos)
+{
+  // Receives the notifications from AsyncPanZoom, sets mAPZenabled as true here
+  // to bypass the notifications from ScrollPositionChanged callbacks
+  mAPZenabled = true;
+  SetVisibility(false);
+  DispatchScrollViewChangeEvent(mPresShell, dom::ScrollState::Started, aScrollPos);
+}
+
+void
+SelectionCarets::AsyncPanZoomStopped(const mozilla::CSSIntPoint aScrollPos)
+{
+  UpdateSelectionCarets();
+  DispatchScrollViewChangeEvent(mPresShell, dom::ScrollState::Stopped, aScrollPos);
+}
+
 void
 SelectionCarets::ScrollPositionChanged()
 {
-  SetVisibility(false);
-  LaunchScrollEndDetector();
+  if (!mAPZenabled) {
+    SetVisibility(false);
+    //TODO: handling scrolling for selection bubble when APZ is off
+    LaunchScrollEndDetector();
+  }
 }
 
 void
 SelectionCarets::LaunchLongTapDetector()
 {
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
     return;
   }
--- a/layout/base/SelectionCarets.h
+++ b/layout/base/SelectionCarets.h
@@ -59,16 +59,20 @@ public:
   explicit SelectionCarets(nsIPresShell *aPresShell);
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISELECTIONLISTENER
 
   // nsIScrollObserver
   virtual void ScrollPositionChanged() MOZ_OVERRIDE;
 
+  // AsyncPanZoom started/stopped callbacks from nsIScrollObserver
+  virtual void AsyncPanZoomStarted(const mozilla::CSSIntPoint aScrollPos) MOZ_OVERRIDE;
+  virtual void AsyncPanZoomStopped(const mozilla::CSSIntPoint aScrollPos) MOZ_OVERRIDE;
+
   void Terminate()
   {
     mPresShell = nullptr;
   }
 
   nsEventStatus HandleEvent(WidgetEvent* aEvent);
 
   /**
@@ -209,18 +213,21 @@ private:
   // drag distance
   nsPoint mDownPoint;
 
   // For filter multitouch event
   int32_t mActiveTouchId;
 
   nscoord mCaretCenterToDownPointOffsetY;
   DragMode mDragMode;
-  bool mVisible;
+
+  // True if AsyncPanZoom is enabled
+  bool mAPZenabled;
+  bool mEndCaretVisible;
   bool mStartCaretVisible;
-  bool mEndCaretVisible;
+  bool mVisible;
 
   // Preference
   static int32_t sSelectionCaretsInflateSize;
 };
 } // namespace mozilla
 
 #endif //SelectionCarets_h__
--- a/layout/base/moz.build
+++ b/layout/base/moz.build
@@ -54,16 +54,17 @@ EXPORTS += [
     'Units.h',
     'UnitTransforms.h',
     'WordMovementType.h',
 ]
 
 EXPORTS.mozilla += [
     'GeometryUtils.h',
     'PaintTracker.h',
+    'RestyleLogging.h',
 ]
 
 UNIFIED_SOURCES += [
     'ActiveLayerTracker.cpp',
     'DisplayItemClip.cpp',
     'DisplayListClipState.cpp',
     'FrameLayerBuilder.cpp',
     'FramePropertyTable.cpp',
--- a/layout/base/nsChangeHint.h
+++ b/layout/base/nsChangeHint.h
@@ -148,17 +148,18 @@ enum nsChangeHint {
    * set, then nsChangeHint_NeutralChange need not also be included, but it is
    * safe to do so.  (An example of style structs having non-meaningfully
    * different data would be cached information that would be re-calculated
    * to the same values, such as nsStyleBorder::mSubImages.)
    */
   nsChangeHint_NeutralChange = 0x100000
 
   // IMPORTANT NOTE: When adding new hints, consider whether you need to
-  // add them to NS_HintsNotHandledForDescendantsIn() below.
+  // add them to NS_HintsNotHandledForDescendantsIn() below.  Please also
+  // add them to RestyleManager::ChangeHintToString.
 };
 
 // Redefine these operators to return nothing. This will catch any use
 // of these operators on hints. We should not be using these operators
 // on nsChangeHints
 inline void operator<(nsChangeHint s1, nsChangeHint s2) {}
 inline void operator>(nsChangeHint s1, nsChangeHint s2) {}
 inline void operator!=(nsChangeHint s1, nsChangeHint s2) {}
@@ -272,16 +273,19 @@ inline nsChangeHint NS_HintsNotHandledFo
  * can stop processing at a frame when it detects no style changes and it is
  * known that the styles of the subtree beneath it will not change, leaving
  * the old style context on the frame.  eRestyle_Force can be used to skip this
  * optimization on a frame, and to force its new style context to be used.
  *
  * Similarly, eRestyle_ForceDescendants will cause the frame and all of its
  * descendants to be traversed and for the new style contexts that are created
  * to be set on the frames.
+ *
+ * NOTE: When adding new restyle hints, please also add them to
+ * RestyleManager::RestyleHintToString.
  */
 enum nsRestyleHint {
   // Rerun selector matching on the element.  If a new style context
   // results, update the style contexts of descendants.  (Irrelevant if
   // eRestyle_Subtree is also set, since that implies a superset of the
   // work.)
   eRestyle_Self = (1<<0),
 
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -266,16 +266,21 @@ public:
   bool GetSelectedFramesOnly() { return mSelectedFramesOnly; }
   /**
    * Calling this setter makes us compute accurate visible regions at the cost
    * of performance if regions get very complex.
    */
   void SetAccurateVisibleRegions() { mAccurateVisibleRegions = true; }
   bool GetAccurateVisibleRegions() { return mAccurateVisibleRegions; }
   /**
+   * @return Returns true if we should include the caret in any display lists
+   * that we make.
+   */
+  bool IsBuildingCaret() { return mBuildCaret; }
+  /**
    * Allows callers to selectively override the regular paint suppression checks,
    * so that methods like GetFrameForPoint work when painting is suppressed.
    */
   void IgnorePaintSuppression() { mIgnoreSuppression = true; }
   /**
    * @return Returns if this builder will ignore paint suppression.
    */
   bool IsIgnoringPaintSuppression() { return mIgnoreSuppression; }
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -36,17 +36,17 @@
 #include "SurfaceCache.h"
 #include "nsCSSRuleProcessor.h"
 #include "nsRuleNode.h"
 #include "gfxPlatform.h"
 #include "nsCSSRules.h"
 #include "nsFontFaceLoader.h"
 #include "mozilla/EventListenerManager.h"
 #include "prenv.h"
-#include "nsObjectFrame.h"
+#include "nsPluginFrame.h"
 #include "nsTransitionManager.h"
 #include "nsAnimationManager.h"
 #include "CounterStyleManager.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/Element.h"
 #include "nsIMessageManager.h"
 #include "mozilla/dom/MediaQueryList.h"
 #include "nsSMILAnimationController.h"
@@ -1069,16 +1069,20 @@ nsPresContext::Init(nsDeviceContext* aDe
                                 "nglayout.debug.paint_flashing_chrome",
                                 this);
 
   nsresult rv = mEventManager->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   mEventManager->SetPresContext(this);
 
+#ifdef RESTYLE_LOGGING
+  mRestyleLoggingEnabled = RestyleManager::RestyleLoggingInitiallyEnabled();
+#endif
+
 #ifdef DEBUG
   mInitialized = true;
 #endif
 
   mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THIN] = CSSPixelsToAppUnits(1);
   mBorderWidthTable[NS_STYLE_BORDER_WIDTH_MEDIUM] = CSSPixelsToAppUnits(3);
   mBorderWidthTable[NS_STYLE_BORDER_WIDTH_THICK] = CSSPixelsToAppUnits(5);
 
@@ -2851,17 +2855,17 @@ nsRootPresContext::UnregisterPluginForGe
 {
   mRegisteredPlugins.RemoveEntry(aPlugin);
 }
 
 static PLDHashOperator
 SetPluginHidden(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
 {
   nsIFrame* root = static_cast<nsIFrame*>(userArg);
-  nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
+  nsPluginFrame* f = static_cast<nsPluginFrame*>(aEntry->GetKey()->GetPrimaryFrame());
   if (!f) {
     NS_WARNING("Null frame in SetPluginHidden");
     return PL_DHASH_NEXT;
   }
   if (!nsLayoutUtils::IsAncestorFrameCrossDoc(root, f)) {
     // f is not managed by this frame so we should ignore it.
     return PL_DHASH_NEXT;
   }
@@ -3011,34 +3015,34 @@ SortConfigurations(nsTArray<nsIWidget::C
     aConfigurations->AppendElement(pluginsToMove[i]);
     pluginsToMove.RemoveElementAt(i);
   }
 }
 
 static PLDHashOperator
 PluginDidSetGeometryEnumerator(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
 {
-  nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
+  nsPluginFrame* f = static_cast<nsPluginFrame*>(aEntry->GetKey()->GetPrimaryFrame());
   if (!f) {
     NS_WARNING("Null frame in PluginDidSetGeometryEnumerator");
     return PL_DHASH_NEXT;
   }
   f->DidSetWidgetGeometry();
   return PL_DHASH_NEXT;
 }
 
 struct PluginGetGeometryUpdateClosure {
   nsTArray<nsIWidget::Configuration> mConfigurations;
 };
 static PLDHashOperator
 PluginGetGeometryUpdate(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
 {
   PluginGetGeometryUpdateClosure* closure =
     static_cast<PluginGetGeometryUpdateClosure*>(userArg);
-  nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
+  nsPluginFrame* f = static_cast<nsPluginFrame*>(aEntry->GetKey()->GetPrimaryFrame());
   if (!f) {
     NS_WARNING("Null frame in GetPluginGeometryUpdate");
     return PL_DHASH_NEXT;
   }
   f->GetWidgetConfiguration(&closure->mConfigurations);
   return PL_DHASH_NEXT;
 }
 
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -32,16 +32,17 @@
 #include "nsAutoPtr.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/AppUnits.h"
 #include "prclist.h"
 #include "nsThreadUtils.h"
 #include "ScrollbarStyles.h"
 #include "nsIMessageManager.h"
+#include "mozilla/RestyleLogging.h"
 
 class nsBidiPresUtils;
 class nsAString;
 class nsIPrintSettings;
 class nsDocShell;
 class nsIDocShell;
 class nsIDocument;
 class nsILanguageAtomService;
@@ -54,17 +55,17 @@ class nsIAtom;
 class nsICSSPseudoComparator;
 struct nsStyleBackground;
 struct nsStyleBorder;
 class nsIRunnable;
 class gfxUserFontSet;
 class gfxTextPerfMetrics;
 class nsUserFontSet;
 struct nsFontFaceRuleContainer;
-class nsObjectFrame;
+class nsPluginFrame;
 class nsTransitionManager;
 class nsAnimationManager;
 class nsRefreshDriver;
 class nsIWidget;
 class nsDeviceContext;
 
 namespace mozilla {
 class EventStateManager;
@@ -1146,16 +1147,24 @@ public:
 
   /**
    * Checks for MozAfterPaint listeners on the document and
    * any subdocuments, except for subdocuments that are non-top-level
    * content documents.
    */
   bool MayHavePaintEventListenerInSubDocument();
 
+#ifdef RESTYLE_LOGGING
+  // Controls for whether debug information about restyling in this
+  // document should be output.
+  bool RestyleLoggingEnabled() const { return mRestyleLoggingEnabled; }
+  void StartRestyleLogging() { mRestyleLoggingEnabled = true; }
+  void StopRestyleLogging() { mRestyleLoggingEnabled = false; }
+#endif
+
 protected:
   void InvalidateThebesLayers();
   void AppUnitsPerDevPixelChanged();
 
   void HandleRebuildUserFontSet() {
     mPostedFlushUserFontSet = false;
     FlushUserFontSet();
   }
@@ -1347,16 +1356,21 @@ protected:
 
   // Should we paint flash in this context? Do not use this variable directly.
   // Use GetPaintFlashing() method instead.
   mutable unsigned mPaintFlashing : 1;
   mutable unsigned mPaintFlashingInitialized : 1;
 
   unsigned mHasWarnedAboutPositionedTableParts : 1;
 
+#ifdef RESTYLE_LOGGING
+  // Should we output debug information about restyling for this document?
+  bool                  mRestyleLoggingEnabled;
+#endif
+
 #ifdef DEBUG
   bool                  mInitialized;
 #endif
 
 
 protected:
 
   virtual ~nsPresContext();
@@ -1426,17 +1440,17 @@ public:
   bool NeedToComputePluginGeometryUpdates()
   {
     return mRegisteredPlugins.Count() > 0;
   }
   /**
    * Compute geometry updates for each plugin given that aList is the display
    * list for aFrame. The updates are not yet applied;
    * ApplyPluginGeometryUpdates is responsible for that. In the meantime they
-   * are stored on each nsObjectFrame.
+   * are stored on each nsPluginFrame.
    * This needs to be called even when aFrame is a popup, since although
    * windowed plugins aren't allowed in popups, windowless plugins are
    * and ComputePluginGeometryUpdates needs to be called for them.
    */
   void ComputePluginGeometryUpdates(nsIFrame* aFrame,
                                     nsDisplayListBuilder* aBuilder,
                                     nsDisplayList* aList);
 
--- a/layout/base/tests/mochitest.ini
+++ b/layout/base/tests/mochitest.ini
@@ -485,8 +485,9 @@ skip-if = true || (toolkit == 'android')
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 948948
 [test_bug687297.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 948948
 support-files =
   bug687297_a.html
   bug687297_b.html
   bug687297_c.html
 [test_bug990340.html]
+[test_bug1070851.html]
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/test_bug1070851.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1070851
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1070851</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+  <style>
+  /* Eliminate the blue glow when focusing an element. */
+  input, textarea, div {
+    background: none;
+    border: none;
+    outline: none;
+  }
+  </style>
+
+  <script type="application/javascript">
+
+  /** Test for Bug 1070851 **/
+
+  SimpleTest.waitForExplicitFinish();
+
+  function testSnapshot(aElementId)
+  {
+    var noTouchCaret = snapshotWindow(window, true);
+
+    // Focus the element to make the touch caret show, but do not capture it.
+    var element = document.getElementById(aElementId);
+    element.focus();
+    var notCaptureTouchCaret = snapshotWindow(window, false);
+
+    [result, first, second] = compareSnapshots(noTouchCaret, notCaptureTouchCaret,
+                                               true);
+    ok(result, "Both snapshots of " + aElementId + " should have no touch caret." +
+       "\nFirst snapshot: " + first + "\nSecond snapshot: " + second);
+
+    element.blur();
+  }
+
+  SimpleTest.waitForFocus(function() {
+    testSnapshot('input');
+    testSnapshot('textarea');
+    testSnapshot('content');
+    SimpleTest.finish();
+  })
+  </script>
+</head>
+<body>
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1070851">Mozilla Bug 1070851</a>
+  <input id="input">
+  <textarea id="textarea"></textarea>
+  <div id="content" contenteditable="true">test</div>
+</body>
+</html>
--- a/layout/generic/moz.build
+++ b/layout/generic/moz.build
@@ -22,17 +22,17 @@ EXPORTS += [
     'nsIFrameInlines.h',
     'nsIFrameUtil.h',
     'nsILineIterator.h',
     'nsIObjectFrame.h',
     'nsIPageSequenceFrame.h',
     'nsIScrollableFrame.h',
     'nsIScrollPositionListener.h',
     'nsIStatefulFrame.h',
-    'nsObjectFrame.h',
+    'nsPluginFrame.h',
     'nsQueryFrame.h',
     'nsSplittableFrame.h',
     'nsSubDocumentFrame.h',
     'nsTextRunTransformations.h',
     'ScrollbarActivity.h',
     'Selection.h',
     'WritingModes.h',
 ]
@@ -95,20 +95,20 @@ UNIFIED_SOURCES += [
     'nsVideoFrame.cpp',
     'nsViewportFrame.cpp',
     'ScrollbarActivity.cpp',
     'StickyScrollContainer.cpp',
     'TextOverflow.cpp',
 ]
 
 # nsLineLayout.cpp needs to be built separately because it uses plarena.h.
-# nsObjectFrame.cpp needs to be built separately because of name clashes in the OS X headers.
+# nsPluginFrame.cpp needs to be built separately because of name clashes in the OS X headers.
 SOURCES += [
     'nsLineLayout.cpp',
-    'nsObjectFrame.cpp',
+    'nsPluginFrame.cpp',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     UNIFIED_SOURCES += [
         'nsPluginUtilsOSX.mm',
     ]
 
 FAIL_ON_WARNINGS = not CONFIG['_MSC_VER']
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -411,16 +411,21 @@ nsCanvasFrame::BuildDisplayList(nsDispla
     if (needBlendContainer) {
       aLists.BorderBackground()->AppendNewToTop(
         new (aBuilder) nsDisplayBlendContainer(aBuilder, this, aLists.BorderBackground()));
     }
   }
 
   nsIFrame* kid;
   for (kid = GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
+    // Skip touch caret frame if we do not build caret.
+    if (!aBuilder->IsBuildingCaret() && kid->GetContent() == mTouchCaretElement) {
+      continue;
+    }
+
     // Put our child into its own pseudo-stack.
     BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
   }
 
 #ifdef DEBUG_CANVAS_FOCUS
   nsCOMPtr<nsIContent> focusContent;
   aPresContext->EventStateManager()->
     GetFocusedContent(getter_AddRefs(focusContent));
--- a/layout/generic/nsFrameIdList.h
+++ b/layout/generic/nsFrameIdList.h
@@ -98,17 +98,17 @@ FRAME_ID(nsMathMLmunderFrame)
 FRAME_ID(nsMathMLmunderoverFrame)
 FRAME_ID(nsMathMLsemanticsFrame)
 FRAME_ID(nsMathMLTokenFrame)
 FRAME_ID(nsMenuBarFrame)
 FRAME_ID(nsMenuFrame)
 FRAME_ID(nsMenuPopupFrame)
 FRAME_ID(nsMeterFrame)
 FRAME_ID(nsNumberControlFrame)
-FRAME_ID(nsObjectFrame)
+FRAME_ID(nsPluginFrame)
 FRAME_ID(nsPageBreakFrame)
 FRAME_ID(nsPageContentFrame)
 FRAME_ID(nsPageFrame)
 FRAME_ID(nsPlaceholderFrame)
 FRAME_ID(nsPopupSetFrame)
 FRAME_ID(nsProgressFrame)
 FRAME_ID(nsProgressMeterFrame)
 FRAME_ID(nsRangeFrame)
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -483,19 +483,19 @@ nsHTMLScrollFrame::ReflowScrolledFrame(S
   // it to the correct size anyway in PlaceScrollArea. Allowing it to
   // resize here would size it to the natural height of the frame,
   // which will usually be different from the scrollport height;
   // invalidating the difference will cause unnecessary repainting.
   FinishReflowChild(mHelper.mScrolledFrame, presContext,
                     *aMetrics, &kidReflowState, 0, 0,
                     NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_SIZE_VIEW);
 
-  // XXX Some frames (e.g., nsObjectFrame, nsFrameFrame, nsTextFrame) don't bother
+  // XXX Some frames (e.g., nsPluginFrame, nsFrameFrame, nsTextFrame) don't bother
   // setting their mOverflowArea. This is wrong because every frame should
-  // always set mOverflowArea. In fact nsObjectFrame and nsFrameFrame don't
+  // always set mOverflowArea. In fact nsPluginFrame and nsFrameFrame don't
   // support the 'outline' property because of this. Rather than fix the world
   // right now, just fix up the overflow area if necessary. Note that we don't
   // check HasOverflowRect() because it could be set even though the
   // overflow area doesn't include the frame bounds.
   aMetrics->UnionOverflowAreasWithDesiredBounds();
 
   if (MOZ_UNLIKELY(StyleDisplay()->mOverflowClipBox ==
                      NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX)) {
rename from layout/generic/nsObjectFrame.cpp
rename to layout/generic/nsPluginFrame.cpp
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsPluginFrame.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 // vim:set ts=2 sts=2 sw=2 et cin:
 /* 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/. */
 
 /* rendering objects for replaced elements implemented by a plugin */
 
-#include "nsObjectFrame.h"
+#include "nsPluginFrame.h"
 
 #include "gfx2DGlue.h"
 #include "gfxMatrix.h"
 #include "mozilla/BasicEvents.h"
 #ifdef XP_WIN
 // This is needed for DoublePassRenderingEvent.
 #include "mozilla/plugins/PluginMessageUtils.h"
 #endif
@@ -92,17 +92,17 @@ using mozilla::DefaultXDisplay;
 #endif
 
 #ifdef PR_LOGGING 
 static PRLogModuleInfo *
 GetObjectFrameLog()
 {
   static PRLogModuleInfo *sLog;
   if (!sLog)
-    sLog = PR_NewLogModule("nsObjectFrame");
+    sLog = PR_NewLogModule("nsPluginFrame");
   return sLog;
 }
 #endif /* PR_LOGGING */
 
 #if defined(XP_MACOSX) && !defined(__LP64__)
 
 // The header files QuickdrawAPI.h and QDOffscreen.h are missing on OS X 10.7
 // and up (though the QuickDraw APIs defined in them are still present) -- so
@@ -140,17 +140,17 @@ extern "C" {
 #endif /* #if defined(XP_MACOSX) && !defined(__LP64__) */
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
 class PluginBackgroundSink : public ReadbackSink {
 public:
-  PluginBackgroundSink(nsObjectFrame* aFrame, uint64_t aStartSequenceNumber)
+  PluginBackgroundSink(nsPluginFrame* aFrame, uint64_t aStartSequenceNumber)
     : mLastSequenceNumber(aStartSequenceNumber), mFrame(aFrame) {}
   ~PluginBackgroundSink()
   {
     if (mFrame) {
       mFrame->mBackgroundSink = nullptr;
     }
   }
 
@@ -182,67 +182,67 @@ protected:
         mFrame->mInstanceOwner) {
       mLastSequenceNumber = aSequenceNumber;
       return true;
     }
     return false;
   }
 
   uint64_t mLastSequenceNumber;
-  nsObjectFrame* mFrame;
+  nsPluginFrame* mFrame;
 };
 
-nsObjectFrame::nsObjectFrame(nsStyleContext* aContext)
-  : nsObjectFrameSuper(aContext)
+nsPluginFrame::nsPluginFrame(nsStyleContext* aContext)
+  : nsPluginFrameSuper(aContext)
   , mReflowCallbackPosted(false)
 {
   PR_LOG(GetObjectFrameLog(), PR_LOG_DEBUG,
-         ("Created new nsObjectFrame %p\n", this));
+         ("Created new nsPluginFrame %p\n", this));
 }
 
-nsObjectFrame::~nsObjectFrame()
+nsPluginFrame::~nsPluginFrame()
 {
   PR_LOG(GetObjectFrameLog(), PR_LOG_DEBUG,
-         ("nsObjectFrame %p deleted\n", this));
+         ("nsPluginFrame %p deleted\n", this));
 }
 
-NS_QUERYFRAME_HEAD(nsObjectFrame)
-  NS_QUERYFRAME_ENTRY(nsObjectFrame)
+NS_QUERYFRAME_HEAD(nsPluginFrame)
+  NS_QUERYFRAME_ENTRY(nsPluginFrame)
   NS_QUERYFRAME_ENTRY(nsIObjectFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsObjectFrameSuper)
+NS_QUERYFRAME_TAIL_INHERITING(nsPluginFrameSuper)
 
 #ifdef ACCESSIBILITY
 a11y::AccType
-nsObjectFrame::AccessibleType()
+nsPluginFrame::AccessibleType()
 {
   return a11y::ePluginType;
 }
 
 #ifdef XP_WIN
-NS_IMETHODIMP nsObjectFrame::GetPluginPort(HWND *aPort)
+NS_IMETHODIMP nsPluginFrame::GetPluginPort(HWND *aPort)
 {
   *aPort = (HWND) mInstanceOwner->GetPluginPortFromWidget();
   return NS_OK;
 }
 #endif
 #endif
 
 void
-nsObjectFrame::Init(nsIContent*       aContent,
+nsPluginFrame::Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow)
 {
   PR_LOG(GetObjectFrameLog(), PR_LOG_DEBUG,
-         ("Initializing nsObjectFrame %p for content %p\n", this, aContent));
+         ("Initializing nsPluginFrame %p for content %p\n", this, aContent));
 
-  nsObjectFrameSuper::Init(aContent, aParent, aPrevInFlow);
+  nsPluginFrameSuper::Init(aContent, aParent, aPrevInFlow);
 }
 
 void
-nsObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
+nsPluginFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   if (mReflowCallbackPosted) {
     PresContext()->PresShell()->CancelReflowCallback(this);
   }
 
   // Tell content owner of the instance to disconnect its frame.
   nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
   NS_ASSERTION(objContent, "Why not an object loading content?");
@@ -254,51 +254,51 @@ nsObjectFrame::DestroyFrom(nsIFrame* aDe
     mInstanceOwner->SetFrame(nullptr);
   }
   objContent->HasNewFrame(nullptr);
 
   if (mBackgroundSink) {
     mBackgroundSink->Destroy();
   }
 
-  nsObjectFrameSuper::DestroyFrom(aDestructRoot);
+  nsPluginFrameSuper::DestroyFrom(aDestructRoot);
 }
 
 /* virtual */ void
-nsObjectFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
+nsPluginFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
   if (HasView()) {
     nsView* view = GetView();
     nsViewManager* vm = view->GetViewManager();
     if (vm) {
       nsViewVisibility visibility = 
         IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow;
       vm->SetViewVisibility(view, visibility);
     }
   }
 
-  nsObjectFrameSuper::DidSetStyleContext(aOldStyleContext);
+  nsPluginFrameSuper::DidSetStyleContext(aOldStyleContext);
 }
 
 nsIAtom*
-nsObjectFrame::GetType() const
+nsPluginFrame::GetType() const
 {
   return nsGkAtoms::objectFrame; 
 }
 
 #ifdef DEBUG_FRAME_DUMP
 nsresult
-nsObjectFrame::GetFrameName(nsAString& aResult) const
+nsPluginFrame::GetFrameName(nsAString& aResult) const
 {
-  return MakeFrameName(NS_LITERAL_STRING("ObjectFrame"), aResult);
+  return MakeFrameName(NS_LITERAL_STRING("PluginFrame"), aResult);
 }
 #endif
 
 nsresult
-nsObjectFrame::PrepForDrawing(nsIWidget *aWidget)
+nsPluginFrame::PrepForDrawing(nsIWidget *aWidget)
 {
   mWidget = aWidget;
 
   nsView* view = GetView();
   NS_ASSERTION(view, "Object frames must have views");  
   if (!view) {
     return NS_ERROR_FAILURE;
   }
@@ -406,39 +406,39 @@ nsObjectFrame::PrepForDrawing(nsIWidget 
 
   return NS_OK;
 }
 
 #define EMBED_DEF_WIDTH 240
 #define EMBED_DEF_HEIGHT 200
 
 /* virtual */ nscoord
-nsObjectFrame::GetMinISize(nsRenderingContext *aRenderingContext)
+nsPluginFrame::GetMinISize(nsRenderingContext *aRenderingContext)
 {
   nscoord result = 0;
 
   if (!IsHidden(false)) {
     nsIAtom *atom = mContent->Tag();
     if (atom == nsGkAtoms::applet || atom == nsGkAtoms::embed) {
       result = nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH);
     }
   }
 
   DISPLAY_MIN_WIDTH(this, result);
   return result;
 }
 
 /* virtual */ nscoord
-nsObjectFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
+nsPluginFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
 {
-  return nsObjectFrame::GetMinISize(aRenderingContext);
+  return nsPluginFrame::GetMinISize(aRenderingContext);
 }
 
 void
-nsObjectFrame::GetDesiredSize(nsPresContext* aPresContext,
+nsPluginFrame::GetDesiredSize(nsPresContext* aPresContext,
                               const nsHTMLReflowState& aReflowState,
                               nsHTMLReflowMetrics& aMetrics)
 {
   // By default, we have no area
   aMetrics.ClearSize();
 
   if (IsHidden(false)) {
     return;
@@ -493,22 +493,22 @@ nsObjectFrame::GetDesiredSize(nsPresCont
   // XXXbz don't add in the border and padding, because we screw up our
   // plugin's size and positioning if we do...  Eventually we _do_ want to
   // paint borders, though!  At that point, we will need to adjust the desired
   // size either here or in Reflow....  Further, we will need to fix Paint() to
   // call the superclass in all cases.
 }
 
 void
-nsObjectFrame::Reflow(nsPresContext*           aPresContext,
+nsPluginFrame::Reflow(nsPresContext*           aPresContext,
                       nsHTMLReflowMetrics&     aMetrics,
                       const nsHTMLReflowState& aReflowState,
                       nsReflowStatus&          aStatus)
 {
-  DO_GLOBAL_REFLOW_COUNT("nsObjectFrame");
+  DO_GLOBAL_REFLOW_COUNT("nsPluginFrame");
   DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
 
   // Get our desired size
   GetDesiredSize(aPresContext, aReflowState, aMetrics);
   aMetrics.SetOverflowAreasToDesiredBounds();
   FinishAndStoreOverflow(&aMetrics);
 
   // delay plugin instantiation until all children have
@@ -543,31 +543,31 @@ nsObjectFrame::Reflow(nsPresContext*    
   aStatus = NS_FRAME_COMPLETE;
 
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
 }
 
 ///////////// nsIReflowCallback ///////////////
 
 bool
-nsObjectFrame::ReflowFinished()
+nsPluginFrame::ReflowFinished()
 {
   mReflowCallbackPosted = false;
   CallSetWindow();
   return true;
 }
 
 void
-nsObjectFrame::ReflowCallbackCanceled()
+nsPluginFrame::ReflowCallbackCanceled()
 {
   mReflowCallbackPosted = false;
 }
 
 void
-nsObjectFrame::FixupWindow(const nsSize& aSize)
+nsPluginFrame::FixupWindow(const nsSize& aSize)
 {
   nsPresContext* presContext = PresContext();
 
   if (!mInstanceOwner)
     return;
 
   NPWindow *window;
   mInstanceOwner->GetWindow(window);
@@ -608,17 +608,17 @@ nsObjectFrame::FixupWindow(const nsSize&
 #else
   mInstanceOwner->UpdateWindowPositionAndClipRect(false);
 #endif
 
   NotifyPluginReflowObservers();
 }
 
 nsresult
-nsObjectFrame::CallSetWindow(bool aCheckIsHidden)
+nsPluginFrame::CallSetWindow(bool aCheckIsHidden)
 {
   NPWindow *win = nullptr;
  
   nsresult rv = NS_ERROR_FAILURE;
   nsRefPtr<nsNPAPIPluginInstance> pi;
   if (!mInstanceOwner ||
       NS_FAILED(rv = mInstanceOwner->GetInstance(getter_AddRefs(pi))) ||
       !pi ||
@@ -678,17 +678,17 @@ nsObjectFrame::CallSetWindow(bool aCheck
   }
 
   instanceOwnerRef->ReleasePluginPort(window->window);
 
   return rv;
 }
 
 void
-nsObjectFrame::RegisterPluginForGeometryUpdates()
+nsPluginFrame::RegisterPluginForGeometryUpdates()
 {
   nsRootPresContext* rpc = PresContext()->GetRootPresContext();
   NS_ASSERTION(rpc, "We should have a root pres context!");
   if (mRootPresContextRegisteredWith == rpc || !rpc) {
     // Already registered with current root pres context,
     // or null root pres context...
     return;
   }
@@ -697,28 +697,28 @@ nsObjectFrame::RegisterPluginForGeometry
     // re-register with our current one...
     UnregisterPluginForGeometryUpdates();
   }
   mRootPresContextRegisteredWith = rpc;
   mRootPresContextRegisteredWith->RegisterPluginForGeometryUpdates(mContent);
 }
 
 void
-nsObjectFrame::UnregisterPluginForGeometryUpdates()
+nsPluginFrame::UnregisterPluginForGeometryUpdates()
 {
   if (!mRootPresContextRegisteredWith) {
     // Not registered...
     return;
   }
   mRootPresContextRegisteredWith->UnregisterPluginForGeometryUpdates(mContent);
   mRootPresContextRegisteredWith = nullptr;
 }
 
 void
-nsObjectFrame::SetInstanceOwner(nsPluginInstanceOwner* aOwner)
+nsPluginFrame::SetInstanceOwner(nsPluginInstanceOwner* aOwner)
 {
   // The ownership model here is historically fuzzy. This should only be called
   // by nsPluginInstanceOwner when it is given a new frame, and
   // nsObjectLoadingContent should be arbitrating frame-ownership via its
   // HasNewFrame callback.
   mInstanceOwner = aOwner;
   if (mInstanceOwner) {
     return;
@@ -738,25 +738,25 @@ nsObjectFrame::SetInstanceOwner(nsPlugin
       mWidget->Show(false);
       mWidget->Enable(false);
       mWidget->SetParent(nullptr);
     }
   }
 }
 
 bool
-nsObjectFrame::IsFocusable(int32_t *aTabIndex, bool aWithMouse)
+nsPluginFrame::IsFocusable(int32_t *aTabIndex, bool aWithMouse)
 {
   if (aTabIndex)
     *aTabIndex = -1;
-  return nsObjectFrameSuper::IsFocusable(aTabIndex, aWithMouse);
+  return nsPluginFrameSuper::IsFocusable(aTabIndex, aWithMouse);
 }
 
 bool
-nsObjectFrame::IsHidden(bool aCheckVisibilityStyle) const
+nsPluginFrame::IsHidden(bool aCheckVisibilityStyle) const
 {
   if (aCheckVisibilityStyle) {
     if (!StyleVisibility()->IsVisibleOrCollapsed())
       return true;    
   }
 
   // only <embed> tags support the HIDDEN attribute
   if (mContent->Tag() == nsGkAtoms::embed) {
@@ -775,17 +775,17 @@ nsObjectFrame::IsHidden(bool aCheckVisib
          !hidden.LowerCaseEqualsLiteral("off")))) {
       return true;
     }
   }
 
   return false;
 }
 
-nsIntPoint nsObjectFrame::GetWindowOriginInPixels(bool aWindowless)
+nsIntPoint nsPluginFrame::GetWindowOriginInPixels(bool aWindowless)
 {
   nsView * parentWithView;
   nsPoint origin(0,0);
 
   GetOffsetFromView(origin, &parentWithView);
 
   // if it's windowless, let's make sure we have our origin set right
   // it may need to be corrected, like after scrolling
@@ -796,61 +796,61 @@ nsIntPoint nsObjectFrame::GetWindowOrigi
   }
   origin += GetContentRectRelativeToSelf().TopLeft();
 
   return nsIntPoint(PresContext()->AppUnitsToDevPixels(origin.x),
                     PresContext()->AppUnitsToDevPixels(origin.y));
 }
 
 void
-nsObjectFrame::DidReflow(nsPresContext*            aPresContext,
+nsPluginFrame::DidReflow(nsPresContext*            aPresContext,
                          const nsHTMLReflowState*  aReflowState,
                          nsDidReflowStatus         aStatus)
 {
   // Do this check before calling the superclass, as that clears
   // NS_FRAME_FIRST_REFLOW
   if (aStatus == nsDidReflowStatus::FINISHED &&
       (GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
     nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
     NS_ASSERTION(objContent, "Why not an object loading content?");
     objContent->HasNewFrame(this);
   }
 
-  nsObjectFrameSuper::DidReflow(aPresContext, aReflowState, aStatus);
+  nsPluginFrameSuper::DidReflow(aPresContext, aReflowState, aStatus);
 
   // The view is created hidden; once we have reflowed it and it has been
   // positioned then we show it.
   if (aStatus != nsDidReflowStatus::FINISHED)
     return;
 
   if (HasView()) {
     nsView* view = GetView();
     nsViewManager* vm = view->GetViewManager();
     if (vm)
       vm->SetViewVisibility(view, IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow);
   }
 }
 
 /* static */ void
-nsObjectFrame::PaintPrintPlugin(nsIFrame* aFrame, nsRenderingContext* aCtx,
+nsPluginFrame::PaintPrintPlugin(nsIFrame* aFrame, nsRenderingContext* aCtx,
                                 const nsRect& aDirtyRect, nsPoint aPt)
 {
   gfxContext* ctx = aCtx->ThebesContext();
 
   // Translate the context:
   nsPoint pt = aPt + aFrame->GetContentRectRelativeToSelf().TopLeft();
   gfxPoint devPixelPt =
     nsLayoutUtils::PointToGfxPoint(pt, aFrame->PresContext()->AppUnitsPerDevPixel());
 
   gfxContextMatrixAutoSaveRestore autoSR(ctx);
   ctx->SetMatrix(ctx->CurrentMatrix().Translate(devPixelPt));
 
   // FIXME - Bug 385435: Doesn't aDirtyRect need translating too?
 
-  static_cast<nsObjectFrame*>(aFrame)->PrintPlugin(*aCtx, aDirtyRect);
+  static_cast<nsPluginFrame*>(aFrame)->PrintPlugin(*aCtx, aDirtyRect);
 }
 
 /**
  * nsDisplayPluginReadback creates an active ReadbackLayer. The ReadbackLayer
  * obtains from the compositor the contents of the window underneath
  * the ReadbackLayer, which we then use as an opaque buffer for plugins to
  * asynchronously draw onto.
  */
@@ -871,17 +871,17 @@ public:
                            bool* aSnap) MOZ_OVERRIDE;
 
   NS_DISPLAY_DECL_NAME("PluginReadback", TYPE_PLUGIN_READBACK)
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE
   {
-    return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters);
+    return static_cast<nsPluginFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters);
   }
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) MOZ_OVERRIDE
   {
     return LAYER_ACTIVE;
   }
@@ -920,17 +920,17 @@ public:
                            bool* aSnap) MOZ_OVERRIDE;
 
   NS_DISPLAY_DECL_NAME("PluginVideo", TYPE_PLUGIN_VIDEO)
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE
   {
-    return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters);
+    return static_cast<nsPluginFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters);
   }
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) MOZ_OVERRIDE
   {
     return LAYER_ACTIVE;
   }
@@ -956,27 +956,27 @@ nsDisplayPlugin::GetBounds(nsDisplayList
   *aSnap = true;
   return GetDisplayItemBounds(aBuilder, this, mFrame);
 }
 
 void
 nsDisplayPlugin::Paint(nsDisplayListBuilder* aBuilder,
                        nsRenderingContext* aCtx)
 {
-  nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
+  nsPluginFrame* f = static_cast<nsPluginFrame*>(mFrame);
   bool snap;
   f->PaintPlugin(aBuilder, *aCtx, mVisibleRect, GetBounds(aBuilder, &snap));