Merge inbound to mozilla-central. a=merge
authorNarcis Beleuzu <nbeleuzu@mozilla.com>
Wed, 06 Jun 2018 12:36:55 +0300
changeset 421531 cec4a3cecc29ff97860198969b6fdff24b9e93bb
parent 421510 d51b920aef6953a2911aab2a9f05470803708f76 (current diff)
parent 421530 633a10eff02a2ada758db8459dc9927bbce31df5 (diff)
child 421537 841300ddc8ec135573453aa95a31196d84bba872
child 421581 072201279e41b15e1ff1606bfd7460e3656d13b3
push id34096
push usernbeleuzu@mozilla.com
push dateWed, 06 Jun 2018 09:37:23 +0000
treeherdermozilla-central@cec4a3cecc29 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.0a1
first release with
nightly linux32
cec4a3cecc29 / 62.0a1 / 20180606100133 / files
nightly linux64
cec4a3cecc29 / 62.0a1 / 20180606100133 / files
nightly mac
cec4a3cecc29 / 62.0a1 / 20180606100133 / files
nightly win32
cec4a3cecc29 / 62.0a1 / 20180606100133 / files
nightly win64
cec4a3cecc29 / 62.0a1 / 20180606100133 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
gfx/vr/gfxVRGVR.cpp
gfx/vr/gfxVRGVR.h
gfx/vr/gfxVRGVRAPI.h
gfx/vr/jni/gfxGVRJNI.cpp
image/ImageURL.h
--- a/accessible/base/ARIAMap.cpp
+++ b/accessible/base/ARIAMap.cpp
@@ -83,27 +83,45 @@ static const nsRoleMapEntry sWAIRoleMaps
     roles::NOTHING,
     kUseNativeRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     eLandmark,
     kNoReqStates
   },
+  { // blockquote
+    &nsGkAtoms::blockquote,
+    roles::BLOCKQUOTE,
+    kUseMapRole,
+    eNoValue,
+    eNoAction,
+    eNoLiveAttr,
+    kGenericAccType,
+  },
   { // button
     &nsGkAtoms::button,
     roles::PUSHBUTTON,
     kUseMapRole,
     eNoValue,
     ePressAction,
     eNoLiveAttr,
     eButton,
     kNoReqStates
     // eARIAPressed is auto applied on any button
   },
+  { // caption
+    &nsGkAtoms::caption,
+    roles::CAPTION,
+    kUseMapRole,
+    eNoValue,
+    eNoAction,
+    eNoLiveAttr,
+    kGenericAccType,
+  },
   { // cell
     &nsGkAtoms::cell,
     roles::CELL,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     eTableCell,
@@ -892,16 +910,25 @@ static const nsRoleMapEntry sWAIRoleMaps
     eNoValue,
     eSelectAction,
     eNoLiveAttr,
     kGenericAccType,
     kNoReqStates,
     eARIASelectable,
     eARIACheckedMixed
   },
+  { // paragraph
+    &nsGkAtoms::paragraph,
+    roles::PARAGRAPH,
+    kUseMapRole,
+    eNoValue,
+    eNoAction,
+    eNoLiveAttr,
+    kGenericAccType,
+  },
   { // presentation
     &nsGkAtoms::presentation,
     roles::NOTHING,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     kGenericAccType,
--- a/accessible/base/MarkupMap.h
+++ b/accessible/base/MarkupMap.h
@@ -23,17 +23,17 @@ MARKUPMAP(article,
           Attr(xmlroles, article))
 
 MARKUPMAP(aside,
           New_HyperText,
           roles::NOTE)
 
 MARKUPMAP(blockquote,
           New_HyperText,
-          roles::SECTION)
+          roles::BLOCKQUOTE)
 
 MARKUPMAP(dd,
           New_HTMLDefinition,
           roles::DEFINITION)
 
 MARKUPMAP(details,
           New_HyperText,
           roles::DETAILS)
--- a/accessible/base/Role.h
+++ b/accessible/base/Role.h
@@ -1015,17 +1015,22 @@ enum Role {
   REGION = 173,
 
   /**
    * Represents a control with a text input and a popup with a set of predefined
    * choices. It is used for ARIA's combobox role. See also COMBOBOX.
    */
   EDITCOMBOBOX = 174,
 
-  LAST_ROLE = EDITCOMBOBOX
+  /**
+   * A section of content that is quoted from another source.
+   */
+  BLOCKQUOTE = 175,
+
+  LAST_ROLE = BLOCKQUOTE
 };
 
 } // namespace role
 
 typedef enum mozilla::a11y::roles::Role role;
 
 } // namespace a11y
 } // namespace mozilla
--- a/accessible/base/RoleMap.h
+++ b/accessible/base/RoleMap.h
@@ -1413,8 +1413,16 @@ ROLE(REGION,
 // See also COMBOBOX.
 ROLE(EDITCOMBOBOX,
      "editcombobox",
      ATK_ROLE_COMBO_BOX,
      NSAccessibilityComboBoxRole,
      ROLE_SYSTEM_COMBOBOX,
      ROLE_SYSTEM_COMBOBOX,
      eNameFromValueRule)
+
+ROLE(BLOCKQUOTE,
+     "blockquote",
+     ATK_ROLE_BLOCK_QUOTE,
+     NSAccessibilityGroupRole,
+     ROLE_SYSTEM_GROUPING,
+     IA2_ROLE_SECTION,
+     eNoNameRule)
--- a/accessible/interfaces/nsIAccessibleRole.idl
+++ b/accessible/interfaces/nsIAccessibleRole.idl
@@ -1009,9 +1009,14 @@ interface nsIAccessibleRole : nsISupport
    */
   const unsigned long ROLE_REGION = 173;
 
   /**
    * Represents a control with a text input and a popup with a set of predefined
    * choices. It is used for ARIA's combobox role. See also ROLE_COMBOBOX.
    */
   const unsigned long ROLE_EDITCOMBOBOX = 174;
+
+  /**
+   * A section of content that is quoted from another source.
+   */
+  const unsigned long ROLE_BLOCKQUOTE = 175;
 };
--- a/accessible/tests/mochitest/elm/test_HTMLSpec.html
+++ b/accessible/tests/mochitest/elm/test_HTMLSpec.html
@@ -175,17 +175,17 @@
         ]
       };
       testElm("bdo_container", obj);
 
       // ////////////////////////////////////////////////////////////////////////
       // HTML:blockquote
 
       obj = {
-        role: ROLE_SECTION,
+        role: ROLE_BLOCKQUOTE,
         interfaces: [ nsIAccessibleText, nsIAccessibleHyperText ],
         children: [ { role: ROLE_PARAGRAPH } ]
       };
       testElm("blockquote", obj);
 
       // ////////////////////////////////////////////////////////////////////////
       // HTML:br contained by paragraph
 
--- a/accessible/tests/mochitest/role.js
+++ b/accessible/tests/mochitest/role.js
@@ -2,16 +2,17 @@
 // Role constants
 
 const ROLE_ALERT = nsIAccessibleRole.ROLE_ALERT;
 const ROLE_ARTICLE = nsIAccessibleRole.ROLE_ARTICLE;
 const ROLE_ANIMATION = nsIAccessibleRole.ROLE_ANIMATION;
 const ROLE_APPLICATION = nsIAccessibleRole.ROLE_APPLICATION;
 const ROLE_APP_ROOT = nsIAccessibleRole.ROLE_APP_ROOT;
 const ROLE_AUTOCOMPLETE = nsIAccessibleRole.ROLE_AUTOCOMPLETE;
+const ROLE_BLOCKQUOTE = nsIAccessibleRole.ROLE_BLOCKQUOTE;
 const ROLE_BUTTONDROPDOWNGRID = nsIAccessibleRole.ROLE_BUTTONDROPDOWNGRID;
 const ROLE_CANVAS = nsIAccessibleRole.ROLE_CANVAS;
 const ROLE_CAPTION = nsIAccessibleRole.ROLE_CAPTION;
 const ROLE_CELL = nsIAccessibleRole.ROLE_CELL;
 const ROLE_CHECKBUTTON = nsIAccessibleRole.ROLE_CHECKBUTTON;
 const ROLE_CHECK_MENU_ITEM = nsIAccessibleRole.ROLE_CHECK_MENU_ITEM;
 const ROLE_CHROME_WINDOW = nsIAccessibleRole.ROLE_CHROME_WINDOW;
 const ROLE_COMBOBOX = nsIAccessibleRole.ROLE_COMBOBOX;
--- a/accessible/tests/mochitest/role/test_aria.html
+++ b/accessible/tests/mochitest/role/test_aria.html
@@ -16,17 +16,19 @@
   <script type="application/javascript">
 
     function doTest() {
       // ARIA role map.
       testRole("aria_alert", ROLE_ALERT);
       testRole("aria_alertdialog", ROLE_DIALOG);
       testRole("aria_application", ROLE_APPLICATION);
       testRole("aria_article", ROLE_ARTICLE);
+      testRole("aria_blockquote", ROLE_BLOCKQUOTE);
       testRole("aria_button", ROLE_PUSHBUTTON);
+      testRole("aria_caption", ROLE_CAPTION);
       testRole("aria_checkbox", ROLE_CHECKBUTTON);
       testRole("aria_columnheader", ROLE_COLUMNHEADER);
       testRole("aria_combobox", ROLE_EDITCOMBOBOX);
       testRole("aria_dialog", ROLE_DIALOG);
       testRole("aria_directory", ROLE_LIST);
       testRole("aria_document", ROLE_NON_NATIVE_DOCUMENT);
       testRole("aria_form", ROLE_FORM);
       testRole("aria_feed", ROLE_GROUPING);
@@ -44,16 +46,17 @@
       testRole("aria_marquee", ROLE_ANIMATION);
       testRole("aria_math", ROLE_FLAT_EQUATION);
       testRole("aria_menu", ROLE_MENUPOPUP);
       testRole("aria_menubar", ROLE_MENUBAR);
       testRole("aria_menuitem", ROLE_MENUITEM);
       testRole("aria_menuitemcheckbox", ROLE_CHECK_MENU_ITEM);
       testRole("aria_menuitemradio", ROLE_RADIO_MENU_ITEM);
       testRole("aria_note", ROLE_NOTE);
+      testRole("aria_paragraph", ROLE_PARAGRAPH);
       testRole("aria_presentation", ROLE_TEXT); // weak role
       testRole("aria_progressbar", ROLE_PROGRESSBAR);
       testRole("aria_radio", ROLE_RADIOBUTTON);
       testRole("aria_radiogroup", ROLE_RADIO_GROUP);
       testRole("aria_region_no_name", ROLE_TEXT);
       testRole("aria_region_has_label", ROLE_REGION);
       testRole("aria_region_has_labelledby", ROLE_REGION);
       testRole("aria_region_has_title", ROLE_REGION);
@@ -204,17 +207,19 @@
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <span id="aria_alert" role="alert"/>
   <span id="aria_alertdialog" role="alertdialog"/>
   <span id="aria_application" role="application"/>
   <span id="aria_article" role="article"/>
+  <span id="aria_blockquote" role="blockquote"/>
   <span id="aria_button" role="button"/>
+  <span id="aria_caption" role="caption"/>
   <span id="aria_checkbox" role="checkbox"/>
   <span id="aria_columnheader" role="columnheader"/>
   <span id="aria_combobox" role="combobox"/>
   <span id="aria_dialog" role="dialog"/>
   <span id="aria_directory" role="directory"/>
   <span id="aria_document" role="document"/>
   <span id="aria_form" role="form"/>
   <span id="aria_feed" role="feed"/>
@@ -232,16 +237,17 @@
   <span id="aria_marquee" role="marquee"/>
   <span id="aria_math" role="math"/>
   <span id="aria_menu" role="menu"/>
   <span id="aria_menubar" role="menubar"/>
   <span id="aria_menuitem" role="menuitem"/>
   <span id="aria_menuitemcheckbox" role="menuitemcheckbox"/>
   <span id="aria_menuitemradio" role="menuitemradio"/>
   <span id="aria_note" role="note"/>
+  <span id="aria_paragraph" role="paragraph"/>
   <span id="aria_presentation" role="presentation" tabindex="0"/>
   <span id="aria_progressbar" role="progressbar"/>
   <span id="aria_radio" role="radio"/>
   <span id="aria_radiogroup" role="radiogroup"/>
   <span id="aria_region_no_name" role="region"/>
   <span id="aria_region_has_label" role="region" aria-label="label"/>
   <span id="aria_region_has_labelledby" role="region" aria-labelledby="label"/><span id="label" aria-label="label">
   <span id="aria_region_has_title" role="region" title="title"/>
--- a/accessible/tests/mochitest/role/test_general.html
+++ b/accessible/tests/mochitest/role/test_general.html
@@ -36,17 +36,17 @@
       testRole("aside_overflow", ROLE_NOTE);
       testRole("footer_overflow", ROLE_SECTION);
       testRole("article_overflow", ROLE_ARTICLE);
 
       // test html:div
       testRole("sec", ROLE_SECTION);
 
       // Test html:blockquote
-      testRole("quote", ROLE_SECTION);
+      testRole("quote", ROLE_BLOCKQUOTE);
 
       // Test html:h, all levels
       testRole("head1", ROLE_HEADING);
       testRole("head2", ROLE_HEADING);
       testRole("head3", ROLE_HEADING);
       testRole("head4", ROLE_HEADING);
       testRole("head5", ROLE_HEADING);
       testRole("head6", ROLE_HEADING);
--- a/accessible/tests/mochitest/tree/test_txtcntr.html
+++ b/accessible/tests/mochitest/tree/test_txtcntr.html
@@ -90,17 +90,17 @@
 
       testAccessibleTree("c4", accTree);
 
       // blockquote
       accTree = {
         role: ROLE_SECTION,
         children: [
           { // block quote
-            role: ROLE_SECTION,
+            role: ROLE_BLOCKQUOTE,
             children: [
               { // text child
                 role: ROLE_TEXT_LEAF,
                 name: "Hello",
                 children: []
               }
             ]
           }
--- a/devtools/client/themes/animation.css
+++ b/devtools/client/themes/animation.css
@@ -403,16 +403,17 @@ select.playback-rate-selector.devtools-b
   white-space: nowrap;
 }
 
 .animation-detail-close-button {
   margin: 0;
 }
 
 .animation-detail-close-button::before {
+  fill: var(--theme-toolbar-photon-icon-color);
   background-image: url(chrome://devtools/skin/images/close.svg);
 }
 
 /* Animated Property List Container */
 .animated-property-list-container {
   display: flex;
   flex: 1;
   flex-direction: column;
--- a/gfx/vr/VRDisplayClient.cpp
+++ b/gfx/vr/VRDisplayClient.cpp
@@ -76,27 +76,27 @@ VRDisplayClient::SetGroupMask(uint32_t a
 {
   VRManagerChild *vm = VRManagerChild::Get();
   vm->SendSetGroupMask(mDisplayInfo.mDisplayID, aGroupMask);
 }
 
 bool
 VRDisplayClient::IsPresentationGenerationCurrent() const
 {
-  if (mLastPresentingGeneration != mDisplayInfo.mPresentingGeneration) {
+  if (mLastPresentingGeneration != mDisplayInfo.mDisplayState.mPresentingGeneration) {
     return false;
   }
 
   return true;
 }
 
 void
 VRDisplayClient::MakePresentationGenerationCurrent()
 {
-  mLastPresentingGeneration = mDisplayInfo.mPresentingGeneration;
+  mLastPresentingGeneration = mDisplayInfo.mDisplayState.mPresentingGeneration;
 }
 
 void
 VRDisplayClient::FireEvents()
 {
   VRManagerChild *vm = VRManagerChild::Get();
   // Only fire these events for non-chrome VR sessions
   bool isPresenting = (mDisplayInfo.mPresentingGroups & kVRGroupContent) != 0;
--- a/gfx/vr/VRDisplayHost.cpp
+++ b/gfx/vr/VRDisplayHost.cpp
@@ -21,19 +21,19 @@
 #include "mozilla/layers/TextureD3D11.h"
 
 #elif defined(XP_MACOSX)
 
 #include "mozilla/gfx/MacIOSurface.h"
 
 #endif
 
-#if defined(MOZ_ANDROID_GOOGLE_VR)
+#if defined(MOZ_WIDGET_ANDROID)
 #include "mozilla/layers/CompositorThread.h"
-#endif // defined(MOZ_ANDROID_GOOGLE_VR)
+#endif // defined(MOZ_WIDGET_ANDROID)
 
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
 VRDisplayHost::AutoRestoreRenderState::AutoRestoreRenderState(VRDisplayHost* aDisplay)
   : mDisplay(aDisplay)
@@ -72,17 +72,17 @@ VRDisplayHost::VRDisplayHost(VRDeviceTyp
  , mFrameStarted(false)
 {
   MOZ_COUNT_CTOR(VRDisplayHost);
   mDisplayInfo.mType = aType;
   mDisplayInfo.mDisplayID = VRSystemManager::AllocateDisplayID();
   mDisplayInfo.mPresentingGroups = 0;
   mDisplayInfo.mGroupMask = kVRGroupContent;
   mDisplayInfo.mFrameId = 0;
-  mDisplayInfo.mPresentingGeneration = 0;
+  mDisplayInfo.mDisplayState.mPresentingGeneration = 0;
   mDisplayInfo.mDisplayState.mDisplayName[0] = '\0';
 }
 
 VRDisplayHost::~VRDisplayHost()
 {
   if (mSubmitThread) {
     mSubmitThread->Shutdown();
     mSubmitThread = nullptr;
@@ -263,19 +263,19 @@ VRDisplayHost::NotifyVSync()
 }
 
 void
 VRDisplayHost::SubmitFrameInternal(const layers::SurfaceDescriptor &aTexture,
                                    uint64_t aFrameId,
                                    const gfx::Rect& aLeftEyeRect,
                                    const gfx::Rect& aRightEyeRect)
 {
-#if !defined(MOZ_ANDROID_GOOGLE_VR)
+#if !defined(MOZ_WIDGET_ANDROID)
   MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread());
-#endif // !defined(MOZ_ANDROID_GOOGLE_VR)
+#endif // !defined(MOZ_WIDGET_ANDROID)
   AUTO_PROFILER_TRACING("VR", "SubmitFrameAtVRDisplayHost");
 
   mFrameStarted = false;
   switch (aTexture.type()) {
 
 #if defined(XP_WIN)
     case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
       if (!CreateD3DObjects()) {
@@ -332,32 +332,32 @@ VRDisplayHost::SubmitFrameInternal(const
       }
       IntSize texSize = gfx::IntSize(surf->GetDevicePixelWidth(),
                                      surf->GetDevicePixelHeight());
       if (!SubmitFrame(surf, texSize, aLeftEyeRect, aRightEyeRect)) {
         return;
       }
       break;
     }
-#elif defined(MOZ_ANDROID_GOOGLE_VR)
-    case SurfaceDescriptor::TEGLImageDescriptor: {
-      const EGLImageDescriptor& desc = aTexture.get_EGLImageDescriptor();
-      if (!SubmitFrame(&desc, aLeftEyeRect, aRightEyeRect)) {
+#elif defined(MOZ_WIDGET_ANDROID)
+    case SurfaceDescriptor::TSurfaceTextureDescriptor: {
+      const SurfaceTextureDescriptor& desc = aTexture.get_SurfaceTextureDescriptor();
+      if (!SubmitFrame(desc, aLeftEyeRect, aRightEyeRect)) {
         return;
       }
       break;
     }
 #endif
     default: {
       NS_WARNING("Unsupported SurfaceDescriptor type for VR layer texture");
       return;
     }
   }
 
-#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_ANDROID_GOOGLE_VR)
+#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID)
 
   /**
    * Trigger the next VSync immediately after we are successfully
    * submitting frames.  As SubmitFrame is responsible for throttling
    * the render loop, if we don't successfully call it, we shouldn't trigger
    * NotifyVRVsync immediately, as it will run unbounded.
    * If NotifyVRVsync is not called here due to SubmitFrame failing, the
    * fallback "watchdog" code in VRDisplayHost::NotifyVSync() will cause
@@ -376,43 +376,43 @@ VRDisplayHost::SubmitFrameInternal(const
 
 void
 VRDisplayHost::SubmitFrame(VRLayerParent* aLayer,
                            const layers::SurfaceDescriptor &aTexture,
                            uint64_t aFrameId,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect)
 {
-#if !defined(MOZ_ANDROID_GOOGLE_VR)
+#if !defined(MOZ_WIDGET_ANDROID)
   if (!mSubmitThread) {
     mSubmitThread = new VRThread(NS_LITERAL_CSTRING("VR_SubmitFrame"));
   }
-#endif // !defined(MOZ_ANDROID_GOOGLE_VR)
+#endif // !defined(MOZ_WIDGET_ANDROID)
 
   if ((mDisplayInfo.mGroupMask & aLayer->GetGroup()) == 0) {
     // Suppress layers hidden by the group mask
     return;
   }
 
   // Ensure that we only accept the first SubmitFrame call per RAF cycle.
   if (!mFrameStarted || aFrameId != mDisplayInfo.mFrameId) {
     return;
   }
 
   RefPtr<Runnable> submit =
     NewRunnableMethod<StoreCopyPassByConstLRef<layers::SurfaceDescriptor>, uint64_t,
       StoreCopyPassByConstLRef<gfx::Rect>, StoreCopyPassByConstLRef<gfx::Rect>>(
       "gfx::VRDisplayHost::SubmitFrameInternal", this, &VRDisplayHost::SubmitFrameInternal,
       aTexture, aFrameId, aLeftEyeRect, aRightEyeRect);
-#if !defined(MOZ_ANDROID_GOOGLE_VR)
+#if !defined(MOZ_WIDGET_ANDROID)
   mSubmitThread->Start();
   mSubmitThread->PostTask(submit.forget());
 #else
   CompositorThreadHolder::Loop()->PostTask(submit.forget());
-#endif // defined(MOZ_ANDROID_GOOGLE_VR)
+#endif // defined(MOZ_WIDGET_ANDROID)
 }
 
 bool
 VRDisplayHost::CheckClearDisplayInfoDirty()
 {
   if (mDisplayInfo == mLastUpdateDisplayInfo) {
     return false;
   }
--- a/gfx/vr/VRDisplayHost.h
+++ b/gfx/vr/VRDisplayHost.h
@@ -81,18 +81,18 @@ protected:
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) = 0;
 #elif defined(XP_MACOSX)
   virtual bool SubmitFrame(MacIOSurface* aMacIOSurface,
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) = 0;
-#elif defined(MOZ_ANDROID_GOOGLE_VR)
-  virtual bool SubmitFrame(const mozilla::layers::EGLImageDescriptor* aDescriptor,
+#elif defined(MOZ_WIDGET_ANDROID)
+  virtual bool SubmitFrame(const mozilla::layers::SurfaceTextureDescriptor& aSurface,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) = 0;
 #endif
 
   VRDisplayInfo mDisplayInfo;
 
   nsTArray<VRLayerParent *> mLayers;
   // Weak reference to mLayers entries are cleared in
--- a/gfx/vr/VRManager.cpp
+++ b/gfx/vr/VRManager.cpp
@@ -21,19 +21,16 @@
 #include "gfxVRExternal.h"
 #if defined(XP_WIN)
 #include "gfxVROculus.h"
 #endif
 #if defined(XP_WIN) || defined(XP_MACOSX) || (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
 #include "gfxVROpenVR.h"
 #include "gfxVROSVR.h"
 #endif
-#if defined(MOZ_ANDROID_GOOGLE_VR)
-#include "gfxVRGVR.h"
-#endif // MOZ_ANDROID_GOOGLE_VR
 
 #include "gfxVRPuppet.h"
 #include "ipc/VRLayerParent.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using namespace mozilla::gl;
@@ -99,23 +96,16 @@ VRManager::VRManager()
 
   // OSVR is cross platform compatible
   mgr = VRSystemManagerOSVR::Create();
   if (mgr) {
       mManagers.AppendElement(mgr);
   }
 #endif
 
-#if defined(MOZ_ANDROID_GOOGLE_VR)
-   mgr = VRSystemManagerGVR::Create();
-   if (mgr) {
-     mManagers.AppendElement(mgr);
-   }
-#endif // defined(MOZ_ANDROID_GOOGLE_VR)
-
   // Enable gamepad extensions while VR is enabled.
   // Preference only can be set at the Parent process.
   if (XRE_IsParentProcess() && gfxPrefs::VREnabled()) {
     Preferences::SetBool("dom.gamepad.extensions.enabled", true);
   }
 }
 
 VRManager::~VRManager()
--- a/gfx/vr/external_api/moz_external_vr.h
+++ b/gfx/vr/external_api/moz_external_vr.h
@@ -11,24 +11,30 @@
 #include <stdint.h>
 #include <type_traits>
 
 #ifdef MOZILLA_INTERNAL_API
 #include "mozilla/TypedEnumBits.h"
 #include "mozilla/gfx/2D.h"
 #endif // MOZILLA_INTERNAL_API
 
+#if defined(__ANDROID__)
+#include <pthread.h>
+#endif // defined(__ANDROID__)
+
 namespace mozilla {
 #ifdef MOZILLA_INTERNAL_API
 namespace dom {
   enum class GamepadHand : uint8_t;
 }
 #endif //  MOZILLA_INTERNAL_API
 namespace gfx {
 
+static const int32_t kVRExternalVersion = 0;
+
 // We assign VR presentations to groups with a bitmask.
 // Currently, we will only display either content or chrome.
 // Later, we will have more groups to support VR home spaces and
 // multitasking environments.
 // These values are not exposed to regular content and only affect
 // chrome-only API's.  They may be changed at any time.
 static const uint32_t kVRGroupNone = 0;
 static const uint32_t kVRGroupContent = 1 << 0;
@@ -211,26 +217,30 @@ struct VRFieldOfView {
 struct VRDisplayState
 {
   enum Eye {
     Eye_Left,
     Eye_Right,
     NumEyes
   };
 
+#if defined(__ANDROID__)
+  bool shutdown;
+#endif // defined(__ANDROID__)
   char mDisplayName[kVRDisplayNameMaxLen];
   VRDisplayCapabilityFlags mCapabilityFlags;
   VRFieldOfView mEyeFOV[VRDisplayState::NumEyes];
   Point3D_POD mEyeTranslation[VRDisplayState::NumEyes];
   IntSize_POD mEyeResolution;
   bool mIsConnected;
   bool mIsMounted;
   FloatSize_POD mStageSize;
   // We can't use a Matrix4x4 here unless we ensure it's a POD type
   float mSittingToStandingTransform[16];
+  uint32_t mPresentingGeneration;
 };
 
 struct VRControllerState
 {
   char mControllerName[kVRControllerNameMaxLen];
 #ifdef MOZILLA_INTERNAL_API
   dom::GamepadHand mHand;
 #else
@@ -291,34 +301,49 @@ struct VRLayerState
   union {
     VRLayer_2D_Content layer_2d_content;
     VRLayer_Stereo_Immersive layer_stereo_immersive;
   };
 };
 
 struct VRBrowserState
 {
+#if defined(__ANDROID__)
+  bool shutdown;
+#endif // defined(__ANDROID__)
   VRLayerState layerState[kVRLayerMaxCount];
 };
 
 struct VRSystemState
 {
+  uint32_t presentingGeneration;
   VRDisplayState displayState;
   VRHMDSensorState sensorState;
   VRControllerState controllerState[kVRControllerMaxCount];
 };
 
 struct VRExternalShmem
 {
+  int32_t version;
+  int32_t size;
+#if defined(__ANDROID__)
+  pthread_mutex_t systemMutex;
+  pthread_mutex_t browserMutex;
+#else
   int64_t generationA;
+#endif // defined(__ANDROID__)
   VRSystemState state;
+#if !defined(__ANDROID__)
   int64_t generationB;
   int64_t browserGenerationA;
+#endif // !defined(__ANDROID__)
   VRBrowserState browserState;
+#if !defined(__ANDROID__)
   int64_t browserGenerationB;
+#endif // !defined(__ANDROID__)
 };
 
 // As we are memcpy'ing VRExternalShmem and its members around, it must be a POD type
 static_assert(std::is_pod<VRExternalShmem>::value, "VRExternalShmem must be a POD type.");
 
 } // namespace gfx
 } // namespace mozilla
 
--- a/gfx/vr/gfxVR.h
+++ b/gfx/vr/gfxVR.h
@@ -54,17 +54,16 @@ enum class VRDeviceType : uint16_t {
 
 struct VRDisplayInfo
 {
   uint32_t mDisplayID;
   VRDeviceType mType;
   uint32_t mPresentingGroups;
   uint32_t mGroupMask;
   uint64_t mFrameId;
-  uint32_t mPresentingGeneration;
   VRDisplayState mDisplayState;
 
   VRHMDSensorState mLastSensorState[kVRMaxLatencyFrames];
   const VRHMDSensorState& GetSensorState() const
   {
     return mLastSensorState[mFrameId % kVRMaxLatencyFrames];
   }
 
@@ -91,18 +90,17 @@ struct VRDisplayInfo
       }
     }
     // Note that mDisplayState is asserted to be a POD type, so memcmp is safe
     return mType == other.mType &&
            mDisplayID == other.mDisplayID &&
            memcmp(&mDisplayState, &other.mDisplayState, sizeof(VRDisplayState)) == 0 &&
            mPresentingGroups == other.mPresentingGroups &&
            mGroupMask == other.mGroupMask &&
-           mFrameId == other.mFrameId &&
-           mPresentingGeneration == other.mPresentingGeneration;
+           mFrameId == other.mFrameId;
   }
 
   bool operator!=(const VRDisplayInfo& other) const {
     return !(*this == other);
   }
 };
 
 struct VRSubmitFrameResultInfo
--- a/gfx/vr/gfxVRExternal.cpp
+++ b/gfx/vr/gfxVRExternal.cpp
@@ -19,17 +19,21 @@
 static const char* kShmemName = "moz.gecko.vr_ext.0.0.1";
 #elif defined(XP_MACOSX)
 #include "mozilla/gfx/MacIOSurface.h"
 #include <sys/mman.h>
 #include <sys/stat.h>        /* For mode constants */
 #include <fcntl.h>           /* For O_* constants */
 #include <errno.h>
 static const char* kShmemName = "/moz.gecko.vr_ext.0.0.1";
-#endif
+#elif defined(MOZ_WIDGET_ANDROID)
+#include <string.h>
+#include <pthread.h>
+#include "GeckoVRManager.h"
+#endif // defined(MOZ_WIDGET_ANDROID)
 
 #include "gfxVRExternal.h"
 #include "VRManagerParent.h"
 #include "VRManager.h"
 #include "VRThread.h"
 
 #include "nsServiceManagerUtils.h"
 #include "nsIScreenManager.h"
@@ -167,16 +171,26 @@ VRDisplayExternal::SubmitFrame(MacIOSurf
   if (ioSurface == nullptr) {
     NS_WARNING("VRDisplayExternal::SubmitFrame() could not get an IOSurface");
   } else {
     // FINDME!  Implement this
   }
   return result;
 }
 
+#elif defined(MOZ_WIDGET_ANDROID)
+
+bool
+VRDisplayExternal::SubmitFrame(const layers::SurfaceTextureDescriptor& aSurface,
+                               const gfx::Rect& aLeftEyeRect,
+                               const gfx::Rect& aRightEyeRect) {
+
+  return false;
+}
+
 #endif
 
 VRControllerExternal::VRControllerExternal(dom::GamepadHand aHand, uint32_t aDisplayID,
                                        uint32_t aNumButtons, uint32_t aNumTriggers,
                                        uint32_t aNumAxes, const nsCString& aId)
   : VRControllerHost(VRDeviceType::External, aHand, aDisplayID)
 {
   MOZ_COUNT_CTOR_INHERITED(VRControllerExternal, VRControllerHost);
@@ -196,33 +210,39 @@ VRControllerExternal::~VRControllerExter
 
 VRSystemManagerExternal::VRSystemManagerExternal()
  : mExternalShmem(nullptr)
 {
 #if defined(XP_MACOSX)
   mShmemFD = 0;
 #elif defined(XP_WIN)
   mShmemFile = NULL;
+#elif defined(MOZ_WIDGET_ANDROID)
+  mDoShutdown = false;
+  mExternalStructFailed = false;
 #endif
 }
 
 VRSystemManagerExternal::~VRSystemManagerExternal()
 {
   CloseShmem();
 }
 
 void
 VRSystemManagerExternal::OpenShmem()
 {
   if (mExternalShmem) {
     return;
+#if defined(MOZ_WIDGET_ANDROID)
+  } else if (mExternalStructFailed) {
+    return;
+#endif // defined(MOZ_WIDGET_ANDROID)
   }
 
 #if defined(XP_MACOSX)
-
   if (mShmemFD == 0) {
     mShmemFD = shm_open(kShmemName, O_RDWR, S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH);
   }
   if (mShmemFD <= 0) {
     mShmemFD = 0;
     return;
   }
 
@@ -239,17 +259,16 @@ VRSystemManagerExternal::OpenShmem()
   if (mExternalShmem == MAP_FAILED) {
     // TODO - Implement logging
     mExternalShmem = NULL;
     CloseShmem();
     return;
   }
 
 #elif defined(XP_WIN)
-
   if (mShmemFile == NULL) {
     mShmemFile = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, kShmemName);
     if (mShmemFile == NULL) {
       // TODO - Implement logging
       CloseShmem();
       return;
     }
   }
@@ -261,53 +280,74 @@ VRSystemManagerExternal::OpenShmem()
     0,
     length.QuadPart);
 
   if (mExternalShmem == NULL) {
     // TODO - Implement logging
     CloseShmem();
     return;
   }
+#elif defined(MOZ_WIDGET_ANDROID)
+  mExternalShmem = (VRExternalShmem*)mozilla::GeckoVRManager::GetExternalContext();
+  if (!mExternalShmem) {
+    return;
+  }
+  if (mExternalShmem->version != kVRExternalVersion) {
+    mExternalShmem = nullptr;
+    mExternalStructFailed = true;
+    return;
+  }
+  if (mExternalShmem->size != sizeof(VRExternalShmem)) {
+    mExternalShmem = nullptr;
+    mExternalStructFailed = true;
+    return;
+  }
 #endif
   CheckForShutdown();
 }
 
 void
 VRSystemManagerExternal::CheckForShutdown()
 {
+#if defined(MOZ_WIDGET_ANDROID)
+  if (mDoShutdown) {
+    Shutdown();
+  }
+#else
   if (mExternalShmem) {
     if (mExternalShmem->generationA == -1 && mExternalShmem->generationB == -1) {
       Shutdown();
     }
   }
+#endif // defined(MOZ_WIDGET_ANDROID)
 }
 
 void
 VRSystemManagerExternal::CloseShmem()
 {
 #if defined(XP_MACOSX)
-  
   if (mExternalShmem) {
     munmap((void *)mExternalShmem, sizeof(VRExternalShmem));
     mExternalShmem = NULL;
   }
   if (mShmemFD) {
     close(mShmemFD);
   }
   mShmemFD = 0;
-  
 #elif defined(XP_WIN)
   if (mExternalShmem) {
     UnmapViewOfFile((void *)mExternalShmem);
     mExternalShmem = NULL;
   }
   if (mShmemFile) {
     CloseHandle(mShmemFile);
     mShmemFile = NULL;
   }
+#elif defined(MOZ_WIDGET_ANDROID)
+  mExternalShmem = NULL;
 #endif
 }
 
 /*static*/ already_AddRefed<VRSystemManagerExternal>
 VRSystemManagerExternal::Create()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -328,16 +368,19 @@ VRSystemManagerExternal::Destroy()
 void
 VRSystemManagerExternal::Shutdown()
 {
   if (mDisplay) {
     mDisplay = nullptr;
   }
   RemoveControllers();
   CloseShmem();
+#if defined(MOZ_WIDGET_ANDROID)
+  mDoShutdown = false;
+#endif
 }
 
 void
 VRSystemManagerExternal::NotifyVSync()
 {
   VRSystemManager::NotifyVSync();
 
   CheckForShutdown();
@@ -445,19 +488,29 @@ VRSystemManagerExternal::RemoveControlle
   mControllerCount = 0;
 }
 
 void
 VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState, VRHMDSensorState* aSensorState /* = nullptr */)
 {
   MOZ_ASSERT(mExternalShmem);
   if (mExternalShmem) {
-    // TODO - Add locking here for non-x86 platforms
+#if defined(MOZ_WIDGET_ANDROID)
+    if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) == 0) {
+        memcpy(aDisplayState, (void*)&(mExternalShmem->state.displayState), sizeof(VRDisplayState));
+        if (aSensorState) {
+          memcpy(aSensorState, (void*)&(mExternalShmem->state.sensorState), sizeof(VRHMDSensorState));
+        }
+        pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex));
+        mDoShutdown = aDisplayState->shutdown;
+    }
+#else
     VRExternalShmem tmp;
     memcpy(&tmp, (void *)mExternalShmem, sizeof(VRExternalShmem));
     if (tmp.generationA == tmp.generationB && tmp.generationA != 0 && tmp.generationA != -1) {
       memcpy(aDisplayState, &tmp.state.displayState, sizeof(VRDisplayState));
       if (aSensorState) {
         memcpy(aSensorState, &tmp.state.sensorState, sizeof(VRHMDSensorState));
       }
     }
+#endif // defined(MOZ_WIDGET_ANDROID)
   }
 }
--- a/gfx/vr/gfxVRExternal.h
+++ b/gfx/vr/gfxVRExternal.h
@@ -41,16 +41,20 @@ protected:
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) override;
 #elif defined(XP_MACOSX)
   virtual bool SubmitFrame(MacIOSurface* aMacIOSurface,
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) override;
+#elif defined(MOZ_WIDGET_ANDROID)
+  bool SubmitFrame(const layers::SurfaceTextureDescriptor& aSurface,
+                           const gfx::Rect& aLeftEyeRect,
+                           const gfx::Rect& aRightEyeRect) override;
 #endif
 
 public:
   explicit VRDisplayExternal(const VRDisplayState& aDisplayState);
   void Refresh();
 protected:
   virtual ~VRDisplayExternal();
   void Destroy();
@@ -101,22 +105,25 @@ public:
 protected:
   VRSystemManagerExternal();
   virtual ~VRSystemManagerExternal();
 
 private:
   // there can only be one
   RefPtr<impl::VRDisplayExternal> mDisplay;
   nsTArray<RefPtr<impl::VRControllerExternal>> mExternalController;
-
 #if defined(XP_MACOSX)
   int mShmemFD;
 #elif defined(XP_WIN)
   HANDLE mShmemFile;
+#elif defined(MOZ_WIDGET_ANDROID)
+  bool mDoShutdown;
+  bool mExternalStructFailed;
 #endif
+
   volatile VRExternalShmem* mExternalShmem;
 
   void OpenShmem();
   void CloseShmem();
   void CheckForShutdown();
 };
 
 } // namespace gfx
deleted file mode 100644
--- a/gfx/vr/gfxVRGVR.cpp
+++ /dev/null
@@ -1,816 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-#include <math.h>
-
-#include "GLBlitHelper.h"
-#include "GLContextEGL.h"
-#include "GLContextProvider.h"
-#include "GLContextTypes.h"
-#include "GLImages.h"
-#include "GLLibraryEGL.h"
-
-#include "gfxPrefs.h"
-#include "gfxVRGVRAPI.h"
-#include "gfxVRGVR.h"
-
-#include "mozilla/dom/GamepadEventTypes.h"
-#include "mozilla/dom/GamepadBinding.h"
-#include "mozilla/gfx/Matrix.h"
-#include "mozilla/gfx/Quaternion.h"
-#include "mozilla/jni/Utils.h"
-#include "mozilla/layers/CompositorThread.h"
-#include "mozilla/layers/TextureHostOGL.h"
-#include "mozilla/Preferences.h"
-
-#include "GeckoVRManager.h"
-#include "nsString.h"
-
-#include "SurfaceTypes.h"
-
-#include "VRManager.h"
-
-#define MOZ_CHECK_GVR_ERRORS
-
-#if defined(MOZ_CHECK_GVR_ERRORS)
-#define GVR_LOGTAG "GeckoWebVR"
-#include <android/log.h>
-#define GVR_CHECK(X) X; \
-{ \
-  gvr_context* context = (mPresentingContext ? mPresentingContext : GetNonPresentingContext()); \
-  if (context && (gvr_get_error(context) != GVR_ERROR_NONE)) { \
-     __android_log_print(ANDROID_LOG_ERROR, GVR_LOGTAG, \
-                         "GVR ERROR: %s at:%s:%s:%d", \
-                         gvr_get_error_string(gvr_get_error(context)), \
-                         __FILE__, __FUNCTION__, __LINE__); \
-    gvr_clear_error(context); \
-  } else if (!context) { \
-    __android_log_print(ANDROID_LOG_ERROR, GVR_LOGTAG, \
-                        "UNABLE TO CHECK GVR ERROR: NO CONTEXT"); \
-  } \
-}
-#define GVR_LOG(format, ...) __android_log_print(ANDROID_LOG_INFO, GVR_LOGTAG, format, ##__VA_ARGS__);
-#else
-#define GVR_CHECK(X) X
-#define GVR_LOG(...)
-#endif
-
-using namespace mozilla;
-using namespace mozilla::gl;
-using namespace mozilla::gfx;
-using namespace mozilla::gfx::impl;
-using namespace mozilla::layers;
-using namespace mozilla::dom;
-
-namespace {
-static VRDisplayGVR* sContextObserver;
-static RefPtr<GLContextEGL> sGLContextEGL;
-static gvr_context* sNonPresentingContext;
-
-gvr_context*
-GetNonPresentingContext() {
-  if (!sNonPresentingContext) {
-    // Try and restore if it has been lost
-    sNonPresentingContext = (gvr_context*)GeckoVRManager::CreateGVRNonPresentingContext();
-  }
-  return sNonPresentingContext;
-}
-
-class SynchronousRunnable : public nsIRunnable {
-public:
-  enum class Type {
-    PresentingContext,
-    NonPresentingContext,
-    Pause,
-    Resume
-  };
-  SynchronousRunnable(const Type aType, void* aContext)
-  : mType(aType)
-  , mContext(aContext)
-  , mUpdateMonitor(new Monitor("SynchronousRunnable_for_Android"))
-  , mUpdated(false)
-  {}
-  NS_DECL_THREADSAFE_ISUPPORTS
-  nsresult Run() override
-  {
-    MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
-    MonitorAutoLock lock(*mUpdateMonitor);
-    if (mType == Type::PresentingContext) {
-      SetGVRPresentingContext(mContext);
-    } else if (mType == Type::NonPresentingContext) {
-      CleanupGVRNonPresentingContext();
-    } else if (mType == Type::Pause) {
-      SetGVRPaused(true);
-    } else if (mType == Type::Resume) {
-      SetGVRPaused(false);
-    } else {
-      GVR_LOG("UNKNOWN SynchronousRunnable::Type!");
-    }
-    mUpdated = true;
-    lock.NotifyAll();
-    return NS_OK;
-  }
-  void Wait()
-  {
-    MonitorAutoLock lock(*mUpdateMonitor);
-    while(!mUpdated) {
-      lock.Wait();
-    }
-  }
-
-  static bool Dispatch(const Type aType, void* aContext)
-  {
-    if (!CompositorThreadHolder::IsInCompositorThread()) {
-      RefPtr<SynchronousRunnable> runnable = new SynchronousRunnable(aType, aContext);
-      CompositorThreadHolder::Loop()->PostTask(do_AddRef(runnable));
-      runnable->Wait();
-      return true;
-    }
-
-    return false;
-  }
-
-protected:
-  virtual ~SynchronousRunnable()
-  {
-    delete mUpdateMonitor;
-  }
-
-  Type mType;
-  void* mContext;
-  Monitor* mUpdateMonitor;
-  bool mUpdated;
-};
-
-}
-
-NS_IMPL_ISUPPORTS(SynchronousRunnable, nsIRunnable)
-
-void
-mozilla::gfx::SetGVRPresentingContext(void* aGVRPresentingContext)
-{
-  if (SynchronousRunnable::Dispatch(SynchronousRunnable::Type::PresentingContext, aGVRPresentingContext)) {
-    GVR_LOG("Done waiting for compositor thread to set presenting context.");
-    return;
-  }
-
-  MOZ_ASSERT(sContextObserver);
-  if (!sGLContextEGL && aGVRPresentingContext) {
-    CreateContextFlags flags = CreateContextFlags::NONE;
-    SurfaceCaps caps = SurfaceCaps::ForRGBA();
-    nsCString str;
-    sGLContextEGL = GLContextEGL::CreateEGLPBufferOffscreenContext(flags, IntSize(4, 4), caps, &str);
-    if (!sGLContextEGL->MakeCurrent()) {
-      GVR_LOG("Failed to make GL context current");
-    }
-  }
-  sContextObserver->SetPresentingContext(aGVRPresentingContext);
-}
-
-void
-mozilla::gfx::CleanupGVRNonPresentingContext()
-{
-  if (SynchronousRunnable::Dispatch(SynchronousRunnable::Type::NonPresentingContext, nullptr)) {
-    GVR_LOG("Done waiting for compositor thread to set non presenting context.");
-    return;
-  }
-
-  if (sNonPresentingContext) {
-    sNonPresentingContext = nullptr;
-    GeckoVRManager::DestroyGVRNonPresentingContext();
-  }
-}
-
-void
-mozilla::gfx::SetGVRPaused(const bool aPaused)
-{
-  if (SynchronousRunnable::Dispatch((aPaused ? SynchronousRunnable::Type::Pause : SynchronousRunnable::Type::Resume), nullptr)) {
-    GVR_LOG("Done waiting for GVR in compositor to: %s",(aPaused ? "Pause" : "Resume"));
-    return;
-  }
-  MOZ_ASSERT(sContextObserver);
-  sContextObserver->SetPaused(aPaused);
-}
-
-VRDisplayGVR::VRDisplayGVR()
-  : VRDisplayHost(VRDeviceType::GVR)
-  , mIsPresenting(false)
-  , mControllerAdded(false)
-  , mPresentingContext(nullptr)
-  , mControllerContext(nullptr)
-  , mControllerState(nullptr)
-  , mViewportList(nullptr)
-  , mLeftViewport(nullptr)
-  , mRightViewport(nullptr)
-  , mSwapChain(nullptr)
-  , mFrameBufferSize{0, 0}
-{
-  MOZ_COUNT_CTOR_INHERITED(VRDisplayGVR, VRDisplayHost);
-  MOZ_ASSERT(GetNonPresentingContext());
-  MOZ_ASSERT(!sContextObserver); // There can be only one GVR display at a time.
-  sContextObserver = this;
-
-  strncpy(mDisplayInfo.mDisplayName, "GVR HMD", kVRDisplayNameMaxLen);
-  mDisplayInfo.mIsConnected = true;
-  mDisplayInfo.mIsMounted = true;
-  mDisplayInfo.mCapabilityFlags = VRDisplayCapabilityFlags::Cap_None |
-                                  VRDisplayCapabilityFlags::Cap_Orientation |
-                                  VRDisplayCapabilityFlags::Cap_Position | // Not yet...
-                                  VRDisplayCapabilityFlags::Cap_Present;
-
-  GVR_CHECK(gvr_refresh_viewer_profile(GetNonPresentingContext()));
-  mViewportList = GVR_CHECK(gvr_buffer_viewport_list_create(GetNonPresentingContext()));
-  mLeftViewport = GVR_CHECK(gvr_buffer_viewport_create(GetNonPresentingContext()));
-  mRightViewport = GVR_CHECK(gvr_buffer_viewport_create(GetNonPresentingContext()));
-  UpdateViewport();
-
-  dom::GamepadHand hand = dom::GamepadHand::Right;
-  const gvr_user_prefs* prefs = GVR_CHECK(gvr_get_user_prefs(GetNonPresentingContext()));
-  if (prefs) {
-    hand = ((gvr_user_prefs_get_controller_handedness(prefs) == GVR_CONTROLLER_RIGHT_HANDED) ?
-             dom::GamepadHand::Right : dom::GamepadHand::Left);
-  }
-  mController = new VRControllerGVR(hand, mDisplayInfo.mDisplayID);
-}
-
-VRDisplayGVR::~VRDisplayGVR()
-{
-  MOZ_COUNT_DTOR_INHERITED(VRDisplayGVR, VRDisplayHost);
-}
-
-void
-VRDisplayGVR::ZeroSensor()
-{
-}
-
-void
-VRDisplayGVR::StartPresentation()
-{
-  if (mIsPresenting) {
-    return;
-  }
-
-  mIsPresenting = true;
-  GeckoVRManager::EnableVRMode();
-}
-
-void
-VRDisplayGVR::StopPresentation()
-{
-  if (!mIsPresenting) {
-    return;
-  }
-
-  mIsPresenting = false;
-  GeckoVRManager::DisableVRMode();
-}
-
-bool
-VRDisplayGVR::SubmitFrame(const mozilla::layers::EGLImageDescriptor* aDescriptor,
-                          const gfx::Rect& aLeftEyeRect,
-                          const gfx::Rect& aRightEyeRect)
-{
-  if (!mPresentingContext) {
-    GVR_LOG("Unable to submit frame. No presenting context")
-    return false;
-  }
-
-  if (!sGLContextEGL) {
-    GVR_LOG("Unable to submit frame. No GL Context");
-    return false;
-  }
-
-  if (!sGLContextEGL->MakeCurrent()) {
-    GVR_LOG("Failed to make GL context current");
-    return false;
-  }
-
-  EGLImage image = (EGLImage)aDescriptor->image();
-  EGLSync sync = (EGLSync)aDescriptor->fence();
-  gfx::IntSize size = aDescriptor->size();
-  MOZ_ASSERT(mSwapChain);
-  GVR_CHECK(gvr_get_recommended_buffer_viewports(mPresentingContext, mViewportList));
-  if ((size.width != mFrameBufferSize.width) || (size.height != mFrameBufferSize.height)) {
-    mFrameBufferSize.width = size.width;
-    mFrameBufferSize.height = size.height;
-    GVR_CHECK(gvr_swap_chain_resize_buffer(mSwapChain, 0, mFrameBufferSize));
-    GVR_LOG("Resize Swap Chain %d,%d", mFrameBufferSize.width, mFrameBufferSize.height);
-  }
-  gvr_frame* frame = GVR_CHECK(gvr_swap_chain_acquire_frame(mSwapChain));
-  if (!frame) {
-    // Sometimes the swap chain seems to not initialized correctly so that
-    // frames can not be acquired. Recreating the swap chain seems to fix the
-    // issue.
-    GVR_LOG("Unable to acquire GVR frame. Recreating swap chain.");
-    RecreateSwapChain();
-    return false;
-  }
-  GVR_CHECK(gvr_frame_bind_buffer(frame, 0));
-
-  EGLint status = LOCAL_EGL_CONDITION_SATISFIED;
-  auto* egl = gl::GLLibraryEGL::Get();
-
-  if (sync) {
-    MOZ_ASSERT(egl->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync));
-    status = egl->fClientWaitSync(EGL_DISPLAY(), sync, 0, LOCAL_EGL_FOREVER);
-  }
-
-  if (status != LOCAL_EGL_CONDITION_SATISFIED) {
-    MOZ_ASSERT(status != 0,
-               "ClientWaitSync generated an error. Has sync already been destroyed?");
-    return false;
-  }
-
-  if (image) {
-    GLuint tex = 0;
-    sGLContextEGL->fGenTextures(1, &tex);
-
-    const ScopedSaveMultiTex saveTex(sGLContextEGL, 1, LOCAL_GL_TEXTURE_2D);
-    sGLContextEGL->fBindTexture(LOCAL_GL_TEXTURE_2D, tex);
-    sGLContextEGL->TexParams_SetClampNoMips();
-    sGLContextEGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, image);
-    sGLContextEGL->BlitHelper()->DrawBlitTextureToFramebuffer(tex, gfx::IntSize(size.width, size.height), gfx::IntSize(mFrameBufferSize.width,  mFrameBufferSize.height));
-    sGLContextEGL->fDeleteTextures(1, &tex);
-  } else {
-    GVR_LOG("Unable to submit frame. Unable to extract EGLImage");
-    return false;
-  }
-  GVR_CHECK(gvr_frame_unbind(frame));
-  GVR_CHECK(gvr_frame_submit(&frame, mViewportList, mHeadMatrix));
-  return true;
-}
-
-static void
-FillMatrix(gfx::Matrix4x4 &target, const gvr_mat4f& source)
-{
-  target._11 = source.m[0][0];
-  target._12 = source.m[0][1];
-  target._13 = source.m[0][2];
-  target._14 = source.m[0][3];
-  target._21 = source.m[1][0];
-  target._22 = source.m[1][1];
-  target._23 = source.m[1][2];
-  target._24 = source.m[1][3];
-  target._31 = source.m[2][0];
-  target._32 = source.m[2][1];
-  target._33 = source.m[2][2];
-  target._34 = source.m[2][3];
-  target._41 = source.m[3][0];
-  target._42 = source.m[3][1];
-  target._43 = source.m[3][2];
-  target._44 = source.m[3][3];
-}
-
-VRHMDSensorState
-VRDisplayGVR::GetSensorState()
-{
-  VRHMDSensorState result{};
-
-  gvr_context* context = (mPresentingContext ? mPresentingContext : GetNonPresentingContext());
-
-  if (!context) {
-    GVR_LOG("Unable to get sensor state. Context is null");
-    return result;
-  }
-
-  gvr_clock_time_point when = GVR_CHECK(gvr_get_time_point_now());
-  if (mIsPresenting) {
-    // 50ms into the future is what GVR docs recommends using for head rotation
-    // prediction.
-    when.monotonic_system_time_nanos += 50000000;
-  }
-  mHeadMatrix = GVR_CHECK(gvr_get_head_space_from_start_space_rotation(context, when));
-  gvr_mat4f neck = GVR_CHECK(gvr_apply_neck_model(context, mHeadMatrix, 1.0));;
-
-  gfx::Matrix4x4 m;
-
-  FillMatrix(m, neck);
-  m.Invert();
-  gfx::Quaternion rot;
-  rot.SetFromRotationMatrix(m);
-
-  result.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
-  result.orientation[0] = rot.x;
-  result.orientation[1] = rot.y;
-  result.orientation[2] = rot.z;
-  result.orientation[3] = rot.w;
-  result.angularVelocity[0] = 0.0f;
-  result.angularVelocity[1] = 0.0f;
-  result.angularVelocity[2] = 0.0f;
-
-  result.flags |= VRDisplayCapabilityFlags::Cap_Position;
-  result.position[0] = m._14;
-  result.position[1] = m._24;
-  result.position[2] = m._34;
-  result.linearVelocity[0] = 0.0f;
-  result.linearVelocity[1] = 0.0f;
-  result.linearVelocity[2] = 0.0f;
-
-  UpdateHeadToEye(context);
-  CalcViewMatrices(&result, mHeadToEyes);
-
-  return result;
-}
-
-void
-VRDisplayGVR::SetPaused(const bool aPaused)
-{
-  if (aPaused) {
-    if (mPresentingContext) {
-      GVR_CHECK(gvr_pause_tracking(mPresentingContext));
-    } else if (sNonPresentingContext) {
-      GVR_CHECK(gvr_pause_tracking(sNonPresentingContext));
-    }
-
-    if (mControllerContext) {
-      GVR_CHECK(gvr_controller_pause(mControllerContext));
-    }
-  } else {
-    if (mPresentingContext) {
-      GVR_CHECK(gvr_refresh_viewer_profile(mPresentingContext));
-      GVR_CHECK(gvr_resume_tracking(mPresentingContext));
-    } else if (sNonPresentingContext) {
-      GVR_CHECK(gvr_resume_tracking(sNonPresentingContext));
-    }
-
-    if (mControllerContext) {
-      GVR_CHECK(gvr_controller_resume(mControllerContext));
-    }
-  }
-}
-
-void
-VRDisplayGVR::SetPresentingContext(void* aGVRPresentingContext)
-{
-  MOZ_ASSERT(sGLContextEGL);
-  sGLContextEGL->MakeCurrent();
-  mPresentingContext = (gvr_context*)aGVRPresentingContext;
-  if (mPresentingContext) {
-    GVR_CHECK(gvr_initialize_gl(mPresentingContext));
-    RecreateSwapChain();
-  } else {
-
-    if (mSwapChain) {
-      // gvr_swap_chain_destroy will set the pointer to null
-      GVR_CHECK(gvr_swap_chain_destroy(&mSwapChain));
-      MOZ_ASSERT(!mSwapChain);
-    }
-
-    // The presentation context has been destroy, probably by the user so increment the presenting
-    // generation if we are presenting so that the DOM knows to end the current presentation.
-    if (mIsPresenting) {
-      mDisplayInfo.mPresentingGeneration++;
-    }
-  }
-}
-
-void
-VRDisplayGVR::UpdateHeadToEye(gvr_context* aContext)
-{
-  if (!aContext) {
-    return;
-  }
-
-  for (uint32_t eyeIndex = 0; eyeIndex < 2; eyeIndex++) {
-    gvr_mat4f eye = GVR_CHECK(gvr_get_eye_from_head_matrix(aContext, eyeIndex));
-    mDisplayInfo.mEyeTranslation[eyeIndex].x = -eye.m[0][3];
-    mDisplayInfo.mEyeTranslation[eyeIndex].y = -eye.m[1][3];
-    mDisplayInfo.mEyeTranslation[eyeIndex].z = -eye.m[2][3];
-    mHeadToEyes[eyeIndex] = gfx::Matrix4x4();
-    mHeadToEyes[eyeIndex].PreTranslate(eye.m[0][3], eye.m[1][3], eye.m[2][3]);
-  }
-}
-
-void
-VRDisplayGVR::UpdateViewport()
-{
-  gvr_context* context = (mPresentingContext ? mPresentingContext : GetNonPresentingContext());
-
-  if (!context) {
-    return;
-  }
-
-  GVR_CHECK(gvr_get_recommended_buffer_viewports(context, mViewportList));
-  GVR_CHECK(gvr_buffer_viewport_list_get_item(mViewportList, 0, mLeftViewport));
-  GVR_CHECK(gvr_buffer_viewport_list_get_item(mViewportList, 1, mRightViewport));
-
-  gvr_rectf fov = GVR_CHECK(gvr_buffer_viewport_get_source_fov(mLeftViewport));
-  mDisplayInfo.mEyeFOV[VRDisplayInfo::Eye_Left] = VRFieldOfView(fov.top, fov.right, fov.bottom, fov.left);
-  GVR_LOG("FOV:L top:%f right:%f bottom:%f left:%f",(float)fov.top, (float)fov.left, (float)fov.bottom, (float)fov.right);
-
-  fov = GVR_CHECK(gvr_buffer_viewport_get_source_fov(mRightViewport));
-  mDisplayInfo.mEyeFOV[VRDisplayInfo::Eye_Right] = VRFieldOfView(fov.top, fov.right, fov.bottom, fov.left);
-  GVR_LOG("FOV:R top:%f right:%f bottom:%f left:%f",(float)fov.top, (float)fov.left, (float)fov.bottom, (float)fov.right);
-
-  gvr_sizei size = GVR_CHECK(gvr_get_maximum_effective_render_target_size(context));
-  mDisplayInfo.mEyeResolution = IntSize(size.width / 2, size.height);
-  GVR_LOG("Eye Resolution: %dx%d",mDisplayInfo.mEyeResolution.width,mDisplayInfo.mEyeResolution.height);
-
-  UpdateHeadToEye(context);
-}
-
-void
-VRDisplayGVR::RecreateSwapChain()
-{
-  MOZ_ASSERT(sGLContextEGL);
-  sGLContextEGL->MakeCurrent();
-  if (mSwapChain) {
-    // gvr_swap_chain_destroy will set the pointer to null
-    GVR_CHECK(gvr_swap_chain_destroy(&mSwapChain));
-    MOZ_ASSERT(!mSwapChain);
-  }
-  gvr_buffer_spec* spec = GVR_CHECK(gvr_buffer_spec_create(mPresentingContext));
-  mFrameBufferSize = GVR_CHECK(gvr_get_maximum_effective_render_target_size(mPresentingContext));
-  GVR_CHECK(gvr_buffer_spec_set_size(spec, mFrameBufferSize));
-  GVR_CHECK(gvr_buffer_spec_set_samples(spec, 0));
-  GVR_CHECK(gvr_buffer_spec_set_color_format(spec, GVR_COLOR_FORMAT_RGBA_8888));
-  GVR_CHECK(gvr_buffer_spec_set_depth_stencil_format(spec, GVR_DEPTH_STENCIL_FORMAT_NONE));
-  mSwapChain = GVR_CHECK(gvr_swap_chain_create(mPresentingContext, (const gvr_buffer_spec**)&spec, 1));
-  GVR_CHECK(gvr_buffer_spec_destroy(&spec));
-}
-
-void
-VRDisplayGVR::EnableControllers(const bool aEnable, VRSystemManager* aManager)
-{
-  if (aEnable && !mControllerAdded) {
-    // Sometimes the gamepad doesn't get removed cleanly so just try to remove it before adding it.
-    aManager->RemoveGamepad(mController->GetControllerInfo().mControllerID);
-    aManager->AddGamepad(mController->GetControllerInfo());
-    mControllerAdded = true;
-  } else if (!aEnable && mControllerAdded) {
-    mControllerAdded = false;
-    aManager->RemoveGamepad(mController->GetControllerInfo().mControllerID);
-  }
-
-  gvr_context* context = mPresentingContext;
-
-  if (!context) {
-    if (mControllerContext) {
-      GVR_CHECK(gvr_controller_destroy(&mControllerContext));
-    }
-    return;
-  }
-
-  if ((aEnable && mControllerContext) || (!aEnable && !mControllerContext)) {
-    return;
-  }
-
-  if (aEnable) {
-    if (!mControllerContext) {
-      int32_t options = GVR_CHECK(gvr_controller_get_default_options());
-      options |= GVR_CONTROLLER_ENABLE_GYRO | GVR_CONTROLLER_ENABLE_ACCEL | GVR_CONTROLLER_ENABLE_ARM_MODEL;
-      mControllerContext = GVR_CHECK(gvr_controller_create_and_init(options, context));
-      GVR_CHECK(gvr_controller_resume(mControllerContext));
-    }
-    if (!mControllerState) {
-      mControllerState = GVR_CHECK(gvr_controller_state_create());
-    }
-  } else {
-    GVR_CHECK(gvr_controller_pause(mControllerContext));
-    GVR_CHECK(gvr_controller_destroy(&mControllerContext));
-  }
-}
-
-void
-VRDisplayGVR::UpdateControllers(VRSystemManager* aManager)
-{
-  if (!mControllerContext) {
-    return;
-  }
-
-  GVR_CHECK(gvr_controller_apply_arm_model(mControllerContext, 0, mController->GetHand() == dom::GamepadHand::Right ? GVR_CONTROLLER_RIGHT_HANDED : GVR_CONTROLLER_LEFT_HANDED, GVR_ARM_MODEL_FOLLOW_GAZE, mHeadMatrix));
-  GVR_CHECK(gvr_controller_state_update(mControllerContext, 0, mControllerState));
-  mController->Update(mControllerState, aManager);
-}
-
-
-void
-VRDisplayGVR::GetControllers(nsTArray<RefPtr<VRControllerHost> >& aControllerResult)
-{
-  aControllerResult.AppendElement(mController.get());
-}
-
-VRControllerGVR::VRControllerGVR(dom::GamepadHand aHand, uint32_t aDisplayID)
-  : VRControllerHost(VRDeviceType::GVR, aHand, aDisplayID)
-{
-  MOZ_COUNT_CTOR_INHERITED(VRControllerGVR, VRControllerHost);
-
-  VRControlerState& state = mControllerInfo.mControllerState;
-  strncpy(state.mControllerName, "Daydream Controller", kVRControllerNameMaxLen);
-
-  // The gvr_controller_button enum starts with GVR_CONTROLLER_BUTTON_NONE at index zero
-  // so the GVR controller has one less button than GVR_CONTROLLER_BUTTON_COUNT specifies.
-  state.mNumButtons = GVR_CONTROLLER_BUTTON_COUNT - 1; // Skip dummy none button
-  state.mNumAxes = 2;
-  state.mNumHaptics = 0;
-}
-
-VRControllerGVR::~VRControllerGVR()
-{
-  MOZ_COUNT_DTOR_INHERITED(VRControllerGVR, VRControllerHost);
-}
-
-void
-VRControllerGVR::Update(gvr_controller_state* aState, VRSystemManager* aManager)
-{
-  mPose.Clear();
-
-  if (gvr_controller_state_get_connection_state(aState) != GVR_CONTROLLER_CONNECTED) {
-    return;
-  }
-  const uint64_t previousPressMask = GetButtonPressed();
-  const uint64_t previousTouchMask = GetButtonTouched();
-  uint64_t currentPressMask = 0;
-  uint64_t currentTouchMask = 0;
-  // Index 0 is the dummy button so skip it.
-  for (int ix = 1; ix < GVR_CONTROLLER_BUTTON_COUNT; ix++) {
-    const uint64_t buttonMask = 0x01 << (ix - 1);
-    bool pressed = gvr_controller_state_get_button_state(aState, ix);
-    bool touched = pressed;
-    if (ix == GVR_CONTROLLER_BUTTON_CLICK) {
-       touched = gvr_controller_state_is_touching(aState);
-       double xAxis = 0.0;
-       double yAxis = 0.0;
-       if (touched) {
-         gvr_vec2f axes = gvr_controller_state_get_touch_pos(aState);
-         xAxis = (axes.x * 2.0) - 1.0;
-         yAxis = (axes.y * 2.0) - 1.0;
-       }
-       aManager->NewAxisMove(0, 0, xAxis);
-       aManager->NewAxisMove(0, 1, yAxis);
-    }
-    if (pressed) {
-      currentPressMask |= buttonMask;
-    }
-    if (touched) {
-      currentTouchMask |= buttonMask;
-    }
-    if (((currentPressMask & buttonMask) ^ (previousPressMask & buttonMask)) ||
-        ((currentTouchMask & buttonMask) ^ (previousTouchMask & buttonMask))) {
-      aManager->NewButtonEvent(0, ix - 1, pressed, touched, pressed ? 1.0 : 0.0);
-    }
-  }
-  SetButtonPressed(currentPressMask);
-  SetButtonTouched(currentTouchMask);
-
-  mPose.flags = dom::GamepadCapabilityFlags::Cap_Orientation | dom::GamepadCapabilityFlags::Cap_Position | dom::GamepadCapabilityFlags::Cap_LinearAcceleration;
-
-  gvr_quatf ori = gvr_controller_state_get_orientation(aState);
-  mPose.orientation[0] = ori.qx;
-  mPose.orientation[1] = ori.qy;
-  mPose.orientation[2] = ori.qz;
-  mPose.orientation[3] = ori.qw;
-  mPose.isOrientationValid = true;
-
-  gvr_vec3f acc = gvr_controller_state_get_accel(aState);
-  mPose.linearAcceleration[0] = acc.x;
-  mPose.linearAcceleration[1] = acc.y;
-  mPose.linearAcceleration[2] = acc.z;
-
-  gvr_vec3f vel = gvr_controller_state_get_gyro(aState);
-  mPose.angularVelocity[0] = vel.x;
-  mPose.angularVelocity[1] = vel.y;
-  mPose.angularVelocity[2] = vel.z;
-
-  gvr_vec3f pos =  gvr_controller_state_get_position(aState);
-  mPose.position[0] = pos.x;
-  mPose.position[1] = pos.y;
-  mPose.position[2] = pos.z;
-
-  aManager->NewPoseState(0, mPose);
-}
-
-/*static*/ already_AddRefed<VRSystemManagerGVR>
-VRSystemManagerGVR::Create()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (!gfxPrefs::VREnabled()) {
-    return nullptr;
-  }
-
-  RefPtr<VRSystemManagerGVR> manager = new VRSystemManagerGVR();
-  return manager.forget();
-}
-
-void
-VRSystemManagerGVR::Destroy()
-{
-
-}
-
-void
-VRSystemManagerGVR::Shutdown()
-{
-
-}
-
-void
-VRSystemManagerGVR::Enumerate()
-{
-  if (!GeckoVRManager::IsGVRPresent()) {
-    return;
-  }
-
-  if (!mGVRHMD) {
-    mGVRHMD = new VRDisplayGVR();
-  }
-}
-
-bool
-VRSystemManagerGVR::ShouldInhibitEnumeration()
-{
-  if (VRSystemManager::ShouldInhibitEnumeration()) {
-    return true;
-  }
-  if (mGVRHMD) {
-    // When we find an a VR device, don't
-    // allow any further enumeration as it
-    // may get picked up redundantly by other
-    // API's.
-    return true;
-  }
-  return false;
-}
-
-void
-VRSystemManagerGVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
-{
-  if (mGVRHMD) {
-    aHMDResult.AppendElement(mGVRHMD);
-  }
-}
-
-bool
-VRSystemManagerGVR::GetIsPresenting()
-{
-  if (!mGVRHMD) {
-    return false;
-  }
-
-  VRDisplayInfo displayInfo(mGVRHMD->GetDisplayInfo());
-  return displayInfo.GetPresentingGroups() != kVRGroupNone;
-}
-
-void
-VRSystemManagerGVR::HandleInput()
-{
-  if (mGVRHMD) {
-    mGVRHMD->UpdateControllers(this);
-  }
-}
-
-void
-VRSystemManagerGVR::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
-{
-  if (mGVRHMD) {
-    mGVRHMD->GetControllers(aControllerResult);
-  }
-}
-
-void
-VRSystemManagerGVR::ScanForControllers()
-{
-  if (mGVRHMD) {
-    mGVRHMD->EnableControllers(true, this);
-  }
-}
-
-void
-VRSystemManagerGVR::RemoveControllers()
-{
-  if (mGVRHMD) {
-    mGVRHMD->EnableControllers(false, this);
-  }
-}
-
-void
-VRSystemManagerGVR::VibrateHaptic(uint32_t aControllerIdx,
-                                  uint32_t aHapticIndex,
-                                  double aIntensity,
-                                  double aDuration,
-                                  const VRManagerPromise& aPromise)
-{
-
-}
-
-void
-VRSystemManagerGVR::StopVibrateHaptic(uint32_t aControllerIdx)
-{
-
-}
-
-VRSystemManagerGVR::VRSystemManagerGVR()
-  : mGVRHMD(nullptr)
-{
-
-}
-
-VRSystemManagerGVR::~VRSystemManagerGVR()
-{
-
-}
-
deleted file mode 100644
--- a/gfx/vr/gfxVRGVR.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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 GFX_VR_GVR_H
-#define GFX_VR_GVR_H
-
-#include "gfxVR.h"
-
-#include <memory>
-
-#include "mozilla/EnumeratedArray.h"
-#include "mozilla/gfx/2D.h"
-#include "mozilla/gfx/Matrix.h"
-#include "mozilla/RefPtr.h"
-#include "mozilla/UniquePtr.h"
-
-#include "nsTArray.h"
-#include "nsIRunnable.h"
-#include "nsIScreen.h"
-#include "nsCOMPtr.h"
-
-#include "VRDisplayHost.h"
-
-#pragma GCC system_header
-#pragma GCC visibility push(default)
-#include "vr/gvr/capi/include/gvr.h"
-#include "vr/gvr/capi/include/gvr_controller.h"
-#pragma GCC visibility pop
-
-
-namespace mozilla {
-namespace gl {
-class GLContextEGL;
-} // namespace gl
-namespace layers {
-class EGLImageDescriptor;
-} // namespace layers
-namespace gfx {
-namespace impl {
-
-class VRControllerGVR : public VRControllerHost
-{
-public:
-  explicit VRControllerGVR(dom::GamepadHand aHand, uint32_t aDisplayID);
-  virtual ~VRControllerGVR();
-  void Update(gvr_controller_state* aState, VRSystemManager* aManager);
-};
-
-class VRDisplayGVR : public VRDisplayHost
-{
-public:
-  VRDisplayGVR();
-
-  // BEGIN VRDisplayHost interface
-  void ZeroSensor() override;
-  void StartPresentation() override;
-  void StopPresentation() override;
-  bool SubmitFrame(const mozilla::layers::EGLImageDescriptor* aDescriptor,
-                   const gfx::Rect& aLeftEyeRect,
-                   const gfx::Rect& aRightEyeRect) override;
-protected:
-  virtual VRHMDSensorState GetSensorState() override;
-  // END VRDisplayHost interface
-
-public:
-  void SetPaused(const bool aPaused);
-  void SetPresentingContext(void* aGVRPresentingContext);
-  void EnableControllers(const bool aEnable, VRSystemManager* aManager);
-  void UpdateControllers(VRSystemManager* aManager);
-  void GetControllers(nsTArray<RefPtr<VRControllerHost> >& aControllerResult);
-
-protected:
-  virtual ~VRDisplayGVR();
-  void UpdateHeadToEye(gvr_context* aContext);
-  void UpdateViewport();
-  void RecreateSwapChain();
-
-  bool mIsPresenting;
-  bool mControllerAdded;
-
-  gfx::Matrix4x4 mHeadToEyes[2];
-  gvr_context* mPresentingContext;
-  gvr_controller_context* mControllerContext;
-  gvr_controller_state* mControllerState;
-  gvr_buffer_viewport_list* mViewportList;
-  gvr_buffer_viewport* mLeftViewport;
-  gvr_buffer_viewport* mRightViewport;
-  gvr_mat4f mHeadMatrix;
-  gvr_swap_chain* mSwapChain;
-  gvr_sizei mFrameBufferSize;
-
-  RefPtr<VRControllerGVR> mController;
-};
-
-
-} // namespace impl
-
-class VRSystemManagerGVR : public VRSystemManager
-{
-public:
-  static already_AddRefed<VRSystemManagerGVR> Create();
-
-  void Destroy() override;
-  void Shutdown() override;
-  void Enumerate() override;
-  bool ShouldInhibitEnumeration() override;
-  void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) override;
-  bool GetIsPresenting() override;
-  void HandleInput() override;
-  void GetControllers(nsTArray<RefPtr<VRControllerHost>>&
-                      aControllerResult) override;
-  void ScanForControllers() override;
-  void RemoveControllers() override;
-  void VibrateHaptic(uint32_t aControllerIdx,
-                     uint32_t aHapticIndex,
-                     double aIntensity,
-                     double aDuration,
-                     const VRManagerPromise& aPromise) override;
-  void StopVibrateHaptic(uint32_t aControllerIdx) override;
-
-protected:
-  VRSystemManagerGVR();
-  virtual ~VRSystemManagerGVR();
-
-private:
-  RefPtr<impl::VRDisplayGVR> mGVRHMD;
-};
-
-} // namespace gfx
-} // namespace mozilla
-
-
-#endif /* GFX_VR_GVR_H */
deleted file mode 100644
--- a/gfx/vr/gfxVRGVRAPI.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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 GFX_VR_GVR_API_H
-#define GFX_VR_GVR_API_H
-namespace mozilla {
-namespace gfx {
-
-void SetGVRPresentingContext(void* aGVRPresentingContext);
-void CleanupGVRNonPresentingContext();
-void SetGVRPaused(const bool aPaused);
-
-} // namespace gfx
-} // namespace mozilla
-#endif // GFX_VR_GVR_API_H
--- a/gfx/vr/gfxVROSVR.cpp
+++ b/gfx/vr/gfxVROSVR.cpp
@@ -360,28 +360,16 @@ VRDisplayOSVR::SubmitFrame(MacIOSurface*
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect)
 {
   // XXX Add code to submit frame
   MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread());
   return false;
 }
 
-#elif defined(MOZ_ANDROID_GOOGLE_VR)
-
-bool
-VRDisplayOSVR::SubmitFrame(const mozilla::layers::EGLImageDescriptor*,
-                           const gfx::Rect& aLeftEyeRect,
-                           const gfx::Rect& aRightEyeRect)
-{
-  // XXX Add code to submit frame
-  MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread());
-  return false;
-}
-
 #endif
 
 void
 VRDisplayOSVR::StartPresentation()
 {
   // XXX Add code to start VR Presentation
 }
 
--- a/gfx/vr/gfxVROSVR.h
+++ b/gfx/vr/gfxVROSVR.h
@@ -41,20 +41,16 @@ protected:
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) override;
 #elif defined(XP_MACOSX)
   virtual bool SubmitFrame(MacIOSurface* aMacIOSurface,
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) override;
-#elif defined(MOZ_ANDROID_GOOGLE_VR)
-  virtual bool SubmitFrame(const mozilla::layers::EGLImageDescriptor*,
-                           const gfx::Rect& aLeftEyeRect,
-                           const gfx::Rect& aRightEyeRect) override;
 #endif
 
 public:
   explicit VRDisplayOSVR(OSVR_ClientContext* context,
                          OSVR_ClientInterface* iface,
                          OSVR_DisplayConfig* display);
 
 protected:
--- a/gfx/vr/gfxVRPuppet.cpp
+++ b/gfx/vr/gfxVRPuppet.cpp
@@ -553,22 +553,22 @@ VRDisplayPuppet::SubmitFrame(MacIOSurfac
       MOZ_ASSERT(false, "No support for showing VR frames on MacOSX yet.");
       break;
     }
   }
 
   return false;
 }
 
-#elif defined(MOZ_ANDROID_GOOGLE_VR)
+#elif defined(MOZ_WIDGET_ANDROID)
 
 bool
-VRDisplayPuppet::SubmitFrame(const mozilla::layers::EGLImageDescriptor* aDescriptor,
-                           const gfx::Rect& aLeftEyeRect,
-                           const gfx::Rect& aRightEyeRect)
+VRDisplayPuppet::SubmitFrame(const mozilla::layers::SurfaceTextureDescriptor& aDescriptor,
+                             const gfx::Rect& aLeftEyeRect,
+                             const gfx::Rect& aRightEyeRect)
 {
   MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread());
   return false;
 }
 
 #endif
 
 void
--- a/gfx/vr/gfxVRPuppet.h
+++ b/gfx/vr/gfxVRPuppet.h
@@ -37,18 +37,18 @@ protected:
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) override;
 #elif defined(XP_MACOSX)
   virtual bool SubmitFrame(MacIOSurface* aMacIOSurface,
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) override;
-#elif defined(MOZ_ANDROID_GOOGLE_VR)
-  virtual bool SubmitFrame(const mozilla::layers::EGLImageDescriptor* aDescriptor,
+#elif defined(MOZ_WIDGET_ANDROID)
+  virtual bool SubmitFrame(const mozilla::layers::SurfaceTextureDescriptor& aDescriptor,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) override;
 #endif
 
 public:
   explicit VRDisplayPuppet();
   void Refresh();
 
--- a/gfx/vr/ipc/VRManagerChild.cpp
+++ b/gfx/vr/ipc/VRManagerChild.cpp
@@ -15,16 +15,18 @@
 #include "mozilla/dom/VREventObserver.h"
 #include "mozilla/dom/WindowBinding.h" // for FrameRequestCallback
 #include "mozilla/dom/ContentChild.h"
 #include "nsContentUtils.h"
 #include "mozilla/dom/GamepadManager.h"
 #include "mozilla/dom/VRServiceTest.h"
 #include "mozilla/layers/SyncObject.h"
 
+using namespace mozilla::dom;
+
 namespace {
 const nsTArray<RefPtr<dom::VREventObserver>>::index_type kNoIndex =
   nsTArray<RefPtr<dom::VREventObserver> >::NoIndex;
 } // namespace
 
 namespace mozilla {
 namespace gfx {
 
--- a/gfx/vr/ipc/VRMessageUtils.h
+++ b/gfx/vr/ipc/VRMessageUtils.h
@@ -42,16 +42,17 @@ struct ParamTraits<mozilla::gfx::VRDispl
     WriteParam(aMsg, displayName);
     WriteParam(aMsg, aParam.mCapabilityFlags);
     WriteParam(aMsg, aParam.mEyeResolution.width);
     WriteParam(aMsg, aParam.mEyeResolution.height);
     WriteParam(aMsg, aParam.mIsConnected);
     WriteParam(aMsg, aParam.mIsMounted);
     WriteParam(aMsg, aParam.mStageSize.width);
     WriteParam(aMsg, aParam.mStageSize.height);
+    WriteParam(aMsg, aParam.mPresentingGeneration);
     for (int i = 0; i < 16; i++) {
       // TODO - Should probably memcpy the whole array or
       // convert Maxtrix4x4 to a POD type and use it
       // instead
       WriteParam(aMsg, aParam.mSittingToStandingTransform[i]);
     }
     for (int i = 0; i < mozilla::gfx::VRDisplayState::NumEyes; i++) {
       WriteParam(aMsg, aParam.mEyeFOV[i]);
@@ -66,17 +67,18 @@ struct ParamTraits<mozilla::gfx::VRDispl
     nsCString displayName;
     if (!ReadParam(aMsg, aIter, &(displayName)) ||
         !ReadParam(aMsg, aIter, &(aResult->mCapabilityFlags)) ||
         !ReadParam(aMsg, aIter, &(aResult->mEyeResolution.width)) ||
         !ReadParam(aMsg, aIter, &(aResult->mEyeResolution.height)) ||
         !ReadParam(aMsg, aIter, &(aResult->mIsConnected)) ||
         !ReadParam(aMsg, aIter, &(aResult->mIsMounted)) ||
         !ReadParam(aMsg, aIter, &(aResult->mStageSize.width)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mStageSize.height))) {
+        !ReadParam(aMsg, aIter, &(aResult->mStageSize.height)) ||
+        !ReadParam(aMsg, aIter, &(aResult->mPresentingGeneration))) {
       return false;
     }
     for (int i = 0; i < 16; i++) {
       if (!ReadParam(aMsg, aIter, &(aResult->mSittingToStandingTransform[i]))) {
         return false;
       }
     }
     strncpy(aResult->mDisplayName, displayName.BeginReading(), mozilla::gfx::kVRDisplayNameMaxLen);
@@ -99,31 +101,29 @@ struct ParamTraits<mozilla::gfx::VRDispl
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mType);
     WriteParam(aMsg, aParam.mDisplayID);
     WriteParam(aMsg, aParam.mPresentingGroups);
     WriteParam(aMsg, aParam.mGroupMask);
     WriteParam(aMsg, aParam.mFrameId);
-    WriteParam(aMsg, aParam.mPresentingGeneration);
     WriteParam(aMsg, aParam.mDisplayState);
     for (int i = 0; i < mozilla::gfx::kVRMaxLatencyFrames; i++) {
       WriteParam(aMsg, aParam.mLastSensorState[i]);
     }
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &(aResult->mType)) ||
         !ReadParam(aMsg, aIter, &(aResult->mDisplayID)) ||
         !ReadParam(aMsg, aIter, &(aResult->mPresentingGroups)) ||
         !ReadParam(aMsg, aIter, &(aResult->mGroupMask)) ||
         !ReadParam(aMsg, aIter, &(aResult->mFrameId)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mPresentingGeneration)) ||
         !ReadParam(aMsg, aIter, &(aResult->mDisplayState))) {
       return false;
     }
     for (int i = 0; i < mozilla::gfx::kVRMaxLatencyFrames; i++) {
       if (!ReadParam(aMsg, aIter, &(aResult->mLastSensorState[i]))) {
         return false;
       }
     }
deleted file mode 100644
--- a/gfx/vr/jni/gfxGVRJNI.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <jni.h>
-
-extern "C" __attribute__((visibility("default"))) jlong
-Java_com_google_vr_cardboard_DisplaySynchronizer_nativeCreate(
-    JNIEnv* env,
-    jobject jcaller,
-    jclass classLoader,
-    jobject appContext);
-
-// Step 2: method stubs.
-extern "C" __attribute__((visibility("default"))) void
-Java_com_google_vr_cardboard_DisplaySynchronizer_nativeDestroy(
-    JNIEnv* env,
-    jobject jcaller,
-    jlong nativeDisplaySynchronizer);
-
-extern "C" __attribute__((visibility("default"))) void
-Java_com_google_vr_cardboard_DisplaySynchronizer_nativeReset(
-    JNIEnv* env,
-    jobject jcaller,
-    jlong nativeDisplaySynchronizer,
-    jlong expectedInterval,
-    jlong vsyncOffset);
-
-extern "C" __attribute__((visibility("default"))) void
-Java_com_google_vr_cardboard_DisplaySynchronizer_nativeUpdate(
-    JNIEnv* env,
-    jobject jcaller,
-    jlong nativeDisplaySynchronizer,
-    jlong syncTime,
-    jint currentRotation);
-
-namespace {
-
-bool
-check(JNIEnv* env) {
-  if (env->ExceptionCheck()) {
-    env->ExceptionDescribe();
-    env->ExceptionClear();
-    return false;
-  }
-  return true;
-}
-
-const char kDisplaySynchronizerClassPath[] = "com/google/vr/cardboard/DisplaySynchronizer";
-
-static const JNINativeMethod kMethodsDisplaySynchronizer[] = {
-    {"nativeCreate",
-     "("
-     "Ljava/lang/ClassLoader;"
-     "Landroid/content/Context;"
-     ")"
-     "J",
-     reinterpret_cast<void*>(
-         Java_com_google_vr_cardboard_DisplaySynchronizer_nativeCreate)},
-    {"nativeDestroy",
-     "("
-     "J"
-     ")"
-     "V",
-     reinterpret_cast<void*>(
-         Java_com_google_vr_cardboard_DisplaySynchronizer_nativeDestroy)},
-    {"nativeReset",
-     "("
-     "J"
-     "J"
-     "J"
-     ")"
-     "V",
-     reinterpret_cast<void*>(
-         Java_com_google_vr_cardboard_DisplaySynchronizer_nativeReset)},
-    {"nativeUpdate",
-     "("
-     "J"
-     "J"
-     "I"
-     ")"
-     "V",
-     reinterpret_cast<void*>(
-         Java_com_google_vr_cardboard_DisplaySynchronizer_nativeUpdate)},
-};
-}
-
-bool
-SetupGVRJNI(JNIEnv* env)
-{
-  jclass displaySynchronizerClazz = env->FindClass(kDisplaySynchronizerClassPath);
-  if (!check(env)) { return false; }
-  if (displaySynchronizerClazz == nullptr) {
-    return false;
-  }
-  env->RegisterNatives(displaySynchronizerClazz, kMethodsDisplaySynchronizer, sizeof(kMethodsDisplaySynchronizer) / sizeof(kMethodsDisplaySynchronizer[0]));
-  if (!check(env)) { return false; }
-  env->DeleteLocalRef(displaySynchronizerClazz);
-  if (!check(env)) { return false; }
-
-  return true;
-}
-
--- a/gfx/vr/moz.build
+++ b/gfx/vr/moz.build
@@ -20,27 +20,31 @@ EXPORTS += [
 LOCAL_INCLUDES += [
     '/dom/base',
     '/gfx/layers/d3d11',
     '/gfx/thebes',
 ]
 
 UNIFIED_SOURCES += [
     'gfxVR.cpp',
-    'gfxVROSVR.cpp',
     'ipc/VRLayerChild.cpp',
     'ipc/VRLayerParent.cpp',
     'ipc/VRManagerChild.cpp',
     'ipc/VRManagerParent.cpp',
     'VRDisplayClient.cpp',
     'VRDisplayPresentation.cpp',
     'VRManager.cpp',
     'VRThread.cpp',
 ]
 
+if CONFIG['OS_TARGET'] != 'Android':
+    UNIFIED_SOURCES += [
+        'gfxVROSVR.cpp',
+    ]
+
 # VRDisplayHost includes MacIOSurface.h which includes Mac headers
 # which define Size and Points types in the root namespace that
 # often conflict with our own types.
 SOURCES += [
     'gfxVRExternal.cpp',
     'gfxVRPuppet.cpp',
     'VRDisplayHost.cpp',
 ]
@@ -54,22 +58,17 @@ if CONFIG['OS_TARGET'] in ('WINNT', 'Lin
         'gfxVROpenVR.cpp',
     ]
 
 if CONFIG['OS_TARGET'] == 'WINNT':
     SOURCES += [
         'gfxVROculus.cpp',
     ]
 
-if CONFIG['MOZ_ANDROID_GOOGLE_VR']:
-    SOURCES += [
-        'gfxVRGVR.cpp',
-        'jni/gfxGVRJNI.cpp',
-    ]
-    CXXFLAGS += ['-I%s' % CONFIG['MOZ_ANDROID_GOOGLE_VR_INCLUDE']]
+if CONFIG['OS_TARGET'] == 'Android':
     LOCAL_INCLUDES += ['/widget/android']
 
 IPDL_SOURCES = [
     'ipc/PVRLayer.ipdl',
     'ipc/PVRManager.ipdl',
 ]
 
 # For building with the real SDK instead of our local hack
--- a/image/DynamicImage.cpp
+++ b/image/DynamicImage.cpp
@@ -99,18 +99,18 @@ DynamicImage::HasError()
 {
   return !mDrawable;
 }
 
 void
 DynamicImage::SetHasError()
 { }
 
-ImageURL*
-DynamicImage::GetURI()
+nsIURI*
+DynamicImage::GetURI() const
 {
   return nullptr;
 }
 
 // Methods inherited from XPCOM interfaces.
 
 NS_IMPL_ISUPPORTS(DynamicImage, imgIContainer)
 
--- a/image/DynamicImage.h
+++ b/image/DynamicImage.h
@@ -58,17 +58,17 @@ public:
   virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) override;
 
   virtual void SetInnerWindowID(uint64_t aInnerWindowId) override;
   virtual uint64_t InnerWindowID() const override;
 
   virtual bool HasError() override;
   virtual void SetHasError() override;
 
-  virtual ImageURL* GetURI() override;
+  nsIURI* GetURI() const override;
 
 private:
   virtual ~DynamicImage() { }
 
   RefPtr<gfxDrawable> mDrawable;
 };
 
 } // namespace image
--- a/image/Image.cpp
+++ b/image/Image.cpp
@@ -21,17 +21,17 @@ namespace image {
 ImageMemoryCounter::ImageMemoryCounter(Image* aImage,
                                        SizeOfState& aState,
                                        bool aIsUsed)
   : mIsUsed(aIsUsed)
 {
   MOZ_ASSERT(aImage);
 
   // Extract metadata about the image.
-  RefPtr<ImageURL> imageURL(aImage->GetURI());
+  nsCOMPtr<nsIURI> imageURL(aImage->GetURI());
   if (imageURL) {
     imageURL->GetSpec(mURI);
   }
 
   int32_t width = 0;
   int32_t height = 0;
   aImage->GetWidth(&width);
   aImage->GetHeight(&height);
@@ -49,16 +49,30 @@ ImageMemoryCounter::ImageMemoryCounter(I
   }
 }
 
 
 ///////////////////////////////////////////////////////////////////////////////
 // Image Base Types
 ///////////////////////////////////////////////////////////////////////////////
 
+bool
+ImageResource::GetSpecTruncatedTo1k(nsCString& aSpec) const
+{
+  static const size_t sMaxTruncatedLength = 1024;
+
+  mURI->GetSpec(aSpec);
+  if (sMaxTruncatedLength >= aSpec.Length()) {
+    return true;
+  }
+
+  aSpec.Truncate(sMaxTruncatedLength);
+  return false;
+}
+
 void
 ImageResource::SetCurrentImage(ImageContainer* aContainer,
                                SourceSurface* aSurface,
                                bool aInTransaction)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aContainer);
 
@@ -264,17 +278,17 @@ ImageResource::UpdateImageContainer()
 void
 ImageResource::ReleaseImageContainer()
 {
   MOZ_ASSERT(NS_IsMainThread());
   mImageContainers.Clear();
 }
 
 // Constructor
-ImageResource::ImageResource(ImageURL* aURI) :
+ImageResource::ImageResource(nsIURI* aURI) :
   mURI(aURI),
   mInnerWindowId(0),
   mAnimationConsumers(0),
   mAnimationMode(kNormalAnimMode),
   mInitialized(false),
   mAnimating(false),
   mError(false),
   mImageProducerID(ImageContainer::AllocateProducerID()),
@@ -399,17 +413,17 @@ ImageResource::NotifyDrawingObservers()
 
   bool match = false;
   if ((NS_FAILED(mURI->SchemeIs("resource", &match)) || !match) &&
       (NS_FAILED(mURI->SchemeIs("chrome", &match)) || !match)) {
     return;
   }
 
   // Record the image drawing for startup performance testing.
-  nsCOMPtr<nsIURI> uri = mURI->ToIURI();
+  nsCOMPtr<nsIURI> uri = mURI;
   nsContentUtils::AddScriptRunner(NS_NewRunnableFunction(
     "image::ImageResource::NotifyDrawingObservers", [uri]() {
       nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
       NS_WARNING_ASSERTION(obs, "Can't get an observer service handle");
       if (obs) {
         nsAutoCString spec;
         uri->GetSpec(spec);
         obs->NotifyObservers(nullptr, "image-drawing", NS_ConvertUTF8toUTF16(spec).get());
--- a/image/Image.h
+++ b/image/Image.h
@@ -6,17 +6,16 @@
 #ifndef mozilla_image_Image_h
 #define mozilla_image_Image_h
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Tuple.h"
 #include "mozilla/TimeStamp.h"
 #include "gfx2DGlue.h"
 #include "imgIContainer.h"
-#include "ImageURL.h"
 #include "ImageContainer.h"
 #include "LookupResult.h"
 #include "nsStringFwd.h"
 #include "ProgressTracker.h"
 #include "SurfaceCache.h"
 
 class nsIRequest;
 class nsIInputStream;
@@ -228,17 +227,17 @@ public:
   virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) = 0;
 
   virtual void SetInnerWindowID(uint64_t aInnerWindowId) = 0;
   virtual uint64_t InnerWindowID() const = 0;
 
   virtual bool HasError() = 0;
   virtual void SetHasError() = 0;
 
-  virtual ImageURL* GetURI() = 0;
+  virtual nsIURI* GetURI() const = 0;
 
   virtual void ReportUseCounters() { }
 };
 
 class ImageResource : public Image
 {
 public:
   already_AddRefed<ProgressTracker> GetProgressTracker() override
@@ -274,22 +273,24 @@ public:
 
   virtual bool HasError() override    { return mError; }
   virtual void SetHasError() override { mError = true; }
 
   /*
    * Returns a non-AddRefed pointer to the URI associated with this image.
    * Illegal to use off-main-thread.
    */
-  virtual ImageURL* GetURI() override { return mURI.get(); }
+  nsIURI* GetURI() const override { return mURI; }
 
 protected:
-  explicit ImageResource(ImageURL* aURI);
+  explicit ImageResource(nsIURI* aURI);
   ~ImageResource();
 
+  bool GetSpecTruncatedTo1k(nsCString& aSpec) const;
+
   // Shared functionality for implementors of imgIContainer. Every
   // implementation of attribute animationMode should forward here.
   nsresult GetAnimationModeInternal(uint16_t* aAnimationMode);
   nsresult SetAnimationModeInternal(uint16_t aAnimationMode);
 
   /**
    * Helper for RequestRefresh.
    *
@@ -321,18 +322,18 @@ protected:
   void SendOnUnlockedDraw(uint32_t aFlags);
 
 #ifdef DEBUG
   // Records the image drawing for startup performance testing.
   void NotifyDrawingObservers();
 #endif
 
   // Member data shared by all implementations of this abstract class
-  RefPtr<ProgressTracker>     mProgressTracker;
-  RefPtr<ImageURL>            mURI;
+  RefPtr<ProgressTracker>       mProgressTracker;
+  nsCOMPtr<nsIURI>              mURI;
   TimeStamp                     mLastRefreshTime;
   uint64_t                      mInnerWindowId;
   uint32_t                      mAnimationConsumers;
   uint16_t                      mAnimationMode; // Enum values in imgIContainer
   bool                          mInitialized:1; // Have we been initalized?
   bool                          mAnimating:1;   // Are we currently animating?
   bool                          mError:1;       // Error handling
 
--- a/image/ImageCacheKey.cpp
+++ b/image/ImageCacheKey.cpp
@@ -1,43 +1,33 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ImageCacheKey.h"
 
+#include "mozilla/HashFunctions.h"
 #include "mozilla/Move.h"
-#include "ImageURL.h"
 #include "nsLayoutUtils.h"
 #include "nsString.h"
 #include "mozilla/dom/BlobURLProtocolHandler.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ServiceWorkerManager.h"
 #include "nsIDocument.h"
 #include "nsPrintfCString.h"
 
 namespace mozilla {
 
 using namespace dom;
 
 namespace image {
 
-bool
-URISchemeIs(ImageURL* aURI, const char* aScheme)
-{
-  bool schemeMatches = false;
-  if (NS_WARN_IF(NS_FAILED(aURI->SchemeIs(aScheme, &schemeMatches)))) {
-    return false;
-  }
-  return schemeMatches;
-}
-
 static Maybe<uint64_t>
-BlobSerial(ImageURL* aURI)
+BlobSerial(nsIURI* aURI)
 {
   nsAutoCString spec;
   aURI->GetSpec(spec);
 
   RefPtr<BlobImpl> blob;
   if (NS_SUCCEEDED(NS_GetBlobForBlobURISpec(spec, getter_AddRefs(blob))) &&
       blob) {
     return Some(blob->GetSerialNumber());
@@ -45,61 +35,63 @@ BlobSerial(ImageURL* aURI)
 
   return Nothing();
 }
 
 ImageCacheKey::ImageCacheKey(nsIURI* aURI,
                              const OriginAttributes& aAttrs,
                              nsIDocument* aDocument,
                              nsresult& aRv)
-  : mURI(new ImageURL(aURI, aRv))
-  , mOriginAttributes(aAttrs)
-  , mControlledDocument(GetControlledDocumentToken(aDocument))
-  , mIsChrome(URISchemeIs(mURI, "chrome"))
-{
-  NS_ENSURE_SUCCESS_VOID(aRv);
-
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (URISchemeIs(mURI, "blob")) {
-    mBlobSerial = BlobSerial(mURI);
-  }
-
-  mHash = ComputeHash(mURI, mBlobSerial, mOriginAttributes, mControlledDocument);
-}
-
-ImageCacheKey::ImageCacheKey(ImageURL* aURI,
-                             const OriginAttributes& aAttrs,
-                             nsIDocument* aDocument)
   : mURI(aURI)
   , mOriginAttributes(aAttrs)
   , mControlledDocument(GetControlledDocumentToken(aDocument))
-  , mIsChrome(URISchemeIs(mURI, "chrome"))
+  , mHash(0)
+  , mIsChrome(false)
 {
-  MOZ_ASSERT(aURI);
-
-  if (URISchemeIs(mURI, "blob")) {
+  if (SchemeIs("blob")) {
     mBlobSerial = BlobSerial(mURI);
+  } else if (SchemeIs("chrome")) {
+    mIsChrome = true;
   }
 
-  mHash = ComputeHash(mURI, mBlobSerial, mOriginAttributes, mControlledDocument);
+  // Since we frequently call Hash() several times in a row on the same
+  // ImageCacheKey, as an optimization we compute our hash once and store it.
+
+  nsPrintfCString ptr("%p", mControlledDocument);
+  nsAutoCString suffix;
+  mOriginAttributes.CreateSuffix(suffix);
+
+  if (mBlobSerial) {
+    aRv = mURI->GetRef(mBlobRef);
+    NS_ENSURE_SUCCESS_VOID(aRv);
+    mHash = HashGeneric(*mBlobSerial, HashString(mBlobRef));
+  } else {
+    nsAutoCString spec;
+    aRv = mURI->GetSpec(spec);
+    NS_ENSURE_SUCCESS_VOID(aRv);
+    mHash = HashString(spec);
+  }
+
+  mHash = AddToHash(mHash, HashString(suffix), HashString(ptr));
 }
 
 ImageCacheKey::ImageCacheKey(const ImageCacheKey& aOther)
   : mURI(aOther.mURI)
   , mBlobSerial(aOther.mBlobSerial)
+  , mBlobRef(aOther.mBlobRef)
   , mOriginAttributes(aOther.mOriginAttributes)
   , mControlledDocument(aOther.mControlledDocument)
   , mHash(aOther.mHash)
   , mIsChrome(aOther.mIsChrome)
 { }
 
 ImageCacheKey::ImageCacheKey(ImageCacheKey&& aOther)
   : mURI(std::move(aOther.mURI))
   , mBlobSerial(std::move(aOther.mBlobSerial))
+  , mBlobRef(std::move(aOther.mBlobRef))
   , mOriginAttributes(aOther.mOriginAttributes)
   , mControlledDocument(aOther.mControlledDocument)
   , mHash(aOther.mHash)
   , mIsChrome(aOther.mIsChrome)
 { }
 
 bool
 ImageCacheKey::operator==(const ImageCacheKey& aOther) const
@@ -111,44 +103,30 @@ ImageCacheKey::operator==(const ImageCac
   // The origin attributes always have to match.
   if (mOriginAttributes != aOther.mOriginAttributes) {
     return false;
   }
   if (mBlobSerial || aOther.mBlobSerial) {
     // If at least one of us has a blob serial, just compare the blob serial and
     // the ref portion of the URIs.
     return mBlobSerial == aOther.mBlobSerial &&
-           mURI->HasSameRef(*aOther.mURI);
+           mBlobRef == aOther.mBlobRef;
   }
 
   // For non-blob URIs, compare the URIs.
-  return *mURI == *aOther.mURI;
-}
-
-const char*
-ImageCacheKey::Spec() const
-{
-  return mURI->Spec();
+  bool equals = false;
+  nsresult rv = mURI->Equals(aOther.mURI, &equals);
+  return NS_SUCCEEDED(rv) && equals;
 }
 
-/* static */ PLDHashNumber
-ImageCacheKey::ComputeHash(ImageURL* aURI,
-                           const Maybe<uint64_t>& aBlobSerial,
-                           const OriginAttributes& aAttrs,
-                           void* aControlledDocument)
+bool
+ImageCacheKey::SchemeIs(const char* aScheme)
 {
-  // Since we frequently call Hash() several times in a row on the same
-  // ImageCacheKey, as an optimization we compute our hash once and store it.
-
-  nsPrintfCString ptr("%p", aControlledDocument);
-  nsAutoCString suffix;
-  aAttrs.CreateSuffix(suffix);
-
-  return AddToHash(0, aURI->ComputeHash(aBlobSerial),
-                   HashString(suffix), HashString(ptr));
+  bool matches = false;
+  return NS_SUCCEEDED(mURI->SchemeIs(aScheme, &matches)) && matches;
 }
 
 /* static */ void*
 ImageCacheKey::GetControlledDocumentToken(nsIDocument* aDocument)
 {
   // For non-controlled documents, we just return null.  For controlled
   // documents, we cast the pointer into a void* to avoid dereferencing
   // it (since we only use it for comparisons), and return it.
--- a/image/ImageCacheKey.h
+++ b/image/ImageCacheKey.h
@@ -16,59 +16,53 @@
 #include "PLDHashTable.h"
 
 class nsIDocument;
 class nsIURI;
 
 namespace mozilla {
 namespace image {
 
-class ImageURL;
-
 /**
  * An ImageLib cache entry key.
  *
  * We key the cache on the initial URI (before any redirects), with some
  * canonicalization applied. See ComputeHash() for the details.
  * Controlled documents do not share their cache entries with
  * non-controlled documents, or other controlled documents.
  */
 class ImageCacheKey final
 {
 public:
   ImageCacheKey(nsIURI* aURI, const OriginAttributes& aAttrs,
                 nsIDocument* aDocument, nsresult& aRv);
-  ImageCacheKey(ImageURL* aURI, const OriginAttributes& aAttrs,
-                nsIDocument* aDocument);
 
   ImageCacheKey(const ImageCacheKey& aOther);
   ImageCacheKey(ImageCacheKey&& aOther);
 
   bool operator==(const ImageCacheKey& aOther) const;
   PLDHashNumber Hash() const { return mHash; }
 
-  /// A weak pointer to the URI spec for this cache entry. For logging only.
-  const char* Spec() const;
+  /// A weak pointer to the URI. For logging only.
+  nsIURI* URI() const { return mURI; }
 
   /// Is this cache entry for a chrome image?
   bool IsChrome() const { return mIsChrome; }
 
   /// A token indicating which service worker controlled document this entry
   /// belongs to, if any.
   void* ControlledDocument() const { return mControlledDocument; }
 
 private:
-  static PLDHashNumber ComputeHash(ImageURL* aURI,
-                                   const Maybe<uint64_t>& aBlobSerial,
-                                   const OriginAttributes& aAttrs,
-                                   void* aControlledDocument);
+  bool SchemeIs(const char* aScheme);
   static void* GetControlledDocumentToken(nsIDocument* aDocument);
 
-  RefPtr<ImageURL> mURI;
+  nsCOMPtr<nsIURI> mURI;
   Maybe<uint64_t> mBlobSerial;
+  nsCString mBlobRef;
   OriginAttributes mOriginAttributes;
   void* mControlledDocument;
   PLDHashNumber mHash;
   bool mIsChrome;
 };
 
 } // namespace image
 } // namespace mozilla
--- a/image/ImageFactory.cpp
+++ b/image/ImageFactory.cpp
@@ -29,17 +29,17 @@
 namespace mozilla {
 namespace image {
 
 /*static*/ void
 ImageFactory::Initialize()
 { }
 
 static uint32_t
-ComputeImageFlags(ImageURL* uri, const nsCString& aMimeType, bool isMultiPart)
+ComputeImageFlags(nsIURI* uri, const nsCString& aMimeType, bool isMultiPart)
 {
   nsresult rv;
 
   // We default to the static globals.
   bool isDiscardable = gfxPrefs::ImageMemDiscardable();
   bool doDecodeImmediately = gfxPrefs::ImageDecodeImmediatelyEnabled();
 
   // We want UI to be as snappy as possible and not to flicker. Disable
@@ -83,20 +83,20 @@ ComputeImageFlags(ImageURL* uri, const n
     imageFlags |= Image::INIT_FLAG_SYNC_LOAD;
   }
 
   return imageFlags;
 }
 
 #ifdef DEBUG
 static void
-NotifyImageLoading(ImageURL* aURI)
+NotifyImageLoading(nsIURI* aURI)
 {
   if (!NS_IsMainThread()) {
-    RefPtr<ImageURL> uri(aURI);
+    nsCOMPtr<nsIURI> uri(aURI);
     nsCOMPtr<nsIRunnable> ev =
       NS_NewRunnableFunction("NotifyImageLoading", [uri] () -> void {
         NotifyImageLoading(uri);
     });
     SystemGroup::Dispatch(TaskCategory::Other, ev.forget());
     return;
   }
 
@@ -109,17 +109,17 @@ NotifyImageLoading(ImageURL* aURI)
   }
 }
 #endif
 
 /* static */ already_AddRefed<Image>
 ImageFactory::CreateImage(nsIRequest* aRequest,
                           ProgressTracker* aProgressTracker,
                           const nsCString& aMimeType,
-                          ImageURL* aURI,
+                          nsIURI* aURI,
                           bool aIsMultiPart,
                           uint32_t aInnerWindowId)
 {
   MOZ_ASSERT(gfxPrefs::SingletonExists(),
              "Pref observers should have been initialized already");
 
   // Compute the image's initialization flags.
   uint32_t imageFlags = ComputeImageFlags(aURI, aMimeType, aIsMultiPart);
@@ -235,17 +235,17 @@ GetContentSize(nsIRequest* aRequest)
   // Fallback - neither http nor file. We'll use dynamic allocation.
   return 0;
 }
 
 /* static */ already_AddRefed<Image>
 ImageFactory::CreateRasterImage(nsIRequest* aRequest,
                                 ProgressTracker* aProgressTracker,
                                 const nsCString& aMimeType,
-                                ImageURL* aURI,
+                                nsIURI* aURI,
                                 uint32_t aImageFlags,
                                 uint32_t aInnerWindowId)
 {
   MOZ_ASSERT(aProgressTracker);
 
   nsresult rv;
 
   RefPtr<RasterImage> newImage = new RasterImage(aURI);
@@ -266,17 +266,17 @@ ImageFactory::CreateRasterImage(nsIReque
 
   return newImage.forget();
 }
 
 /* static */ already_AddRefed<Image>
 ImageFactory::CreateVectorImage(nsIRequest* aRequest,
                                 ProgressTracker* aProgressTracker,
                                 const nsCString& aMimeType,
-                                ImageURL* aURI,
+                                nsIURI* aURI,
                                 uint32_t aImageFlags,
                                 uint32_t aInnerWindowId)
 {
   MOZ_ASSERT(aProgressTracker);
 
   nsresult rv;
 
   RefPtr<VectorImage> newImage = new VectorImage(aURI);
--- a/image/ImageFactory.h
+++ b/image/ImageFactory.h
@@ -7,22 +7,22 @@
 #ifndef mozilla_image_ImageFactory_h
 #define mozilla_image_ImageFactory_h
 
 #include "nsCOMPtr.h"
 #include "nsProxyRelease.h"
 #include "nsStringFwd.h"
 
 class nsIRequest;
+class nsIURI;
 
 namespace mozilla {
 namespace image {
 
 class Image;
-class ImageURL;
 class MultipartImage;
 class ProgressTracker;
 
 class ImageFactory
 {
 public:
   /**
    * Registers vars with Preferences. Should only be called on the main thread.
@@ -38,17 +38,17 @@ public:
    * @param aMimeType        The mimetype of the image.
    * @param aURI             The URI of the image.
    * @param aIsMultiPart     Whether the image is part of a multipart request.
    * @param aInnerWindowId   The window this image belongs to.
    */
   static already_AddRefed<Image> CreateImage(nsIRequest* aRequest,
                                              ProgressTracker* aProgressTracker,
                                              const nsCString& aMimeType,
-                                             ImageURL* aURI,
+                                             nsIURI* aURI,
                                              bool aIsMultiPart,
                                              uint32_t aInnerWindowId);
   /**
    * Creates a new image which isn't associated with a URI or loaded through
    * the usual image loading mechanism.
    *
    * @param aMimeType      The mimetype of the image.
    * @param aSizeHint      The length of the source data for the image.
@@ -69,25 +69,25 @@ public:
   CreateMultipartImage(Image* aFirstPart, ProgressTracker* aProgressTracker);
 
 private:
   // Factory functions that create specific types of image containers.
   static already_AddRefed<Image>
   CreateRasterImage(nsIRequest* aRequest,
                     ProgressTracker* aProgressTracker,
                     const nsCString& aMimeType,
-                    ImageURL* aURI,
+                    nsIURI* aURI,
                     uint32_t aImageFlags,
                     uint32_t aInnerWindowId);
 
   static already_AddRefed<Image>
   CreateVectorImage(nsIRequest* aRequest,
                     ProgressTracker* aProgressTracker,
                     const nsCString& aMimeType,
-                    ImageURL* aURI,
+                    nsIURI* aURI,
                     uint32_t aImageFlags,
                     uint32_t aInnerWindowId);
 
   // This is a static factory class, so disallow instantiation.
   virtual ~ImageFactory() = 0;
 };
 
 } // namespace image
--- a/image/ImageLogging.h
+++ b/image/ImageLogging.h
@@ -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/. */
 
 #ifndef mozilla_image_ImageLogging_h
 #define mozilla_image_ImageLogging_h
 
 #include "mozilla/Logging.h"
+#include "Image.h"
+#include "nsIURI.h"
 #include "prinrval.h"
 
 static mozilla::LazyLogModule gImgLog("imgRequest");
 
 #define GIVE_ME_MS_NOW() PR_IntervalToMilliseconds(PR_IntervalNow())
 
 using mozilla::LogLevel;
 
@@ -71,16 +73,45 @@ public:
     , mFrom(from)
     , mFunc(fn)
   {
     MOZ_LOG(mLog, LogLevel::Debug, ("%d [this=%p] %s (%s=\"%d\") {ENTER}\n",
                                 GIVE_ME_MS_NOW(), mFrom, mFunc,
                                 paramName, paramValue));
   }
 
+  /* nsIURI constructor */
+  LogScope(mozilla::LogModule* aLog, void* from, const char* fn,
+           const char* paramName, nsIURI* aURI)
+    : mLog(aLog)
+    , mFrom(from)
+    , mFunc(fn)
+  {
+    if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
+      static const size_t sMaxTruncatedLength = 1024;
+      nsAutoCString spec("<unknown>");
+      if (aURI) {
+        aURI->GetSpec(spec);
+        if (spec.Length() >= sMaxTruncatedLength) {
+          spec.Truncate(sMaxTruncatedLength);
+        }
+      }
+      MOZ_LOG(aLog, LogLevel::Debug, ("%d [this=%p] %s (%s=\"%s\") {ENTER}\n",
+                                  GIVE_ME_MS_NOW(), from, fn,
+                                  paramName, spec.get()));
+    }
+  }
+
+  /* Image constructor */
+  LogScope(mozilla::LogModule* aLog, void* from, const char* fn,
+           const char* paramName, mozilla::image::Image* aImage)
+    : LogScope(aLog, from, fn, paramName, aImage ? aImage->GetURI() : nullptr)
+  {
+  }
+
   ~LogScope()
   {
     MOZ_LOG(mLog, LogLevel::Debug, ("%d [this=%p] %s {EXIT}\n",
                                 GIVE_ME_MS_NOW(), mFrom, mFunc));
   }
 
 private:
   mozilla::LogModule* mLog;
@@ -116,16 +147,40 @@ public:
   LogFunc(mozilla::LogModule* aLog, void* from, const char* fn,
           const char* paramName, uint32_t paramValue)
   {
     MOZ_LOG(aLog, LogLevel::Debug, ("%d [this=%p] %s (%s=\"%d\")\n",
                                 GIVE_ME_MS_NOW(), from, fn,
                                 paramName, paramValue));
   }
 
+  LogFunc(mozilla::LogModule* aLog, void* from, const char* fn,
+          const char* paramName, nsIURI* aURI)
+  {
+    if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
+      static const size_t sMaxTruncatedLength = 1024;
+      nsAutoCString spec("<unknown>");
+      if (aURI) {
+        aURI->GetSpec(spec);
+        if (spec.Length() >= sMaxTruncatedLength) {
+          spec.Truncate(sMaxTruncatedLength);
+        }
+      }
+      MOZ_LOG(aLog, LogLevel::Debug, ("%d [this=%p] %s (%s=\"%s\")\n",
+                                  GIVE_ME_MS_NOW(), from, fn,
+                                  paramName, spec.get()));
+    }
+  }
+
+  LogFunc(mozilla::LogModule* aLog, void* from, const char* fn,
+          const char* paramName, mozilla::image::Image* aImage)
+    : LogFunc(aLog, from, fn, paramName, aImage ? aImage->GetURI() : nullptr)
+  {
+  }
+
 };
 
 
 class LogMessage {
 public:
   LogMessage(mozilla::LogModule* aLog, void* from, const char* fn,
              const char* msg)
   {
--- a/image/ImageOps.cpp
+++ b/image/ImageOps.cpp
@@ -11,16 +11,17 @@
 #include "DecoderFactory.h"
 #include "DynamicImage.h"
 #include "FrozenImage.h"
 #include "IDecodingTask.h"
 #include "Image.h"
 #include "ImageMetadata.h"
 #include "imgIContainer.h"
 #include "mozilla/gfx/2D.h"
+#include "nsNetUtil.h" // for NS_NewBufferedInputStream
 #include "nsStreamUtils.h"
 #include "OrientedImage.h"
 #include "SourceBuffer.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace image {
deleted file mode 100644
--- a/image/ImageURL.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_image_ImageURL_h
-#define mozilla_image_ImageURL_h
-
-#include "nsIURI.h"
-#include "MainThreadUtils.h"
-#include "nsNetUtil.h"
-#include "mozilla/HashFunctions.h"
-#include "nsHashKeys.h"
-#include "nsProxyRelease.h"
-
-namespace mozilla {
-namespace image {
-
-class ImageCacheKey;
-
-/** ImageURL
- *
- * nsStandardURL is not threadsafe, so this class is created to hold only the
- * necessary URL data required for image loading and decoding.
- *
- * Note: Although several APIs have the same or similar prototypes as those
- * found in nsIURI/nsStandardURL, the class does not implement nsIURI. This is
- * intentional; functionality is limited, and is only useful for imagelib code.
- * By not implementing nsIURI, external code cannot unintentionally be given an
- * nsIURI pointer with this limited class behind it; instead, conversion to a
- * fully implemented nsIURI is required (e.g. through NS_NewURI).
- */
-class ImageURL
-{
-public:
-  explicit ImageURL(nsIURI* aURI, nsresult& aRv)
-    : mURI(new nsMainThreadPtrHolder<nsIURI>("ImageURL::mURI", aURI))
-  {
-    MOZ_ASSERT(NS_IsMainThread(), "Cannot use nsIURI off main thread!");
-
-    aRv = aURI->GetSpec(mSpec);
-    NS_ENSURE_SUCCESS_VOID(aRv);
-
-    aRv = aURI->GetScheme(mScheme);
-    NS_ENSURE_SUCCESS_VOID(aRv);
-
-    aRv = aURI->GetRef(mRef);
-    NS_ENSURE_SUCCESS_VOID(aRv);
-  }
-
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageURL)
-
-  nsresult GetSpec(nsACString& result)
-  {
-    result = mSpec;
-    return NS_OK;
-  }
-
-  /// A weak pointer to the URI spec for this ImageURL. For logging only.
-  const char* Spec() const { return mSpec.get(); }
-
-  enum TruncatedSpecStatus {
-    FitsInto1k,
-    TruncatedTo1k
-  };
-  TruncatedSpecStatus GetSpecTruncatedTo1k(nsACString& result)
-  {
-    static const size_t sMaxTruncatedLength = 1024;
-
-    if (sMaxTruncatedLength >= mSpec.Length()) {
-      result = mSpec;
-      return FitsInto1k;
-    }
-
-    result = Substring(mSpec, 0, sMaxTruncatedLength);
-    return TruncatedTo1k;
-  }
-
-  nsresult GetScheme(nsACString& result)
-  {
-    result = mScheme;
-    return NS_OK;
-  }
-
-  nsresult SchemeIs(const char* scheme, bool* result)
-  {
-    MOZ_ASSERT(scheme, "scheme is null");
-    MOZ_ASSERT(result, "result is null");
-
-    *result = mScheme.Equals(scheme);
-    return NS_OK;
-  }
-
-  nsresult GetRef(nsACString& result)
-  {
-    result = mRef;
-    return NS_OK;
-  }
-
-  already_AddRefed<nsIURI> ToIURI()
-  {
-    nsCOMPtr<nsIURI> newURI = mURI.get();
-    return newURI.forget();
-  }
-
-  bool operator==(const ImageURL& aOther) const
-  {
-    // Note that we don't need to consider mScheme and mRef, because they're
-    // already represented in mSpec.
-    return mSpec == aOther.mSpec;
-  }
-
-  bool HasSameRef(const ImageURL& aOther) const
-  {
-    return mRef == aOther.mRef;
-  }
-
-private:
-  friend class ImageCacheKey;
-
-  PLDHashNumber ComputeHash(const Maybe<uint64_t>& aBlobSerial) const
-  {
-    if (aBlobSerial) {
-      // For blob URIs, we hash the serial number of the underlying blob, so that
-      // different blob URIs which point to the same blob share a cache entry. We
-      // also include the ref portion of the URI to support media fragments which
-      // requires us to create different Image objects even if the source data is
-      // the same.
-      return HashGeneric(*aBlobSerial, HashString(mRef));
-    }
-    // For non-blob URIs, we hash the URI spec.
-    return HashString(mSpec);
-  }
-
-  nsMainThreadPtrHandle<nsIURI> mURI;
-
-  // Since this is a basic storage class, no duplication of spec parsing is
-  // included in the functionality. Instead, the class depends upon the
-  // parsing implementation in the nsIURI class used in object construction.
-  // This means each field is stored separately, but since only a few are
-  // required, this small memory tradeoff for threadsafe usage should be ok.
-  nsAutoCString mSpec;
-  nsAutoCString mScheme;
-  nsAutoCString mRef;
-
-  ~ImageURL() { }
-};
-
-} // namespace image
-} // namespace mozilla
-
-#endif // mozilla_image_ImageURL_h
--- a/image/ImageWrapper.cpp
+++ b/image/ImageWrapper.cpp
@@ -112,18 +112,18 @@ ImageWrapper::HasError()
 }
 
 void
 ImageWrapper::SetHasError()
 {
   mInnerImage->SetHasError();
 }
 
-ImageURL*
-ImageWrapper::GetURI()
+nsIURI*
+ImageWrapper::GetURI() const
 {
   return mInnerImage->GetURI();
 }
 
 // Methods inherited from XPCOM interfaces.
 
 NS_IMPL_ISUPPORTS(ImageWrapper, imgIContainer)
 
--- a/image/ImageWrapper.h
+++ b/image/ImageWrapper.h
@@ -50,17 +50,17 @@ public:
   virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) override;
 
   virtual void SetInnerWindowID(uint64_t aInnerWindowId) override;
   virtual uint64_t InnerWindowID() const override;
 
   virtual bool HasError() override;
   virtual void SetHasError() override;
 
-  virtual ImageURL* GetURI() override;
+  nsIURI* GetURI() const override;
 
 protected:
   explicit ImageWrapper(Image* aInnerImage)
     : mInnerImage(aInnerImage)
   {
     MOZ_ASSERT(aInnerImage, "Need an image to wrap");
   }
 
--- a/image/ProgressTracker.cpp
+++ b/image/ProgressTracker.cpp
@@ -173,26 +173,18 @@ ProgressTracker::Notify(IProgressObserve
 
   if (aObserver->NotificationsDeferred()) {
     // There is a pending notification, or the observer isn't ready yet.
     return;
   }
 
   if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
     RefPtr<Image> image = GetImage();
-    if (image && image->GetURI()) {
-      RefPtr<ImageURL> uri(image->GetURI());
-      nsAutoCString spec;
-      uri->GetSpec(spec);
-      LOG_FUNC_WITH_PARAM(gImgLog,
-                          "ProgressTracker::Notify async", "uri", spec.get());
-    } else {
-      LOG_FUNC_WITH_PARAM(gImgLog,
-                          "ProgressTracker::Notify async", "uri", "<unknown>");
-    }
+    LOG_FUNC_WITH_PARAM(gImgLog,
+                        "ProgressTracker::Notify async", "uri", image);
   }
 
   aObserver->MarkPendingNotify();
 
   // If we have an existing runnable that we can use, we just append this
   // observer to its list of observers to be notified. This ensures we don't
   // unnecessarily delay onload.
   AsyncNotifyRunnable* runnable =
@@ -248,22 +240,18 @@ ProgressTracker::NotifyCurrentState(IPro
 
   if (aObserver->NotificationsDeferred()) {
     // There is a pending notification, or the observer isn't ready yet.
     return;
   }
 
   if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
     RefPtr<Image> image = GetImage();
-    nsAutoCString spec;
-    if (image && image->GetURI()) {
-      image->GetURI()->GetSpec(spec);
-    }
     LOG_FUNC_WITH_PARAM(gImgLog,
-                        "ProgressTracker::NotifyCurrentState", "uri", spec.get());
+                        "ProgressTracker::NotifyCurrentState", "uri", image);
   }
 
   aObserver->MarkPendingNotify();
 
   nsCOMPtr<nsIRunnable> ev = new AsyncNotifyCurrentStateRunnable(this,
                                                                  aObserver);
   mEventTarget->Dispatch(ev.forget(), NS_DISPATCH_NORMAL);
 }
@@ -396,23 +384,18 @@ ProgressTracker::SyncNotifyProgress(Prog
 }
 
 void
 ProgressTracker::SyncNotify(IProgressObserver* aObserver)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   RefPtr<Image> image = GetImage();
-
-  nsAutoCString spec;
-  if (image && image->GetURI()) {
-    image->GetURI()->GetSpec(spec);
-  }
   LOG_SCOPE_WITH_PARAM(gImgLog,
-                       "ProgressTracker::SyncNotify", "uri", spec.get());
+                       "ProgressTracker::SyncNotify", "uri", image);
 
   nsIntRect rect;
   if (image) {
     int32_t width, height;
     if (NS_FAILED(image->GetWidth(&width)) ||
         NS_FAILED(image->GetHeight(&height))) {
       // Either the image has no intrinsic size, or it has an error.
       rect = GetMaxSizedIntRect();
@@ -591,21 +574,17 @@ ProgressTracker::FireFailureNotification
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // Some kind of problem has happened with image decoding.
   // Report the URI to net:failed-to-process-uri-conent observers.
   RefPtr<Image> image = GetImage();
   if (image) {
     // Should be on main thread, so ok to create a new nsIURI.
-    nsCOMPtr<nsIURI> uri;
-    {
-      RefPtr<ImageURL> threadsafeUriData = image->GetURI();
-      uri = threadsafeUriData ? threadsafeUriData->ToIURI() : nullptr;
-    }
+    nsCOMPtr<nsIURI> uri = image->GetURI();
     if (uri) {
       nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
       if (os) {
         os->NotifyObservers(uri, "net:failed-to-process-uri-content", nullptr);
       }
     }
   }
 }
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -65,17 +65,17 @@ using std::min;
 #ifndef DEBUG
 NS_IMPL_ISUPPORTS(RasterImage, imgIContainer, nsIProperties)
 #else
 NS_IMPL_ISUPPORTS(RasterImage, imgIContainer, nsIProperties,
                   imgIContainerDebug)
 #endif
 
 //******************************************************************************
-RasterImage::RasterImage(ImageURL* aURI /* = nullptr */) :
+RasterImage::RasterImage(nsIURI* aURI /* = nullptr */) :
   ImageResource(aURI), // invoke superclass's constructor
   mSize(0,0),
   mLockCount(0),
   mDecodeCount(0),
 #ifdef DEBUG
   mFramesNotified(0),
 #endif
   mSourceBuffer(MakeNotNull<SourceBuffer*>()),
@@ -1812,18 +1812,18 @@ RasterImage::ReportDecoderError()
     do_GetService(NS_CONSOLESERVICE_CONTRACTID);
   nsCOMPtr<nsIScriptError> errorObject =
     do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
 
   if (consoleService && errorObject) {
     nsAutoString msg(NS_LITERAL_STRING("Image corrupt or truncated."));
     nsAutoString src;
     if (GetURI()) {
-      nsCString uri;
-      if (GetURI()->GetSpecTruncatedTo1k(uri) == ImageURL::TruncatedTo1k) {
+      nsAutoCString uri;
+      if (!GetSpecTruncatedTo1k(uri)) {
         msg += NS_LITERAL_STRING(" URI in this note truncated due to length.");
       }
       src = NS_ConvertUTF8toUTF16(uri);
     }
     if (NS_SUCCEEDED(errorObject->InitWithWindowID(
                        msg,
                        src,
                        EmptyString(), 0, 0, nsIScriptError::errorFlag,
--- a/image/RasterImage.h
+++ b/image/RasterImage.h
@@ -464,17 +464,17 @@ private: // data
   // Helpers
   bool CanDiscard();
 
   bool IsOpaque();
 
   DrawableSurface RequestDecodeForSizeInternal(const gfx::IntSize& aSize, uint32_t aFlags);
 
 protected:
-  explicit RasterImage(ImageURL* aURI = nullptr);
+  explicit RasterImage(nsIURI* aURI = nullptr);
 
   bool ShouldAnimate() override;
 
   friend class ImageFactory;
 };
 
 inline NS_IMETHODIMP
 RasterImage::GetAnimationMode(uint16_t* aAnimationMode) {
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -366,17 +366,17 @@ private:
 NS_IMPL_ISUPPORTS(VectorImage,
                   imgIContainer,
                   nsIStreamListener,
                   nsIRequestObserver)
 
 //------------------------------------------------------------------------------
 // Constructor / Destructor
 
-VectorImage::VectorImage(ImageURL* aURI /* = nullptr */) :
+VectorImage::VectorImage(nsIURI* aURI /* = nullptr */) :
   ImageResource(aURI), // invoke superclass's constructor
   mLockCount(0),
   mIsInitialized(false),
   mIsFullyLoaded(false),
   mIsDrawing(false),
   mHaveAnimations(false),
   mHasPendingInvalidation(false)
 { }
@@ -917,18 +917,17 @@ VectorImage::MaybeRestrictSVGContext(May
                                      const Maybe<SVGImageContext>& aSVGContext,
                                      uint32_t aFlags)
 {
   bool overridePAR = (aFlags & FLAG_FORCE_PRESERVEASPECTRATIO_NONE) && aSVGContext;
 
   bool haveContextPaint = aSVGContext && aSVGContext->GetContextPaint();
   bool blockContextPaint = false;
   if (haveContextPaint) {
-    nsCOMPtr<nsIURI> imageURI = mURI->ToIURI();
-    blockContextPaint = !SVGContextPaint::IsAllowedForImageFromURI(imageURI);
+    blockContextPaint = !SVGContextPaint::IsAllowedForImageFromURI(mURI);
   }
 
   if (overridePAR || blockContextPaint) {
     // The key that we create for the image surface cache must match the way
     // that the image will be painted, so we need to initialize a new matching
     // SVGImageContext here in order to generate the correct key.
 
     aNewSVGContext = aSVGContext; // copy
--- a/image/VectorImage.h
+++ b/image/VectorImage.h
@@ -68,17 +68,17 @@ public:
 
   // Callbacks for SVGLoadEventListener.
   void OnSVGDocumentLoaded();
   void OnSVGDocumentError();
 
   virtual void ReportUseCounters() override;
 
 protected:
-  explicit VectorImage(ImageURL* aURI = nullptr);
+  explicit VectorImage(nsIURI* aURI = nullptr);
   virtual ~VectorImage();
 
   virtual nsresult StartAnimation() override;
   virtual nsresult StopAnimation() override;
   virtual bool     ShouldAnimate() override;
 
 private:
   Tuple<ImgDrawResult, IntSize, RefPtr<SourceSurface>>
--- a/image/imgLoader.cpp
+++ b/image/imgLoader.cpp
@@ -989,20 +989,20 @@ void imgCacheEntry::UpdateLoadTime()
 }
 
 void
 imgCacheEntry::SetHasNoProxies(bool hasNoProxies)
 {
   if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
     if (hasNoProxies) {
       LOG_FUNC_WITH_PARAM(gImgLog, "imgCacheEntry::SetHasNoProxies true",
-                          "uri", mRequest->CacheKey().Spec());
+                          "uri", mRequest->CacheKey().URI());
     } else {
       LOG_FUNC_WITH_PARAM(gImgLog, "imgCacheEntry::SetHasNoProxies false",
-                          "uri", mRequest->CacheKey().Spec());
+                          "uri", mRequest->CacheKey().URI());
     }
   }
 
   mHasNoProxies = hasNoProxies;
 }
 
 imgCacheQueue::imgCacheQueue()
  : mDirty(false),
@@ -1167,17 +1167,17 @@ imgLoader::CreateNewProxyForRequest(imgR
 
   RefPtr<imgRequestProxy> proxyRequest = new imgRequestProxy();
 
   /* It is important to call |SetLoadFlags()| before calling |Init()| because
      |Init()| adds the request to the loadgroup.
    */
   proxyRequest->SetLoadFlags(aLoadFlags);
 
-  RefPtr<ImageURL> uri;
+  nsCOMPtr<nsIURI> uri;
   aRequest->GetURI(getter_AddRefs(uri));
 
   // init adds itself to imgRequest's list of observers
   nsresult rv = proxyRequest->Init(aRequest, aLoadGroup, aLoadingDocument,
                                    uri, aObserver);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -1210,17 +1210,17 @@ imgCacheExpirationTracker::NotifyExpired
   // mechanism doesn't.
   RefPtr<imgCacheEntry> kungFuDeathGrip(entry);
 
   if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
     RefPtr<imgRequest> req = entry->GetRequest();
     if (req) {
       LOG_FUNC_WITH_PARAM(gImgLog,
                          "imgCacheExpirationTracker::NotifyExpired",
-                         "entry", req->CacheKey().Spec());
+                         "entry", req->CacheKey().URI());
     }
   }
 
   // We can be called multiple times on the same entry. Don't do work multiple
   // times.
   if (!entry->Evicted()) {
     entry->Loader()->RemoveFromCache(entry);
   }
@@ -1575,17 +1575,17 @@ imgLoader::MinimizeCaches()
 }
 
 bool
 imgLoader::PutIntoCache(const ImageCacheKey& aKey, imgCacheEntry* entry)
 {
   imgCacheTable& cache = GetCache(aKey);
 
   LOG_STATIC_FUNC_WITH_PARAM(gImgLog,
-                             "imgLoader::PutIntoCache", "uri", aKey.Spec());
+                             "imgLoader::PutIntoCache", "uri", aKey.URI());
 
   // Check to see if this request already exists in the cache. If so, we'll
   // replace the old version.
   RefPtr<imgCacheEntry> tmpCacheEntry;
   if (cache.Get(aKey, getter_AddRefs(tmpCacheEntry)) && tmpCacheEntry) {
     MOZ_LOG(gImgLog, LogLevel::Debug,
            ("[this=%p] imgLoader::PutIntoCache -- Element already in the cache",
             nullptr));
@@ -1633,17 +1633,17 @@ imgLoader::PutIntoCache(const ImageCache
   return true;
 }
 
 bool
 imgLoader::SetHasNoProxies(imgRequest* aRequest, imgCacheEntry* aEntry)
 {
   LOG_STATIC_FUNC_WITH_PARAM(gImgLog,
                              "imgLoader::SetHasNoProxies", "uri",
-                             aRequest->CacheKey().Spec());
+                             aRequest->CacheKey().URI());
 
   aEntry->SetHasNoProxies(true);
 
   if (aEntry->Evicted()) {
     return false;
   }
 
   imgCacheQueue& queue = GetCacheQueue(aRequest->IsChrome());
@@ -1668,17 +1668,17 @@ bool
 imgLoader::SetHasProxies(imgRequest* aRequest)
 {
   VerifyCacheSizes();
 
   const ImageCacheKey& key = aRequest->CacheKey();
   imgCacheTable& cache = GetCache(key);
 
   LOG_STATIC_FUNC_WITH_PARAM(gImgLog,
-                             "imgLoader::SetHasProxies", "uri", key.Spec());
+                             "imgLoader::SetHasProxies", "uri", key.URI());
 
   RefPtr<imgCacheEntry> entry;
   if (cache.Get(key, getter_AddRefs(entry)) && entry) {
     // Make sure the cache entry is for the right request
     RefPtr<imgRequest> entryRequest = entry->GetRequest();
     if (entryRequest == aRequest && entry->HasNoProxies()) {
       imgCacheQueue& queue = GetCacheQueue(key);
       queue.Remove(entry);
@@ -1724,17 +1724,17 @@ imgLoader::CheckCacheLimits(imgCacheTabl
 
     NS_ASSERTION(entry, "imgLoader::CheckCacheLimits -- NULL entry pointer");
 
     if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
       RefPtr<imgRequest> req = entry->GetRequest();
       if (req) {
         LOG_STATIC_FUNC_WITH_PARAM(gImgLog,
                                    "imgLoader::CheckCacheLimits",
-                                   "entry", req->CacheKey().Spec());
+                                   "entry", req->CacheKey().URI());
       }
     }
 
     if (entry) {
       // We just popped this entry from the queue, so pass AlreadyRemoved
       // to avoid searching the queue again in RemoveFromCache.
       RemoveFromCache(entry, QueueState::AlreadyRemoved);
     }
@@ -1999,17 +1999,17 @@ imgLoader::ValidateEntry(imgCacheEntry* 
 
   return !validateRequest;
 }
 
 bool
 imgLoader::RemoveFromCache(const ImageCacheKey& aKey)
 {
   LOG_STATIC_FUNC_WITH_PARAM(gImgLog,
-                             "imgLoader::RemoveFromCache", "uri", aKey.Spec());
+                             "imgLoader::RemoveFromCache", "uri", aKey.URI());
 
   imgCacheTable& cache = GetCache(aKey);
   imgCacheQueue& queue = GetCacheQueue(aKey);
 
   RefPtr<imgCacheEntry> entry;
   cache.Remove(aKey, getter_AddRefs(entry));
   if (entry) {
     MOZ_ASSERT(!entry->Evicted(), "Evicting an already-evicted cache entry!");
@@ -2041,17 +2041,17 @@ imgLoader::RemoveFromCache(imgCacheEntry
   RefPtr<imgRequest> request = entry->GetRequest();
   if (request) {
     const ImageCacheKey& key = request->CacheKey();
     imgCacheTable& cache = GetCache(key);
     imgCacheQueue& queue = GetCacheQueue(key);
 
     LOG_STATIC_FUNC_WITH_PARAM(gImgLog,
                                "imgLoader::RemoveFromCache", "entry's uri",
-                               key.Spec());
+                               key.URI());
 
     cache.Remove(key);
 
     if (entry->HasNoProxies()) {
       LOG_STATIC_FUNC(gImgLog,
                       "imgLoader::RemoveFromCache removing from tracker");
       if (mCacheTracker) {
         mCacheTracker->RemoveObject(entry);
@@ -2209,18 +2209,17 @@ imgLoader::LoadImage(nsIURI* aURI,
   VerifyCacheSizes();
 
   NS_ASSERTION(aURI, "imgLoader::LoadImage -- NULL URI pointer");
 
   if (!aURI) {
     return NS_ERROR_NULL_POINTER;
   }
 
-  LOG_SCOPE_WITH_PARAM(gImgLog, "imgLoader::LoadImage", "aURI",
-                       aURI->GetSpecOrDefault().get());
+  LOG_SCOPE_WITH_PARAM(gImgLog, "imgLoader::LoadImage", "aURI", aURI);
 
   *_retval = nullptr;
 
   RefPtr<imgRequest> request;
 
   nsresult rv;
   nsLoadFlags requestFlags = nsIRequest::LOAD_NORMAL;
 
@@ -2305,17 +2304,17 @@ imgLoader::LoadImage(nsIURI* aURI,
                       aLoadingDocument, requestFlags, aContentPolicyType, true,
                       _retval, aTriggeringPrincipal, corsmode)) {
       request = entry->GetRequest();
 
       // If this entry has no proxies, its request has no reference to the
       // entry.
       if (entry->HasNoProxies()) {
         LOG_FUNC_WITH_PARAM(gImgLog,
-          "imgLoader::LoadImage() adding proxyless entry", "uri", key.Spec());
+          "imgLoader::LoadImage() adding proxyless entry", "uri", key.URI());
         MOZ_ASSERT(!request->HasCacheEntry(),
           "Proxyless entry's request has cache entry!");
         request->SetCacheEntry(entry);
 
         if (mCacheTracker && entry->GetExpirationState()->IsTracked()) {
           mCacheTracker->MarkUsed(entry);
         }
       }
@@ -2593,17 +2592,17 @@ imgLoader::LoadImageWithChannel(nsIChann
       }
 
       if (request && entry) {
         // If this entry has no proxies, its request has no reference to
         // the entry.
         if (entry->HasNoProxies()) {
           LOG_FUNC_WITH_PARAM(gImgLog,
             "imgLoader::LoadImageWithChannel() adding proxyless entry",
-            "uri", key.Spec());
+            "uri", key.URI());
           MOZ_ASSERT(!request->HasCacheEntry(),
             "Proxyless entry's request has cache entry!");
           request->SetCacheEntry(entry);
 
           if (mCacheTracker && entry->GetExpirationState()->IsTracked()) {
             mCacheTracker->MarkUsed(entry);
           }
         }
@@ -3062,27 +3061,21 @@ imgCacheValidator::OnStartRequest(nsIReq
       UpdateProxies(/* aCancelRequest */ false, /* aSyncNotify */ true);
       return NS_OK;
     }
   }
 
   // We can't load out of cache. We have to create a whole new request for the
   // data that's coming in off the channel.
   nsCOMPtr<nsIURI> uri;
-  {
-    RefPtr<ImageURL> imageURL;
-    mRequest->GetURI(getter_AddRefs(imageURL));
-    uri = imageURL->ToIURI();
-  }
-
-  if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
-    LOG_MSG_WITH_PARAM(gImgLog,
-                       "imgCacheValidator::OnStartRequest creating new request",
-                       "uri", uri->GetSpecOrDefault().get());
-  }
+  mRequest->GetURI(getter_AddRefs(uri));
+
+  LOG_MSG_WITH_PARAM(gImgLog,
+                     "imgCacheValidator::OnStartRequest creating new request",
+                     "uri", uri);
 
   int32_t corsmode = mRequest->GetCORSMode();
   ReferrerPolicy refpol = mRequest->GetReferrerPolicy();
   nsCOMPtr<nsIPrincipal> triggeringPrincipal = mRequest->GetTriggeringPrincipal();
 
   // Doom the old request's cache entry
   mRequest->RemoveFromCache();
 
--- a/image/imgLoader.h
+++ b/image/imgLoader.h
@@ -29,17 +29,16 @@ class imgLoader;
 class imgRequestProxy;
 class imgINotificationObserver;
 class nsILoadGroup;
 class imgCacheExpirationTracker;
 class imgMemoryReporter;
 
 namespace mozilla {
 namespace image {
-class ImageURL;
 } // namespace image
 } // namespace mozilla
 
 class imgCacheEntry
 {
 public:
   static uint32_t SecondsFromPRTime(PRTime prTime);
 
@@ -229,17 +228,16 @@ class imgLoader final : public imgILoade
                         public imgICache,
                         public nsSupportsWeakReference,
                         public nsIObserver
 {
   virtual ~imgLoader();
 
 public:
   typedef mozilla::image::ImageCacheKey ImageCacheKey;
-  typedef mozilla::image::ImageURL ImageURL;
   typedef nsRefPtrHashtable<nsGenericHashKey<ImageCacheKey>,
                             imgCacheEntry> imgCacheTable;
   typedef nsTHashtable<nsPtrHashKey<imgRequest>> imgSet;
   typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
   typedef mozilla::Mutex Mutex;
 
   NS_DECL_ISUPPORTS
   NS_DECL_IMGILOADER
--- a/image/imgRequest.cpp
+++ b/image/imgRequest.cpp
@@ -75,20 +75,18 @@ imgRequest::imgRequest(imgLoader* aLoade
 }
 
 imgRequest::~imgRequest()
 {
   if (mLoader) {
     mLoader->RemoveFromUncachedImages(this);
   }
   if (mURI) {
-    nsAutoCString spec;
-    mURI->GetSpec(spec);
     LOG_FUNC_WITH_PARAM(gImgLog, "imgRequest::~imgRequest()",
-                        "keyuri", spec.get());
+                        "keyuri", mURI);
   } else
     LOG_FUNC(gImgLog, "imgRequest::~imgRequest()");
 }
 
 nsresult
 imgRequest::Init(nsIURI *aURI,
                  nsIURI *aFinalURI,
                  bool aHadInsecureRedirect,
@@ -106,27 +104,21 @@ imgRequest::Init(nsIURI *aURI,
 
   MOZ_ASSERT(!mImage, "Multiple calls to init");
   MOZ_ASSERT(aURI, "No uri");
   MOZ_ASSERT(aFinalURI, "No final uri");
   MOZ_ASSERT(aRequest, "No request");
   MOZ_ASSERT(aChannel, "No channel");
 
   mProperties = do_CreateInstance("@mozilla.org/properties;1");
-
-  // Use ImageURL to ensure access to URI data off main thread.
-  nsresult rv;
-  mURI = new ImageURL(aURI, rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
+  mURI = aURI;
   mFinalURI = aFinalURI;
   mRequest = aRequest;
   mChannel = aChannel;
   mTimedChannel = do_QueryInterface(mChannel);
-
   mTriggeringPrincipal = aTriggeringPrincipal;
   mCORSMode = aCORSMode;
   mReferrerPolicy = aReferrerPolicy;
 
   // If the original URI and the final URI are different, check whether the
   // original URI is secure. We deliberately don't take the final URI into
   // account, as it needs to be handled using more complicated rules than
   // earlier elements of the redirect chain.
@@ -260,22 +252,20 @@ imgRequest::RemoveProxy(imgRequestProxy*
     // been cancelled and thus removed from the cache, tell the image loader so
     // we can be evicted from the cache.
     if (mCacheEntry) {
       MOZ_ASSERT(mURI, "Removing last observer without key uri.");
 
       if (mLoader) {
         mLoader->SetHasNoProxies(this, mCacheEntry);
       }
-    } else if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
-      nsAutoCString spec;
-      mURI->GetSpec(spec);
+    } else {
       LOG_MSG_WITH_PARAM(gImgLog,
                          "imgRequest::RemoveProxy no cache entry",
-                         "uri", spec.get());
+                         "uri", mURI);
     }
 
     /* If |aStatus| is a failure code, then cancel the load if it is still in
        progress.  Otherwise, let the load continue, keeping 'this' in the cache
        with no observers.  This way, if a proxy is destroyed without calling
        cancel on it, it won't leak and won't leave a bad pointer in the observer
        list.
      */
@@ -417,17 +407,17 @@ imgRequest::StartDecoding()
 
 bool
 imgRequest::IsDecodeRequested() const
 {
   MutexAutoLock lock(mMutex);
   return mDecodeRequested;
 }
 
-nsresult imgRequest::GetURI(ImageURL** aURI)
+nsresult imgRequest::GetURI(nsIURI** aURI)
 {
   MOZ_ASSERT(aURI);
 
   LOG_FUNC(gImgLog, "imgRequest::GetURI");
 
   if (mURI) {
     *aURI = mURI;
     NS_ADDREF(*aURI);
@@ -983,17 +973,17 @@ struct NewPartResult final
   RefPtr<image::Image> mImage;
   const bool mIsFirstPart;
   bool mSucceeded;
   bool mShouldResetCacheEntry;
 };
 
 static NewPartResult
 PrepareForNewPart(nsIRequest* aRequest, nsIInputStream* aInStr, uint32_t aCount,
-                  ImageURL* aURI, bool aIsMultipart, image::Image* aExistingImage,
+                  nsIURI* aURI, bool aIsMultipart, image::Image* aExistingImage,
                   ProgressTracker* aProgressTracker, uint32_t aInnerWindowId)
 {
   NewPartResult result(aExistingImage);
 
   if (aInStr) {
     mimetype_closure closure;
     closure.newType = &result.mContentType;
 
--- a/image/imgRequest.h
+++ b/image/imgRequest.h
@@ -30,32 +30,30 @@ class nsIApplicationCache;
 class nsIProperties;
 class nsIRequest;
 class nsITimedChannel;
 class nsIURI;
 
 namespace mozilla {
 namespace image {
 class Image;
-class ImageURL;
 class ProgressTracker;
 } // namespace image
 } // namespace mozilla
 
 struct NewPartResult;
 
 class imgRequest final : public nsIStreamListener,
                          public nsIThreadRetargetableStreamListener,
                          public nsIChannelEventSink,
                          public nsIInterfaceRequestor,
                          public nsIAsyncVerifyRedirectCallback
 {
   typedef mozilla::image::Image Image;
   typedef mozilla::image::ImageCacheKey ImageCacheKey;
-  typedef mozilla::image::ImageURL ImageURL;
   typedef mozilla::image::ProgressTracker ProgressTracker;
   typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
 
 public:
   imgRequest(imgLoader* aLoader, const ImageCacheKey& aCacheKey);
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSISTREAMLISTENER
@@ -146,17 +144,17 @@ public:
 
   /// Get the ImageCacheKey associated with this request.
   const ImageCacheKey& CacheKey() const { return mCacheKey; }
 
   // Resize the cache entry to 0 if it exists
   void ResetCacheEntry();
 
   // OK to use on any thread.
-  nsresult GetURI(ImageURL** aURI);
+  nsresult GetURI(nsIURI** aURI);
   nsresult GetFinalURI(nsIURI** aURI);
   bool IsScheme(const char* aScheme) const;
   bool IsChrome() const;
   bool IsData() const;
 
   nsresult GetImageErrorCode(void);
 
   /// Returns true if we've received any data.
@@ -230,17 +228,17 @@ private:
   void AdjustPriorityInternal(int32_t aDelta);
 
   // Weak reference to parent loader; this request cannot outlive its owner.
   imgLoader* mLoader;
   nsCOMPtr<nsIRequest> mRequest;
   // The original URI we were loaded with. This is the same as the URI we are
   // keyed on in the cache. We store a string here to avoid off main thread
   // refcounting issues with nsStandardURL.
-  RefPtr<ImageURL> mURI;
+  nsCOMPtr<nsIURI> mURI;
   // The URI of the resource we ended up loading after all redirects, etc.
   nsCOMPtr<nsIURI> mFinalURI;
   // The principal which triggered the load of this image. Generally either
   // the principal of the document the image is being loaded into, or of the
   // stylesheet which specified the image to load. Used when validating for CORS.
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   // The principal of this image.
   nsCOMPtr<nsIPrincipal> mPrincipal;
--- a/image/imgRequestProxy.cpp
+++ b/image/imgRequestProxy.cpp
@@ -175,17 +175,17 @@ imgRequestProxy::~imgRequestProxy()
   RemoveFromLoadGroup();
   LOG_FUNC(gImgLog, "imgRequestProxy::~imgRequestProxy");
 }
 
 nsresult
 imgRequestProxy::Init(imgRequest* aOwner,
                       nsILoadGroup* aLoadGroup,
                       nsIDocument* aLoadingDocument,
-                      ImageURL* aURI,
+                      nsIURI* aURI,
                       imgINotificationObserver* aObserver)
 {
   MOZ_ASSERT(!GetOwner() && !mListener,
              "imgRequestProxy is already initialized");
 
   LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequestProxy::Init", "request",
                        aOwner);
 
@@ -767,43 +767,31 @@ imgRequestProxy::GetImageErrorCode(nsres
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 imgRequestProxy::GetURI(nsIURI** aURI)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread to convert URI");
-  nsCOMPtr<nsIURI> uri = mURI->ToIURI();
+  nsCOMPtr<nsIURI> uri = mURI;
   uri.forget(aURI);
   return NS_OK;
 }
 
 nsresult
 imgRequestProxy::GetFinalURI(nsIURI** aURI)
 {
   if (!GetOwner()) {
     return NS_ERROR_FAILURE;
   }
 
   return GetOwner()->GetFinalURI(aURI);
 }
 
-nsresult
-imgRequestProxy::GetURI(ImageURL** aURI)
-{
-  if (!mURI) {
-    return NS_ERROR_FAILURE;
-  }
-
-  NS_ADDREF(*aURI = mURI);
-
-  return NS_OK;
-}
-
 NS_IMETHODIMP
 imgRequestProxy::GetNotificationObserver(imgINotificationObserver** aObserver)
 {
   *aObserver = mListener;
   NS_IF_ADDREF(*aObserver);
   return NS_OK;
 }
 
@@ -1090,22 +1078,18 @@ imgRequestProxy::Notify(int32_t aType, c
   nsCOMPtr<imgINotificationObserver> listener(mListener);
 
   listener->Notify(this, aType, aRect);
 }
 
 void
 imgRequestProxy::OnLoadComplete(bool aLastPart)
 {
-  if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
-    nsAutoCString name;
-    GetName(name);
-    LOG_FUNC_WITH_PARAM(gImgLog, "imgRequestProxy::OnLoadComplete",
-                        "name", name.get());
-  }
+  LOG_FUNC_WITH_PARAM(gImgLog, "imgRequestProxy::OnLoadComplete",
+                      "uri", mURI);
 
   // There's all sorts of stuff here that could kill us (the OnStopRequest call
   // on the listener, the removal from the loadgroup, the release of the
   // listener, etc).  Don't let them do it.
   RefPtr<imgRequestProxy> self(this);
 
   if (!IsOnEventTarget()) {
     DispatchWithTarget(NS_NewRunnableFunction("imgRequestProxy::OnLoadComplete",
--- a/image/imgRequestProxy.h
+++ b/image/imgRequestProxy.h
@@ -37,33 +37,31 @@ class ProxyBehaviour;
 
 namespace mozilla {
 namespace dom {
 class TabGroup;
 }
 
 namespace image {
 class Image;
-class ImageURL;
 class ProgressTracker;
 } // namespace image
 } // namespace mozilla
 
 class imgRequestProxy : public imgIRequest,
                         public mozilla::image::IProgressObserver,
                         public nsISupportsPriority,
                         public nsISecurityInfoProvider,
                         public nsITimedChannel
 {
 protected:
   virtual ~imgRequestProxy();
 
 public:
   typedef mozilla::image::Image Image;
-  typedef mozilla::image::ImageURL ImageURL;
   typedef mozilla::image::ProgressTracker ProgressTracker;
 
   MOZ_DECLARE_REFCOUNTED_TYPENAME(imgRequestProxy)
   NS_DECL_ISUPPORTS
   NS_DECL_IMGIREQUEST
   NS_DECL_NSIREQUEST
   NS_DECL_NSISUPPORTSPRIORITY
   NS_DECL_NSISECURITYINFOPROVIDER
@@ -71,17 +69,17 @@ public:
 
   imgRequestProxy();
 
   // Callers to Init or ChangeOwner are required to call NotifyListener after
   // (although not immediately after) doing so.
   nsresult Init(imgRequest* aOwner,
                 nsILoadGroup* aLoadGroup,
                 nsIDocument* aLoadingDocument,
-                ImageURL* aURI,
+                nsIURI* aURI,
                 imgINotificationObserver* aObserver);
 
   nsresult ChangeOwner(imgRequest* aNewOwner); // this will change mOwner.
                                                // Do not call this if the
                                                // previous owner has already
                                                // sent notifications out!
 
   // Add the request to the load group, if any. This should only be called once
@@ -145,18 +143,16 @@ public:
                      nsIDocument* aLoadingDocument,
                      imgRequestProxy** aClone);
   nsresult Clone(imgINotificationObserver* aObserver,
                  nsIDocument* aLoadingDocument,
                  imgRequestProxy** aClone);
   nsresult GetStaticRequest(nsIDocument* aLoadingDocument,
                             imgRequestProxy** aReturn);
 
-  nsresult GetURI(ImageURL** aURI);
-
 protected:
   friend class mozilla::image::ProgressTracker;
   friend class imgStatusNotifyRunnable;
 
   class imgCancelRunnable;
   friend class imgCancelRunnable;
 
   class imgCancelRunnable : public mozilla::Runnable
@@ -225,17 +221,17 @@ private:
 
   void AddToOwner(nsIDocument* aLoadingDocument);
   void RemoveFromOwner(nsresult aStatus);
 
   nsresult DispatchWithTargetIfAvailable(already_AddRefed<nsIRunnable> aEvent);
   void DispatchWithTarget(already_AddRefed<nsIRunnable> aEvent);
 
   // The URI of our request.
-  RefPtr<ImageURL> mURI;
+  nsCOMPtr<nsIURI> mURI;
 
   // mListener is only promised to be a weak ref (see imgILoader.idl),
   // but we actually keep a strong ref to it until we've seen our
   // first OnStopRequest.
   imgINotificationObserver* MOZ_UNSAFE_REF("Observers must call Cancel() or "
                                            "CancelAndForgetObserver() before "
                                            "they are destroyed") mListener;
 
--- a/image/imgTools.cpp
+++ b/image/imgTools.cpp
@@ -13,16 +13,17 @@
 #include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIDocument.h"
 #include "nsError.h"
 #include "imgLoader.h"
 #include "imgICache.h"
 #include "imgIContainer.h"
 #include "imgIEncoder.h"
+#include "nsNetUtil.h" // for NS_NewBufferedInputStream
 #include "nsStreamUtils.h"
 #include "nsStringStream.h"
 #include "nsContentUtils.h"
 #include "nsProxyRelease.h"
 #include "ImageFactory.h"
 #include "Image.h"
 #include "ScriptedNotificationObserver.h"
 #include "imgIScriptedNotificationObserver.h"
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -622,32 +622,38 @@ AddAppDirToCommandLine(std::vector<std::
 }
 
 bool
 GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExtraOpts)
 {
   // We rely on the fact that InitializeChannel() has already been processed
   // on the IO thread before this point is reached.
   if (!GetChannel()) {
+#ifdef ASYNC_CONTENTPROC_LAUNCH
+    MOZ_RELEASE_ASSERT(1 == 2);
+#endif
     return false;
   }
 
   base::ProcessHandle process = 0;
 
   // send the child the PID so that it can open a ProcessHandle back to us.
   // probably don't want to do this in the long run
   char pidstring[32];
   SprintfLiteral(pidstring, "%d", base::GetCurrentProcId());
 
   const char* const childProcessType =
       XRE_ChildProcessTypeToString(mProcessType);
 
   PRFileDesc* crashAnnotationReadPipe;
   PRFileDesc* crashAnnotationWritePipe;
   if (PR_CreatePipe(&crashAnnotationReadPipe, &crashAnnotationWritePipe) != PR_SUCCESS) {
+#ifdef ASYNC_CONTENTPROC_LAUNCH
+    MOZ_RELEASE_ASSERT(2 == 3);
+#endif
     return false;
   }
 
 //--------------------------------------------------
 #if defined(OS_POSIX)
   // For POSIX, we have to be extremely anal about *not* using
   // std::wstring in code compiled with Mozilla's -fshort-wchar
   // configuration, because chromium is compiled with -fno-short-wchar
@@ -828,27 +834,36 @@ GeckoChildProcessHost::PerformAsyncLaunc
   const int kTimeoutMs = 10000;
 
   MachReceiveMessage child_message;
   ReceivePort parent_recv_port(mach_connection_name.c_str());
   kern_return_t err = parent_recv_port.WaitForMessage(&child_message, kTimeoutMs);
   if (err != KERN_SUCCESS) {
     std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err));
     CHROMIUM_LOG(ERROR) << "parent WaitForMessage() failed: " << errString;
+#ifdef ASYNC_CONTENTPROC_LAUNCH
+    MOZ_RELEASE_ASSERT(3 == 4);
+#endif
     return false;
   }
 
   task_t child_task = child_message.GetTranslatedPort(0);
   if (child_task == MACH_PORT_NULL) {
     CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(0) failed.";
+#ifdef ASYNC_CONTENTPROC_LAUNCH
+    MOZ_RELEASE_ASSERT(4 == 5);
+#endif
     return false;
   }
 
   if (child_message.GetTranslatedPort(1) == MACH_PORT_NULL) {
     CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(1) failed.";
+#ifdef ASYNC_CONTENTPROC_LAUNCH
+    MOZ_RELEASE_ASSERT(5 == 6);
+#endif
     return false;
   }
   MachPortSender parent_sender(child_message.GetTranslatedPort(1));
 
   if (child_message.GetTranslatedPort(2) == MACH_PORT_NULL) {
     CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(2) failed.";
   }
   auto* parent_recv_port_memory_ack = new MachPortSender(child_message.GetTranslatedPort(2));
@@ -856,35 +871,47 @@ GeckoChildProcessHost::PerformAsyncLaunc
   if (child_message.GetTranslatedPort(3) == MACH_PORT_NULL) {
     CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(3) failed.";
   }
   auto* parent_send_port_memory = new MachPortSender(child_message.GetTranslatedPort(3));
 
   MachSendMessage parent_message(/* id= */0);
   if (!parent_message.AddDescriptor(MachMsgPortDescriptor(bootstrap_port))) {
     CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port << ") failed.";
+#ifdef ASYNC_CONTENTPROC_LAUNCH
+    MOZ_RELEASE_ASSERT(6 == 7);
+#endif
     return false;
   }
 
   auto* parent_recv_port_memory = new ReceivePort();
   if (!parent_message.AddDescriptor(MachMsgPortDescriptor(parent_recv_port_memory->GetPort()))) {
     CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << parent_recv_port_memory->GetPort() << ") failed.";
+#ifdef ASYNC_CONTENTPROC_LAUNCH
+    MOZ_RELEASE_ASSERT(7 == 8);
+#endif
     return false;
   }
 
   auto* parent_send_port_memory_ack = new ReceivePort();
   if (!parent_message.AddDescriptor(MachMsgPortDescriptor(parent_send_port_memory_ack->GetPort()))) {
     CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << parent_send_port_memory_ack->GetPort() << ") failed.";
+#ifdef ASYNC_CONTENTPROC_LAUNCH
+    MOZ_RELEASE_ASSERT(8 == 9);
+#endif
     return false;
   }
 
   err = parent_sender.SendMessage(parent_message, kTimeoutMs);
   if (err != KERN_SUCCESS) {
     std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err));
     CHROMIUM_LOG(ERROR) << "parent SendMessage() failed: " << errString;
+#ifdef ASYNC_CONTENTPROC_LAUNCH
+    MOZ_RELEASE_ASSERT(9 == 10);
+#endif
     return false;
   }
 
   SharedMemoryBasic::SetupMachMemory(process, parent_recv_port_memory, parent_recv_port_memory_ack,
                                      parent_send_port_memory, parent_send_port_memory_ack, false);
 
 # endif // MOZ_WIDGET_COCOA
 
@@ -943,26 +970,32 @@ GeckoChildProcessHost::PerformAsyncLaunc
       }
 #  endif // defined(MOZ_CONTENT_SANDBOX)
       break;
     case GeckoProcessType_Plugin:
       if (mSandboxLevel > 0 &&
           !PR_GetEnv("MOZ_DISABLE_NPAPI_SANDBOX")) {
         bool ok = mSandboxBroker.SetSecurityLevelForPluginProcess(mSandboxLevel);
         if (!ok) {
+#ifdef ASYNC_CONTENTPROC_LAUNCH
+          MOZ_RELEASE_ASSERT(10 == 11);
+#endif
           return false;
         }
         shouldSandboxCurrentProcess = true;
       }
       break;
 #ifdef MOZ_ENABLE_SKIA_PDF
     case GeckoProcessType_PDFium:
       if (!PR_GetEnv("MOZ_DISABLE_PDFIUM_SANDBOX")) {
         bool ok = mSandboxBroker.SetSecurityLevelForPDFiumProcess();
         if (!ok) {
+#ifdef ASYNC_CONTENTPROC_LAUNCH
+          MOZ_RELEASE_ASSERT(11 == 12);
+#endif
           return false;
         }
         shouldSandboxCurrentProcess = true;
       }
       break;
 #endif
     case GeckoProcessType_IPDLUnitTest:
       // XXX: We don't sandbox this process type yet
@@ -973,16 +1006,19 @@ GeckoChildProcessHost::PerformAsyncLaunc
         // not at USER_LOCKDOWN. So look in the command line arguments
         // to see if we're loading the path to the Widevine CDM, and if
         // so use sandbox level USER_RESTRICTED instead of USER_LOCKDOWN.
         bool isWidevine = std::any_of(aExtraOpts.begin(), aExtraOpts.end(),
           [](const std::string arg) { return arg.find("gmp-widevinecdm") != std::string::npos; });
         auto level = isWidevine ? SandboxBroker::Restricted : SandboxBroker::LockDown;
         bool ok = mSandboxBroker.SetSecurityLevelForGMPlugin(level);
         if (!ok) {
+#ifdef ASYNC_CONTENTPROC_LAUNCH
+          MOZ_RELEASE_ASSERT(12 == 13);
+#endif
           return false;
         }
         shouldSandboxCurrentProcess = true;
       }
       break;
     case GeckoProcessType_GPU:
       if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_GPU_SANDBOX")) {
         // For now we treat every failure as fatal in SetSecurityLevelForGPUProcess
@@ -1082,16 +1118,19 @@ GeckoChildProcessHost::PerformAsyncLaunc
 # endif // MOZ_SANDBOX
   }
 
 #else // goes with defined(OS_POSIX)
 #  error Sorry
 #endif // defined(OS_POSIX)
 
   if (!process) {
+#ifdef ASYNC_CONTENTPROC_LAUNCH
+    MOZ_RELEASE_ASSERT(13 == 14);
+#endif
     return false;
   }
   // NB: on OS X, we block much longer than we need to in order to
   // reach this call, waiting for the child process's task_t.  The
   // best way to fix that is to refactor this file, hard.
 #if defined(MOZ_WIDGET_COCOA)
   mChildTask = child_task;
 #endif // defined(MOZ_WIDGET_COCOA)
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -1153,16 +1153,18 @@ function ArrayFlat(/* depth */) {
 
     // Step 6.
     FlattenIntoArray(A, O, sourceLen, 0, depthNum);
 
     // Step 7.
     return A;
 }
 
+// https://tc39.github.io/proposal-flatMap/
+// May 23, 2018
 function FlattenIntoArray(target, source, sourceLen, start, depth, mapperFunction, thisArg) {
     // Step 1.
     var targetIndex = start;
 
     // Steps 2-3.
     for (var sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
         // Steps 3.a-c.
         if (sourceIndex in source) {
@@ -1173,34 +1175,40 @@ function FlattenIntoArray(target, source
                 // Step 3.c.ii.1.
                 assert(arguments.length === 7, "thisArg is present");
 
                 // Step 3.c.ii.2.
                 element = callContentFunction(mapperFunction, thisArg, element, sourceIndex, source);
             }
 
             // Step 3.c.iii.
-            var flattenable = IsArray(element);
+            var shouldFlatten = false;
 
             // Step 3.c.iv.
-            if (flattenable && depth > 0) {
+            if (depth > 0) {
                 // Step 3.c.iv.1.
+                shouldFlatten = IsArray(element);
+            }
+
+            // Step 3.c.v.
+            if (shouldFlatten) {
+                // Step 3.c.v.1.
                 var elementLen = ToLength(element.length);
 
-                // Step 3.c.iv.2.
+                // Step 3.c.v.2.
                 targetIndex = FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1);
             } else {
-                // Step 3.c.v.1.
+                // Step 3.c.vi.1.
                 if (targetIndex >= MAX_NUMERIC_INDEX)
                     ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
 
-                // Step 3.c.v.2.
+                // Step 3.c.vi.2.
                 _DefineDataProperty(target, targetIndex, element);
 
-                // Step 3.c.v.3.
+                // Step 3.c.vi.3.
                 targetIndex++;
             }
         }
     }
 
     // Step 4.
     return targetIndex;
 }
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -333,22 +333,34 @@ FRAME_STATE_GROUP(GridContainer, nsGridC
 FRAME_STATE_BIT(GridContainer, 20, NS_STATE_GRID_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER)
 
 // True iff some first-in-flow in-flow children were pushed.
 // Note that those child frames may have been removed without this bit
 // being updated for performance reasons, so code shouldn't depend on
 // actually finding any pushed items when this bit is set.
 FRAME_STATE_BIT(GridContainer, 21, NS_STATE_GRID_DID_PUSH_ITEMS)
 
-// True iff computed grid values should be generated on the next reflow
+// True iff computed grid values should be generated on the next reflow.
 FRAME_STATE_BIT(GridContainer, 22, NS_STATE_GRID_GENERATE_COMPUTED_VALUES)
 
-// True if the container has no grid items; may lie if there is a pending reflow
+// True if the container has no grid items; may lie if there is a pending reflow.
 FRAME_STATE_BIT(GridContainer, 23, NS_STATE_GRID_SYNTHESIZE_BASELINE)
 
+// True if the container is a subgrid in its inline axis.
+FRAME_STATE_BIT(GridContainer, 24, NS_STATE_GRID_IS_COL_SUBGRID)
+
+// True if the container is a subgrid in its block axis.
+FRAME_STATE_BIT(GridContainer, 25, NS_STATE_GRID_IS_ROW_SUBGRID)
+
+// The container contains one or more items subgridded in its inline axis.
+FRAME_STATE_BIT(GridContainer, 26, NS_STATE_GRID_HAS_COL_SUBGRID_ITEM)
+
+// The container contains one or more items subgridded in its block axis.
+FRAME_STATE_BIT(GridContainer, 27, NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM)
+
 // == Frame state bits that apply to SVG frames ===============================
 
 FRAME_STATE_GROUP(SVG, nsSVGDisplayableFrame)
 FRAME_STATE_GROUP(SVG, nsSVGContainerFrame)
 
 FRAME_STATE_BIT(SVG, 20, NS_STATE_IS_OUTER_SVG)
 
 // If this bit is set, we are a <clipPath> element or descendant.
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -23,16 +23,17 @@
 #include "mozilla/Poison.h"
 #include "nsAbsoluteContainingBlock.h"
 #include "nsAlgorithm.h" // for clamped()
 #include "nsCSSAnonBoxes.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsDataHashtable.h"
 #include "nsDisplayList.h"
 #include "nsHashKeys.h"
+#include "nsFieldSetFrame.h"
 #include "nsIFrameInlines.h"
 #include "nsPresContext.h"
 #include "nsReadableUtils.h"
 #include "nsTableWrapperFrame.h"
 
 using namespace mozilla;
 
 typedef nsAbsoluteContainingBlock::AbsPosReflowFlags AbsPosReflowFlags;
@@ -540,29 +541,54 @@ struct nsGridContainerFrame::GridItemInf
     // Ditto *-content:[last ]baseline. Mutually exclusive w. eSelfBaseline.
     eContentBaseline =       0x10,
     eAllBaselineBits = eIsBaselineAligned | eSelfBaseline | eContentBaseline,
     // Should apply Automatic Minimum Size per:
     // https://drafts.csswg.org/css-grid/#min-size-auto
     eApplyAutoMinSize =      0x20,
     // Clamp per https://drafts.csswg.org/css-grid/#min-size-auto
     eClampMarginBoxMinSize = 0x40,
+    eIsSubgrid =             0x80,
   };
 
   explicit GridItemInfo(nsIFrame* aFrame,
                         const GridArea& aArea)
     : mFrame(aFrame)
     , mArea(aArea)
   {
     mState[eLogicalAxisBlock] = StateBits(0);
     mState[eLogicalAxisInline] = StateBits(0);
+    nsIFrame* innerFrame = InnerFrame(mFrame);
+    if (innerFrame->IsGridContainerFrame()) {
+      const auto* f = static_cast<nsGridContainerFrame*>(innerFrame);
+      auto parentWM = aFrame->GetParent()->GetWritingMode();
+      bool isOrthogonal = parentWM.IsOrthogonalTo(f->GetWritingMode());
+      if (f->IsColSubgrid()) {
+        mState[isOrthogonal ? eLogicalAxisBlock : eLogicalAxisInline] =
+          StateBits::eIsSubgrid;
+      }
+      if (f->IsRowSubgrid()) {
+        mState[isOrthogonal ? eLogicalAxisInline : eLogicalAxisBlock] =
+          StateBits::eIsSubgrid;
+      }
+    }
     mBaselineOffset[eLogicalAxisBlock] = nscoord(0);
     mBaselineOffset[eLogicalAxisInline] = nscoord(0);
   }
 
+  // Is this item a subgrid in the given container axis?
+  bool IsSubgrid(LogicalAxis aAxis) const {
+    return mState[aAxis] & StateBits::eIsSubgrid;
+  }
+
+  // Is this item a subgrid in either axis?
+  bool IsSubgrid() const {
+    return IsSubgrid(eLogicalAxisInline) || IsSubgrid(eLogicalAxisBlock);
+  }
+
   /**
    * If the item is [align|justify]-self:[last ]baseline aligned in the given
    * axis then set aBaselineOffset to the baseline offset and return aAlign.
    * Otherwise, return a fallback alignment.
    */
   uint8_t GetSelfBaseline(uint8_t aAlign, LogicalAxis aAxis,
                           nscoord* aBaselineOffset) const
   {
@@ -606,16 +632,27 @@ struct nsGridContainerFrame::GridItemInf
   void Dump() const;
 #endif
 
   static bool IsStartRowLessThan(const GridItemInfo* a, const GridItemInfo* b)
   {
     return a->mArea.mRows.mStart < b->mArea.mRows.mStart;
   }
 
+  // Return the inner frame of aFrame that might be a grid container.
+  // This drills down through scroll frames and such.
+  static nsIFrame* InnerFrame(nsIFrame* aFrame)
+  {
+    nsIFrame* inner = aFrame;
+    if (MOZ_UNLIKELY(aFrame->IsFieldSetFrame())) {
+      inner = static_cast<nsFieldSetFrame*>(aFrame)->GetInner();
+    }
+    return inner->GetContentInsertionFrame();
+  }
+
   nsIFrame* const mFrame;
   GridArea mArea;
   // Offset from the margin edge to the baseline (LogicalAxis index).  It's from
   // the start edge when eFirstBaseline is set, end edge otherwise. It's mutable
   // since we update the value fairly late (just before reflowing the item).
   mutable nscoord mBaselineOffset[2];
   mutable StateBits mState[2]; // state bits per axis (LogicalAxis index)
   static_assert(mozilla::eLogicalAxisBlock == 0, "unexpected index value");
@@ -631,16 +668,19 @@ void
 nsGridContainerFrame::GridItemInfo::Dump() const
 {
   auto Dump1 = [this] (const char* aMsg, LogicalAxis aAxis) {
     auto state = mState[aAxis];
     if (!state) {
       return;
     }
     printf("%s", aMsg);
+    if (state & ItemState::eIsSubgrid) {
+      printf("subgrid ");
+    }
     if (state & ItemState::eIsFlexing) {
       printf("flexing ");
     }
     if (state & ItemState::eApplyAutoMinSize) {
       printf("auto-min-size ");
     }
     if (state & ItemState::eClampMarginBoxMinSize) {
       printf("clamp ");
@@ -3126,16 +3166,20 @@ nsGridContainerFrame::Grid::PlaceGridIte
                                            const LogicalSize& aComputedMinSize,
                                            const LogicalSize& aComputedSize,
                                            const LogicalSize& aComputedMaxSize)
 {
   mAreas = aState.mFrame->GetImplicitNamedAreas();
   const nsStylePosition* const gridStyle = aState.mGridStyle;
   MOZ_ASSERT(mCellMap.mCells.IsEmpty(), "unexpected entries in cell map");
 
+  // SubgridPlaceGridItems will set these if we find any subgrid items.
+  aState.mFrame->RemoveStateBits(NS_STATE_GRID_HAS_COL_SUBGRID_ITEM |
+                                 NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM);
+
   // http://dev.w3.org/csswg/css-grid/#grid-definition
   // Initialize the end lines of the Explicit Grid (mExplicitGridCol[Row]End).
   // This is determined by the larger of the number of rows/columns defined
   // by 'grid-template-areas' and the 'grid-template-rows'/'-columns', plus one.
   // Also initialize the Implicit Grid (mGridCol[Row]End) to the same values.
   // Note that this is for a grid with a 1,1 origin.  We'll change that
   // to a 0,0 based grid after placing definite lines.
   auto areas = gridStyle->mGridTemplateAreas.get();
@@ -4116,17 +4160,17 @@ nsGridContainerFrame::Tracks::Initialize
                 (ItemState::eSelfBaseline | ItemState::eContentBaseline)) !=
                (ItemState::eSelfBaseline | ItemState::eContentBaseline),
                "*-self and *-content baseline bits are mutually exclusive");
     MOZ_ASSERT(!(state &
                  (ItemState::eFirstBaseline | ItemState::eLastBaseline)) ==
                !(state &
                  (ItemState::eSelfBaseline | ItemState::eContentBaseline)),
                "first/last bit requires self/content bit and vice versa");
-    gridItem.mState[mAxis] = state;
+    gridItem.mState[mAxis] |= state;
     gridItem.mBaselineOffset[mAxis] = nscoord(0);
   }
 
   if (firstBaselineItems.IsEmpty() && lastBaselineItems.IsEmpty()) {
     return;
   }
 
   // TODO: CSS Align spec issue - how to align a baseline subtree in a track?
@@ -6325,16 +6369,48 @@ nsGridContainerFrame::Reflow(nsPresConte
       DeleteProperty(SharedGridData::Prop());
     }
   }
 
   FinishAndStoreOverflow(&aDesiredSize);
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
 }
 
+void
+nsGridContainerFrame::Init(nsIContent*       aContent,
+                           nsContainerFrame* aParent,
+                           nsIFrame*         aPrevInFlow)
+{
+  nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
+
+  nsFrameState bits = nsFrameState(0);
+  if (MOZ_LIKELY(!aPrevInFlow)) {
+    // skip our scroll frame and such if we have it
+    auto* parent = aParent;
+    while (parent && parent->GetContent() == aContent) {
+      parent = parent->GetParent();
+    }
+    if (parent && parent->IsGridContainerFrame()) {
+      const auto* pos = StylePosition();
+      if (pos->GridTemplateColumns().mIsSubgrid) {
+        bits |= NS_STATE_GRID_IS_COL_SUBGRID;
+      }
+      if (pos->GridTemplateRows().mIsSubgrid) {
+        bits |= NS_STATE_GRID_IS_ROW_SUBGRID;
+      }
+    }
+  } else {
+    bits = aPrevInFlow->GetStateBits() & (NS_STATE_GRID_IS_COL_SUBGRID |
+                                          NS_STATE_GRID_IS_ROW_SUBGRID |
+                                          NS_STATE_GRID_HAS_COL_SUBGRID_ITEM |
+                                          NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM);
+  }
+  AddStateBits(bits);
+}
+
 nscoord
 nsGridContainerFrame::IntrinsicISize(gfxContext* aRenderingContext,
                                      IntrinsicISizeType  aType)
 {
   RenumberList();
 
   // Calculate the sum of column sizes under intrinsic sizing.
   // http://dev.w3.org/csswg/css-grid/#intrinsic-sizes
--- a/layout/generic/nsGridContainerFrame.h
+++ b/layout/generic/nsGridContainerFrame.h
@@ -92,16 +92,18 @@ public:
   typedef mozilla::ComputedGridTrackInfo ComputedGridTrackInfo;
   typedef mozilla::ComputedGridLineInfo ComputedGridLineInfo;
 
   // nsIFrame overrides
   void Reflow(nsPresContext*           aPresContext,
               ReflowOutput&     aDesiredSize,
               const ReflowInput& aReflowInput,
               nsReflowStatus&          aStatus) override;
+  void Init(nsIContent* aContent, nsContainerFrame* aParent,
+            nsIFrame* aPrevInFlow) override;
   nscoord GetMinISize(gfxContext* aRenderingContext) override;
   nscoord GetPrefISize(gfxContext* aRenderingContext) override;
   void MarkIntrinsicISizesDirty() override;
   bool IsFrameOfType(uint32_t aFlags) const override
   {
     return nsContainerFrame::IsFrameOfType(aFlags &
              ~nsIFrame::eCanContainOverflowContainers);
   }
@@ -212,16 +214,42 @@ public:
 
   typedef nsTArray<mozilla::css::GridNamedArea> ExplicitNamedAreas;
   NS_DECLARE_FRAME_PROPERTY_DELETABLE(ExplicitNamedAreasProperty,
                                       ExplicitNamedAreas)
   ExplicitNamedAreas* GetExplicitNamedAreas() const {
     return GetProperty(ExplicitNamedAreasProperty());
   }
 
+  /** Return true if this frame is subgridded in its aAxis. */
+  bool IsSubgrid(mozilla::LogicalAxis aAxis) const {
+    return HasAnyStateBits(
+      aAxis == mozilla::eLogicalAxisBlock ? NS_STATE_GRID_IS_ROW_SUBGRID
+                                          : NS_STATE_GRID_IS_COL_SUBGRID);
+  }
+  bool IsColSubgrid() const { return IsSubgrid(mozilla::eLogicalAxisInline); }
+  bool IsRowSubgrid() const { return IsSubgrid(mozilla::eLogicalAxisBlock); }
+  /** Return true if this frame is subgridded in any axis. */
+  bool IsSubgrid() const {
+    return HasAnyStateBits(NS_STATE_GRID_IS_ROW_SUBGRID |
+                           NS_STATE_GRID_IS_COL_SUBGRID);
+  }
+
+  /** Return true if this frame has an item that is subgridded in our aAxis. */
+  bool HasSubgridItems(mozilla::LogicalAxis aAxis) const {
+    return HasAnyStateBits(
+      aAxis == mozilla::eLogicalAxisBlock ? NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM
+                                          : NS_STATE_GRID_HAS_COL_SUBGRID_ITEM);
+  }
+  /** Return true if this frame has any subgrid items. */
+  bool HasSubgridItems() const {
+    return HasAnyStateBits(NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM |
+                           NS_STATE_GRID_HAS_COL_SUBGRID_ITEM);
+  }
+
   /**
    * Return a containing grid frame, and ensure it has computed grid info
    * @return nullptr if aFrame has no grid container, or frame was destroyed
    * @note this might destroy layout/style data since it may flush layout
    */
   static nsGridContainerFrame* GetGridFrameWithComputedInfo(nsIFrame* aFrame);
 
   struct TrackSize;
--- a/layout/style/test/test_font_loading_api.html
+++ b/layout/style/test/test_font_loading_api.html
@@ -223,18 +223,18 @@ function runTest() {
     is(Object.getPrototypeOf(FontFaceSetLoadEvent.prototype), Event.prototype, "FontFaceSetLoadEvent should inherit from Event (TEST 2)");
 
   }).then(function() {
 
     // (TEST 3) Test that document.fonts.ready is resolved with the
     // document.fonts FontFaceSet.
     var p = Promise.resolve();
     sourceDocuments.forEach(function({ doc, what }) {
-      p = p.then(doc.fonts.ready).then(function() {
-        return is_resolved_with(doc.fonts.ready, doc.fonts, "document.fonts.ready resolves with document.fonts", "(TEST 3) (" + what + ")");
+      p = p.then(_ => { return doc.fonts.ready }).then(function() {
+        return is_resolved_with(doc.fonts.ready, doc.fonts, "document.fonts.ready resolves with document.fonts.", "(TEST 3) (" + what + ")");
       });
     });
     return p;
 
   }).then(function() {
 
     // (TEST 4) Test that document.fonts in this test document starts out with no
     // FontFace objects in it.
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoVRManager.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoVRManager.java
@@ -5,121 +5,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.annotation.WrapForJNI;
 import org.mozilla.gecko.util.ThreadUtils;
 
 public class GeckoVRManager {
-    /**
-     * GeckoView applications implement this interface to provide GVR support for WebVR.
-     */
-    public interface GVRDelegate {
-        /**
-         * Creates non-presenting context. Will be invoked in the compositor thread.
-         */
-        long createNonPresentingContext();
-        /**
-         * Destroys non-presenting context. Will be invoked in the compositor thread.
-         */
-        void destroyNonPresentingContext();
-        /**
-         * Called when WebVR needs a presenting context. Will be invoked in the UI thread.
-         */
-        boolean enableVRMode();
-        /**
-         * Called when WebVR has finished presenting. Will be invoked in the UI thread.
-         */
-        void disableVRMode();
-    }
-
-    private static GVRDelegate mGVRDelegate;
-
-    /**
-     * Set the GVR Delegate for GeckoView.
-     * @param delegate GVRDelegate instance or null to unset.
-     */
-    public static void setGVRDelegate(GVRDelegate delegate) {
-        mGVRDelegate = delegate;
-    }
-
-    /**
-     * Set the GVR paused state.
-     * @param aPaused True if the application is being paused, False if the
-     * application is resuming.
-     */
-    @WrapForJNI(calledFrom = "ui")
-    public static native void setGVRPaused(final boolean aPaused);
-
-    /**
-     * Set the GVR presenting context.
-     * @param aContext GVR context to use when WebVR starts to present. Pass in
-     * zero to stop presenting.
-     */
-    @WrapForJNI(calledFrom = "ui")
-    public static native void setGVRPresentingContext(final long aContext);
-
-    /**
-     * Inform WebVR that the non-presenting context needs to be destroyed.
-     */
-    @WrapForJNI(calledFrom = "ui")
-    public static native void cleanupGVRNonPresentingContext();
+    private static long mExternalContext;
 
     @WrapForJNI
-    /* package */ static boolean isGVRPresent() {
-        return mGVRDelegate != null;
-    }
-
-    @WrapForJNI
-    /* package */ static long createGVRNonPresentingContext() {
-        if (mGVRDelegate == null) {
-            return 0;
-        }
-        return mGVRDelegate.createNonPresentingContext();
-    }
-
-    @WrapForJNI
-    /* package */ static void destroyGVRNonPresentingContext() {
-        if (mGVRDelegate == null) {
-            return;
-        }
-        mGVRDelegate.destroyNonPresentingContext();
+    public static synchronized long getExternalContext() {
+      return mExternalContext;
     }
 
-    @WrapForJNI
-    /* package */ static void enableVRMode() {
-        if (!ThreadUtils.isOnUiThread()) {
-            ThreadUtils.postToUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    enableVRMode();
-                }
-            });
-            return;
-        }
-
-        if (mGVRDelegate == null) {
-            return;
-        }
-
-        mGVRDelegate.enableVRMode();
+    public static synchronized void setExternalContext(final long externalContext) {
+        mExternalContext = externalContext;
     }
 
-    @WrapForJNI
-    /* package */ static void disableVRMode() {
-        if (!ThreadUtils.isOnUiThread()) {
-            ThreadUtils.postToUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    disableVRMode();
-                }
-            });
-            return;
-        }
-
-        if (mGVRDelegate == null) {
-            return;
-        }
-
-        mGVRDelegate.disableVRMode();
-    }
 }
--- a/mobile/android/geckoview/src/thirdparty/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java
+++ b/mobile/android/geckoview/src/thirdparty/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java
@@ -26,23 +26,26 @@ import java.io.EOFException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InterruptedIOException;
 import java.io.OutputStream;
 import java.lang.reflect.Method;
 import java.net.HttpURLConnection;
 import java.net.NoRouteToHostException;
 import java.net.ProtocolException;
+import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.mozilla.gecko.util.ProxySelector;
+
 /**
  * An {@link HttpDataSource} that uses Android's {@link HttpURLConnection}.
  * <p>
  * By default this implementation will not follow cross-protocol redirects (i.e. redirects from
  * HTTP to HTTPS or vice versa). Cross-protocol redirects can be enabled by using the
  * {@link #DefaultHttpDataSource(String, Predicate, TransferListener, int, int, boolean,
  * RequestProperties)} constructor and passing {@code true} as the second last argument.
  */
@@ -188,16 +191,18 @@ public class DefaultHttpDataSource imple
     this.dataSpec = dataSpec;
     this.bytesRead = 0;
     this.bytesSkipped = 0;
     try {
       connection = makeConnection(dataSpec);
     } catch (IOException e) {
       throw new HttpDataSourceException("Unable to connect to " + dataSpec.uri.toString(), e,
           dataSpec, HttpDataSourceException.TYPE_OPEN);
+    } catch (URISyntaxException e) {
+      throw new HttpDataSourceException("URI invalid: " + dataSpec.uri.toString(), dataSpec, HttpDataSourceException.TYPE_OPEN);
     }
 
     int responseCode;
     try {
       responseCode = connection.getResponseCode();
     } catch (IOException e) {
       closeConnectionQuietly();
       throw new HttpDataSourceException("Unable to connect to " + dataSpec.uri.toString(), e,
@@ -332,17 +337,17 @@ public class DefaultHttpDataSource imple
    */
   protected final long bytesRemaining() {
     return bytesToRead == C.LENGTH_UNSET ? bytesToRead : bytesToRead - bytesRead;
   }
 
   /**
    * Establishes a connection, following redirects to do so where permitted.
    */
-  private HttpURLConnection makeConnection(DataSpec dataSpec) throws IOException {
+  private HttpURLConnection makeConnection(DataSpec dataSpec) throws IOException, URISyntaxException {
     URL url = new URL(dataSpec.uri.toString());
     byte[] postBody = dataSpec.postBody;
     long position = dataSpec.position;
     long length = dataSpec.length;
     boolean allowGzip = dataSpec.isFlagSet(DataSpec.FLAG_ALLOW_GZIP);
 
     if (!allowCrossProtocolRedirects) {
       // HttpURLConnection disallows cross-protocol redirects, but otherwise performs redirection
@@ -384,18 +389,24 @@ public class DefaultHttpDataSource imple
    * @param url The url to connect to.
    * @param postBody The body data for a POST request.
    * @param position The byte offset of the requested data.
    * @param length The length of the requested data, or {@link C#LENGTH_UNSET}.
    * @param allowGzip Whether to allow the use of gzip.
    * @param followRedirects Whether to follow redirects.
    */
   private HttpURLConnection makeConnection(URL url, byte[] postBody, long position,
-      long length, boolean allowGzip, boolean followRedirects) throws IOException {
-    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+      long length, boolean allowGzip, boolean followRedirects) throws IOException, URISyntaxException {
+    /**
+     * Tor Project modified the way the connection object was created. For the sake of
+     * simplicity, instead of duplicating the whole file we changed the connection object
+     * to use the ProxySelector.
+     */
+    HttpURLConnection connection = (HttpURLConnection) ProxySelector.openConnectionWithProxy(url.toURI());
+
     connection.setConnectTimeout(connectTimeoutMillis);
     connection.setReadTimeout(readTimeoutMillis);
     if (defaultRequestProperties != null) {
       for (Map.Entry<String, String> property : defaultRequestProperties.getSnapshot().entrySet()) {
         connection.setRequestProperty(property.getKey(), property.getValue());
       }
     }
     for (Map.Entry<String, String> property : requestProperties.getSnapshot().entrySet()) {
--- a/modules/libpref/StaticPrefs.h
+++ b/modules/libpref/StaticPrefs.h
@@ -2,16 +2,21 @@
 /* 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_StaticPrefs_h
 #define mozilla_StaticPrefs_h
 
+#include "mozilla/Assertions.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/TypeTraits.h"
+#include "MainThreadUtils.h"
+
 namespace mozilla {
 
 // These typedefs are for use within StaticPrefList.h.
 
 typedef const char* String;
 
 typedef Atomic<bool, Relaxed> RelaxedAtomicBool;
 typedef Atomic<bool, ReleaseAcquire> ReleaseAcquireAtomicBool;
@@ -37,35 +42,46 @@ template<typename T, MemoryOrdering Orde
 struct StripAtomicImpl<Atomic<T, Order>>
 {
   typedef T Type;
 };
 
 template<typename T>
 using StripAtomic = typename StripAtomicImpl<T>::Type;
 
+template<typename T>
+struct IsAtomic : FalseType {};
+
+template<typename T, MemoryOrdering Order>
+struct IsAtomic<Atomic<T, Order>> : TrueType {};
+
 class StaticPrefs
 {
 // For a VarCache pref like this:
 //
 //   VARCACHE_PREF("my.varcache", my_varcache, int32_t, 99)
 //
 // we generate a static variable declaration and a getter definition:
 //
 //   private:
 //     static int32_t sVarCache_my_varcache;
 //   public:
 //     static int32_t my_varcache() { return sVarCache_my_varcache; }
 //
-#define PREF(str, cpp_type, value)
-#define VARCACHE_PREF(str, id, cpp_type, value)                                \
+#define PREF(str, cpp_type, default_value)
+#define VARCACHE_PREF(str, id, cpp_type, default_value)                        \
 private:                                                                       \
   static cpp_type sVarCache_##id;                                              \
 public:                                                                        \
-  static StripAtomic<cpp_type> id() { return sVarCache_##id; }
+  static StripAtomic<cpp_type> id() {                                          \
+    MOZ_ASSERT(IsAtomic<cpp_type>::value || NS_IsMainThread(),                 \
+               "Non-atomic static pref '" str                                  \
+               "' being accessed on background thread");                       \
+    return sVarCache_##id;                                                     \
+  }
 #include "mozilla/StaticPrefList.h"
 #undef PREF
 #undef VARCACHE_PREF
 
 public:
   static void InitAll(bool aIsStartup);
 };
 
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -79,17 +79,17 @@
 
 //---------------------------------------------------------------------------
 // Accessibility prefs
 //---------------------------------------------------------------------------
 
 VARCACHE_PREF(
   "accessibility.monoaudio.enable",
    accessibility_monoaudio_enable,
-  bool, false
+  RelaxedAtomicBool, false
 )
 
 //---------------------------------------------------------------------------
 // DOM prefs
 //---------------------------------------------------------------------------
 
 VARCACHE_PREF(
   "dom.webcomponents.shadowdom.report_usage",
@@ -143,25 +143,25 @@ VARCACHE_PREF(
 )
 
 // Time in milliseconds between the time a network buffer is seen and the timer
 // firing when the timer hasn't fired previously in this parse in the
 // off-the-main-thread HTML5 parser.
 VARCACHE_PREF(
   "html5.flushtimer.initialdelay",
    html5_flushtimer_initialdelay,
-  int32_t, 120
+  RelaxedAtomicInt32, 120
 )
 
 // Time in milliseconds between the time a network buffer is seen and the timer
 // firing when the timer has already fired previously in this parse.
 VARCACHE_PREF(
   "html5.flushtimer.subsequentdelay",
    html5_flushtimer_subsequentdelay,
-  int32_t, 120
+  RelaxedAtomicInt32, 120
 )
 
 //---------------------------------------------------------------------------
 // Layout prefs
 //---------------------------------------------------------------------------
 
 // Is parallel CSS parsing enabled?
 VARCACHE_PREF(
@@ -354,17 +354,17 @@ VARCACHE_PREF(
 #ifdef ANDROID
 # define PREF_VALUE  32768  // Measured in KiB
 #else
 # define PREF_VALUE 512000  // Measured in KiB
 #endif
 VARCACHE_PREF(
   "media.cache_size",
    MediaCacheSize,
-  uint32_t, PREF_VALUE
+  RelaxedAtomicUint32, PREF_VALUE
 )
 #undef PREF_VALUE
 
 // If a resource is known to be smaller than this size (in kilobytes), a
 // memory-backed MediaCache may be used; otherwise the (single shared global)
 // file-backed MediaCache is used.
 VARCACHE_PREF(
   "media.memory_cache_max_size",
@@ -399,60 +399,60 @@ VARCACHE_PREF(
 #ifdef ANDROID
 # define PREF_VALUE 10  // Use a smaller limit to save battery.
 #else
 # define PREF_VALUE 30
 #endif
 VARCACHE_PREF(
   "media.cache_resume_threshold",
    MediaCacheResumeThreshold,
-  int32_t, PREF_VALUE
+  RelaxedAtomicInt32, PREF_VALUE
 )
 #undef PREF_VALUE
 
 // Stop reading ahead when our buffered data is this many seconds ahead of the
 // current playback position. This limit can stop us from using arbitrary
 // amounts of network bandwidth prefetching huge videos.
 #ifdef ANDROID
 # define PREF_VALUE 30  // Use a smaller limit to save battery.
 #else
 # define PREF_VALUE 60
 #endif
 VARCACHE_PREF(
   "media.cache_readahead_limit",
    MediaCacheReadaheadLimit,
-  int32_t, PREF_VALUE
+  RelaxedAtomicInt32, PREF_VALUE
 )
 #undef PREF_VALUE
 
 // AudioSink
 VARCACHE_PREF(
   "media.resampling.enabled",
    MediaResamplingEnabled,
-  bool, false
+  RelaxedAtomicBool, false
 )
 
 #if defined(XP_WIN) || defined(XP_DARWIN) || defined(MOZ_PULSEAUDIO)
 // libcubeb backend implement .get_preferred_channel_layout
 # define PREF_VALUE false
 #else
 # define PREF_VALUE true
 #endif
 VARCACHE_PREF(
   "media.forcestereo.enabled",
    MediaForcestereoEnabled,
-  bool, PREF_VALUE
+  RelaxedAtomicBool, PREF_VALUE
 )
 #undef PREF_VALUE
 
 // VideoSink
 VARCACHE_PREF(
   "media.ruin-av-sync.enabled",
    MediaRuinAvSyncEnabled,
-  bool, false
+  RelaxedAtomicBool, false
 )
 
 // Encrypted Media Extensions
 #if defined(ANDROID)
 # if defined(NIGHTLY_BUILD)
 #  define PREF_VALUE true
 # else
 #  define PREF_VALUE false
@@ -494,44 +494,44 @@ VARCACHE_PREF(
 #endif
 
 // Specifies whether the PDMFactory can create a test decoder that just outputs
 // blank frames/audio instead of actually decoding. The blank decoder works on
 // all platforms.
 VARCACHE_PREF(
   "media.use-blank-decoder",
    MediaUseBlankDecoder,
-  bool, false
+  RelaxedAtomicBool, false
 )
 
 #if defined(XP_WIN)
 # define PREF_VALUE true
 #else
 # define PREF_VALUE false
 #endif
 VARCACHE_PREF(
   "media.gpu-process-decoder",
    MediaGpuProcessDecoder,
-  bool, PREF_VALUE
+  RelaxedAtomicBool, PREF_VALUE
 )
 #undef PREF_VALUE
 
 #ifdef ANDROID
 
 // Enable the MediaCodec PlatformDecoderModule by default.
 VARCACHE_PREF(
   "media.android-media-codec.enabled",
    MediaAndroidMediaCodecEnabled,
-  bool, true
+  RelaxedAtomicBool, true
 )
 
 VARCACHE_PREF(
   "media.android-media-codec.preferred",
    MediaAndroidMediaCodecPreferred,
-  bool, true
+  RelaxedAtomicBool, true
 )
 
 #endif // ANDROID
 
 // WebRTC
 #ifdef MOZ_WEBRTC
 #ifdef ANDROID
 
@@ -569,129 +569,129 @@ VARCACHE_PREF(
 # if defined(XP_MACOSX)
 #  define PREF_VALUE false
 # else
 #  define PREF_VALUE true
 # endif
 VARCACHE_PREF(
   "media.ffmpeg.enabled",
    MediaFfmpegEnabled,
-  bool, PREF_VALUE
+  RelaxedAtomicBool, PREF_VALUE
 )
 #undef PREF_VALUE
 
 VARCACHE_PREF(
   "media.libavcodec.allow-obsolete",
    MediaLibavcodecAllowObsolete,
   bool, false
 )
 
 #endif // MOZ_FFMPEG
 
 #ifdef MOZ_FFVPX
 VARCACHE_PREF(
   "media.ffvpx.enabled",
    MediaFfvpxEnabled,
-  bool, true
+  RelaxedAtomicBool, true
 )
 #endif
 
 #if defined(MOZ_FFMPEG) || defined(MOZ_FFVPX)
 VARCACHE_PREF(
   "media.ffmpeg.low-latency.enabled",
    MediaFfmpegLowLatencyEnabled,
   bool, false
 )
 #endif
 
 #ifdef MOZ_WMF
 
 VARCACHE_PREF(
   "media.wmf.enabled",
    MediaWmfEnabled,
-  bool, true
+  RelaxedAtomicBool, true
 )
 
 // Whether DD should consider WMF-disabled a WMF failure, useful for testing.
 VARCACHE_PREF(
   "media.decoder-doctor.wmf-disabled-is-failure",
    MediaDecoderDoctorWmfDisabledIsFailure,
   bool, false
 )
 
 VARCACHE_PREF(
   "media.wmf.vp9.enabled",
    MediaWmfVp9Enabled,
-  bool, true
+  RelaxedAtomicBool, true
 )
 
 #endif // MOZ_WMF
 
 // Whether to check the decoder supports recycling.
 #ifdef ANDROID
 # define PREF_VALUE true
 #else
 # define PREF_VALUE false
 #endif
 VARCACHE_PREF(
   "media.decoder.recycle.enabled",
    MediaDecoderRecycleEnabled,
-  bool, PREF_VALUE
+  RelaxedAtomicBool, PREF_VALUE
 )
 #undef PREF_VALUE
 
 // Should MFR try to skip to the next key frame?
 VARCACHE_PREF(
   "media.decoder.skip-to-next-key-frame.enabled",
    MediaDecoderSkipToNextKeyFrameEnabled,
-  bool, true
+  RelaxedAtomicBool, true
 )
 
 VARCACHE_PREF(
   "media.gmp.decoder.enabled",
    MediaGmpDecoderEnabled,
-  bool, false
+  RelaxedAtomicBool, false
 )
 
 VARCACHE_PREF(
   "media.eme.audio.blank",
    MediaEmeAudioBlank,
-  bool, false
+  RelaxedAtomicBool, false
 )
 VARCACHE_PREF(
   "media.eme.video.blank",
    MediaEmeVideoBlank,
-  bool, false
+  RelaxedAtomicBool, false
 )
 
 VARCACHE_PREF(
   "media.eme.chromium-api.video-shmems",
    MediaEmeChromiumApiVideoShmems,
-  uint32_t, 6
+  RelaxedAtomicUint32, 6
 )
 
 // Whether to suspend decoding of videos in background tabs.
 VARCACHE_PREF(
   "media.suspend-bkgnd-video.enabled",
    MediaSuspendBkgndVideoEnabled,
-  bool, true
+  RelaxedAtomicBool, true
 )
 
 // Delay, in ms, from time window goes to background to suspending
 // video decoders. Defaults to 10 seconds.
 VARCACHE_PREF(
   "media.suspend-bkgnd-video.delay-ms",
    MediaSuspendBkgndVideoDelayMs,
   RelaxedAtomicUint32, 10000
 )
 
 VARCACHE_PREF(
   "media.dormant-on-pause-timeout-ms",
    MediaDormantOnPauseTimeoutMs,
-  int32_t, 5000
+  RelaxedAtomicInt32, 5000
 )
 
 VARCACHE_PREF(
   "media.webspeech.synth.force_global_queue",
    MediaWebspeechSynthForceGlobalQueue,
   bool, false
 )
 
@@ -752,32 +752,32 @@ VARCACHE_PREF(
   uint32_t, PREF_VALUE
 )
 #undef PREF_VALUE
 
 // Ogg
 VARCACHE_PREF(
   "media.ogg.enabled",
    MediaOggEnabled,
-  bool, true
+  RelaxedAtomicBool, true
 )
 
 // AV1
 VARCACHE_PREF(
   "media.av1.enabled",
    MediaAv1Enabled,
-  bool, true
+  RelaxedAtomicBool, true
 )
 
 // Flac
 // Use new MediaFormatReader architecture for plain ogg.
 VARCACHE_PREF(
   "media.ogg.flac.enabled",
    MediaOggFlacEnabled,
-  bool, true
+  RelaxedAtomicBool, true
 )
 
 VARCACHE_PREF(
   "media.flac.enabled",
    MediaFlacEnabled,
   bool, true
 )
 
@@ -797,27 +797,27 @@ VARCACHE_PREF(
 #ifdef MOZ_FMP4
 # define PREF_VALUE true
 #else
 # define PREF_VALUE false
 #endif
 VARCACHE_PREF(
   "media.mp4.enabled",
    mediaMp4Enabled,
-  bool, PREF_VALUE
+  RelaxedAtomicBool, PREF_VALUE
 )
 #undef PREF_VALUE
 
 // Error/warning handling, Decoder Doctor.
 //
 // Set to true to force demux/decode warnings to be treated as errors.
 VARCACHE_PREF(
   "media.playback.warnings-as-errors",
    MediaPlaybackWarningsAsErrors,
-  bool, false
+  RelaxedAtomicBool, false
 )
 
 // Resume video decoding when the cursor is hovering on a background tab to
 // reduce the resume latency and improve the user experience.
 VARCACHE_PREF(
   "media.resume-bkgnd-video-on-tabhover",
    MediaResumeBkgndVideoOnTabhover,
   bool, true
@@ -834,17 +834,17 @@ VARCACHE_PREF(
   bool, PREF_VALUE
 )
 #undef PREF_VALUE
 
 // Media Seamless Looping
 VARCACHE_PREF(
   "media.seamless-looping",
    MediaSeamlessLooping,
-  bool, true
+  RelaxedAtomicBool, true
 )
 
 //---------------------------------------------------------------------------
 // Network prefs
 //---------------------------------------------------------------------------
 
 // Sub-resources HTTP-authentication:
 //   0 - don't allow sub-resources to open HTTP authentication credentials
--- a/widget/android/GeckoVRManager.h
+++ b/widget/android/GeckoVRManager.h
@@ -4,79 +4,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_GeckoVRManager_h_
 #define mozilla_GeckoVRManager_h_
 
 #include "GeneratedJNINatives.h"
 #include "mozilla/jni/Utils.h"
 
-#if defined(MOZ_ANDROID_GOOGLE_VR)
-#include "gfxVRGVRAPI.h"
-extern bool SetupGVRJNI(JNIEnv* env);
-#endif // defined(MOZ_ANDROID_GOOGLE_VR)
-
 namespace mozilla {
 
 class GeckoVRManager
-    : public mozilla::java::GeckoVRManager::Natives<mozilla::GeckoVRManager>
 {
-  typedef mozilla::java::GeckoVRManager::Natives<mozilla::GeckoVRManager> Super;
 public:
-  static void Init()
-  {
-    Super::Init();
-#if defined(MOZ_ANDROID_GOOGLE_VR)
-    SetupGVRJNI(jni::GetGeckoThreadEnv());
-#endif // defined(MOZ_ANDROID_GOOGLE_VR)
-  }
-
-  static void SetGVRPresentingContext(const int64_t aContext)
-  {
-#if defined(MOZ_ANDROID_GOOGLE_VR)
-    mozilla::gfx::SetGVRPresentingContext((void*)aContext);
-#endif // defined(MOZ_ANDROID_GOOGLE_VR)
-  }
-
-  static void CleanupGVRNonPresentingContext()
-  {
-#if defined(MOZ_ANDROID_GOOGLE_VR)
-    mozilla::gfx::CleanupGVRNonPresentingContext();
-#endif // defined(MOZ_ANDROID_GOOGLE_VR)
+  static void* GetExternalContext() {
+    return reinterpret_cast<void*>(mozilla::java::GeckoVRManager::GetExternalContext());
   }
-
-  static void SetGVRPaused(const bool aPaused)
-  {
-#if defined(MOZ_ANDROID_GOOGLE_VR)
-    mozilla::gfx::SetGVRPaused(aPaused);
-#endif // defined(MOZ_ANDROID_GOOGLE_VR)
-  }
-
-  static void* CreateGVRNonPresentingContext()
-  {
-    return (void*)mozilla::java::GeckoVRManager::CreateGVRNonPresentingContext();
-  }
-
-  static void DestroyGVRNonPresentingContext()
-  {
-    mozilla::java::GeckoVRManager::DestroyGVRNonPresentingContext();
-  }
-
-  static void EnableVRMode()
-  {
-    mozilla::java::GeckoVRManager::EnableVRMode();
-  }
-
-  static void DisableVRMode()
-  {
-    mozilla::java::GeckoVRManager::DisableVRMode();
-  }
-
-  static bool IsGVRPresent()
-  {
-    return mozilla::java::GeckoVRManager::IsGVRPresent();
-  }
-
 };
 
 } // namespace mozilla
 
 #endif // mozilla_GeckoVRManager_h_
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -420,17 +420,16 @@ nsAppShell::nsAppShell()
         AndroidBridge::ConstructBridge();
         GeckoAppShellSupport::Init();
         GeckoThreadSupport::Init();
         mozilla::GeckoBatteryManager::Init();
         mozilla::GeckoNetworkManager::Init();
         mozilla::GeckoProcessManager::Init();
         mozilla::GeckoScreenOrientation::Init();
         mozilla::PrefsHelper::Init();
-        mozilla::GeckoVRManager::Init();
         nsWindow::InitNatives();
 
         if (jni::IsFennec()) {
             BrowserLocaleManagerSupport::Init();
             mozilla::ANRReporter::Init();
             mozilla::MemoryMonitor::Init();
             mozilla::widget::Telemetry::Init();
             mozilla::ThumbnailHelper::Init();
--- a/xpcom/ds/nsGkAtomList.h
+++ b/xpcom/ds/nsGkAtomList.h
@@ -878,16 +878,17 @@ GK_ATOM(output, "output")
 GK_ATOM(overflow, "overflow")
 GK_ATOM(overlay, "overlay")
 GK_ATOM(p, "p")
 GK_ATOM(pack, "pack")
 GK_ATOM(page, "page")
 GK_ATOM(pageincrement, "pageincrement")
 GK_ATOM(paint_order, "paint-order")
 GK_ATOM(panel, "panel")
+GK_ATOM(paragraph, "paragraph")
 GK_ATOM(param, "param")
 GK_ATOM(parameter, "parameter")
 GK_ATOM(parent, "parent")
 GK_ATOM(parentfocused, "parentfocused")
 GK_ATOM(password, "password")
 GK_ATOM(pattern, "pattern")
 GK_ATOM(patternSeparator, "pattern-separator")
 GK_ATOM(perMille, "per-mille")
--- a/xpcom/io/InputStreamLengthHelper.cpp
+++ b/xpcom/io/InputStreamLengthHelper.cpp
@@ -152,18 +152,20 @@ InputStreamLengthHelper::GetAsyncLength(
   // Let's be sure that we don't call ::Available() on main-thread.
   if (NS_IsMainThread()) {
     nsCOMPtr<nsIInputStreamLength> streamLength = do_QueryInterface(aStream);
     nsCOMPtr<nsIAsyncInputStreamLength> asyncStreamLength =
       do_QueryInterface(aStream);
     if (!streamLength && !asyncStreamLength) {
       // We cannot calculate the length of an async stream. We must fix the
       // caller if this happens.
+#ifdef DEBUG
       nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
       MOZ_DIAGNOSTIC_ASSERT(!asyncStream);
+#endif
 
       bool nonBlocking = false;
       if (NS_SUCCEEDED(aStream->IsNonBlocking(&nonBlocking)) && !nonBlocking) {
         nsCOMPtr<nsIEventTarget> target =
           do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
         MOZ_ASSERT(target);
 
         RefPtr<AvailableEvent> event = new AvailableEvent(aStream, aCallback);