mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 04:41:11 +00:00
Bug 1886604: Part 1: Add JS-scriptable MockDragService r=win-reviewers,edgar,rkraesig
Introduces MockDragService as a subclass/implementation of nsBaseDragService. This class is based on the Windows implementation of nsBaseDragService. The service is created with a MockDragServiceController that JS can use to initiate drag events that would normally come from the system. Native drag-and-drop is not permitted in automation because it puts the browser into a state where, if anything goes wrong (e.g. a test failure), it cannot be killed without manual intervention. This allows us to avoid that limitation while still testing most of the browser's drag-and-drop behavior, including the (substantial and complex) nsBaseDragService base-class that is common to all platforms. Differential Revision: https://phabricator.services.mozilla.com/D205640
This commit is contained in:
parent
e247d7e4d1
commit
7d6e26c06c
@ -983,6 +983,13 @@ nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
mMouseEnterLeaveHelper->TryToRestorePendingRemovedOverTarget(aEvent);
|
||||
}
|
||||
|
||||
static constexpr auto const allowSynthesisForTests = []() -> bool {
|
||||
nsCOMPtr<nsIDragService> dragService =
|
||||
do_GetService("@mozilla.org/widget/dragservice;1");
|
||||
return dragService &&
|
||||
!dragService->GetNeverAllowSessionIsSynthesizedForTests();
|
||||
};
|
||||
|
||||
switch (aEvent->mMessage) {
|
||||
case eContextMenu:
|
||||
if (PointerLockManager::IsLocked()) {
|
||||
@ -1142,20 +1149,21 @@ nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
case eDragOver: {
|
||||
WidgetDragEvent* dragEvent = aEvent->AsDragEvent();
|
||||
MOZ_ASSERT(dragEvent);
|
||||
if (dragEvent->mFlags.mIsSynthesizedForTests) {
|
||||
if (dragEvent->mFlags.mIsSynthesizedForTests &&
|
||||
allowSynthesisForTests()) {
|
||||
dragEvent->InitDropEffectForTests();
|
||||
}
|
||||
// Send the enter/exit events before eDrop.
|
||||
GenerateDragDropEnterExit(aPresContext, dragEvent);
|
||||
break;
|
||||
}
|
||||
case eDrop:
|
||||
if (aEvent->mFlags.mIsSynthesizedForTests) {
|
||||
case eDrop: {
|
||||
if (aEvent->mFlags.mIsSynthesizedForTests && allowSynthesisForTests()) {
|
||||
MOZ_ASSERT(aEvent->AsDragEvent());
|
||||
aEvent->AsDragEvent()->InitDropEffectForTests();
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case eKeyPress: {
|
||||
WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
|
||||
if (keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eChrome) ||
|
||||
@ -4347,8 +4355,11 @@ nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
||||
|
||||
case eDrop: {
|
||||
if (aEvent->mFlags.mIsSynthesizedForTests) {
|
||||
if (nsCOMPtr<nsIDragSession> dragSession =
|
||||
nsContentUtils::GetDragSession()) {
|
||||
nsCOMPtr<nsIDragService> dragService =
|
||||
do_GetService("@mozilla.org/widget/dragservice;1");
|
||||
nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
|
||||
if (dragSession && dragService &&
|
||||
!dragService->GetNeverAllowSessionIsSynthesizedForTests()) {
|
||||
MOZ_ASSERT(dragSession->IsSynthesizedForTests());
|
||||
RefPtr<WindowContext> sourceWC;
|
||||
DebugOnly<nsresult> rvIgnored =
|
||||
|
204
widget/MockDragServiceController.cpp
Normal file
204
widget/MockDragServiceController.cpp
Normal file
@ -0,0 +1,204 @@
|
||||
/* -*- 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 "MockDragServiceController.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/DragEvent.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/SpinEventLoopUntil.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsBaseDragService.h"
|
||||
|
||||
namespace mozilla::test {
|
||||
|
||||
NS_IMPL_ISUPPORTS(MockDragServiceController, nsIMockDragServiceController)
|
||||
|
||||
class MockDragService : public nsBaseDragService {
|
||||
public:
|
||||
MOZ_CAN_RUN_SCRIPT nsresult
|
||||
InvokeDragSessionImpl(nsIArray* aTransferableArray,
|
||||
const mozilla::Maybe<mozilla::CSSIntRegion>& aRegion,
|
||||
uint32_t aActionType) override {
|
||||
// In Windows' nsDragService, InvokeDragSessionImpl would establish a
|
||||
// nested (native) event loop that runs as long as the drag is happening.
|
||||
// See DoDragDrop in MSDN.
|
||||
// We cannot do anything like that here since it would block mochitest
|
||||
// from scripting behavior with MockDragServiceController::SendDragEvent.
|
||||
|
||||
// mDragAction is not yet handled properly in the MockDragService.
|
||||
// This should be updated with each drag event. Instead, we always MOVE.
|
||||
mDragAction = DRAGDROP_ACTION_MOVE;
|
||||
StartDragSession();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool IsMockService() override { return true; }
|
||||
|
||||
uint32_t mLastModifierKeyState = 0;
|
||||
};
|
||||
|
||||
static void SetDragEndPointFromScreenPoint(
|
||||
MockDragService* aService, nsPresContext* aPc,
|
||||
const LayoutDeviceIntPoint& aScreenPt) {
|
||||
// aScreenPt is screen-relative, and we want to be
|
||||
// top-level-widget-relative.
|
||||
auto* widget = aPc->GetRootWidget();
|
||||
auto pt = aScreenPt - widget->WidgetToScreenOffset();
|
||||
pt += widget->WidgetToTopLevelWidgetOffset();
|
||||
aService->SetDragEndPoint(pt);
|
||||
}
|
||||
|
||||
static bool IsMouseEvent(nsIMockDragServiceController::EventType aEventType) {
|
||||
using EventType = nsIMockDragServiceController::EventType;
|
||||
switch (aEventType) {
|
||||
case EventType::eMouseDown:
|
||||
case EventType::eMouseMove:
|
||||
case EventType::eMouseUp:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static EventMessage MockEventTypeToEventMessage(
|
||||
nsIMockDragServiceController::EventType aEventType) {
|
||||
using EventType = nsIMockDragServiceController::EventType;
|
||||
|
||||
switch (aEventType) {
|
||||
case EventType::eDragEnter:
|
||||
return EventMessage::eDragEnter;
|
||||
case EventType::eDragOver:
|
||||
return EventMessage::eDragOver;
|
||||
case EventType::eDragLeave:
|
||||
return EventMessage::eDragLeave;
|
||||
case EventType::eDrop:
|
||||
return EventMessage::eDrop;
|
||||
case EventType::eMouseDown:
|
||||
return EventMessage::eMouseDown;
|
||||
case EventType::eMouseMove:
|
||||
return EventMessage::eMouseMove;
|
||||
case EventType::eMouseUp:
|
||||
return EventMessage::eMouseUp;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Invalid event type");
|
||||
return EventMessage::eVoidEvent;
|
||||
}
|
||||
}
|
||||
|
||||
MockDragServiceController::MockDragServiceController()
|
||||
: mDragService(new MockDragService()) {}
|
||||
|
||||
MockDragServiceController::~MockDragServiceController() = default;
|
||||
|
||||
NS_IMETHODIMP
|
||||
MockDragServiceController::GetMockDragService(nsIDragService** aService) {
|
||||
RefPtr<nsIDragService> ds = mDragService;
|
||||
ds.forget(aService);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MockDragServiceController::SendEvent(
|
||||
dom::BrowsingContext* aBC,
|
||||
nsIMockDragServiceController::EventType aEventType, int32_t aScreenX,
|
||||
int32_t aScreenY, uint32_t aKeyModifiers = 0) {
|
||||
RefPtr<nsIWidget> widget =
|
||||
aBC->Canonical()->GetParentProcessWidgetContaining();
|
||||
NS_ENSURE_TRUE(widget, NS_ERROR_UNEXPECTED);
|
||||
auto* embedder = aBC->Top()->GetEmbedderElement();
|
||||
NS_ENSURE_TRUE(embedder, NS_ERROR_UNEXPECTED);
|
||||
auto* frame = embedder->GetPrimaryFrame();
|
||||
NS_ENSURE_TRUE(frame, NS_ERROR_UNEXPECTED);
|
||||
auto* presCxt = frame->PresContext();
|
||||
MOZ_ASSERT(presCxt);
|
||||
|
||||
EventMessage eventType = MockEventTypeToEventMessage(aEventType);
|
||||
UniquePtr<WidgetInputEvent> widgetEvent;
|
||||
if (IsMouseEvent(aEventType)) {
|
||||
widgetEvent = MakeUnique<WidgetMouseEvent>(true, eventType, widget,
|
||||
WidgetMouseEvent::Reason::eReal);
|
||||
} else {
|
||||
widgetEvent = MakeUnique<WidgetDragEvent>(true, eventType, widget);
|
||||
}
|
||||
|
||||
widgetEvent->mWidget = widget;
|
||||
widgetEvent->mFlags.mIsSynthesizedForTests = true;
|
||||
|
||||
auto clientPosInScreenCoords = widget->GetClientBounds().TopLeft();
|
||||
widgetEvent->mRefPoint =
|
||||
LayoutDeviceIntPoint(aScreenX, aScreenY) - clientPosInScreenCoords;
|
||||
|
||||
RefPtr<MockDragService> ds = mDragService;
|
||||
ds->mLastModifierKeyState = aKeyModifiers;
|
||||
|
||||
if (aEventType == EventType::eDragEnter) {
|
||||
// We expect StartDragSession to return an "error" when a drag session
|
||||
// already exists, which it will since we are testing dragging from
|
||||
// inside Gecko, so we don't check the return value.
|
||||
ds->StartDragSession();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDragSession> currentDragSession;
|
||||
nsresult rv = ds->GetCurrentSession(getter_AddRefs(currentDragSession));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
switch (aEventType) {
|
||||
case EventType::eMouseDown:
|
||||
case EventType::eMouseMove:
|
||||
case EventType::eMouseUp:
|
||||
widget->DispatchInputEvent(widgetEvent.get());
|
||||
break;
|
||||
case EventType::eDragEnter:
|
||||
NS_ENSURE_TRUE(currentDragSession, NS_ERROR_UNEXPECTED);
|
||||
currentDragSession->SetDragAction(nsIDragService::DRAGDROP_ACTION_MOVE);
|
||||
widget->DispatchInputEvent(widgetEvent.get());
|
||||
break;
|
||||
case EventType::eDragLeave: {
|
||||
NS_ENSURE_TRUE(currentDragSession, NS_ERROR_UNEXPECTED);
|
||||
currentDragSession->SetDragAction(nsIDragService::DRAGDROP_ACTION_MOVE);
|
||||
widget->DispatchInputEvent(widgetEvent.get());
|
||||
SetDragEndPointFromScreenPoint(ds, presCxt,
|
||||
LayoutDeviceIntPoint(aScreenX, aScreenY));
|
||||
nsCOMPtr<nsINode> sourceNode;
|
||||
rv = currentDragSession->GetSourceNode(getter_AddRefs(sourceNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!sourceNode) {
|
||||
rv = ds->EndDragSession(false /* doneDrag */, aKeyModifiers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
} break;
|
||||
case EventType::eDragOver:
|
||||
NS_ENSURE_TRUE(currentDragSession, NS_ERROR_UNEXPECTED);
|
||||
rv = ds->FireDragEventAtSource(EventMessage::eDrag, aKeyModifiers);
|
||||
currentDragSession->SetDragAction(nsIDragService::DRAGDROP_ACTION_MOVE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
widget->DispatchInputEvent(widgetEvent.get());
|
||||
break;
|
||||
case EventType::eDrop: {
|
||||
NS_ENSURE_TRUE(currentDragSession, NS_ERROR_UNEXPECTED);
|
||||
currentDragSession->SetDragAction(nsIDragService::DRAGDROP_ACTION_MOVE);
|
||||
widget->DispatchInputEvent(widgetEvent.get());
|
||||
SetDragEndPointFromScreenPoint(ds, presCxt,
|
||||
LayoutDeviceIntPoint(aScreenX, aScreenY));
|
||||
rv = ds->EndDragSession(true /* doneDrag */, aKeyModifiers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Impossible event type?");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MockDragServiceController::CancelDrag(uint32_t aKeyModifiers = 0) {
|
||||
RefPtr<MockDragService> ds = mDragService;
|
||||
ds->mLastModifierKeyState = aKeyModifiers;
|
||||
return ds->EndDragSession(false /* doneDrag */, aKeyModifiers);
|
||||
}
|
||||
|
||||
} // namespace mozilla::test
|
29
widget/MockDragServiceController.h
Normal file
29
widget/MockDragServiceController.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* -*- 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 MockDragServiceController_h__
|
||||
#define MockDragServiceController_h__
|
||||
|
||||
#include "nsIMockDragServiceController.h"
|
||||
|
||||
namespace mozilla::test {
|
||||
|
||||
class MockDragService;
|
||||
|
||||
class MockDragServiceController : public nsIMockDragServiceController {
|
||||
public:
|
||||
MockDragServiceController();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMOCKDRAGSERVICECONTROLLER
|
||||
|
||||
private:
|
||||
virtual ~MockDragServiceController();
|
||||
RefPtr<MockDragService> mDragService;
|
||||
};
|
||||
|
||||
} // namespace mozilla::test
|
||||
|
||||
#endif // MockDragServiceController_h__
|
@ -124,6 +124,7 @@ XPIDL_SOURCES += [
|
||||
"nsIFormatConverter.idl",
|
||||
"nsIGfxInfo.idl",
|
||||
"nsIGfxInfoDebug.idl",
|
||||
"nsIMockDragServiceController.idl",
|
||||
"nsIPaper.idl",
|
||||
"nsIPaperMargin.idl",
|
||||
"nsIPrinter.idl",
|
||||
@ -383,6 +384,12 @@ IPDL_SOURCES += [
|
||||
LOCAL_INCLUDES += [
|
||||
"/widget/%s" % toolkit,
|
||||
]
|
||||
|
||||
if CONFIG["ENABLE_TESTS"]:
|
||||
UNIFIED_SOURCES += [
|
||||
"MockDragServiceController.cpp",
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = "xul"
|
||||
|
||||
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
|
||||
|
@ -50,6 +50,8 @@
|
||||
#include "gfxContext.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "nscore.h"
|
||||
#include "MockDragServiceController.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace mozilla;
|
||||
@ -341,18 +343,17 @@ nsBaseDragService::InvokeDragSession(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If you're hitting this, a test is causing the browser to attempt to enter
|
||||
// the drag-drop native nested event loop, which will put the browser in a
|
||||
// state that won't run tests properly until there's manual intervention
|
||||
// to exit the drag-drop loop (either by moving the mouse or hitting escape),
|
||||
// which can't be done from script since we're in the nested loop.
|
||||
//
|
||||
// The best way to avoid this is to catch the dragstart event on the item
|
||||
// being dragged, and then to call preventDefault() and stopPropagating() on
|
||||
// it.
|
||||
if (XRE_IsParentProcess()) {
|
||||
// If you're hitting this, a test is causing the browser to attempt to enter
|
||||
// the drag-drop native nested event loop, which will put the browser in a
|
||||
// state that won't run tests properly until there's manual intervention
|
||||
// to exit the drag-drop loop (either by moving the mouse or hitting
|
||||
// escape), which can't be done from script since we're in the nested loop.
|
||||
//
|
||||
// The best way to avoid this is to use the mock service in tests. See
|
||||
// synthesizeMockDragAndDrop.
|
||||
MOZ_ASSERT(
|
||||
!xpc::IsInAutomation(),
|
||||
!xpc::IsInAutomation() || IsMockService(),
|
||||
"About to start drag-drop native loop on which will prevent later "
|
||||
"tests from running properly.");
|
||||
}
|
||||
@ -409,7 +410,8 @@ nsBaseDragService::InvokeDragSessionWithImage(
|
||||
NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE);
|
||||
|
||||
mSessionIsSynthesizedForTests =
|
||||
aDragEvent->WidgetEventPtr()->mFlags.mIsSynthesizedForTests;
|
||||
aDragEvent->WidgetEventPtr()->mFlags.mIsSynthesizedForTests &&
|
||||
!GetNeverAllowSessionIsSynthesizedForTests();
|
||||
mDataTransfer = aDataTransfer;
|
||||
mSelection = nullptr;
|
||||
mHasImage = true;
|
||||
@ -460,7 +462,8 @@ nsBaseDragService::InvokeDragSessionWithRemoteImage(
|
||||
NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE);
|
||||
|
||||
mSessionIsSynthesizedForTests =
|
||||
aDragEvent->WidgetEventPtr()->mFlags.mIsSynthesizedForTests;
|
||||
aDragEvent->WidgetEventPtr()->mFlags.mIsSynthesizedForTests &&
|
||||
!GetNeverAllowSessionIsSynthesizedForTests();
|
||||
mDataTransfer = aDataTransfer;
|
||||
mSelection = nullptr;
|
||||
mHasImage = true;
|
||||
@ -492,7 +495,8 @@ nsBaseDragService::InvokeDragSessionWithSelection(
|
||||
NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE);
|
||||
|
||||
mSessionIsSynthesizedForTests =
|
||||
aDragEvent->WidgetEventPtr()->mFlags.mIsSynthesizedForTests;
|
||||
aDragEvent->WidgetEventPtr()->mFlags.mIsSynthesizedForTests &&
|
||||
!GetNeverAllowSessionIsSynthesizedForTests();
|
||||
mDataTransfer = aDataTransfer;
|
||||
mSelection = aSelection;
|
||||
mHasImage = true;
|
||||
@ -550,6 +554,8 @@ nsBaseDragService::StartDragSession() {
|
||||
|
||||
NS_IMETHODIMP nsBaseDragService::StartDragSessionForTests(
|
||||
uint32_t aAllowedEffect) {
|
||||
// This method must set mSessionIsSynthesizedForTests
|
||||
MOZ_ASSERT(!mNeverAllowSessionIsSynthesizedForTests);
|
||||
if (NS_WARN_IF(NS_FAILED(StartDragSession()))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -1042,3 +1048,38 @@ nsBaseDragService::MaybeEditorDeletedSourceNode(Element* aEditingHost) {
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseDragService::GetMockDragController(
|
||||
nsIMockDragServiceController** aController) {
|
||||
#ifdef ENABLE_TESTS
|
||||
if (XRE_IsContentProcess()) {
|
||||
// The mock drag controller is only available in the parent process.
|
||||
MOZ_ASSERT(!XRE_IsContentProcess());
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
if (!mMockController) {
|
||||
mMockController = new mozilla::test::MockDragServiceController();
|
||||
}
|
||||
auto controller = mMockController;
|
||||
controller.forget(aController);
|
||||
return NS_OK;
|
||||
#else
|
||||
*aController = nullptr;
|
||||
MOZ_ASSERT(false, "CreateMockDragController may only be called for testing");
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseDragService::GetNeverAllowSessionIsSynthesizedForTests(
|
||||
bool* aNeverAllow) {
|
||||
*aNeverAllow = mNeverAllowSessionIsSynthesizedForTests;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseDragService::SetNeverAllowSessionIsSynthesizedForTests(bool aNeverAllow) {
|
||||
mNeverAllowSessionIsSynthesizedForTests = aNeverAllow;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -45,6 +45,10 @@ namespace dom {
|
||||
class DataTransfer;
|
||||
class Selection;
|
||||
} // namespace dom
|
||||
|
||||
namespace test {
|
||||
class MockDragServiceController;
|
||||
} // namespace test
|
||||
} // namespace mozilla
|
||||
|
||||
/**
|
||||
@ -146,10 +150,13 @@ class nsBaseDragService : public nsIDragService, public nsIDragSession {
|
||||
return retval;
|
||||
}
|
||||
|
||||
virtual bool IsMockService() { return false; }
|
||||
|
||||
bool mCanDrop;
|
||||
bool mOnlyChromeDrop;
|
||||
bool mDoingDrag;
|
||||
bool mSessionIsSynthesizedForTests;
|
||||
|
||||
bool mIsDraggingTextInTextControl;
|
||||
|
||||
// true if in EndDragSession
|
||||
@ -216,6 +223,13 @@ class nsBaseDragService : public nsIDragService, public nsIDragSession {
|
||||
|
||||
// Sub-region for tree-selections.
|
||||
mozilla::Maybe<mozilla::CSSIntRegion> mRegion;
|
||||
|
||||
RefPtr<mozilla::test::MockDragServiceController> mMockController;
|
||||
|
||||
// If this is set, mSessionIsSynthesizedForTests should not become true.
|
||||
// This hack is used to bypass the "old" drag-drop test behavior.
|
||||
// See nsIDragService.idl for details.
|
||||
bool mNeverAllowSessionIsSynthesizedForTests = false;
|
||||
};
|
||||
|
||||
#endif // nsBaseDragService_h__
|
||||
|
@ -15,6 +15,7 @@ webidl Node;
|
||||
webidl Selection;
|
||||
|
||||
interface nsICookieJarSettings;
|
||||
interface nsIMockDragServiceController;
|
||||
|
||||
%{C++
|
||||
#include "mozilla/EventForwards.h"
|
||||
@ -205,6 +206,30 @@ interface nsIDragService : nsISupports
|
||||
* @param aEditingHost The editing host when the editor deletes selection.
|
||||
*/
|
||||
[noscript] void maybeEditorDeletedSourceNode(in Element aEditingHost);
|
||||
|
||||
/**
|
||||
* The controller is used to issue events that would normally come from
|
||||
* the system (when it is not mocked for testing). This allows us to test
|
||||
* without engaging any native DND behavior.
|
||||
*
|
||||
* In order for the controller to be effective, the existing nsIDragService
|
||||
* needs to be replaced with the one in the controller. See
|
||||
* nsIMockDragServiceController for details.
|
||||
*/
|
||||
nsIMockDragServiceController getMockDragController();
|
||||
|
||||
/**
|
||||
* If this is true, mSessionIsSynthesizedForTests should not become true.
|
||||
* This hack is used to bypass the "old" drag-drop test behavior, which needed
|
||||
* special behavior to pass. The new framework requires the actual browser
|
||||
* behavior. The test for whether we are using the new framework or not can
|
||||
* only be done in the main process with nsBaseDragService::IsMockService.
|
||||
* Unfortunately, mSessionIsSynthesizedForTests is inherited from
|
||||
* synthetic mouse events in content processes (when dragging content) so we
|
||||
* set this early in the relevant tests. Once the old tests are replaced,
|
||||
* this can be removed along with mSessionIsSynthesizedForTests.
|
||||
*/
|
||||
[infallible] attribute boolean neverAllowSessionIsSynthesizedForTests;
|
||||
};
|
||||
|
||||
|
||||
|
68
widget/nsIMockDragServiceController.idl
Normal file
68
widget/nsIMockDragServiceController.idl
Normal file
@ -0,0 +1,68 @@
|
||||
/* -*- Mode: IDL; 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 "nsISupports.idl"
|
||||
|
||||
webidl BrowsingContext;
|
||||
|
||||
interface nsIDragService;
|
||||
|
||||
/**
|
||||
* A driver for MockDragService, so that tests can mock system DND behavior.
|
||||
* (System DND is not permitted in tests.)
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(32037ab0-bfc7-11ee-9f4b-09901bed55fa)]
|
||||
interface nsIMockDragServiceController : nsISupports
|
||||
{
|
||||
// Types of event that can be sent by this controller.
|
||||
cenum EventType : 8 {
|
||||
eDragEnter = 0,
|
||||
eDragOver = 1,
|
||||
eDragLeave = 2,
|
||||
eDrop = 3,
|
||||
eMouseDown = 4,
|
||||
eMouseMove = 5,
|
||||
eMouseUp = 6,
|
||||
};
|
||||
|
||||
/**
|
||||
* The nsIDragService that this controller targets. It is a mock version
|
||||
* of the normal nsIDragService. The caller must replace the drag
|
||||
* service in the service manager with this object before sending
|
||||
* drag events to it. This can be done with MockRegistrar or by calling
|
||||
* the nsComponentManager directly.
|
||||
*/
|
||||
readonly attribute nsIDragService mockDragService;
|
||||
|
||||
/**
|
||||
* Issue the given event from our mock drag service, as if that type
|
||||
* of event came from the system. The mock object attempts to mimic the
|
||||
* essential behavior of the native drag classes for this.
|
||||
*
|
||||
* @param aBC A BrowsingContext in the widget the event is
|
||||
* targetted at
|
||||
* @param aEventType Type of event to send
|
||||
* @param aScreenX Screen X coordinate of event
|
||||
* @param aScreenY Screen Y coordinate of event
|
||||
* @param aKeyModifiers Keys that are pressed during event.
|
||||
* NOTE: Keys should be interpreted as selecting
|
||||
* the drag action, but that logic is very
|
||||
* platform-dependent and is not yet mocked.
|
||||
* Drops will be processed as "moves".
|
||||
*/
|
||||
[can_run_script]
|
||||
void sendEvent(in BrowsingContext aBC,
|
||||
in nsIMockDragServiceController_EventType aEventType,
|
||||
in long aScreenX, in long aScreenY,
|
||||
[optional] in uint32_t aKeyModifiers);
|
||||
|
||||
/**
|
||||
* Windows' IDropTarget has the ability to "Cancel" a drag that is
|
||||
* different than dragleave. This emulates that behavior for testing.
|
||||
*/
|
||||
[can_run_script]
|
||||
void cancelDrag([optional] in uint32_t aKeyModifiers);
|
||||
};
|
Loading…
Reference in New Issue
Block a user