Merge mozilla-central to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 13 Jul 2016 17:28:49 +0200
changeset 304906 0b6a509a03d1fdec9a92e41c45730b8a6975caac
parent 304905 98e51699f47e171256a8eb54605bed04a0be5e71 (current diff)
parent 304871 5fc004cf355f0321c2f6de841f84c20822bc2a91 (diff)
child 304907 9efa66f1c6a15449be7a3c37ade8e104ce2afef8
push id30446
push usercbook@mozilla.com
push dateThu, 14 Jul 2016 09:44:34 +0000
treeherdermozilla-central@cd9da00ffcc3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to fx-team
browser/locales/generic/extract-bookmarks.py
dom/canvas/test/webgl-conf/checkout/conformance/ogles/GL/biv_array_oob/biv_array_oob_001_to_001.html
dom/canvas/test/webgl-conf/checkout/conformance/ogles/GL/biv_array_oob/gl_Color.frag
dom/canvas/test/webgl-conf/checkout/conformance/resources/1-channel.jpg
dom/canvas/test/webgl-conf/checkout/conformance/resources/3x3.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/blue-1x1.jpg
dom/canvas/test/webgl-conf/checkout/conformance/resources/bug-32888-texture.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/gray-ramp-256-with-128-alpha.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/gray-ramp-256.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/gray-ramp-default-gamma.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/gray-ramp-gamma0.1.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/gray-ramp-gamma1.0.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/gray-ramp-gamma2.0.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/gray-ramp-gamma4.0.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/gray-ramp-gamma9.0.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/gray-ramp.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/green-2x2-16bit.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/npot-video.mp4
dom/canvas/test/webgl-conf/checkout/conformance/resources/npot-video.theora.ogv
dom/canvas/test/webgl-conf/checkout/conformance/resources/npot-video.webmvp8.webm
dom/canvas/test/webgl-conf/checkout/conformance/resources/opengl_logo.jpg
dom/canvas/test/webgl-conf/checkout/conformance/resources/red-green.mp4
dom/canvas/test/webgl-conf/checkout/conformance/resources/red-green.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/red-green.theora.ogv
dom/canvas/test/webgl-conf/checkout/conformance/resources/red-green.webmvp8.webm
dom/canvas/test/webgl-conf/checkout/conformance/resources/red-indexed.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/small-square-with-cie-rgb-profile.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/small-square-with-colormatch-profile.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/small-square-with-colorspin-profile.jpg
dom/canvas/test/webgl-conf/checkout/conformance/resources/small-square-with-colorspin-profile.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/small-square-with-e-srgb-profile.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/small-square-with-smpte-c-profile.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/small-square-with-srgb-iec61966-2.1-profile.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/tex-image-and-sub-image-2d-with-image.js
dom/canvas/test/webgl-conf/checkout/conformance/resources/tex-image-and-sub-image-2d-with-svg-image.js
dom/canvas/test/webgl-conf/checkout/conformance/resources/tex-image-and-sub-image-2d-with-video.js
dom/canvas/test/webgl-conf/checkout/conformance/resources/thunderbird-logo-64x64.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/transparent-on-left-indexed.png
dom/canvas/test/webgl-conf/checkout/conformance/resources/webgl-test-utils.js
dom/canvas/test/webgl-conf/checkout/conformance/resources/zero-alpha.png
dom/canvas/test/webgl-conf/checkout/conformance/textures/tex-image-canvas-corruption.html
dom/plugins/base/nsPluginNativeWindowQt.cpp
dom/plugins/ipc/PluginHelperQt.h
gfx/thebes/gfxQtNativeRenderer.cpp
gfx/thebes/gfxQtNativeRenderer.h
gfx/thebes/gfxQtPlatform.cpp
gfx/thebes/gfxQtPlatform.h
media/libyuv/include/libyuv/format_conversion.h
media/libyuv/source/compare_posix.cc
media/libyuv/source/format_conversion.cc
media/libyuv/source/row_posix.cc
media/libyuv/source/row_x86.asm
media/libyuv/source/scale_posix.cc
media/libyuv/source/x86inc.asm
media/libyuv/unit_test/version_test.cc
testing/mozharness/scripts/b2g_desktop_multilocale.py
testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/align_middle_position_gt_50.html.ini
testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/bidi/u06E9_no_strong_dir.html.ini
testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/evil/single_quote.html.ini
toolkit/components/remote/nsQtRemoteService.cpp
toolkit/components/remote/nsQtRemoteService.h
toolkit/xre/nsNativeAppSupportQt.cpp
toolkit/xre/nsNativeAppSupportQt.h
toolkit/xre/nsQAppInstance.cpp
toolkit/xre/nsQAppInstance.h
uriloader/exthandler/unix/nsMIMEInfoQt.cpp
uriloader/exthandler/unix/nsMIMEInfoQt.h
--- a/.taskcluster.yml
+++ b/.taskcluster.yml
@@ -49,17 +49,16 @@ tasks:
 
       tags:
         createdForUser: {{owner}}
 
       scopes:
         # Bug 1269443: cache scopes, etc. must be listed explicitly
         - "docker-worker:cache:level-{{level}}-*"
         - "docker-worker:cache:tooltool-cache"
-        - "secrets:get:project/taskcluster/gecko/hgfingerprint"
         # mozilla-taskcluster will append the appropriate assume:repo:<repo>
         # scope here.
 
       routes:
         - "index.gecko.v2.{{project}}.latest.firefox.decision"
         - "tc-treeherder.v2.{{project}}.{{revision}}.{{pushlog_id}}"
         - "tc-treeherder-stage.v2.{{project}}.{{revision}}.{{pushlog_id}}"
 
--- a/accessible/base/TextAttrs.cpp
+++ b/accessible/base/TextAttrs.cpp
@@ -654,19 +654,17 @@ TextAttrsMgr::FontWeightTextAttr::
     return 700;
 
   bool useFontEntryWeight = true;
 
   // Under Linux, when gfxPangoFontGroup code is used,
   // font->GetStyle()->weight will give the absolute weight requested of the
   // font face. The gfxPangoFontGroup code uses the gfxFontEntry constructor
   // which doesn't initialize the weight field.
-#if defined(MOZ_WIDGET_QT)
-  useFontEntryWeight = false;
-#elif defined(MOZ_WIDGET_GTK)
+#if defined(MOZ_WIDGET_GTK)
   useFontEntryWeight = gfxPlatformGtk::UseFcFontList();
 #endif
 
   if (useFontEntryWeight) {
     // On Windows, font->GetStyle()->weight will give the same weight as
     // fontEntry->Weight(), the weight of the first font in the font group,
     // which may not be the weight of the font face used to render the
     // characters. On Mac, font->GetStyle()->weight will just give the same
--- a/accessible/generic/Accessible-inl.h
+++ b/accessible/generic/Accessible-inl.h
@@ -6,16 +6,20 @@
 
 #ifndef mozilla_a11y_Accessible_inl_h_
 #define mozilla_a11y_Accessible_inl_h_
 
 #include "DocAccessible.h"
 #include "ARIAMap.h"
 #include "nsCoreUtils.h"
 
+#ifdef A11Y_LOG
+#include "Logging.h"
+#endif
+
 namespace mozilla {
 namespace a11y {
 
 inline mozilla::a11y::role
 Accessible::Role()
 {
   if (!mRoleMapEntry || mRoleMapEntry->roleRule != kUseMapRole)
     return ARIATransformRole(NativeRole());
@@ -71,12 +75,36 @@ Accessible::HasNumericValue() const
 
 inline void
 Accessible::ScrollTo(uint32_t aHow) const
 {
   if (mContent)
     nsCoreUtils::ScrollTo(mDoc->PresShell(), mContent, aHow);
 }
 
+inline bool
+Accessible::InsertAfter(Accessible* aNewChild, Accessible* aRefChild)
+{
+  MOZ_ASSERT(aNewChild, "No new child to insert");
+
+  if (aRefChild && aRefChild->Parent() != this) {
+#ifdef A11Y_LOG
+    logging::TreeInfo("broken accessible tree", 0,
+                      "parent", this, "prev sibling parent",
+                      aRefChild->Parent(), "child", aNewChild, nullptr);
+    if (logging::IsEnabled(logging::eVerbose)) {
+      logging::Tree("TREE", "Document tree", mDoc);
+      logging::DOMTree("TREE", "DOM document tree", mDoc);
+    }
+#endif
+    MOZ_ASSERT_UNREACHABLE("Broken accessible tree");
+    mDoc->UnbindFromDocument(aNewChild);
+    return false;
+  }
+
+  return InsertChildAt(aRefChild ? aRefChild->IndexInParent() + 1 : 0,
+                       aNewChild);
+}
+
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -13,17 +13,16 @@
 #include "nsAccUtils.h"
 #include "nsAccessibilityService.h"
 #include "ApplicationAccessible.h"
 #include "NotificationController.h"
 #include "nsEventShell.h"
 #include "nsTextEquivUtils.h"
 #include "DocAccessibleChild.h"
 #include "EventTree.h"
-#include "Logging.h"
 #include "Relation.h"
 #include "Role.h"
 #include "RootAccessible.h"
 #include "States.h"
 #include "StyleInfo.h"
 #include "TableAccessible.h"
 #include "TableCellAccessible.h"
 #include "TreeWalker.h"
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -388,22 +388,22 @@ public:
 
   /**
    * Append/insert/remove a child. Return true if operation was successful.
    */
   bool AppendChild(Accessible* aChild)
     { return InsertChildAt(mChildren.Length(), aChild); }
   virtual bool InsertChildAt(uint32_t aIndex, Accessible* aChild);
 
-  bool InsertAfter(Accessible* aNewChild, Accessible* aRefChild)
-  {
-    MOZ_ASSERT(aNewChild, "No new child to insert");
-    return InsertChildAt(aRefChild ? aRefChild->IndexInParent() + 1 : 0,
-                         aNewChild);
-  }
+  /**
+   * Inserts a child after given sibling. If the child cannot be inserted,
+   * then the child is unbound from the document, and false is returned. Make
+   * sure to null out any references on the child object as it may be destroyed.
+   */
+  bool InsertAfter(Accessible* aNewChild, Accessible* aRefChild);
 
   virtual bool RemoveChild(Accessible* aChild);
 
   /**
    * Reallocates the child withing its parent.
    */
   void MoveChild(uint32_t aNewIndex, Accessible* aChild);
 
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -1676,16 +1676,22 @@ public:
   Accessible* ChildBefore() const { return mChildBefore; }
   DocAccessible* Document() const { return mWalker.Document(); }
 
   /**
    * Iterates to a next accessible within the inserted content.
    */
   bool Next();
 
+  void Rejected()
+  {
+    mChild = nullptr;
+    mChildBefore = nullptr;
+  }
+
 private:
   Accessible* mChild;
   Accessible* mChildBefore;
   TreeWalker mWalker;
   nsIContent* mStopNode;
 
   const nsTArray<nsCOMPtr<nsIContent> >* mNodes;
   uint32_t mNodesIdx;
@@ -1810,16 +1816,17 @@ DocAccessible::ProcessContentInserted(Ac
 #endif
 
       mt.AfterInsertion(iter.Child());
       CreateSubtree(iter.Child());
       continue;
     }
 
     MOZ_ASSERT_UNREACHABLE("accessible was rejected");
+    iter.Rejected();
   } while (iter.Next());
 
   mt.Done();
 
 #ifdef A11Y_LOG
   logging::TreeInfo("children after insertion", logging::eVerbose,
                     aContainer);
 #endif
@@ -1847,17 +1854,19 @@ DocAccessible::ProcessContentInserted(Ac
   if (aContainer->IsAcceptableChild(aNode) && walker.Seek(aNode)) {
     Accessible* child = GetAccessible(aNode);
     if (!child) {
       child = GetAccService()->CreateAccessible(aNode, aContainer);
     }
 
     if (child) {
       TreeMutation mt(aContainer);
-      aContainer->InsertAfter(child, walker.Prev());
+      if (!aContainer->InsertAfter(child, walker.Prev())) {
+        return;
+      }
       mt.AfterInsertion(child);
       mt.Done();
 
       CreateSubtree(child);
       FireEventsOnInsertion(aContainer);
     }
   }
 
--- a/accessible/xpcom/xpcAccessibleGeneric.h
+++ b/accessible/xpcom/xpcAccessibleGeneric.h
@@ -93,18 +93,18 @@ xpcAccessibleHyperLink::Intl()
 }
 
 inline Accessible*
 xpcAccessibleSelectable::Intl()
 {
   return static_cast<xpcAccessibleGeneric*>(this)->mIntl.AsAccessible();
 }
 
-inline Accessible*
+inline AccessibleOrProxy
 xpcAccessibleValue::Intl()
 {
-  return static_cast<xpcAccessibleGeneric*>(this)->mIntl.AsAccessible();
+  return static_cast<xpcAccessibleGeneric*>(this)->mIntl;
 }
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/xpcom/xpcAccessibleValue.cpp
+++ b/accessible/xpcom/xpcAccessibleValue.cpp
@@ -11,75 +11,119 @@ using namespace mozilla;
 using namespace mozilla::a11y;
 
 NS_IMETHODIMP
 xpcAccessibleValue::GetMaximumValue(double* aValue)
 {
   NS_ENSURE_ARG_POINTER(aValue);
   *aValue = 0;
 
-  if (Intl()->IsDefunct())
+  if (Intl().IsNull())
+    return NS_ERROR_FAILURE;
+
+  if (Intl().IsAccessible() && Intl().AsAccessible()->IsDefunct())
     return NS_ERROR_FAILURE;
 
-  double value = Intl()->MaxValue();
+  double value;
+  if (Intl().IsAccessible()) {
+    value = Intl().AsAccessible()->MaxValue();
+  } else { 
+    value = Intl().AsProxy()->MaxValue();
+  }
+
   if (!IsNaN(value))
     *aValue = value;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessibleValue::GetMinimumValue(double* aValue)
 {
   NS_ENSURE_ARG_POINTER(aValue);
   *aValue = 0;
 
-  if (Intl()->IsDefunct())
+  if (Intl().IsNull())
+    return NS_ERROR_FAILURE;
+
+  if (Intl().IsAccessible() && Intl().AsAccessible()->IsDefunct())
     return NS_ERROR_FAILURE;
 
-  double value = Intl()->MinValue();
+  double value;
+  if (Intl().IsAccessible()) {
+    value = Intl().AsAccessible()->MinValue();
+  } else { 
+    value = Intl().AsProxy()->MinValue();
+  }
+
   if (!IsNaN(value))
     *aValue = value;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessibleValue::GetCurrentValue(double* aValue)
 {
   NS_ENSURE_ARG_POINTER(aValue);
   *aValue = 0;
 
-  if (Intl()->IsDefunct())
+  if (Intl().IsNull())
+    return NS_ERROR_FAILURE;
+
+  if (Intl().IsAccessible() && Intl().AsAccessible()->IsDefunct())
     return NS_ERROR_FAILURE;
 
-  double value = Intl()->CurValue();
+  double value;
+  if (Intl().IsAccessible()) {
+    value = Intl().AsAccessible()->CurValue();
+  } else { 
+    value = Intl().AsProxy()->MinValue();
+  }
+
   if (!IsNaN(value))
     *aValue = value;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessibleValue::SetCurrentValue(double aValue)
 {
-  if (Intl()->IsDefunct())
+  if (Intl().IsNull())
+    return NS_ERROR_FAILURE;
+
+  if (Intl().IsAccessible() && Intl().AsAccessible()->IsDefunct())
     return NS_ERROR_FAILURE;
 
-  Intl()->SetCurValue(aValue);
+  if (Intl().IsAccessible()) {
+    Intl().AsAccessible()->SetCurValue(aValue);
+  } else { 
+    Intl().AsProxy()->SetCurValue(aValue);
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessibleValue::GetMinimumIncrement(double* aValue)
 {
   NS_ENSURE_ARG_POINTER(aValue);
   *aValue = 0;
 
-  if (Intl()->IsDefunct())
+  if (Intl().IsNull())
+    return NS_ERROR_FAILURE;
+
+  if (Intl().IsAccessible() && Intl().AsAccessible()->IsDefunct())
     return NS_ERROR_FAILURE;
 
-  double value = Intl()->Step();
+  double value = Intl().AsAccessible()->Step();
+  if (Intl().IsAccessible()) {
+    value = Intl().AsAccessible()->Step();
+  } else { 
+    value = Intl().AsProxy()->Step();
+  }
+
   if (!IsNaN(value))
     *aValue = value;
 
   return NS_OK;
 }
--- a/accessible/xpcom/xpcAccessibleValue.h
+++ b/accessible/xpcom/xpcAccessibleValue.h
@@ -27,18 +27,17 @@ public:
   NS_IMETHOD SetCurrentValue(double aValue) final override;
   NS_IMETHOD GetMinimumIncrement(double* aMinIncrement) final override;
 
 protected:
   xpcAccessibleValue() { }
   virtual ~xpcAccessibleValue() {}
 
 private:
-  Accessible* Intl();
+  AccessibleOrProxy Intl();
 
   xpcAccessibleValue(const xpcAccessibleValue&) = delete;
   xpcAccessibleValue& operator =(const xpcAccessibleValue&) = delete;
 };
 
 } // namespace a11y
 } // namespace mozilla
-
 #endif
--- a/b2g/locales/Makefile.in
+++ b/b2g/locales/Makefile.in
@@ -131,17 +131,17 @@ ident:
 	@printf 'b2g_revision '
 	@$(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(B2G_APPLICATION_INI_PATH) App SourceStamp
 	@printf 'buildid '
 	@$(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(B2G_APPLICATION_INI_PATH) App BuildID
 
 merge-%:
 ifdef LOCALE_MERGEDIR
 	$(RM) -rf $(LOCALE_MERGEDIR)
-	MACOSX_DEPLOYMENT_TARGET= compare-locales -m $(LOCALE_MERGEDIR) $(srcdir)/l10n.ini $(L10NBASEDIR) $*
+	$(topsrcdir)/mach compare-locales --merge-dir $(LOCALE_MERGEDIR) $*
 endif
 	@echo
 
 # test target, depends on make package
 # try to repack x-test, with just toolkit/defines.inc being there
 l10n-check::
 	$(RM) -rf x-test
 	$(NSINSTALL) -D x-test/toolkit
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -70,17 +70,17 @@
                           accesskey="&savePageCmd.accesskey;"
                           key="key_savePage"
                           command="Browser:SavePage"/>
                 <menuitem id="menu_sendLink"
                           label="&emailPageCmd.label;"
                           accesskey="&emailPageCmd.accesskey;"
                           command="Browser:SendLink"/>
                 <menuseparator/>
-#if !defined(MOZ_WIDGET_GTK) && !defined(MOZ_WIDGET_QT)
+#if !defined(MOZ_WIDGET_GTK)
                 <menuitem id="menu_printSetup"
                           label="&printSetupCmd.label;"
                           accesskey="&printSetupCmd.accesskey;"
                           command="cmd_pageSetup"/>
 #endif
 #ifndef XP_MACOSX
                 <menuitem id="menu_printPreview"
                           label="&printPreviewCmd.label;"
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -268,17 +268,17 @@ toolbar[customizing] > .overflow-button 
 }
 %else
 /* On non-OSX, these should be start-aligned */
 #titlebar-buttonbox-container {
   -moz-box-align: start;
 }
 %endif
 
-%if !defined(MOZ_WIDGET_GTK) && !defined(MOZ_WIDGET_QT)
+%if !defined(MOZ_WIDGET_GTK)
 #TabsToolbar > .private-browsing-indicator {
   -moz-box-ordinal-group: 1000;
 }
 %endif
 
 %ifdef XP_WIN
 #main-window[sizemode="maximized"] #titlebar-buttonbox {
   -moz-appearance: -moz-window-button-box-maximized;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -220,26 +220,24 @@
            type="arrow"
            hidden="true"
            noautofocus="true"
            noautohide="true"
            align="start"
            orient="vertical"
            role="alert">
      <vbox>
-      <hbox pack="end">
-        <toolbarbutton id="UITourTooltipClose" class="close-icon"
-                       tooltiptext="&uiTour.infoPanel.close;"/>
-      </hbox>
       <hbox id="UITourTooltipBody">
-        <vbox id="UITourTooltipIconContainer">
-          <image id="UITourTooltipIcon"/>
-        </vbox>
+        <image id="UITourTooltipIcon"/>
         <vbox flex="1">
-          <label id="UITourTooltipTitle" flex="1"/>
+          <hbox id="UITourTooltipTitleContainer">
+            <label id="UITourTooltipTitle" flex="1"/>
+            <toolbarbutton id="UITourTooltipClose" class="close-icon"
+                           tooltiptext="&uiTour.infoPanel.close;"/>
+          </hbox>
           <description id="UITourTooltipDescription" flex="1"/>
         </vbox>
       </hbox>
       <hbox id="UITourTooltipButtons" flex="1" align="center"/>
      </vbox>
     </panel>
     <!-- type="default" forces frames to be created so that the panel's size can be determined -->
     <panel id="UITourHighlightContainer"
@@ -558,17 +556,17 @@
 
   <toolbox id="navigator-toolbox" mode="icons">
     <!-- Menu -->
     <toolbar type="menubar" id="toolbar-menubar" class="chromeclass-menubar" customizable="true"
              mode="icons" iconsize="small"
 #ifdef MENUBAR_CAN_AUTOHIDE
              toolbarname="&menubarCmd.label;"
              accesskey="&menubarCmd.accesskey;"
-#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
+#if defined(MOZ_WIDGET_GTK)
              autohide="true"
 #endif
 #endif
              context="toolbar-context-menu">
       <toolbaritem id="menubar-items" align="center">
 # The entire main menubar is placed into browser-menubar.inc, so that it can be shared by
 # hiddenWindow.xul.
 #include browser-menubar.inc
@@ -587,17 +585,17 @@
              fullscreentoolbar="true"
              customizable="true"
              mode="icons"
              iconsize="small"
              aria-label="&tabsToolbar.label;"
              context="toolbar-context-menu"
              collapsed="true">
 
-#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
+#if defined(MOZ_WIDGET_GTK)
       <hbox id="private-browsing-indicator"
             skipintoolbarset="true"/>
 #endif
 
       <tabs id="tabbrowser-tabs"
             class="tabbrowser-tabs"
             tabbrowser="content"
             flex="1"
@@ -637,17 +635,17 @@
           <menu id="alltabs_containersTab"
                 label="&newUserContext.label;">
             <menupopup id="alltabs_containersMenuTab" />
           </menu>
           <menuseparator id="alltabs-popup-separator-2"/>
         </menupopup>
       </toolbarbutton>
 
-#if !defined(MOZ_WIDGET_GTK) && !defined(MOZ_WIDGET_QT)
+#if !defined(MOZ_WIDGET_GTK)
       <hbox class="private-browsing-indicator" skipintoolbarset="true"/>
 #endif
 #ifdef CAN_DRAW_IN_TITLEBAR
       <hbox class="titlebar-placeholder" type="caption-buttons"
             id="titlebar-placeholder-on-TabsToolbar-for-captions-buttons" persist="width"
 #ifndef XP_MACOSX
             ordinal="1000"
 #endif
--- a/browser/base/content/tab-content.js
+++ b/browser/base/content/tab-content.js
@@ -366,17 +366,26 @@ var AboutReaderListener = {
       // We need to stop this check before we re-add one because we don't know
       // if forceNonArticle was true or false last time.
       this.cancelPotentialPendingReadabilityCheck();
     }
     this._pendingReadabilityCheck = this.onPaintWhenWaitedFor.bind(this, forceNonArticle);
     addEventListener("MozAfterPaint", this._pendingReadabilityCheck);
   },
 
-  onPaintWhenWaitedFor: function(forceNonArticle) {
+  onPaintWhenWaitedFor: function(forceNonArticle, event) {
+    // In non-e10s, we'll get called for paints other than ours, and so it's
+    // possible that this page hasn't been laid out yet, in which case we
+    // should wait until we get an event that does relate to our layout. We
+    // determine whether any of our content got painted by checking if there
+    // are any painted rects.
+    if (!event.clientRects.length) {
+      return;
+    }
+
     this.cancelPotentialPendingReadabilityCheck();
     // Only send updates when there are articles; there's no point updating with
     // |false| all the time.
     if (ReaderMode.isProbablyReaderable(content.document)) {
       sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: true });
     } else if (forceNonArticle) {
       sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: false });
     }
--- a/browser/components/preferences/connection.xul
+++ b/browser/components/preferences/connection.xul
@@ -138,17 +138,16 @@
             <row>
               <spacer/>
               <box pack="start">
               <radiogroup id="networkProxySOCKSVersion" orient="horizontal"
                           preference="network.proxy.socks_version">
                 <radio id="networkProxySOCKSVersion4" value="4" label="&socks4.label;" accesskey="&socks4.accesskey;" />
                 <radio id="networkProxySOCKSVersion5" value="5" label="&socks5.label;" accesskey="&socks5.accesskey;" />
               </radiogroup>
-              <checkbox id="networkProxySOCKSRemoteDNS"  preference="network.proxy.socks_remote_dns" label="&socksRemoteDNS.label;" accesskey="&socksRemoteDNS.accesskey;" />
               </box>
             </row>
             <label value="&noproxy.label;" accesskey="&noproxy.accesskey;" control="networkProxyNone"/>
             <textbox id="networkProxyNone" preference="network.proxy.no_proxies_on" multiline="true" rows="2"/>
             <label value="&noproxyExplain.label;" control="networkProxyNone"/>
           </rows>
         </grid>
         <radio value="2" label="&autoTypeRadio.label;" accesskey="&autoTypeRadio.accesskey;"/>
@@ -163,12 +162,13 @@
       </radiogroup>
     </groupbox>
     <separator class="thin"/>
     <checkbox id="autologinProxy"
               label="&autologinproxy.label;"
               accesskey="&autologinproxy.accesskey;"
               preference="signon.autologin.proxy"
               tooltiptext="&autologinproxy.tooltip;"/>
+    <checkbox id="networkProxySOCKSRemoteDNS"  preference="network.proxy.socks_remote_dns" label="&socksRemoteDNS.label2;" accesskey="&socksRemoteDNS.accesskey;" />
     <separator/>
   </prefpane>
 </prefwindow>
 
--- a/browser/components/uitour/UITour.jsm
+++ b/browser/components/uitour/UITour.jsm
@@ -1552,27 +1552,26 @@ this.UITour = {
     function showInfoPanel(aAnchorEl) {
       aAnchorEl.focus();
 
       let document = aChromeWindow.document;
       let tooltip = document.getElementById("UITourTooltip");
       let tooltipTitle = document.getElementById("UITourTooltipTitle");
       let tooltipDesc = document.getElementById("UITourTooltipDescription");
       let tooltipIcon = document.getElementById("UITourTooltipIcon");
-      let tooltipIconContainer = document.getElementById("UITourTooltipIconContainer");
       let tooltipButtons = document.getElementById("UITourTooltipButtons");
 
       if (tooltip.state == "showing" || tooltip.state == "open") {
         tooltip.hidePopup();
       }
 
       tooltipTitle.textContent = aTitle || "";
       tooltipDesc.textContent = aDescription || "";
       tooltipIcon.src = aIconURL || "";
-      tooltipIconContainer.hidden = !aIconURL;
+      tooltipIcon.hidden = !aIconURL;
 
       while (tooltipButtons.firstChild)
         tooltipButtons.firstChild.remove();
 
       for (let button of aButtons) {
         let isButton = button.style != "text";
         let el = document.createElement(isButton ? "button" : "label");
         el.setAttribute(isButton ? "label" : "value", button.label);
--- a/browser/config/tooltool-manifests/linux32/releng.manifest
+++ b/browser/config/tooltool-manifests/linux32/releng.manifest
@@ -11,19 +11,19 @@
 "size": 11189216,
 "digest": "18bc52b0599b1308b667e282abb45f47597bfc98a5140cfcab8da71dacf89dd76d0dee22a04ce26fe7ad1f04e2d6596991f9e5b01fd2aaaab5542965f596b0e6",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
 "setup": "setup.sh",
 "unpack": true
 },
 {
-"version": "gecko rust 1.9.0 (commit e4e8b666850a763fdf1c3c2c142856ab51e32779)",
-"size": 96854912,
-"digest": "d613d5528e83bb73917372948c05a766912a9dd0ec4e8a5fab69161a515c1545d52e9ed3394716df96a9dcdf1c086b6f970413e97c2df78a11e5f9151573921a",
+"version": "gecko rustc 1.10.0 (cfcb716cf 2016-07-03)",
+"size": 102276708,
+"digest": "8cc9ea8347fc7e6e6fdb15a8fd1faae977f1235a426b879b3f9128ec91d8f2b6268297ce80bf4eceb47738bd40bfeda13f143dc3fe85f1434b13adfbc095ab90",
 "algorithm": "sha512",
 "filename": "rustc.tar.xz",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
--- a/browser/config/tooltool-manifests/linux64/releng.manifest
+++ b/browser/config/tooltool-manifests/linux64/releng.manifest
@@ -11,19 +11,19 @@
 "size": 12072532,
 "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
 "setup": "setup.sh",
 "unpack": true
 },
 {
-"version": "gecko rust 1.9.0 (commit e4e8b666850a763fdf1c3c2c142856ab51e32779)",
-"size": 96854912,
-"digest": "d613d5528e83bb73917372948c05a766912a9dd0ec4e8a5fab69161a515c1545d52e9ed3394716df96a9dcdf1c086b6f970413e97c2df78a11e5f9151573921a",
+"version": "gecko rustc 1.10.0 (cfcb716cf 2016-07-03)",
+"size": 102276708,
+"digest": "8cc9ea8347fc7e6e6fdb15a8fd1faae977f1235a426b879b3f9128ec91d8f2b6268297ce80bf4eceb47738bd40bfeda13f143dc3fe85f1434b13adfbc095ab90",
 "algorithm": "sha512",
 "filename": "rustc.tar.xz",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -183,17 +183,17 @@ ident:
 	    $(STAGEDIST)/application.ini App SourceStamp
 	@printf 'buildid '
 	@$(PYTHON) $(topsrcdir)/config/printconfigsetting.py \
 	    $(STAGEDIST)/application.ini App BuildID
 
 merge-%:
 ifdef LOCALE_MERGEDIR
 	$(RM) -rf $(LOCALE_MERGEDIR)
-	MACOSX_DEPLOYMENT_TARGET= compare-locales -m $(LOCALE_MERGEDIR) $(srcdir)/l10n.ini $(L10NBASEDIR) $*
+	$(topsrcdir)/mach compare-locales --merge-dir $(LOCALE_MERGEDIR) $*
 endif
 	@echo
 
 # test target, depends on make package
 # try to repack x-test, with just toolkit/defines.inc being there
 l10n-check:: INNER_UNMAKE_PACKAGE=true
 l10n-check::
 	$(RM) -rf x-test
--- a/browser/locales/en-US/chrome/browser/preferences/connection.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/connection.dtd
@@ -27,17 +27,17 @@
 <!ENTITY  ssl.label                     "SSL Proxy:">
 <!ENTITY  ssl.accesskey                 "L">
 <!ENTITY  socks.label                   "SOCKS Host:">
 <!ENTITY  socks.accesskey               "C">
 <!ENTITY  socks4.label                  "SOCKS v4">
 <!ENTITY  socks4.accesskey              "K">
 <!ENTITY  socks5.label                  "SOCKS v5">
 <!ENTITY  socks5.accesskey              "v">
-<!ENTITY  socksRemoteDNS.label          "Remote DNS">
+<!ENTITY  socksRemoteDNS.label2         "Proxy DNS when using SOCKS v5">
 <!ENTITY  socksRemoteDNS.accesskey      "d">
 <!ENTITY  port.label                    "Port:">
 <!ENTITY  HTTPport.accesskey            "P">
 <!ENTITY  SSLport.accesskey             "o">
 <!ENTITY  FTPport.accesskey             "r">
 <!ENTITY  SOCKSport.accesskey           "t">
 <!ENTITY  noproxy.label                 "No Proxy for:">
 <!ENTITY  noproxy.accesskey             "n">
deleted file mode 100644
--- a/browser/locales/generic/extract-bookmarks.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-import sys
-import re
-import codecs
-try:
-  from Mozilla.Parser import getParser
-except ImportError:
-  sys.exit('''extract-bookmarks needs compare-locales
-
-Find that on http://pypi.python.org/pypi/compare-locales.
-This script has been tested with version 0.6, and might work with future 
-versions.''')
-
-ll=re.compile('\.(title|a|dd|h[0-9])$')
-
-p = getParser(sys.argv[1])
-p.readFile(sys.argv[1])
-
-template = '''#filter emptyLines
-
-# LOCALIZATION NOTE: The 'en-US' strings in the URLs will be replaced with
-# your locale code, and link to your translated pages as soon as they're 
-# live.
-
-#define bookmarks_title %s
-#define bookmarks_heading %s
-
-#define bookmarks_toolbarfolder %s
-#define bookmarks_toolbarfolder_description %s
-
-# LOCALIZATION NOTE (getting_started):
-# link title for https://www.mozilla.org/en-US/firefox/central/
-#define getting_started %s
-
-# LOCALIZATION NOTE (firefox_heading):
-# Firefox links folder name
-#define firefox_heading %s
-
-# LOCALIZATION NOTE (firefox_help):
-# link title for https://www.mozilla.org/en-US/firefox/help/
-#define firefox_help %s
-
-# LOCALIZATION NOTE (firefox_customize):
-# link title for https://www.mozilla.org/en-US/firefox/customize/
-#define firefox_customize %s
-
-# LOCALIZATION NOTE (firefox_community):
-# link title for https://www.mozilla.org/en-US/contribute/
-#define firefox_community %s
-
-# LOCALIZATION NOTE (firefox_about):
-# link title for https://www.mozilla.org/en-US/about/
-#define firefox_about %s
-
-#unfilter emptyLines'''
-
-strings = tuple(e.val for e in p if ll.search(e.key))
-
-print codecs.utf_8_encode(template % strings)[0]
--- a/browser/themes/moz.build
+++ b/browser/themes/moz.build
@@ -3,14 +3,14 @@
 # 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/.
 
 toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
 
 if toolkit == 'cocoa':
     DIRS += ['osx']
-elif toolkit in ('gtk2', 'gtk3', 'qt'):
+elif toolkit in ('gtk2', 'gtk3'):
     DIRS += ['linux']
 else:
     DIRS += ['windows']
 
 FINAL_TARGET_FILES.extensions['{972ce4c6-7e08-4474-a285-3208198ce6fd}'] += ['shared/icon.png']
--- a/browser/themes/shared/UITour.inc.css
+++ b/browser/themes/shared/UITour.inc.css
@@ -21,42 +21,39 @@
   /* The box-shadow opacity needs to be < 0.5 so it doesn't appear at 100% opacity
      on Linux without an X compositor where opacity is either 0 or 1. */
   box-shadow: 0 0 3px 0 rgba(0,0,0,0.49);
   min-height: 32px;
   min-width: 32px;
 }
 
 #UITourTooltipBody {
-  margin-inline-end: 14px;
-  margin-inline-start: 14px;
-  margin-top: -16px;
-  margin-bottom: 8px;
+  -moz-box-align: start;
+}
+
+#UITourTooltipTitleContainer {
+  -moz-box-align: start;
+  margin-bottom: 10px;
 }
 
 #UITourTooltipIcon {
   width: 48px;
   height: 48px;
-  margin-inline-start: 14px;
-  margin-inline-end: 14px;
+  margin-inline-end: 10px;
 }
 
 #UITourTooltipTitle,
 #UITourTooltipDescription {
   max-width: 20rem;
 }
 
 #UITourTooltipTitle {
   font-size: 1.45rem;
   font-weight: bold;
-  margin-inline-start: 0;
-  /* Avoid the title overlapping the close button */
-  margin-inline-end: 14px;
-  margin-top: 0;
-  margin-bottom: 9px;
+  margin: 0;
 }
 
 #UITourTooltipDescription {
   margin-inline-start: 0;
   margin-inline-end: 0;
   font-size: 1.15rem;
   line-height: 1.8rem;
   margin-bottom: 0; /* Override global.css */
@@ -76,29 +73,34 @@
   display: none;
 }
 
 #UITourTooltipButtons {
   -moz-box-pack: end;
   background-color: hsla(210,4%,10%,.07);
   border-top: 1px solid hsla(210,4%,10%,.14);
   margin: 10px -16px -16px;
-  padding: 2em 15px;
+  padding: 16px;
 }
 
 #UITourTooltipButtons > label,
 #UITourTooltipButtons > button {
   margin: 0 15px;
 }
 
 #UITourTooltipButtons > label:first-child,
 #UITourTooltipButtons > button:first-child {
   margin-inline-start: 0;
 }
 
+#UITourTooltipButtons > label:last-child,
+#UITourTooltipButtons > button:last-child {
+  margin-inline-end: 0;
+}
+
 #UITourTooltipButtons > button[image] > .button-box > .button-icon {
   width: 16px;
   height: 16px;
   margin-inline-end: 5px;
 }
 
 #UITourTooltipButtons > label,
 #UITourTooltipButtons > button .button-text {
--- a/browser/themes/shared/notification-icons.inc.css
+++ b/browser/themes/shared/notification-icons.inc.css
@@ -86,37 +86,37 @@
 
 .desktop-notification-icon.blocked {
   list-style-image: url(chrome://browser/skin/permissions.svg#desktop-notification-blocked);
 }
 
 .geo-icon {
 %ifdef XP_MACOSX
   list-style-image: url(chrome://browser/skin/permissions.svg#geo-osx);
-%elif defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
+%elif defined(MOZ_WIDGET_GTK)
   list-style-image: url(chrome://browser/skin/permissions.svg#geo-linux);
 %else
   list-style-image: url(chrome://browser/skin/permissions.svg#geo-windows);
 %endif
 }
 
 .geo-icon.blocked {
 %ifdef XP_MACOSX
   list-style-image: url(chrome://browser/skin/permissions.svg#geo-osx-blocked);
-%elif defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
+%elif defined(MOZ_WIDGET_GTK)
   list-style-image: url(chrome://browser/skin/permissions.svg#geo-linux-blocked);
 %else
   list-style-image: url(chrome://browser/skin/permissions.svg#geo-windows-blocked);
 %endif
 }
 
 .popup-notification-icon[popupid="geolocation"] {
 %ifdef XP_MACOSX
   list-style-image: url(chrome://browser/skin/permissions.svg#geo-osx);
-%elif defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
+%elif defined(MOZ_WIDGET_GTK)
   list-style-image: url(chrome://browser/skin/permissions.svg#geo-linux-detailed);
 %else
   list-style-image: url(chrome://browser/skin/permissions.svg#geo-windows-detailed);
 %endif
 }
 
 .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
 .indexedDB-icon {
--- a/browser/themes/shared/tab-selected.svg
+++ b/browser/themes/shared/tab-selected.svg
@@ -2,17 +2,17 @@
    - 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/. -->
 <svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" width="30px" height="31px" preserveAspectRatio="none">
   <defs>
     <style>
 %filter substitution
 %ifdef XP_MACOSX
 %include ../osx/shared.inc
-%elif defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
+%elif defined(MOZ_WIDGET_GTK)
 %include ../linux/linuxShared.inc
 %else
 %include ../windows/windowsShared.inc
 %endif
       #tab-background-fill {
         background-color: @fgTabBackgroundColor@;
         background-image: @fgTabTexture@;
         background-repeat: no-repeat;
--- a/build/mozconfig.cache
+++ b/build/mozconfig.cache
@@ -2,16 +2,18 @@
 # 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/.
 
 # Setup for build cache
 
 # Avoid duplication if the file happens to be included twice.
 if test -z "$bucket" -a -z "$NO_CACHE"; then
 
+# buildbot (or builders that use buildprops.json):
+if [ -f $topsrcdir/../buildprops.json ]; then
 read branch platform master <<EOF
 $(python2.7 -c 'import json; p = json.loads(open("'"$topsrcdir"'/../buildprops.json").read())["properties"]; print p["branch"], p["platform"], p["master"]' 2> /dev/null)
 EOF
 
 bucket=
 if test -z "$SCCACHE_DISABLE" -a -z "$no_sccache" -a -z "$MOZ_PGO_IS_SET" -a -z "$MOZ_PGO"; then
     case "${branch}" in
     try)
@@ -35,30 +37,77 @@ if test -z "$SCCACHE_DISABLE" -a -z "$no
         *usw2.mozilla.com*)
             bucket=mozilla-releng-s3-cache-us-west-2-prod
             ;;
         esac
         ;;
     esac
 fi
 
+# builds without buildprops (eg: taskcluster or non-buildbot) and without ccache env config and without sccache disabled:
+elif test -z "$CCACHE_DIR" -a -z "$SCCACHE_DISABLE" -a -z "$no_sccache" -a -z "$MOZ_PGO_IS_SET" -a -z "$MOZ_PGO"; then
+
+    # prevent rerun if az is set, or wget is not available
+    if test -z "$availability_zone" -a -x "$(command -v wget)"; then
+        # timeout after 1 second, and don't retry (failure indicates instance is not in ec2 or network issue)
+        # availability_zone is of the form <region><letter> where region is e.g. us-west-2, and az is us-west-2a
+        availability_zone=$(wget -T 1 -t 1 -q -O - http://169.254.169.254/latest/meta-data/placement/availability-zone || true)
+        if test -z "$availability_zone" -o "$availability_zone" = "not-ec2"; then
+            availability_zone=not-ec2
+        else
+            # region is az with last letter trimmed
+            region=${availability_zone%?}
+            # set S3 bucket according to tree (level)
+            case "${GECKO_HEAD_REPOSITORY}" in
+            *hg.mozilla.org/try*)
+                bucket=taskcluster-level-1-sccache-${region}
+                ;;
+            *hg.mozilla.org/integration/mozilla-inbound*|*hg.mozilla.org/integration/fx-team*)
+                bucket=taskcluster-level-3-sccache-${region}
+                ;;
+            esac
+
+            # set a dummy master
+            case "${region}" in
+            us-east-1)
+                master=dummy.use1.mozilla.com
+                ;;
+            us-west-1)
+                master=dummy.usw1.mozilla.com
+                ;;
+            us-west-2)
+                master=dummy.usw2.mozilla.com
+                ;;
+            esac
+        fi
+    fi
+
+
+    # set platform based on the SYSTEMROOT env var
+    case "${SYSTEMROOT}" in
+    *Windows)
+        platform=windows
+        ;;
+    esac
+fi
+
 if test -z "$bucket"; then
     case "$platform" in
     win*) : ;;
     *)
         ac_add_options --with-ccache
     esac
 else
     if ! test -e $topsrcdir/sccache/sccache.py; then
         echo "Sccache missing in the tooltool manifest" >&2
         exit 1
     fi
     mk_add_options "export SCCACHE_BUCKET=$bucket"
     case "$master" in
-    *use1.mozilla.com*|*usw2.mozilla.com*)
+    *us[ew][12].mozilla.com*)
         mk_add_options "export SCCACHE_NAMESERVER=169.254.169.253"
         ;;
     esac
     ac_add_options "--with-compiler-wrapper=python2.7 $topsrcdir/sccache/sccache.py"
     mk_add_options MOZ_PREFLIGHT_ALL+=build/sccache.mk
     mk_add_options MOZ_POSTFLIGHT_ALL+=build/sccache.mk
     mk_add_options "UPLOAD_EXTRA_FILES+=sccache.log.gz"
     case "$platform" in
index e921ffa3f802e04d22560dbacb5fd3d7940441a6..b22fc3da7566196e9676deb799e0d4d957885c8f
GIT binary patch
literal 12718
zc$}qr1#}%rvgH#qGqc5v7RzFm#mrC443;crMvIx5nJkN$nJuuG8P+|sGY!9cr{{0H
zQ|DB@s=OHy8I>6~Dix%`z|jE!05qUBepNz73RV&l0RYfI1^|BfS5{P6h+a}ojM3WG
z!`#ZsfWg7hU@h64YxV_qV9YR}CLqH4*cj&_n$NQ_pKd7*c4o1k<JK#K92glRl4Oh{
zEs;b=;Yl^T$f7}GOijWQ%snyVn0d9`&b`o5d3E~svN2-Y;(fQ@Y2(vv2APK$J{_r9
z1oqLl4km&d;QJ8_9yG@s!~(m3iw}HMND^f7)dduYws`{Zy`&KIL9QdwN5+N+OIgEE
zMglu{y#}2k1Q)G;kpX4)|N5oJ<eeFV&yK<*6YJ3qm^}jnwytb@5zji>PGoOe4h2Z4
zFfD!EInlh*V^F(TrkfVgaSm7&%y<vN{$97G;r@^C-sPMrpYH~M0F7@i@{}-DdUB}h
zqc9N_^y_0s0Y_C<l;@d<W;lX}6ZDGy>VfUv1($K%ZJwcTmv0zVuj1&KXRvl;2a^sy
z=?S2kx~fu;)gqIUIY{}>0u;zWCLmwDPcr5QXT~A+!yJ3vAfJ!6G(eJsh5BTQqVMdl
z`ZrhI#_V0Z&4T>3p4_Rcl>`>v$PS@d)vwSskvHGm#W3Y4)9E!qcf#WPx!OD>_4@RW
z@n<uR+t--YO??1+Z%1qXRMf=aOkjOIpK+N$;BybOG)+Mez_H=4_0H4_)+6OO3HC|^
zQ}h;D<Ae*+mQFv>qt+hBM>l1ta3U7v)eg#A*MI^Hb@scN#l4_CL#Tz&GtyBMHkdTB
z_+Gw}Qhxd*muB8!PyyOOu8GAzfr2y|#A1{wpS87PxhHissL}3Wf55D;L(c2lj*z;C
z2zN*+kC|-LPF=4%Wg*YjE_i*jlq{B{ml1aBwNl04Of<xJ(_gh<f5on7p0h&1)Ni=8
z*RU%tO&bzimFhRN6OujSO`+BJUGX@DQn5ux)Ux0Qf#!g`D>H3vM4t%hyYZR+IEf)M
zDOXiJ$r?3T5Zex2YM^jr1lq(*TH8cCdtUn!1Ue3l;(GxISP4IxQ`)R5YL;Mj=N`HB
z-M~@2ca5oI=6q?lPvru(0S-~&O-*)1YClT7Ez!PD$u?kA?@%S##@h$(Np7=d-X7#>
z;kC8C)KS+AW6dvWXx*OZv1F7)6rkTNt4s7FpbJEAx?B998c~-|8(>j!VA(U$7GpT3
zD?78Q#HD;7BnY!FpKNAb0C+`zIFAo{a3#EmnUA_Jav<1Rg>0^;D+i8hKVD9)2p_sI
z3nQedh|CeKGfgYlWUAR*4fH2@uCh<~hB&=Ne^9Y+Rxz6ZtK|?ITKuk>GO!srtl&s-
z3tP1omSA%vV%lS|Q2RwRn0)%Ko;U$g8x<bpqtB~qMoe$;7Di|Do5J>YZ$tyIDzvUF
zu7#*|;eLpjd!#|maP@_bd;J1GwUw8k<|zs^$0e;~v+}H#+c<uh9$phPJT81erx}N!
zin;(%2Gj|0VON|)$Y=WfE)IGso?Y_%iXSu%=drF@5sTgLL8HGiGIG(z3R!w+&L>xo
z&>)>kn`m?LcS^n{SPU$gBhwrINIGA2WeHX@*3K5o4oD(Y>9CK$WB;;_rR*JjSg8+|
zEYIJjgi3_quPUcT<w#>oQj+M@vnr)Zqa09Sb`vDiBinNKRb;g$Z64&E>;ebw8kRst
zk?kslH`hRS{wLg=;-hmanhtuYS7>E)jCY*EbY5?ym{I$A1*fzrOND;H0cOl_2NbY4
zF&Ccnc9ETIy+!uKosKIg8jY|1H=X`C$O@IQBfSL&xajhl&jf5LZ|ztjr;cMsVbLl>
z(G7``9V*PjvNVv4T{@TOYlp<s*$pZxxzS86AtPkbP5rYjDc01cB(@0OxH}QK(XeJw
zMob#Ylf_};H1{OlQ_yJ;R#%mYV>6h%FZGr&WY&&P6IoGBv?YbidS>B}sm>I;J#Vy4
z8*$w@Kn?ebpo|dnHu-wm0);e0+8WUt({R{g<jFSV-iU?s?&&Ms%v`5~rkCD>jl>v=
zpziJd@Xkf`D0RvJhe&Z|N@jXV_2tJ!hf1WpnihLV;_gNeP^U+%ev%0E&8|+=dyrn?
z*D~mRkeDvy@x#yoPa;9BZAPkr=Izh9YM3!%Bhr#Y)vAZc9l?rwS(k5xeb1DBP1h39
zyt{^}`6y=X15smH>@7W8&f-q*owo{v3s2?D<iRXWjdEXFWl$UrgxBIxDPIin{KdLb
z;9o8=FLY5q!+)aN3Kp9mMcm7D!2QA@rK?_55ck17Z5m6*fRd(DZP6ENF{sm&Fi2p6
zRcC9bbJ&g|`a2d@7C~`agq5j)Wm4$zpc#!rfAR$N)uU_w=dPs$I2t(7#EH~&M+ukS
z)L<@EbM|p=L1V)E_IRnda#KmT+G(KcQd%$Geiigpe>!rc7;^Mo)$5mcdV02ApZjf|
zTZ%n))_qP79uyKh_v7e9qnp24dlKjhg;<dIzb7BsIx_O@rpyjkj`eK|!tDHH`&B?x
zBI<U*rAX^~S#)+sEZDWBSF>5dN^EM>gf}+rhQ_wTw6>E?edKd|^BAg=h&G2pg2i0C
z26312=}@%U#8wa09jD8X2hQz$@k7kYwa|0bP#r~4vf@_LV3<~wuwo_k650r(s%jPc
zVWE^w2Kyx!?b)5;(7P`Yy9Wx9yB(gOM5p#cnuUT(YtPra+gSDDPScX)+`5rzCyz0(
zd|TgBkJUHc$2X!7k=O<`5%KgUP#W3bEX+o*Va_$W&^$8D_`p}Lt&gGI-PD?))8Oix
z?H}Smck)<|(W<7>xQ1Vw1>5a<*0~_&Ic*Maca9<}TV}W>yg@&5MBjc&ivq_6WsRR8
z^N|AukD&tyxFtxKP*DItd~ZP>h5PKzAp!{#nBn#LW<LbuB2IQkh4cz0Bq$>fPACdb
z3v1-it@q5+Jt#d$&ZtyYe?5|TPY*87hWydZ49iE%7z`z4i%tbWkFGs5-saUX@!J#V
zYM{EZrmUREx8CYEW>jcmWMYK8#?Wa9QEM}wYy|^VA#qz<S5e8K&sAcQbYiGSKODZU
zjo;YnKP|mV1*ZxJ4PZ{Oyyj%UAQYmNoK1wOM>Jig1PYh{C01R(+O%)kCt)#Vk_tJ^
zGU3o@!}-Ew&A}yiKZOuBNQ{+&lz@(7Flh9#z9LuDvOwfstb~z-HijA<x(U(qt2GRz
zP>Vr$u;1E5N_`t)EY_ydLVJtM(;{0N-u@8;GRIyp*?gJ#?d&5DLr<ik#HlQrKc=2s
zplbwjdsnqk5=yPU*|Pq_Hkf3Q;YMg!gS2y46N@DMz-k2fGrvjFZqMbnnxKH-6RW%c
zA4|3(9r&g^E~0n%6bG(5$*E8ItOMs8Vua9L?Mjm4jL2adOF^u|G#Lxtxt1NvxXW~}
zI7$2vTk;XZ?znS>N_r%oL?CNnHMMn=QK=#06A51p+MFU}?QzPYG>fMK7*o$JHw60{
z8nOrO4x`Fs>>S2q*u8hvN4q9n3ikKVmesBY0^(+NdD$v;KU`z0DRA{eNfOdu2Qw0_
zrN`XIX?=;yQgQCpI2eTWyTeg?M7k1xK>C<2WXl3#Q!59fL0?42ad8;7B@&$J;hH95
zZG$3@dee8fAI3*C{C&Q}QA{|OjY!Z$-o{E^ROy!bAqWUle_u?ff_Joxt>M-k0IQLf
z$h6}<?^57gP&Y<2aB9+e@wn_sG!FGi5WPhXLlppwC4ermPWm#T-T=v0;hvBFd0?|9
z1<DFr)<>J`i=hl+KLPRf*qb!#gCqVEUl&jhWYL?_FZ+#q97MZ|KEW)gYmD2c+m;sH
zt2+uG)y_*J;k@VGt=4ESd1Xo_S=9P<zBL=1DKN{$W_|5!YX!#q>{AQ(xBQ^>6JASg
z>YUwb**HSkDUrRd`4Mt(HILf?Rirq<H13Ayea8L1lnos4{UnkyGEwF}mQcx?>r<xJ
zfXyTSp*q)E4|$kS#IK&hOVIue2_gl|1rbk;+mKA^HNEY@29q<AFpdJI{15zd3e?Qa
zjO0T3u4GfzjZjv%NuuuKX8lF^+5PwNyK6cStTWVvtsjxv_&XMPX|YVxX<l(E$8~Q4
zYgDMw&pO^$cCz<t9Jh|sUy5`daPQs^WSXv2d8*Lq!N^m<S_WG6$$@iQquk|5UXH|;
z+11kZ7E<G{@QL9`S!fQ|HB8-4R%|ZG-JVMtAZRHi&bF~s*NLy^<HEY?kBn?8HNZJ~
zI5kFnh4`r0>f;KO7~*cM5SA)T;pXhkXrsKkS%VNdJG7Osxl^Bti5<{*+%vBe!Oi2S
zwp8quU}_qqv}ULZx77JAX_>%tdu^j-Vo%ecmQnx@Wztgu5STYOavP!D!_)Ikf5`O)
zifS#pLAHg<RfVgM24$HPZ=VM9WD%zBu^><>2;~_Lp%Pl{Ua`}$Iyw+o5;Bt#Q#-1q
z%v=N<vn7m;t8;>lS(I)W8-pLU#Ae=|wFMmw^XR&1tFbT$n@2|rEX%szn$Tpsg&4PT
zR9UxHNmVg)ag0Ft*S`6%Umd;+w$^)rQusG-;)R`)AOxS1vP1;{5Lo~KcmOuQ(AL(;
z(aFKUj={oFMHvDB#(Hn2=IjOs00F-R0RX^%HUva!daA8RB)w(Hf7}{1Un0;7N*{G<
zS~_;w4j^ca?*?5O#ZR?1E{VVxp^26PU4`H9`g}JpOku^nHR@FEvD$j3Hh17@&p*+?
zr6iju#r!b^J-Ad8HsXiLqiA76aboel;%u#^MUKhyh0seZmME!Qs(EY?&$j0UzdW#H
zS8(;)wrD$6cwUNxNU5r2*Z%j8X4!fw75ZB31r>g4i<Hon_Dmz8N|;ePM!-&1DT=uw
zEPF*f{#$|~dBc~58w*}s`mv>&(n@ik_g~HP)ISL<FX2Rfo6wZ%I<E}t?Yq504w+X`
zj9^3Kd(0JYl@fO?Q%<CSCd8l_G8P^A{64LC7j_`|#*;8&X3oNt(xM(+L{L*4>eKO5
zaQx29)dJDP!1hh#Fl(%_hOTaSzIJ%~=n*gVr9d3FT0t>d$D|<x?PSWtH{ARrR4YIl
zt7vt-rc^apTaiN{jbwGuB6KX12~M--A^zfI1dX@~SUYWvvWAibevxI0@q~+unFjr-
zs3y6lG#_TX69C1i+G1K$1^Wvi7&R_~f|_v<D!1gy&zr-az~GIhBrUhF$AUOXGDTZ@
zxg8y8JMkQU8tV3&cE->l<fCBS57BE!ssP3Lrc%ua2liQ$xgKvPoTs|wE=vt9t`14U
z<i~@9Men;cNx=x<{ayYjZ1tv!r%S{MWn!sHDJ;)g`08VE*NNcOoj_#yym%D#?SWDW
z5y%zS0sDOiZ^<Rgn3|*zo4kik>R4Q&7N{Q-DX4N6_2HeSn|WeYd8@S%v9~bLAl+nZ
z((Fh{W_6RSk?6(2WnN~&&+&PyOltg9#ElK1k3NS^FMb{KA)~%KYx7NYeWsC9MX}H^
z+N4&KAdwZQuzHg1rZ$9982o+@>DIMrv(a}!fWPCjHQ*7<X1bz!i!><@Ps1Gh61huF
zGO;^`V|<Bg`}0_4=!Rc>x^HHur<cn!%DzrWF*Q~}E4`$EQ--p0-FDVh;rMYiUA#HT
z53Enc4=qE(A?bpO==J5)z0q^d5WZI~05+oS%kC|fu@U$$_#8l~aT>WA#=@RVqFlzW
zoiPm;;`s$YC3Gm>*#x#l9H}&TOxBT`XZS`|71xZVT8+W0PdGkX2BxL9bEqVOXr4ZM
zqlP5)<?<)62ep+~tvMIE{Ucj_rR|KTuHTHfE=s2y+hCPL1{la8Hz`2~k9n(`-oUX^
z7A&`FO7>yigBF_=NX;D>A~Z{iA>!d*n}%o<B;mtVUEyh<7SncjeE2e0U2H>x3@bEy
zUWl(ZeAG;lLhQ}Wcj!K?Ie}L<6Xp0x&DnM#BN*Ea!I8;VD4Ksbl_|RGV3%QL{A&tj
z2;uj}RVQj&N|S2WiPAu@fvs{;Q10s=&vy4@38CNTIXxt%-|~GQG!_`6AabL=#X)^$
zqe>V;rPRVVY>3;1y9_|&>@w^{BeB3BtA_1|wgs`&W51cCv*l9^o6sbTeN0|Qr?i<t
zIeEWB9}&k#U+A{R+69Jscix4`Dg##b1SKw&Gz$ZnJBScd%~UPEk%Af&>oQ3ol4VM_
zyS~0Q`icO}u|ozwyI*BS-YFR-Hhu2joIxgu$`^EdoG3gZBnwwi0L-1D4%%_Ls{`i;
zDx;|m%E{ykEd|=6Zu4vr1gVdB5Xa;jpth`*gD^=l*~Gq#swfeUQNuc0qM^%D%V-Yf
zTd9(!`1aBl3r3zuM91JFOV`unOdy@Wc3C>gZUQ1akLhx*=e~&PRM1aUFfqZ6<EeR0
zRd%vPyi4QfLmg~f<faWopEId=<9ffH&*lP`$0*4j<>qCRWQQsCV~Iu*i^YF>60%Lq
zK-4+y2vhJZUJQ{_C*1IJl~o-_4$Wo3=9bL-4{hz5vlzAR(rn~4MX+P&OWGvM;|K!b
z8r`7;hzY0+qAotdaHJs*8nD<3WNqqR)0-4Z73v1UQVeF5UUr|j{GB04MEnSDpy1#r
z(GPj0uk6HfAn3kApW=J9zQH(`1$Rex)`cW(ygOP%Gem+Q=@O)2CM82(aDOkp>xj~q
zXKg0-(n*o1ziX`StvOE~me&O3-6@mAqArw0pZ6}mo=(bm9mYP<bk&g4O{k55k<`vE
z1y3q(1aOd5^>o*@q}R-9nwaoef}c&j$o=sPT-74o4==R)*B;Dn0*g)vv#!1~W!*fn
zJY2BdA#1#^q-e-wmUNRId9QX-3Ywo7V!dMJW`}+KU_>>w-y<)V)Hj8^B^B#!mf)C!
zZ9v0|O)Jo$sOD}ToMiKbs*do0OK*b|;&UD6ZkkUDCN+Me`yi8;pDmuIpFv$B8D4_v
z`_+GVbG1e-t#GJLi7HCAM(piw#p}$__Fjo4U1$C6p6R+v&%5{R1q<nAgYcCFc6OdH
ztd+tM#<*g=OiM!+^>W*$I<Cx*WqWEO&+<OmKoKc#Y-q!fHLb*YCJ1x%4JZIB8yxre
zJnoi2B|$*CnAwLU#ubJL`q_fQoTGs~Sr!p=h2WuqERAx}sz>li6BjEJooYV-jOUr&
z84>;Y_(}E5sV<jpuvJ~Dp{d>w>V3K=rGnx$Xy8L+eWv<V3PdN!qUw6SN3pwTto#Z8
zeZCpK-D%5|8Yy<T7(eAeEAFejK+E#@<Bd8NUu-9i?5p2gJJ&e{QCuRcaQgTXc`t>c
z_TCU?(UJua^r?o88F~QYh!oSIf)iha$oHLPwipBGos61(cl|Y=_}D=pWenf<nFtTV
zWZ+1==Slm<n0XY4A^MSlelctUWJ<JUy`UOhFudNTlCfk?g++{pF&vLOk2uY4fqXEJ
z`YfRl78xtyhj){#B#<26;;=zwW}Bc{Xt1U@6)_e~@^;gLVB?REPpYhoTSABjlo6Tv
z(o@~}Ckj~u#_GoBRr#$=L_SAvLEQ+jE38wgC_JpK+<2=FWVScgc`l@~x!JzSq755)
z_&PA1L1*7}T_S!o(Z7<|IYM%z6O1k1AN`pt6Lcf#=9(seO=H@Sw0be#?sOP`?xsef
zuh!3S=cz6xj<HDLqZdTSCNN%Q&}&(%a7ezRk7vmeGM>adwx~DXf~okV?};F-Oi?Pd
z&20i#fNABIZ-mJ9Yzav4CRJb;G#qQ5K9~-lqZO=_1ebf9EII4Ek~v+=ulXT2m}#B(
zt<e(X&h{SdrtfnI->_6`*ff$C8BY?X+L@?~G*^}1aFS{3VQ0=k1rU2jz)YTWPFzzw
zXwFRdSq6l58?k6-{E0;NUF7}C_5FQ%&SD-EJza%N#KeVwYOU(`sJ@zem0^|1?D3XC
zlF`<DK)R$&jw}UCb$d`-HFFR$OkaqIX}kG_o)OrK<xms8J9I6R8;-khj<}=bG)jO%
z3{4;xeIX16271{trjEKYmyeH%=B|aAxS<w0J;o|uVP0{FyD`K3w`Di(-Og3afu5ZX
zDm%Q}fG^Xq#zzSYXz`>+9NO?K$T0ojK$}}ar#sSo#5*KB6bW7wzrpjtfQEgfg=W^%
z{v(saW=@@z)sRA?M|_l#kc9cACU>x#A|_m=qlQY4C$9u8QN&}z@0xnby0^$DkG^t5
z@w=4fG-}RJ@waa0g(dfy*@D3Qiwt*H7xvcL?7>qQ-%g>OhcXU4*2UO-85&Fn#*#&6
zR$D8H8Z)6~rB2hFNbQ1gG!Bb&TSWPT`$iXn5OM38ZoBwEwi2$Ev|5*04bd<#T)I@O
z+l}U!U1vU`Q@t?LsxO6|cluGJ;zwl3-?hxz?W{&zr4~hEc%8!z1FC>FaX-_t6~8nJ
z_bKIRu88;P6e5P|$R7$LU`5%QRG}A3{aEk_5_V;YL#u%ONtN^|)f;b9%BAuta%r&x
z;}p0&wV?t2x5_5g@{5_8Pa+Y-x;7<H_}&x37|)H@M_}lpi&W&g&9`CUIqP}%*|@WF
zF2#Y)-y-Gg=UkGuc&pMK*<yK6Dpy9Qh2eeYNY6aAQR|uHB4WjFU#q})i@ldG#!}5K
zJLM2Fzbx>T$j(`nZvvC;jPQGF1MA3Z$4UY!d58=h$16V1>TPQWwlDhl0X<8HG^u;d
z!E#tz21K0gJV0IJqlQ2^P-3<uH>*#simIkA!9hQ{U7O<9_c*LjfD!0-c@W&cSWoAV
z9~%+Zw3ErsR2+IK&&4q~7BpMjurk7Al`&mqE6bBv3IF)<m>O&wdZ!TH7(r$2*|!8y
zo;x@qTAbA=bbiki9@}LDQ$H6$aPPvaR{?&tH(s^>mBP`(>J_Gzit@dw*LZx}S<M?e
z^y-zR5;IW;`ws|1?W74Vl9Ilocrt4bdfAk>GT(V)>~Yf;GOWFr$cwigNM6KtmjoWR
z=Z!Jvq-dLx7kq)K+$+foNPM*`;Ph%OO>~a`Ir^xqIvw$hgNvZqL4tU{OaIj*WtdQ}
zKH9rL`F$_hI^eN4c({)LT<F(TVXdM5lU89VFywigvi2lW?pJow0ThBxeh;D?@3s-@
zm+}0Vk-|-Jcp=-+Py8pg4^vTrZfXl-ah0Xrnq#3wn7t&2b=>m7lFla|YH@lj)<CTW
z8lh<<T&-Df^KE*{ha|MJ@stSYZx>Z(30P#ohNlAEEw>VT76-Yg?DDeA*9HmE0+sw|
zMjS`I?N;zv)-KLJV1br=+3h)Wq0<hX%`G&=u}OSDR3o;`dEW8YF0~+VAjL*pIMS?$
z8gW%AC{@7rX3~a}P9=SBv9RPj{xG{)M0>Pp#fe@iz0ab<+y66P)8qdz-GFOlN^E7h
zY@EIG0PpXKFVB(78x~RICqnTymwo*Ml!x7)56ny-$%$%_ey{vI12GK3)fFhaQ5NFM
z*7(LvGqe-^(B&^!;cRw=PR9CP`XEv6Uc&$LjI-qT2Vty`N@n2?PC%u3I<=02Ncs4D
z6rNlgTAVsCM0rbxs5gq%4I=|vR)kG{gBz_D1W@c4hT=PYe#sYY%^~q+`+yG*H5zij
zU44y|*(<5FR8g5JM0Q~>4eTJV&l)z|Yo)54Pi14M-U~`qY7VQh{t!%v0{Cx~T;9|I
zWfnbW*?x>!SPy9iCv~xsXguYF9XPnyqhFdE+cL7bgl;$Sh>F=R!!nCwO;Po5b<*M@
zN5z|$r%jsl>Om4qOXJLS%3XOo7z!@#7Hn4WMmt(A_G!J_+}dl}>KYoN8#yLei!>AP
z_i(V>+o)MB7YZ`OViG`V#DAPL!X99|0)6#99%Ph_-a1|Gmg>t5(yd!ZM$yKesw{MT
z$-h0(vdL_g#r58R6icJDj;H7_xth+1cp#98)*WcDrF#TJ4Sd0dLepD-HFX=U-CR-`
zZQac@OyR^xvU<Dh=2tXmJ;vADg=*T(>0F@*y7_jm<Dq9{>Po$p&KC5bFrYtddkiX$
zA!+NVtaNukJ&A6@BdDlMel%Zd@#JQ@(}FI4zEWI)#C$)66h8p>u-0d)ypHCH46a6#
z9}Eq8YE?@6a7}NUxvB@?<$v2BYTJkw=zMxPJ{#C4p+vCIQ9L0lqtr$J)XM{E*i<7>
z^dQE;|6ws09%^lLjo%}eS^ZecJKa9btQ8R=X-^bFueR#h-+!)jQ0Xc?!Gc?V+}iHL
zhE}@hEl$LEY~#vFti3q+Bvv8V90$k)N4{5(M}--D<$z0Jai+${eLhicY&I!tT^Q8+
zNJcWb0%Vd-?O{6k&5%}EoYVRdo)iulA60&5uy%6xAGCaun<MmB+mU*r528I4<6rBY
zyzZ|UlO-4Z8`FTez14fUK56F|R2dR4jF>(muV0(MIuD^UOCVH*dKs+Io;*E0GgMd7
z_B5ZbFL&iXuVM8zLI`=C0(&Rak`KjNImuZp)6^0+S+~Tbm#x~alB^3$T_q1Q>q6Du
zaLCg(9xE$m{5%etK+5ryz_>ld!Z|ihAf$-V+w>1PC*k&J@z^VmclqYJZ{_+P3CzLf
z_ixQn$|#2tc5q7#Y2{C{o2>bYzL7Asn*4~JV<4x^h>TDj@LDFT5#dj5?@p4ASI15p
zr4C_1Tzz*lz@=R@Jsfwfz~|Mxv52Hg`9rRYRD1WrEn>eBLv_vjeyhs!^OFG`VrWZn
z@RPtI7LTDpRU`5SKi)iLW3WXIgswR&6}B#~$C-IEtIBKz<XRu8YxMqDd_Qgce#B|2
zA#_$?k5nt?aq*k?`zK^``*=#o@jRP#AE6j))`=cN|FjxsGFK(U>iZj?wIq-^_e5Z0
zUx0OT>zGZn&?{Z`qa}|ZE|sP0alPOD$_SC(X{0a|P{(`H;qac^28l$ZlH?t<$v|8F
zNmQf`w$9~T0%V___<Xy=r%UG3-tjlEUy4<*fPV@J!0ftk2>IvPFUK#%Dl1zf11q2-
zgN385%|D7&KA01ze<)UYlK$VPNV$o%bi81HMI={Wl>q!kV16PR15FH^t(+Vg{{d&z
z=J3bb*Y6ejt&sd|?f`VOb#^cUIx-qM*t$9b9rTP1P4x_njcsjM8Li9>8UISlzlMeV
z9qfPK9{qRi|Dg)Kqp{`RK>9QP{Ciu)fA1fH|Ky+ltPxKtP~?x0{~j?r2cQYi0ci6J
z`Y-2>|EgeaA7Cl{Z6h)M3i7`<82c|g|DWREpT$|WpSEHURA#LGyh`|ao9gd`m$iYp
z&A-f^{hww>M%T#oG9d@u@%9ZVkp_yChx!Soe8I*>@we1d3janq9#x>YyH+F2SC1B6
zFypoH@aAva++A#ejbOzD*txU7md=rrfeR~T{5l?^;wH`YGS^yn)m)D~>5;sdQRpv>
zICyr!{t<5*iD=tBhlq8emLzjIg11?q@H2YWSioy(LY{fKr&k-F6GHr&+nu5yArDuj
zs=F}eu!SDLjJJFyV0FNpwh^0gZZXf5RWfqb+$r-1-Jvmp{M`~>e<0`{F;I7b`0@hl
ztbjWQQ|0jUnRLY)#e!WzoixU0kiQ-XsDDotf5Y#ETB{Ox(tN!5pa1~e&wFq`8=KoW
zIvH45F*q2T`~%>w=YNC&Fn-M@O%OTo>;+xPVFdzS6;%t-e2z`AKrC#zRIw`8m*7}d
zAL|6M$9&H93>Us8jdqcB<C!4o=BBc8Go@TfOb_CU3DL*NAb&coEPGc`8**XkF$4MB
zs0{xTX9YbpKaQlGr4@p%qxGu<1Q^~XJxF{7!IxTr)s&6WQsmQ>cEvt;0Qe^r2y^kX
zt@i=s5yJP1pdSoUlc|qhX`K!P@gPg^wGx|TP`UfGkf=D(X;gO0o>}P8i+jFD3=6P<
zuvn#}si4mZzfCU6elHX2)I;|}UV2;^qrYEkXoE$xT5vW<zCHNVqAg~RN)cLJi+(D~
zdK%zj+7nZk`$&G$EQ>l29&+fltr7Dexxo1ywhZ?c6Kt;#cve1FCOj==KA^6WD^?-p
zuuA#BR;ngt5-l|jF;CN1)L-zP)S90cl~bL!A`c|xyw`Pf+iq&0{|fwET3BOx;BkRE
z2CsMB)QY8%{-(Q(?PJAy)0kBGYBzqslHjrJP(`hB>e~ADLZun!H=?wDJ&^C_*-EBj
z)|$^q7|Hgy$ym7(hUno}qSQ(5GKQIkVbYqq`N`p3l!OsW4buWhWt95{tE}S7)ZuL(
z<#%Ge=K3Y`IP(x0I(1G4;VjvDP3gCyux(>5zF|hP16$ZL$exI=#=xY^ot76)jL@i~
zJ;=TvD1#7UirrOzVok+@lOF6h;bSH=se5sIqpyp4?ur?E1^G3&ewn~1{b?6Se+JhA
z_&+CSGXn=3pra$bt(}v(t<7&1vp<=)B9&#Mmzj_|u4v2C@dhc=u9Zs(HA^Z~OJ}7U
zJ{WnT!iUP91VB{WpEX<w3AUM~Nq<e_WVKyiY#$97;23l{!nG`rUl&&t1fGM{fFuag
zY8zpH!PCaxIM0yR8lwHqnM2Rvso!R+M|Wrqf#g*z3g6ZdN)1TLg7jOcp@qP2$OGM%
zYAp?yniRb|HH4dYSjk5=VckgOFM}k}k-O_8j-Ir_mum3fC|*cUI;ym2Z+<8BG25K(
z0w{JG|HO3BY`C|uppw8qPrg#>phDM~p-`3GeMz+|`oTY#7pAUWFf|B8-T`+Y29hmu
zJ2(WWfeFb=-|XcOkZ$t8f-pUaXE7hvgz*}HYa3LDVv3!RJZU*a_Hk!J)vWv@he>+R
ziCP)I<Ne{%H%E@Nc=KxAO@l#qFsJWVlRd<i0daZgZFE@t6CQqQMqv23*e@OB&JO4Z
zGlpkj&7id7UKB7*6*LX5UnQ;Y<d8?r`J)<oXX>U`hn{9=H@<>Aawi)oBz=&pbIvH*
ztPwK*hT&jEyC!8WzY&5y-|~Tgu?s4#?IH`3B2m9lj`J~k;EX&KDo^Y^7mF+}o{p!b
zf$K5gLl3lAc3q!m(@|NOUBUNP=J(kg!oB*0>vZQC#-8X6LU&bmjz@R%?`NrSQYUc9
zSDqJ6n%=!+Ccxi5ecXnU7KnJJf;M_18G2^vX7Z&Xs>L+}*ZNV*v(;h2gRHWbYwq&;
zo3DGn?263czQAby89bt3f7}&mU}J6qbaY~{Hc5<?wyhP!4!nDXy%Q17H)FT&5zV>G
zQ9#a53mUPDPnp7*+^(uBd{Cd2UCa2+H+1!#&m<%qz1Cw>Xc*RS-^-ip@P>oL@5<X(
zgFtmI=AF4beXXZ#Da(g&ZgH!1PL-Oo1JsSSz@7=O^?~IfYd#Q=zAxq1VGp*DRg2-G
zXY0qBtHA}-jGvwnUD7HZtNIJxSd28h8%O&-dx%JkS>O@|Q#`SH*K!J%7A4uUyW5WC
zmeGzb?s5`-ASrFqeVRK|3Ybc*s9@0uZ$;YR{zRw<kAoLu<n;vCCW-uPiXc2@h#1m8
zFR&B<xyWB%a+RGkCNnT85*6<1c1HZYvl8Al#ddl1l#K>87~>P_XY}JwETHk>rT#kp
zYyCF@!@(%Z?-`mKV82~ZZEPiy!KtOZkzP6^Ip2d98Ys=d<5SC!1abulr0~_jGDeTt
zpVQQg@|mE*7OGa}FWF|<hYp)lDDJaZbU>%m>cJvHLVq90xyp%&4O*ulm12OOo**CQ
z?<FTu2dJQcpkv<Sup8R+#TGA(!9X-t*83@K5A`aJs5tOpc$=GtwhO=oM`D_;dIE+|
zbWZSoKhj+O$fFiNuiSqgXn;T2|LSN0H!d?FO-D^HHHRQgPcuF`QK!f>%er~#%sl5j
zBqLAHFm)q4IwAwcQjRX=Fh=92IP)Cu$mc-jN3VpY(^1zxY;E1*$A^!=oQUUkp9oY|
z0T%7u<B5as;@sojtKVZodGPENtT@<%{9H{zK+(bedUNi-#0LcMXR10l8vKGl2=>>X
zseh4Q8t40R{lxt{AFcn1_}5(GSHxW+z~5pPzeW7BT=}1Z3^)<uBnJE)X7PIke=8)v
zgLC-__y55({<<63-*q$gyKeqBc<8^wLm&bCmrUgE`d5tv@OPNWUn@%RJGdm0|KQ)h
zqw$|{m48XT?++5d|CYJ@wNo&DX9X|mUv%-maS-<Jpo2;Od?f#K-2FAT`9=Qu{>_p8
zjqv^tOy~b)3)JsyK_&<MXL9hX>VHNLepOxeC)nR03%>>Yvy|{xz|wbs|0+TJ<IMZV
u1mIud1A<BY=jp&75&pQa{E7ge{nKSeK^g+`mj_UP{$3yefHc})uKo{5NNz^}
--- a/docshell/test/unit/test_nsDefaultURIFixup_info.js
+++ b/docshell/test/unit/test_nsDefaultURIFixup_info.js
@@ -424,34 +424,28 @@ var testcases = [ {
     protocolChange: true,
   }, {
     input: "a?.com",
     fixedURI: "http://a/?.com",
     alternateURI: "http://www.a.com/?.com",
     protocolChange: true,
   }, {
     input: "?'.com",
-    fixedURI: "http:///?%27.com",
-    alternateURI: "http://www..com/?%27.com",
     keywordLookup: true,
     protocolChange: true,
   }, {
     input: "' ?.com",
     keywordLookup: true,
     protocolChange: true
   }, {
     input: "?mozilla",
-    fixedURI: "http:///?mozilla",
-    alternateURI: "http://www..com/?mozilla",
     keywordLookup: true,
     protocolChange: true,
   }, {
     input: "??mozilla",
-    fixedURI: "http:///??mozilla",
-    alternateURI: "http://www..com/??mozilla",
     keywordLookup: true,
     protocolChange: true,
   }, {
     input: "mozilla/",
     fixedURI: "http://mozilla/",
     alternateURI: "http://www.mozilla.com/",
     protocolChange: true,
   }, {
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -516,20 +516,17 @@ KeyframeUtils::ApplySpacing(nsTArray<Key
     RangedPtr<Keyframe> keyframeB = keyframeA + 1;
     while (keyframeB->mOffset.isNothing() && keyframeB != last) {
       ++keyframeB;
     }
     keyframeB->mComputedOffset = keyframeB->mOffset.valueOr(1.0);
 
     // Fill computed offsets in (keyframe A, keyframe B).
     if (aSpacingMode == SpacingMode::distribute) {
-      // Bug 1276573: Use the new constructor accepting two RangedPtr<T>
-      // arguments, so we can make the code simpler.
-      DistributeRange(Range<Keyframe>(keyframeA.get(),
-                                      keyframeB - keyframeA + 1));
+      DistributeRange(Range<Keyframe>(keyframeA, keyframeB + 1));
     } else {
       // a) Find Paced A (first paceable keyframe) and
       //    Paced B (last paceable keyframe) in [keyframe A, keyframe B].
       RangedPtr<Keyframe> pacedA = keyframeA;
       while (pacedA < keyframeB &&
              cumulativeDistances[pacedA - begin] == kNotPaceable) {
         ++pacedA;
       }
@@ -541,45 +538,41 @@ KeyframeUtils::ApplySpacing(nsTArray<Key
       // As spec says, if there is no paceable keyframe
       // in [keyframe A, keyframe B], we let Paced A and Paced B refer to
       // keyframe B.
       if (pacedA > pacedB) {
         pacedA = pacedB = keyframeB;
       }
       // b) Apply distributing offsets in (keyframe A, Paced A] and
       //    [Paced B, keyframe B).
-      DistributeRange(Range<Keyframe>(keyframeA.get(),
-                                      keyframeB - keyframeA + 1),
-                      Range<Keyframe>((keyframeA + 1).get(),
-                                      pacedA - keyframeA));
-      DistributeRange(Range<Keyframe>(keyframeA.get(),
-                                      keyframeB - keyframeA + 1),
-                      Range<Keyframe>(pacedB.get(),
-                                      keyframeB - pacedB));
+      DistributeRange(Range<Keyframe>(keyframeA, keyframeB + 1),
+                      Range<Keyframe>(keyframeA + 1, pacedA + 1));
+      DistributeRange(Range<Keyframe>(keyframeA, keyframeB + 1),
+                      Range<Keyframe>(pacedB, keyframeB));
       // c) Apply paced offsets to each paceable keyframe in (Paced A, Paced B).
       //    We pass the range [Paced A, Paced B] since PaceRange needs the end
       //    points of the range in order to calculate the correct offset.
-      PaceRange(Range<Keyframe>(pacedA.get(), pacedB - pacedA + 1),
+      PaceRange(Range<Keyframe>(pacedA, pacedB + 1),
                 Range<double>(&cumulativeDistances[pacedA - begin],
                               pacedB - pacedA + 1));
       // d) Fill in any computed offsets in (Paced A, Paced B) that are still
       //    not set (e.g. because the keyframe was not paceable, or because the
       //    cumulative distance between paceable properties was zero).
       for (RangedPtr<Keyframe> frame = pacedA + 1; frame < pacedB; ++frame) {
         if (frame->mComputedOffset != Keyframe::kComputedOffsetNotSet) {
           continue;
         }
 
         RangedPtr<Keyframe> start = frame - 1;
         RangedPtr<Keyframe> end = frame + 1;
         while (end < pacedB &&
                end->mComputedOffset == Keyframe::kComputedOffsetNotSet) {
           ++end;
         }
-        DistributeRange(Range<Keyframe>(start.get(), end - start + 1));
+        DistributeRange(Range<Keyframe>(start, end + 1));
         frame = end;
       }
     }
     keyframeA = keyframeB;
   }
 }
 
 /* static */ void
@@ -1482,19 +1475,18 @@ DistributeRange(const Range<Keyframe>& a
  * @param aSpacingRange The sequence of keyframes between whose endpoints we
  *   should apply distribute spacing.
  */
 static void
 DistributeRange(const Range<Keyframe>& aSpacingRange)
 {
   // We don't need to apply distribute spacing to keyframe A and keyframe B.
   DistributeRange(aSpacingRange,
-                  Range<Keyframe>((aSpacingRange.start() + 1).get(),
-                                  aSpacingRange.end() - aSpacingRange.start()
-                                    - 2));
+                  Range<Keyframe>(aSpacingRange.start() + 1,
+                                  aSpacingRange.end() - 1));
 }
 
 /**
  * Apply paced spacing to all paceable keyframes in between the endpoints of the
  * given range.
  *
  * @param aKeyframes The range of keyframes between whose endpoints we should
  *   apply paced spacing. Both endpoints should be paceable, i.e. the
--- a/dom/base/File.cpp
+++ b/dom/base/File.cpp
@@ -771,17 +771,21 @@ BlobImplBase::GetSendInfo(nsIInputStream
   *aContentLength = GetSize(rv);
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
 
   nsAutoString contentType;
   GetType(contentType);
 
-  CopyUTF16toUTF8(contentType, aContentType);
+  if (contentType.IsEmpty()) {
+    aContentType.SetIsVoid(true);
+  } else {
+    CopyUTF16toUTF8(contentType, aContentType);
+  }
 
   aCharset.Truncate();
 
   stream.forget(aBody);
   return NS_OK;
 }
 
 nsresult
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -25,16 +25,17 @@
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/OffscreenCanvas.h"
 #include "mozilla/dom/OffscreenCanvasBinding.h"
 #include "mozilla/dom/PMessagePort.h"
 #include "mozilla/dom/StructuredCloneTags.h"
 #include "mozilla/dom/SubtleCryptoBinding.h"
 #include "mozilla/dom/ToJSValue.h"
+#include "mozilla/dom/URLSearchParams.h"
 #include "mozilla/dom/WebCryptoCommon.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "MultipartBlobImpl.h"
 #include "nsIRemoteBlob.h"
 #include "nsQueryObject.h"
@@ -390,30 +391,39 @@ StructuredCloneHolder::FreeBuffer(uint64
 StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx,
                                                     JSStructuredCloneReader* aReader,
                                                     uint32_t aTag)
 {
   if (aTag == SCTAG_DOM_IMAGEDATA) {
     return ReadStructuredCloneImageData(aCx, aReader);
   }
 
-  if (aTag == SCTAG_DOM_WEBCRYPTO_KEY) {
+  if (aTag == SCTAG_DOM_WEBCRYPTO_KEY || aTag == SCTAG_DOM_URLSEARCHPARAMS) {
     nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
     if (!global) {
       return nullptr;
     }
 
     // Prevent the return value from being trashed by a GC during ~nsRefPtr.
     JS::Rooted<JSObject*> result(aCx);
     {
-      RefPtr<CryptoKey> key = new CryptoKey(global);
-      if (!key->ReadStructuredClone(aReader)) {
-        result = nullptr;
-      } else {
-        result = key->WrapObject(aCx, nullptr);
+      if (aTag == SCTAG_DOM_WEBCRYPTO_KEY) {
+        RefPtr<CryptoKey> key = new CryptoKey(global);
+        if (!key->ReadStructuredClone(aReader)) {
+         result = nullptr;
+        } else {
+          result = key->WrapObject(aCx, nullptr);
+        }
+      } else if (aTag == SCTAG_DOM_URLSEARCHPARAMS) {
+        RefPtr<URLSearchParams> usp = new URLSearchParams(global);
+       if (!usp->ReadStructuredClone(aReader)) {
+          result = nullptr;
+        } else {
+          result = usp->WrapObject(aCx, nullptr);
+        }
       }
     }
     return result;
   }
 
   if (aTag == SCTAG_DOM_NULL_PRINCIPAL ||
       aTag == SCTAG_DOM_SYSTEM_PRINCIPAL ||
       aTag == SCTAG_DOM_CONTENT_PRINCIPAL ||
@@ -499,16 +509,25 @@ StructuredCloneHolder::WriteFullySeriali
   // See if this is a ImageData object.
   {
     ImageData* imageData = nullptr;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageData, aObj, imageData))) {
       return WriteStructuredCloneImageData(aCx, aWriter, imageData);
     }
   }
 
+  // Handle URLSearchParams cloning
+  {
+    URLSearchParams* usp = nullptr;
+    if (NS_SUCCEEDED(UNWRAP_OBJECT(URLSearchParams, aObj, usp))) {
+      return JS_WriteUint32Pair(aWriter, SCTAG_DOM_URLSEARCHPARAMS, 0) &&
+             usp->WriteStructuredClone(aWriter);
+    }
+  }
+
   // Handle Key cloning
   {
     CryptoKey* key = nullptr;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(CryptoKey, aObj, key))) {
       return JS_WriteUint32Pair(aWriter, SCTAG_DOM_WEBCRYPTO_KEY, 0) &&
              key->WriteStructuredClone(aWriter);
     }
   }
--- a/dom/base/StructuredCloneTags.h
+++ b/dom/base/StructuredCloneTags.h
@@ -49,15 +49,18 @@ enum StructuredCloneTags {
 
   // This tag is for OffscreenCanvas.
   SCTAG_DOM_CANVAS,
 
   SCTAG_DOM_EXPANDED_PRINCIPAL,
 
   SCTAG_DOM_DIRECTORY,
 
+  // This tag is used by both main thread and workers.
+  SCTAG_DOM_URLSEARCHPARAMS,
+
   SCTAG_DOM_MAX
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // StructuredCloneTags_h__
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -218,17 +218,16 @@
 #include "mozilla/OwningNonNull.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/UndoManager.h"
 #include "mozilla/dom/WebComponentsBinding.h"
 #include "nsFrame.h"
 #include "nsDOMCaretPosition.h"
 #include "nsIDOMHTMLTextAreaElement.h"
 #include "nsViewportInfo.h"
-#include "nsIContentPermissionPrompt.h"
 #include "mozilla/StaticPtr.h"
 #include "nsITextControlElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIEditor.h"
 #include "nsIDOMCSSStyleRule.h"
 #include "mozilla/css/Rule.h"
 #include "nsIDOMLocation.h"
 #include "nsIHttpChannelInternal.h"
@@ -236,17 +235,16 @@
 #include "nsCharSeparatedTokenizer.h"
 #include "mozilla/dom/XPathEvaluator.h"
 #include "mozilla/dom/XPathNSResolverBinding.h"
 #include "mozilla/dom/XPathResult.h"
 #include "nsIDocumentEncoder.h"
 #include "nsIDocumentActivity.h"
 #include "nsIStructuredCloneContainer.h"
 #include "nsIMutableArray.h"
-#include "nsContentPermissionHelper.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "nsWindowMemoryReporter.h"
 #include "nsLocation.h"
 #include "mozilla/dom/FontFaceSet.h"
 #include "mozilla/dom/BoxObject.h"
 #include "gfxVR.h"
 #include "gfxPrefs.h"
 #include "nsISupportsPrimitives.h"
@@ -11873,37 +11871,21 @@ nsDocument::FullscreenElementReadyCheck(
   return true;
 }
 
 FullscreenRequest::FullscreenRequest(Element* aElement)
   : mElement(aElement)
   , mDocument(static_cast<nsDocument*>(aElement->OwnerDoc()))
 {
   MOZ_COUNT_CTOR(FullscreenRequest);
-  mDocument->mPendingFullscreenRequests++;
-  if (MOZ_UNLIKELY(!mDocument->mPendingFullscreenRequests)) {
-    NS_WARNING("Pending fullscreen request counter overflow");
-  }
-}
-
-static void RedispatchPendingPointerLockRequest(nsIDocument* aDocument);
+}
 
 FullscreenRequest::~FullscreenRequest()
 {
   MOZ_COUNT_DTOR(FullscreenRequest);
-  if (MOZ_UNLIKELY(!mDocument->mPendingFullscreenRequests)) {
-    NS_WARNING("Pending fullscreen request counter underflow");
-    return;
-  }
-  mDocument->mPendingFullscreenRequests--;
-  if (!mDocument->mPendingFullscreenRequests) {
-    // There may be pointer lock request be blocked because of pending
-    // fullscreen requests. Re-dispatch it to ensure it gets handled.
-    RedispatchPendingPointerLockRequest(mDocument);
-  }
 }
 
 // Any fullscreen request waiting for the widget to finish being full-
 // screen is queued here. This is declared static instead of a member
 // of nsDocument because in the majority of time, there would be at most
 // one document requesting fullscreen. We shouldn't waste the space to
 // hold for it in every document.
 class PendingFullscreenRequestList
@@ -12296,252 +12278,296 @@ DispatchPointerLockChange(nsIDocument* a
     new AsyncEventDispatcher(aTarget,
                              NS_LITERAL_STRING("mozpointerlockchange"),
                              true,
                              false);
   asyncDispatcher->PostDOMEvent();
 }
 
 static void
-DispatchPointerLockError(nsIDocument* aTarget)
+DispatchPointerLockError(nsIDocument* aTarget, const char* aMessage)
 {
   if (!aTarget) {
     return;
   }
 
   RefPtr<AsyncEventDispatcher> asyncDispatcher =
     new AsyncEventDispatcher(aTarget,
                              NS_LITERAL_STRING("mozpointerlockerror"),
                              true,
                              false);
   asyncDispatcher->PostDOMEvent();
-}
-
-static const uint8_t kPointerLockRequestLimit = 2;
-
-class nsPointerLockPermissionRequest;
-mozilla::StaticRefPtr<nsPointerLockPermissionRequest> gPendingPointerLockRequest;
-
-class nsPointerLockPermissionRequest : public Runnable,
-                                       public nsIContentPermissionRequest
+  nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+                                  NS_LITERAL_CSTRING("DOM"), aTarget,
+                                  nsContentUtils::eDOM_PROPERTIES,
+                                  aMessage);
+}
+
+class PointerLockRequest final : public Runnable
 {
 public:
-  nsPointerLockPermissionRequest(Element* aElement, bool aUserInputOrChromeCaller)
-  : mElement(do_GetWeakReference(aElement)),
-    mDocument(do_GetWeakReference(aElement->OwnerDoc())),
-    mUserInputOrChromeCaller(aUserInputOrChromeCaller)
-  {
-    nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
-    if (doc && doc->GetInnerWindow()) {
-      mRequester = new nsContentPermissionRequester(doc->GetInnerWindow());
-    }
-  }
-
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSICONTENTPERMISSIONREQUEST
-
-  NS_IMETHOD Run() override
-  {
-    nsCOMPtr<Element> e = do_QueryReferent(mElement);
-    nsCOMPtr<nsIDocument> d = do_QueryReferent(mDocument);
-    if (!e || !d || gPendingPointerLockRequest != this ||
-        e->GetUncomposedDoc() != d) {
-      Handled();
-      DispatchPointerLockError(d);
-      return NS_OK;
-    }
-
-    nsDocument* doc = static_cast<nsDocument*>(d.get());
-    if (doc->mPendingFullscreenRequests > 0) {
-      // We're still entering fullscreen.
-      return NS_OK;
-    }
-
-    if (doc->GetFullscreenElement() || doc->mAllowRelocking) {
-      Allow(JS::UndefinedHandleValue);
-      return NS_OK;
-    }
-
-    // In non-fullscreen mode user input (or chrome caller) is required!
-    // Also, don't let the page to try to get the permission too many times.
-    if (!mUserInputOrChromeCaller ||
-        doc->mCancelledPointerLockRequests > kPointerLockRequestLimit) {
-      Handled();
-      DispatchPointerLockError(d);
-      return NS_OK;
-    }
-
-    Allow(JS::UndefinedHandleValue);
-    return NS_OK;
-  }
-
-  void Handled()
-  {
-    mElement = nullptr;
-    mDocument = nullptr;
-    if (gPendingPointerLockRequest == this) {
-      gPendingPointerLockRequest = nullptr;
-    }
-  }
-
+  PointerLockRequest(Element* aElement, bool aUserInputOrChromeCaller)
+    : mElement(do_GetWeakReference(aElement))
+    , mDocument(do_GetWeakReference(aElement->OwnerDoc()))
+    , mUserInputOrChromeCaller(aUserInputOrChromeCaller)
+  {}
+
+  NS_IMETHOD Run() final;
+
+private:
   nsWeakPtr mElement;
   nsWeakPtr mDocument;
   bool mUserInputOrChromeCaller;
-
-protected:
-  virtual ~nsPointerLockPermissionRequest() {}
-  nsCOMPtr<nsIContentPermissionRequester> mRequester;
 };
 
-NS_IMPL_ISUPPORTS_INHERITED(nsPointerLockPermissionRequest,
-                            Runnable,
-                            nsIContentPermissionRequest)
-
-NS_IMETHODIMP
-nsPointerLockPermissionRequest::GetTypes(nsIArray** aTypes)
-{
-  nsTArray<nsString> emptyOptions;
-  return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("pointerLock"),
-                                                         NS_LITERAL_CSTRING("unused"),
-                                                         emptyOptions,
-                                                         aTypes);
-}
-
-NS_IMETHODIMP
-nsPointerLockPermissionRequest::GetPrincipal(nsIPrincipal** aPrincipal)
-{
-  nsCOMPtr<nsIDocument> d = do_QueryReferent(mDocument);
-  if (d) {
-    NS_ADDREF(*aPrincipal = d->NodePrincipal());
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPointerLockPermissionRequest::GetWindow(mozIDOMWindow** aWindow)
-{
-  nsCOMPtr<nsIDocument> d = do_QueryReferent(mDocument);
-  if (d) {
-    NS_IF_ADDREF(*aWindow = d->GetInnerWindow());
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPointerLockPermissionRequest::GetElement(nsIDOMElement** aElement)
-{
-  // It is enough to implement GetWindow.
-  *aElement = nullptr;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPointerLockPermissionRequest::Cancel()
-{
-  nsCOMPtr<nsIDocument> d = do_QueryReferent(mDocument);
-  Handled();
-  if (d) {
-    auto doc = static_cast<nsDocument*>(d.get());
-    if (doc->mCancelledPointerLockRequests <= kPointerLockRequestLimit) {
-      doc->mCancelledPointerLockRequests++;
-    }
-    DispatchPointerLockError(d);
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPointerLockPermissionRequest::Allow(JS::HandleValue aChoices)
-{
-  MOZ_ASSERT(aChoices.isUndefined());
-
+static const char*
+GetPointerLockError(Element* aElement, Element* aCurrentLock,
+                    bool aNoFocusCheck = false)
+{
+  // Check if pointer lock pref is enabled
+  if (!Preferences::GetBool("full-screen-api.pointer-lock.enabled")) {
+    return "PointerLockDeniedDisabled";
+  }
+
+  nsCOMPtr<nsIDocument> ownerDoc = aElement->OwnerDoc();
+  if (aCurrentLock && aCurrentLock->OwnerDoc() != ownerDoc) {
+    return "PointerLockDeniedInUse";
+  }
+
+  if (!aElement->IsInUncomposedDoc()) {
+    return "PointerLockDeniedNotInDocument";
+  }
+
+  if (ownerDoc->GetSandboxFlags() & SANDBOXED_POINTER_LOCK) {
+    return "PointerLockDeniedSandboxed";
+  }
+
+  // Check if the element is in a document with a docshell.
+  if (!ownerDoc->GetContainer()) {
+    return "PointerLockDeniedHidden";
+  }
+  nsCOMPtr<nsPIDOMWindowOuter> ownerWindow = ownerDoc->GetWindow();
+  if (!ownerWindow) {
+    return "PointerLockDeniedHidden";
+  }
+  nsCOMPtr<nsPIDOMWindowInner> ownerInnerWindow = ownerDoc->GetInnerWindow();
+  if (!ownerInnerWindow) {
+    return "PointerLockDeniedHidden";
+  }
+  if (ownerWindow->GetCurrentInnerWindow() != ownerInnerWindow) {
+    return "PointerLockDeniedHidden";
+  }
+
+  nsCOMPtr<nsPIDOMWindowOuter> top = ownerWindow->GetScriptableTop();
+  if (!top || !top->GetExtantDoc() || top->GetExtantDoc()->Hidden()) {
+    return "PointerLockDeniedHidden";
+  }
+
+  if (!aNoFocusCheck) {
+    mozilla::ErrorResult rv;
+    if (!top->GetExtantDoc()->HasFocus(rv)) {
+      return "PointerLockDeniedNotFocused";
+    }
+  }
+
+  return nullptr;
+}
+
+NS_IMETHODIMP
+PointerLockRequest::Run()
+{
   nsCOMPtr<Element> e = do_QueryReferent(mElement);
   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
   nsDocument* d = static_cast<nsDocument*>(doc.get());
-  if (!e || !d || gPendingPointerLockRequest != this ||
-      e->GetUncomposedDoc() != d) {
-    Handled();
-    DispatchPointerLockError(d);
-    return NS_OK;
-  }
-
-  // Mark handled here so that we don't need to call it everywhere below.
-  Handled();
-
-  nsCOMPtr<Element> pointerLockedElement =
-    do_QueryReferent(EventStateManager::sPointerLockedElement);
-  if (e == pointerLockedElement) {
-    DispatchPointerLockChange(d);
+  const char* error = nullptr;
+  if (!e || !d || !e->GetUncomposedDoc()) {
+    error = "PointerLockDeniedNotInDocument";
+  } else if (e->GetUncomposedDoc() != d) {
+    error = "PointerLockDeniedMovedDocument";
+  }
+  if (!error) {
+    nsCOMPtr<Element> pointerLockedElement =
+      do_QueryReferent(EventStateManager::sPointerLockedElement);
+    if (e == pointerLockedElement) {
+      DispatchPointerLockChange(d);
+      return NS_OK;
+    }
+    // Note, we must bypass focus change, so pass true as the last parameter!
+    error = GetPointerLockError(e, pointerLockedElement, true);
+  }
+  // If it is neither user input initiated, nor requested in fullscreen,
+  // it should be rejected.
+  if (!error && !mUserInputOrChromeCaller && !doc->GetFullscreenElement()) {
+    error = "PointerLockDeniedNotInputDriven";
+  }
+  if (!error && !d->SetPointerLock(e, NS_STYLE_CURSOR_NONE)) {
+    error = "PointerLockDeniedFailedToLock";
+  }
+  if (error) {
+    DispatchPointerLockError(d, error);
     return NS_OK;
   }
 
-  // Note, we must bypass focus change, so pass true as the last parameter!
-  if (!d->ShouldLockPointer(e, pointerLockedElement, true)) {
-    DispatchPointerLockError(d);
-    return NS_OK;
-  }
-
-  if (!d->SetPointerLock(e, NS_STYLE_CURSOR_NONE)) {
-    DispatchPointerLockError(d);
-    return NS_OK;
-  }
-
-  d->mCancelledPointerLockRequests = 0;
   e->SetPointerLock();
   EventStateManager::sPointerLockedElement = do_GetWeakReference(e);
   EventStateManager::sPointerLockedDoc = do_GetWeakReference(doc);
   NS_ASSERTION(EventStateManager::sPointerLockedElement &&
                EventStateManager::sPointerLockedDoc,
                "aElement and this should support weak references!");
 
   nsContentUtils::DispatchEventOnlyToChrome(
     doc, ToSupports(e), NS_LITERAL_STRING("MozDOMPointerLock:Entered"),
     /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
 
   DispatchPointerLockChange(d);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsPointerLockPermissionRequest::GetRequester(nsIContentPermissionRequester** aRequester)
-{
-  NS_ENSURE_ARG_POINTER(aRequester);
-
-  nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
-  requester.forget(aRequester);
-  return NS_OK;
-}
-
-static void
-RedispatchPendingPointerLockRequest(nsIDocument* aDocument)
-{
-  if (!gPendingPointerLockRequest) {
-    return;
-  }
-  nsCOMPtr<nsIDocument> doc =
-    do_QueryReferent(gPendingPointerLockRequest->mDocument);
-  if (doc != aDocument) {
-    return;
-  }
-  nsCOMPtr<Element> elem =
-    do_QueryReferent(gPendingPointerLockRequest->mElement);
-  if (!elem || elem->GetUncomposedDoc() != aDocument) {
-    gPendingPointerLockRequest->Handled();
-    return;
-  }
-
-  // We have a request pending on the document which may previously be
-  // blocked for fullscreen change. Create a clone and re-dispatch it
-  // to guarantee that Run() method gets called again.
-  bool userInputOrChromeCaller =
-    gPendingPointerLockRequest->mUserInputOrChromeCaller;
-  gPendingPointerLockRequest->Handled();
-  gPendingPointerLockRequest =
-    new nsPointerLockPermissionRequest(elem, userInputOrChromeCaller);
-  NS_DispatchToMainThread(gPendingPointerLockRequest);
+void
+nsDocument::RequestPointerLock(Element* aElement)
+{
+  NS_ASSERTION(aElement,
+    "Must pass non-null element to nsDocument::RequestPointerLock");
+
+  nsCOMPtr<Element> pointerLockedElement =
+    do_QueryReferent(EventStateManager::sPointerLockedElement);
+  if (aElement == pointerLockedElement) {
+    DispatchPointerLockChange(this);
+    return;
+  }
+
+  if (const char* msg = GetPointerLockError(aElement, pointerLockedElement)) {
+    DispatchPointerLockError(this, msg);
+    return;
+  }
+
+  bool userInputOrChromeCaller = EventStateManager::IsHandlingUserInput() ||
+                                 nsContentUtils::IsCallerChrome();
+  NS_DispatchToMainThread(new PointerLockRequest(aElement,
+                                                 userInputOrChromeCaller));
+}
+
+bool
+nsDocument::SetPointerLock(Element* aElement, int aCursorStyle)
+{
+  MOZ_ASSERT(!aElement || aElement->OwnerDoc() == this,
+             "We should be either unlocking pointer (aElement is nullptr), "
+             "or locking pointer to an element in this document");
+#ifdef DEBUG
+  if (!aElement) {
+    nsCOMPtr<nsIDocument> pointerLockedDoc =
+      do_QueryReferent(EventStateManager::sPointerLockedDoc);
+    MOZ_ASSERT(pointerLockedDoc == this);
+  }
+#endif
+
+  nsIPresShell* shell = GetShell();
+  if (!shell) {
+    NS_WARNING("SetPointerLock(): No PresShell");
+    return false;
+  }
+  nsPresContext* presContext = shell->GetPresContext();
+  if (!presContext) {
+    NS_WARNING("SetPointerLock(): Unable to get PresContext");
+    return false;
+  }
+
+  nsCOMPtr<nsIWidget> widget;
+  nsIFrame* rootFrame = shell->GetRootFrame();
+  if (!NS_WARN_IF(!rootFrame)) {
+    widget = rootFrame->GetNearestWidget();
+    NS_WARN_IF_FALSE(widget, "SetPointerLock(): Unable to find widget "
+                     "in shell->GetRootFrame()->GetNearestWidget();");
+    if (aElement && !widget) {
+      return false;
+    }
+  }
+
+  // Hide the cursor and set pointer lock for future mouse events
+  RefPtr<EventStateManager> esm = presContext->EventStateManager();
+  esm->SetCursor(aCursorStyle, nullptr, false,
+                 0.0f, 0.0f, widget, true);
+  esm->SetPointerLock(widget, aElement);
+
+  return true;
+}
+
+void
+nsDocument::UnlockPointer(nsIDocument* aDoc)
+{
+  if (!EventStateManager::sIsPointerLocked) {
+    return;
+  }
+
+  nsCOMPtr<nsIDocument> pointerLockedDoc =
+    do_QueryReferent(EventStateManager::sPointerLockedDoc);
+  if (!pointerLockedDoc || (aDoc && aDoc != pointerLockedDoc)) {
+    return;
+  }
+  nsDocument* doc = static_cast<nsDocument*>(pointerLockedDoc.get());
+  if (!doc->SetPointerLock(nullptr, NS_STYLE_CURSOR_AUTO)) {
+    return;
+  }
+
+  nsCOMPtr<Element> pointerLockedElement =
+    do_QueryReferent(EventStateManager::sPointerLockedElement);
+  if (pointerLockedElement) {
+    pointerLockedElement->ClearPointerLock();
+  }
+
+  EventStateManager::sPointerLockedElement = nullptr;
+  EventStateManager::sPointerLockedDoc = nullptr;
+
+  nsContentUtils::DispatchEventOnlyToChrome(
+    doc, ToSupports(pointerLockedElement),
+    NS_LITERAL_STRING("MozDOMPointerLock:Exited"),
+    /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
+
+  DispatchPointerLockChange(pointerLockedDoc);
+}
+
+void
+nsIDocument::UnlockPointer(nsIDocument* aDoc)
+{
+  nsDocument::UnlockPointer(aDoc);
+}
+
+NS_IMETHODIMP
+nsDocument::MozExitPointerLock()
+{
+  nsIDocument::MozExitPointerLock();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocument::GetMozPointerLockElement(nsIDOMElement** aPointerLockedElement)
+{
+  Element* el = nsIDocument::GetMozPointerLockElement();
+  nsCOMPtr<nsIDOMElement> retval = do_QueryInterface(el);
+  retval.forget(aPointerLockedElement);
+  return NS_OK;
+}
+
+Element*
+nsIDocument::GetMozPointerLockElement()
+{
+  nsCOMPtr<Element> pointerLockedElement =
+    do_QueryReferent(EventStateManager::sPointerLockedElement);
+  if (!pointerLockedElement) {
+    return nullptr;
+  }
+
+  // Make sure pointer locked element is in the same document.
+  nsCOMPtr<nsIDocument> pointerLockedDoc =
+    do_QueryReferent(EventStateManager::sPointerLockedDoc);
+  if (pointerLockedDoc != this) {
+    return nullptr;
+  }
+
+  return pointerLockedElement;
 }
 
 nsresult
 nsDocument::Observe(nsISupports *aSubject,
                     const char *aTopic,
                     const char16_t *aData)
 {
   if (strcmp("app-theme-changed", aTopic) == 0) {
@@ -12608,227 +12634,18 @@ nsDocument::OnAppThemeChanged()
     }
     bool willNotify;
     bool isAlternate;
     link->UpdateStyleSheet(nullptr, &willNotify, &isAlternate, true);
   }
 }
 
 void
-nsDocument::RequestPointerLock(Element* aElement)
-{
-  NS_ASSERTION(aElement,
-    "Must pass non-null element to nsDocument::RequestPointerLock");
-
-  nsCOMPtr<Element> pointerLockedElement =
-    do_QueryReferent(EventStateManager::sPointerLockedElement);
-  if (aElement == pointerLockedElement) {
-    DispatchPointerLockChange(this);
-    return;
-  }
-
-  if (!ShouldLockPointer(aElement, pointerLockedElement)) {
-    DispatchPointerLockError(this);
-    return;
-  }
-
-  bool userInputOrChromeCaller = EventStateManager::IsHandlingUserInput() ||
-                                 nsContentUtils::IsCallerChrome();
-
-  gPendingPointerLockRequest =
-    new nsPointerLockPermissionRequest(aElement, userInputOrChromeCaller);
-  nsCOMPtr<nsIRunnable> r = gPendingPointerLockRequest.get();
-  NS_DispatchToMainThread(r);
-}
-
-bool
-nsDocument::ShouldLockPointer(Element* aElement, Element* aCurrentLock,
-                              bool aNoFocusCheck)
-{
-  // Check if pointer lock pref is enabled
-  if (!Preferences::GetBool("full-screen-api.pointer-lock.enabled")) {
-    NS_WARNING("ShouldLockPointer(): Pointer Lock pref not enabled");
-    return false;
-  }
-
-  if (aCurrentLock && aCurrentLock->OwnerDoc() != aElement->OwnerDoc()) {
-    NS_WARNING("ShouldLockPointer(): Existing pointer lock element in a different document");
-    return false;
-  }
-
-  if (!aElement->IsInUncomposedDoc()) {
-    NS_WARNING("ShouldLockPointer(): Element without Document");
-    return false;
-  }
-
-  if (mSandboxFlags & SANDBOXED_POINTER_LOCK) {
-    NS_WARNING("ShouldLockPointer(): Document is sandboxed and doesn't allow pointer-lock");
-    return false;
-  }
-
-  // Check if the element is in a document with a docshell.
-  nsCOMPtr<nsIDocument> ownerDoc = aElement->OwnerDoc();
-  if (!ownerDoc->GetContainer()) {
-    return false;
-  }
-  nsCOMPtr<nsPIDOMWindowOuter> ownerWindow = ownerDoc->GetWindow();
-  if (!ownerWindow) {
-    return false;
-  }
-  nsCOMPtr<nsPIDOMWindowInner> ownerInnerWindow = ownerDoc->GetInnerWindow();
-  if (!ownerInnerWindow) {
-    return false;
-  }
-  if (ownerWindow->GetCurrentInnerWindow() != ownerInnerWindow) {
-    return false;
-  }
-
-  nsCOMPtr<nsPIDOMWindowOuter> top = ownerWindow->GetScriptableTop();
-  if (!top || !top->GetExtantDoc() || top->GetExtantDoc()->Hidden()) {
-    NS_WARNING("ShouldLockPointer(): Top document isn't visible.");
-    return false;
-  }
-
-  if (!aNoFocusCheck) {
-    mozilla::ErrorResult rv;
-    if (!top->GetExtantDoc()->HasFocus(rv)) {
-      NS_WARNING("ShouldLockPointer(): Top document isn't focused.");
-      return false;
-    }
-  }
-
-  return true;
-}
-
-bool
-nsDocument::SetPointerLock(Element* aElement, int aCursorStyle)
-{
-  MOZ_ASSERT(!aElement || aElement->OwnerDoc() == this,
-             "We should be either unlocking pointer (aElement is nullptr), "
-             "or locking pointer to an element in this document");
-#ifdef DEBUG
-  if (!aElement) {
-    nsCOMPtr<nsIDocument> pointerLockedDoc =
-      do_QueryReferent(EventStateManager::sPointerLockedDoc);
-    MOZ_ASSERT(pointerLockedDoc == this);
-  }
-#endif
-
-  nsIPresShell* shell = GetShell();
-  if (!shell) {
-    NS_WARNING("SetPointerLock(): No PresShell");
-    return false;
-  }
-  nsPresContext* presContext = shell->GetPresContext();
-  if (!presContext) {
-    NS_WARNING("SetPointerLock(): Unable to get PresContext");
-    return false;
-  }
-
-  nsCOMPtr<nsIWidget> widget;
-  nsIFrame* rootFrame = shell->GetRootFrame();
-  if (!NS_WARN_IF(!rootFrame)) {
-    widget = rootFrame->GetNearestWidget();
-    NS_WARN_IF_FALSE(widget, "SetPointerLock(): Unable to find widget "
-                     "in shell->GetRootFrame()->GetNearestWidget();");
-    if (aElement && !widget) {
-      return false;
-    }
-  }
-
-  // Hide the cursor and set pointer lock for future mouse events
-  RefPtr<EventStateManager> esm = presContext->EventStateManager();
-  esm->SetCursor(aCursorStyle, nullptr, false,
-                 0.0f, 0.0f, widget, true);
-  esm->SetPointerLock(widget, aElement);
-
-  return true;
-}
-
-void
-nsDocument::UnlockPointer(nsIDocument* aDoc)
-{
-  if (!EventStateManager::sIsPointerLocked) {
-    return;
-  }
-
-  nsCOMPtr<nsIDocument> pointerLockedDoc =
-    do_QueryReferent(EventStateManager::sPointerLockedDoc);
-  if (!pointerLockedDoc || (aDoc && aDoc != pointerLockedDoc)) {
-    return;
-  }
-  nsDocument* doc = static_cast<nsDocument*>(pointerLockedDoc.get());
-  if (!doc->SetPointerLock(nullptr, NS_STYLE_CURSOR_AUTO)) {
-    return;
-  }
-
-  nsCOMPtr<Element> pointerLockedElement =
-    do_QueryReferent(EventStateManager::sPointerLockedElement);
-  if (pointerLockedElement) {
-    pointerLockedElement->ClearPointerLock();
-  }
-
-  EventStateManager::sPointerLockedElement = nullptr;
-  EventStateManager::sPointerLockedDoc = nullptr;
-  static_cast<nsDocument*>(pointerLockedDoc.get())->mAllowRelocking = !!aDoc;
-  gPendingPointerLockRequest = nullptr;
-
-  nsContentUtils::DispatchEventOnlyToChrome(
-    doc, ToSupports(pointerLockedElement),
-    NS_LITERAL_STRING("MozDOMPointerLock:Exited"),
-    /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
-
-  DispatchPointerLockChange(pointerLockedDoc);
-}
-
-void
-nsIDocument::UnlockPointer(nsIDocument* aDoc)
-{
-  nsDocument::UnlockPointer(aDoc);
-}
-
-NS_IMETHODIMP
-nsDocument::MozExitPointerLock()
-{
-  nsIDocument::MozExitPointerLock();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDocument::GetMozPointerLockElement(nsIDOMElement** aPointerLockedElement)
-{
-  Element* el = nsIDocument::GetMozPointerLockElement();
-  nsCOMPtr<nsIDOMElement> retval = do_QueryInterface(el);
-  retval.forget(aPointerLockedElement);
-  return NS_OK;
-}
-
-Element*
-nsIDocument::GetMozPointerLockElement()
-{
-  nsCOMPtr<Element> pointerLockedElement =
-    do_QueryReferent(EventStateManager::sPointerLockedElement);
-  if (!pointerLockedElement) {
-    return nullptr;
-  }
-
-  // Make sure pointer locked element is in the same document.
-  nsCOMPtr<nsIDocument> pointerLockedDoc =
-    do_QueryReferent(EventStateManager::sPointerLockedDoc);
-  if (pointerLockedDoc != this) {
-    return nullptr;
-  }
-
-  return pointerLockedElement;
-}
-
-void
 nsDocument::XPCOMShutdown()
 {
-  gPendingPointerLockRequest = nullptr;
   sProcessingStack.reset();
 }
 
 void
 nsDocument::UpdateVisibilityState()
 {
   dom::VisibilityState oldState = mVisibilityState;
   mVisibilityState = GetVisibilityState();
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -1263,18 +1263,16 @@ public:
   // Returns the top element from the full-screen stack.
   Element* FullScreenStackTop();
 
   // DOM-exposed fullscreen API
   bool FullscreenEnabled() override;
   Element* GetFullscreenElement() override;
 
   void RequestPointerLock(Element* aElement) override;
-  bool ShouldLockPointer(Element* aElement, Element* aCurrentLock,
-                         bool aNoFocusCheck = false);
   bool SetPointerLock(Element* aElement, int aCursorStyle);
   static void UnlockPointer(nsIDocument* aDoc = nullptr);
 
   void SetCurrentOrientation(mozilla::dom::OrientationType aType,
                              uint16_t aAngle) override;
   uint16_t CurrentOrientationAngle() const override;
   mozilla::dom::OrientationType CurrentOrientationType() const override;
   void SetOrientationPendingPromise(mozilla::dom::Promise* aPromise) override;
@@ -1646,21 +1644,17 @@ public:
   // Whether we're currently under a FlushPendingNotifications call to
   // our presshell.  This is used to handle flush reentry correctly.
   bool mInFlush:1;
 
   // Parser aborted. True if the parser of this document was forcibly
   // terminated instead of letting it finish at its own pace.
   bool mParserAborted:1;
 
-  friend class nsPointerLockPermissionRequest;
   friend class nsCallRequestFullScreen;
-  // When set, trying to lock the pointer doesn't require permission from the
-  // user.
-  bool mAllowRelocking:1;
 
   // ScreenOrientation "pending promise" as described by
   // http://www.w3.org/TR/screen-orientation/
   RefPtr<mozilla::dom::Promise> mOrientationPendingPromise;
 
   uint16_t mCurrentOrientationAngle;
   mozilla::dom::OrientationType mCurrentOrientationType;
 
@@ -1669,20 +1663,16 @@ public:
   // OnPageShow notifications in a row without an OnPageHide in between, if
   // we're getting document.open()/close() called on us.
   bool mObservingAppThemeChanged:1;
 
   // Keeps track of whether we have a pending
   // 'style-sheet-applicable-state-changed' notification.
   bool mSSApplicableStateNotificationPending:1;
 
-  // The number of pointer lock requests which are cancelled by the user.
-  // The value is saturated to kPointerLockRequestLimit+1 = 3.
-  uint8_t mCancelledPointerLockRequests:2;
-
   // Whether we have reported use counters for this document with Telemetry yet.
   // Normally this is only done at document destruction time, but for image
   // documents (SVG documents) that are not guaranteed to be destroyed, we
   // report use counters when the image cache no longer has any imgRequestProxys
   // pointing to them.  We track whether we ever reported use counters so
   // that we only report them once for the document.
   bool mReportedUseCounters:1;
 
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -127,16 +127,23 @@ GetObjectLog()
 static bool
 IsJavaMIME(const nsACString & aMIMEType)
 {
   return
     nsPluginHost::GetSpecialType(aMIMEType) == nsPluginHost::eSpecialType_Java;
 }
 
 static bool
+IsFlashMIME(const nsACString & aMIMEType)
+{
+  return
+    nsPluginHost::GetSpecialType(aMIMEType) == nsPluginHost::eSpecialType_Flash;
+}
+
+static bool
 InActiveDocument(nsIContent *aContent)
 {
   if (!aContent->IsInComposedDoc()) {
     return false;
   }
   nsIDocument *doc = aContent->OwnerDoc();
   return (doc && doc->IsActive());
 }
@@ -460,21 +467,20 @@ private:
   nsObjectLoadingContent* mContent;
 };
 
 ///
 /// Helper functions
 ///
 
 static bool
-IsSuccessfulRequest(nsIRequest* aRequest)
+IsSuccessfulRequest(nsIRequest* aRequest, nsresult* aStatus)
 {
-  nsresult status;
-  nsresult rv = aRequest->GetStatus(&status);
-  if (NS_FAILED(rv) || NS_FAILED(status)) {
+  nsresult rv = aRequest->GetStatus(aStatus);
+  if (NS_FAILED(rv) || NS_FAILED(*aStatus)) {
     return false;
   }
 
   // This may still be an error page or somesuch
   nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(aRequest));
   if (httpChan) {
     bool success;
     rv = httpChan->GetRequestSucceeded(&success);
@@ -714,16 +720,17 @@ nsObjectLoadingContent::nsObjectLoadingC
   : mType(eType_Loading)
   , mFallbackType(eFallbackAlternate)
   , mRunID(0)
   , mHasRunID(false)
   , mChannelLoaded(false)
   , mInstantiating(false)
   , mNetworkCreated(true)
   , mActivated(false)
+  , mContentBlockingDisabled(false)
   , mIsStopping(false)
   , mIsLoading(false)
   , mScriptRequested(false)
   , mRewrittenYoutubeEmbed(false) {}
 
 nsObjectLoadingContent::~nsObjectLoadingContent()
 {
   // Should have been unbound from the tree at this point, and
@@ -1118,23 +1125,41 @@ nsObjectLoadingContent::OnStartRequest(n
   NS_ASSERTION(!mChannelLoaded, "mChannelLoaded set already?");
   NS_ASSERTION(!mFinalListener, "mFinalListener exists already?");
 
   mChannelLoaded = true;
 
   nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
   NS_ASSERTION(chan, "Why is our request not a channel?");
 
-  nsCOMPtr<nsIURI> uri;
-
-  if (IsSuccessfulRequest(aRequest)) {
-    chan->GetURI(getter_AddRefs(uri));
+  nsresult status;
+  bool success = IsSuccessfulRequest(aRequest, &status);
+
+  if (status == NS_ERROR_BLOCKED_URI) {
+    nsCOMPtr<nsIConsoleService> console(
+      do_GetService("@mozilla.org/consoleservice;1"));
+    if (console) {
+      nsCOMPtr<nsIURI> uri;
+      chan->GetURI(getter_AddRefs(uri));
+      nsAutoCString spec;
+      uri->GetSpec(spec);
+      nsString message = NS_LITERAL_STRING("Blocking ") +
+        NS_ConvertASCIItoUTF16(spec.get()) +
+        NS_LITERAL_STRING(" since it was found on an internal Firefox blocklist.");
+      console->LogStringMessage(message.get());
+    }
+    Telemetry::Accumulate(Telemetry::PLUGIN_BLOCKED_FOR_STABILITY, 1);
+    return NS_ERROR_FAILURE;
+  } else if (status == NS_ERROR_TRACKING_URI) {
+    return NS_ERROR_FAILURE;
+  } else {
+    mContentBlockingDisabled = true;
   }
 
-  if (!uri) {
+  if (!success) {
     LOG(("OBJLC [%p]: OnStartRequest: Request failed\n", this));
     // If the request fails, we still call LoadObject() to handle fallback
     // content and notifying of failure. (mChannelLoaded && !mChannel) indicates
     // the bad state.
     mChannel = nullptr;
     LoadObject(true, false);
     return NS_ERROR_FAILURE;
   }
@@ -2275,42 +2300,16 @@ nsObjectLoadingContent::LoadObject(bool 
     }
     // If we're loading a type now, check ProcessPolicy. Note that we may check
     // both now in the case of plugins whose type is determined before opening a
     // channel.
     if (allowLoad && mType != eType_Loading) {
       allowLoad = CheckProcessPolicy(&contentPolicy);
     }
 
-    // This needs to be reverted once the plugin stability experiment is over (see bug #1268120).
-    if (allowLoad && Preferences::GetBool(kPrefBlockURIs)) {
-      RefPtr<nsChannelClassifier> channelClassifier = new nsChannelClassifier();
-      nsCOMPtr<nsIURIClassifier> classifier = do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID);
-      if (classifier) {
-        nsAutoCString tables;
-        Preferences::GetCString("urlclassifier.blockedTable", &tables);
-        nsAutoCString results;
-        rv = classifier->ClassifyLocalWithTables(mURI, tables, results);
-        if (NS_SUCCEEDED(rv) && !results.IsEmpty()) {
-          nsAutoCString uri;
-          mURI->GetSpec(uri);
-          nsCOMPtr<nsIConsoleService> console(
-            do_GetService("@mozilla.org/consoleservice;1"));
-          if (console) {
-            nsString message = NS_LITERAL_STRING("Blocking ") +
-              NS_ConvertASCIItoUTF16(uri) +
-              NS_LITERAL_STRING(" since it was found on an internal Firefox blocklist.");
-            console->LogStringMessage(message.get());
-          }
-          Telemetry::Accumulate(Telemetry::PLUGIN_BLOCKED_FOR_STABILITY, 1);
-          allowLoad = false;
-        }
-      }
-    }
-
     // Content policy implementations can mutate the DOM, check for re-entry
     if (!mIsLoading) {
       LOG(("OBJLC [%p]: We re-entered in content policy, leaving original load",
            this));
       return NS_OK;
     }
 
     // Load denied, switch to fallback and set disabled/suppressed if applicable
@@ -2348,16 +2347,23 @@ nsObjectLoadingContent::LoadObject(bool 
         break;
       }
 
       nestedURI->GetInnerURI(getter_AddRefs(tempURI));
       nestedURI = do_QueryInterface(tempURI);
     }
   }
 
+  // Items resolved as Image/Document are no candidates for content blocking,
+  // as well as invalid plugins (they will not have the mContentType set).
+  if ((mType == eType_Null || mType == eType_Plugin) && ShouldBlockContent()) {
+    LOG(("OBJLC [%p]: Enable content blocking", this));
+    mType = eType_Loading;
+  }
+
   // If we're a plugin but shouldn't start yet, load fallback with
   // reason click-to-play instead. Items resolved as Image/Document
   // will not be checked for previews, as well as invalid plugins
   // (they will not have the mContentType set).
   FallbackType clickToPlayReason;
   if (!mActivated && (mType == eType_Null || mType == eType_Plugin) &&
       !ShouldPlay(clickToPlayReason, false)) {
     LOG(("OBJLC [%p]: Marking plugin as click-to-play", this));
@@ -3358,16 +3364,30 @@ nsObjectLoadingContent::GetRunID(uint32_
   return NS_OK;
 }
 
 static bool sPrefsInitialized;
 static uint32_t sSessionTimeoutMinutes;
 static uint32_t sPersistentTimeoutDays;
 
 bool
+nsObjectLoadingContent::ShouldBlockContent()
+{
+  if (mContentBlockingDisabled)
+    return false;
+
+  if (!IsFlashMIME(mContentType) || !Preferences::GetBool(kPrefBlockURIs)) {
+    mContentBlockingDisabled = true;
+    return false;
+  }
+
+  return true;
+}
+
+bool
 nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentType)
 {
   nsresult rv;
 
   if (!sPrefsInitialized) {
     Preferences::AddUintVarCache(&sSessionTimeoutMinutes,
                                  "plugin.sessionPermissionNow.intervalInMinutes", 60);
     Preferences::AddUintVarCache(&sPersistentTimeoutDays,
--- a/dom/base/nsObjectLoadingContent.h
+++ b/dom/base/nsObjectLoadingContent.h
@@ -441,16 +441,21 @@ class nsObjectLoadingContent : public ns
     nsresult OpenChannel();
 
     /**
      * Closes and releases references to mChannel and, if opened, mFinalListener
      */
     nsresult CloseChannel();
 
     /**
+     * If this object should be tested against blocking list.
+     */
+    bool ShouldBlockContent();
+
+    /**
      * If this object is allowed to play plugin content, or if it would display
      * click-to-play instead.
      * NOTE that this does not actually check if the object is a loadable plugin
      * NOTE This ignores the current activated state. The caller should check this if appropriate.
      */
     bool ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentType);
 
     /*
@@ -648,16 +653,19 @@ class nsObjectLoadingContent : public ns
     // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
     // it may lose the flag.
     bool                        mNetworkCreated : 1;
 
     // Used to keep track of whether or not a plugin has been explicitly
     // activated by PlayPlugin(). (see ShouldPlay())
     bool                        mActivated : 1;
 
+    // Whether content blocking is enabled or not for this object.
+    bool                        mContentBlockingDisabled : 1;
+
     // Protects DoStopPlugin from reentry (bug 724781).
     bool                        mIsStopping : 1;
 
     // Protects LoadObject from re-entry
     bool                        mIsLoading : 1;
 
     // For plugin stand-in types (click-to-play) tracks
     // whether content js has tried to access the plugin script object.
--- a/dom/canvas/TexUnpackBlob.cpp
+++ b/dom/canvas/TexUnpackBlob.cpp
@@ -14,284 +14,326 @@
 #include "nsLayoutUtils.h"
 #include "WebGLContext.h"
 #include "WebGLTexelConversions.h"
 #include "WebGLTexture.h"
 
 namespace mozilla {
 namespace webgl {
 
-TexUnpackBlob::TexUnpackBlob(const WebGLContext* webgl, uint32_t alignment,
-                             uint32_t rowLength, uint32_t imageHeight, uint32_t width,
-                             uint32_t height, uint32_t depth, bool hasData)
-    : mAlignment(alignment)
-    , mRowLength(rowLength)
-    , mImageHeight(imageHeight)
-
-    , mSkipPixels(webgl->mPixelStore_UnpackSkipPixels)
-    , mSkipRows(webgl->mPixelStore_UnpackSkipRows)
-    , mSkipImages(webgl->mPixelStore_UnpackSkipImages)
-
-    , mWidth(width)
-    , mHeight(height)
-    , mDepth(depth)
-
-    , mHasData(hasData)
-{ }
-
-static GLenum
-DoTexOrSubImage(bool isSubImage, gl::GLContext* gl, TexImageTarget target, GLint level,
-                const DriverUnpackInfo* dui, GLint xOffset, GLint yOffset, GLint zOffset,
-                GLsizei width, GLsizei height, GLsizei depth, const void* data)
-{
-    if (isSubImage) {
-        return DoTexSubImage(gl, target, level, xOffset, yOffset, zOffset, width, height,
-                             depth, dui->ToPacking(), data);
-    } else {
-        return DoTexImage(gl, target, level, dui, width, height, depth, data);
-    }
-}
-
-/*static*/ void
-TexUnpackBlob::OriginsForDOM(WebGLContext* webgl, gl::OriginPos* const out_src,
-                             gl::OriginPos* const out_dst)
-{
-    // Our surfaces are TopLeft.
-    *out_src = gl::OriginPos::TopLeft;
-
-    // WebGL specs the default as passing DOM elements top-left first.
-    // Thus y-flip would give us bottom-left.
-    *out_dst = webgl->mPixelStore_FlipY ? gl::OriginPos::BottomLeft
-                                        : gl::OriginPos::TopLeft;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// TexUnpackBytes
-
-static uint32_t
-FallbackOnZero(uint32_t val, uint32_t fallback)
-{
-    return (val ? val : fallback);
-}
-
-TexUnpackBytes::TexUnpackBytes(const WebGLContext* webgl, uint32_t width, uint32_t height,
-                               uint32_t depth, const void* bytes)
-    : TexUnpackBlob(webgl, webgl->mPixelStore_UnpackAlignment,
-                    FallbackOnZero(webgl->mPixelStore_UnpackRowLength, width),
-                    FallbackOnZero(webgl->mPixelStore_UnpackImageHeight, height),
-                    width, height, depth, bool(bytes))
-    , mBytes(bytes)
-{ }
-
 static bool
 UnpackFormatHasAlpha(GLenum unpackFormat)
 {
     switch (unpackFormat) {
     case LOCAL_GL_ALPHA:
     case LOCAL_GL_LUMINANCE_ALPHA:
     case LOCAL_GL_RGBA:
         return true;
 
     default:
         return false;
     }
 }
 
 static WebGLTexelFormat
-FormatFromPacking(const webgl::PackingInfo& pi)
+FormatForPackingInfo(const PackingInfo& pi)
 {
     switch (pi.type) {
+    case LOCAL_GL_UNSIGNED_BYTE:
+        switch (pi.format) {
+        case LOCAL_GL_RED:
+        case LOCAL_GL_LUMINANCE:
+        case LOCAL_GL_RED_INTEGER:
+            return WebGLTexelFormat::R8;
+
+        case LOCAL_GL_ALPHA:
+            return WebGLTexelFormat::A8;
+
+        case LOCAL_GL_LUMINANCE_ALPHA:
+            return WebGLTexelFormat::RA8;
+
+        case LOCAL_GL_RGB:
+        case LOCAL_GL_RGB_INTEGER:
+            return WebGLTexelFormat::RGB8;
+
+        case LOCAL_GL_RGBA:
+        case LOCAL_GL_RGBA_INTEGER:
+            return WebGLTexelFormat::RGBA8;
+
+        case LOCAL_GL_RG:
+        case LOCAL_GL_RG_INTEGER:
+            return WebGLTexelFormat::RG8;
+
+        default:
+            break;
+        }
+        break;
+
     case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
-        return WebGLTexelFormat::RGB565;
+        if (pi.format == LOCAL_GL_RGB)
+            return WebGLTexelFormat::RGB565;
+        break;
 
     case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
-        return WebGLTexelFormat::RGBA5551;
+        if (pi.format == LOCAL_GL_RGBA)
+            return WebGLTexelFormat::RGBA5551;
+        break;
 
     case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
-        return WebGLTexelFormat::RGBA4444;
-
-    case LOCAL_GL_UNSIGNED_BYTE:
-        switch (pi.format) {
-        case LOCAL_GL_LUMINANCE:        return WebGLTexelFormat::R8;
-        case LOCAL_GL_ALPHA:            return WebGLTexelFormat::A8;
-        case LOCAL_GL_LUMINANCE_ALPHA:  return WebGLTexelFormat::RA8;
-        case LOCAL_GL_RGB:              return WebGLTexelFormat::RGB8;
-        case LOCAL_GL_SRGB:             return WebGLTexelFormat::RGB8;
-        case LOCAL_GL_RGBA:             return WebGLTexelFormat::RGBA8;
-        case LOCAL_GL_SRGB_ALPHA:       return WebGLTexelFormat::RGBA8;
-        }
+        if (pi.format == LOCAL_GL_RGBA)
+            return WebGLTexelFormat::RGBA4444;
+        break;
 
     case LOCAL_GL_HALF_FLOAT:
     case LOCAL_GL_HALF_FLOAT_OES:
         switch (pi.format) {
-        case LOCAL_GL_LUMINANCE:        return WebGLTexelFormat::R16F;
-        case LOCAL_GL_ALPHA:            return WebGLTexelFormat::A16F;
-        case LOCAL_GL_LUMINANCE_ALPHA:  return WebGLTexelFormat::RA16F;
-        case LOCAL_GL_RGB:              return WebGLTexelFormat::RGB16F;
-        case LOCAL_GL_RGBA:             return WebGLTexelFormat::RGBA16F;
+        case LOCAL_GL_RED:
+        case LOCAL_GL_LUMINANCE:
+            return WebGLTexelFormat::R16F;
+
+        case LOCAL_GL_ALPHA:           return WebGLTexelFormat::A16F;
+        case LOCAL_GL_LUMINANCE_ALPHA: return WebGLTexelFormat::RA16F;
+        case LOCAL_GL_RG:              return WebGLTexelFormat::RG16F;
+        case LOCAL_GL_RGB:             return WebGLTexelFormat::RGB16F;
+        case LOCAL_GL_RGBA:            return WebGLTexelFormat::RGBA16F;
+
+        default:
+            break;
         }
+        break;
 
     case LOCAL_GL_FLOAT:
         switch (pi.format) {
-        case LOCAL_GL_LUMINANCE:        return WebGLTexelFormat::R32F;
-        case LOCAL_GL_ALPHA:            return WebGLTexelFormat::A32F;
-        case LOCAL_GL_LUMINANCE_ALPHA:  return WebGLTexelFormat::RA32F;
-        case LOCAL_GL_RGB:              return WebGLTexelFormat::RGB32F;
-        case LOCAL_GL_RGBA:             return WebGLTexelFormat::RGBA32F;
+        case LOCAL_GL_RED:
+        case LOCAL_GL_LUMINANCE:
+            return WebGLTexelFormat::R32F;
+
+        case LOCAL_GL_ALPHA:           return WebGLTexelFormat::A32F;
+        case LOCAL_GL_LUMINANCE_ALPHA: return WebGLTexelFormat::RA32F;
+        case LOCAL_GL_RG:              return WebGLTexelFormat::RG32F;
+        case LOCAL_GL_RGB:             return WebGLTexelFormat::RGB32F;
+        case LOCAL_GL_RGBA:            return WebGLTexelFormat::RGBA32F;
+
+        default:
+            break;
         }
+        break;
+
+    case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
+        if (pi.format == LOCAL_GL_RGB)
+            return WebGLTexelFormat::RGB11F11F10F;
+        break;
+
+    default:
+        break;
     }
 
     return WebGLTexelFormat::FormatNotSupportingAnyConversion;
 }
 
+////////////////////
+
+static uint32_t
+FallbackOnZero(uint32_t val, uint32_t fallback)
+{
+    return (val ? val : fallback);
+}
+
+TexUnpackBlob::TexUnpackBlob(const WebGLContext* webgl, TexImageTarget target,
+                             uint32_t rowLength, uint32_t width, uint32_t height,
+                             uint32_t depth, bool isSrcPremult)
+    : mAlignment(webgl->mPixelStore_UnpackAlignment)
+    , mRowLength(rowLength)
+    , mImageHeight(FallbackOnZero(webgl->mPixelStore_UnpackImageHeight, height))
+
+    , mSkipPixels(webgl->mPixelStore_UnpackSkipPixels)
+    , mSkipRows(webgl->mPixelStore_UnpackSkipRows)
+    , mSkipImages(IsTarget3D(target) ? webgl->mPixelStore_UnpackSkipImages : 0)
+
+    , mWidth(width)
+    , mHeight(height)
+    , mDepth(depth)
+
+    , mIsSrcPremult(isSrcPremult)
+{
+    MOZ_ASSERT_IF(!IsTarget3D(target), mDepth == 1);
+}
+
+bool
+TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
+                               const void* srcBytes, uint32_t srcStride, uint8_t srcBPP,
+                               WebGLTexelFormat srcFormat,
+                               const webgl::DriverUnpackInfo* dstDUI,
+                               const void** const out_bytes,
+                               UniqueBuffer* const out_anchoredBuffer) const
+{
+    *out_bytes = srcBytes;
+
+    if (!HasData() || !mWidth || !mHeight || !mDepth)
+        return true;
+
+    //////
+
+    const auto totalSkipRows = mSkipRows + CheckedUint32(mSkipImages) * mImageHeight;
+    const auto offset = mSkipPixels * CheckedUint32(srcBPP) + totalSkipRows * srcStride;
+    if (!offset.isValid()) {
+        webgl->ErrorOutOfMemory("%s: Invalid offset calculation during conversion.",
+                                funcName);
+        return false;
+    }
+    const uint32_t skipBytes = offset.value();
+
+    auto const srcBegin = (const uint8_t*)srcBytes + skipBytes;
+
+    //////
+
+    const auto srcOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft
+                                                     : gl::OriginPos::BottomLeft);
+    const auto dstOrigin = gl::OriginPos::BottomLeft;
+    const bool isDstPremult = webgl->mPixelStore_PremultiplyAlpha;
+
+    const auto pi = dstDUI->ToPacking();
+    const auto dstFormat = FormatForPackingInfo(pi);
+
+    const auto dstBPP = webgl::BytesPerPixel(pi);
+    const auto dstWidthBytes = CheckedUint32(dstBPP) * mWidth;
+    const auto dstRowLengthBytes = CheckedUint32(dstBPP) * mRowLength;
+
+    const auto dstAlignment = mAlignment;
+    const auto dstStride = RoundUpToMultipleOf(dstRowLengthBytes, dstAlignment);
+
+    //////
+
+    const auto dstTotalRows = CheckedUint32(mDepth - 1) * mImageHeight + mHeight;
+
+    const auto dstSize = skipBytes + (dstTotalRows - 1) * dstStride + dstWidthBytes;
+    if (!dstSize.isValid()) {
+        webgl->ErrorOutOfMemory("%s: Invalid dstSize calculation during conversion.",
+                                funcName);
+        return false;
+    }
+
+    //////
+
+    bool needsConvert = (srcOrigin != dstOrigin ||
+                         srcFormat != dstFormat ||
+                         srcStride != dstStride.value());
+
+    if (UnpackFormatHasAlpha(dstDUI->unpackFormat)) {
+        needsConvert |= (mIsSrcPremult != isDstPremult);
+    }
+
+    if (!needsConvert)
+        return true;
+
+    ////////////
+    // Ugh, ok, fine!
+
+    webgl->GenerateWarning("%s: Incurred CPU data conversion, which is slow.",
+                           funcName);
+
+    //////
+
+    *out_anchoredBuffer = calloc(1, dstSize.value());
+    if (!out_anchoredBuffer->get()) {
+        webgl->ErrorOutOfMemory("%s: Unable to allocate buffer during conversion.",
+                                funcName);
+        return false;
+    }
+    const auto dstBegin = (uint8_t*)out_anchoredBuffer->get() + skipBytes;
+
+    //////
+
+    // And go!:
+    bool wasTrivial;
+    if (!ConvertImage(mWidth, dstTotalRows.value(),
+                      srcBegin, srcStride, srcOrigin, srcFormat, mIsSrcPremult,
+                      dstBegin, dstStride.value(), dstOrigin, dstFormat, isDstPremult,
+                      &wasTrivial))
+    {
+        webgl->ErrorImplementationBug("%s: ConvertImage failed.", funcName);
+        return false;
+    }
+
+    if (!wasTrivial) {
+        webgl->GenerateWarning("%s: Chosen format/type incurred an expensive reformat:"
+                               " 0x%04x/0x%04x",
+                               funcName, dstDUI->unpackFormat, dstDUI->unpackType);
+    }
+
+    *out_bytes = out_anchoredBuffer->get();
+    return true;
+}
+
+static GLenum
+DoTexOrSubImage(bool isSubImage, gl::GLContext* gl, TexImageTarget target, GLint level,
+                const DriverUnpackInfo* dui, GLint xOffset, GLint yOffset, GLint zOffset,
+                GLsizei width, GLsizei height, GLsizei depth, const void* data)
+{
+    if (isSubImage) {
+        return DoTexSubImage(gl, target, level, xOffset, yOffset, zOffset, width, height,
+                             depth, dui->ToPacking(), data);
+    } else {
+        return DoTexImage(gl, target, level, dui, width, height, depth, data);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// TexUnpackBytes
+
+TexUnpackBytes::TexUnpackBytes(const WebGLContext* webgl, TexImageTarget target,
+                               uint32_t width, uint32_t height, uint32_t depth,
+                               const void* bytes)
+    : TexUnpackBlob(webgl, target,
+                    FallbackOnZero(webgl->mPixelStore_UnpackRowLength, width), width,
+                    height, depth, false)
+    , mBytes(bytes)
+{ }
+
 bool
 TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
                               WebGLTexture* tex, TexImageTarget target, GLint level,
                               const webgl::DriverUnpackInfo* dui, GLint xOffset,
                               GLint yOffset, GLint zOffset, GLenum* const out_error) const
 {
     WebGLContext* webgl = tex->mContext;
-    gl::GLContext* gl = webgl->gl;
 
-    const void* uploadBytes = mBytes;
-    UniqueBuffer tempBuffer;
-
-    do {
-        if (!mBytes || !mWidth || !mHeight || !mDepth)
-            break;
-
-        if (webgl->IsWebGL2())
-            break;
-        MOZ_ASSERT(mDepth == 1);
-
-        const webgl::PackingInfo pi = { dui->unpackFormat, dui->unpackType };
-
-        const bool needsYFlip = webgl->mPixelStore_FlipY;
-
-        bool needsAlphaPremult = webgl->mPixelStore_PremultiplyAlpha;
-        if (!UnpackFormatHasAlpha(pi.format))
-            needsAlphaPremult = false;
-
-        if (!needsYFlip && !needsAlphaPremult)
-            break;
-
-        ////////////
-        // This is literally the worst.
+    const auto pi = dui->ToPacking();
+    const auto format = FormatForPackingInfo(pi);
 
-        if (mSkipPixels || mSkipRows || mSkipImages ||
-            mRowLength != mWidth ||
-            mImageHeight != mHeight)
-        {
-            webgl->ErrorInvalidOperation("%s: FLIP_Y and PREMULTIPLY_ALPHA are"
-                                         " incompatible with WebGL 2's new UNPACK_*"
-                                         " settings.",
-                                         funcName);
-            return false;
-        }
-
-        if (mDepth != 1) {
-            webgl->ErrorInvalidOperation("%s: FLIP_Y and PREMULTIPLY_ALPHA are"
-                                         " incompatible with 3D textures.",
-                                         funcName);
-            return false;
-        }
-
-        webgl->GenerateWarning("%s: Uploading ArrayBuffers with FLIP_Y or"
-                               " PREMULTIPLY_ALPHA is slow.",
-                               funcName);
-
-        const auto bytesPerPixel = webgl::BytesPerPixel(pi);
-
-        const auto bytesPerRow = CheckedUint32(mRowLength) * bytesPerPixel;
-        const auto rowStride = RoundUpToMultipleOf(bytesPerRow, mAlignment);
-        const auto imageStride = rowStride * mImageHeight;
-
-        if (!imageStride.isValid()) {
-            webgl->ErrorOutOfMemory("%s: Invalid calculation during"
-                                    " FLIP_Y/PREMULTIPLY_ALPHA handling.",
-                                    funcName);
-            return false;
-        }
+    const auto bytesPerPixel = webgl::BytesPerPixel(pi);
+    const auto bytesPerRow = CheckedUint32(mRowLength) * bytesPerPixel;
+    const auto rowStride = RoundUpToMultipleOf(bytesPerRow, mAlignment);
+    if (!rowStride.isValid()) {
+        MOZ_CRASH("Should be checked earlier.");
+    }
 
-        tempBuffer = malloc(imageStride.value());
-        if (!tempBuffer) {
-            webgl->ErrorOutOfMemory("%s: OOM during FLIP_Y/PREMULTIPLY_ALPHA handling.",
-                                    funcName);
-            return false;
-        }
-
-        if (!needsAlphaPremult) {
-            MOZ_ASSERT(needsYFlip);
-
-            const uint8_t* src = (const uint8_t*)mBytes;
-            const uint8_t* const srcEnd = src + rowStride.value() * mHeight;
-
-            uint8_t* dst = (uint8_t*)tempBuffer.get() + rowStride.value() * (mHeight - 1);
-
-            while (src != srcEnd) {
-                memcpy(dst, src, bytesPerRow.value());
-                src += rowStride.value();
-                dst -= rowStride.value();
-            }
-
-            uploadBytes = tempBuffer.get();
-            break;
-        }
+    const void* uploadBytes;
+    UniqueBuffer tempBuffer;
+    if (!ConvertIfNeeded(webgl, funcName, mBytes, rowStride.value(), bytesPerPixel,
+                         format, dui, &uploadBytes, &tempBuffer))
+    {
+        return false;
+    }
 
-        const auto texelFormat = FormatFromPacking(pi);
-        if (texelFormat == WebGLTexelFormat::FormatNotSupportingAnyConversion) {
-            MOZ_ASSERT(false, "Bad texelFormat from pi.");
-            webgl->ErrorOutOfMemory("%s: FormatFromPacking failed during"
-                                    " PREMULTIPLY_ALPHA handling.",
-                                    funcName);
-            return false;
-        }
-
-        const auto srcOrigin = gl::OriginPos::BottomLeft;
-        const auto dstOrigin = (needsYFlip ? gl::OriginPos::TopLeft
-                                           : gl::OriginPos::BottomLeft);
-
-        const bool srcPremultiplied = false;
-        const bool dstPremultiplied = needsAlphaPremult; // Always true here.
-
-        // And go!:
-        MOZ_ASSERT(srcOrigin != dstOrigin || srcPremultiplied != dstPremultiplied);
-        bool unused_wasTrivial;
-        if (!ConvertImage(mWidth, mHeight,
-                          mBytes, rowStride.value(), srcOrigin, texelFormat,
-                          srcPremultiplied,
-                          tempBuffer.get(), rowStride.value(), dstOrigin, texelFormat,
-                          dstPremultiplied, &unused_wasTrivial))
-        {
-            MOZ_ASSERT(false, "ConvertImage failed unexpectedly.");
-            webgl->ErrorOutOfMemory("%s: ConvertImage failed during PREMULTIPLY_ALPHA"
-                                    " handling.",
-                                    funcName);
-            return false;
-        }
-
-        uploadBytes = tempBuffer.get();
-    } while (false);
-
-    *out_error = DoTexOrSubImage(isSubImage, gl, target, level, dui, xOffset, yOffset,
-                                 zOffset, mWidth, mHeight, mDepth, uploadBytes);
+    *out_error = DoTexOrSubImage(isSubImage, webgl->gl, target, level, dui, xOffset,
+                                 yOffset, zOffset, mWidth, mHeight, mDepth, uploadBytes);
     return true;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 // TexUnpackImage
 
-TexUnpackImage::TexUnpackImage(const WebGLContext* webgl, uint32_t imageHeight,
+TexUnpackImage::TexUnpackImage(const WebGLContext* webgl, TexImageTarget target,
                                uint32_t width, uint32_t height, uint32_t depth,
-                               const RefPtr<layers::Image>& image, bool isAlphaPremult)
-    : TexUnpackBlob(webgl, 0, image->GetSize().width, imageHeight, width, height, depth,
-                    true)
+                               layers::Image* image, bool isAlphaPremult)
+    : TexUnpackBlob(webgl, target, image->GetSize().width, width, height, depth,
+                    isAlphaPremult)
     , mImage(image)
-    , mIsAlphaPremult(isAlphaPremult)
 { }
 
 bool
 TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
                               WebGLTexture* tex, TexImageTarget target, GLint level,
                               const webgl::DriverUnpackInfo* dui, GLint xOffset,
                               GLint yOffset, GLint zOffset, GLenum* const out_error) const
 {
@@ -306,16 +348,23 @@ TexUnpackImage::TexOrSubImage(bool isSub
         *out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset,
                                      yOffset, zOffset, mWidth, mHeight, mDepth,
                                      nullptr);
         if (*out_error)
             return false;
     }
 
     do {
+        if (mDepth != 1)
+            break;
+
+        const bool isDstPremult = webgl->mPixelStore_PremultiplyAlpha;
+        if (mIsSrcPremult != isDstPremult)
+            break;
+
         if (dui->unpackFormat != LOCAL_GL_RGB && dui->unpackFormat != LOCAL_GL_RGBA)
             break;
 
         if (dui->unpackType != LOCAL_GL_UNSIGNED_BYTE)
             break;
 
         gl::ScopedFramebuffer scopedFB(gl);
         gl::ScopedBindFramebuffer bindFB(gl, scopedFB.FB());
@@ -329,530 +378,175 @@ TexUnpackImage::TexOrSubImage(bool isSub
             if (errorScope.GetError())
                 break;
         }
 
         const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
         if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE)
             break;
 
-        gl::OriginPos srcOrigin, dstOrigin;
-        OriginsForDOM(webgl, &srcOrigin, &dstOrigin);
-
         const gfx::IntSize destSize(mWidth, mHeight);
+        const auto dstOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft
+                                                         : gl::OriginPos::BottomLeft);
         if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, scopedFB.FB(),
                                                       dstOrigin))
         {
             break;
         }
 
         // Blitting was successful, so we're done!
         *out_error = 0;
         return true;
     } while (false);
 
     webgl->GenerateWarning("%s: Failed to hit GPU-copy fast-path. Falling back to CPU"
                            " upload.",
                            funcName);
 
-    RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
-    if (!surface) {
-        webgl->ErrorOutOfMemory("%s: GetAsSourceSurface failed after blit failed for"
-                                " TexUnpackImage.",
+    const RefPtr<SourceSurface> surf = mImage->GetAsSourceSurface();
+
+    RefPtr<DataSourceSurface> dataSurf;
+    if (surf) {
+        // WARNING: OSX can lose our MakeCurrent here.
+        dataSurf = surf->GetDataSurface();
+    }
+    if (!dataSurf) {
+        webgl->ErrorOutOfMemory("%s: GetAsSourceSurface or GetDataSurface failed after"
+                                " blit failed for TexUnpackImage.",
                                 funcName);
         return false;
     }
 
-    TexUnpackSurface surfBlob(webgl, mImageHeight, mWidth, mHeight, mDepth, surface,
-                              mIsAlphaPremult);
+    const TexUnpackSurface surfBlob(webgl, target, mWidth, mHeight, mDepth, dataSurf,
+                                    mIsSrcPremult);
 
     return surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level,
                                   dui, xOffset, yOffset, zOffset, out_error);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 // TexUnpackSurface
 
-TexUnpackSurface::TexUnpackSurface(const WebGLContext* webgl, uint32_t imageHeight,
+TexUnpackSurface::TexUnpackSurface(const WebGLContext* webgl, TexImageTarget target,
                                    uint32_t width, uint32_t height, uint32_t depth,
-                                   gfx::SourceSurface* surf, bool isAlphaPremult)
-    : TexUnpackBlob(webgl, 0, surf->GetSize().width, imageHeight, width, height, depth,
-                    true)
+                                   gfx::DataSourceSurface* surf, bool isAlphaPremult)
+    : TexUnpackBlob(webgl, target, surf->GetSize().width, width, height, depth,
+                    isAlphaPremult)
     , mSurf(surf)
-    , mIsAlphaPremult(isAlphaPremult)
 { }
 
 //////////
 
 static bool
-GuessAlignment(const void* data, size_t bytesPerRow, size_t stride, size_t maxAlignment,
-               size_t* const out_alignment)
-{
-    size_t alignmentGuess = maxAlignment;
-    while (alignmentGuess) {
-        size_t guessStride = RoundUpToMultipleOf(bytesPerRow, alignmentGuess);
-        if (guessStride == stride &&
-            uintptr_t(data) % alignmentGuess == 0)
-        {
-            *out_alignment = alignmentGuess;
-            return true;
-        }
-        alignmentGuess /= 2;
-    }
-    return false;
-}
-
-static bool
-SupportsBGRA(gl::GLContext* gl)
-{
-    if (gl->IsANGLE())
-        return true;
-
-    return false;
-}
-
-/*static*/ bool
-TexUnpackSurface::UploadDataSurface(bool isSubImage, WebGLContext* webgl,
-                                    TexImageTarget target, GLint level,
-                                    const webgl::DriverUnpackInfo* dui, GLint xOffset,
-                                    GLint yOffset, GLint zOffset, GLsizei width,
-                                    GLsizei height, gfx::DataSourceSurface* surf,
-                                    bool isSurfAlphaPremult, GLenum* const out_glError)
+GetFormatForSurf(gfx::SourceSurface* surf, WebGLTexelFormat* const out_texelFormat,
+                 uint8_t* const out_bpp)
 {
-    gl::GLContext* gl = webgl->GL();
-    MOZ_ASSERT(gl->IsCurrent());
-    *out_glError = 0;
-
-    if (isSurfAlphaPremult != webgl->mPixelStore_PremultiplyAlpha)
-        return false;
-
-    gl::OriginPos srcOrigin, dstOrigin;
-    OriginsForDOM(webgl, &srcOrigin, &dstOrigin);
-    if (srcOrigin != dstOrigin)
-        return false;
-
-    // This differs from the raw-data upload in that we choose how we do the unpack.
-    // (alignment, etc.)
-
-    // Uploading RGBX as RGBA and blitting to RGB is faster than repacking RGBX into
-    // RGB on the CPU. However, this is optimization is out-of-scope for now.
-
-    static const webgl::DriverUnpackInfo kInfoBGRA = {
-        LOCAL_GL_BGRA,
-        LOCAL_GL_BGRA,
-        LOCAL_GL_UNSIGNED_BYTE,
-    };
-
-    const webgl::DriverUnpackInfo* chosenDUI = nullptr;
-
-    switch (surf->GetFormat()) {
-    case gfx::SurfaceFormat::B8G8R8A8:
-        if (SupportsBGRA(gl) &&
-            dui->internalFormat == LOCAL_GL_RGBA &&
-            dui->unpackFormat == LOCAL_GL_RGBA &&
-            dui->unpackType == LOCAL_GL_UNSIGNED_BYTE)
-        {
-            chosenDUI = &kInfoBGRA;
-        }
-        break;
-
-    case gfx::SurfaceFormat::R8G8B8A8:
-        if (dui->unpackFormat == LOCAL_GL_RGBA &&
-            dui->unpackType == LOCAL_GL_UNSIGNED_BYTE)
-        {
-            chosenDUI = dui;
-        }
-        break;
-
-    case gfx::SurfaceFormat::R5G6B5_UINT16:
-        if (dui->unpackFormat == LOCAL_GL_RGB &&
-            dui->unpackType == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
-        {
-            chosenDUI = dui;
-        }
-        break;
-
-    default:
-        break;
-    }
-
-    if (!chosenDUI)
-        return false;
-
-    gfx::DataSourceSurface::ScopedMap map(surf, gfx::DataSourceSurface::MapType::READ);
-    if (!map.IsMapped())
-        return false;
-
-    const webgl::PackingInfo pi = {chosenDUI->unpackFormat, chosenDUI->unpackType};
-    const auto bytesPerPixel = webgl::BytesPerPixel(pi);
-    const size_t bytesPerRow = width * bytesPerPixel;
-
-    const GLint kMaxUnpackAlignment = 8;
-    size_t unpackAlignment;
-    if (!GuessAlignment(map.GetData(), bytesPerRow, map.GetStride(), kMaxUnpackAlignment,
-                        &unpackAlignment))
-    {
-        return false;
-        // TODO: Consider using UNPACK_ settings to set the stride based on the too-large
-        // alignment used for some SourceSurfaces. (D2D allegedy likes alignment=16)
-    }
-
-    MOZ_ALWAYS_TRUE( webgl->gl->MakeCurrent() );
-    ScopedUnpackReset scopedReset(webgl);
-    gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, unpackAlignment);
-
-    const GLsizei depth = 1;
-    GLenum error = DoTexOrSubImage(isSubImage, gl, target.get(), level, chosenDUI,
-                                   xOffset, yOffset, zOffset, width, height, depth,
-                                   map.GetData());
-    if (error) {
-        *out_glError = error;
-        return false;
-    }
-
-    return true;
-}
-
-////////////////////
-
-static bool
-GetFormatForSurf(gfx::SourceSurface* surf, WebGLTexelFormat* const out_texelFormat)
-{
-    gfx::SurfaceFormat surfFormat = surf->GetFormat();
-
+    const auto surfFormat = surf->GetFormat();
     switch (surfFormat) {
     case gfx::SurfaceFormat::B8G8R8A8:
         *out_texelFormat = WebGLTexelFormat::BGRA8;
+        *out_bpp = 4;
         return true;
 
     case gfx::SurfaceFormat::B8G8R8X8:
         *out_texelFormat = WebGLTexelFormat::BGRX8;
+        *out_bpp = 4;
         return true;
 
     case gfx::SurfaceFormat::R8G8B8A8:
         *out_texelFormat = WebGLTexelFormat::RGBA8;
+        *out_bpp = 4;
         return true;
 
     case gfx::SurfaceFormat::R8G8B8X8:
         *out_texelFormat = WebGLTexelFormat::RGBX8;
+        *out_bpp = 4;
         return true;
 
     case gfx::SurfaceFormat::R5G6B5_UINT16:
         *out_texelFormat = WebGLTexelFormat::RGB565;
+        *out_bpp = 2;
         return true;
 
     case gfx::SurfaceFormat::A8:
         *out_texelFormat = WebGLTexelFormat::A8;
+        *out_bpp = 1;
         return true;
 
     case gfx::SurfaceFormat::YUV:
         // Ugh...
         NS_ERROR("We don't handle uploads from YUV sources yet.");
         // When we want to, check out gfx/ycbcr/YCbCrUtils.h. (specifically
         // GetYCbCrToRGBDestFormatAndSize and ConvertYCbCrToRGB)
         return false;
 
     default:
         return false;
     }
 }
 
-static bool
-GetFormatForPackingTuple(GLenum packingFormat, GLenum packingType,
-                         WebGLTexelFormat* const out_texelFormat)
-{
-    switch (packingType) {
-    case LOCAL_GL_UNSIGNED_BYTE:
-        switch (packingFormat) {
-        case LOCAL_GL_RED:
-        case LOCAL_GL_LUMINANCE:
-        case LOCAL_GL_RED_INTEGER:
-            *out_texelFormat = WebGLTexelFormat::R8;
-            return true;
-
-        case LOCAL_GL_ALPHA:
-            *out_texelFormat = WebGLTexelFormat::A8;
-            return true;
-
-        case LOCAL_GL_LUMINANCE_ALPHA:
-            *out_texelFormat = WebGLTexelFormat::RA8;
-            return true;
-
-        case LOCAL_GL_RGB:
-        case LOCAL_GL_RGB_INTEGER:
-            *out_texelFormat = WebGLTexelFormat::RGB8;
-            return true;
-
-        case LOCAL_GL_RGBA:
-        case LOCAL_GL_RGBA_INTEGER:
-            *out_texelFormat = WebGLTexelFormat::RGBA8;
-            return true;
-
-        case LOCAL_GL_RG:
-        case LOCAL_GL_RG_INTEGER:
-            *out_texelFormat = WebGLTexelFormat::RG8;
-            return true;
-
-        default:
-            break;
-        }
-        break;
-
-    case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
-        switch (packingFormat) {
-        case LOCAL_GL_RGB:
-            *out_texelFormat = WebGLTexelFormat::RGB565;
-            return true;
-
-        default:
-            break;
-        }
-        break;
-
-    case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
-        switch (packingFormat) {
-        case LOCAL_GL_RGBA:
-            *out_texelFormat = WebGLTexelFormat::RGBA5551;
-            return true;
-
-        default:
-            break;
-        }
-        break;
-
-    case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
-        switch (packingFormat) {
-        case LOCAL_GL_RGBA:
-            *out_texelFormat = WebGLTexelFormat::RGBA4444;
-            return true;
-
-        default:
-            break;
-        }
-        break;
-
-    case LOCAL_GL_HALF_FLOAT:
-    case LOCAL_GL_HALF_FLOAT_OES:
-        switch (packingFormat) {
-        case LOCAL_GL_RED:
-        case LOCAL_GL_LUMINANCE:
-            *out_texelFormat = WebGLTexelFormat::R16F;
-            return true;
-
-        case LOCAL_GL_ALPHA:
-            *out_texelFormat = WebGLTexelFormat::A16F;
-            return true;
-
-        case LOCAL_GL_LUMINANCE_ALPHA:
-            *out_texelFormat = WebGLTexelFormat::RA16F;
-            return true;
-
-        case LOCAL_GL_RGB:
-            *out_texelFormat = WebGLTexelFormat::RGB16F;
-            return true;
-
-        case LOCAL_GL_RGBA:
-            *out_texelFormat = WebGLTexelFormat::RGBA16F;
-            return true;
-
-        case LOCAL_GL_RG:
-            *out_texelFormat = WebGLTexelFormat::RG16F;
-            return true;
-
-        default:
-            break;
-        }
-        break;
-
-    case LOCAL_GL_FLOAT:
-        switch (packingFormat) {
-        case LOCAL_GL_RED:
-        case LOCAL_GL_LUMINANCE:
-            *out_texelFormat = WebGLTexelFormat::R32F;
-            return true;
-
-        case LOCAL_GL_ALPHA:
-            *out_texelFormat = WebGLTexelFormat::A32F;
-            return true;
-
-        case LOCAL_GL_LUMINANCE_ALPHA:
-            *out_texelFormat = WebGLTexelFormat::RA32F;
-            return true;
-
-        case LOCAL_GL_RGB:
-            *out_texelFormat = WebGLTexelFormat::RGB32F;
-            return true;
-
-        case LOCAL_GL_RGBA:
-            *out_texelFormat = WebGLTexelFormat::RGBA32F;
-            return true;
-
-        case LOCAL_GL_RG:
-            *out_texelFormat = WebGLTexelFormat::RG32F;
-            return true;
-
-        default:
-            break;
-        }
-        break;
-
-    case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
-        switch (packingFormat) {
-        case LOCAL_GL_RGB:
-            *out_texelFormat = WebGLTexelFormat::RGB11F11F10F;
-            return true;
-
-        default:
-            break;
-        }
-        break;
-    default:
-        break;
-    }
-
-    NS_ERROR("Unsupported EffectiveFormat dest format for DOM element upload.");
-    return false;
-}
-
-/*static*/ bool
-TexUnpackSurface::ConvertSurface(WebGLContext* webgl, const webgl::DriverUnpackInfo* dui,
-                                 gfx::DataSourceSurface* surf, bool isSurfAlphaPremult,
-                                 UniqueBuffer* const out_convertedBuffer,
-                                 uint8_t* const out_convertedAlignment,
-                                 bool* const out_wasTrivial, bool* const out_outOfMemory)
-{
-    *out_outOfMemory = false;
-
-    const size_t width = surf->GetSize().width;
-    const size_t height = surf->GetSize().height;
-
-    // Source args:
-
-    // After we call this, on OSX, our GLContext will no longer be current.
-    gfx::DataSourceSurface::ScopedMap srcMap(surf, gfx::DataSourceSurface::MapType::READ);
-    if (!srcMap.IsMapped())
-        return false;
-
-    const void* const srcBegin = srcMap.GetData();
-    const size_t srcStride = srcMap.GetStride();
-
-    WebGLTexelFormat srcFormat;
-    if (!GetFormatForSurf(surf, &srcFormat))
-        return false;
-
-    const bool srcPremultiplied = isSurfAlphaPremult;
-
-    // Dest args:
-
-    WebGLTexelFormat dstFormat;
-    if (!GetFormatForPackingTuple(dui->unpackFormat, dui->unpackType, &dstFormat))
-        return false;
-
-    const auto bytesPerPixel = webgl::BytesPerPixel({dui->unpackFormat, dui->unpackType});
-    const size_t dstRowBytes = bytesPerPixel * width;
-
-    const size_t dstAlignment = 8; // Just use the max!
-    const size_t dstStride = RoundUpToMultipleOf(dstRowBytes, dstAlignment);
-
-    CheckedUint32 checkedDstSize = dstStride;
-    checkedDstSize *= height;
-    if (!checkedDstSize.isValid()) {
-        *out_outOfMemory = true;
-        return false;
-    }
-
-    const size_t dstSize = checkedDstSize.value();
-
-    UniqueBuffer dstBuffer = malloc(dstSize);
-    if (!dstBuffer) {
-        *out_outOfMemory = true;
-        return false;
-    }
-    void* const dstBegin = dstBuffer.get();
-
-    gl::OriginPos srcOrigin, dstOrigin;
-    OriginsForDOM(webgl, &srcOrigin, &dstOrigin);
-
-    const bool dstPremultiplied = webgl->mPixelStore_PremultiplyAlpha;
-
-    // And go!:
-    bool wasTrivial;
-    if (!ConvertImage(width, height,
-                      srcBegin, srcStride, srcOrigin, srcFormat, srcPremultiplied,
-                      dstBegin, dstStride, dstOrigin, dstFormat, dstPremultiplied,
-                      &wasTrivial))
-    {
-        MOZ_ASSERT(false, "ConvertImage failed unexpectedly.");
-        NS_ERROR("ConvertImage failed unexpectedly.");
-        *out_outOfMemory = true;
-        return false;
-    }
-
-    *out_convertedBuffer = Move(dstBuffer);
-    *out_convertedAlignment = dstAlignment;
-    *out_wasTrivial = wasTrivial;
-    return true;
-}
-
-
-////////////////////
+//////////
 
 bool
 TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
                                 WebGLTexture* tex, TexImageTarget target, GLint level,
-                                const webgl::DriverUnpackInfo* dui, GLint xOffset,
+                                const webgl::DriverUnpackInfo* dstDUI, GLint xOffset,
                                 GLint yOffset, GLint zOffset,
                                 GLenum* const out_error) const
 {
     WebGLContext* webgl = tex->mContext;
 
-    // MakeCurrent is a big mess in here, because mapping (and presumably unmapping) on
-    // OSX can lose our MakeCurrent. Therefore it's easiest to MakeCurrent just before we
-    // call into GL, instead of trying to keep MakeCurrent-ed.
-
-    RefPtr<gfx::DataSourceSurface> dataSurf = mSurf->GetDataSurface();
-    if (!dataSurf) {
-        // Since GetDataSurface didn't return error code, assume system
-        // is out of memory
-        webgl->ErrorOutOfMemory("%s: OOM in GetDataSurface for TexUnpackSurface.",
-                                funcName);
+    WebGLTexelFormat srcFormat;
+    uint8_t srcBPP;
+    if (!GetFormatForSurf(mSurf, &srcFormat, &srcBPP)) {
+        webgl->ErrorImplementationBug("%s: GetFormatForSurf failed for"
+                                      " WebGLTexelFormat::%u.",
+                                      funcName, uint32_t(mSurf->GetFormat()));
         return false;
     }
 
-    if (UploadDataSurface(isSubImage, webgl, target, level, dui, xOffset, yOffset,
-                          zOffset, mWidth, mHeight, dataSurf, mIsAlphaPremult, out_error))
-    {
-        return true;
-    }
+    gfx::DataSourceSurface::ScopedMap map(mSurf, gfx::DataSourceSurface::MapType::READ);
+    if (!map.IsMapped())
+        return false;
+
+    const auto srcBytes = map.GetData();
+    const auto srcStride = map.GetStride();
 
     // CPU conversion. (++numCopies)
 
-    UniqueBuffer convertedBuffer;
-    uint8_t convertedAlignment;
-    bool wasTrivial;
-    bool outOfMemory;
-    if (!ConvertSurface(webgl, dui, dataSurf, mIsAlphaPremult, &convertedBuffer,
-                        &convertedAlignment, &wasTrivial, &outOfMemory))
+    webgl->GenerateWarning("%s: Incurred CPU-side conversion, which is very slow.",
+                           funcName);
+
+    const void* uploadBytes;
+    UniqueBuffer tempBuffer;
+    if (!ConvertIfNeeded(webgl, funcName, srcBytes, srcStride, srcBPP, srcFormat,
+                         dstDUI, &uploadBytes, &tempBuffer))
     {
-        webgl->ErrorOutOfMemory("%s: %s in ConvertSurface for TexUnpackSurface.",
-                                funcName, outOfMemory ? "OOM" : "Failure");
         return false;
     }
 
-    if (!wasTrivial) {
-        webgl->GenerateWarning("%s: Chosen format/type incured an expensive reformat:"
-                               " 0x%04x/0x%04x",
-                               funcName, dui->unpackFormat, dui->unpackType);
+    //////
+
+    gl::GLContext* const gl = webgl->gl;
+    MOZ_ALWAYS_TRUE( gl->MakeCurrent() );
+
+    const auto curEffectiveRowLength = FallbackOnZero(webgl->mPixelStore_UnpackRowLength,
+                                                      mWidth);
+
+    const bool changeRowLength = (mRowLength != curEffectiveRowLength);
+    if (changeRowLength) {
+        MOZ_ASSERT(webgl->IsWebGL2());
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, mRowLength);
     }
 
-    MOZ_ALWAYS_TRUE( webgl->gl->MakeCurrent() );
-    ScopedUnpackReset scopedReset(webgl);
-    webgl->gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, convertedAlignment);
+    *out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dstDUI, xOffset,
+                                 yOffset, zOffset, mWidth, mHeight, mDepth, uploadBytes);
 
-    *out_error = DoTexOrSubImage(isSubImage, webgl->gl, target.get(), level, dui, xOffset,
-                                 yOffset, zOffset, mWidth, mHeight, mDepth,
-                                 convertedBuffer.get());
+    if (changeRowLength) {
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, webgl->mPixelStore_UnpackRowLength);
+    }
+
     return true;
 }
 
 } // namespace webgl
 } // namespace mozilla
--- a/dom/canvas/TexUnpackBlob.h
+++ b/dom/canvas/TexUnpackBlob.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TEX_UNPACK_BLOB_H_
 #define TEX_UNPACK_BLOB_H_
 
 #include "GLContextTypes.h"
 #include "GLTypes.h"
 #include "WebGLStrongTypes.h"
+#include "WebGLTypes.h"
 
 
 template <class T>
 class RefPtr;
 
 namespace mozilla {
 
 class UniqueBuffer;
@@ -51,94 +52,87 @@ public:
     const uint32_t mRowLength;
     const uint32_t mImageHeight;
     const uint32_t mSkipPixels;
     const uint32_t mSkipRows;
     const uint32_t mSkipImages;
     const uint32_t mWidth;
     const uint32_t mHeight;
     const uint32_t mDepth;
-    const bool mHasData;
+    const bool mIsSrcPremult;
 
 protected:
-    TexUnpackBlob(const WebGLContext* webgl, uint32_t alignment, uint32_t rowLength,
-                  uint32_t imageHeight, uint32_t width, uint32_t height, uint32_t depth,
-                  bool hasData);
+    TexUnpackBlob(const WebGLContext* webgl, TexImageTarget target, uint32_t rowLength,
+                  uint32_t width, uint32_t height, uint32_t depth, bool isSrcPremult);
 
 public:
     virtual ~TexUnpackBlob() { }
 
+protected:
+    bool ConvertIfNeeded(WebGLContext* webgl, const char* funcName, const void* srcBytes,
+                         uint32_t srcStride, uint8_t srcBPP, WebGLTexelFormat srcFormat,
+                         const webgl::DriverUnpackInfo* dstDUI,
+                         const void** const out_bytes,
+                         UniqueBuffer* const out_anchoredBuffer) const;
+
+public:
+    virtual bool HasData() const { return true; }
+
     virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
-                                 WebGLTexture* tex, TexImageTarget target, GLint level,
-                                 const webgl::DriverUnpackInfo* dui, GLint xOffset,
-                                 GLint yOffset, GLint zOffset,
-                                 GLenum* const out_error) const = 0;
-
-    static void OriginsForDOM(WebGLContext* webgl, gl::OriginPos* const out_src,
-                              gl::OriginPos* const out_dst);
+                               WebGLTexture* tex, TexImageTarget target, GLint level,
+                               const webgl::DriverUnpackInfo* dui, GLint xOffset,
+                               GLint yOffset, GLint zOffset,
+                               GLenum* const out_error) const = 0;
 };
 
-class TexUnpackBytes : public TexUnpackBlob
+class TexUnpackBytes final : public TexUnpackBlob
 {
 public:
     const void* const mBytes;
 
-    TexUnpackBytes(const WebGLContext* webgl, uint32_t width, uint32_t height,
-                   uint32_t depth, const void* bytes);
+    TexUnpackBytes(const WebGLContext* webgl, TexImageTarget target, uint32_t width,
+                   uint32_t height, uint32_t depth, const void* bytes);
+
+    virtual bool HasData() const override { return bool(mBytes); }
+
+    virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
+                               WebGLTexture* tex, TexImageTarget target, GLint level,
+                               const webgl::DriverUnpackInfo* dui, GLint xOffset,
+                               GLint yOffset, GLint zOffset,
+                               GLenum* const out_error) const override;
+};
+
+class TexUnpackImage final : public TexUnpackBlob
+{
+public:
+    const RefPtr<layers::Image> mImage;
+
+    TexUnpackImage(const WebGLContext* webgl, TexImageTarget target, uint32_t width,
+                   uint32_t height, uint32_t depth, layers::Image* image,
+                   bool isAlphaPremult);
+
+    virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
+                               WebGLTexture* tex, TexImageTarget target, GLint level,
+                               const webgl::DriverUnpackInfo* dui, GLint xOffset,
+                               GLint yOffset, GLint zOffset,
+                               GLenum* const out_error) const override;
+};
+
+class TexUnpackSurface final : public TexUnpackBlob
+{
+public:
+    const RefPtr<gfx::DataSourceSurface> mSurf;
+
+    TexUnpackSurface(const WebGLContext* webgl, TexImageTarget target, uint32_t width,
+                     uint32_t height, uint32_t depth, gfx::DataSourceSurface* surf,
+                     bool isAlphaPremult);
 
     virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
                                  WebGLTexture* tex, TexImageTarget target, GLint level,
                                  const webgl::DriverUnpackInfo* dui, GLint xOffset,
                                  GLint yOffset, GLint zOffset,
                                  GLenum* const out_error) const override;
 };
 
-class TexUnpackImage : public TexUnpackBlob
-{
-public:
-    const RefPtr<layers::Image> mImage;
-    const bool mIsAlphaPremult;
-
-    TexUnpackImage(const WebGLContext* webgl, uint32_t imageHeight, uint32_t width,
-                   uint32_t height, uint32_t depth, const RefPtr<layers::Image>& image,
-                   bool isAlphaPremult);
-
-    virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
-                                 WebGLTexture* tex, TexImageTarget target, GLint level,
-                                 const webgl::DriverUnpackInfo* dui, GLint xOffset,
-                                 GLint yOffset, GLint zOffset,
-                                 GLenum* const out_error) const override;
-};
-
-class TexUnpackSurface : public TexUnpackBlob
-{
-public:
-    const RefPtr<gfx::SourceSurface> mSurf;
-    const bool mIsAlphaPremult;
-
-    TexUnpackSurface(const WebGLContext* webgl, uint32_t imageHeight, uint32_t width,
-                     uint32_t height, uint32_t depth, gfx::SourceSurface* surf,
-                     bool isAlphaPremult);
-
-    virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
-                                 WebGLTexture* tex, TexImageTarget target, GLint level,
-                                 const webgl::DriverUnpackInfo* dui, GLint xOffset,
-                                 GLint yOffset, GLint zOffset,
-                                 GLenum* const out_error) const override;
-
-protected:
-    static bool ConvertSurface(WebGLContext* webgl, const webgl::DriverUnpackInfo* dui,
-                               gfx::DataSourceSurface* surf, bool isSurfAlphaPremult,
-                               UniqueBuffer* const out_convertedBuffer,
-                               uint8_t* const out_convertedAlignment,
-                               bool* const out_wasTrivial, bool* const out_outOfMemory);
-    static bool UploadDataSurface(bool isSubImage, WebGLContext* webgl,
-                                  TexImageTarget target, GLint level,
-                                  const webgl::DriverUnpackInfo* dui, GLint xOffset,
-                                  GLint yOffset, GLint zOffset, GLsizei width,
-                                  GLsizei height, gfx::DataSourceSurface* surf,
-                                  bool isSurfAlphaPremult, GLenum* const out_glError);
-};
-
 } // namespace webgl
 } // namespace mozilla
 
 #endif // TEX_UNPACK_BLOB_H_
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -283,16 +283,17 @@ public:
     void ErrorInvalidEnum(const char* fmt = 0, ...);
     void ErrorInvalidOperation(const char* fmt = 0, ...);
     void ErrorInvalidValue(const char* fmt = 0, ...);
     void ErrorInvalidFramebufferOperation(const char* fmt = 0, ...);
     void ErrorInvalidEnumInfo(const char* info, GLenum enumValue);
     void ErrorInvalidEnumInfo(const char* info, const char* funcName,
                               GLenum enumValue);
     void ErrorOutOfMemory(const char* fmt = 0, ...);
+    void ErrorImplementationBug(const char* fmt = 0, ...);
 
     const char* ErrorName(GLenum error);
 
     /**
      * Return displayable name for GLenum.
      * This version is like gl::GLenumToStr but with out the GL_ prefix to
      * keep consistency with how errors are reported from WebGL.
      */
@@ -958,20 +959,16 @@ protected:
     bool ValidateTexImageSelection(const char* funcName, uint8_t funcDims,
                                    GLenum texImageTarget, GLint level, GLint xOffset,
                                    GLint yOffset, GLint zOffset, GLsizei width,
                                    GLsizei height, GLsizei depth,
                                    TexImageTarget* const out_target,
                                    WebGLTexture** const out_texture,
                                    WebGLTexture::ImageInfo** const out_imageInfo);
 
-    bool GetUnpackValuesForImage(const char* funcName, uint32_t srcImageWidth,
-                                 uint32_t srcImageHeight, uint32_t* const out_rowLength,
-                                 uint32_t* const out_imageHeight);
-
     bool ValidateUnpackInfo(const char* funcName, GLenum format, GLenum type,
                             webgl::PackingInfo* const out);
 
 // -----------------------------------------------------------------------------
 // Vertices Feature (WebGLContextVertices.cpp)
 public:
     void DrawArrays(GLenum mode, GLint first, GLsizei count);
     void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count,
@@ -1329,34 +1326,18 @@ protected:
     // helpers
 
     bool ConvertImage(size_t width, size_t height, size_t srcStride,
                       size_t dstStride, const uint8_t* src, uint8_t* dst,
                       WebGLTexelFormat srcFormat, bool srcPremultiplied,
                       WebGLTexelFormat dstFormat, bool dstPremultiplied,
                       size_t dstTexelSize);
 
-public:
-    nsLayoutUtils::SurfaceFromElementResult
-    SurfaceFromElement(dom::Element* elem)
-    {
-        uint32_t flags = nsLayoutUtils::SFE_WANT_IMAGE_SURFACE |
-                         nsLayoutUtils::SFE_USE_ELEMENT_SIZE_IF_VECTOR;
+    //////
 
-        if (mPixelStore_ColorspaceConversion == LOCAL_GL_NONE)
-            flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
-
-        if (!mPixelStore_PremultiplyAlpha)
-            flags |= nsLayoutUtils::SFE_PREFER_NO_PREMULTIPLY_ALPHA;
-
-        RefPtr<gfx::DrawTarget> idealDrawTarget = nullptr; // Don't care for now.
-        return nsLayoutUtils::SurfaceFromElement(elem, flags, idealDrawTarget);
-    }
-
-protected:
     // Returns false if `object` is null or not valid.
     template<class ObjectType>
     bool ValidateObject(const char* info, ObjectType* object);
 
     // Returns false if `object` is not valid.  Considers null to be valid.
     template<class ObjectType>
     bool ValidateObjectAllowNull(const char* info, ObjectType* object);
 
@@ -1624,16 +1605,17 @@ public:
     CreateFormatUsage(gl::GLContext* gl) const = 0;
 
     // Friend list
     friend class ScopedCopyTexImageSource;
     friend class ScopedResolveTexturesForDraw;
     friend class ScopedUnpackReset;
     friend class webgl::TexUnpackBlob;
     friend class webgl::TexUnpackBytes;
+    friend class webgl::TexUnpackImage;
     friend class webgl::TexUnpackSurface;
     friend class WebGLTexture;
     friend class WebGLFBAttachPoint;
     friend class WebGLFramebuffer;
     friend class WebGLRenderbuffer;
     friend class WebGLProgram;
     friend class WebGLQuery;
     friend class WebGLBuffer;
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -1,13 +1,14 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "WebGLContextUtils.h"
 #include "WebGLContext.h"
 
 #include "GLContext.h"
 #include "jsapi.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/Preferences.h"
 #include "nsIDOMDataContainerEvent.h"
 #include "nsIDOMEvent.h"
@@ -18,17 +19,16 @@
 #include "prprf.h"
 #include <stdarg.h>
 #include "WebGLBuffer.h"
 #include "WebGLExtensions.h"
 #include "WebGLFramebuffer.h"
 #include "WebGLProgram.h"
 #include "WebGLTexture.h"
 #include "WebGLVertexArray.h"
-#include "WebGLContextUtils.h"
 
 namespace mozilla {
 
 TexTarget
 TexImageTargetToTexTarget(TexImageTarget texImageTarget)
 {
     switch (texImageTarget.get()) {
     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
@@ -202,16 +202,32 @@ WebGLContext::ErrorOutOfMemory(const cha
     va_list va;
     va_start(va, fmt);
     GenerateWarning(fmt, va);
     va_end(va);
 
     return SynthesizeGLError(LOCAL_GL_OUT_OF_MEMORY);
 }
 
+void
+WebGLContext::ErrorImplementationBug(const char* fmt, ...)
+{
+    const nsPrintfCString warning("Implementation bug, please file at %s! %s",
+                                  "https://bugzilla.mozilla.org/", fmt);
+
+    va_list va;
+    va_start(va, fmt);
+    GenerateWarning(warning.BeginReading(), va);
+    va_end(va);
+
+    MOZ_ASSERT(false, "WebGLContext::ErrorImplementationBug");
+    NS_ERROR("WebGLContext::ErrorImplementationBug");
+    return SynthesizeGLError(LOCAL_GL_OUT_OF_MEMORY);
+}
+
 const char*
 WebGLContext::ErrorName(GLenum error)
 {
     switch(error) {
     case LOCAL_GL_INVALID_ENUM:
         return "INVALID_ENUM";
     case LOCAL_GL_INVALID_OPERATION:
         return "INVALID_OPERATION";
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -407,16 +407,19 @@ TexImageTargetForTargetAndFace(TexTarget
     default:
         MOZ_CRASH("GFX: TexImageTargetForTargetAndFace");
     }
 }
 
 already_AddRefed<mozilla::layers::Image>
 ImageFromVideo(dom::HTMLVideoElement* elem);
 
+bool
+IsTarget3D(TexImageTarget target);
+
 GLenum
 DoTexImage(gl::GLContext* gl, TexImageTarget target, GLint level,
            const webgl::DriverUnpackInfo* dui, GLsizei width, GLsizei height,
            GLsizei depth, const void* data);
 GLenum
 DoTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLint xOffset,
               GLint yOffset, GLint zOffset, GLsizei width, GLsizei height,
               GLsizei depth, const webgl::PackingInfo& pi, const void* data);
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -173,21 +173,22 @@ WebGLContext::ValidateUnpackPixels(const
                           " rows plus %u pixels needed, %u rows plus %u pixels"
                           " available)",
                           funcName, fullRowsNeeded.value(), usedPixelsPerRow.value(),
                           fullRows, tailPixels);
     return false;
 }
 
 static UniquePtr<webgl::TexUnpackBlob>
-BlobFromView(WebGLContext* webgl, const char* funcName, uint32_t width, uint32_t height,
-             uint32_t depth, const webgl::PackingInfo& pi,
+BlobFromView(WebGLContext* webgl, const char* funcName, TexImageTarget target,
+             uint32_t width, uint32_t height, uint32_t depth,
+             const webgl::PackingInfo& pi,
              const dom::Nullable<dom::ArrayBufferView>& maybeView)
 {
-    const void* bytes = nullptr;
+    const uint8_t* bytes = nullptr;
     uint32_t byteCount = 0;
 
     if (!maybeView.IsNull()) {
         const auto& view = maybeView.Value();
 
         const auto jsType = JS_GetArrayBufferViewType(view.Obj());
         if (!DoesJSTypeMatchUnpackType(pi.type, jsType)) {
             webgl->ErrorInvalidOperation("%s: `pixels` must be compatible with `type`.",
@@ -198,18 +199,18 @@ BlobFromView(WebGLContext* webgl, const 
         if (width && height && depth) {
             view.ComputeLengthAndData();
 
             bytes = view.DataAllowShared();
             byteCount = view.LengthAllowShared();
         }
     }
 
-    UniquePtr<webgl::TexUnpackBlob> blob(new webgl::TexUnpackBytes(webgl, width, height,
-                                                                   depth, bytes));
+    UniquePtr<webgl::TexUnpackBlob> blob(new webgl::TexUnpackBytes(webgl, target, width,
+                                                                   height, depth, bytes));
 
     //////
 
     if (bytes) {
         const auto bytesPerPixel = webgl::BytesPerPixel(pi);
         const auto bytesPerRow = CheckedUint32(blob->mRowLength) * bytesPerPixel;
         const auto rowStride = RoundUpToMultipleOf(bytesPerRow, blob->mAlignment);
 
@@ -263,29 +264,29 @@ WebGLTexture::TexOrSubImage(bool isSubIm
     {
         return;
     }
 
     webgl::PackingInfo pi;
     if (!mContext->ValidateUnpackInfo(funcName, unpackFormat, unpackType, &pi))
         return;
 
-    const auto blob = BlobFromView(mContext, funcName, width, height, depth, pi,
+    const auto blob = BlobFromView(mContext, funcName, target, width, height, depth, pi,
                                    maybeView);
     if (!blob)
         return;
 
     TexOrSubImageBlob(isSubImage, funcName, target, level, internalFormat, xOffset,
                       yOffset, zOffset, pi, blob.get());
 }
 
 ////////////////////////////////////////
 // ImageData
 
-static already_AddRefed<gfx::SourceSurface>
+static already_AddRefed<gfx::DataSourceSurface>
 FromImageData(WebGLContext* webgl, const char* funcName, GLenum unpackType,
               dom::ImageData* imageData, dom::Uint8ClampedArray* scopedArr)
 {
     DebugOnly<bool> inited = scopedArr->Init(imageData->GetDataObject());
     MOZ_ASSERT(inited);
 
     scopedArr->ComputeLengthAndData();
     const DebugOnly<size_t> dataSize = scopedArr->Length();
@@ -294,58 +295,29 @@ FromImageData(WebGLContext* webgl, const
     const gfx::IntSize size(imageData->Width(), imageData->Height());
     const size_t stride = size.width * 4;
     const gfx::SurfaceFormat surfFormat = gfx::SurfaceFormat::R8G8B8A8;
 
     MOZ_ASSERT(dataSize == stride * size.height);
 
     uint8_t* wrappableData = (uint8_t*)data;
 
-    RefPtr<gfx::SourceSurface> surf =
+    RefPtr<gfx::DataSourceSurface> surf =
         gfx::Factory::CreateWrappingDataSourceSurface(wrappableData,
                                                       stride,
                                                       size,
                                                       surfFormat);
     if (!surf) {
         webgl->ErrorOutOfMemory("%s: OOM in FromImageData.", funcName);
         return nullptr;
     }
 
     return surf.forget();
 }
 
-bool
-WebGLContext::GetUnpackValuesForImage(const char* funcName, uint32_t srcImageWidth,
-                                      uint32_t srcImageHeight,
-                                      uint32_t* const out_rowLength,
-                                      uint32_t* const out_imageHeight)
-{
-    uint32_t rowLength = mPixelStore_UnpackRowLength;
-    if (!rowLength) {
-        rowLength = srcImageWidth;
-    } else if (rowLength != srcImageWidth) {
-        ErrorInvalidOperation("%s: UNPACK_ROW_LENGTH, if set, must be == width of"
-                              " object.");
-        return false;
-    }
-
-    uint32_t imageHeight = mPixelStore_UnpackImageHeight;
-    if (!imageHeight) {
-        imageHeight = srcImageHeight;
-    } else if (imageHeight > srcImageHeight) {
-        ErrorInvalidOperation("%s: UNPACK_IMAGE_HEIGHT, if set, must be <= height of"
-                              " object");
-        return false;
-    }
-
-    *out_rowLength = rowLength;
-    *out_imageHeight = imageHeight;
-    return true;
-}
-
 void
 WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
                             GLint level, GLenum internalFormat, GLint xOffset,
                             GLint yOffset, GLint zOffset, GLenum unpackFormat,
                             GLenum unpackType, dom::ImageData* imageData)
 {
     webgl::PackingInfo pi;
     if (!mContext->ValidateUnpackInfo(funcName, unpackFormat, unpackType, &pi))
@@ -357,37 +329,30 @@ WebGLTexture::TexOrSubImage(bool isSubIm
         return;
     }
 
     // Eventually, these will be args.
     const uint32_t width = imageData->Width();
     const uint32_t height = imageData->Height();
     const uint32_t depth = 1;
 
-    uint32_t rowLength, imageHeight;
-    if (!mContext->GetUnpackValuesForImage(funcName, imageData->Width(),
-                                           imageData->Height(), &rowLength, &imageHeight))
-    {
-        return;
-    }
-
-    dom::RootedTypedArray<dom::Uint8ClampedArray> scopedArr(
-      nsContentUtils::RootingCx());
-    const RefPtr<gfx::SourceSurface> surf = FromImageData(mContext, funcName, unpackType,
-                                                          imageData, &scopedArr);
+    dom::RootedTypedArray<dom::Uint8ClampedArray> scopedArr(nsContentUtils::RootingCx());
+    const RefPtr<gfx::DataSourceSurface> surf = FromImageData(mContext, funcName,
+                                                              unpackType, imageData,
+                                                              &scopedArr);
     if (!surf)
         return;
 
     // WhatWG "HTML Living Standard" (30 October 2015):
     // "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned as
     //  non-premultiplied alpha values."
-    const bool surfIsAlphaPremult = false;
+    const bool isAlphaPremult = false;
 
-    const webgl::TexUnpackSurface blob(mContext, imageHeight, width, height, depth, surf,
-                                       surfIsAlphaPremult);
+    const webgl::TexUnpackSurface blob(mContext, target, width, height, depth, surf,
+                                       isAlphaPremult);
 
     const uint32_t fullRows = imageData->Height();
     const uint32_t tailPixels = 0;
     if (!mContext->ValidateUnpackPixels(funcName, fullRows, tailPixels, &blob))
         return;
 
     TexOrSubImageBlob(isSubImage, funcName, target, level, internalFormat, xOffset,
                       yOffset, zOffset, pi, &blob);
@@ -402,51 +367,71 @@ WebGLTexture::TexOrSubImage(bool isSubIm
                             GLint yOffset, GLint zOffset, GLenum unpackFormat,
                             GLenum unpackType, dom::Element* elem,
                             ErrorResult* const out_error)
 {
     webgl::PackingInfo pi;
     if (!mContext->ValidateUnpackInfo(funcName, unpackFormat, unpackType, &pi))
         return;
 
-    auto sfer = mContext->SurfaceFromElement(elem);
+    //////
+
+    uint32_t flags = nsLayoutUtils::SFE_WANT_IMAGE_SURFACE |
+                     nsLayoutUtils::SFE_USE_ELEMENT_SIZE_IF_VECTOR;
+
+    if (mContext->mPixelStore_ColorspaceConversion == LOCAL_GL_NONE)
+        flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
+
+    if (!mContext->mPixelStore_PremultiplyAlpha)
+        flags |= nsLayoutUtils::SFE_PREFER_NO_PREMULTIPLY_ALPHA;
+
+    RefPtr<gfx::DrawTarget> idealDrawTarget = nullptr; // Don't care for now.
+    auto sfer = nsLayoutUtils::SurfaceFromElement(elem, flags, idealDrawTarget);
+
+    //////
 
     uint32_t elemWidth = 0;
     uint32_t elemHeight = 0;
     layers::Image* layersImage = nullptr;
     if (!gfxPrefs::WebGLDisableDOMBlitUploads() && sfer.mLayersImage) {
         layersImage = sfer.mLayersImage;
         elemWidth = layersImage->GetSize().width;
         elemHeight = layersImage->GetSize().height;
     }
 
-    gfx::SourceSurface* surf = nullptr;
+    RefPtr<gfx::DataSourceSurface> dataSurf;
     if (!layersImage && sfer.GetSourceSurface()) {
-        surf = sfer.GetSourceSurface();
+        const auto surf = sfer.GetSourceSurface();
         elemWidth = surf->GetSize().width;
         elemHeight = surf->GetSize().height;
+
+        // WARNING: OSX can lose our MakeCurrent here.
+        dataSurf = surf->GetDataSurface();
     }
 
+    //////
+
     // Eventually, these will be args.
     const uint32_t width = elemWidth;
     const uint32_t height = elemHeight;
     const uint32_t depth = 1;
 
-    // While it's counter-intuitive, the shape of the SFEResult API means that we should
-    // try to pull out a surface first, and then, if we do pull out a surface, check
-    // CORS/write-only/etc..
-    if (!layersImage && !surf) {
-        webgl::TexUnpackBytes blob(mContext, width, height, depth, nullptr);
+    if (!layersImage && !dataSurf) {
+        const webgl::TexUnpackBytes blob(mContext, target, width, height, depth, nullptr);
         TexOrSubImageBlob(isSubImage, funcName, target, level, internalFormat, xOffset,
                           yOffset, zOffset, pi, &blob);
         return;
     }
 
     //////
 
+    // While it's counter-intuitive, the shape of the SFEResult API means that we should
+    // try to pull out a surface first, and then, if we do pull out a surface, check
+    // CORS/write-only/etc..
+
     if (!sfer.mCORSUsed) {
         auto& srcPrincipal = sfer.mPrincipal;
         nsIPrincipal* dstPrincipal = mContext->GetCanvas()->NodePrincipal();
 
         if (!dstPrincipal->Subsumes(srcPrincipal)) {
             mContext->GenerateWarning("%s: Cross-origin elements require CORS.",
                                       funcName);
             out_error->Throw(NS_ERROR_DOM_SECURITY_ERR);
@@ -463,33 +448,26 @@ WebGLTexture::TexOrSubImage(bool isSubIm
                                   funcName);
         out_error->Throw(NS_ERROR_DOM_SECURITY_ERR);
         return;
     }
 
     //////
     // Ok, we're good!
 
-    uint32_t rowLength, imageHeight;
-    if (!mContext->GetUnpackValuesForImage(funcName, elemWidth, elemHeight, &rowLength,
-                                           &imageHeight))
-    {
-        return;
-    }
-
     UniquePtr<const webgl::TexUnpackBlob> blob;
     const bool isAlphaPremult = sfer.mIsPremultiplied;
 
     if (layersImage) {
-        blob.reset(new webgl::TexUnpackImage(mContext, imageHeight, width, height, depth,
+        blob.reset(new webgl::TexUnpackImage(mContext, target, width, height, depth,
                                              layersImage, isAlphaPremult));
     } else {
-        MOZ_ASSERT(surf);
-        blob.reset(new webgl::TexUnpackSurface(mContext, imageHeight, width, height,
-                                               depth, surf, isAlphaPremult));
+        MOZ_ASSERT(dataSurf);
+        blob.reset(new webgl::TexUnpackSurface(mContext, target, width, height, depth,
+                                               dataSurf, isAlphaPremult));
     }
 
     const uint32_t fullRows = elemHeight;
     const uint32_t tailPixels = 0;
     if (!mContext->ValidateUnpackPixels(funcName, fullRows, tailPixels, blob.get()))
         return;
 
     TexOrSubImageBlob(isSubImage, funcName, target, level, internalFormat, xOffset,
@@ -831,18 +809,18 @@ DoTexStorage(gl::GLContext* gl, TexTarge
 
     default:
         MOZ_CRASH("GFX: bad target");
     }
 
     return errorScope.GetError();
 }
 
-static bool
-Is3D(TexImageTarget target)
+bool
+IsTarget3D(TexImageTarget target)
 {
     switch (target.get()) {
     case LOCAL_GL_TEXTURE_2D:
     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
@@ -862,17 +840,17 @@ GLenum
 DoTexImage(gl::GLContext* gl, TexImageTarget target, GLint level,
            const webgl::DriverUnpackInfo* dui, GLsizei width, GLsizei height,
            GLsizei depth, const void* data)
 {
     const GLint border = 0;
 
     gl::GLContext::LocalErrorScope errorScope(*gl);
 
-    if (Is3D(target)) {
+    if (IsTarget3D(target)) {
         gl->fTexImage3D(target.get(), level, dui->internalFormat, width, height, depth,
                         border, dui->unpackFormat, dui->unpackType, data);
     } else {
         MOZ_ASSERT(depth == 1);
         gl->fTexImage2D(target.get(), level, dui->internalFormat, width, height, border,
                         dui->unpackFormat, dui->unpackType, data);
     }
 
@@ -881,17 +859,17 @@ DoTexImage(gl::GLContext* gl, TexImageTa
 
 GLenum
 DoTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLint xOffset,
               GLint yOffset, GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
               const webgl::PackingInfo& pi, const void* data)
 {
     gl::GLContext::LocalErrorScope errorScope(*gl);
 
-    if (Is3D(target)) {
+    if (IsTarget3D(target)) {
         gl->fTexSubImage3D(target.get(), level, xOffset, yOffset, zOffset, width, height,
                            depth, pi.format, pi.type, data);
     } else {
         MOZ_ASSERT(zOffset == 0);
         MOZ_ASSERT(depth == 1);
         gl->fTexSubImage2D(target.get(), level, xOffset, yOffset, width, height,
                            pi.format, pi.type, data);
     }
@@ -903,17 +881,17 @@ static inline GLenum
 DoCompressedTexImage(gl::GLContext* gl, TexImageTarget target, GLint level,
                      GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth,
                      GLsizei dataSize, const void* data)
 {
     const GLint border = 0;
 
     gl::GLContext::LocalErrorScope errorScope(*gl);
 
-    if (Is3D(target)) {
+    if (IsTarget3D(target)) {
         gl->fCompressedTexImage3D(target.get(), level, internalFormat, width, height,
                                   depth, border, dataSize, data);
     } else {
         MOZ_ASSERT(depth == 1);
         gl->fCompressedTexImage2D(target.get(), level, internalFormat, width, height,
                                   border, dataSize, data);
     }
 
@@ -923,17 +901,17 @@ DoCompressedTexImage(gl::GLContext* gl, 
 GLenum
 DoCompressedTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level,
                         GLint xOffset, GLint yOffset, GLint zOffset, GLsizei width,
                         GLsizei height, GLsizei depth, GLenum sizedUnpackFormat,
                         GLsizei dataSize, const void* data)
 {
     gl::GLContext::LocalErrorScope errorScope(*gl);
 
-    if (Is3D(target)) {
+    if (IsTarget3D(target)) {
         gl->fCompressedTexSubImage3D(target.get(), level, xOffset, yOffset, zOffset,
                                      width, height, depth, sizedUnpackFormat, dataSize,
                                      data);
     } else {
         MOZ_ASSERT(zOffset == 0);
         MOZ_ASSERT(depth == 1);
         gl->fCompressedTexSubImage2D(target.get(), level, xOffset, yOffset, width,
                                      height, sizedUnpackFormat, dataSize, data);
@@ -945,31 +923,31 @@ DoCompressedTexSubImage(gl::GLContext* g
 static inline GLenum
 DoCopyTexImage2D(gl::GLContext* gl, TexImageTarget target, GLint level,
                  GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
 {
     const GLint border = 0;
 
     gl::GLContext::LocalErrorScope errorScope(*gl);
 
-    MOZ_ASSERT(!Is3D(target));
+    MOZ_ASSERT(!IsTarget3D(target));
     gl->fCopyTexImage2D(target.get(), level, internalFormat, x, y, width, height,
                         border);
 
     return errorScope.GetError();
 }
 
 static inline GLenum
 DoCopyTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLint xOffset,
                   GLint yOffset, GLint zOffset, GLint x, GLint y, GLsizei width,
                   GLsizei height)
 {
     gl::GLContext::LocalErrorScope errorScope(*gl);
 
-    if (Is3D(target)) {
+    if (IsTarget3D(target)) {
         gl->fCopyTexSubImage3D(target.get(), level, xOffset, yOffset, zOffset, x, y,
                                width, height);
     } else {
         MOZ_ASSERT(zOffset == 0);
         gl->fCopyTexSubImage2D(target.get(), level, xOffset, yOffset, x, y, width,
                                height);
     }
 
@@ -1258,17 +1236,17 @@ WebGLTexture::TexImage(const char* funcN
     // Check that source and dest info are compatible
     auto dstFormat = dstUsage->format;
 
     if (!ValidateTargetForFormat(funcName, mContext, target, dstFormat))
         return;
 
     if (!mContext->IsWebGL2() && dstFormat->d) {
         if (target != LOCAL_GL_TEXTURE_2D ||
-            blob->mHasData ||
+            blob->HasData() ||
             level != 0)
         {
             mContext->ErrorInvalidOperation("%s: With format %s, this function may only"
                                             " be called with target=TEXTURE_2D,"
                                             " data=null, and level=0.",
                                             funcName, dstFormat->name);
             return;
         }
@@ -1279,17 +1257,17 @@ WebGLTexture::TexImage(const char* funcN
 
     MOZ_ALWAYS_TRUE( mContext->gl->MakeCurrent() );
     MOZ_ASSERT(mContext->gl->IsCurrent());
 
     // It's tempting to do allocation first, and TexSubImage second, but this is generally
     // slower.
 
     const ImageInfo newImageInfo(dstUsage, blob->mWidth, blob->mHeight, blob->mDepth,
-                                 blob->mHasData);
+                                 blob->HasData());
 
     const bool isSubImage = false;
     const bool needsRespec = (imageInfo->mWidth  != newImageInfo.mWidth ||
                               imageInfo->mHeight != newImageInfo.mHeight ||
                               imageInfo->mDepth  != newImageInfo.mDepth ||
                               imageInfo->mFormat != newImageInfo.mFormat);
     const GLint xOffset = 0;
     const GLint yOffset = 0;
--- a/dom/canvas/test/imagebitmap_extensions.js
+++ b/dom/canvas/test/imagebitmap_extensions.js
@@ -118,33 +118,33 @@ function testColorConversions() {
   return Promise.all([// From RGBA32
                       testColorConversion("RGBA32", "RGBA32"),
                       testColorConversion("RGBA32", "BGRA32"),
                       testColorConversion("RGBA32", "RGB24"),
                       testColorConversion("RGBA32", "BGR24"),
                       testColorConversion("RGBA32", "GRAY8"),
                       testColorConversion("RGBA32", "YUV444P"),
                       testColorConversion("RGBA32", "YUV422P"),
-                      testColorConversion("RGBA32", "YUV420P"),
+                      testColorConversion("RGBA32", "YUV420P", 2),
                       testColorConversion("RGBA32", "YUV420SP_NV12"),
                       testColorConversion("RGBA32", "YUV420SP_NV21"),
                       testColorConversion("RGBA32", "HSV", 0.01),
                       testColorConversion("RGBA32", "Lab", 0.5),
 
                       // From BGRA32
                       testColorConversion("BGRA32", "RGBA32"),
                       testColorConversion("BGRA32", "BGRA32"),
                       testColorConversion("BGRA32", "RGB24"),
                       testColorConversion("BGRA32", "BGR24"),
                       testColorConversion("BGRA32", "GRAY8"),
                       testColorConversion("BGRA32", "YUV444P", 3),
-                      testColorConversion("BGRA32", "YUV422P"),
-                      testColorConversion("BGRA32", "YUV420P"),
-                      testColorConversion("BGRA32", "YUV420SP_NV12"),
-                      testColorConversion("BGRA32", "YUV420SP_NV21"),
+                      testColorConversion("BGRA32", "YUV422P", 2),
+                      testColorConversion("BGRA32", "YUV420P", 2),
+                      testColorConversion("BGRA32", "YUV420SP_NV12", 2),
+                      testColorConversion("BGRA32", "YUV420SP_NV21", 2),
                       testColorConversion("BGRA32", "HSV", 0.01),
                       testColorConversion("BGRA32", "Lab", 0.5),
 
                       // From RGB24
                       testColorConversion("RGB24", "RGBA32"),
                       testColorConversion("RGB24", "BGRA32"),
                       testColorConversion("RGB24", "RGB24"),
                       testColorConversion("RGB24", "BGR24"),
@@ -173,73 +173,73 @@ function testColorConversions() {
 
                       // From YUV444P
                       testColorConversion("YUV444P", "RGBA32"),
                       testColorConversion("YUV444P", "BGRA32"),
                       testColorConversion("YUV444P", "RGB24"),
                       testColorConversion("YUV444P", "BGR24"),
                       testColorConversion("YUV444P", "GRAY8"),
                       testColorConversion("YUV444P", "YUV444P"),
-                      testColorConversion("YUV444P", "YUV422P", 3),
+                      testColorConversion("YUV444P", "YUV422P", 4),
                       testColorConversion("YUV444P", "YUV420P", 3),
                       testColorConversion("YUV444P", "YUV420SP_NV12", 3),
                       testColorConversion("YUV444P", "YUV420SP_NV21", 3),
                       testColorConversion("YUV444P", "HSV", 0.01),
                       testColorConversion("YUV444P", "Lab", 0.01),
 
                       // From YUV422P
                       testColorConversion("YUV422P", "RGBA32"),
-                      testColorConversion("YUV422P", "BGRA32"),
+                      testColorConversion("YUV422P", "BGRA32", 2),
                       testColorConversion("YUV422P", "RGB24"),
                       testColorConversion("YUV422P", "BGR24"),
                       testColorConversion("YUV422P", "GRAY8"),
                       testColorConversion("YUV422P", "YUV444P", 3),
                       testColorConversion("YUV422P", "YUV422P"),
                       testColorConversion("YUV422P", "YUV420P"),
                       testColorConversion("YUV422P", "YUV420SP_NV12"),
                       testColorConversion("YUV422P", "YUV420SP_NV21"),
                       testColorConversion("YUV422P", "HSV", 0.01),
                       testColorConversion("YUV422P", "Lab", 0.01),
 
                       // From YUV420P
-                      testColorConversion("YUV420P", "RGBA32"),
-                      testColorConversion("YUV420P", "BGRA32"),
+                      testColorConversion("YUV420P", "RGBA32", 2),
+                      testColorConversion("YUV420P", "BGRA32", 2),
                       testColorConversion("YUV420P", "RGB24"),
                       testColorConversion("YUV420P", "BGR24"),
                       testColorConversion("YUV420P", "GRAY8"),
                       testColorConversion("YUV420P", "YUV444P", 3),
-                      testColorConversion("YUV420P", "YUV422P"),
+                      testColorConversion("YUV420P", "YUV422P", 1),
                       testColorConversion("YUV420P", "YUV420P"),
                       testColorConversion("YUV420P", "YUV420SP_NV12"),
                       testColorConversion("YUV420P", "YUV420SP_NV21"),
                       testColorConversion("YUV420P", "HSV", 0.01),
                       testColorConversion("YUV420P", "Lab", 0.01),
 
                       // From NV12
                       testColorConversion("YUV420SP_NV12", "RGBA32"),
-                      testColorConversion("YUV420SP_NV12", "BGRA32"),
+                      testColorConversion("YUV420SP_NV12", "BGRA32", 2),
                       testColorConversion("YUV420SP_NV12", "RGB24"),
                       testColorConversion("YUV420SP_NV12", "BGR24"),
                       testColorConversion("YUV420SP_NV12", "GRAY8"),
                       testColorConversion("YUV420SP_NV12", "YUV444P", 3),
-                      testColorConversion("YUV420SP_NV12", "YUV422P"),
+                      testColorConversion("YUV420SP_NV12", "YUV422P", 1),
                       testColorConversion("YUV420SP_NV12", "YUV420P"),
                       testColorConversion("YUV420SP_NV12", "YUV420SP_NV12"),
                       testColorConversion("YUV420SP_NV12", "YUV420SP_NV21"),
                       testColorConversion("YUV420SP_NV12", "HSV", 0.01),
                       testColorConversion("YUV420SP_NV12", "Lab", 0.01),
 
                       // From NV21
                       testColorConversion("YUV420SP_NV21", "RGBA32"),
-                      testColorConversion("YUV420SP_NV21", "BGRA32"),
+                      testColorConversion("YUV420SP_NV21", "BGRA32", 2),
                       testColorConversion("YUV420SP_NV21", "RGB24"),
                       testColorConversion("YUV420SP_NV21", "BGR24"),
                       testColorConversion("YUV420SP_NV21", "GRAY8"),
                       testColorConversion("YUV420SP_NV21", "YUV444P", 3),
-                      testColorConversion("YUV420SP_NV21", "YUV422P"),
+                      testColorConversion("YUV420SP_NV21", "YUV422P", 1),
                       testColorConversion("YUV420SP_NV21", "YUV420P"),
                       testColorConversion("YUV420SP_NV21", "YUV420SP_NV12"),
                       testColorConversion("YUV420SP_NV21", "YUV420SP_NV21"),
                       testColorConversion("YUV420SP_NV21", "HSV", 0.01),
                       testColorConversion("YUV420SP_NV21", "Lab", 0.01),
 
                       // From HSV
                       testColorConversion("HSV", "RGBA32"),
--- a/dom/geolocation/nsGeolocation.cpp
+++ b/dom/geolocation/nsGeolocation.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsXULAppAPI.h"
 
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/Telemetry.h"
 
 #include "nsAutoPtr.h"
+#include "nsISettingsService.h"
 
 #include "nsGeolocation.h"
 #include "nsDOMClassInfoID.h"
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsContentPermissionHelper.h"
 #include "nsIDocument.h"
@@ -26,16 +27,17 @@
 #include "mozilla/Hal.h"
 #include "mozilla/Services.h"
 #include "mozilla/unused.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/WeakPtr.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
+#include "mozilla/dom/SettingChangeNotificationBinding.h"
 #include "mozilla/dom/WakeLock.h"
 
 class nsIPrincipal;
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidLocationProvider.h"
 #endif
 
@@ -51,16 +53,19 @@ class nsIPrincipal;
 #include "WindowsLocationProvider.h"
 #include "mozilla/WindowsVersion.h"
 #endif
 
 // Some limit to the number of get or watch geolocation requests
 // that a window can make.
 #define MAX_GEO_REQUESTS_PER_WINDOW  1500
 
+// The settings key.
+#define GEO_SETTINGS_ENABLED          "geolocation.enabled"
+
 using mozilla::Unused;          // <snicker>
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::hal;
 
 class nsGeolocationRequest final
  : public nsIContentPermissionRequest
  , public nsIGeolocationUpdate
@@ -136,16 +141,63 @@ CreatePositionOptionsCopy(const Position
 
   geoOptions->mEnableHighAccuracy = aOptions.mEnableHighAccuracy;
   geoOptions->mMaximumAge = aOptions.mMaximumAge;
   geoOptions->mTimeout = aOptions.mTimeout;
 
   return geoOptions.forget();
 }
 
+class GeolocationSettingsCallback : public nsISettingsServiceCallback
+{
+  virtual ~GeolocationSettingsCallback() {
+    MOZ_COUNT_DTOR(GeolocationSettingsCallback);
+  }
+
+public:
+  NS_DECL_ISUPPORTS
+
+  GeolocationSettingsCallback() {
+    MOZ_COUNT_CTOR(GeolocationSettingsCallback);
+  }
+
+  NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult) override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    // The geolocation is enabled by default:
+    bool value = true;
+    if (aResult.isBoolean()) {
+        value = aResult.toBoolean();
+    }
+
+    MozSettingValue(value);
+    return NS_OK;
+  }
+
+  NS_IMETHOD HandleError(const nsAString& aName) override
+  {
+    NS_WARNING("Unable to get value for '" GEO_SETTINGS_ENABLED "'");
+
+    // Default it's enabled:
+    MozSettingValue(true);
+    return NS_OK;
+  }
+
+  void MozSettingValue(const bool aValue)
+  {
+    RefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService();
+    if (gs) {
+      gs->HandleMozsettingValue(aValue);
+    }
+  }
+};
+
+NS_IMPL_ISUPPORTS(GeolocationSettingsCallback, nsISettingsServiceCallback)
+
 class RequestPromptEvent : public Runnable
 {
 public:
   RequestPromptEvent(nsGeolocationRequest* aRequest, nsWeakPtr aWindow)
     : mRequest(aRequest)
     , mWindow(aWindow)
   {
   }
@@ -321,24 +373,22 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
   NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
   NS_INTERFACE_MAP_ENTRY(nsIGeolocationUpdate)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGeolocationRequest)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGeolocationRequest)
 NS_IMPL_CYCLE_COLLECTION(nsGeolocationRequest, mCallback, mErrorCallback, mLocator)
-
 void
 nsGeolocationRequest::Notify()
 {
   SetTimeoutTimer();
   NotifyErrorAndShutdown(nsIDOMGeoPositionError::TIMEOUT);
 }
-
 void
 nsGeolocationRequest::NotifyErrorAndShutdown(uint16_t aErrorCode)
 {
   MOZ_ASSERT(!mShutdown, "timeout after shutdown");
   if (!mIsWatchPositionRequest) {
     Shutdown();
     mLocator->RemoveRequest(this);
   }
@@ -500,17 +550,16 @@ nsGeolocationRequest::Allow(JS::HandleVa
 
 NS_IMETHODIMP
 nsGeolocationRequest::GetRequester(nsIContentPermissionRequester** aRequester)
 {
   NS_ENSURE_ARG_POINTER(aRequester);
 
   nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
   requester.forget(aRequester);
-
   return NS_OK;
 }
 
 void
 nsGeolocationRequest::SetTimeoutTimer()
 {
   StopTimeoutTimer();
 
@@ -588,34 +637,32 @@ nsGeolocationRequest::SendLocation(nsIDO
     nsIDOMGeoPositionCallback* callback = mCallback.GetXPCOMCallback();
     MOZ_ASSERT(callback);
     callback->HandleEvent(aPosition);
   }
   SetTimeoutTimer();
   MOZ_ASSERT(mShutdown || mIsWatchPositionRequest,
              "non-shutdown getCurrentPosition request after callback!");
 }
-
 nsIPrincipal*
 nsGeolocationRequest::GetPrincipal()
 {
   if (!mLocator) {
     return nullptr;
   }
   return mLocator->GetPrincipal();
 }
 
 NS_IMETHODIMP
 nsGeolocationRequest::Update(nsIDOMGeoPosition* aPosition)
 {
   nsCOMPtr<nsIRunnable> ev = new RequestSendLocationEvent(aPosition, this);
   NS_DispatchToMainThread(ev);
   return NS_OK;
 }
-
 NS_IMETHODIMP
 nsGeolocationRequest::NotifyError(uint16_t aErrorCode)
 {
   MOZ_ASSERT(NS_IsMainThread());
   RefPtr<PositionError> positionError = new PositionError(mLocator, aErrorCode);
   positionError->NotifyCallback(mErrorCallback);
   return NS_OK;
 }
@@ -647,17 +694,16 @@ NS_IMPL_ISUPPORTS(nsGeolocationRequest::
 
 NS_IMETHODIMP
 nsGeolocationRequest::TimerCallbackHolder::Notify(nsITimer*)
 {
   if (mRequest && mRequest->mLocator) {
     RefPtr<nsGeolocationRequest> request(mRequest);
     request->Notify();
   }
-
   return NS_OK;
 }
 
 
 ////////////////////////////////////////////////////
 // nsGeolocationService
 ////////////////////////////////////////////////////
 NS_INTERFACE_MAP_BEGIN(nsGeolocationService)
@@ -666,38 +712,59 @@ NS_INTERFACE_MAP_BEGIN(nsGeolocationServ
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsGeolocationService)
 NS_IMPL_RELEASE(nsGeolocationService)
 
 
 static bool sGeoEnabled = true;
+static bool sGeoInitPending = true;
 static int32_t sProviderTimeout = 6000; // Time, in milliseconds, to wait for the location provider to spin up.
 
 nsresult nsGeolocationService::Init()
 {
   Preferences::AddIntVarCache(&sProviderTimeout, "geo.timeout", sProviderTimeout);
   Preferences::AddBoolVarCache(&sGeoEnabled, "geo.enabled", sGeoEnabled);
 
   if (!sGeoEnabled) {
     return NS_ERROR_FAILURE;
   }
 
   if (XRE_IsContentProcess()) {
+    sGeoInitPending = false;
     return NS_OK;
   }
 
+  // check if the geolocation service is enable from settings
+  nsCOMPtr<nsISettingsService> settings =
+    do_GetService("@mozilla.org/settingsService;1");
+
+  if (settings) {
+    nsCOMPtr<nsISettingsServiceLock> settingsLock;
+    nsresult rv = settings->CreateLock(nullptr, getter_AddRefs(settingsLock));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    RefPtr<GeolocationSettingsCallback> callback = new GeolocationSettingsCallback();
+    rv = settingsLock->Get(GEO_SETTINGS_ENABLED, callback);
+    NS_ENSURE_SUCCESS(rv, rv);
+  } else {
+    // If we cannot obtain the settings service, we continue
+    // assuming that the geolocation is enabled:
+    sGeoInitPending = false;
+  }
+
   // geolocation service can be enabled -> now register observer
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (!obs) {
     return NS_ERROR_FAILURE;
   }
 
   obs->AddObserver(this, "xpcom-shutdown", false);
+  obs->AddObserver(this, "mozsettings-changed", false);
 
 #ifdef MOZ_WIDGET_ANDROID
   mProvider = new AndroidLocationProvider();
 #endif
 
 #ifdef MOZ_WIDGET_GONK
   // GonkGPSGeolocationProvider can be started at boot up time for initialization reasons.
   // do_getService gets hold of the already initialized component and starts
@@ -740,35 +807,82 @@ nsresult nsGeolocationService::Init()
 
   return NS_OK;
 }
 
 nsGeolocationService::~nsGeolocationService()
 {
 }
 
+void
+nsGeolocationService::HandleMozsettingChanged(nsISupports* aSubject)
+{
+    // The string that we're interested in will be a JSON string that looks like:
+    //  {"key":"gelocation.enabled","value":true}
+
+    RootedDictionary<SettingChangeNotification> setting(nsContentUtils::RootingCx());
+    if (!WrappedJSToDictionary(aSubject, setting)) {
+      return;
+    }
+    if (!setting.mKey.EqualsASCII(GEO_SETTINGS_ENABLED)) {
+      return;
+    }
+    if (!setting.mValue.isBoolean()) {
+      return;
+    }
+
+    HandleMozsettingValue(setting.mValue.toBoolean());
+}
+
+void
+nsGeolocationService::HandleMozsettingValue(const bool aValue)
+{
+    if (!aValue) {
+      // turn things off
+      StopDevice();
+      Update(nullptr);
+      mLastPosition.position = nullptr;
+      sGeoEnabled = false;
+    } else {
+      sGeoEnabled = true;
+    }
+
+    if (sGeoInitPending) {
+      sGeoInitPending = false;
+      for (uint32_t i = 0, length = mGeolocators.Length(); i < length; ++i) {
+        mGeolocators[i]->ServiceReady();
+      }
+    }
+}
+
 NS_IMETHODIMP
 nsGeolocationService::Observe(nsISupports* aSubject,
                               const char* aTopic,
                               const char16_t* aData)
 {
   if (!strcmp("xpcom-shutdown", aTopic)) {
     nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
     if (obs) {
       obs->RemoveObserver(this, "xpcom-shutdown");
+      obs->RemoveObserver(this, "mozsettings-changed");
     }
 
     for (uint32_t i = 0; i< mGeolocators.Length(); i++) {
       mGeolocators[i]->Shutdown();
     }
     StopDevice();
 
     return NS_OK;
   }
 
+  if (!strcmp("mozsettings-changed", aTopic)) {
+    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();
         return NS_OK;
       }
 
@@ -782,31 +896,27 @@ nsGeolocationService::Observe(nsISupport
 }
 
 NS_IMETHODIMP
 nsGeolocationService::Update(nsIDOMGeoPosition *aSomewhere)
 {
   if (aSomewhere) {
     SetCachedPosition(aSomewhere);
   }
-
   for (uint32_t i = 0; i< mGeolocators.Length(); i++) {
     mGeolocators[i]->Update(aSomewhere);
   }
-
   return NS_OK;
 }
-
 NS_IMETHODIMP
 nsGeolocationService::NotifyError(uint16_t aErrorCode)
 {
   for (uint32_t i = 0; i < mGeolocators.Length(); i++) {
     mGeolocators[i]->NotifyError(aErrorCode);
   }
-
   return NS_OK;
 }
 
 void
 nsGeolocationService::SetCachedPosition(nsIDOMGeoPosition* aPosition)
 {
   mLastPosition.position = aPosition;
   mLastPosition.isHighAccuracy = mHigherAccuracy;
@@ -816,17 +926,17 @@ CachedPositionAndAccuracy
 nsGeolocationService::GetCachedPosition()
 {
   return mLastPosition;
 }
 
 nsresult
 nsGeolocationService::StartDevice(nsIPrincipal *aPrincipal)
 {
-  if (!sGeoEnabled) {
+  if (!sGeoEnabled || sGeoInitPending) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // we do not want to keep the geolocation devices online
   // indefinitely.  Close them down after a reasonable period of
   // inactivivity
   SetDisconnectTimer();
 
@@ -867,16 +977,17 @@ void
 nsGeolocationService::StopDisconnectTimer()
 {
   if (mDisconnectTimer) {
     mDisconnectTimer->Cancel();
     mDisconnectTimer = nullptr;
   }
 }
 
+
 void
 nsGeolocationService::SetDisconnectTimer()
 {
   if (!mDisconnectTimer) {
     mDisconnectTimer = do_CreateInstance("@mozilla.org/timer;1");
   } else {
     mDisconnectTimer->Cancel();
   }
@@ -889,47 +1000,51 @@ nsGeolocationService::SetDisconnectTimer
 bool
 nsGeolocationService::HighAccuracyRequested()
 {
   for (uint32_t i = 0; i < mGeolocators.Length(); i++) {
     if (mGeolocators[i]->HighAccuracyRequested()) {
       return true;
     }
   }
-
   return false;
 }
 
 void
 nsGeolocationService::UpdateAccuracy(bool aForceHigh)
 {
   bool highRequired = aForceHigh || HighAccuracyRequested();
 
   if (XRE_IsContentProcess()) {
     ContentChild* cpc = ContentChild::GetSingleton();
     if (cpc->IsAlive()) {
       cpc->SendSetGeolocationHigherAccuracy(highRequired);
     }
-
     return;
   }
 
-  mProvider->SetHighAccuracy(!mHigherAccuracy && highRequired);
+  if (!mHigherAccuracy && highRequired) {
+      mProvider->SetHighAccuracy(true);
+  }
+
+  if (mHigherAccuracy && !highRequired) {
+      mProvider->SetHighAccuracy(false);
+  }
+
   mHigherAccuracy = highRequired;
 }
 
 void
 nsGeolocationService::StopDevice()
 {
   StopDisconnectTimer();
 
   if (XRE_IsContentProcess()) {
     ContentChild* cpc = ContentChild::GetSingleton();
     cpc->SendRemoveGeolocationListener();
-
     return; // bail early
   }
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (!obs) {
     return;
   }
 
@@ -955,20 +1070,18 @@ nsGeolocationService::GetGeolocationServ
     result = nsGeolocationService::sService;
     return result.forget();
   }
 
   result = new nsGeolocationService();
   if (NS_FAILED(result->Init())) {
     return nullptr;
   }
-
   ClearOnShutdown(&nsGeolocationService::sService);
   nsGeolocationService::sService = result;
-
   return result.forget();
 }
 
 void
 nsGeolocationService::AddLocator(Geolocation* aLocator)
 {
   mGeolocators.AppendElement(aLocator);
 }
@@ -1061,31 +1174,31 @@ Geolocation::Init(nsPIDOMWindowInner* aC
 
   // If no aContentDom was passed into us, we are being used
   // by chrome/c++ and have no mOwner, no mPrincipal, and no need
   // to prompt.
   mService = nsGeolocationService::GetGeolocationService();
   if (mService) {
     mService->AddLocator(this);
   }
-
   return NS_OK;
 }
 
 bool
 Geolocation::ContainsRequest(nsGeolocationRequest* aRequest)
 {
-  if (aRequest->IsWatch() && mWatchingCallbacks.Contains(aRequest)) {
+  if (aRequest->IsWatch()) {
+    if (mWatchingCallbacks.Contains(aRequest)) {
 	return true;
+    }
+  } else {
+    if (mPendingCallbacks.Contains(aRequest)) {
+        return true;
+    }
   }
-
-  if (mPendingCallbacks.Contains(aRequest)) {
-    return true;
-  }
-
   return false;
 }
 
 
 NS_IMETHODIMP
 Geolocation::HandleEvent(nsIDOMEvent* aEvent)
 {
 
@@ -1099,37 +1212,33 @@ Geolocation::HandleEvent(nsIDOMEvent* aE
   MOZ_ASSERT(doc);
 
   if (doc->Hidden()) {
     WakeLockInformation info;
     GetWakeLockInfo(NS_LITERAL_STRING("gps"), &info);
 
     MOZ_ASSERT(XRE_IsContentProcess());
     ContentChild* cpc = ContentChild::GetSingleton();
-
     if (!info.lockingProcesses().Contains(cpc->GetID())) {
       cpc->SendRemoveGeolocationListener();
       mService->StopDisconnectTimer();
     }
-
-    return NS_OK;
-  }
-
-  mService->SetDisconnectTimer();
+  } else {
+    mService->SetDisconnectTimer();
 
-  // We will unconditionally allow all the requests in the callbacks
-  // because if a request is put into either of these two callbacks,
-  // it means that it has been allowed before.
-  // That's why when we resume them, we unconditionally allow them again.
-  for (uint32_t i = 0, length = mWatchingCallbacks.Length(); i < length; ++i) {
-    mWatchingCallbacks[i]->Allow(JS::UndefinedHandleValue);
-  }
-
-  for (uint32_t i = 0, length = mPendingCallbacks.Length(); i < length; ++i) {
-    mPendingCallbacks[i]->Allow(JS::UndefinedHandleValue);
+    // We will unconditionally allow all the requests in the callbacks
+    // because if a request is put into either of these two callbacks,
+    // it means that it has been allowed before.
+    // That's why when we resume them, we unconditionally allow them again.
+    for (uint32_t i = 0, length = mWatchingCallbacks.Length(); i < length; ++i) {
+      mWatchingCallbacks[i]->Allow(JS::UndefinedHandleValue);
+    }
+    for (uint32_t i = 0, length = mPendingCallbacks.Length(); i < length; ++i) {
+      mPendingCallbacks[i]->Allow(JS::UndefinedHandleValue);
+    }
   }
 
   return NS_OK;
 }
 
 void
 Geolocation::Shutdown()
 {
@@ -1220,28 +1329,25 @@ Geolocation::Update(nsIDOMGeoPosition *a
     mPendingCallbacks[i-1]->Update(aSomewhere);
     RemoveRequest(mPendingCallbacks[i-1]);
   }
 
   // notify everyone that is watching
   for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
     mWatchingCallbacks[i]->Update(aSomewhere);
   }
-
   return NS_OK;
 }
-
 NS_IMETHODIMP
 Geolocation::NotifyError(uint16_t aErrorCode)
 {
   if (!WindowOwnerStillExists()) {
     Shutdown();
     return NS_OK;
   }
-
   mozilla::Telemetry::Accumulate(mozilla::Telemetry::GEOLOCATION_ERROR, true);
 
   for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) {
     mPendingCallbacks[i-1]->NotifyErrorAndShutdown(aErrorCode);
     //NotifyErrorAndShutdown() removes the request from the array
   }
 
   // notify everyone that is watching
@@ -1255,29 +1361,27 @@ Geolocation::NotifyError(uint16_t aError
 bool
 Geolocation::IsAlreadyCleared(nsGeolocationRequest* aRequest)
 {
   for (uint32_t i = 0, length = mClearedWatchIDs.Length(); i < length; ++i) {
     if (mClearedWatchIDs[i] == aRequest->WatchId()) {
       return true;
     }
   }
-
   return false;
 }
 
 bool
 Geolocation::ClearPendingRequest(nsGeolocationRequest* aRequest)
 {
   if (aRequest->IsWatch() && this->IsAlreadyCleared(aRequest)) {
     this->NotifyAllowedRequest(aRequest);
     this->ClearWatch(aRequest->WatchId());
     return true;
   }
-
   return false;
 }
 
 void
 Geolocation::GetCurrentPosition(PositionCallback& aCallback,
                                 PositionErrorCallback* aErrorCallback,
                                 const PositionOptions& aOptions,
                                 ErrorResult& aRv)
@@ -1330,16 +1434,21 @@ Geolocation::GetCurrentPosition(GeoPosit
     NS_DispatchToMainThread(ev);
     return NS_OK;
   }
 
   if (!mOwner && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
     return NS_ERROR_FAILURE;
   }
 
+  if (sGeoInitPending) {
+    mPendingRequests.AppendElement(request);
+    return NS_OK;
+  }
+
   return GetCurrentPositionReady(request);
 }
 
 nsresult
 Geolocation::GetCurrentPositionReady(nsGeolocationRequest* aRequest)
 {
   if (mOwner) {
     if (!RegisterRequestWithPrompt(aRequest)) {
@@ -1419,16 +1528,21 @@ Geolocation::WatchPosition(GeoPositionCa
     NS_DispatchToMainThread(ev);
     return NS_OK;
   }
 
   if (!mOwner && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
     return NS_ERROR_FAILURE;
   }
 
+  if (sGeoInitPending) {
+    mPendingRequests.AppendElement(request);
+    return NS_OK;
+  }
+
   return WatchPositionReady(request);
 }
 
 nsresult
 Geolocation::WatchPositionReady(nsGeolocationRequest* aRequest)
 {
   if (mOwner) {
     if (!RegisterRequestWithPrompt(aRequest))
--- a/dom/geolocation/nsGeolocation.h
+++ b/dom/geolocation/nsGeolocation.h
@@ -67,16 +67,19 @@ public:
   NS_DECL_NSIOBSERVER
 
   nsGeolocationService() {
       mHigherAccuracy = false;
   }
 
   nsresult Init();
 
+  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();
 
   // Find and startup a geolocation device (gps, nmea, etc.)
--- a/dom/html/test/test_bug558788-1.html
+++ b/dom/html/test/test_bug558788-1.html
@@ -149,23 +149,24 @@ function checkInputURL()
   element.focus();
 
   synthesizeKey("h", {});
   checkInvalidApplies(element);
 
   sendString("ttp://mozilla.org");
   checkValidApplies(element);
 
-  for (var i=0; i<13; ++i) {
+  for (var i=0; i<10; ++i) {
     synthesizeKey("VK_BACK_SPACE", {});
     checkValidApplies(element);
   }
 
   synthesizeKey("VK_BACK_SPACE", {});
-  for (var i=0; i<4; ++i) {
+  // "http://" is now invalid
+  for (var i=0; i<7; ++i) {
     checkInvalidApplies(element);
     synthesizeKey("VK_BACK_SPACE", {});
   }
   checkValidApplies(element);
 
   gContent.removeChild(element);
 }
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -3,20 +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/. */
 
 #ifdef MOZ_WIDGET_GTK
 #include <gtk/gtk.h>
 #endif
 
-#ifdef MOZ_WIDGET_QT
-#include "nsQAppInstance.h"
-#endif
-
 #include "ContentChild.h"
 
 #include "BlobChild.h"
 #include "CrashReporterChild.h"
 #include "GeckoProfiler.h"
 #include "TabChild.h"
 #include "HandlerServiceChild.h"
 
@@ -614,21 +610,16 @@ ContentChild::Init(MessageLoop* aIOLoop,
     };
     char** argvp = argv;
     gtk_init(&argc, &argvp);
   } else {
     gtk_init(nullptr, nullptr);
   }
 #endif
 
-#ifdef MOZ_WIDGET_QT
-  // sigh, seriously
-  nsQAppInstance::AddRef();
-#endif
-
 #ifdef MOZ_X11
   // Do this after initializing GDK, or GDK will install its own handler.
   XRE_InstallX11ErrorHandler();
 #endif
 
   NS_ASSERTION(!sSingleton, "only one ContentChild per child");
 
   // Once we start sending IPC messages, we need the thread manager to be
@@ -1036,24 +1027,16 @@ ContentChild::InitXPCOM()
     initialData.Read(jsapi.cx(), &data, rv);
     if (NS_WARN_IF(rv.Failed())) {
       MOZ_CRASH();
     }
     ProcessGlobal* global = ProcessGlobal::Get();
     global->SetInitialProcessData(data);
   }
 
-  // Loading the ServiceWorker configuration.
-  ServiceWorkerConfiguration configuration;
-  SendGetServiceWorkerConfiguration(&configuration);
-
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  MOZ_ASSERT(swm);
-  swm->LoadRegistrations(configuration.serviceWorkerRegistrations());
-
   InitOnContentProcessCreated();
 }
 
 PMemoryReportRequestChild*
 ContentChild::AllocPMemoryReportRequestChild(const uint32_t& aGeneration,
                                              const bool &aAnonymize,
                                              const bool &aMinimizeMemoryUsage,
                                              const MaybeFileDesc& aDMDFile)
@@ -2638,16 +2621,25 @@ ContentChild::RecvAppInit()
     MessageLoop::current()->PostTask(NewRunnableFunction(OnFinishNuwaPreparation));
   }
 #endif
 
   return true;
 }
 
 bool
+ContentChild::RecvInitServiceWorkers(const ServiceWorkerConfiguration& aConfig)
+{
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  MOZ_ASSERT(swm);
+  swm->LoadRegistrations(aConfig.serviceWorkerRegistrations());
+  return true;
+}
+
+bool
 ContentChild::RecvLastPrivateDocShellDestroyed()
 {
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   obs->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
   return true;
 }
 
 bool
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -452,16 +452,19 @@ public:
   virtual bool RecvCycleCollect() override;
 
   virtual bool RecvAppInfo(const nsCString& version, const nsCString& buildID,
                            const nsCString& name, const nsCString& UAName,
                            const nsCString& ID, const nsCString& vendor) override;
 
   virtual bool RecvAppInit() override;
 
+  virtual bool
+  RecvInitServiceWorkers(const ServiceWorkerConfiguration& aConfig) override;
+
   virtual bool RecvLastPrivateDocShellDestroyed() override;
 
   virtual bool RecvVolumes(InfallibleTArray<VolumeInfo>&& aVolumes) override;
 
   virtual bool RecvFilePathUpdate(const nsString& aStorageType,
                                   const nsString& aStorageName,
                                   const nsString& aPath,
                                   const nsCString& aReason) override;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2506,16 +2506,24 @@ ContentParent::InitInternal(ProcessPrior
   nsID id;
   nsString sessionName;
   nsString iconPath;
   if (NS_SUCCEEDED(mozilla::widget::GetAudioSessionData(id, sessionName,
                                                         iconPath))) {
     Unused << SendSetAudioSessionData(id, sessionName, iconPath);
   }
 #endif
+
+  RefPtr<ServiceWorkerRegistrar> swr = ServiceWorkerRegistrar::Get();
+  MOZ_ASSERT(swr);
+
+  nsTArray<ServiceWorkerRegistrationData> registrations;
+  swr->GetRegistrations(registrations);
+
+  Unused << SendInitServiceWorkers(ServiceWorkerConfiguration(registrations));
 }
 
 bool
 ContentParent::IsAlive() const
 {
   return mIsAlive;
 }
 
@@ -5499,28 +5507,16 @@ ContentParent::PermissionManagerRelease(
   if (appId != nsIScriptSecurityManager::NO_APP_ID && permMgr) {
     permMgr->ReleaseAppId(appId);
     return true;
   }
   return false;
 }
 
 bool
-ContentParent::RecvGetServiceWorkerConfiguration(ServiceWorkerConfiguration* aConfig)
-{
-  MOZ_ASSERT(XRE_IsParentProcess());
-
-  RefPtr<ServiceWorkerRegistrar> swr = ServiceWorkerRegistrar::Get();
-  MOZ_ASSERT(swr);
-
-  swr->GetRegistrations(aConfig->serviceWorkerRegistrations());
-  return true;
-}
-
-bool
 ContentParent::RecvProfile(const nsCString& aProfile)
 {
 #ifdef MOZ_ENABLE_PROFILER_SPS
   if (NS_WARN_IF(!mGatherer)) {
     return true;
   }
   mProfile = aProfile;
   mGatherer->GatheredOOPProfile();
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1130,19 +1130,16 @@ private:
 
   virtual PWebrtcGlobalParent* AllocPWebrtcGlobalParent() override;
   virtual bool DeallocPWebrtcGlobalParent(PWebrtcGlobalParent *aActor) override;
 
 
   virtual bool RecvUpdateDropEffect(const uint32_t& aDragAction,
                                     const uint32_t& aDropEffect) override;
 
-  virtual bool
-  RecvGetServiceWorkerConfiguration(ServiceWorkerConfiguration* aConfig) override;
-
   virtual bool RecvProfile(const nsCString& aProfile) override;
 
   virtual bool RecvGetGraphicsDeviceInitData(DeviceInitData* aOut) override;
 
   void StartProfiler(nsIProfilerStartParams* aParams);
 
   virtual bool RecvGetDeviceStorageLocation(const nsString& aType,
                                             nsString* aPath) override;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -521,16 +521,21 @@ child:
      * Start accessibility engine in content process.
      */
     async ActivateA11y();
 
     async AppInfo(nsCString version, nsCString buildID, nsCString name, nsCString UAName,
                   nsCString ID, nsCString vendor);
     async AppInit();
 
+    /**
+     * Send ServiceWorkerRegistrationData to child process.
+     */
+    async InitServiceWorkers(ServiceWorkerConfiguration aConfig);
+
     // Notify child that last-pb-context-exited notification was observed
     async LastPrivateDocShellDestroyed();
 
     async FilePathUpdate(nsString storageType, nsString storageName, nsString filepath,
                          nsCString reasons);
 
     // Note: Any changes to this structure should also be changed in
     // VolumeInfo above.
@@ -1079,22 +1084,16 @@ parent:
      *
      * NOTE: The principal is untrusted in the parent process. Only
      *       principals that can live in the content process should
      *       provided.
      */
     async PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal,
                                     TabId tabId);
 
-    /**
-     * Send ServiceWorkerRegistrationData to child process.
-     */
-    sync GetServiceWorkerConfiguration()
-        returns (ServiceWorkerConfiguration aConfig);
-
     async Profile(nsCString aProfile);
 
     /**
      * Request graphics initialization information from the parent.
      */
     sync GetGraphicsDeviceInitData()
         returns (DeviceInitData aData);
 
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -163,17 +163,17 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_
 
 if CONFIG['OS_ARCH'] != 'WINNT':
     LOCAL_INCLUDES += [
         '/modules/libjar',
     ]
 
 DEFINES['BIN_SUFFIX'] = '"%s"' % CONFIG['BIN_SUFFIX']
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gonk', 'qt'):
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gonk'):
     DEFINES['MOZ_ENABLE_FREETYPE'] = True
 
 if CONFIG['MOZ_TOOLKIT_SEARCH']:
     DEFINES['MOZ_TOOLKIT_SEARCH'] = True
 
 JAR_MANIFESTS += ['jar.mn']
 
 BROWSER_CHROME_MANIFESTS += ['tests/browser.ini']
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -73,16 +73,25 @@ FullscreenDeniedNotInputDriven=Request f
 FullscreenDeniedNotInDocument=Request for fullscreen was denied because requesting element is no longer in its document.
 FullscreenDeniedMovedDocument=Request for fullscreen was denied because requesting element has moved document.
 FullscreenDeniedLostWindow=Request for fullscreen was denied because we no longer have a window.
 FullscreenDeniedSubDocFullscreen=Request for fullscreen was denied because a subdocument of the document requesting fullscreen is already fullscreen.
 FullscreenDeniedNotDescendant=Request for fullscreen was denied because requesting element is not a descendant of the current fullscreen element.
 FullscreenDeniedNotFocusedTab=Request for fullscreen was denied because requesting element is not in the currently focused tab.
 RemovedFullscreenElement=Exited fullscreen because fullscreen element was removed from document.
 FocusedWindowedPluginWhileFullscreen=Exited fullscreen because windowed plugin was focused.
+PointerLockDeniedDisabled=Request for pointer lock was denied because Pointer Lock API is disabled by user preference.
+PointerLockDeniedInUse=Request for pointer lock was denied because the pointer is currently controlled by a different document.
+PointerLockDeniedNotInDocument=Request for pointer lock was denied because the requesting element is not in a document.
+PointerLockDeniedSandboxed=Request for pointer lock was denied because Pointer Lock API is restricted via sandbox.
+PointerLockDeniedHidden=Request for pointer lock was denied because the document is not visible.
+PointerLockDeniedNotFocused=Request for pointer lock was denied because the document is not focused.
+PointerLockDeniedMovedDocument=Request for pointer lock was denied because the requesting element has moved document.
+PointerLockDeniedNotInputDriven=Request for pointer lock was denied because Element.requestPointerLock() was not called from inside a short running user-generated event handler, and the document is not in full screen.
+PointerLockDeniedFailedToLock=Request for pointer lock was denied because the browser failed to lock the pointer.
 HTMLSyncXHRWarning=HTML parsing in XMLHttpRequest is not supported in the synchronous mode.
 InvalidRedirectChannelWarning=Unable to redirect to %S because the channel doesn’t implement nsIWritablePropertyBag2.
 ResponseTypeSyncXHRWarning=Use of XMLHttpRequest’s responseType attribute is no longer supported in the synchronous mode in window context.
 TimeoutSyncXHRWarning=Use of XMLHttpRequest’s timeout attribute is not supported in the synchronous mode in window context.
 JSONCharsetWarning=An attempt was made to declare a non-UTF-8 encoding for JSON retrieved using XMLHttpRequest. Only UTF-8 is supported for decoding JSON.
 # LOCALIZATION NOTE: Do not translate AudioBufferSourceNode
 MediaBufferSourceNodeResampleOutOfMemory=Insufficient memory to resample the AudioBufferSourceNode for playback.
 # LOCALIZATION NOTE: Do not translate decodeAudioData.
--- a/dom/moz.build
+++ b/dom/moz.build
@@ -155,11 +155,11 @@ if CONFIG['MOZ_B2G']:
 
 DIRS += ['presentation']
 
 TEST_DIRS += [
     'tests',
     'imptests',
 ]
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'cocoa', 'windows', 'android', 'qt'):
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'cocoa', 'windows', 'android'):
     TEST_DIRS += ['plugins/test']
 
--- a/dom/plugins/base/moz.build
+++ b/dom/plugins/base/moz.build
@@ -72,20 +72,16 @@ else:
     UNIFIED_SOURCES += [
         'nsPluginsDirUnix.cpp',
     ]
     if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
         # This file cannot be built in unified mode because of name clashes in X11 headers.
         SOURCES += [
             'nsPluginNativeWindowGtk.cpp',
         ]
-    elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
-        UNIFIED_SOURCES += [
-            'nsPluginNativeWindowQt.cpp',
-        ]
     else:
         UNIFIED_SOURCES += [
             'nsPluginNativeWindow.cpp',
         ]
 
 LOCAL_INCLUDES += [
     '/dom/base',
     '/dom/plugins/ipc',
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -1806,17 +1806,17 @@ NPError
 #endif
     return NPERR_GENERIC_ERROR;
   }
 
   case NPNVxtAppContext:
     return NPERR_GENERIC_ERROR;
 #endif
 
-#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
   case NPNVnetscapeWindow: {
     if (!npp || !npp->ndata)
       return NPERR_INVALID_INSTANCE_ERROR;
 
     nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata;
 
     RefPtr<nsPluginInstanceOwner> owner = inst->GetOwner();
     NS_ENSURE_TRUE(owner, NPERR_NO_ERROR);
@@ -1855,34 +1855,25 @@ NPError
     return NPERR_NO_ERROR;
   }
 
   case NPNVToolkit: {
 #ifdef MOZ_WIDGET_GTK
     *((NPNToolkitType*)result) = NPNVGtk2;
 #endif
 
-#ifdef MOZ_WIDGET_QT
-    /* Fake toolkit so flash plugin works */
-    *((NPNToolkitType*)result) = NPNVGtk2;
-#endif
     if (*(NPNToolkitType*)result)
         return NPERR_NO_ERROR;
 
     return NPERR_GENERIC_ERROR;
   }
 
   case NPNVSupportsXEmbedBool: {
 #ifdef MOZ_WIDGET_GTK
     *(NPBool*)result = true;
-#elif defined(MOZ_WIDGET_QT)
-    // Desktop Flash fail to initialize if browser does not support NPNVSupportsXEmbedBool
-    // even when wmode!=windowed, lets return fake support
-    fprintf(stderr, "Fake support for XEmbed plugins in Qt port\n");
-    *(NPBool*)result = true;
 #else
     *(NPBool*)result = false;
 #endif
     return NPERR_NO_ERROR;
   }
 
   case NPNVWindowNPObject: {
     *(NPObject **)result = _getwindowobject(npp);
@@ -1893,17 +1884,17 @@ NPError
   case NPNVPluginElementNPObject: {
     *(NPObject **)result = _getpluginelement(npp);
 
     return *(NPObject **)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
   }
 
   case NPNVSupportsWindowless: {
 #if defined(XP_WIN) || defined(XP_MACOSX) || \
-    (defined(MOZ_X11) && (defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)))
+    (defined(MOZ_X11) && defined(MOZ_WIDGET_GTK))
     *(NPBool*)result = true;
 #else
     *(NPBool*)result = false;
 #endif
     return NPERR_NO_ERROR;
   }
 
   case NPNVprivateModeBool: {
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -758,17 +758,17 @@ NS_IMETHODIMP nsPluginInstanceOwner::Get
   nsCOMPtr<nsIWidget> widget = GetRootWidgetForPluginFrame(mPluginFrame);
   if (widget) {
     *pvalue = widget->GetNativeData(NS_NATIVE_SHAREABLE_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)
+#elif defined(MOZ_WIDGET_GTK) && defined(MOZ_X11)
   // X11 window managers want the toplevel window for WM_TRANSIENT_FOR.
   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;
@@ -2611,18 +2611,16 @@ nsEventStatus nsPluginInstanceOwner::Pro
         const WidgetMouseEvent& mouseEvent = *anEvent.AsMouseEvent();
         // Get reference point relative to screen:
         LayoutDeviceIntPoint rootPoint(-1, -1);
         if (widget) {
           rootPoint = anEvent.mRefPoint + widget->WidgetToScreenOffset();
         }
 #ifdef MOZ_WIDGET_GTK
         Window root = GDK_ROOT_WINDOW();
-#elif defined(MOZ_WIDGET_QT)
-        Window root = RootWindowOfScreen(DefaultScreenOfDisplay(mozilla::DefaultXDisplay()));
 #else
         Window root = None; // Could XQueryTree, but this is not important.
 #endif
 
         switch (anEvent.mMessage) {
           case eMouseOver:
           case eMouseOut:
             {
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -41,22 +41,18 @@ struct MozPluginParameter;
 namespace widget {
 class PuppetWidget;
 } // namespace widget
 } // namespace mozilla
 
 using mozilla::widget::PuppetWidget;
 
 #ifdef MOZ_X11
-#ifdef MOZ_WIDGET_QT
-#include "gfxQtNativeRenderer.h"
-#else
 #include "gfxXlibNativeRenderer.h"
 #endif
-#endif
 
 class nsPluginInstanceOwner final : public nsIPluginInstanceOwner
                                   , public nsIDOMEventListener
                                   , public nsIPrivacyTransitionObserver
                                   , public nsIKeyEventInPluginCallback
                                   , public nsSupportsWeakReference
 {
 public:
@@ -390,22 +386,17 @@ private:
                             double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
                             double *destX, double *destY, NPCoordinateSpace destSpace);
   void PerformDelayedBlurs();
 #endif    // XP_MACOSX
 
   int mLastMouseDownButtonType;
 
 #ifdef MOZ_X11
-  class Renderer
-#if defined(MOZ_WIDGET_QT)
-  : public gfxQtNativeRenderer
-#else
-  : public gfxXlibNativeRenderer
-#endif
+  class Renderer : public gfxXlibNativeRenderer
   {
   public:
     Renderer(NPWindow* aWindow, nsPluginInstanceOwner* aInstanceOwner,
              const nsIntSize& aPluginSize, const nsIntRect& aDirtyRect)
     : mWindow(aWindow), mInstanceOwner(aInstanceOwner),
     mPluginSize(aPluginSize), mDirtyRect(aDirtyRect)
     {}
     virtual nsresult DrawWithXlib(cairo_surface_t* surface,
deleted file mode 100644
--- a/dom/plugins/base/nsPluginNativeWindowQt.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:expandtab:shiftwidth=2:tabstop=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/. */
-
-/**
- *  This file is the Qt implementation of plugin native window.
- */
-
-#include "nsDebug.h"
-#include "nsPluginNativeWindow.h"
-#include "npapi.h"
-
-/**
- * Qt implementation of plugin window
- */
-class nsPluginNativeWindowQt : public nsPluginNativeWindow
-{
-public:
-  nsPluginNativeWindowQt();
-  virtual ~nsPluginNativeWindowQt();
-
-  virtual nsresult CallSetWindow(RefPtr<nsNPAPIPluginInstance> &aPluginInstance);
-private:
-
-  NPSetWindowCallbackStruct mWsInfo;
-};
-
-nsPluginNativeWindowQt::nsPluginNativeWindowQt() : nsPluginNativeWindow()
-{
-  //Initialize member variables
-#ifdef DEBUG
-  fprintf(stderr,"\n\n\nCreating plugin native window %p\n\n\n", (void *) this);
-#endif
-  window = nullptr;
-  x = 0;
-  y = 0;
-  width = 0;
-  height = 0;
-  memset(&clipRect, 0, sizeof(clipRect));
-  ws_info = &mWsInfo;
-  type = NPWindowTypeWindow;
-  mWsInfo.type = 0;
-#if defined(MOZ_X11)
-  mWsInfo.display = nullptr;
-  mWsInfo.visual = nullptr;
-  mWsInfo.colormap = 0;
-  mWsInfo.depth = 0;
-#endif
-}
-
-nsPluginNativeWindowQt::~nsPluginNativeWindowQt()
-{
-#ifdef DEBUG
-  fprintf(stderr,"\n\n\nDestoying plugin native window %p\n\n\n", (void *) this);
-#endif
-}
-
-nsresult PLUG_NewPluginNativeWindow(nsPluginNativeWindow **aPluginNativeWindow)
-{
-  NS_ENSURE_ARG_POINTER(aPluginNativeWindow);
-  *aPluginNativeWindow = new nsPluginNativeWindowQt();
-  return NS_OK;
-}
-
-nsresult PLUG_DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow)
-{
-  NS_ENSURE_ARG_POINTER(aPluginNativeWindow);
-  nsPluginNativeWindowQt *p = (nsPluginNativeWindowQt *)aPluginNativeWindow;
-  delete p;
-  return NS_OK;
-}
-
-nsresult nsPluginNativeWindowQt::CallSetWindow(RefPtr<nsNPAPIPluginInstance> &aPluginInstance)
-{
-  if (aPluginInstance) {
-    if (type == NPWindowTypeWindow) {
-      return NS_ERROR_FAILURE;
-    } // NPWindowTypeWindow
-    aPluginInstance->SetWindow(this);
-  }
-  else if (mPluginInstance)
-    mPluginInstance->SetWindow(nullptr);
-
-  SetPluginInstance(aPluginInstance);
-  return NS_OK;
-}
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -836,17 +836,17 @@ nsresult nsPluginStreamListenerPeer::Ser
 
   // mPluginInstance->Stop calls mPStreamListener->CleanUpStream(), so stream will be properly clean up
   mPluginInstance->Stop();
   mPluginInstance->Start();
   RefPtr<nsPluginInstanceOwner> owner = mPluginInstance->GetOwner();
   if (owner) {
     NPWindow* window = nullptr;
     owner->GetWindow(window);
-#if (MOZ_WIDGET_GTK == 2) || defined(MOZ_WIDGET_QT)
+#if (MOZ_WIDGET_GTK == 2)
     // Should call GetPluginPort() here.
     // This part is copied from nsPluginInstanceOwner::GetPluginPort().
     nsCOMPtr<nsIWidget> widget;
     ((nsPluginNativeWindow*)window)->GetPluginWidget(getter_AddRefs(widget));
     if (widget) {
       window->window = widget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
     }
 #endif
deleted file mode 100644
--- a/dom/plugins/ipc/PluginHelperQt.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* -*- Mode: C++; tab-width: 3; 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 PluginHelperQt_h_
-#define PluginHelperQt_h_
-
-class PluginHelperQt
-{
-public:
-  static bool AnswerProcessSomeEvents();
-};
-
-#endif // PluginHelperQt_h_
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -49,19 +49,16 @@ using namespace std;
 
 #ifdef MOZ_WIDGET_GTK
 
 #include <gtk/gtk.h>
 #include <gdk/gdkx.h>
 #include <gdk/gdk.h>
 #include "gtk2xtbin.h"
 
-#elif defined(MOZ_WIDGET_QT)
-#undef KeyPress
-#undef KeyRelease
 #elif defined(OS_WIN)
 
 #include <windows.h>
 #include <windowsx.h>
 
 #include "mozilla/widget/WinMessages.h"
 #include "mozilla/widget/WinModifierKeyState.h"
 #include "mozilla/widget/WinNativeEventData.h"
@@ -1381,18 +1378,16 @@ PluginInstanceChild::AnswerNPP_SetWindow
         mShContext = nullptr;
     }
 
     if (mPluginIface->setwindow)
         (void) mPluginIface->setwindow(&mData, &mWindow);
 
 #elif defined(ANDROID)
     // TODO: Need Android impl
-#elif defined(MOZ_WIDGET_QT)
-    // TODO: Need QT-nonX impl
 #elif defined(MOZ_WIDGET_UIKIT)
     // Don't care
 #else
 #  error Implement me for your OS
 #endif
 
     return true;
 }
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -282,19 +282,16 @@ PluginInstanceParent::AnswerNPN_GetValue
     HWND id;
 #elif defined(MOZ_X11)
     XID id;
 #elif defined(XP_DARWIN)
     intptr_t id;
 #elif defined(ANDROID)
     // TODO: Need Android impl
     int id;
-#elif defined(MOZ_WIDGET_QT)
-    // TODO: Need Qt non X impl
-    int id;
 #else
 #warning Implement me
 #endif
 
     *result = mNPNIface->getvalue(mNPP, NPNVnetscapeWindow, &id);
     *value = id;
     return true;
 }
--- a/dom/plugins/ipc/PluginMessageUtils.h
+++ b/dom/plugins/ipc/PluginMessageUtils.h
@@ -97,17 +97,17 @@ struct NPRemoteWindow
   double contentsScaleFactor;
 #endif
 };
 
 #ifdef XP_WIN
 typedef HWND NativeWindowHandle;
 #elif defined(MOZ_X11)
 typedef XID NativeWindowHandle;
-#elif defined(XP_DARWIN) || defined(ANDROID) || defined(MOZ_WIDGET_QT)
+#elif defined(XP_DARWIN) || defined(ANDROID)
 typedef intptr_t NativeWindowHandle; // never actually used, will always be 0
 #else
 #error Need NativeWindowHandle for this platform
 #endif
 
 #ifdef XP_WIN
 typedef base::SharedMemoryHandle WindowsSharedMemoryHandle;
 typedef HANDLE DXGISharedSurfaceHandle;
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -1,20 +1,14 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set sw=4 ts=4 et : */
 /* 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/. */
 
-#ifdef MOZ_WIDGET_QT
-#include <QtCore/QTimer>
-#include "nsQAppInstance.h"
-#include "NestedLoopTimer.h"
-#endif
-
 #include "mozilla/plugins/PluginModuleChild.h"
 
 /* This must occur *after* plugins/PluginModuleChild.h to avoid typedefs conflicts. */
 #include "mozilla/ArrayUtils.h"
 
 #include "mozilla/ipc/MessageChannel.h"
 
 #ifdef MOZ_WIDGET_GTK
@@ -68,22 +62,16 @@ const wchar_t * kFlashFullscreenClass = 
 const wchar_t * kMozillaWindowClass = L"MozillaWindowClass";
 #endif
 
 namespace {
 // see PluginModuleChild::GetChrome()
 PluginModuleChild* gChromeInstance = nullptr;
 } // namespace
 
-#ifdef MOZ_WIDGET_QT
-typedef void (*_gtk_init_fn)(int argc, char **argv);
-static _gtk_init_fn s_gtk_init = nullptr;
-static PRLibrary *sGtkLib = nullptr;
-#endif
-
 #ifdef XP_WIN
 // Hooking CreateFileW for protected-mode magic
 static WindowsDllInterceptor sKernel32Intercept;
 typedef HANDLE (WINAPI *CreateFileWPtr)(LPCWSTR fname, DWORD access,
                                         DWORD share,
                                         LPSECURITY_ATTRIBUTES security,
                                         DWORD creation, DWORD flags,
                                         HANDLE ftemplate);
@@ -126,18 +114,16 @@ PluginModuleChild::PluginModuleChild(boo
   , mHasShutdown(false)
   , mTransport(nullptr)
   , mShutdownFunc(0)
   , mInitializeFunc(0)
 #if defined(OS_WIN) || defined(OS_MACOSX)
   , mGetEntryPointsFunc(0)
 #elif defined(MOZ_WIDGET_GTK)
   , mNestedLoopTimerId(0)
-#elif defined(MOZ_WIDGET_QT)
-  , mNestedLoopTimerObject(0)
 #endif
 #ifdef OS_WIN
   , mNestedEventHook(nullptr)
   , mGlobalCallWndProcHook(nullptr)
 #endif
 {
     memset(&mFunctions, 0, sizeof(mFunctions));
     if (mIsChrome) {
@@ -320,16 +306,17 @@ PluginModuleChild::InitForChrome(const s
 #  error Please copy the initialization code from nsNPAPIPlugin.cpp
 
 #endif
 
     return true;
 }
 
 #if defined(MOZ_WIDGET_GTK)
+
 typedef void (*GObjectDisposeFn)(GObject*);
 typedef gboolean (*GtkWidgetScrollEventFn)(GtkWidget*, GdkEventScroll*);
 typedef void (*GtkPlugEmbeddedFn)(GtkPlug*);
 
 static GObjectDisposeFn real_gtk_plug_dispose;
 static GtkPlugEmbeddedFn real_gtk_plug_embedded;
 
 static void
@@ -543,36 +530,16 @@ void
 PluginModuleChild::ExitedCxxStack()
 {
     MOZ_ASSERT(0 < mNestedLoopTimerId,
                "nested loop timeout not scheduled");
 
     g_source_remove(mNestedLoopTimerId);
     mNestedLoopTimerId = 0;
 }
-#elif defined (MOZ_WIDGET_QT)
-
-void
-PluginModuleChild::EnteredCxxStack()
-{
-    MOZ_ASSERT(mNestedLoopTimerObject == nullptr,
-               "previous timer not descheduled");
-    mNestedLoopTimerObject = new NestedLoopTimer(this);
-    QTimer::singleShot(kNestedLoopDetectorIntervalMs,
-                       mNestedLoopTimerObject, SLOT(timeOut()));
-}
-
-void
-PluginModuleChild::ExitedCxxStack()
-{
-    MOZ_ASSERT(mNestedLoopTimerObject != nullptr,
-               "nested loop timeout not scheduled");
-    delete mNestedLoopTimerObject;
-    mNestedLoopTimerObject = nullptr;
-}
 
 #endif
 
 bool
 PluginModuleChild::RecvSetParentHangTimeout(const uint32_t& aSeconds)
 {
 #ifdef XP_WIN
     SetReplyTimeoutMs(((aSeconds > 0) ? (1000 * aSeconds) : 0));
@@ -623,51 +590,29 @@ PluginModuleChild::InitGraphics()
     if (!*scroll_event) {
         *scroll_event = gtk_plug_scroll_event;
     }
 
     GtkPlugEmbeddedFn* embedded = &GTK_PLUG_CLASS(gtk_plug_class)->embedded;
     real_gtk_plug_embedded = *embedded;
     *embedded = wrap_gtk_plug_embedded;
 
-#elif defined(MOZ_WIDGET_QT)
-    nsQAppInstance::AddRef();
-    // Work around plugins that don't interact well without gtk initialized
-    // see bug 566845
-#if defined(MOZ_X11)
-    if (!sGtkLib)
-         sGtkLib = PR_LoadLibrary("libgtk-x11-2.0.so.0");
-#endif
-    if (sGtkLib) {
-         s_gtk_init = (_gtk_init_fn)PR_FindFunctionSymbol(sGtkLib, "gtk_init");
-         if (s_gtk_init)
-             s_gtk_init(0, 0);
-    }
 #else
     // may not be necessary on all platforms
 #endif
 #ifdef MOZ_X11
     // Do this after initializing GDK, or GDK will install its own handler.
     XRE_InstallX11ErrorHandler();
 #endif
     return true;
 }
 
 void
 PluginModuleChild::DeinitGraphics()
 {
-#ifdef MOZ_WIDGET_QT
-    nsQAppInstance::Release();
-    if (sGtkLib) {
-        PR_UnloadLibrary(sGtkLib);
-        sGtkLib = nullptr;
-        s_gtk_init = nullptr;
-    }
-#endif
-
 #if defined(MOZ_X11) && defined(NS_FREE_PERMANENT_DATA)
     // We free some data off of XDisplay close hooks, ensure they're
     // run.  Closing the display is pretty scary, so we only do it to
     // silence leak checkers.
     XCloseDisplay(DefaultXDisplay());
 #endif
 }
 
@@ -1144,17 +1089,17 @@ NPError
           void* aValue)
 {
     PLUGIN_LOG_DEBUG_FUNCTION;
     ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
 
     switch (aVariable) {
         // Copied from nsNPAPIPlugin.cpp
         case NPNVToolkit:
-#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
+#if defined(MOZ_WIDGET_GTK)
             *static_cast<NPNToolkitType*>(aValue) = NPNVGtk2;
             return NPERR_NO_ERROR;
 #endif
             return NPERR_GENERIC_ERROR;
 
         case NPNVjavascriptEnabledBool:
             *(NPBool*)aValue = PluginModuleChild::GetChrome()->Settings().javascriptEnabled();
             return NPERR_NO_ERROR;
--- a/dom/plugins/ipc/PluginModuleChild.h
+++ b/dom/plugins/ipc/PluginModuleChild.h
@@ -47,21 +47,16 @@ typedef NS_NPAPIPLUGIN_CALLBACK(NPError,
 
 namespace mozilla {
 namespace dom {
 class PCrashReporterChild;
 } // namespace dom
 
 namespace plugins {
 
-#ifdef MOZ_WIDGET_QT
-class NestedLoopTimer;
-static const int kNestedLoopDetectorIntervalMs = 90;
-#endif
-
 class PluginInstanceChild;
 
 class PluginModuleChild : public PPluginModuleChild
 {
     typedef mozilla::dom::PCrashReporterChild PCrashReporterChild;
 protected:
     virtual mozilla::ipc::RacyInterruptPolicy
     MediateInterruptRace(const MessageInfo& parent,
@@ -258,20 +253,16 @@ private:
 #endif
 
 #if defined(MOZ_WIDGET_GTK)
     static gboolean DetectNestedEventLoop(gpointer data);
     static gboolean ProcessBrowserEvents(gpointer data);
 
     virtual void EnteredCxxStack() override;
     virtual void ExitedCxxStack() override;
-#elif defined(MOZ_WIDGET_QT)
-
-    virtual void EnteredCxxStack() override;
-    virtual void ExitedCxxStack() override;
 #endif
 
     PRLibrary* mLibrary;
     nsCString mPluginFilename; // UTF8
     int mQuirks;
 
     bool mIsChrome;
     bool mHasShutdown; // true if NP_Shutdown has run
@@ -323,18 +314,16 @@ private:
     guint mNestedLoopTimerId;
 #  ifdef DEBUG
     // Depth of the stack of calls to g_main_context_dispatch before any
     // nested loops are run.  This is 1 when IPC calls are dispatched from
     // g_main_context_iteration, or 0 when dispatched directly from
     // MessagePumpForUI.
     int mTopLoopDepth;
 #  endif
-#elif defined (MOZ_WIDGET_QT)
-    NestedLoopTimer *mNestedLoopTimerObject;
 #endif
 
 public: // called by PluginInstanceChild
     /**
      * Dealloc an NPObject after last-release or when the associated instance
      * is destroyed. This function will remove the object from mObjectMap.
      */
     static void DeallocNPObject(NPObject* o);
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -1,18 +1,14 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: sw=4 ts=4 et :
  * 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/. */
 
-#ifdef MOZ_WIDGET_QT
-#include "PluginHelperQt.h"
-#endif
-
 #include "mozilla/plugins/PluginModuleParent.h"
 
 #include "base/process_util.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/PCrashReporterParent.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
@@ -2854,28 +2850,17 @@ PluginModuleParent::ContentsScaleFactorC
     PluginInstanceParent* i = PluginInstanceParent::Cast(instance);
     if (!i)
         return NS_ERROR_FAILURE;
 
     return i->ContentsScaleFactorChanged(aContentsScaleFactor);
 }
 #endif // #if defined(XP_MACOSX)
 
-#if defined(MOZ_WIDGET_QT)
-bool
-PluginModuleParent::AnswerProcessSomeEvents()
-{
-    PLUGIN_LOG_DEBUG(("Spinning mini nested loop ..."));
-    PluginHelperQt::AnswerProcessSomeEvents();
-    PLUGIN_LOG_DEBUG(("... quitting mini nested loop"));
-
-    return true;
-}
-
-#elif defined(XP_MACOSX)
+#if defined(XP_MACOSX)
 bool
 PluginModuleParent::AnswerProcessSomeEvents()
 {
     mozilla::plugins::PluginUtilsOSX::InvokeNativeEventLoop();
     return true;
 }
 
 #elif !defined(MOZ_WIDGET_GTK)
--- a/dom/presentation/PresentationConnection.cpp
+++ b/dom/presentation/PresentationConnection.cpp
@@ -85,48 +85,38 @@ PresentationConnection::Init()
     return false;
   }
 
   nsresult rv = service->RegisterSessionListener(mId, mRole, this);
   if(NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
 
-  nsCOMPtr<nsILoadGroup> loadGroup;
-  GetLoadGroup(getter_AddRefs(loadGroup));
-  if(NS_WARN_IF(!loadGroup)) {
-    return false;
-  }
-
-  rv = loadGroup->AddRequest(this, nullptr);
+  rv = AddIntoLoadGroup();
   if(NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
-  mWeakLoadGroup = do_GetWeakReference(loadGroup);
 
   return true;
 }
 
 void
 PresentationConnection::Shutdown()
 {
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if (NS_WARN_IF(!service)) {
     return;
   }
 
   nsresult rv = service->UnregisterSessionListener(mId, mRole);
   NS_WARN_IF(NS_FAILED(rv));
 
-  nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakLoadGroup);
-  if (loadGroup) {
-    loadGroup->RemoveRequest(this, nullptr, NS_OK);
-    mWeakLoadGroup = nullptr;
-  }
+  rv = RemoveFromLoadGroup();
+  NS_WARN_IF(NS_FAILED(rv));
 }
 
 /* virtual */ void
 PresentationConnection::DisconnectFromOwner()
 {
   NS_WARN_IF(NS_FAILED(ProcessConnectionWentAway()));
   DOMEventTargetHelper::DisconnectFromOwner();
 }
@@ -171,30 +161,41 @@ PresentationConnection::Send(const nsASt
   if(NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
   }
 }
 
 void
 PresentationConnection::Close(ErrorResult& aRv)
 {
-  // It only works when the state is CONNECTED.
-  if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
+  // It only works when the state is CONNECTED or CONNECTING.
+  if (NS_WARN_IF(mState != PresentationConnectionState::Connected &&
+                 mState != PresentationConnectionState::Connecting)) {
     return;
   }
 
-  // TODO Bug 1210340 - Support close semantics.
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  nsCOMPtr<nsIPresentationService> service =
+    do_GetService(PRESENTATION_SERVICE_CONTRACTID);
+  if(NS_WARN_IF(!service)) {
+    aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
+    return;
+  }
+
+  NS_WARN_IF(NS_FAILED(
+    service->CloseSession(mId,
+                          mRole,
+                          nsIPresentationService::CLOSED_REASON_CLOSED)));
 }
 
 void
 PresentationConnection::Terminate(ErrorResult& aRv)
 {
-  // It only works when the state is CONNECTED.
-  if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
+  // It only works when the state is CONNECTED or CONNECTING.
+  if (NS_WARN_IF(mState != PresentationConnectionState::Connected &&
+                 mState != PresentationConnectionState::Connecting)) {
     return;
   }
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if(NS_WARN_IF(!service)) {
     aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
     return;
@@ -271,33 +272,37 @@ PresentationConnection::ProcessStateChan
                                                          name,
                                                          message))) {
           mozilla::GetErrorName(aReason, message);
           message.InsertLiteral("Internal error: ", 0);
         }
         CopyUTF8toUTF16(message, errorMsg);
       }
 
-      return DispatchConnectionClosedEvent(reason, errorMsg);
+      NS_WARN_IF(NS_FAILED(DispatchConnectionClosedEvent(reason, errorMsg)));
+
+      return RemoveFromLoadGroup();
     }
     case PresentationConnectionState::Terminated: {
       nsCOMPtr<nsIPresentationService> service =
         do_GetService(PRESENTATION_SERVICE_CONTRACTID);
       if (NS_WARN_IF(!service)) {
         return NS_ERROR_NOT_AVAILABLE;
       }
 
       nsresult rv = service->UnregisterSessionListener(mId, mRole);
       if(NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       RefPtr<AsyncEventDispatcher> asyncDispatcher =
         new AsyncEventDispatcher(this, NS_LITERAL_STRING("terminate"), false);
-      return asyncDispatcher->PostDOMEvent();
+      NS_WARN_IF(NS_FAILED(asyncDispatcher->PostDOMEvent()));
+
+      return RemoveFromLoadGroup();
     }
     default:
       MOZ_CRASH("Unknown presentation session state.");
       return NS_ERROR_INVALID_ARG;
   }
 }
 
 NS_IMETHODIMP
@@ -470,8 +475,47 @@ PresentationConnection::GetLoadFlags(nsL
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationConnection::SetLoadFlags(nsLoadFlags aLoadFlags)
 {
   return NS_OK;
 }
+
+nsresult
+PresentationConnection::AddIntoLoadGroup()
+{
+  // Avoid adding to loadgroup multiple times
+  if (mWeakLoadGroup) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsILoadGroup> loadGroup;
+  nsresult rv = GetLoadGroup(getter_AddRefs(loadGroup));
+  if(NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = loadGroup->AddRequest(this, nullptr);
+  if(NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  mWeakLoadGroup = do_GetWeakReference(loadGroup);
+  return NS_OK;
+}
+
+nsresult
+PresentationConnection::RemoveFromLoadGroup()
+{
+  if (!mWeakLoadGroup) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakLoadGroup);
+  if (loadGroup) {
+    mWeakLoadGroup = nullptr;
+    return loadGroup->RemoveRequest(this, nullptr, NS_OK);
+  }
+
+  return NS_OK;
+}
--- a/dom/presentation/PresentationConnection.h
+++ b/dom/presentation/PresentationConnection.h
@@ -74,16 +74,20 @@ private:
 
   nsresult DispatchConnectionClosedEvent(PresentationConnectionClosedReason aReason,
                                          const nsAString& aMessage);
 
   nsresult DispatchMessageEvent(JS::Handle<JS::Value> aData);
 
   nsresult ProcessConnectionWentAway();
 
+  nsresult AddIntoLoadGroup();
+
+  nsresult RemoveFromLoadGroup();
+
   nsString mId;
   uint8_t mRole;
   PresentationConnectionState mState;
   RefPtr<PresentationConnectionList> mOwningConnectionList;
   nsWeakPtr mWeakLoadGroup;;
 };
 
 } // namespace dom
--- a/dom/presentation/tests/mochitest/file_presentation_1ua_receiver.html
+++ b/dom/presentation/tests/mochitest/file_presentation_1ua_receiver.html
@@ -100,28 +100,25 @@ function testSendMessage() {
       if (message.type === 'message-from-receiver-received') {
         window.removeEventListener('hashchange', hashchangeHandler);
         aResolve();
       }
     });
   });
 }
 
-// Currently, PresentationSessionInfo::NotifyTransportClosed only set the state to
-// STATE_CLOSED. So, when sender call connection.terminate(), we can only get STATE_CLOSED
-// at receiver side. This should be fixed in bu 1210340.
 function testConnectionClosed() {
   return new Promise(function(aResolve, aReject) {
     info('Receiver: --- testConnectionClosed ---');
     connection.onclose = function() {
       connection.onclose = null;
       is(connection.state, "closed", "Receiver: Connection should be closed.");
       aResolve();
     };
-    command('forward-command', JSON.stringify({ name: 'ready-to-terminate' }));
+    command('forward-command', JSON.stringify({ name: 'ready-to-close' }));
   });
 }
 
 function runTests() {
   testConnectionAvailable()
   .then(testConnectionReady)
   .then(testIncomingMessage)
   .then(testSendMessage)
--- a/dom/presentation/tests/mochitest/file_presentation_receiver.html
+++ b/dom/presentation/tests/mochitest/file_presentation_receiver.html
@@ -116,32 +116,32 @@ function testIncomingMessage() {
       aResolve();
     });
 
     command({ name: 'trigger-incoming-message',
               data: incomingMessage });
   });
 }
 
-function testTerminateConnection() {
+function testCloseConnection() {
   return new Promise(function(aResolve, aReject) {
-    connection.onterminate = function() {
-      connection.onterminate = null;
-      is(connection.state, "terminated", "Connection should be terminated.");
+    connection.onclose = function() {
+      connection.onclose = null;
+      is(connection.state, "closed", "Connection should be closed.");
       aResolve();
     };
 
-    connection.terminate();
+    connection.close();
   });
 }
 
 testConnectionAvailable().
 then(testDefauleRequestIsNull).
 then(testConnectionAvailableSameOriginInnerIframe).
 then(testConnectionUnavailableDiffOriginInnerIframe).
 then(testConnectionListSameObject).
 then(testIncomingMessage).
-then(testTerminateConnection).
+then(testCloseConnection).
 then(finish);
 
 </script>
 </body>
 </html>
--- a/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.html
+++ b/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.html
@@ -172,27 +172,27 @@ function testIncomingMessage() {
       is(msg, "msg-receiver-to-sender", "Sender: Sender should receive message from Receiver");
       postMessageToIframe('message-from-receiver-received');
       aResolve();
     });
     postMessageToIframe('trigger-message-from-receiver');
   });
 }
 
-function testTerminateConnection() {
+function testCloseConnection() {
   return new Promise(function(aResolve, aReject) {
-    info('Sender: --- testTerminateConnection ---');
-    connection.onterminate = function() {
-      connection.onterminate = null;
-      is(connection.state, "terminated", "Sender: Connection should be terminated.");
+    info('Sender: --- testCloseConnection ---');
+    connection.onclose = function() {
+      connection.onclose = null;
+      is(connection.state, "closed", "Sender: Connection should be closed.");
       aResolve();
     };
-    gScript.addMessageListener('ready-to-terminate', function onReadyToTerminate() {
-      gScript.removeMessageListener('ready-to-terminate', onReadyToTerminate);
-      connection.terminate();
+    gScript.addMessageListener('ready-to-close', function onReadyToClose() {
+      gScript.removeMessageListener('ready-to-close', onReadyToClose);
+      connection.close();
     });
   });
 }
 
 function teardown() {
   gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
     debug('Got message: teardown-complete');
     gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
@@ -203,17 +203,17 @@ function teardown() {
   gScript.sendAsyncMessage('teardown');
 }
 
 function runTests() {
   setup().then(testCreateRequest)
          .then(testStartConnection)
          .then(testSendMessage)
          .then(testIncomingMessage)
-         .then(testTerminateConnection);
+         .then(testCloseConnection);
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPermissions([
   {type: 'presentation-device-manage', allow: false, context: document},
   {type: 'presentation', allow: true, context: document},
   {type: "browser", allow: true, context: document},
 ], () => {
--- a/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver_oop.html
+++ b/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver_oop.html
@@ -179,27 +179,27 @@ function testIncomingMessage() {
       is(msg, "msg-receiver-to-sender", "Sender: Sender should receive message from Receiver");
       postMessageToIframe('message-from-receiver-received');
       aResolve();
     });
     postMessageToIframe('trigger-message-from-receiver');
   });
 }
 
-function testTerminateConnection() {
+function testCloseConnection() {
   return new Promise(function(aResolve, aReject) {
-    info('Sender: --- testTerminateConnection ---');
-    connection.onterminate = function() {
-      connection.onterminate = null;
-      is(connection.state, "terminated", "Sender: Connection should be terminated.");
+    info('Sender: --- testCloseConnection ---');
+    connection.onclose = function() {
+      connection.onclose = null;
+      is(connection.state, "closed", "Sender: Connection should be closed.");
       aResolve();
     };
-    gScript.addMessageListener('ready-to-terminate', function onReadyToTerminate() {
-      gScript.removeMessageListener('ready-to-terminate', onReadyToTerminate);
-      connection.terminate();
+    gScript.addMessageListener('ready-to-close', function onReadyToClose() {
+      gScript.removeMessageListener('ready-to-close', onReadyToClose);
+      connection.close();
     });
   });
 }
 
 function teardown() {
   gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
     gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
     gScript.destroy();
@@ -210,17 +210,17 @@ function teardown() {
 }
 
 function runTests() {
   setup()
   .then(testCreateRequest)
   .then(testStartConnection)
   .then(testSendMessage)
   .then(testIncomingMessage)
-  .then(testTerminateConnection);
+  .then(testCloseConnection);
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPermissions([
   {type: 'presentation-device-manage', allow: false, context: document},
   {type: 'presentation', allow: true, context: document},
   {type: "browser", allow: true, context: document},
 ], () => {
--- a/dom/presentation/tests/mochitest/test_presentation_dc_sender.html
+++ b/dom/presentation/tests/mochitest/test_presentation_dc_sender.html
@@ -152,30 +152,30 @@ function testIncomingMessage() {
       is(aEvent.data, incomingMessage, "An incoming message should be received.");
       aResolve();
     });
 
     frameScript.sendAsyncMessage('trigger-incoming-message', incomingMessage);
   });
 }
 
-function testTerminateConnection() {
+function testCloseConnection() {
   return new Promise(function(aResolve, aReject) {
     frameScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
       frameScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
       info("The data transport is closed. " + aReason);
     });
 
-    connection.onterminate = function() {
-      connection.onterminate = null;
-      is(connection.state, "terminated", "Connection should be terminated.");
+    connection.onclose = function() {
+      connection.onclose = null;
+      is(connection.state, "closed", "Connection should be closed.");
       aResolve();
     };
 
-    connection.terminate();
+    connection.close();
   });
 }
 
 function teardown() {
   gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
     gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
     gScript.destroy();
     info('teardown-complete');
@@ -187,17 +187,17 @@ function teardown() {
 
 function runTests() {
   ok(window.PresentationRequest, "PresentationRequest should be available.");
 
   testSetup().
   then(testStartConnection).
   then(testSend).
   then(testIncomingMessage).
-  then(testTerminateConnection).
+  then(testCloseConnection).
   then(teardown);
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPermissions([
   {type: 'presentation-device-manage', allow: false, context: document},
   {type: 'presentation', allow: true, context: document},
 ], function() {
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_sender.html
+++ b/dom/presentation/tests/mochitest/test_presentation_tcp_sender.html
@@ -146,30 +146,30 @@ function testIncomingMessage() {
       is(aEvent.data, incomingMessage, "An incoming message should be received.");
       aResolve();
     });
 
     gScript.sendAsyncMessage('trigger-incoming-message', incomingMessage);
   });
 }
 
-function testTerminateConnection() {
+function testCloseConnection() {
   return new Promise(function(aResolve, aReject) {
     gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
       gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
       info("The data transport is closed. " + aReason);
     });
 
-    connection.onterminate = function() {
-      connection.onterminate = null;
-      is(connection.state, "terminated", "Connection should be terminated.");
+    connection.onclose = function() {
+      connection.onclose = null;
+      is(connection.state, "closed", "Connection should be closed.");
       aResolve();
     };
 
-    connection.terminate();
+    connection.close();
   });
 }
 
 function teardown() {
   gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
     gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
     gScript.destroy();
     SimpleTest.finish();
@@ -180,17 +180,17 @@ function teardown() {
 
 function runTests() {
   ok(window.PresentationRequest, "PresentationRequest should be available.");
 
   testSetup().
   then(testStartConnection).
   then(testSend).
   then(testIncomingMessage).
-  then(testTerminateConnection).
+  then(testCloseConnection).
   then(teardown);
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPermissions([
   {type: 'presentation-device-manage', allow: false, context: document},
   {type: 'presentation', allow: true, context: document},
 ], function() {
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_sender_default_request.html
+++ b/dom/presentation/tests/mochitest/test_presentation_tcp_sender_default_request.html
@@ -96,30 +96,30 @@ function testStartConnection() {
       };
     };
 
     // Simulate the UA triggers |start()| of the default request.
     navigator.presentation.defaultRequest.start();
   });
 }
 
-function testTerminateConnection() {
+function testCloseConnection() {
   return new Promise(function(aResolve, aReject) {
     gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
       gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
       info("The data transport is closed. " + aReason);
     });
 
-    connection.onterminate = function() {
-      connection.onterminate = null;
-      is(connection.state, "terminated", "Connection should be terminated.");
+    connection.onclose = function() {
+      connection.onclose = null;
+      is(connection.state, "closed", "Connection should be closed.");
       aResolve();
     };
 
-    connection.terminate();
+    connection.close();
   });
 }
 
 function teardown() {
   gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
     gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
     gScript.destroy();
     SimpleTest.finish();
@@ -129,17 +129,17 @@ function teardown() {
 }
 
 function runTests() {
   ok(window.PresentationRequest, "PresentationRequest should be available.");
   ok(navigator.presentation, "navigator.presentation should be available.");
 
   testSetup().
   then(testStartConnection).
-  then(testTerminateConnection).
+  then(testCloseConnection).
   then(teardown);
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPermissions([
   {type: 'presentation-device-manage', allow: false, context: document},
   {type: 'presentation', allow: true, context: document},
 ], function() {
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -643,17 +643,17 @@ nsCSPContext::SetRequestContext(nsIDOMDo
     // console messages until it becomes available, see flushConsoleMessages
     mQueueUpMessages = !mInnerWindowID;
     mCallingChannelLoadGroup = doc->GetDocumentLoadGroup();
 
     // set the flag on the document for CSP telemetry
     doc->SetHasCSP(true);
   }
   else {
-    NS_WARNING("No Document in SetRequestContext; can not query loadgroup; sending reports may fail.");
+    CSPCONTEXTLOG(("No Document in SetRequestContext; can not query loadgroup; sending reports may fail."));
     mLoadingPrincipal = aPrincipal;
     mLoadingPrincipal->GetURI(getter_AddRefs(mSelfURI));
     // if no document is available, then it also does not make sense to queue console messages
     // sending messages to the browser conolse instead of the web console in that case.
     mQueueUpMessages = false;
   }
 
   NS_ASSERTION(mSelfURI, "mSelfURI not available, can not translate 'self' into actual URI");
--- a/dom/system/moz.build
+++ b/dom/system/moz.build
@@ -1,19 +1,17 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
 
-if toolkit == 'qt':
-    DIRS += ['qt']
-elif toolkit == 'windows':
+if toolkit == 'windows':
     DIRS += ['windows']
 elif toolkit == 'cocoa':
     DIRS += ['mac']
 elif toolkit == 'android':
     DIRS += ['android']
 elif toolkit == 'gonk':
     DIRS += ['gonk']
 
--- a/dom/tests/mochitest/geolocation/mochitest.ini
+++ b/dom/tests/mochitest/geolocation/mochitest.ini
@@ -31,16 +31,20 @@ skip-if = buildapp == 'b2g' || toolkit =
 [test_manyCurrentSerial.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
 [test_manyWatchConcurrent.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
 [test_manyWatchSerial.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
 [test_manyWindows.html]
 skip-if = buildapp == 'b2g'
+[test_mozsettings.html]
+skip-if = buildapp == 'b2g' || toolkit == 'android'
+[test_mozsettingsWatch.html]
+skip-if = buildapp == 'b2g' || toolkit == 'android'
 [test_optional_api_params.html]
 skip-if = buildapp == 'b2g'
 [test_shutdown.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
 [test_timeoutCurrent.html]
 [test_timerRestartWatch.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
 [test_windowClose.html]
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/geolocation/test_mozsettings.html
@@ -0,0 +1,92 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=478911
+-->
+<head>
+  <title>Test for getCurrentPosition </title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="geolocation_common.js"></script>
+
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=777594">Mozilla Bug 777594</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+
+var timeToWaitMs = 1000;
+
+resume_geolocationProvider(function() {
+  force_prompt(true, test1);
+});
+
+SpecialPowers.importInMainProcess("resource://gre/modules/SettingsRequestManager.jsm");
+
+function test1() {
+  //This pushPermissions call is after pushPrefEnv call and pushPrefEnv calls follow after this
+  SpecialPowers.pushPermissions([{'type': 'settings-read', 'allow': true, 'context': document},
+                                 {'type': 'settings-write', 'allow': true, 'context': document},
+                                 {'type': 'settings-api-write', 'allow': true, 'context': document},
+                                 {'type': 'settings-api-read', 'allow': true, 'context': document}
+  ], test2);
+}
+
+function test2() {
+  ok(navigator.geolocation, "get geolocation object");
+
+  toggleGeolocationSetting(false, function() {
+      ok(true, "turned off geolocation via mozSettings");
+      setTimeout(function() {
+          navigator.geolocation.getCurrentPosition(successCallbackAfterMozsettingOff,
+                                                   failureCallbackAfterMozsettingOff);
+        }, timeToWaitMs); // need to wait a bit for all of these async callbacks to finish
+  });
+}
+
+function successCallbackAfterMozsettingOff(position) {
+  ok(false, "Success callback should not have been called after setting geolocation.enabled to false.");
+
+  toggleGeolocationSetting(true, function() {
+      ok(true, "turned on geolocation via mozSettings");
+      setTimeout(function() {
+         navigator.geolocation.getCurrentPosition(successCallbackAfterMozsettingOn,
+                                                  failureCallbackAfterMozsettingOn);
+        }, timeToWaitMs); // need to wait a bit for all of these async callbacks to finish
+    });
+}
+
+function failureCallbackAfterMozsettingOff(error) {
+  ok(true, "Geolocation didn't work after setting geolocation.enabled to false.");
+
+  toggleGeolocationSetting(true, function() {
+      ok(true, "turned on geolocation via mozSettings");
+      setTimeout(function() {
+         navigator.geolocation.getCurrentPosition(successCallbackAfterMozsettingOn,
+                                                  failureCallbackAfterMozsettingOn);
+        }, timeToWaitMs); // need to wait a bit for all of these async callbacks to finish
+    });
+}
+
+function successCallbackAfterMozsettingOn(position) {
+  ok(true, "Geolocation worked after setting geolocation.enabled to true.");
+  SimpleTest.finish();
+}
+
+function failureCallbackAfterMozsettingOn(error) {
+  ok(false, "Geolocation didn't work after setting geolocation.enabled to true.");
+  SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/geolocation/test_mozsettingsWatch.html
@@ -0,0 +1,97 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=478911
+-->
+<head>
+  <title>Test for getCurrentPosition </title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="geolocation_common.js"></script>
+
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=777594">Mozilla Bug 777594</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+
+resume_geolocationProvider(function() {
+  force_prompt(true, test1);
+});
+
+SpecialPowers.importInMainProcess("resource://gre/modules/SettingsRequestManager.jsm");
+
+function test1() {
+  //This pushPermissions call is after pushPrefEnv call and pushPrefEnv calls follow after this
+  SpecialPowers.pushPermissions([{'type': 'settings-read', 'allow': true, 'context': document},
+                                 {'type': 'settings-write', 'allow': true, 'context': document},
+                                 {'type': 'settings-api-write', 'allow': true, 'context': document},
+                                 {'type': 'settings-api-read', 'allow': true, 'context': document}
+  ], test2);
+}
+
+var watchId;
+function test2() {
+  ok(navigator.geolocation, "get geolocation object");
+
+  toggleGeolocationSetting(false, function() {
+      ok(true, "turned off geolocation via mozSettings");
+      setTimeout(function() {
+          watchId = navigator.geolocation.watchPosition(successCallbackAfterMozsettingOff,
+                                                        failureCallbackAfterMozsettingOff);
+      }, 500); // need to wait a bit for all of these async callbacks to finish
+  });
+}
+
+function successCallbackAfterMozsettingOff(position) {
+  ok(false, "Success callback should not have been called after setting geolocation.enabled to false.");
+
+  navigator.geolocation.clearWatch(watchId);
+  toggleGeolocationSetting(true, function() {
+      ok(true, "turned on geolocation via mozSettings");
+      setTimeout(function() {
+          watchId = navigator.geolocation.watchPosition(successCallbackAfterMozsettingOn,
+                                                        failureCallbackAfterMozsettingOn);
+        }, 500); // need to wait a bit for all of these async callbacks to finish
+    });
+}
+
+function failureCallbackAfterMozsettingOff(error) {
+  ok(true, "Geolocation didn't work after setting geolocation.enabled to false.");
+
+  navigator.geolocation.clearWatch(watchId);
+  toggleGeolocationSetting(true, function() {
+      ok(true, "turned on geolocation via mozSettings");
+      setTimeout(function() {
+          watchId = navigator.geolocation.watchPosition(successCallbackAfterMozsettingOn,
+                                                        failureCallbackAfterMozsettingOn);
+        }, 500); // need to wait a bit for all of these async callbacks to finish
+    });
+}
+
+function successCallbackAfterMozsettingOn(position) {
+  ok(true, "Geolocation worked after setting geolocation.enabled to true.");
+
+  navigator.geolocation.clearWatch(watchId);
+  SimpleTest.finish();
+}
+
+function failureCallbackAfterMozsettingOn(error) {
+  ok(false, "Geolocation didn't work after setting geolocation.enabled to true.");
+
+  navigator.geolocation.clearWatch(watchId);
+  SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/dom/url/URLSearchParams.cpp
+++ b/dom/url/URLSearchParams.cpp
@@ -3,16 +3,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "URLSearchParams.h"
 #include "mozilla/dom/URLSearchParamsBinding.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "nsDOMString.h"
+#include "nsIInputStream.h"
+#include "nsStringStream.h"
 
 namespace mozilla {
 namespace dom {
 
 bool
 URLParams::Has(const nsAString& aName)
 {
   for (uint32_t i = 0, len = mParams.Length(); i < len; ++i) {
@@ -295,16 +297,17 @@ URLParams::Serialize(nsAString& aValue) 
 }
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLSearchParams, mParent, mObserver)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearchParams)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URLSearchParams)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 URLSearchParams::URLSearchParams(nsISupports* aParent,
                                  URLSearchParamsObserver* aObserver)
   : mParams(new URLParams())
   , mParent(aParent)
   , mObserver(aObserver)
@@ -439,10 +442,108 @@ URLSearchParams::GetKeyAtIndex(uint32_t 
 }
 
 const nsAString&
 URLSearchParams::GetValueAtIndex(uint32_t aIndex) const
 {
   return mParams->GetValueAtIndex(aIndex);
 }
 
+// Helper functions for structured cloning
+inline bool
+ReadString(JSStructuredCloneReader* aReader, nsString& aString)
+{
+  MOZ_ASSERT(aReader);
+
+  bool read;
+  uint32_t nameLength, zero;
+  read = JS_ReadUint32Pair(aReader, &nameLength, &zero);
+  if (!read) {
+    return false;
+  }
+  MOZ_ASSERT(zero == 0);
+  aString.SetLength(nameLength);
+  size_t charSize = sizeof(nsString::char_type);
+  read = JS_ReadBytes(aReader, (void*) aString.BeginWriting(),
+                      nameLength * charSize);
+  if (!read) {
+    return false;
+  }
+
+  return true;
+}
+
+inline bool
+WriteString(JSStructuredCloneWriter* aWriter, const nsString& aString)
+{
+  MOZ_ASSERT(aWriter);
+
+  size_t charSize = sizeof(nsString::char_type);
+  return JS_WriteUint32Pair(aWriter, aString.Length(), 0) &&
+         JS_WriteBytes(aWriter, aString.get(), aString.Length() * charSize);
+}
+
+bool
+URLParams::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const
+{
+  const uint32_t& nParams = mParams.Length();
+  if (!JS_WriteUint32Pair(aWriter, nParams, 0)) {
+    return false;
+  }
+  for (uint32_t i = 0; i < nParams; ++i) {
+    if (!WriteString(aWriter, mParams[i].mKey) ||
+        !WriteString(aWriter, mParams[i].mValue)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool
+URLParams::ReadStructuredClone(JSStructuredCloneReader* aReader)
+{
+  MOZ_ASSERT(aReader);
+
+  DeleteAll();
+
+  uint32_t nParams, zero;
+  nsAutoString key, value;
+  if (!JS_ReadUint32Pair(aReader, &nParams, &zero)) {
+    return false;
+  }
+  MOZ_ASSERT(zero == 0);
+  for (uint32_t i = 0; i < nParams; ++i) {
+    if (!ReadString(aReader, key) || !ReadString(aReader, value)) {
+      return false;
+    }
+    Append(key, value);
+  }
+  return true;
+}
+
+bool
+URLSearchParams::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const
+{
+  return mParams->WriteStructuredClone(aWriter);
+}
+
+bool
+URLSearchParams::ReadStructuredClone(JSStructuredCloneReader* aReader)
+{
+ return mParams->ReadStructuredClone(aReader);
+}
+
+NS_IMETHODIMP
+URLSearchParams::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
+                             nsACString& aContentType, nsACString& aCharset)
+{
+  aContentType.AssignLiteral("application/x-www-form-urlencoded");
+  aCharset.AssignLiteral("UTF-8");
+
+  nsAutoString serialized;
+  Serialize(serialized);
+  NS_ConvertUTF16toUTF8 converted(serialized);
+  *aContentLength = converted.Length();
+  return NS_NewCStringInputStream(aBody, converted);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/url/URLSearchParams.h
+++ b/dom/url/URLSearchParams.h
@@ -2,22 +2,24 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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_dom_URLSearchParams_h
 #define mozilla_dom_URLSearchParams_h
 
+#include "js/StructuredClone.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/ErrorResult.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 #include "nsISupports.h"
 #include "nsIUnicodeDecoder.h"
+#include "nsIXMLHttpRequest.h"
 
 namespace mozilla {
 namespace dom {
 
 class URLSearchParams;
 
 class URLSearchParamsObserver : public nsISupports
 {
@@ -103,41 +105,49 @@ public:
   }
 
   const nsAString& GetValueAtIndex(uint32_t aIndex) const
   {
     MOZ_ASSERT(aIndex < mParams.Length());
     return mParams[aIndex].mValue;
   }
 
+  bool
+  ReadStructuredClone(JSStructuredCloneReader* aReader);
+
+  bool
+  WriteStructuredClone(JSStructuredCloneWriter* aWriter) const;
+
 private:
   void DecodeString(const nsACString& aInput, nsAString& aOutput);
   void ConvertString(const nsACString& aInput, nsAString& aOutput);
 
   struct Param
   {
     nsString mKey;
     nsString mValue;
   };
 
   nsTArray<Param> mParams;
   nsCOMPtr<nsIUnicodeDecoder> mDecoder;
 };
 
-class URLSearchParams final : public nsISupports,
+class URLSearchParams final : public nsIXHRSendable,
                               public nsWrapperCache
 {
   ~URLSearchParams();
 
 public:
+  NS_DECL_NSIXHRSENDABLE
+
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(URLSearchParams)
 
-  URLSearchParams(nsISupports* aParent,
-                  URLSearchParamsObserver* aObserver);
+  explicit URLSearchParams(nsISupports* aParent,
+                           URLSearchParamsObserver* aObserver=nullptr);
 
   URLSearchParams(nsISupports* aParent,
                   const URLSearchParams& aOther);
 
   // WebIDL methods
   nsISupports* GetParentObject() const
   {
     return mParent;
@@ -184,16 +194,22 @@ public:
   bool
   ForEach(ForEachIterator& aIterator) const
   {
     return mParams->ForEach(aIterator);
 
     return true;
   }
 
+  bool
+  ReadStructuredClone(JSStructuredCloneReader* aReader);
+
+  bool
+  WriteStructuredClone(JSStructuredCloneWriter* aWriter) const;
+
 private:
   void AppendInternal(const nsAString& aName, const nsAString& aValue);
 
   void DeleteAll();
 
   void NotifyObserver();
 
   UniquePtr<URLParams> mParams;
--- a/dom/url/tests/test_url.html
+++ b/dom/url/tests/test_url.html
@@ -382,10 +382,22 @@
     is(url.href, "ftp://tmp/test");
 
     url = new URL("ftp:\\\\tmp\\test", base);
     is(url.href, "ftp://tmp/test");
 
     url = new URL("scheme://tmp\\test", base);
     is(url.href, "scheme://tmp\\test");
   </script>
+
+  <script>
+    /** Test for Bug 1275746 **/
+    SimpleTest.doesThrow(() => { var url = new URL("http:"); }, "http: is not a valid URL");
+    SimpleTest.doesThrow(() => { var url = new URL("http:///"); }, "http: is not a valid URL");
+
+    var url = new URL("file:");
+    is(url.href, "file:///", "Parsing file: should work.");
+
+    url = new URL("file:///");
+    is(url.href, "file:///", "Parsing file:/// should work.");
+  </script>
 </body>
 </html>
--- a/dom/webidl/PresentationConnection.webidl
+++ b/dom/webidl/PresentationConnection.webidl
@@ -55,21 +55,20 @@ interface PresentationConnection : Event
    * It is triggered when receiving messages.
    */
   attribute EventHandler onmessage;
 
   /*
    * Both the controlling and receiving browsing context can close the
    * connection. Then the connection state should turn into "closed".
    *
-   * This function only works when the state is not "connected".
+   * This function only works when the state is "connected" or "connecting".
    */
-  // TODO Bug 1210340 - Support close semantics.
-  // [Throws]
-  // void close();
+  [Throws]
+  void close();
 
   /*
    * Both the controlling and receiving browsing context can terminate the
    * connection. Then the connection state should turn into "terminated".
    *
    * This function only works when the state is not "connected".
    */
    [Throws]
--- a/dom/webidl/XMLHttpRequest.webidl
+++ b/dom/webidl/XMLHttpRequest.webidl
@@ -97,16 +97,18 @@ interface XMLHttpRequest : XMLHttpReques
   [Throws]
   void send(Document data);
   [Throws]
   void send(DOMString? data);
   [Throws]
   void send(FormData data);
   [Throws]
   void send(InputStream data);
+  [Throws]
+  void send(URLSearchParams data);
 
   [Throws]
   void abort();
 
   // response
   readonly attribute DOMString responseURL;
 
   [Throws]
--- a/dom/wifi/WifiUtils.cpp
+++ b/dom/wifi/WifiUtils.cpp
@@ -474,38 +474,16 @@ bool WpaSupplicant::ExecuteCommand(Comma
     }
     aResult.mReply = value;
   } else if (aOptions.mCmd.EqualsLiteral("hostapd_get_stations")) {
     aResult.mStatus = mWifiHotspotUtils->do_wifi_hostapd_get_stations();
   } else if (aOptions.mCmd.EqualsLiteral("connect_to_hostapd")) {
     aResult.mStatus = mWifiHotspotUtils->do_wifi_connect_to_hostapd();
   } else if (aOptions.mCmd.EqualsLiteral("close_hostapd_connection")) {
     aResult.mStatus = mWifiHotspotUtils->do_wifi_close_hostapd_connection();
-  } else if (aOptions.mCmd.EqualsLiteral("hostapd_command")) {
-    size_t len = BUFFER_SIZE - 1;
-    char buffer[BUFFER_SIZE];
-    NS_ConvertUTF16toUTF8 request(aOptions.mRequest);
-    aResult.mStatus = mWifiHotspotUtils->do_wifi_hostapd_command(request.get(),
-                                                                 buffer,
-                                                                 &len);
-    nsString value;
-    if (aResult.mStatus == 0) {
-      if (buffer[len - 1] == '\n') { // remove trailing new lines.
-        len--;
-      }
-      buffer[len] = '\0';
-      CheckBuffer(buffer, len, value);
-    }
-    aResult.mReply = value;
-  } else if (aOptions.mCmd.EqualsLiteral("hostapd_get_stations")) {
-    aResult.mStatus = mWifiHotspotUtils->do_wifi_hostapd_get_stations();
-  } else if (aOptions.mCmd.EqualsLiteral("connect_to_hostapd")) {
-    aResult.mStatus = mWifiHotspotUtils->do_wifi_connect_to_hostapd();
-  } else if (aOptions.mCmd.EqualsLiteral("close_hostapd_connection")) {
-    aResult.mStatus = mWifiHotspotUtils->do_wifi_close_hostapd_connection();
 
   } else {
     NS_WARNING("WpaSupplicant::ExecuteCommand : Unknown command");
     printf_stderr("WpaSupplicant::ExecuteCommand : Unknown command: %s",
       NS_ConvertUTF16toUTF8(aOptions.mCmd).get());
     return false;
   }
 
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -1229,17 +1229,17 @@ ExtendableMessageEvent::Constructor(mozi
   event->mOrigin = aOptions.mOrigin;
   event->mLastEventId = aOptions.mLastEventId;
 
   if (aOptions.mSource.WasPassed() && !aOptions.mSource.Value().IsNull()) {
     if (aOptions.mSource.Value().Value().IsClient()) {
       event->mClient = aOptions.mSource.Value().Value().GetAsClient();
     } else if (aOptions.mSource.Value().Value().IsServiceWorker()){
       event->mServiceWorker = aOptions.mSource.Value().Value().GetAsServiceWorker();
-    } else if (aOptions.mSource.Value().Value().IsServiceWorker()){
+    } else if (aOptions.mSource.Value().Value().IsMessagePort()){
       event->mMessagePort = aOptions.mSource.Value().Value().GetAsMessagePort();
     }
     MOZ_ASSERT(event->mClient || event->mServiceWorker || event->mMessagePort);
   }
 
   if (aOptions.mPorts.WasPassed() && !aOptions.mPorts.Value().IsNull()) {
     nsTArray<RefPtr<MessagePort>> ports;
     const Sequence<OwningNonNull<MessagePort>>& portsParam =
--- a/dom/xbl/builtin/moz.build
+++ b/dom/xbl/builtin/moz.build
@@ -5,13 +5,13 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     DIRS += ['win']
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     DIRS += ['mac']
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     DIRS += ['android']
-elif CONFIG['MOZ_WIDGET_TOOLKIT'] in ('qt', 'gtk2', 'gtk3'):
+elif CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'):
     DIRS += ['unix']
 else:
     DIRS += ['emacs']
 
--- a/dom/xhr/XMLHttpRequest.h
+++ b/dom/xhr/XMLHttpRequest.h
@@ -14,16 +14,17 @@
 
 class nsIJSID;
 
 namespace mozilla {
 namespace dom {
 
 class Blob;
 class FormData;
+class URLSearchParams;
 class XMLHttpRequestUpload;
 
 class XMLHttpRequest : public XMLHttpRequestEventTarget
 {
 public:
   static already_AddRefed<XMLHttpRequest>
   Constructor(const GlobalObject& aGlobal,
               const MozXMLHttpRequestParameters& aParams,
@@ -84,16 +85,19 @@ public:
   virtual void
   Send(JSContext* aCx, const ArrayBufferView& aArrayBufferView,
        ErrorResult& aRv) = 0;
 
   virtual void
   Send(JSContext* aCx, Blob& aBlob, ErrorResult& aRv) = 0;
 
   virtual void
+  Send(JSContext* aCx, URLSearchParams& aURLSearchParams, ErrorResult& aRv) = 0;
+
+  virtual void
   Send(JSContext* aCx, nsIDocument& aDoc, ErrorResult& aRv) = 0;
 
   virtual void
   Send(JSContext* aCx, const nsAString& aString, ErrorResult& aRv) = 0;
 
   virtual void
   Send(JSContext* aCx, FormData& aFormData, ErrorResult& aRv) = 0;
 
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -10,16 +10,17 @@
 #include <unistd.h>
 #endif
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/BlobSet.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FetchUtil.h"
 #include "mozilla/dom/FormData.h"
+#include "mozilla/dom/URLSearchParams.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsIDOMDocument.h"
 #include "mozilla/dom/ProgressEvent.h"
 #include "nsIJARChannel.h"
 #include "nsIJARURI.h"
@@ -2213,16 +2214,25 @@ GetRequestBodyInternal(nsIInputStream* a
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ADDREF(*aResult = aStream);
 
   return NS_OK;
 }
 
 static nsresult
+GetRequestBodyInternal(URLSearchParams* aURLSearchParams,
+                       nsIInputStream** aResult, uint64_t* aContentLength,
+                       nsACString& aContentType, nsACString& aCharset)
+{
+  return aURLSearchParams->GetSendInfo(aResult, aContentLength,
+                                       aContentType, aCharset);
+}
+
+static nsresult
 GetRequestBodyInternal(nsIXHRSendable* aSendable, nsIInputStream** aResult,
                        uint64_t* aContentLength, nsACString& aContentType,
                        nsACString& aCharset)
 {
   return aSendable->GetSendInfo(aResult, aContentLength, aContentType, aCharset);
 }
 
 // Used for array buffers and array buffer views
@@ -2339,16 +2349,20 @@ GetRequestBodyInternal(nsIVariant* aBody
 nsresult
 XMLHttpRequestMainThread::GetRequestBody(nsIVariant* aVariant,
                                          const Nullable<RequestBody>& aBody,
                                          nsIInputStream** aResult,
                                          uint64_t* aContentLength,
                                          nsACString& aContentType,
                                          nsACString& aCharset)
 {
+  // null the content type and charset by default, as per XHR spec step 4
+  aContentType.SetIsVoid(true);
+  aCharset.SetIsVoid(true);
+
   if (aVariant) {
     return GetRequestBodyInternal(aVariant, aResult, aContentLength,
                                   aContentType, aCharset);
   }
 
   const RequestBody& body = aBody.Value();
   RequestBody::Value value = body.GetValue();
   switch (body.GetType()) {
@@ -2388,16 +2402,22 @@ XMLHttpRequestMainThread::GetRequestBody
                                     aContentType, aCharset);
     }
     case XMLHttpRequestMainThread::RequestBody::eFormData:
     {
       MOZ_ASSERT(value.mFormData);
       return GetRequestBodyInternal(value.mFormData, aResult, aContentLength,
                                     aContentType, aCharset);
     }
+    case XMLHttpRequestMainThread::RequestBody::eURLSearchParams:
+    {
+      MOZ_ASSERT(value.mURLSearchParams);
+      return GetRequestBodyInternal(value.mURLSearchParams, aResult,
+                                    aContentLength, aContentType, aCharset);
+    }
     case XMLHttpRequestMainThread::RequestBody::eInputStream:
     {
       return GetRequestBodyInternal(value.mStream, aResult, aContentLength,
                                     aContentType, aCharset);
     }
     default:
     {
       return NS_ERROR_FAILURE;
@@ -2507,21 +2527,20 @@ XMLHttpRequestMainThread::Send(nsIVarian
       net::InScriptableRange(size_u64) ? static_cast<int64_t>(size_u64) : -1;
 
     if (postDataStream) {
       // If no content type header was set by the client, we set it to
       // application/xml.
       nsAutoCString contentType;
       if (NS_FAILED(httpChannel->
                       GetRequestHeader(NS_LITERAL_CSTRING("Content-Type"),
-                                       contentType)) ||
-          contentType.IsEmpty()) {
+                                       contentType))) {
         contentType = defaultContentType;
 
-        if (!charset.IsEmpty()) {
+        if (!charset.IsEmpty() && !contentType.IsVoid()) {
           // If we are providing the default content type, then we also need to
           // provide a charset declaration.
           contentType.Append(NS_LITERAL_CSTRING(";charset="));
           contentType.Append(charset);
         }
       }
 
       // We don't want to set a charset for streams.
--- a/dom/xhr/XMLHttpRequestMainThread.h
+++ b/dom/xhr/XMLHttpRequestMainThread.h
@@ -51,16 +51,17 @@ class nsIUnicodeDecoder;
 class nsIJSID;
 
 namespace mozilla {
 namespace dom {
 
 class Blob;
 class BlobSet;
 class FormData;
+class URLSearchParams;
 class XMLHttpRequestUpload;
 
 // A helper for building up an ArrayBuffer object's data
 // before creating the ArrayBuffer itself.  Will do doubling
 // based reallocation, up to an optional maximum growth given.
 //
 // When all the data has been appended, call getArrayBuffer,
 // passing in the JSContext* for which the ArrayBuffer object
@@ -258,16 +259,21 @@ private:
     explicit RequestBody(const ArrayBufferView* aArrayBufferView) : mType(eArrayBufferView)
     {
       mValue.mArrayBufferView = aArrayBufferView;
     }
     explicit RequestBody(Blob& aBlob) : mType(eBlob)
     {
       mValue.mBlob = &aBlob;
     }
+    explicit RequestBody(mozilla::dom::URLSearchParams& aURLSearchParams) :
+      mType(eURLSearchParams)
+    {
+      mValue.mURLSearchParams = &aURLSearchParams;
+    }
     explicit RequestBody(nsIDocument* aDocument) : mType(eDocument)
     {
       mValue.mDocument = aDocument;
     }
     explicit RequestBody(const nsAString& aString) : mType(eDOMString)
     {
       mValue.mString = &aString;
     }
@@ -283,26 +289,28 @@ private:
     enum Type {
       eUninitialized,
       eArrayBuffer,
       eArrayBufferView,
       eBlob,
       eDocument,
       eDOMString,
       eFormData,
-      eInputStream
+      eInputStream,
+      eURLSearchParams
     };
     union Value {
       const ArrayBuffer* mArrayBuffer;
       const ArrayBufferView* mArrayBufferView;
       Blob* mBlob;
       nsIDocument* mDocument;
       const nsAString* mString;
       FormData* mFormData;
       nsIInputStream* mStream;
+      URLSearchParams* mURLSearchParams;
     };
 
     Type GetType() const
     {
       MOZ_ASSERT(mType != eUninitialized);
       return mType;
     }
     Value GetValue() const
@@ -363,16 +371,22 @@ public:
   }
 
   virtual void
   Send(JSContext* /*aCx*/, Blob& aBlob, ErrorResult& aRv) override
   {
     aRv = Send(RequestBody(aBlob));
   }
 
+  virtual void Send(JSContext* /*aCx*/, URLSearchParams& aURLSearchParams,
+                    ErrorResult& aRv) override
+  {
+    aRv = Send(RequestBody(aURLSearchParams));
+  }
+
   virtual void
   Send(JSContext* /*aCx*/, nsIDocument& aDoc, ErrorResult& aRv) override
   {
     aRv = Send(RequestBody(&aDoc));
   }
 
   virtual void
   Send(JSContext* aCx, const nsAString& aString, ErrorResult& aRv) override
--- a/dom/xhr/XMLHttpRequestWorker.cpp
+++ b/dom/xhr/XMLHttpRequestWorker.cpp
@@ -16,16 +16,17 @@
 #include "js/TracingAPI.h"
 #include "js/GCPolicyAPI.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FormData.h"
 #include "mozilla/dom/ProgressEvent.h"
 #include "mozilla/dom/StructuredCloneHolder.h"
+#include "mozilla/dom/URLSearchParams.h"
 #include "mozilla/Telemetry.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsJSUtils.h"
 #include "nsThreadUtils.h"
 #include "nsVariant.h"
 
 #include "RuntimeService.h"
@@ -2162,16 +2163,49 @@ XMLHttpRequestWorker::Send(JSContext* aC
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   SendInternal(sendRunnable, aRv);
 }
 
 void
+XMLHttpRequestWorker::Send(JSContext* aCx, URLSearchParams& aBody,
+                           ErrorResult& aRv)
+{
+  mWorkerPrivate->AssertIsOnWorkerThread();
+
+  if (mCanceled) {
+    aRv.ThrowUncatchableException();
+    return;
+  }
+
+  if (!mProxy) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
+
+  JS::Rooted<JS::Value> value(aCx);
+  if (!GetOrCreateDOMReflector(aCx, &aBody, &value)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
+  RefPtr<SendRunnable> sendRunnable =
+    new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
+
+  sendRunnable->Write(aCx, value, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+
+  SendInternal(sendRunnable, aRv);
+}
+
+void
 XMLHttpRequestWorker::Send(JSContext* aCx, const ArrayBuffer& aBody,
                            ErrorResult& aRv)
 {
   JS::Rooted<JSObject*> obj(mWorkerPrivate->GetJSContext(), aBody.Obj());
   return Send(aCx, obj, aRv);
 }
 
 void
--- a/dom/xhr/XMLHttpRequestWorker.h
+++ b/dom/xhr/XMLHttpRequestWorker.h
@@ -171,16 +171,19 @@ public:
 
   virtual void
   Send(JSContext* aCx, const ArrayBuffer& aBody, ErrorResult& aRv) override;
 
   virtual void
   Send(JSContext* aCx, const ArrayBufferView& aBody, ErrorResult& aRv) override;
 
   virtual void
+  Send(JSContext* aCx, URLSearchParams& aBody, ErrorResult& aRv) override;
+
+  virtual void
   Send(JSContext* aCx, nsIDocument& aDoc, ErrorResult& aRv) override
   {
     MOZ_CRASH("This method cannot be called on workers.");
   }
 
   virtual void
   Abort(ErrorResult& aRv) override;
 
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -1118,28 +1118,28 @@ HTMLEditor::TabInTable(bool inIsShift,
     if (cell) {
       selection->Collapse(cell, 0);
     }
   }
 
   return NS_OK;
 }
 
-Element*
+already_AddRefed<Element>
 HTMLEditor::CreateBR(nsINode* aNode,
                      int32_t aOffset,
                      EDirection aSelect)
 {
   nsCOMPtr<nsIDOMNode> parent = GetAsDOMNode(aNode);
   int32_t offset = aOffset;
   nsCOMPtr<nsIDOMNode> outBRNode;
   // We assume everything is fine if the br is not null, irrespective of retval
   CreateBRImpl(address_of(parent), &offset, address_of(outBRNode), aSelect);
   nsCOMPtr<Element> ret = do_QueryInterface(outBRNode);
-  return ret;
+  return ret.forget();
 }
 
 NS_IMETHODIMP
 HTMLEditor::CreateBR(nsIDOMNode* aNode,
                      int32_t aOffset,
                      nsCOMPtr<nsIDOMNode>* outBRNode,
                      EDirection aSelect)
 {
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -487,18 +487,18 @@ protected:
   already_AddRefed<nsINode> GetFocusedNode();
 
   /**
    * Return TRUE if aElement is a table-related elemet and caret was set.
    */
   bool SetCaretInTableCell(nsIDOMElement* aElement);
 
   NS_IMETHOD TabInTable(bool inIsShift, bool* outHandled);
-  Element* CreateBR(nsINode* aNode, int32_t aOffset,
-                    EDirection aSelect = eNone);
+  already_AddRefed<Element> CreateBR(nsINode* aNode, int32_t aOffset,
+                                     EDirection aSelect = eNone);
   NS_IMETHOD CreateBR(
                nsIDOMNode* aNode, int32_t aOffset,
                nsCOMPtr<nsIDOMNode>* outBRNode,
                nsIEditor::EDirection aSelect = nsIEditor::eNone) override;
 
   // Table Editing (implemented in nsTableEditor.cpp)
 
   /**
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -432,28 +432,28 @@ TextEditor::TypedText(const nsAString& a
     case eTypedBreak:
       return InsertLineBreak();
     default:
       // eTypedBR is only for HTML
       return NS_ERROR_FAILURE;
   }
 }
 
-Element*
+already_AddRefed<Element>
 TextEditor::CreateBRImpl(nsCOMPtr<nsINode>* aInOutParent,
                          int32_t* aInOutOffset,
                          EDirection aSelect)
 {
   nsCOMPtr<nsIDOMNode> parent(GetAsDOMNode(*aInOutParent));
   nsCOMPtr<nsIDOMNode> br;
   // We ignore the retval, and assume it's fine if the br is non-null
   CreateBRImpl(address_of(parent), aInOutOffset, address_of(br), aSelect);
   *aInOutParent = do_QueryInterface(parent);
   nsCOMPtr<Element> ret(do_QueryInterface(br));
-  return ret;
+  return ret.forget();
 }
 
 nsresult
 TextEditor::CreateBRImpl(nsCOMPtr<nsIDOMNode>* aInOutParent,
                          int32_t* aInOutOffset,
                          nsCOMPtr<nsIDOMNode>* outBRNode,
                          EDirection aSelect)
 {
--- a/editor/libeditor/TextEditor.h
+++ b/editor/libeditor/TextEditor.h
@@ -179,18 +179,19 @@ protected:
   NS_IMETHOD GetAndInitDocEncoder(const nsAString& aFormatType,
                                   uint32_t aFlags,
                                   const nsACString& aCharset,
                                   nsIDocumentEncoder** encoder);
 
   NS_IMETHOD CreateBR(nsIDOMNode* aNode, int32_t aOffset,
                       nsCOMPtr<nsIDOMNode>* outBRNode,
                       EDirection aSelect = eNone);
-  Element* CreateBRImpl(nsCOMPtr<nsINode>* aInOutParent, int32_t* aInOutOffset,
-                        EDirection aSelect);
+  already_AddRefed<Element> CreateBRImpl(nsCOMPtr<nsINode>* aInOutParent,
+                                         int32_t* aInOutOffset,
+                                         EDirection aSelect);
   nsresult CreateBRImpl(nsCOMPtr<nsIDOMNode>* aInOutParent,
                         int32_t* aInOutOffset,
                         nsCOMPtr<nsIDOMNode>* outBRNode,
                         EDirection aSelect);
   nsresult InsertBR(nsCOMPtr<nsIDOMNode>* outBRNode);
 
   /**
    * Factored methods for handling insertion of data from transferables
--- a/editor/libeditor/WSRunObject.cpp
+++ b/editor/libeditor/WSRunObject.cpp
@@ -161,17 +161,17 @@ WSRunObject::PrepareToSplitAcrossBlocks(
   AutoTrackDOMPoint tracker(aHTMLEditor->mRangeUpdater,
                             aSplitNode, aSplitOffset);
 
   WSRunObject wsObj(aHTMLEditor, *aSplitNode, *aSplitOffset);
 
   return wsObj.PrepareToSplitAcrossBlocksPriv();
 }
 
-Element*
+already_AddRefed<Element>
 WSRunObject::InsertBreak(nsCOMPtr<nsINode>* aInOutParent,
                          int32_t* aInOutOffset,
                          nsIEditor::EDirection aSelect)
 {
   // MOOSE: for now, we always assume non-PRE formatting.  Fix this later.
   // meanwhile, the pre case is handled in WillInsertText in
   // HTMLEditRules.cpp
   NS_ENSURE_TRUE(aInOutParent && aInOutOffset, nullptr);
--- a/editor/libeditor/WSRunObject.h
+++ b/editor/libeditor/WSRunObject.h
@@ -210,19 +210,19 @@ public:
   static nsresult PrepareToSplitAcrossBlocks(HTMLEditor* aHTMLEditor,
                                              nsCOMPtr<nsINode>* aSplitNode,
                                              int32_t* aSplitOffset);
 
   // InsertBreak inserts a br node at {aInOutParent,aInOutOffset}
   // and makes any needed adjustments to ws around that point.
   // example of fixup: normalws after {aInOutParent,aInOutOffset}
   //                   needs to begin with nbsp.
-  dom::Element* InsertBreak(nsCOMPtr<nsINode>* aInOutParent,
-                            int32_t* aInOutOffset,
-                            nsIEditor::EDirection aSelect);
+  already_AddRefed<dom::Element> InsertBreak(nsCOMPtr<nsINode>* aInOutParent,
+                                             int32_t* aInOutOffset,
+                                             nsIEditor::EDirection aSelect);
 
   // InsertText inserts a string at {aInOutParent,aInOutOffset} and makes any
   // needed adjustments to ws around that point.  Example of fixup:
   // trailingws before {aInOutParent,aInOutOffset} needs to be removed.
   nsresult InsertText(const nsAString& aStringToInsert,
                       nsCOMPtr<nsINode>* aInOutNode,
                       int32_t* aInOutOffset,
                       nsIDocument* aDoc);
--- a/extensions/cookie/test/unit/test_bug526789.js
+++ b/extensions/cookie/test/unit/test_bug526789.js
@@ -74,33 +74,20 @@ function run_test() {
     cm.countCookiesFromHost(".co.uk");
   }, Cr.NS_ERROR_ILLEGAL_VALUE);
   do_check_throws(function() {
     cm.countCookiesFromHost(".co.uk.");
   }, Cr.NS_ERROR_ILLEGAL_VALUE);
 
   cm.removeAll();
 
-  // test that setting an empty or '.' http:// host results in a no-op
   var uri = NetUtil.newURI("http://baz.com/");
-  var emptyuri = NetUtil.newURI("http:///");
-  var doturi = NetUtil.newURI("http://./");
   do_check_eq(uri.asciiHost, "baz.com");
-  do_check_eq(emptyuri.asciiHost, "");
-  do_check_eq(doturi.asciiHost, ".");
-  cs.setCookieString(emptyuri, null, "foo2=bar", null);
-  do_check_eq(getCookieCount(), 0);
-  cs.setCookieString(doturi, null, "foo3=bar", null);
-  do_check_eq(getCookieCount(), 0);
   cs.setCookieString(uri, null, "foo=bar", null);
-  do_check_eq(getCookieCount(), 1);
-
   do_check_eq(cs.getCookieString(uri, null), "foo=bar");
-  do_check_eq(cs.getCookieString(emptyuri, null), null);
-  do_check_eq(cs.getCookieString(doturi, null), null);
 
   do_check_eq(cm.countCookiesFromHost(""), 0);
   do_check_throws(function() {
     cm.countCookiesFromHost(".");
   }, Cr.NS_ERROR_ILLEGAL_VALUE);
   do_check_throws(function() {
     cm.countCookiesFromHost("..");
   }, Cr.NS_ERROR_ILLEGAL_VALUE);
--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -341,17 +341,18 @@ public:
            _21 == 0.0f && _22 == 1.0f &&
            _31 == 0.0f && _32 == 0.0f;
   }
 
   /* Returns true if the matrix is singular.
    */
   bool IsSingular() const
   {
-    return Determinant() == 0;
+    Float det = Determinant();
+    return !mozilla::IsFinite(det) || det == 0;
   }
 
   GFX2D_API Matrix &NudgeToIntegers();
 
   bool IsTranslation() const
   {
     return FuzzyEqual(_11, 1.0f) && FuzzyEqual(_12, 0.0f) &&
            FuzzyEqual(_21, 0.0f) && FuzzyEqual(_22, 1.0f);
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -197,17 +197,17 @@ if CONFIG['CPU_ARCH'] == 'arm' and CONFI
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 for var in ('USE_CAIRO', 'MOZ2D_HAS_MOZ_CAIRO'):
     DEFINES[var] = True
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gtk3', 'gonk', 'qt'):
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gtk3', 'gonk'):
     DEFINES['MOZ_ENABLE_FREETYPE'] = True
 
 CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gtk3', 'gonk', 'qt'):
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gtk3', 'gonk'):
     CXXFLAGS += CONFIG['CAIRO_FT_CFLAGS']
 
 LOCAL_INCLUDES += CONFIG['SKIA_INCLUDES']
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -802,16 +802,17 @@ GLContext::InitWithPrefixImpl(const char
     // defined in GLContext.h for renderer IDs.
     const char* rendererMatchStrings[size_t(GLRenderer::Other)] = {
         "Adreno 200",
         "Adreno 205",
         "Adreno (TM) 200",
         "Adreno (TM) 205",
         "Adreno (TM) 320",
         "Adreno (TM) 420",
+        "Mali-400 MP",
         "PowerVR SGX 530",
         "PowerVR SGX 540",
         "NVIDIA Tegra",
         "Android Emulator",
         "Gallium 0.4 on llvmpipe",
         "Intel HD Graphics 3000 OpenGL Engine",
         "Microsoft Basic Render Driver"
     };
@@ -1759,16 +1760,23 @@ GLContext::InitExtensions()
 
         if (Vendor() == GLVendor::Imagination &&
             Renderer() == GLRenderer::SGX540)
         {
             // Bug 980048
             MarkExtensionUnsupported(OES_EGL_sync);
         }
 
+        if (Vendor() == GLVendor::ARM &&
+            Renderer() == GLRenderer::Mali400MP)
+        {
+            // Bug 1264505
+            MarkExtensionUnsupported(OES_EGL_image_external);
+        }
+
         if (Renderer() == GLRenderer::AndroidEmulator) {
             // the Android emulator, which we use to run B2G reftests on,
             // doesn't expose the OES_rgb8_rgba8 extension, but it seems to
             // support it (tautologically, as it only runs on desktop GL).
             MarkExtensionSupported(OES_rgb8_rgba8);
             // there seems to be a similar issue for EXT_texture_format_BGRA8888
             // on the Android 4.3 emulator
             MarkExtensionSupported(EXT_texture_format_BGRA8888);
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -172,16 +172,17 @@ enum class GLVendor {
 
 enum class GLRenderer {
     Adreno200,
     Adreno205,
     AdrenoTM200,
     AdrenoTM205,
     AdrenoTM320,
     AdrenoTM420,
+    Mali400MP,
     SGX530,
     SGX540,
     Tegra,
     AndroidEmulator,
     GalliumLlvmpipe,
     IntelHD3000,
     MicrosoftBasicRenderDriver,
     Other
@@ -3337,16 +3338,21 @@ private:
 
 public:
 
     void ForceDirtyScreen();
     void CleanDirtyScreen();
 
     virtual GLenum GetPreferredARGB32Format() const { return LOCAL_GL_RGBA; }
 
+    virtual GLenum GetPreferredEGLImageTextureTarget() const {
+        return IsExtensionSupported(OES_EGL_image_external) ?
+            LOCAL_GL_TEXTURE_EXTERNAL : LOCAL_GL_TEXTURE_2D;
+    }
+
     virtual bool RenewSurface(nsIWidget* aWidget) { return false; }
 
     // Shared code for GL extensions and GLX extensions.
     static bool ListHasExtension(const GLubyte* extensions,
                                  const char* extension);
 
     GLint GetMaxTextureImageSize() { return mMaxTextureImageSize; }
 
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -2,18 +2,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/. */
 
 #if defined(MOZ_WIDGET_GTK)
     #include <gdk/gdkx.h>
     // we're using default display for now
     #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow*)aWidget->GetNativeData(NS_NATIVE_WINDOW)))
-#elif defined(MOZ_WIDGET_QT)
-    #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW))
 #else
     #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
     #define GET_JAVA_SURFACE(aWidget) (aWidget->GetNativeData(NS_JAVA_SURFACE))
 #endif
 
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -2,18 +2,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/. */
 
 #ifdef MOZ_WIDGET_GTK
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
 #define GET_NATIVE_WINDOW(aWidget) GDK_WINDOW_XID((GdkWindow*) aWidget->GetNativeData(NS_NATIVE_WINDOW))
-#elif defined(MOZ_WIDGET_QT)
-#define GET_NATIVE_WINDOW(aWidget) (Window)(aWidget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW))
 #endif
 
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/StaticPtr.h"
 
@@ -1112,17 +1110,17 @@ GLContextProviderGLX::CreateForWindow(ns
 
     // Currently, we take whatever Visual the window already has, and
     // try to create an fbconfig for that visual.  This isn't
     // necessarily what we want in the long run; an fbconfig may not
     // be available for the existing visual, or if it is, the GL
     // performance might be suboptimal.  But using the existing visual
     // is a relatively safe intermediate step.
 
-    Display* display = (Display*)aWidget->GetNativeData(NS_NATIVE_DISPLAY);
+    Display* display = (Display*)aWidget->GetNativeData(NS_NATIVE_COMPOSITOR_DISPLAY);
     if (!display) {
         NS_ERROR("X Display required for GLX Context provider");
         return nullptr;
     }
 
     int xscreen = DefaultScreen(display);
     Window window = GET_NATIVE_WINDOW(aWidget);
 
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -206,17 +206,17 @@ GLLibraryEGL::ReadbackEGLImage(EGLImage 
     StaticMutexAutoUnlock lock(sMutex);
     if (!mReadbackGL) {
         nsCString discardFailureId;
         mReadbackGL = gl::GLContextProvider::CreateHeadless(gl::CreateContextFlags::NONE,
                                                             &discardFailureId);
     }
 
     ScopedTexture destTex(mReadbackGL);
-    const GLuint target = LOCAL_GL_TEXTURE_EXTERNAL;
+    const GLuint target = mReadbackGL->GetPreferredEGLImageTextureTarget();
     ScopedBindTexture autoTex(mReadbackGL, destTex.Texture(), target);
     mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
     mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
     mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
     mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
     mReadbackGL->fEGLImageTargetTexture2D(target, image);
 
     ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(target,
--- a/gfx/gl/SharedSurfaceEGL.cpp
+++ b/gfx/gl/SharedSurfaceEGL.cpp
@@ -53,17 +53,18 @@ SharedSurface_EGLImage::Create(GLContext
     return Move(ret);
 }
 
 bool
 SharedSurface_EGLImage::HasExtensions(GLLibraryEGL* egl, GLContext* gl)
 {
     return egl->HasKHRImageBase() &&
            egl->IsExtensionSupported(GLLibraryEGL::KHR_gl_texture_2D_image) &&
-           gl->IsExtensionSupported(GLContext::OES_EGL_image_external);
+           (gl->IsExtensionSupported(GLContext::OES_EGL_image_external) ||
+            gl->IsExtensionSupported(GLContext::OES_EGL_image));
 }
 
 SharedSurface_EGLImage::SharedSurface_EGLImage(GLContext* gl,
                                                GLLibraryEGL* egl,
                                                const gfx::IntSize& size,
                                                bool hasAlpha,
                                                const GLFormats& formats,
                                                GLuint prodTex,
@@ -74,38 +75,30 @@ SharedSurface_EGLImage::SharedSurface_EG
                     size,
                     hasAlpha,
                     false) // Can't recycle, as mSync changes never update TextureHost.
     , mMutex("SharedSurface_EGLImage mutex")
     , mEGL(egl)
     , mFormats(formats)
     , mProdTex(prodTex)
     , mImage(image)
-    , mCurConsGL(nullptr)
-    , mConsTex(0)
     , mSync(0)
 {}
 
 SharedSurface_EGLImage::~SharedSurface_EGLImage()
 {
     mEGL->fDestroyImage(Display(), mImage);
 
     if (mSync) {
         // We can't call this unless we have the ext, but we will always have
         // the ext if we have something to destroy.
         mEGL->fDestroySync(Display(), mSync);
         mSync = 0;
     }
 
-    if (mConsTex) {
-        MOZ_ASSERT(mGarbageBin);
-        mGarbageBin->Trash(mConsTex);
-        mConsTex = 0;
-    }
-
     if (!mGL->MakeCurrent())
         return;
 
     mGL->fDeleteTextures(1, &mProdTex);
     mProdTex = 0;
 }
 
 layers::TextureFlags
@@ -152,38 +145,16 @@ SharedSurface_EGLImage::ProducerReadAcqu
 }
 
 EGLDisplay
 SharedSurface_EGLImage::Display() const
 {
     return mEGL->Display();
 }
 
-void
-SharedSurface_EGLImage::AcquireConsumerTexture(GLContext* consGL, GLuint* out_texture, GLuint* out_target)
-{
-    MutexAutoLock lock(mMutex);
-    MOZ_ASSERT(!mCurConsGL || consGL == mCurConsGL);
-
-    if (!mConsTex) {
-        consGL->fGenTextures(1, &mConsTex);
-        MOZ_ASSERT(mConsTex);
-
-        ScopedBindTexture autoTex(consGL, mConsTex, LOCAL_GL_TEXTURE_EXTERNAL);
-        consGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_EXTERNAL, mImage);
-
-        mCurConsGL = consGL;
-        mGarbageBin = consGL->TexGarbageBin();
-    }
-
-    MOZ_ASSERT(consGL == mCurConsGL);
-    *out_texture = mConsTex;
-    *out_target = LOCAL_GL_TEXTURE_EXTERNAL;
-}
-
 bool
 SharedSurface_EGLImage::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
 {
     *out_descriptor = layers::EGLImageDescriptor((uintptr_t)mImage, (uintptr_t)mSync,
                                                  mSize, mHasAlpha);
     return true;
 }
 
--- a/gfx/gl/SharedSurfaceEGL.h
+++ b/gfx/gl/SharedSurfaceEGL.h
@@ -38,19 +38,16 @@ public:
 protected:
     mutable Mutex mMutex;
     GLLibraryEGL* const mEGL;
     const GLFormats mFormats;
     GLuint mProdTex;
 public:
     const EGLImage mImage;
 protected:
-    GLContext* mCurConsGL;
-    GLuint mConsTex;
-    RefPtr<TextureGarbageBin> mGarbageBin;
     EGLSync mSync;
 
     SharedSurface_EGLImage(GLContext* gl,
                            GLLibraryEGL* egl,
                            const gfx::IntSize& size,
                            bool hasAlpha,
                            const GLFormats& formats,
                            GLuint prodTex,
@@ -74,18 +71,16 @@ public:
     virtual void ProducerReadReleaseImpl() override {};
 
     virtual GLuint ProdTexture() override {
       return mProdTex;
     }
 
     // Implementation-specific functions below:
     // Returns texture and target
-    void AcquireConsumerTexture(GLContext* consGL, GLuint* out_texture, GLuint* out_target);
-
     virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
 
     virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override;
 };
 
 
 
 class SurfaceFactory_EGLImage
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -12,18 +12,16 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'co
     gl_provider = 'CGL'
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'uikit':
     gl_provider = 'EAGL'
 elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
     if CONFIG['MOZ_EGL_XRENDER_COMPOSITE']:
         gl_provider = 'EGL'
     else:
         gl_provider = 'GLX'
-elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
-    gl_provider = 'GLX'
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     gl_provider = 'EGL'
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     gl_provider = 'EGL'
 
 if CONFIG['MOZ_GL_PROVIDER']:
     gl_provider = CONFIG['MOZ_GL_PROVIDER']
 
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -49,81 +49,30 @@
 
 struct nsCSSValueSharedList;
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
-enum Op { Resolve, Detach };
-
 static bool
 IsSameDimension(dom::ScreenOrientationInternal o1, dom::ScreenOrientationInternal o2)
 {
   bool isO1portrait = (o1 == dom::eScreenOrientation_PortraitPrimary || o1 == dom::eScreenOrientation_PortraitSecondary);
   bool isO2portrait = (o2 == dom::eScreenOrientation_PortraitPrimary || o2 == dom::eScreenOrientation_PortraitSecondary);
   return !(isO1portrait ^ isO2portrait);
 }
 
 static bool
 ContentMightReflowOnOrientationChange(const IntRect& rect)
 {
   return rect.width != rect.height;
 }
 
-template<Op OP>
-static void
-WalkTheTree(Layer* aLayer,
-            bool& aReady,
-            const TargetConfig& aTargetConfig,
-            CompositorBridgeParent* aCompositor,
-            bool& aHasRemote,
-            bool aWillResolvePlugins,
-            bool& aDidResolvePlugins)
-{
-
-  ForEachNode<ForwardIterator>(
-      aLayer,
-      [&](Layer* layer)
-      {
-        if (RefLayer* ref = layer->AsRefLayer()) {
-          aHasRemote = true;
-          if (const CompositorBridgeParent::LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(ref->GetReferentId())) {
-            if (Layer* referent = state->mRoot) {
-              if (!ref->GetLocalVisibleRegion().IsEmpty()) {
-                dom::ScreenOrientationInternal chromeOrientation = aTargetConfig.orientation();
-                dom::ScreenOrientationInternal contentOrientation = state->mTargetConfig.orientation();
-                if (!IsSameDimension(chromeOrientation, contentOrientation) &&
-                    ContentMightReflowOnOrientationChange(aTargetConfig.naturalBounds())) {
-                  aReady = false;
-                }
-              }
-
-              if (OP == Resolve) {
-                ref->ConnectReferentLayer(referent);
-      #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
-                if (aCompositor && aWillResolvePlugins) {
-                  aDidResolvePlugins |=
-                    aCompositor->UpdatePluginWindowState(ref->GetReferentId());
-                }
-      #endif
-              } else {
-                ref->DetachReferentLayer(referent);
-                WalkTheTree<OP>(referent, aReady, aTargetConfig,
-                                aCompositor, aHasRemote, aWillResolvePlugins,
-                                aDidResolvePlugins);
-              }
-            }
-          }
-        }
-        return TraversalFlag::Continue;
-      });
-}
-
 AsyncCompositionManager::AsyncCompositionManager(LayerManagerComposite* aManager)
   : mLayerManager(aManager)
   , mIsFirstPaint(true)
   , mLayersUpdated(false)
   , mPaintSyncId(0)
   , mReadyForCompose(true)
 {
 }
@@ -136,58 +85,112 @@ void
 AsyncCompositionManager::ResolveRefLayers(CompositorBridgeParent* aCompositor,
                                           bool* aHasRemoteContent,
                                           bool* aResolvePlugins)
 {
   if (aHasRemoteContent) {
     *aHasRemoteContent = false;
   }
 
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
   // If valid *aResolvePlugins indicates if we need to update plugin geometry
   // when we walk the tree.
-  bool willResolvePlugins = (aResolvePlugins && *aResolvePlugins);
+  bool resolvePlugins = (aCompositor && aResolvePlugins && *aResolvePlugins);
+#endif
+
   if (!mLayerManager->GetRoot()) {
     // Updated the return value since this result controls completing composition.
     if (aResolvePlugins) {
       *aResolvePlugins = false;
     }
     return;
   }
 
   mReadyForCompose = true;
   bool hasRemoteContent = false;
   bool didResolvePlugins = false;
-  WalkTheTree<Resolve>(mLayerManager->GetRoot(),
-                       mReadyForCompose,
-                       mTargetConfig,
-                       aCompositor,
-                       hasRemoteContent,
-                       willResolvePlugins,
-                       didResolvePlugins);
+
+  ForEachNode<ForwardIterator>(
+    mLayerManager->GetRoot(),
+    [&](Layer* layer)
+    {
+      RefLayer* refLayer = layer->AsRefLayer();
+      if (!refLayer) {
+        return;
+      }
+
+      hasRemoteContent = true;
+      const CompositorBridgeParent::LayerTreeState* state =
+        CompositorBridgeParent::GetIndirectShadowTree(refLayer->GetReferentId());
+      if (!state) {
+        return;
+      }
+
+      Layer* referent = state->mRoot;
+      if (!referent) {
+        return;
+      }
+
+      if (!refLayer->GetLocalVisibleRegion().IsEmpty()) {
+        dom::ScreenOrientationInternal chromeOrientation =
+          mTargetConfig.orientation();
+        dom::ScreenOrientationInternal contentOrientation =
+          state->mTargetConfig.orientation();
+        if (!IsSameDimension(chromeOrientation, contentOrientation) &&
+            ContentMightReflowOnOrientationChange(mTargetConfig.naturalBounds())) {
+          mReadyForCompose = false;
+        }
+      }
+
+      refLayer->ConnectReferentLayer(referent);
+
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+      if (resolvePlugins) {
+        didResolvePlugins |=
+          aCompositor->UpdatePluginWindowState(refLayer->GetReferentId());
+      }
+#endif
+    });
+
   if (aHasRemoteContent) {
     *aHasRemoteContent = hasRemoteContent;
   }
   if (aResolvePlugins) {
     *aResolvePlugins = didResolvePlugins;
   }
 }
 
 void
 AsyncCompositionManager::DetachRefLayers()
 {
   if (!mLayerManager->GetRoot()) {
     return;
   }
-  CompositorBridgeParent* dummy = nullptr;
-  bool ignored = false;
-  WalkTheTree<Detach>(mLayerManager->GetRoot(),
-                      mReadyForCompose,
-                      mTargetConfig,
-                      dummy,
-                      ignored, ignored, ignored);
+
+  mReadyForCompose = false;
+
+  ForEachNodePostOrder<ForwardIterator>(mLayerManager->GetRoot(),
+    [&](Layer* layer)
+    {
+      RefLayer* refLayer = layer->AsRefLayer();
+      if (!refLayer) {
+        return;
+      }
+
+      const CompositorBridgeParent::LayerTreeState* state =
+        CompositorBridgeParent::GetIndirectShadowTree(refLayer->GetReferentId());
+      if (!state) {
+        return;
+      }
+
+      Layer* referent = state->mRoot;
+      if (referent) {
+        refLayer->DetachReferentLayer(referent);
+      }
+    });
 }
 
 void
 AsyncCompositionManager::ComputeRotation()
 {
   if (!mTargetConfig.naturalBounds().IsEmpty()) {
     mWorldTransform =
       ComputeTransformForRotation(mTargetConfig.naturalBounds(),
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -662,17 +662,17 @@ EGLImageTextureHost::Lock()
     MOZ_ASSERT(status != 0,
                "ClientWaitSync generated an error. Has mSync already been destroyed?");
     return false;
   }
 
   if (!mTextureSource) {
     gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8
                                           : gfx::SurfaceFormat::R8G8B8X8;
-    GLenum target = LOCAL_GL_TEXTURE_EXTERNAL;
+    GLenum target = gl->GetPreferredEGLImageTextureTarget();
     GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
     mTextureSource = new EGLImageTextureSource(mCompositor,
                                                mImage,
                                                format,
                                                target,
                                                wrapMode,
                                                mSize);
   }
--- a/gfx/skia/generate_mozbuild.py
+++ b/gfx/skia/generate_mozbuild.py
@@ -61,17 +61,16 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('and
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in {
     'android',
     'cocoa',
     'gtk2',
     'gtk3',
     'uikit',
     'gonk',
-    'qt',
   }:
     DEFINES['SK_FONTHOST_DOES_NOT_USE_FONTMGR'] = 1
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     DEFINES['UNICODE'] = True
     DEFINES['_UNICODE'] = True
     # These are the usual dwrite default rendering param values
     DEFINES['SK_GAMMA_EXPONENT'] = 1.8
@@ -133,21 +132,21 @@ if CONFIG['GNU_CXX'] and not CONFIG['CLA
 if CONFIG['CLANG_CXX'] or CONFIG['CLANG_CL']:
     CXXFLAGS += [
         '-Wno-implicit-fallthrough',
         '-Wno-inconsistent-missing-override',
         '-Wno-macro-redefined',
         '-Wno-unused-private-field',
     ]
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'android', 'gonk', 'qt'):
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'android', 'gonk'):
     CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
     CXXFLAGS += CONFIG['CAIRO_FT_CFLAGS']
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'qt'):
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'):
     CXXFLAGS += CONFIG['MOZ_PANGO_CFLAGS']
 """
 
 import json
 
 platforms = ['linux', 'mac', 'android', 'win']
 
 def generate_opt_sources():
@@ -414,19 +413,16 @@ def write_mozbuild(sources):
   write_sources(f, sources['android'], 4)
 
   f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] in {'cocoa', 'uikit'}:\n")
   write_sources(f, sources['mac'], 4)
 
   f.write("if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:\n")
   write_sources(f, sources['linux'], 4)
 
-  f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':\n")
-  write_sources(f, sources['linux'], 4)
-
   f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':\n")
   # Windows-specific files don't get unification because of nasty headers.
   # Luckily there are not many files in this.
   write_list(f, "SOURCES", sources['win'], 4)
 
   f.write("if CONFIG['INTEL_ARCHITECTURE']:\n")
   write_sources(f, sources['intel'], 4)
 
--- a/gfx/skia/moz.build
+++ b/gfx/skia/moz.build
@@ -483,28 +483,16 @@ if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']
         'skia/src/ports/SkOSLibrary_posix.cpp',
         'skia/src/ports/SkTLS_pthread.cpp',
         'skia/src/utils/SkThreadUtils_pthread.cpp',
     ]
     SOURCES += [
         'skia/src/ports/SkFontHost_cairo.cpp',
         'skia/src/ports/SkFontHost_FreeType_common.cpp',
     ]
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
-    UNIFIED_SOURCES += [
-        'skia/src/ports/SkDebug_stdio.cpp',
-        'skia/src/ports/SkOSFile_posix.cpp',
-        'skia/src/ports/SkOSLibrary_posix.cpp',
-        'skia/src/ports/SkTLS_pthread.cpp',
-        'skia/src/utils/SkThreadUtils_pthread.cpp',
-    ]
-    SOURCES += [
-        'skia/src/ports/SkFontHost_cairo.cpp',
-        'skia/src/ports/SkFontHost_FreeType_common.cpp',
-    ]
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     SOURCES += [
         'skia/src/ports/SkDebug_win.cpp',
         'skia/src/ports/SkFontHost_win.cpp',
         'skia/src/ports/SkFontMgr_win_dw.cpp',
         'skia/src/ports/SkFontMgr_win_dw_factory.cpp',
         'skia/src/ports/SkOSFile_win.cpp',
         'skia/src/ports/SkOSLibrary_win.cpp',
@@ -597,17 +585,16 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('and
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in {
     'android',
     'cocoa',
     'gtk2',
     'gtk3',
     'uikit',
     'gonk',
-    'qt',
   }:
     DEFINES['SK_FONTHOST_DOES_NOT_USE_FONTMGR'] = 1
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     DEFINES['UNICODE'] = True
     DEFINES['_UNICODE'] = True
     # These are the usual dwrite default rendering param values
     DEFINES['SK_GAMMA_EXPONENT'] = 1.8
@@ -669,14 +656,14 @@ if CONFIG['GNU_CXX'] and not CONFIG['CLA
 if CONFIG['CLANG_CXX'] or CONFIG['CLANG_CL']:
     CXXFLAGS += [
         '-Wno-implicit-fallthrough',
         '-Wno-inconsistent-missing-override',
         '-Wno-macro-redefined',
         '-Wno-unused-private-field',
     ]
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'android', 'gonk', 'qt'):
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'android', 'gonk'):
     CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
     CXXFLAGS += CONFIG['CAIRO_FT_CFLAGS']
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'qt'):
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'):
     CXXFLAGS += CONFIG['MOZ_PANGO_CFLAGS']
--- a/gfx/src/X11Util.h
+++ b/gfx/src/X11Util.h
@@ -8,39 +8,33 @@
 #ifndef mozilla_X11Util_h
 #define mozilla_X11Util_h
 
 // Utilities common to all X clients, regardless of UI toolkit.
 
 #if defined(MOZ_WIDGET_GTK)
 #  include <gdk/gdk.h>
 #  include <gdk/gdkx.h>
-#elif defined(MOZ_WIDGET_QT)
-#include "gfxQtPlatform.h"
-#undef CursorShape
-#  include <X11/Xlib.h>
 #else
 #  error Unknown toolkit
-#endif 
+#endif
 
 #include <string.h>                     // for memset
 #include "mozilla/Scoped.h"             // for SCOPED_TEMPLATE
 
 namespace mozilla {
 
 /**
  * Return the default X Display created and used by the UI toolkit.
  */
 inline Display*
 DefaultXDisplay()
 {
 #if defined(MOZ_WIDGET_GTK)
   return GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
-#elif defined(MOZ_WIDGET_QT)
-  return gfxQtPlatform::GetXDisplay();
 #endif
 }
 
 /**
  * Sets *aVisual to point to aDisplay's Visual struct corresponding to
  * aVisualID, and *aDepth to its depth.  When aVisualID is None, these are set
  * to nullptr and 0 respectively.  Both out-parameter pointers are assumed
  * non-nullptr.
--- a/gfx/thebes/gfxASurface.cpp
+++ b/gfx/thebes/gfxASurface.cpp
@@ -146,18 +146,16 @@ gfxASurface::Wrap (cairo_surface_t *csur
     if (result) {
         // fprintf(stderr, "Existing wrapper for %p -> %p\n", csurf, result);
         return result.forget();
     }
 
     /* No wrapper; figure out the surface type and create it */
     cairo_surface_type_t stype = cairo_surface_get_type(csurf);
 
-    MOZ_ASSERT(stype != CAIRO_SURFACE_TYPE_QT);
-
     if (stype == CAIRO_SURFACE_TYPE_IMAGE) {
         result = new gfxImageSurface(csurf);
     }
 #ifdef CAIRO_HAS_WIN32_SURFACE
     else if (stype == CAIRO_SURFACE_TYPE_WIN32 ||
              stype == CAIRO_SURFACE_TYPE_WIN32_PRINTING) {
         result = new gfxWindowsSurface(csurf);
     }
--- a/gfx/thebes/gfxFT2Fonts.cpp
+++ b/gfx/thebes/gfxFT2Fonts.cpp
@@ -1,20 +1,16 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #if defined(MOZ_WIDGET_GTK)
 #include "gfxPlatformGtk.h"
 #define gfxToolkitPlatform gfxPlatformGtk
-#elif defined(MOZ_WIDGET_QT)
-#include <qfontinfo.h>
-#include "gfxQtPlatform.h"
-#define gfxToolkitPlatform gfxQtPlatform
 #elif defined(XP_WIN)
 #include "gfxWindowsPlatform.h"
 #define gfxToolkitPlatform gfxWindowsPlatform
 #elif defined(ANDROID)
 #include "gfxAndroidPlatform.h"
 #define gfxToolkitPlatform gfxAndroidPlatform
 #endif
 
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -52,17 +52,17 @@ class gfxTextContextPaint;
 #define NO_FONT_LANGUAGE_OVERRIDE      0
 
 #define SMALL_CAPS_SCALE_FACTOR        0.8
 
 // The skew factor used for synthetic-italic [oblique] fonts;
 // we use a platform-dependent value to harmonize with the platform's own APIs.
 #ifdef XP_WIN
 #define OBLIQUE_SKEW_FACTOR  0.3
-#elif defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
+#elif defined(MOZ_WIDGET_GTK)
 #define OBLIQUE_SKEW_FACTOR  0.2
 #else
 #define OBLIQUE_SKEW_FACTOR  0.25
 #endif
 
 struct gfxTextRunDrawCallbacks;
 
 namespace mozilla {
--- a/gfx/thebes/gfxFontconfigFonts.cpp
+++ b/gfx/thebes/gfxFontconfigFonts.cpp
@@ -7,19 +7,16 @@
 #include "gfxTypes.h"
 
 #include "nsTArray.h"
 
 #include "gfxContext.h"
 #ifdef MOZ_WIDGET_GTK
 #include "gfxPlatformGtk.h"
 #endif
-#ifdef MOZ_WIDGET_QT
-#include "gfxQtPlatform.h"
-#endif
 #include "gfxFontconfigFonts.h"
 #include "gfxFT2FontBase.h"
 #include "gfxFT2Utils.h"
 #include "harfbuzz/hb.h"
 #include "harfbuzz/hb-ot.h"
 #include "nsUnicodeProperties.h"
 #include "nsUnicodeScriptCodes.h"
 #include "gfxFontconfigUtils.h"
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -38,18 +38,16 @@
 
 #if defined(XP_WIN)
 #include "gfxWindowsPlatform.h"
 #elif defined(XP_MACOSX)
 #include "gfxPlatformMac.h"
 #include "gfxQuartzSurface.h"
 #elif defined(MOZ_WIDGET_GTK)
 #include "gfxPlatformGtk.h"
-#elif defined(MOZ_WIDGET_QT)
-#include "gfxQtPlatform.h"
 #elif defined(ANDROID)
 #include "gfxAndroidPlatform.h"
 #endif
 
 #ifdef XP_WIN
 #include "mozilla/WindowsVersion.h"
 #endif
 
@@ -659,18 +657,16 @@ gfxPlatform::Init()
     gfxInfo = services::GetGfxInfo();
 
 #if defined(XP_WIN)
     gPlatform = new gfxWindowsPlatform;
 #elif defined(XP_MACOSX)
     gPlatform = new gfxPlatformMac;
 #elif defined(MOZ_WIDGET_GTK)
     gPlatform = new gfxPlatformGtk;
-#elif defined(MOZ_WIDGET_QT)
-    gPlatform = new gfxQtPlatform;
 #elif defined(ANDROID)
     gPlatform = new gfxAndroidPlatform;
 #else
     #error "No gfxPlatform implementation available"
 #endif
     gPlatform->InitAcceleration();
 
 #ifdef USE_SKIA
@@ -686,18 +682,16 @@ gfxPlatform::Init()
     gPlatform->PopulateScreenInfo();
     gPlatform->ComputeTileSize();
 
     nsresult rv;
 
     bool usePlatformFontList = true;
 #if defined(MOZ_WIDGET_GTK)
     usePlatformFontList = gfxPlatformGtk::UseFcFontList();
-#elif defined(MOZ_WIDGET_QT)
-    usePlatformFontList = false;
 #endif
 
     if (usePlatformFontList) {
         rv = gfxPlatformFontList::Init();
         if (NS_FAILED(rv)) {
             NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList");
         }
     }
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -94,25 +94,40 @@ gfxPlatformGtk::gfxPlatformGtk()
     sUseXRender = (GDK_IS_X11_DISPLAY(gdk_display_get_default())) ?
                     mozilla::Preferences::GetBool("gfx.xrender.enabled") : false;
 #endif
 
     uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
     uint32_t contentMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
     InitBackendPrefs(canvasMask, BackendType::CAIRO,
                      contentMask, BackendType::CAIRO);
+
+#ifdef MOZ_X11
+    if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
+      mCompositorDisplay = XOpenDisplay(nullptr);
+      MOZ_ASSERT(mCompositorDisplay, "Failed to create compositor display!");
+    } else {
+      mCompositorDisplay = nullptr;
+    }
+#endif // MOZ_X11
 }
 
 gfxPlatformGtk::~gfxPlatformGtk()
 {
     if (!sUseFcFontList) {
         gfxFontconfigUtils::Shutdown();
         sFontconfigUtils = nullptr;
         gfxPangoFontGroup::Shutdown();
     }
+
+#ifdef MOZ_X11
+    if (mCompositorDisplay) {
+      XCloseDisplay(mCompositorDisplay);
+    }
+#endif // MOZ_X11
 }
 
 void
 gfxPlatformGtk::FlushContentDrawing()
 {
     if (UseXRender()) {
         XFlush(DefaultXDisplay());
     }
--- a/gfx/thebes/gfxPlatformGtk.h
+++ b/gfx/thebes/gfxPlatformGtk.h
@@ -11,16 +11,21 @@
 #include "nsTArray.h"
 
 #if (MOZ_WIDGET_GTK == 2)
 extern "C" {
     typedef struct _GdkDrawable GdkDrawable;
 }
 #endif
 
+#ifdef MOZ_X11
+struct _XDisplay;
+typedef struct _XDisplay Display;
+#endif // MOZ_X11
+
 class gfxFontconfigUtils;
 
 class gfxPlatformGtk : public gfxPlatform {
 public:
     gfxPlatformGtk();
     virtual ~gfxPlatformGtk();
 
     static gfxPlatformGtk *GetPlatform() {
@@ -133,27 +138,35 @@ public:
     bool SupportsPluginDirectBitmapDrawing() override {
       return true;
     }
 
 #ifdef GL_PROVIDER_GLX
     already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() override;
 #endif
 
+#ifdef MOZ_X11
+    Display* GetCompositorDisplay() {
+      return mCompositorDisplay;
+    }
+#endif // MOZ_X11
+
 protected:
     static gfxFontconfigUtils *sFontconfigUtils;
 
     int8_t mMaxGenericSubstitutions;
 
 private:
     virtual void GetPlatformCMSOutputProfile(void *&mem,
                                              size_t &size) override;
 
 #ifdef MOZ_X11
     static bool sUseXRender;
+
+    Display* mCompositorDisplay;
 #endif
 
     // xxx - this will be removed once the new fontconfig platform font list
     // replaces gfxPangoFontGroup
     static bool sUseFcFontList;
 };
 
 #endif /* GFX_PLATFORM_GTK_H */
deleted file mode 100644
--- a/gfx/thebes/gfxQtNativeRenderer.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gfxQtNativeRenderer.h"
-#include "gfxContext.h"
-#include "gfxUtils.h"
-#include "gfxXlibSurface.h"
-
-nsresult
-gfxQtNativeRenderer::Draw(gfxContext* ctx, mozilla::gfx::IntSize size,
-                          uint32_t flags, Screen* screen, Visual* visual)
-{
-    Display *dpy = DisplayOfScreen(screen);
-    bool isOpaque = (flags & DRAW_IS_OPAQUE) ? true : false;
-    int screenNumber = screen - ScreenOfDisplay(dpy, 0);
-
-    if (!isOpaque) {
-        int depth = 32;
-        XVisualInfo vinfo;
-        int foundVisual = XMatchVisualInfo(dpy, screenNumber,
-                                           depth, TrueColor,
-                                           &vinfo);
-        if (!foundVisual)
-            return NS_ERROR_FAILURE;
-
-        visual = vinfo.visual;
-    }
-
-    RefPtr<gfxXlibSurface> xsurf =
-        gfxXlibSurface::Create(screen, visual,
-                               mozilla::gfx::IntSize(size.width, size.height));
-
-    if (!isOpaque) {
-        gfxUtils::ClearThebesSurface(xsurf);
-    }
-
-    nsresult rv = DrawWithXlib(xsurf->CairoSurface(), nsIntPoint(0, 0), nullptr, 0);
-
-    if (NS_FAILED(rv))
-        return rv;
-
-    ctx->SetSource(xsurf);
-    ctx->Paint();
-
-    return rv;
-}
deleted file mode 100644
--- a/gfx/thebes/gfxQtNativeRenderer.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * 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 GFXQTNATIVERENDER_H_
-#define GFXQTNATIVERENDER_H_
-
-#include "gfxContext.h"
-#include "gfxXlibSurface.h"
-#include "mozilla/gfx/Rect.h"
-
-/**
- * This class lets us take code that draws into an Xlib surface drawable and lets us
- * use it to draw into any Thebes context. The user should subclass this class,
- * override NativeDraw, and then call Draw(). The drawing will be subjected
- * to all Thebes transformations, clipping etc.
- */
-class gfxQtNativeRenderer {
-public:
-    /**
-     * Perform the native drawing.
-     * @param offsetX draw at this offset into the given drawable
-     * @param offsetY draw at this offset into the given drawable
-     * @param clipRects an array of rects; clip to the union
-     * @param numClipRects the number of rects in the array, or zero if
-     * no clipping is required
-     */
-    virtual nsresult DrawWithXlib(cairo_surface_t* surface,
-                                  nsIntPoint offset,
-                                  mozilla::gfx::IntRect* clipRects,
-                                  uint32_t numClipRects) = 0;
-
-    enum {
-        // If set, then Draw() is opaque, i.e., every pixel in the intersection
-        // of the clipRect and (offset.x,offset.y,bounds.width,bounds.height)
-        // will be set and there is no dependence on what the existing pixels
-        // in the drawable are set to.
-        DRAW_IS_OPAQUE = 0x01,
-        // If set, then numClipRects can be zero or one
-        DRAW_SUPPORTS_CLIP_RECT = 0x04,
-        // If set, then numClipRects can be any value. If neither this
-        // nor CLIP_RECT are set, then numClipRects will be zero
-        DRAW_SUPPORTS_CLIP_LIST = 0x08,
-        // If set, then the visual passed in can be any visual, otherwise the
-        // visual passed in must be the default visual for dpy's default screen
-        DRAW_SUPPORTS_ALTERNATE_VISUAL = 0x10,
-        // If set, then the Screen 'screen' in the callback can be different
-        // from the default Screen of the display passed to 'Draw' and can be
-        // on a different display.
-        DRAW_SUPPORTS_ALTERNATE_SCREEN = 0x20
-    };
-
-    /**
-     * @param flags see above
-     * @param size Draw()'s drawing is guaranteed to be restricted to
-     * the rectangle (offset.x,offset.y,size.width,size.height)
-     * @param dpy a display to use for the drawing if ctx doesn't have one
-     * @param resultSurface if non-null, we will try to capture a copy of the
-     * rendered image into a surface similar to the surface of ctx; if
-     * successful, a pointer to the new gfxASurface is stored in *resultSurface,
-     * otherwise *resultSurface is set to nullptr.
-     */
-    nsresult Draw(gfxContext* ctx, mozilla::gfx::IntSize size,
-                  uint32_t flags, Screen* screen, Visual* visual);
-};
-
-#endif /*GFXQTNATIVERENDER_H_*/
deleted file mode 100644
--- a/gfx/thebes/gfxQtPlatform.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <QPixmap>
-#include <QWindow>
-#ifdef MOZ_X11
-#include <qpa/qplatformnativeinterface.h>
-#endif
-#include <QGuiApplication>
-#include <QScreen>
-
-#include "gfxQtPlatform.h"
-
-#include "gfxFontconfigUtils.h"
-
-#include "mozilla/gfx/2D.h"
-
-#include "cairo.h"
-
-#include "gfxImageSurface.h"
-#include "nsUnicodeProperties.h"
-
-#include "gfxFontconfigFonts.h"
-#include "gfxContext.h"
-#include "gfxUserFontSet.h"
-
-#include "nsUnicharUtils.h"
-
-#include "nsMathUtils.h"
-#include "nsTArray.h"
-#ifdef MOZ_X11
-#include "gfxXlibSurface.h"
-#include "prenv.h"
-#endif
-
-#include "qcms.h"
-
-#include "mozilla/Preferences.h"
-
-using namespace mozilla;
-using namespace mozilla::unicode;
-using namespace mozilla::gfx;
-
-gfxFontconfigUtils *gfxQtPlatform::sFontconfigUtils = nullptr;
-
-static gfxImageFormat sOffscreenFormat = SurfaceFormat::X8R8G8B8_UINT32;
-
-gfxQtPlatform::gfxQtPlatform()
-{
-    if (!sFontconfigUtils)
-        sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils();
-
-    int32_t depth = GetScreenDepth();
-    if (depth == 16) {
-        sOffscreenFormat = SurfaceFormat::R5G6B5_UINT16;
-    }
-    uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
-    uint32_t contentMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
-    InitBackendPrefs(canvasMask, BackendType::CAIRO,
-                     contentMask, BackendType::CAIRO);
-}
-
-gfxQtPlatform::~gfxQtPlatform()
-{
-    gfxFontconfigUtils::Shutdown();
-    sFontconfigUtils = nullptr;
-
-    gfxPangoFontGroup::Shutdown();
-}
-
-#ifdef MOZ_X11
-Display*
-gfxQtPlatform::GetXDisplay(QWindow* aWindow)
-{
-    return (Display*)(qApp->platformNativeInterface()->
-        nativeResourceForScreen("display", aWindow ? aWindow->screen() : qApp->primaryScreen()));
-}
-
-Screen*
-gfxQtPlatform::GetXScreen(QWindow* aWindow)
-{
-    return ScreenOfDisplay(GetXDisplay(aWindow),
-        (int)(intptr_t)qApp->platformNativeInterface()->
-            nativeResourceForScreen("screen", aWindow ? aWindow->screen() : qApp->primaryScreen()));
-}
-#endif
-
-already_AddRefed<gfxASurface>
-gfxQtPlatform::CreateOffscreenSurface(const IntSize& aSize,
-                                      gfxImageFormat aFormat)
-{
-    RefPtr<gfxASurface> newSurface =
-        new gfxImageSurface(aSize, aFormat);
-
-    return newSurface.forget();
-}
-
-nsresult
-gfxQtPlatform::GetFontList(nsIAtom *aLangGroup,
-                           const nsACString& aGenericFamily,
-                           nsTArray<nsString>& aListOfFonts)
-{
-    return sFontconfigUtils->GetFontList(aLangGroup, aGenericFamily,
-                                         aListOfFonts);
-}
-
-nsresult
-gfxQtPlatform::UpdateFontList()
-{
-    return sFontconfigUtils->UpdateFontList();
-}
-
-nsresult
-gfxQtPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
-{
-    return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName);
-}
-
-gfxFontGroup *
-gfxQtPlatform::CreateFontGroup(const FontFamilyList& aFontFamilyList,
-                               const gfxFontStyle *aStyle,
-                               gfxTextPerfMetrics* aTextPerf,
-                               gfxUserFontSet* aUserFontSet,
-                               gfxFloat aDevToCssSize)
-{
-    return new gfxPangoFontGroup(aFontFamilyList, aStyle,
-                                 aUserFontSet, aDevToCssSize);
-}
-
-gfxFontEntry*
-gfxQtPlatform::LookupLocalFont(const nsAString& aFontName,
-                               uint16_t aWeight,
-                               int16_t aStretch,
-                               uint8_t aStyle)
-{
-    return gfxPangoFontGroup::NewFontEntry(aFontName, aWeight,
-                                           aStretch, aStyle);
-}
-
-gfxFontEntry*
-gfxQtPlatform::MakePlatformFont(const nsAString& aFontName,
-                                uint16_t aWeight,
-                                int16_t aStretch,
-                                uint8_t aStyle,
-                                const uint8_t* aFontData,
-                                uint32_t aLength)
-{
-    // passing ownership of the font data to the new font entry
-    return gfxPangoFontGroup::NewFontEntry(aFontName, aWeight,
-                                           aStretch, aStyle,
-                                           aFontData, aLength);
-}
-
-bool
-gfxQtPlatform::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags)
-{
-    // check for strange format flags
-    NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
-                 "strange font format hint set");
-
-    // accept supported formats
-    // Pango doesn't apply features from AAT TrueType extensions.
-    // Assume that if this is the only SFNT format specified,
-    // then AAT extensions are required for complex script support.
-    if (aFormatFlags & gfxUserFontSet::FLAG_FORMATS_COMMON) {
-        return true;
-    }
-
-    // reject all other formats, known and unknown
-    if (aFormatFlags != 0) {
-        return false;
-    }
-
-    // no format hint set, need to look at data
-    return true;
-}
-
-void
-gfxQtPlatform::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
-{
-    mem = nullptr;
-    size = 0;
-}
-
-int32_t
-gfxQtPlatform::GetDPI()
-{
-    return qApp->primaryScreen()->logicalDotsPerInch();
-}
-
-gfxImageFormat
-gfxQtPlatform::GetOffscreenFormat()
-{
-    return sOffscreenFormat;
-}
-
-already_AddRefed<ScaledFont>
-gfxQtPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont* aFont)
-{
-    return GetScaledFontForFontWithCairoSkia(aTarget, aFont);
-}
deleted file mode 100644
--- a/gfx/thebes/gfxQtPlatform.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * 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 GFX_PLATFORM_QT_H
-#define GFX_PLATFORM_QT_H
-
-#include "gfxPlatform.h"
-#include "nsAutoRef.h"
-#include "nsDataHashtable.h"
-#include "nsTArray.h"
-#ifdef MOZ_X11
-#include "X11/Xlib.h"
-#endif
-
-class gfxFontconfigUtils;
-class QWindow;
-
-class gfxQtPlatform : public gfxPlatform {
-public:
-    gfxQtPlatform();
-    virtual ~gfxQtPlatform();
-
-    static gfxQtPlatform *GetPlatform() {
-        return static_cast<gfxQtPlatform*>(gfxPlatform::GetPlatform());
-    }
-
-    virtual already_AddRefed<gfxASurface>
-      CreateOffscreenSurface(const IntSize& aSize,
-                             gfxImageFormat aFormat) override;
-
-    virtual already_AddRefed<mozilla::gfx::ScaledFont>
-      GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont) override;
-
-    virtual nsresult GetFontList(nsIAtom *aLangGroup,
-                                 const nsACString& aGenericFamily,
-                                 nsTArray<nsString>& aListOfFonts) override;
-
-    virtual nsresult UpdateFontList() override;
-
-    virtual nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) override;
-
-    gfxFontGroup*
-    CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
-                    const gfxFontStyle *aStyle,
-                    gfxTextPerfMetrics* aTextPerf,
-                    gfxUserFontSet *aUserFontSet,
-                    gfxFloat aDevToCssSize) override;
-
-    /**
-     * Look up a local platform font using the full font face name (needed to
-     * support @font-face src local() )
-     */
-    virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
-                                          uint16_t aWeight,
-                                          int16_t aStretch,
-                                          uint8_t aStyle) override;
-
-    /**
-     * Activate a platform font (needed to support @font-face src url() )
-     *
-     */
-    virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                           uint16_t aWeight,
-                                           int16_t aStretch,
-                                           uint8_t aStyle,
-                                           const uint8_t* aFontData,
-                                           uint32_t aLength) override;
-
-    /**
-     * Check whether format is supported on a platform or not (if unclear,
-     * returns true).
-     */
-    virtual bool IsFontFormatSupported(nsIURI *aFontURI,
-                                       uint32_t aFormatFlags) override;
-
-    static int32_t GetDPI();
-
-    virtual gfxImageFormat GetOffscreenFormat() override;
-#ifdef MOZ_X11
-    static Display* GetXDisplay(QWindow* aWindow = 0);
-    static Screen* GetXScreen(QWindow* aWindow = 0);
-#endif
-
-    bool AccelerateLayersByDefault() override {
-      return true;
-    }
-
-protected:
-    static gfxFontconfigUtils *sFontconfigUtils;
-
-private:
-    virtual void GetPlatformCMSOutputProfile(void *&mem, size_t &size) override;
-
-    int mScreenDepth;
-};
-
-#endif /* GFX_PLATFORM_QT_H */
-
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -1605,18 +1605,16 @@ gfxFontGroup::~gfxFontGroup()
 void
 gfxFontGroup::BuildFontList()
 {
     bool enumerateFonts = true;
 
 #if defined(MOZ_WIDGET_GTK)
     // xxx - eliminate this once gfxPangoFontGroup is no longer needed
     enumerateFonts = gfxPlatformGtk::UseFcFontList();
-#elif defined(MOZ_WIDGET_QT)
-    enumerateFonts = false;
 #endif
     if (!enumerateFonts) {
         return;
     }
 
     // initialize fonts in the font family list
     AutoTArray<gfxFontFamily*,10> fonts;
     gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
--- a/gfx/thebes/moz.build
+++ b/gfx/thebes/moz.build
@@ -134,44 +134,16 @@ elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT
             'gfxXlibNativeRenderer.h',
             'gfxXlibSurface.h',
         ]
         SOURCES += [
             'gfxXlibNativeRenderer.cpp',
             'gfxXlibSurface.cpp',
         ]
 
-elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
-    EXPORTS += [
-        'gfxFontconfigFonts.h',
-        'gfxFT2FontBase.h',
-        'gfxQtNativeRenderer.h',
-        'gfxQtPlatform.h',
-    ]
-    EXPORTS.mozilla.gfx += [
-        'PrintTargetPDF.h',
-    ]
-    SOURCES += [
-        'gfxFontconfigFonts.cpp',
-        'gfxFontconfigUtils.cpp',
-        'gfxFT2FontBase.cpp',
-        'gfxFT2Utils.cpp',
-        'gfxQtPlatform.cpp',
-        'PrintTargetPDF.cpp',
-    ]
-
-    if CONFIG['MOZ_X11']:
-        EXPORTS += [
-            'gfxXlibSurface.h',
-        ]
-        SOURCES += [
-            'gfxQtNativeRenderer.cpp',
-            'gfxXlibSurface.cpp',
-        ]
-
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     EXPORTS += [
         'gfxDWriteFonts.h',
         'gfxGDIFont.h',
         'gfxGDIFontList.h',
         'gfxPlatformFontList.h',
         'gfxWindowsNativeDrawing.h',
         'gfxWindowsPlatform.h',
@@ -283,38 +255,38 @@ GENERATED_FILES['DeprecatedPremultiplyTa
 LOCAL_INCLUDES += [
     '/dom/workers',
     '/dom/xml',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
   LOCAL_INCLUDES += ['/widget/gonk']
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gtk3', 'gonk', 'qt'):
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gtk3', 'gonk'):
     DEFINES['MOZ_ENABLE_FREETYPE'] = True
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     for var in ('MOZ_ENABLE_D3D9_LAYER', 'MOZ_ENABLE_D3D10_LAYER'):
         if CONFIG[var]:
             DEFINES[var] = True
 
 CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
 CXXFLAGS += CONFIG['TK_CFLAGS']
 CFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
 CFLAGS += CONFIG['TK_CFLAGS']
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk', 'qt'):
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk'):
     CXXFLAGS += CONFIG['CAIRO_FT_CFLAGS']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     # This is set for "normal Android", that is, when Gecko is running on
     # top of the android java runtime.
     DEFINES['MOZ_USING_ANDROID_JAVA_WIDGETS'] = True
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'qt'):
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'):
     CXXFLAGS += CONFIG['MOZ_PANGO_CFLAGS']
 
 LOCAL_INCLUDES += CONFIG['SKIA_INCLUDES']
 
 DEFINES['GRAPHITE2_STATIC'] = True
 
 if CONFIG['CLANG_CXX']:
     # Suppress warnings from Skia header files.
--- a/image/decoders/icon/moz.build
+++ b/image/decoders/icon/moz.build
@@ -14,19 +14,16 @@ FINAL_LIBRARY = 'xul'
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 platform = None
 
 if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
     platform = 'gtk'
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
-    platform = 'qt'
-
 if CONFIG['OS_ARCH'] == 'WINNT':
     platform = 'win'
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     platform = 'mac'
 
 if CONFIG['OS_TARGET'] == 'Android':
     platform = 'android'
--- a/intl/locale/nsLocaleService.cpp
+++ b/intl/locale/nsLocaleService.cpp
@@ -1,18 +1,13 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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/. */
 
-#ifdef MOZ_WIDGET_QT
-#include <QString>
-#include <QtCore/QLocale>
-#endif
-
 #include "nsCOMPtr.h"
 #include "nsILocale.h"
 #include "nsILocaleService.h"
 #include "nsLocale.h"
 #include "nsCRT.h"
 #include "prprf.h"
 #include "nsTArray.h"
 #include "nsString.h"
@@ -117,22 +112,18 @@ nsLocaleService::nsLocaleService(void)
     nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
     rv = NewLocale(xpLocale, getter_AddRefs(mApplicationLocale));
     NS_ENSURE_SUCCESS_VOID(rv);
 #endif
 #if defined(XP_UNIX) && !defined(XP_MACOSX)
     RefPtr<nsLocale> resultLocale(new nsLocale());
     NS_ENSURE_TRUE_VOID(resultLocale);
 
-#ifdef MOZ_WIDGET_QT
-    const char* lang = QLocale::system().name().toUtf8();
-#else
     // Get system configuration
     const char* lang = getenv("LANG");
-#endif
 
     nsAutoString xpLocale, platformLocale;
     nsAutoString category, category_platform;
     int i;
 
     for( i = 0; i < LocaleListLength; i++ ) {
         nsresult result;
         // setlocale( , "") evaluates LC_* and LANG
--- a/ipc/chromium/src/base/message_loop.cc
+++ b/ipc/chromium/src/base/message_loop.cc
@@ -20,19 +20,16 @@
 #endif
 #if defined(OS_POSIX)
 #include "base/message_pump_libevent.h"
 #endif
 #if defined(OS_LINUX) || defined(OS_BSD)
 #if defined(MOZ_WIDGET_GTK)
 #include "base/message_pump_glib.h"
 #endif
-#ifdef MOZ_WIDGET_QT
-#include "base/message_pump_qt.h"
-#endif
 #endif
 #ifdef ANDROID
 #include "base/message_pump_android.h"
 #endif
 #ifdef MOZ_TASK_TRACER
 #include "GeckoTaskTracer.h"
 #include "TracedTaskCommon.h"
 #endif
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -57,16 +57,17 @@ template <class Key,
           class HashPolicy = DefaultHasher<Key>,
           class AllocPolicy = TempAllocPolicy>
 class HashMap
 {
     typedef HashMapEntry<Key, Value> TableEntry;
 
     struct MapHashPolicy : HashPolicy
     {
+        using Base = HashPolicy;
         typedef Key KeyType;
         static const Key& getKey(TableEntry& e) { return e.key(); }
         static void setKey(TableEntry& e, Key& k) { HashPolicy::rekey(e.mutableKey(), k); }
     };
 
     typedef detail::HashTable<TableEntry, MapHashPolicy, AllocPolicy> Impl;
     Impl impl;
 
@@ -311,16 +312,17 @@ class HashMap
 // - Due to the lack of exception handling, the user must call |init()|.
 template <class T,
           class HashPolicy = DefaultHasher<T>,
           class AllocPolicy = TempAllocPolicy>
 class HashSet
 {
     struct SetOps : HashPolicy
     {
+        using Base = HashPolicy;
         typedef T KeyType;
         static const KeyType& getKey(const T& t) { return t; }
         static void setKey(T& t, KeyType& k) { HashPolicy::rekey(t, k); }
     };
 
     typedef detail::HashTable<const T, SetOps, AllocPolicy> Impl;
     Impl impl;
 
@@ -670,16 +672,48 @@ struct CStringHasher
     static js::HashNumber hash(Lookup l) {
         return mozilla::HashString(l);
     }
     static bool match(const char* key, Lookup lookup) {
         return strcmp(key, lookup) == 0;
     }
 };
 
+// Fallible hashing interface.
+//
+// Most of the time generating a hash code is infallible so this class provides
+// default methods that always succeed.  Specialize this class for your own hash
+// policy to provide fallible hashing.
+//
+// This is used by MovableCellHasher to handle the fact that generating a unique
+// ID for cell pointer may fail due to OOM.
+template <typename HashPolicy>
+struct FallibleHashMethods
+{
+    // Return true if a hashcode is already available for its argument.  Once
+    // this returns true for a specific argument it must continue to do so.
+    template <typename Lookup> static bool hasHash(Lookup&& l) { return true; }
+
+    // Fallible method to ensure a hashcode exists for its argument and create
+    // one if not.  Returns false on error, e.g. out of memory.
+    template <typename Lookup> static bool ensureHash(Lookup&& l) { return true; }
+};
+
+template <typename HashPolicy, typename Lookup>
+static bool
+HasHash(Lookup&& l) {
+    return FallibleHashMethods<typename HashPolicy::Base>::hasHash(mozilla::Forward<Lookup>(l));
+}
+
+template <typename HashPolicy, typename Lookup>
+static bool
+EnsureHash(Lookup&& l) {