Bug 1373739 - Make headless compositing Windows-compatible, in addition to Linux. r=dvander
authorMichael Smith <michael@spinda.net>
Thu, 06 Jul 2017 17:45:34 -0700
changeset 372869 db5a86cfd703c9bd245fd3bb26f2163c4b91b6ab
parent 372868 3a9f911d58cda8c5641a367142bf2193c3dd81a8
child 372870 dd5fea40c368a48555530c920fcd5300ccd384f1
push id93424
push userarchaeopteryx@coole-files.de
push dateFri, 04 Aug 2017 17:33:26 +0000
treeherdermozilla-inbound@5e140881ed5b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs1373739
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1373739 - Make headless compositing Windows-compatible, in addition to Linux. r=dvander To make the HeadlessCompositorWidget work under Windows as well as Linux, I had to change the way that I hooked it into the existing CompositorWidget system. Under GTK, the CompositorWidgetInitData and CompositorWidgetDelegate types provided the information needed by the headless compositor widget already (the widget client size). On Windows, however, the definitions of these types differ, and the client size information is simply retrieved from the platform APIs when needed. After this patch, CompositorWidgetDelegate is renamed to PlatformCompositorWidgetDelegate, and a new base class called CompositorWidgetDelegate is added with "AsPlatformSpecificDelegate()" and "AsHeadlessCompositorWidget()" methods. In non-headless mode, widgets use AsPlatformSpecificDelegate() to access the Windows- and GTK-specific delegate APIs. In headless mode, AsHeadlessCompositorWidget() is used to access the singular CompositorWidget implementation for headless. Meanwhile, the CompositorWidgetInitData IPDL type is made into a union which always contains a headless-specific HeadlessCompositorWidgetInitData struct and under GTK and Windows also contains an {X11,Win}CompositorWidgetInitData struct. This also includes a small patch to ensure that the GPU process and hardware-accelerated compositing are always disabled under headless mode. These features weren't activated by default in the Linux environments I tested in, but did end up activating (and then promptly crashing Firefox) when I tested on Windows. MozReview-Commit-ID: CocPoHBDV7H
gfx/ipc/GPUProcessHost.cpp
gfx/ipc/RemoteCompositorSession.cpp
gfx/thebes/gfxPlatform.cpp
widget/CompositorWidget.h
widget/PlatformWidgetTypes.ipdlh
widget/gtk/CompositorWidgetChild.cpp
widget/gtk/CompositorWidgetChild.h
widget/gtk/CompositorWidgetParent.cpp
widget/gtk/InProcessX11CompositorWidget.cpp
widget/gtk/InProcessX11CompositorWidget.h
widget/gtk/PlatformWidgetTypes.ipdlh
widget/gtk/X11CompositorWidget.cpp
widget/gtk/X11CompositorWidget.h
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
widget/headless/HeadlessCompositorWidget.cpp
widget/headless/HeadlessCompositorWidget.h
widget/headless/HeadlessWidget.cpp
widget/headless/HeadlessWidget.h
widget/headless/HeadlessWidgetTypes.ipdlh
widget/moz.build
widget/nsBaseWidget.cpp
widget/nsBaseWidget.h
widget/windows/CompositorWidgetChild.cpp
widget/windows/CompositorWidgetChild.h
widget/windows/CompositorWidgetParent.cpp
widget/windows/InProcessWinCompositorWidget.cpp
widget/windows/InProcessWinCompositorWidget.h
widget/windows/PlatformWidgetTypes.ipdlh
widget/windows/WinCompositorWidget.cpp
widget/windows/WinCompositorWidget.h
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
--- a/gfx/ipc/GPUProcessHost.cpp
+++ b/gfx/ipc/GPUProcessHost.cpp
@@ -33,16 +33,17 @@ GPUProcessHost::~GPUProcessHost()
   MOZ_COUNT_DTOR(GPUProcessHost);
 }
 
 bool
 GPUProcessHost::Launch()
 {
   MOZ_ASSERT(mLaunchPhase == LaunchPhase::Unlaunched);
   MOZ_ASSERT(!mGPUChild);
+  MOZ_ASSERT(!gfxPlatform::IsHeadless());
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
   mSandboxLevel = Preferences::GetInt("security.sandbox.gpu.level");
 #endif
 
   mLaunchPhase = LaunchPhase::Waiting;
   mLaunchTime = TimeStamp::Now();
 
--- a/gfx/ipc/RemoteCompositorSession.cpp
+++ b/gfx/ipc/RemoteCompositorSession.cpp
@@ -24,16 +24,17 @@ RemoteCompositorSession::RemoteComposito
                                                  CompositorBridgeChild* aChild,
                                                  CompositorWidgetDelegate* aWidgetDelegate,
                                                  APZCTreeManagerChild* aAPZ,
                                                  const uint64_t& aRootLayerTreeId)
  : CompositorSession(aWidgetDelegate, aChild, aRootLayerTreeId),
    mWidget(aWidget),
    mAPZ(aAPZ)
 {
+  MOZ_ASSERT(!gfxPlatform::IsHeadless());
   GPUProcessManager::Get()->RegisterRemoteProcessSession(this);
   if (mAPZ) {
     mAPZ->SetCompositorSession(this);
   }
 }
 
 RemoteCompositorSession::~RemoteCompositorSession()
 {
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2357,16 +2357,23 @@ gfxPlatform::InitGPUProcessPrefs()
       true,
       gfxPrefs::GetGPUProcessEnabledPrefDefault());
   }
 
   if (gfxPrefs::GPUProcessForceEnabled()) {
     gpuProc.UserForceEnable("User force-enabled via pref");
   }
 
+  if (IsHeadless()) {
+    gpuProc.ForceDisable(
+      FeatureStatus::Blocked,
+      "Headless mode is enabled",
+      NS_LITERAL_CSTRING("FEATURE_FAILURE_HEADLESS_MODE"));
+    return;
+  }
   if (InSafeMode()) {
     gpuProc.ForceDisable(
       FeatureStatus::Blocked,
       "Safe-mode is enabled",
       NS_LITERAL_CSTRING("FEATURE_FAILURE_SAFE_MODE"));
     return;
   }
   if (gfxPrefs::LayerScopeEnabled()) {
@@ -2403,21 +2410,25 @@ gfxPlatform::InitCompositorAccelerationP
     }
   }
 
   // This has specific meaning elsewhere, so we always record it.
   if (gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly()) {
     feature.UserForceEnable("Force-enabled by pref");
   }
 
-  // Safe mode trumps everything.
+  // Safe and headless modes override everything.
   if (InSafeMode()) {
     feature.ForceDisable(FeatureStatus::Blocked, "Acceleration blocked by safe-mode",
                          NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_SAFEMODE"));
   }
+  if (IsHeadless()) {
+    feature.ForceDisable(FeatureStatus::Blocked, "Acceleration blocked by headless mode",
+                         NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_HEADLESSMODE"));
+  }
 }
 
 void
 gfxPlatform::InitWebRenderConfig()
 {
   bool prefEnabled = Preferences::GetBool("gfx.webrender.enabled", false);
 
   ScopedGfxFeatureReporter reporter("WR", prefEnabled);
--- a/widget/CompositorWidget.h
+++ b/widget/CompositorWidget.h
@@ -37,17 +37,32 @@ class X11CompositorWidget;
 class AndroidCompositorWidget;
 class CompositorWidgetInitData;
 
 // Gecko widgets usually need to communicate with the CompositorWidget with
 // platform-specific messages (for example to update the window size or
 // transparency). This functionality is controlled through a "host". Since
 // this functionality is platform-dependent, it is only forward declared
 // here.
-class CompositorWidgetDelegate;
+class PlatformCompositorWidgetDelegate;
+
+// Headless mode uses its own, singular CompositorWidget implementation.
+class HeadlessCompositorWidget;
+
+class CompositorWidgetDelegate
+{
+public:
+  virtual PlatformCompositorWidgetDelegate* AsPlatformSpecificDelegate() {
+    return nullptr;
+  }
+
+  virtual HeadlessCompositorWidget* AsHeadlessCompositorWidget() {
+    return nullptr;
+  }
+};
 
 // Platforms that support out-of-process widgets.
 #if defined(XP_WIN) || defined(MOZ_X11)
 // CompositorWidgetParent should implement CompositorWidget and
 // PCompositorWidgetParent.
 class CompositorWidgetParent;
 
 // CompositorWidgetChild should implement CompositorWidgetDelegate and
--- a/widget/PlatformWidgetTypes.ipdlh
+++ b/widget/PlatformWidgetTypes.ipdlh
@@ -2,17 +2,25 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=99: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // This file is a stub, for platforms that do not yet support out-of-process
 // compositing or do not need specialized types to do so.
 
+include HeadlessWidgetTypes;
+
 namespace mozilla {
 namespace widget {
 
-struct CompositorWidgetInitData
+union CompositorWidgetInitData
 {
+  HeadlessCompositorWidgetInitData;
+};
+
+struct HeadlessCompositorWidgetInitData
+{
+  LayoutDeviceIntSize InitialClientSize;
 };
 
 } // namespace widget
 } // namespace mozilla
--- a/widget/gtk/CompositorWidgetChild.cpp
+++ b/widget/gtk/CompositorWidgetChild.cpp
@@ -1,25 +1,27 @@
 /* -*- 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 "CompositorWidgetChild.h"
 #include "mozilla/Unused.h"
+#include "gfxPlatform.h"
 
 namespace mozilla {
 namespace widget {
 
 CompositorWidgetChild::CompositorWidgetChild(RefPtr<CompositorVsyncDispatcher> aVsyncDispatcher,
                                              RefPtr<CompositorWidgetVsyncObserver> aVsyncObserver)
   : mVsyncDispatcher(aVsyncDispatcher)
   , mVsyncObserver(aVsyncObserver)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(!gfxPlatform::IsHeadless());
 }
 
 CompositorWidgetChild::~CompositorWidgetChild()
 {
 }
 
 mozilla::ipc::IPCResult
 CompositorWidgetChild::RecvObserveVsync()
--- a/widget/gtk/CompositorWidgetChild.h
+++ b/widget/gtk/CompositorWidgetChild.h
@@ -10,17 +10,17 @@
 #include "mozilla/widget/PCompositorWidgetChild.h"
 #include "mozilla/widget/CompositorWidgetVsyncObserver.h"
 
 namespace mozilla {
 namespace widget {
 
 class CompositorWidgetChild final
  : public PCompositorWidgetChild
- , public CompositorWidgetDelegate
+ , public PlatformCompositorWidgetDelegate
 {
 public:
   CompositorWidgetChild(RefPtr<CompositorVsyncDispatcher> aVsyncDispatcher,
                         RefPtr<CompositorWidgetVsyncObserver> aVsyncObserver);
   ~CompositorWidgetChild() override;
 
   mozilla::ipc::IPCResult RecvObserveVsync() override;
   mozilla::ipc::IPCResult RecvUnobserveVsync() override;
--- a/widget/gtk/CompositorWidgetParent.cpp
+++ b/widget/gtk/CompositorWidgetParent.cpp
@@ -1,22 +1,23 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "CompositorWidgetParent.h"
 #include "mozilla/Unused.h"
+#include "mozilla/widget/PlatformWidgetTypes.h"
 
 namespace mozilla {
 namespace widget {
 
 CompositorWidgetParent::CompositorWidgetParent(const CompositorWidgetInitData& aInitData,
                                                const layers::CompositorOptions& aOptions)
- : X11CompositorWidget(aInitData, aOptions)
+ : X11CompositorWidget(aInitData.get_X11CompositorWidgetInitData(), aOptions)
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
 }
 
 CompositorWidgetParent::~CompositorWidgetParent()
 {
 }
 
--- a/widget/gtk/InProcessX11CompositorWidget.cpp
+++ b/widget/gtk/InProcessX11CompositorWidget.cpp
@@ -1,36 +1,38 @@
 /* -*- 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 "gfxPlatform.h"
 #include "HeadlessCompositorWidget.h"
 #include "HeadlessWidget.h"
+#include "mozilla/widget/PlatformWidgetTypes.h"
 
 #include "InProcessX11CompositorWidget.h"
 #include "nsWindow.h"
 
 namespace mozilla {
 namespace widget {
 
 /* static */ RefPtr<CompositorWidget>
 CompositorWidget::CreateLocal(const CompositorWidgetInitData& aInitData,
                               const layers::CompositorOptions& aOptions,
                               nsIWidget* aWidget)
 {
-  if (gfxPlatform::IsHeadless()) {
-    return new HeadlessCompositorWidget(aInitData, aOptions, static_cast<HeadlessWidget*>(aWidget));
+  if (aInitData.type() == CompositorWidgetInitData::THeadlessCompositorWidgetInitData) {
+    return new HeadlessCompositorWidget(aInitData.get_HeadlessCompositorWidgetInitData(),
+                                        aOptions, static_cast<HeadlessWidget*>(aWidget));
   } else {
-    return new InProcessX11CompositorWidget(aInitData, aOptions, static_cast<nsWindow*>(aWidget));
+    return new InProcessX11CompositorWidget(aInitData.get_X11CompositorWidgetInitData(),
+                                            aOptions, static_cast<nsWindow*>(aWidget));
   }
 }
 
-InProcessX11CompositorWidget::InProcessX11CompositorWidget(const CompositorWidgetInitData& aInitData,
+InProcessX11CompositorWidget::InProcessX11CompositorWidget(const X11CompositorWidgetInitData& aInitData,
                                                            const layers::CompositorOptions& aOptions,
                                                            nsWindow* aWindow)
   : X11CompositorWidget(aInitData, aOptions, aWindow)
 {
 }
 
 void
 InProcessX11CompositorWidget::ObserveVsync(VsyncObserver* aObserver)
--- a/widget/gtk/InProcessX11CompositorWidget.h
+++ b/widget/gtk/InProcessX11CompositorWidget.h
@@ -11,17 +11,17 @@
 class nsWindow;
 
 namespace mozilla {
 namespace widget {
 
 class InProcessX11CompositorWidget final : public X11CompositorWidget
 {
 public:
-  InProcessX11CompositorWidget(const CompositorWidgetInitData& aInitData,
+  InProcessX11CompositorWidget(const X11CompositorWidgetInitData& aInitData,
                                const layers::CompositorOptions& aOptions,
                                nsWindow* aWindow);
 
   // CompositorWidgetDelegate
 
   void ObserveVsync(VsyncObserver* aObserver) override;
 };
 
--- a/widget/gtk/PlatformWidgetTypes.ipdlh
+++ b/widget/gtk/PlatformWidgetTypes.ipdlh
@@ -1,24 +1,29 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=99: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-// This file is a stub, for platforms that do not yet support out-of-process
-// compositing or do not need specialized types to do so.
+include HeadlessWidgetTypes;
 
 using mozilla::LayoutDeviceIntSize from "Units.h";
 
 namespace mozilla {
 namespace widget {
 
-struct CompositorWidgetInitData
+struct X11CompositorWidgetInitData
 {
   uintptr_t           XWindow;
   nsCString           XDisplayString;
 
   LayoutDeviceIntSize InitialClientSize;
 };
 
+union CompositorWidgetInitData
+{
+  X11CompositorWidgetInitData;
+  HeadlessCompositorWidgetInitData;
+};
+
 } // namespace widget
 } // namespace mozilla
--- a/widget/gtk/X11CompositorWidget.cpp
+++ b/widget/gtk/X11CompositorWidget.cpp
@@ -9,17 +9,17 @@
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/widget/InProcessCompositorWidget.h"
 #include "mozilla/widget/PlatformWidgetTypes.h"
 #include "nsWindow.h"
 
 namespace mozilla {
 namespace widget {
 
-X11CompositorWidget::X11CompositorWidget(const CompositorWidgetInitData& aInitData,
+X11CompositorWidget::X11CompositorWidget(const X11CompositorWidgetInitData& aInitData,
                                          const CompositorOptions& aOptions,
                                          nsWindow* aWindow)
       : CompositorWidget(aOptions)
       , mWidget(aWindow)
 {
   // If we have a nsWindow, then grab the already existing display connection
   // If we don't, then use the init data to connect to the display
   if (aWindow) {
--- a/widget/gtk/X11CompositorWidget.h
+++ b/widget/gtk/X11CompositorWidget.h
@@ -10,54 +10,66 @@
 #include "WindowSurfaceProvider.h"
 
 class nsIWidget;
 class nsWindow;
 
 namespace mozilla {
 namespace widget {
 
-class CompositorWidgetDelegate
+class PlatformCompositorWidgetDelegate
+  : public CompositorWidgetDelegate
 {
 public:
   virtual void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) = 0;
+
+  // CompositorWidgetDelegate Overrides
+
+  PlatformCompositorWidgetDelegate* AsPlatformSpecificDelegate() override {
+    return this;
+  }
 };
 
+class X11CompositorWidgetInitData;
+
 class X11CompositorWidget
  : public CompositorWidget
- , public CompositorWidgetDelegate
+ , public PlatformCompositorWidgetDelegate
 {
 public:
-  X11CompositorWidget(const CompositorWidgetInitData& aInitData,
+  X11CompositorWidget(const X11CompositorWidgetInitData& aInitData,
                       const layers::CompositorOptions& aOptions,
                       nsWindow* aWindow = nullptr);
   ~X11CompositorWidget();
 
   // CompositorWidget Overrides
 
   already_AddRefed<gfx::DrawTarget> StartRemoteDrawing() override;
   void EndRemoteDrawing() override;
 
   already_AddRefed<gfx::DrawTarget>
   StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion,
                              layers::BufferMode* aBufferMode) override;
   void EndRemoteDrawingInRegion(gfx::DrawTarget* aDrawTarget,
                                 LayoutDeviceIntRegion& aInvalidRegion) override;
   uintptr_t GetWidgetKey() override;
 
-  void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) override;
   LayoutDeviceIntSize GetClientSize() override;
 
   nsIWidget* RealWidget() override;
   X11CompositorWidget* AsX11() override { return this; }
   CompositorWidgetDelegate* AsDelegate() override { return this; }
 
   Display* XDisplay() const { return mXDisplay; }
   Window XWindow() const { return mXWindow; }
 
+  // PlatformCompositorWidgetDelegate Overrides
+
+  void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) override;
+
 protected:
   nsWindow* mWidget;
 
 private:
   LayoutDeviceIntSize mClientSize;
 
   Display* mXDisplay;
   Window   mXWindow;
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -432,16 +432,17 @@ nsWindow::nsWindow()
     mHandleTouchEvent    = false;
 #endif
     mIsDragPopup         = false;
     mIsX11Display        = GDK_IS_X11_DISPLAY(gdk_display_get_default());
 
     mContainer           = nullptr;
     mGdkWindow           = nullptr;
     mShell               = nullptr;
+    mCompositorWidgetDelegate = nullptr;
     mHasMappedToplevel   = false;
     mIsFullyObscured     = false;
     mRetryPointerGrab    = false;
     mWindowType          = eWindowType_child;
     mSizeState           = nsSizeMode_Normal;
     mLastSizeMode        = nsSizeMode_Normal;
     mSizeConstraints.mMaxSize = GetSafeWindowSize(mSizeConstraints.mMaxSize);
 
@@ -6525,16 +6526,28 @@ nsWindow::GetLayerManager(PLayerTransact
     {
         mLayerManager = CreateBasicLayerManager();
     }
 
     return nsBaseWidget::GetLayerManager(aShadowManager, aBackendHint, aPersistence);
 }
 
 void
+nsWindow::SetCompositorWidgetDelegate(CompositorWidgetDelegate* delegate)
+{
+    if (delegate) {
+        mCompositorWidgetDelegate = delegate->AsPlatformSpecificDelegate();
+        MOZ_ASSERT(mCompositorWidgetDelegate,
+                   "nsWindow::SetCompositorWidgetDelegate called with a non-PlatformCompositorWidgetDelegate");
+    } else {
+        mCompositorWidgetDelegate = nullptr;
+    }
+}
+
+void
 nsWindow::ClearCachedResources()
 {
     if (mLayerManager &&
         mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_BASIC) {
         mLayerManager->ClearCachedResources();
     }
 
     GList* children = gdk_window_peek_children(mGdkWindow);
@@ -6820,17 +6833,17 @@ int32_t
 nsWindow::RoundsWidgetCoordinatesTo()
 {
     return GdkScaleFactor();
 }
 
 void nsWindow::GetCompositorWidgetInitData(mozilla::widget::CompositorWidgetInitData* aInitData)
 {
   #ifdef MOZ_X11
-  *aInitData = mozilla::widget::CompositorWidgetInitData(
+  *aInitData = mozilla::widget::X11CompositorWidgetInitData(
                                   mXWindow,
                                   nsCString(XDisplayString(mXDisplay)),
                                   GetClientSize());
   #endif
 }
 
 bool
 nsWindow::IsComposited() const
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -12,16 +12,17 @@
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "nsIDragService.h"
 #include "nsITimer.h"
 #include "nsGkAtoms.h"
 #include "nsRefPtrHashtable.h"
 
 #include "nsBaseWidget.h"
+#include "CompositorWidget.h"
 #include <gdk/gdk.h>
 #include <gtk/gtk.h>
 
 #ifdef MOZ_X11
 #include <gdk/gdkx.h>
 #endif /* MOZ_X11 */
 
 #include "mozilla/widget/WindowSurface.h"
@@ -68,16 +69,17 @@ class TimeStamp;
 class CurrentX11TimeGetter;
 }
 
 class nsWindow final : public nsBaseWidget
 {
 public:
     typedef mozilla::gfx::DrawTarget DrawTarget;
     typedef mozilla::WidgetEventTime WidgetEventTime;
+    typedef mozilla::widget::PlatformCompositorWidgetDelegate PlatformCompositorWidgetDelegate;
 
     nsWindow();
 
     static void ReleaseGlobals();
 
     NS_DECL_ISUPPORTS_INHERITED
 
     void CommonCreate(nsIWidget *aParent, bool aListenForResizes);
@@ -431,16 +433,18 @@ private:
     void               ClearCachedResources();
     nsIWidgetListener* GetListener();
     bool               IsComposited() const;
 
 
     GtkWidget          *mShell;
     MozContainer       *mContainer;
     GdkWindow          *mGdkWindow;
+    PlatformCompositorWidgetDelegate* mCompositorWidgetDelegate;
+
 
     uint32_t            mHasMappedToplevel : 1,
                         mIsFullyObscured : 1,
                         mRetryPointerGrab : 1;
     nsSizeMode          mSizeState;
 
     int32_t             mTransparencyBitmapWidth;
     int32_t             mTransparencyBitmapHeight;
@@ -536,16 +540,18 @@ private:
 
     void DispatchMissedButtonReleases(GdkEventCrossing *aGdkEvent);
 
     // nsBaseWidget
     virtual LayerManager* GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
                                           LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
                                           LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT) override;
 
+    void SetCompositorWidgetDelegate(CompositorWidgetDelegate* delegate) override;
+
     void CleanLayerManagerRecursive();
 
     virtual int32_t RoundsWidgetCoordinatesTo() override;
 
     /**
      * |mIMContext| takes all IME related stuff.
      *
      * This is owned by the top-level nsWindow or the topmost child
--- a/widget/headless/HeadlessCompositorWidget.cpp
+++ b/widget/headless/HeadlessCompositorWidget.cpp
@@ -5,17 +5,17 @@
 
 #include "mozilla/widget/PlatformWidgetTypes.h"
 #include "HeadlessCompositorWidget.h"
 #include "VsyncDispatcher.h"
 
 namespace mozilla {
 namespace widget {
 
-HeadlessCompositorWidget::HeadlessCompositorWidget(const CompositorWidgetInitData& aInitData,
+HeadlessCompositorWidget::HeadlessCompositorWidget(const HeadlessCompositorWidgetInitData& aInitData,
                                                    const layers::CompositorOptions& aOptions,
                                                    HeadlessWidget* aWindow)
       : CompositorWidget(aOptions)
       , mWidget(aWindow)
 {
   mClientSize = aInitData.InitialClientSize();
 }
 
--- a/widget/headless/HeadlessCompositorWidget.h
+++ b/widget/headless/HeadlessCompositorWidget.h
@@ -2,44 +2,52 @@
 /* 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 widget_headless_HeadlessCompositorWidget_h
 #define widget_headless_HeadlessCompositorWidget_h
 
 #include "mozilla/widget/CompositorWidget.h"
-#include "InProcessX11CompositorWidget.h"
 
 #include "HeadlessWidget.h"
 
 namespace mozilla {
 namespace widget {
 
+class HeadlessCompositorWidgetInitData;
+
 class HeadlessCompositorWidget final
   : public CompositorWidget
   , public CompositorWidgetDelegate
 {
 public:
-  HeadlessCompositorWidget(const CompositorWidgetInitData& aInitData,
+  HeadlessCompositorWidget(const HeadlessCompositorWidgetInitData& aInitData,
                            const layers::CompositorOptions& aOptions,
                            HeadlessWidget* aWindow);
 
+  void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize);
+
   // CompositorWidget Overrides
 
   uintptr_t GetWidgetKey() override;
 
-  void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) override;
   LayoutDeviceIntSize GetClientSize() override;
 
   nsIWidget* RealWidget() override;
   CompositorWidgetDelegate* AsDelegate() override { return this; }
 
   void ObserveVsync(VsyncObserver* aObserver) override;
 
+  // CompositorWidgetDelegate Overrides
+
+  HeadlessCompositorWidget* AsHeadlessCompositorWidget() override {
+    return this;
+  }
+
 private:
   HeadlessWidget* mWidget;
 
   LayoutDeviceIntSize mClientSize;
 };
 
 } // namespace widget
 } // namespace mozilla
--- a/widget/headless/HeadlessWidget.cpp
+++ b/widget/headless/HeadlessWidget.cpp
@@ -32,16 +32,27 @@ CreateDefaultTarget(IntSize aSize)
   RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(target);
   return ctx.forget();
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(HeadlessWidget, nsBaseWidget)
 
 HeadlessWidget* HeadlessWidget::sActiveWindow = nullptr;
 
+HeadlessWidget::HeadlessWidget()
+  : mEnabled(true)
+  , mVisible(false)
+  , mTopLevel(nullptr)
+  , mCompositorWidget(nullptr)
+  , mLastSizeMode(nsSizeMode_Normal)
+  , mEffectiveSizeMode(nsSizeMode_Normal)
+  , mRestoreBounds(0,0,0,0)
+{
+}
+
 HeadlessWidget::~HeadlessWidget()
 {
   if (sActiveWindow == this)
     sActiveWindow = nullptr;
 }
 
 nsresult
 HeadlessWidget::Create(nsIWidget* aParent,
@@ -50,18 +61,16 @@ HeadlessWidget::Create(nsIWidget* aParen
                        nsWidgetInitData* aInitData)
 {
   MOZ_ASSERT(!aNativeParent, "No native parents for headless widgets.");
 
   BaseCreate(nullptr, aInitData);
 
   mBounds = aRect;
   mRestoreBounds = aRect;
-  mVisible = false;
-  mEnabled = true;
 
   if (aParent) {
     mTopLevel = aParent->GetTopLevelWidget();
   } else {
     mTopLevel = this;
   }
 
   return NS_OK;
@@ -79,23 +88,17 @@ HeadlessWidget::CreateChild(const Layout
   if (NS_FAILED(widget->Create(this, nullptr, aRect, aInitData))) {
     return nullptr;
   }
   return widget.forget();
 }
 
 void HeadlessWidget::GetCompositorWidgetInitData(mozilla::widget::CompositorWidgetInitData* aInitData)
 {
-  uintptr_t xWindow(0);
-  nsCString xDisplayString(0);
-
-  *aInitData = mozilla::widget::CompositorWidgetInitData(
-                                  xWindow,
-                                  xDisplayString,
-                                  GetClientSize());
+  *aInitData = mozilla::widget::HeadlessCompositorWidgetInitData(GetClientSize());
 }
 
 nsIWidget*
 HeadlessWidget::GetTopLevelWidget()
 {
   return mTopLevel;
 }
 
@@ -203,28 +206,39 @@ LayerManager*
 HeadlessWidget::GetLayerManager(PLayerTransactionChild* aShadowManager,
                                 LayersBackend aBackendHint,
                                 LayerManagerPersistence aPersistence)
 {
   return nsBaseWidget::GetLayerManager(aShadowManager, aBackendHint, aPersistence);
 }
 
 void
+HeadlessWidget::SetCompositorWidgetDelegate(CompositorWidgetDelegate* delegate)
+{
+    if (delegate) {
+        mCompositorWidget = delegate->AsHeadlessCompositorWidget();
+        MOZ_ASSERT(mCompositorWidget,
+                   "HeadlessWidget::SetCompositorWidgetDelegate called with a non-HeadlessCompositorWidget");
+    } else {
+        mCompositorWidget = nullptr;
+    }
+}
+
+void
 HeadlessWidget::Resize(double aWidth,
                        double aHeight,
                        bool   aRepaint)
 {
   int32_t width = NSToIntRound(aWidth);
   int32_t height = NSToIntRound(aHeight);
   ConstrainSize(&width, &height);
   mBounds.SizeTo(LayoutDeviceIntSize(width, height));
 
-  if (mCompositorWidgetDelegate) {
-    mCompositorWidgetDelegate->NotifyClientSizeChanged(
-        LayoutDeviceIntSize(mBounds.width, mBounds.height));
+  if (mCompositorWidget) {
+    mCompositorWidget->NotifyClientSizeChanged(LayoutDeviceIntSize(mBounds.width, mBounds.height));
   }
   if (mWidgetListener) {
     mWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
   }
   if (mAttachedWidgetListener) {
     mAttachedWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
   }
 }
--- a/widget/headless/HeadlessWidget.h
+++ b/widget/headless/HeadlessWidget.h
@@ -4,24 +4,25 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #ifndef HEADLESSWIDGET_H
 #define HEADLESSWIDGET_H
 
 #include "mozilla/widget/InProcessCompositorWidget.h"
 #include "nsBaseWidget.h"
+#include "CompositorWidget.h"
 
 namespace mozilla {
 namespace widget {
 
 class HeadlessWidget : public nsBaseWidget
 {
 public:
-  HeadlessWidget() : mEffectiveSizeMode(nsSizeMode_Normal) {}
+  HeadlessWidget();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   void* GetNativeData(uint32_t aDataType) override
   {
     // Headless widgets have no native data.
     return nullptr;
   }
@@ -80,24 +81,27 @@ public:
     return mInputContext;
   }
 
   virtual LayerManager*
   GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
                   LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
                   LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT) override;
 
+  void SetCompositorWidgetDelegate(CompositorWidgetDelegate* delegate) override;
+
   virtual nsresult DispatchEvent(WidgetGUIEvent* aEvent,
                                  nsEventStatus& aStatus) override;
 
 private:
   ~HeadlessWidget();
   bool mEnabled;
   bool mVisible;
   nsIWidget* mTopLevel;
+  HeadlessCompositorWidget* mCompositorWidget;
   // The size mode before entering fullscreen mode.
   nsSizeMode mLastSizeMode;
   // The last size mode set while the window was visible.
   nsSizeMode mEffectiveSizeMode;
   InputContext mInputContext;
   // In headless there is no window manager to track window bounds
   // across size mode changes, so we must track it to emulate.
   LayoutDeviceIntRect mRestoreBounds;
new file mode 100644
--- /dev/null
+++ b/widget/headless/HeadlessWidgetTypes.ipdlh
@@ -0,0 +1,18 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* 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/. */
+
+using mozilla::LayoutDeviceIntSize from "Units.h";
+
+namespace mozilla {
+namespace widget {
+
+struct HeadlessCompositorWidgetInitData
+{
+  LayoutDeviceIntSize InitialClientSize;
+};
+
+} // namespace widget
+} // namespace mozilla
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -287,26 +287,29 @@ LOCAL_INCLUDES += [
     '/layout/xul',
     '/view',
     '/widget',
     '/widget/headless',
 ]
 
 if toolkit == 'windows':
     IPDL_SOURCES = [
+        'headless/HeadlessWidgetTypes.ipdlh',
         'windows/PCompositorWidget.ipdl',
         'windows/PlatformWidgetTypes.ipdlh',
     ]
 elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT'] and CONFIG['MOZ_X11']:
     IPDL_SOURCES = [
         'gtk/PCompositorWidget.ipdl',
         'gtk/PlatformWidgetTypes.ipdlh',
+        'headless/HeadlessWidgetTypes.ipdlh',
     ]
 else:
     IPDL_SOURCES = [
+        'headless/HeadlessWidgetTypes.ipdlh',
         'PCompositorWidget.ipdl',
         'PlatformWidgetTypes.ipdlh',
     ]
 
 widget_dir = toolkit
 if widget_dir in ('gtk3', 'gtk2'):
     # gtk3 shares includes with gtk2
     widget_dir = 'gtk'
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -161,17 +161,16 @@ nsBaseWidget::nsBaseWidget()
 , mBorderStyle(eBorderStyle_none)
 , mBounds(0,0,0,0)
 , mOriginalBounds(nullptr)
 , mClipRectCount(0)
 , mSizeMode(nsSizeMode_Normal)
 , mPopupLevel(ePopupLevelTop)
 , mPopupType(ePopupTypeAny)
 , mHasRemoteContent(false)
-, mCompositorWidgetDelegate(nullptr)
 , mUpdateCursor(true)
 , mUseAttachedEvents(false)
 , mIMEHasFocus(false)
 , mIsFullyOccluded(false)
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
 , mAccessibilityInUseFlag(false)
 #endif
 {
@@ -276,17 +275,17 @@ void nsBaseWidget::DestroyCompositor()
   //  6. Step 5 will schedule DeferredDestroy on the compositor thread, which
   //     releases the reference CompositorBridgeParent holds to itself.
   //
   // When CompositorSession::Shutdown returns, we assume the compositor is gone
   // or will be gone very soon.
   if (mCompositorSession) {
     ReleaseContentController();
     mAPZC = nullptr;
-    mCompositorWidgetDelegate = nullptr;
+    SetCompositorWidgetDelegate(nullptr);
     mCompositorBridgeChild = nullptr;
 
     // XXX CompositorBridgeChild and CompositorBridgeParent might be re-created in
     // ClientLayerManager destructor. See bug 1133426.
     RefPtr<CompositorSession> session = mCompositorSession.forget();
     session->Shutdown();
   }
 }
@@ -1342,17 +1341,17 @@ void nsBaseWidget::CreateCompositor(int 
   RefPtr<LayerManager> lm =
     CreateCompositorSession(aWidth, aHeight, &options);
   if (!lm) {
     return;
   }
 
   MOZ_ASSERT(mCompositorSession);
   mCompositorBridgeChild = mCompositorSession->GetCompositorBridgeChild();
-  mCompositorWidgetDelegate = mCompositorSession->GetCompositorWidgetDelegate();
+  SetCompositorWidgetDelegate(mCompositorSession->GetCompositorWidgetDelegate());
 
   if (options.UseAPZ()) {
     mAPZC = mCompositorSession->GetAPZCTreeManager();
     ConfigureAPZCTreeManager();
   } else {
     mAPZC = nullptr;
   }
 
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -209,16 +209,17 @@ public:
   // A reference to the session object is held until this function has
   // returned.
   void NotifyCompositorSessionLost(mozilla::layers::CompositorSession* aSession);
 
   mozilla::CompositorVsyncDispatcher* GetCompositorVsyncDispatcher();
   void            CreateCompositorVsyncDispatcher();
   virtual void            CreateCompositor();
   virtual void            CreateCompositor(int aWidth, int aHeight);
+  virtual void            SetCompositorWidgetDelegate(CompositorWidgetDelegate* delegate) {}
   virtual void            PrepareWindowEffects() override {}
   virtual void            UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) override {}
   virtual void            SetModal(bool aModal) override {}
   virtual uint32_t        GetMaxTouchPoints() const override;
   virtual void            SetWindowClass(const nsAString& xulWinType)
                             override {}
   virtual nsresult        SetWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects, bool aIntersectWithExisting) override;
   // Return whether this widget interprets parameters to Move and Resize APIs
@@ -685,18 +686,16 @@ protected:
   mozilla::UniquePtr<LayoutDeviceIntRect[]> mClipRects;
   uint32_t          mClipRectCount;
   nsSizeMode        mSizeMode;
   nsPopupLevel      mPopupLevel;
   nsPopupType       mPopupType;
   SizeConstraints   mSizeConstraints;
   bool              mHasRemoteContent;
 
-  CompositorWidgetDelegate* mCompositorWidgetDelegate;
-
   bool              mUpdateCursor;
   bool              mUseAttachedEvents;
   bool              mIMEHasFocus;
   bool              mIsFullyOccluded;
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
   bool              mAccessibilityInUseFlag;
 #endif
   static nsIRollupListener* gRollupListener;
--- a/widget/windows/CompositorWidgetChild.cpp
+++ b/widget/windows/CompositorWidgetChild.cpp
@@ -3,26 +3,28 @@
  * 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 "CompositorWidgetChild.h"
 #include "mozilla/Unused.h"
 #include "mozilla/widget/CompositorWidgetVsyncObserver.h"
 #include "nsBaseWidget.h"
 #include "VsyncDispatcher.h"
+#include "gfxPlatform.h"
 
 namespace mozilla {
 namespace widget {
 
 CompositorWidgetChild::CompositorWidgetChild(RefPtr<CompositorVsyncDispatcher> aVsyncDispatcher,
                                              RefPtr<CompositorWidgetVsyncObserver> aVsyncObserver)
  : mVsyncDispatcher(aVsyncDispatcher),
    mVsyncObserver(aVsyncObserver)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(!gfxPlatform::IsHeadless());
 }
 
 CompositorWidgetChild::~CompositorWidgetChild()
 {
 }
 
 void
 CompositorWidgetChild::EnterPresentLock()
--- a/widget/windows/CompositorWidgetChild.h
+++ b/widget/windows/CompositorWidgetChild.h
@@ -12,17 +12,17 @@
 
 namespace mozilla {
 class CompositorVsyncDispatcher;
 
 namespace widget {
 
 class CompositorWidgetChild final
  : public PCompositorWidgetChild,
-   public CompositorWidgetDelegate
+   public PlatformCompositorWidgetDelegate
 {
 public:
   CompositorWidgetChild(RefPtr<CompositorVsyncDispatcher> aVsyncDispatcher,
                         RefPtr<CompositorWidgetVsyncObserver> aVsyncObserver);
   ~CompositorWidgetChild() override;
 
   void EnterPresentLock() override;
   void LeavePresentLock() override;
--- a/widget/windows/CompositorWidgetParent.cpp
+++ b/widget/windows/CompositorWidgetParent.cpp
@@ -1,23 +1,24 @@
 /* -*- 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 "CompositorWidgetParent.h"
 
 #include "mozilla/Unused.h"
+#include "mozilla/widget/PlatformWidgetTypes.h"
 
 namespace mozilla {
 namespace widget {
 
 CompositorWidgetParent::CompositorWidgetParent(const CompositorWidgetInitData& aInitData,
                                                const layers::CompositorOptions& aOptions)
- : WinCompositorWidget(aInitData, aOptions)
+ : WinCompositorWidget(aInitData.get_WinCompositorWidgetInitData(), aOptions)
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
 }
 
 CompositorWidgetParent::~CompositorWidgetParent()
 {
 }
 
--- a/widget/windows/InProcessWinCompositorWidget.cpp
+++ b/widget/windows/InProcessWinCompositorWidget.cpp
@@ -1,28 +1,39 @@
 /* -*- 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 "gfxPlatform.h"
+#include "HeadlessCompositorWidget.h"
+#include "HeadlessWidget.h"
+#include "mozilla/widget/PlatformWidgetTypes.h"
+
 #include "InProcessWinCompositorWidget.h"
 #include "nsWindow.h"
 
 namespace mozilla {
 namespace widget {
 
 /* static */ RefPtr<CompositorWidget>
 CompositorWidget::CreateLocal(const CompositorWidgetInitData& aInitData,
                               const layers::CompositorOptions& aOptions,
                               nsIWidget* aWidget)
 {
-  return new InProcessWinCompositorWidget(aInitData, aOptions, static_cast<nsWindow*>(aWidget));
+  if (aInitData.type() == CompositorWidgetInitData::THeadlessCompositorWidgetInitData) {
+    return new HeadlessCompositorWidget(aInitData.get_HeadlessCompositorWidgetInitData(),
+                                        aOptions, static_cast<HeadlessWidget*>(aWidget));
+  } else {
+    return new InProcessWinCompositorWidget(aInitData.get_WinCompositorWidgetInitData(),
+                                            aOptions, static_cast<nsWindow*>(aWidget));
+  }
 }
 
-InProcessWinCompositorWidget::InProcessWinCompositorWidget(const CompositorWidgetInitData& aInitData,
+InProcessWinCompositorWidget::InProcessWinCompositorWidget(const WinCompositorWidgetInitData& aInitData,
                                                            const layers::CompositorOptions& aOptions,
                                                            nsWindow* aWindow)
  : WinCompositorWidget(aInitData, aOptions),
    mWindow(aWindow)
 {
   MOZ_ASSERT(mWindow);
 }
 
--- a/widget/windows/InProcessWinCompositorWidget.h
+++ b/widget/windows/InProcessWinCompositorWidget.h
@@ -15,17 +15,17 @@ namespace widget {
 
 // This is the Windows-specific implementation of CompositorWidget. For
 // the most part it only requires an HWND, however it maintains extra state
 // for transparent windows, as well as for synchronizing WM_SETTEXT messages
 // with the compositor.
 class InProcessWinCompositorWidget final : public WinCompositorWidget
 {
 public:
-  InProcessWinCompositorWidget(const CompositorWidgetInitData& aInitData,
+  InProcessWinCompositorWidget(const WinCompositorWidgetInitData& aInitData,
                                const layers::CompositorOptions& aOptions,
                                nsWindow* aWindow);
 
   void ObserveVsync(VsyncObserver* aObserver) override;
   nsIWidget* RealWidget() override;
 
 private:
   nsWindow* mWindow;
--- a/widget/windows/PlatformWidgetTypes.ipdlh
+++ b/widget/windows/PlatformWidgetTypes.ipdlh
@@ -1,23 +1,28 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=99: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-// This file is a stub, for platforms that do not yet support out-of-process
-// compositing or do not need specialized types to do so.
+include HeadlessWidgetTypes;
 
 using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace widget {
 
-struct CompositorWidgetInitData
+struct WinCompositorWidgetInitData
 {
   WindowsHandle hWnd;
   uintptr_t widgetKey;
   int32_t transparencyMode;
 };
 
+union CompositorWidgetInitData
+{
+  WinCompositorWidgetInitData;
+  HeadlessCompositorWidgetInitData;
+};
+
 } // namespace widget
 } // namespace mozilla
--- a/widget/windows/WinCompositorWidget.cpp
+++ b/widget/windows/WinCompositorWidget.cpp
@@ -14,17 +14,17 @@
 
 #include <ddraw.h>
 
 namespace mozilla {
 namespace widget {
 
 using namespace mozilla::gfx;
 
-WinCompositorWidget::WinCompositorWidget(const CompositorWidgetInitData& aInitData,
+WinCompositorWidget::WinCompositorWidget(const WinCompositorWidgetInitData& aInitData,
                                          const layers::CompositorOptions& aOptions)
  : CompositorWidget(aOptions)
  , mWidgetKey(aInitData.widgetKey()),
    mWnd(reinterpret_cast<HWND>(aInitData.hWnd())),
    mTransparencyMode(static_cast<nsTransparencyMode>(aInitData.transparencyMode())),
    mMemoryDC(nullptr),
    mCompositeDC(nullptr),
    mLockedBackBufferData(nullptr)
--- a/widget/windows/WinCompositorWidget.h
+++ b/widget/windows/WinCompositorWidget.h
@@ -12,45 +12,56 @@
 #include "mozilla/gfx/Point.h"
 #include "nsIWidget.h"
 
 class nsWindow;
 
 namespace mozilla {
 namespace widget {
 
-class CompositorWidgetDelegate
+class PlatformCompositorWidgetDelegate
+  : public CompositorWidgetDelegate
 {
 public:
   // Callbacks for nsWindow.
   virtual void EnterPresentLock() = 0;
   virtual void LeavePresentLock() = 0;
   virtual void OnDestroyWindow() = 0;
 
   // Transparency handling.
   virtual void UpdateTransparency(nsTransparencyMode aMode) = 0;
   virtual void ClearTransparentWindow() = 0;
 
   // If in-process and using software rendering, return the backing transparent
   // DC.
   virtual HDC GetTransparentDC() const = 0;
+
+  // CompositorWidgetDelegate Overrides
+
+  PlatformCompositorWidgetDelegate* AsPlatformSpecificDelegate() override {
+    return this;
+  }
 };
- 
+
+class WinCompositorWidgetInitData;
+
 // This is the Windows-specific implementation of CompositorWidget. For
 // the most part it only requires an HWND, however it maintains extra state
 // for transparent windows, as well as for synchronizing WM_SETTEXT messages
 // with the compositor.
 class WinCompositorWidget
  : public CompositorWidget,
-   public CompositorWidgetDelegate
+   public PlatformCompositorWidgetDelegate
 {
 public:
-  WinCompositorWidget(const CompositorWidgetInitData& aInitData,
+  WinCompositorWidget(const WinCompositorWidgetInitData& aInitData,
                       const layers::CompositorOptions& aOptions);
 
+  // CompositorWidget Overrides
+
   bool PreRender(WidgetRenderingContext*) override;
   void PostRender(WidgetRenderingContext*) override;
   already_AddRefed<gfx::DrawTarget> StartRemoteDrawing() override;
   void EndRemoteDrawing() override;
   bool NeedsToDeferEndRemoteDrawing() override;
   LayoutDeviceIntSize GetClientSize() override;
   already_AddRefed<gfx::DrawTarget> GetBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget,
                                                             const LayoutDeviceIntRect& aRect,
@@ -61,17 +72,18 @@ public:
   WinCompositorWidget* AsWindows() override {
     return this;
   }
   CompositorWidgetDelegate* AsDelegate() override {
     return this;
   }
   bool IsHidden() const override;
 
-  // CompositorWidgetDelegate overrides.
+  // PlatformCompositorWidgetDelegate Overrides
+
   void EnterPresentLock() override;
   void LeavePresentLock() override;
   void OnDestroyWindow() override;
   void UpdateTransparency(nsTransparencyMode aMode) override;
   void ClearTransparentWindow() override;
 
   bool RedrawTransparentWindow();
 
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -640,16 +640,18 @@ nsWindow::nsWindow(bool aIsChildWindow)
 #endif
   DWORD background      = ::GetSysColor(COLOR_BTNFACE);
   mBrush                = ::CreateSolidBrush(NSRGB_2_COLOREF(background));
   mSendingSetText       = false;
   mDefaultScale         = -1.0; // not yet set, will be calculated on first use
 
   mTaskbarPreview = nullptr;
 
+  mCompositorWidgetDelegate = nullptr;
+
   // Global initialization
   if (!sInstanceCount) {
     // Global app registration id for Win7 and up. See
     // WinTaskbar.cpp for details.
     mozilla::widget::WinTaskbar::RegisterAppUserModelID();
     KeyboardLayout::GetInstance()->OnLayoutChange(::GetKeyboardLayout(0));
 #if defined(ACCESSIBILITY)
     mozilla::TIPMessageHandler::Initialize();
@@ -3943,17 +3945,17 @@ nsWindow::GetLayerManager(PLayerTransact
   }
 
   if (!mLayerManager) {
     MOZ_ASSERT(!mCompositorSession && !mCompositorBridgeChild);
     MOZ_ASSERT(!mCompositorWidgetDelegate);
 
     // Ensure we have a widget proxy even if we're not using the compositor,
     // since all our transparent window handling lives there.
-    CompositorWidgetInitData initData(
+    WinCompositorWidgetInitData initData(
       reinterpret_cast<uintptr_t>(mWnd),
       reinterpret_cast<uintptr_t>(static_cast<nsIWidget*>(this)),
       mTransparencyMode);
     // If we're not using the compositor, the options don't actually matter.
     CompositorOptions options(false, false);
     mBasicLayersSurface = new InProcessWinCompositorWidget(initData, options, this);
     mCompositorWidgetDelegate = mBasicLayersSurface;
     mLayerManager = CreateBasicLayerManager();
@@ -3961,16 +3963,37 @@ nsWindow::GetLayerManager(PLayerTransact
 
   NS_ASSERTION(mLayerManager, "Couldn't provide a valid layer manager.");
 
   return mLayerManager;
 }
 
 /**************************************************************
  *
+ * SECTION: nsBaseWidget::SetCompositorWidgetDelegate
+ *
+ * Called to connect the nsWindow to the delegate providing
+ * platform compositing API access.
+ *
+ **************************************************************/
+
+void
+nsWindow::SetCompositorWidgetDelegate(CompositorWidgetDelegate* delegate)
+{
+    if (delegate) {
+        mCompositorWidgetDelegate = delegate->AsPlatformSpecificDelegate();
+        MOZ_ASSERT(mCompositorWidgetDelegate,
+                   "nsWindow::SetCompositorWidgetDelegate called with a non-PlatformCompositorWidgetDelegate");
+    } else {
+        mCompositorWidgetDelegate = nullptr;
+    }
+}
+
+/**************************************************************
+ *
  * SECTION: nsIWidget::OnDefaultButtonLoaded
  *
  * Called after the dialog is loaded and it has a default button.
  *
  **************************************************************/
 
 nsresult
 nsWindow::OnDefaultButtonLoaded(const LayoutDeviceIntRect& aButtonRect)
@@ -8374,18 +8397,19 @@ bool nsWindow::OnPointerEvents(UINT msg,
   // Consume WM_POINTER* to stop Windows fires WM_*BUTTONDOWN / WM_*BUTTONUP
   // WM_MOUSEMOVE.
   return true;
 }
 
 void
 nsWindow::GetCompositorWidgetInitData(mozilla::widget::CompositorWidgetInitData* aInitData)
 {
-  aInitData->hWnd() = reinterpret_cast<uintptr_t>(mWnd);
-  aInitData->widgetKey() = reinterpret_cast<uintptr_t>(static_cast<nsIWidget*>(this));
-  aInitData->transparencyMode() = mTransparencyMode;
+  *aInitData = WinCompositorWidgetInitData(
+      reinterpret_cast<uintptr_t>(mWnd),
+      reinterpret_cast<uintptr_t>(static_cast<nsIWidget*>(this)),
+      mTransparencyMode);
 }
 
 bool
 nsWindow::SynchronouslyRepaintOnResize()
 {
   return !gfxWindowsPlatform::GetPlatform()->DwmCompositionEnabled();
 }
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -7,16 +7,17 @@
 #define Window_h__
 
 /*
  * nsWindow - Native window management and event handling.
  */
 
 #include "mozilla/RefPtr.h"
 #include "nsBaseWidget.h"
+#include "CompositorWidget.h"
 #include "nsWindowBase.h"
 #include "nsdefs.h"
 #include "nsIdleService.h"
 #include "nsToolkit.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "gfxWindowsPlatform.h"
 #include "gfxWindowsSurface.h"
@@ -71,16 +72,17 @@ class nsWindow final : public nsWindowBa
 {
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
   typedef mozilla::widget::WindowHook WindowHook;
   typedef mozilla::widget::TaskbarWindowPreview TaskbarWindowPreview;
   typedef mozilla::widget::NativeKey NativeKey;
   typedef mozilla::widget::MSGResult MSGResult;
   typedef mozilla::widget::IMEContext IMEContext;
+  typedef mozilla::widget::PlatformCompositorWidgetDelegate PlatformCompositorWidgetDelegate;
 
 public:
   explicit nsWindow(bool aIsChildWindow = false);
 
   NS_DECL_ISUPPORTS_INHERITED
 
   friend class nsWindowGfx;
 
@@ -172,16 +174,17 @@ public:
   virtual void            CaptureMouse(bool aCapture) override;
   virtual void            CaptureRollupEvents(nsIRollupListener* aListener,
                                               bool aDoCapture) override;
   virtual MOZ_MUST_USE nsresult GetAttention(int32_t aCycleCount) override;
   virtual bool            HasPendingInputEvent() override;
   virtual LayerManager*   GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
                                           LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
                                           LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT) override;
+  void                    SetCompositorWidgetDelegate(CompositorWidgetDelegate* delegate) override;
   virtual MOZ_MUST_USE nsresult OnDefaultButtonLoaded(const LayoutDeviceIntRect& aButtonRect) override;
   virtual nsresult        SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
                                                    int32_t aNativeKeyCode,
                                                    uint32_t aModifierFlags,
                                                    const nsAString& aCharacters,
                                                    const nsAString& aUnmodifiedCharacters,
                                                    nsIObserver* aObserver) override;
   virtual nsresult        SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
@@ -554,16 +557,18 @@ protected:
   static HCURSOR        sHCursor;
   static imgIContainer* sCursorImgContainer;
   static bool           sSwitchKeyboardLayout;
   static bool           sJustGotDeactivate;
   static bool           sJustGotActivate;
   static bool           sIsInMouseCapture;
   static bool           sHaveInitializedPrefs;
 
+  PlatformCompositorWidgetDelegate* mCompositorWidgetDelegate;
+
   // Always use the helper method to read this property.  See bug 603793.
   static TriStateBool   sHasBogusPopupsDropShadowOnMultiMonitor;
   static bool           HasBogusPopupsDropShadowOnMultiMonitor();
 
   // Non-client margin settings
   // Pre-calculated outward offset applied to default frames
   LayoutDeviceIntMargin mNonClientOffset;
   // Margins set by the owner