Bug 1373739 - Use ClientLayerManager in headless mode. r?jrmuizel
This fixes a series of issues uncovered by the Web Platform Tests.
The most immediately noticeable symptom was that, during shutdown, PuppetWidgets
on the client side attempted to delete shadow layers that were never created on
the compositor side. The usage of BasicLayerManager in all other widgets due to
headless mode meant that the PLayerTransactionParent was never initialized with
a layer manager, and thus discarded all transaction messages it received but not
delete layer messages.
The effects of only using BasicLayerManager in headless mode also showed up in
the web platform reftests, which ended up as blank white boxes in e10s mode as
the compositor thread never received paint instructions. Switching over to
using ClientLayerManager in headless mode causes these paint instructions to be
relayed.
In order to make ClientLayerManager work under headless mode, it was necessary
to implement a HeadlessCompositorWidget and hook that up to the CompositorWidget
creation function in widget/gtk. A follow-up patch will be necessary to hook up
the same for the other supported widget platforms.
MozReview-Commit-ID: 8vB3lrxP7iX
--- a/widget/gtk/InProcessX11CompositorWidget.cpp
+++ b/widget/gtk/InProcessX11CompositorWidget.cpp
@@ -1,26 +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 "gfxPlatform.h"
+#include "HeadlessCompositorWidget.h"
+#include "HeadlessWidget.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)
{
- return new InProcessX11CompositorWidget(aInitData, aOptions, static_cast<nsWindow*>(aWidget));
+ if (gfxPlatform::IsHeadless()) {
+ return new HeadlessCompositorWidget(aInitData, aOptions, static_cast<HeadlessWidget*>(aWidget));
+ } else {
+ return new InProcessX11CompositorWidget(aInitData, aOptions, static_cast<nsWindow*>(aWidget));
+ }
}
InProcessX11CompositorWidget::InProcessX11CompositorWidget(const CompositorWidgetInitData& aInitData,
const layers::CompositorOptions& aOptions,
nsWindow* aWindow)
: X11CompositorWidget(aInitData, aOptions, aWindow)
{
}
new file mode 100644
--- /dev/null
+++ b/widget/headless/HeadlessCompositorWidget.cpp
@@ -0,0 +1,54 @@
+/* -*- 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 "mozilla/widget/PlatformWidgetTypes.h"
+#include "HeadlessCompositorWidget.h"
+#include "VsyncDispatcher.h"
+
+namespace mozilla {
+namespace widget {
+
+HeadlessCompositorWidget::HeadlessCompositorWidget(const CompositorWidgetInitData& aInitData,
+ const layers::CompositorOptions& aOptions,
+ HeadlessWidget* aWindow)
+ : CompositorWidget(aOptions)
+ , mWidget(aWindow)
+{
+ mClientSize = aInitData.InitialClientSize();
+}
+
+void
+HeadlessCompositorWidget::ObserveVsync(VsyncObserver* aObserver)
+{
+ if (RefPtr<CompositorVsyncDispatcher> cvd = mWidget->GetCompositorVsyncDispatcher()) {
+ cvd->SetCompositorVsyncObserver(aObserver);
+ }
+}
+
+nsIWidget* HeadlessCompositorWidget::RealWidget()
+{
+ return mWidget;
+}
+
+void
+HeadlessCompositorWidget::NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize)
+{
+ mClientSize = aClientSize;
+}
+
+LayoutDeviceIntSize
+HeadlessCompositorWidget::GetClientSize()
+{
+ return mClientSize;
+}
+
+uintptr_t
+HeadlessCompositorWidget::GetWidgetKey()
+{
+ return reinterpret_cast<uintptr_t>(mWidget);
+}
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/headless/HeadlessCompositorWidget.h
@@ -0,0 +1,47 @@
+/* -*- 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 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 HeadlessCompositorWidget final
+ : public CompositorWidget
+ , public CompositorWidgetDelegate
+{
+public:
+ HeadlessCompositorWidget(const CompositorWidgetInitData& aInitData,
+ const layers::CompositorOptions& aOptions,
+ HeadlessWidget* aWindow);
+
+ // 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;
+
+private:
+ HeadlessWidget* mWidget;
+
+ LayoutDeviceIntSize mClientSize;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // widget_headless_HeadlessCompositor_h
--- a/widget/headless/HeadlessWidget.cpp
+++ b/widget/headless/HeadlessWidget.cpp
@@ -1,13 +1,14 @@
/* -*- 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 "HeadlessWidget.h"
+#include "HeadlessCompositorWidget.h"
#include "Layers.h"
#include "BasicLayers.h"
#include "BasicEvents.h"
#include "mozilla/gfx/gfxVars.h"
using namespace mozilla::gfx;
using namespace mozilla::layers;
@@ -76,16 +77,27 @@ HeadlessWidget::CreateChild(const Layout
return nullptr;
}
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());
+}
+
nsIWidget*
HeadlessWidget::GetTopLevelWidget()
{
return mTopLevel;
}
void
HeadlessWidget::RaiseWindow()
@@ -185,39 +197,32 @@ HeadlessWidget::WidgetToScreenOffset()
return LayoutDeviceIntPoint(mBounds.x, mBounds.y);
}
LayerManager*
HeadlessWidget::GetLayerManager(PLayerTransactionChild* aShadowManager,
LayersBackend aBackendHint,
LayerManagerPersistence aPersistence)
{
- if (!mLayerManager) {
- RefPtr<BasicLayerManager> layerManager = new BasicLayerManager(this);
- RefPtr<gfxContext> ctx = CreateDefaultTarget(IntSize(mBounds.width, mBounds.height));
- layerManager->SetDefaultTarget(ctx);
- mLayerManager = layerManager;
- }
-
- return mLayerManager;
+ return nsBaseWidget::GetLayerManager(aShadowManager, aBackendHint, aPersistence);
}
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 (mLayerManager) {
- RefPtr<gfxContext> ctx = CreateDefaultTarget(IntSize(mBounds.width, mBounds.height));
- mLayerManager->AsBasicLayerManager()->SetDefaultTarget(ctx);
+ if (mCompositorWidgetDelegate) {
+ mCompositorWidgetDelegate->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
@@ -32,16 +32,18 @@ public:
nsWidgetInitData* aInitData = nullptr) override;
using nsBaseWidget::Create; // for Create signature not overridden here
virtual already_AddRefed<nsIWidget> CreateChild(const LayoutDeviceIntRect& aRect,
nsWidgetInitData* aInitData = nullptr,
bool aForceUseIWidgetParent = false) override;
virtual nsIWidget* GetTopLevelWidget() override;
+ virtual void GetCompositorWidgetInitData(mozilla::widget::CompositorWidgetInitData* aInitData) override;
+
virtual void Show(bool aState) override;
virtual bool IsVisible() const override;
virtual void Move(double aX, double aY) override;
virtual void Resize(double aWidth,
double aHeight,
bool aRepaint) override;
virtual void Resize(double aX,
double aY,
--- a/widget/headless/moz.build
+++ b/widget/headless/moz.build
@@ -13,16 +13,17 @@ LOCAL_INCLUDES += [
'/widget',
'/widget/gtk',
'/widget/headless',
]
UNIFIED_SOURCES += [
'HeadlessClipboard.cpp',
'HeadlessClipboardData.cpp',
+ 'HeadlessCompositorWidget.cpp',
'HeadlessLookAndFeel.cpp',
'HeadlessScreenHelper.cpp',
'HeadlessSound.cpp',
'HeadlessWidget.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')