Bug 1353939 - Disable drag service in headless mode. r=jrmuizel

Drag service calls into GTK causing a crash in headless mode.
This commit is contained in:
Brendan Dahl 2017-03-16 16:20:18 -07:00
parent e0c482815a
commit b082e33320
8 changed files with 84 additions and 16 deletions

View File

@ -26,6 +26,7 @@
#include "nsCRT.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/Services.h"
#include "mozilla/ClearOnShutdown.h"
#include "gfxXlibSurface.h"
#include "gfxContext.h"
@ -151,13 +152,20 @@ nsDragService::~nsDragService()
NS_IMPL_ISUPPORTS_INHERITED(nsDragService, nsBaseDragService, nsIObserver)
/* static */ nsDragService*
mozilla::StaticRefPtr<nsDragService> sDragServiceInstance;
/* static */ already_AddRefed<nsDragService>
nsDragService::GetInstance()
{
static const nsIID iid = NS_DRAGSERVICE_CID;
nsCOMPtr<nsIDragService> dragService = do_GetService(iid);
return static_cast<nsDragService*>(dragService.get());
// We rely on XPCOM keeping a reference to the service.
if (gfxPlatform::IsHeadless()) {
return nullptr;
}
if (!sDragServiceInstance) {
sDragServiceInstance = new nsDragService();
ClearOnShutdown(&sDragServiceInstance);
}
RefPtr<nsDragService> service = sDragServiceInstance.get();
return service.forget();
}
// nsIObserver

View File

@ -85,7 +85,7 @@ public:
// Methods called from nsWindow to handle responding to GTK drag
// destination signals
static nsDragService* GetInstance();
static already_AddRefed<nsDragService> GetInstance();
void TargetDataReceived (GtkWidget *aWidget,
GdkDragContext *aContext,

View File

@ -74,7 +74,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIdleServiceGTK, nsIdleServiceGTK::GetInstance)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsClipboard, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDragService)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsDragService, nsDragService::GetInstance)
#endif
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(ScreenManager, ScreenManager::GetAddRefedSingleton)

View File

@ -735,7 +735,7 @@ nsWindow::Destroy()
}
// dragService will be null after shutdown of the service manager.
nsDragService *dragService = nsDragService::GetInstance();
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
if (dragService && this == dragService->GetMostRecentDestWindow()) {
dragService->ScheduleLeaveEvent();
}
@ -3397,7 +3397,8 @@ nsWindow::OnDragDataReceivedEvent(GtkWidget *aWidget,
{
LOGDRAG(("nsWindow::OnDragDataReceived(%p)\n", (void*)this));
nsDragService::GetInstance()->
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
dragService->
TargetDataReceived(aWidget, aDragContext, aX, aY,
aSelectionData, aInfo, aTime);
}
@ -5911,7 +5912,8 @@ drag_motion_event_cb(GtkWidget *aWidget,
LayoutDeviceIntPoint point = window->GdkPointToDevicePixels({ retx, rety });
return nsDragService::GetInstance()->
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
return dragService->
ScheduleMotionEvent(innerMostWindow, aDragContext,
point, aTime);
}
@ -5926,7 +5928,7 @@ drag_leave_event_cb(GtkWidget *aWidget,
if (!window)
return;
nsDragService *dragService = nsDragService::GetInstance();
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
nsWindow *mostRecentDragWindow = dragService->GetMostRecentDestWindow();
if (!mostRecentDragWindow) {
@ -5983,7 +5985,8 @@ drag_drop_event_cb(GtkWidget *aWidget,
LayoutDeviceIntPoint point = window->GdkPointToDevicePixels({ retx, rety });
return nsDragService::GetInstance()->
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
return dragService->
ScheduleDropEvent(innerMostWindow, aDragContext,
point, aTime);
}

View File

@ -126,6 +126,8 @@ HeadlessWidget::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
if (mAttachedWidgetListener) {
aStatus = mAttachedWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
} else if (mWidgetListener) {
aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
}
return NS_OK;

View File

@ -0,0 +1,6 @@
<html>
<head><meta content="text/html; charset=utf-8" http-equiv="Content-Type"></head>
<body>
<button id="btn">button</button>
</body>
</html>

View File

@ -12,6 +12,8 @@ server.start(-1);
const ROOT = `http://localhost:${server.identity.primaryPort}`;
const BASE = `${ROOT}/`;
const HEADLESS_URL = `${BASE}/headless.html`;
const HEADLESS_BUTTON_URL = `${BASE}/headless_button.html`;
do_register_cleanup(() => { server.stop(() => {})});
function loadContentWindow(webNavigation, uri) {
return new Promise((resolve, reject) => {
@ -88,7 +90,52 @@ add_task(function* test_snapshot() {
ok(found, "Found blue text on page.");
webNavigation.close();
yield new Promise((resolve) => {
server.stop(resolve);
});
});
// Ensure keydown events are triggered on the windowless browser.
add_task(function* test_keydown() {
let windowlessBrowser = Services.appShell.createWindowlessBrowser(false);
let webNavigation = windowlessBrowser.QueryInterface(Ci.nsIWebNavigation);
let contentWindow = yield loadContentWindow(webNavigation, HEADLESS_URL);
let utils = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let keydown = new Promise((resolve) => {
contentWindow.addEventListener("keydown", () => {
resolve();
}, { once: true });
})
utils.sendKeyEvent("keydown", 65, 65, 0);
yield keydown;
ok(true, "Send keydown didn't crash");
webNavigation.close();
});
// Test dragging the mouse on a button to ensure the creation of the drag
// service doesn't crash in headless.
add_task(function* test_mouse_drag() {
let windowlessBrowser = Services.appShell.createWindowlessBrowser(false);
let webNavigation = windowlessBrowser.QueryInterface(Ci.nsIWebNavigation);
let contentWindow = yield loadContentWindow(webNavigation, HEADLESS_BUTTON_URL);
contentWindow.resizeTo(400, 400);
let target = contentWindow.document.getElementById('btn');
let rect = target.getBoundingClientRect();
let left = rect.left;
let top = rect.top;
let utils = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mousemove", left, top, 0, 1, 0, false, 0, 0);
// Wait for a turn of the event loop since the synthetic mouse event
// that creates the drag service is processed during the refresh driver.
yield new Promise((r) => {do_execute_soon(r)});
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
ok(true, "Send mouse event didn't crash");
webNavigation.close();
});

View File

@ -1,4 +1,6 @@
[test_headless.js]
skip-if = os != "linux"
headless = true
support-files = headless.html
support-files =
headless.html
headless_button.html