зеркало из https://github.com/mozilla/gecko-dev.git
733 строки
21 KiB
C++
733 строки
21 KiB
C++
/* -*- 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 "DirectManipulationOwner.h"
|
|
#include "nsWindow.h"
|
|
#include "WinModifierKeyState.h"
|
|
#include "InputData.h"
|
|
#include "mozilla/StaticPrefs_apz.h"
|
|
#include "mozilla/SwipeTracker.h"
|
|
#include "mozilla/TimeStamp.h"
|
|
#include "mozilla/VsyncDispatcher.h"
|
|
|
|
// Direct Manipulation is only defined for Win8 and newer.
|
|
#if defined(_WIN32_WINNT)
|
|
# undef _WIN32_WINNT
|
|
# define _WIN32_WINNT _WIN32_WINNT_WIN8
|
|
#endif // defined(_WIN32_WINNT)
|
|
#if defined(NTDDI_VERSION)
|
|
# undef NTDDI_VERSION
|
|
# define NTDDI_VERSION NTDDI_WIN8
|
|
#endif // defined(NTDDI_VERSION)
|
|
|
|
#include "directmanipulation.h"
|
|
|
|
namespace mozilla {
|
|
namespace widget {
|
|
|
|
class DManipEventHandler : public IDirectManipulationViewportEventHandler,
|
|
public IDirectManipulationInteractionEventHandler {
|
|
public:
|
|
typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect;
|
|
|
|
friend class DirectManipulationOwner;
|
|
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DManipEventHandler)
|
|
|
|
STDMETHODIMP QueryInterface(REFIID, void**) override;
|
|
|
|
friend class DirectManipulationOwner;
|
|
|
|
explicit DManipEventHandler(nsWindow* aWindow,
|
|
DirectManipulationOwner* aOwner,
|
|
const LayoutDeviceIntRect& aBounds);
|
|
|
|
HRESULT STDMETHODCALLTYPE OnViewportStatusChanged(
|
|
IDirectManipulationViewport* viewport, DIRECTMANIPULATION_STATUS current,
|
|
DIRECTMANIPULATION_STATUS previous) override;
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
OnViewportUpdated(IDirectManipulationViewport* viewport) override;
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
OnContentUpdated(IDirectManipulationViewport* viewport,
|
|
IDirectManipulationContent* content) override;
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
OnInteraction(IDirectManipulationViewport2* viewport,
|
|
DIRECTMANIPULATION_INTERACTION_TYPE interaction) override;
|
|
|
|
void Update();
|
|
|
|
class VObserver final : public mozilla::VsyncObserver {
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DManipEventHandler::VObserver,
|
|
override)
|
|
|
|
public:
|
|
void NotifyVsync(const mozilla::VsyncEvent& aVsync) override {
|
|
if (mOwner) {
|
|
mOwner->Update();
|
|
}
|
|
}
|
|
explicit VObserver(DManipEventHandler* aOwner) : mOwner(aOwner) {}
|
|
|
|
void ClearOwner() { mOwner = nullptr; }
|
|
|
|
private:
|
|
virtual ~VObserver() {}
|
|
DManipEventHandler* mOwner;
|
|
};
|
|
|
|
enum class State { eNone, ePanning, eInertia, ePinching };
|
|
void TransitionToState(State aNewState);
|
|
|
|
enum class Phase { eStart, eMiddle, eEnd };
|
|
// Return value indicates if we sent an event or not and hence if we should
|
|
// update mLastScale. (We only want to send pinch events if the computed
|
|
// deltaY for the corresponding WidgetWheelEvent would be non-zero.)
|
|
bool SendPinch(Phase aPhase, float aScale);
|
|
void SendPan(Phase aPhase, float x, float y, bool aIsInertia);
|
|
static void SendPanCommon(nsWindow* aWindow, Phase aPhase,
|
|
ScreenPoint aPosition, double aDeltaX,
|
|
double aDeltaY, Modifiers aMods, bool aIsInertia);
|
|
|
|
static void SynthesizeNativeTouchpadPan(
|
|
nsWindow* aWindow, nsIWidget::TouchpadGesturePhase aEventPhase,
|
|
LayoutDeviceIntPoint aPoint, double aDeltaX, double aDeltaY,
|
|
int32_t aModifierFlags);
|
|
|
|
private:
|
|
virtual ~DManipEventHandler() = default;
|
|
|
|
nsWindow* mWindow;
|
|
DirectManipulationOwner* mOwner;
|
|
RefPtr<VObserver> mObserver;
|
|
float mLastScale;
|
|
float mLastXOffset;
|
|
float mLastYOffset;
|
|
LayoutDeviceIntRect mBounds;
|
|
bool mShouldSendPanStart;
|
|
bool mShouldSendPinchStart;
|
|
State mState = State::eNone;
|
|
};
|
|
|
|
DManipEventHandler::DManipEventHandler(nsWindow* aWindow,
|
|
DirectManipulationOwner* aOwner,
|
|
const LayoutDeviceIntRect& aBounds)
|
|
: mWindow(aWindow),
|
|
mOwner(aOwner),
|
|
mLastScale(1.f),
|
|
mLastXOffset(0.f),
|
|
mLastYOffset(0.f),
|
|
mBounds(aBounds),
|
|
mShouldSendPanStart(false),
|
|
mShouldSendPinchStart(false) {}
|
|
|
|
STDMETHODIMP
|
|
DManipEventHandler::QueryInterface(REFIID iid, void** ppv) {
|
|
const IID IID_IDirectManipulationViewportEventHandler =
|
|
__uuidof(IDirectManipulationViewportEventHandler);
|
|
const IID IID_IDirectManipulationInteractionEventHandler =
|
|
__uuidof(IDirectManipulationInteractionEventHandler);
|
|
|
|
if ((IID_IUnknown == iid) ||
|
|
(IID_IDirectManipulationViewportEventHandler == iid)) {
|
|
*ppv = static_cast<IDirectManipulationViewportEventHandler*>(this);
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
if (IID_IDirectManipulationInteractionEventHandler == iid) {
|
|
*ppv = static_cast<IDirectManipulationInteractionEventHandler*>(this);
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
HRESULT
|
|
DManipEventHandler::OnViewportStatusChanged(
|
|
IDirectManipulationViewport* viewport, DIRECTMANIPULATION_STATUS current,
|
|
DIRECTMANIPULATION_STATUS previous) {
|
|
if (current == previous) {
|
|
return S_OK;
|
|
}
|
|
|
|
if (current == DIRECTMANIPULATION_INERTIA) {
|
|
if (previous != DIRECTMANIPULATION_RUNNING || mState != State::ePanning) {
|
|
// xxx transition to none?
|
|
return S_OK;
|
|
}
|
|
|
|
TransitionToState(State::eInertia);
|
|
}
|
|
|
|
if (current == DIRECTMANIPULATION_RUNNING) {
|
|
// INERTIA -> RUNNING, should start a new sequence.
|
|
if (previous == DIRECTMANIPULATION_INERTIA) {
|
|
TransitionToState(State::eNone);
|
|
}
|
|
}
|
|
|
|
if (current != DIRECTMANIPULATION_ENABLED &&
|
|
current != DIRECTMANIPULATION_READY) {
|
|
return S_OK;
|
|
}
|
|
|
|
// A session has ended, reset the transform.
|
|
if (mLastScale != 1.f || mLastXOffset != 0.f || mLastYOffset != 0.f) {
|
|
HRESULT hr =
|
|
viewport->ZoomToRect(0, 0, mBounds.width, mBounds.height, false);
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("ZoomToRect failed");
|
|
}
|
|
}
|
|
mLastScale = 1.f;
|
|
mLastXOffset = 0.f;
|
|
mLastYOffset = 0.f;
|
|
|
|
TransitionToState(State::eNone);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
DManipEventHandler::OnViewportUpdated(IDirectManipulationViewport* viewport) {
|
|
return S_OK;
|
|
}
|
|
|
|
void DManipEventHandler::TransitionToState(State aNewState) {
|
|
if (mState == aNewState) {
|
|
return;
|
|
}
|
|
|
|
State prevState = mState;
|
|
mState = aNewState;
|
|
|
|
// End the previous sequence.
|
|
switch (prevState) {
|
|
case State::ePanning: {
|
|
// ePanning -> *: PanEnd
|
|
SendPan(Phase::eEnd, 0.f, 0.f, false);
|
|
break;
|
|
}
|
|
case State::eInertia: {
|
|
// eInertia -> *: MomentumEnd
|
|
SendPan(Phase::eEnd, 0.f, 0.f, true);
|
|
break;
|
|
}
|
|
case State::ePinching: {
|
|
MOZ_ASSERT(aNewState == State::eNone);
|
|
// ePinching -> eNone: PinchEnd. ePinching should only transition to
|
|
// eNone.
|
|
// Only send a pinch end if we sent a pinch start.
|
|
if (!mShouldSendPinchStart) {
|
|
SendPinch(Phase::eEnd, 0.f);
|
|
}
|
|
mShouldSendPinchStart = false;
|
|
break;
|
|
}
|
|
case State::eNone: {
|
|
// eNone -> *: no cleanup is needed.
|
|
break;
|
|
}
|
|
default:
|
|
MOZ_ASSERT(false);
|
|
}
|
|
|
|
// Start the new sequence.
|
|
switch (aNewState) {
|
|
case State::ePanning: {
|
|
// eInertia, eNone -> ePanning: PanStart.
|
|
// We're being called from OnContentUpdated, it has the coords we need to
|
|
// pass to SendPan(Phase::eStart), so set mShouldSendPanStart and when we
|
|
// return OnContentUpdated will check it and call SendPan(Phase::eStart).
|
|
mShouldSendPanStart = true;
|
|
break;
|
|
}
|
|
case State::eInertia: {
|
|
// Only ePanning can transition to eInertia.
|
|
MOZ_ASSERT(prevState == State::ePanning);
|
|
SendPan(Phase::eStart, 0.f, 0.f, true);
|
|
break;
|
|
}
|
|
case State::ePinching: {
|
|
// * -> ePinching: PinchStart.
|
|
// Pinch gesture may begin with some scroll events.
|
|
// We're being called from OnContentUpdated, it has the scale we need to
|
|
// pass to SendPinch(Phase::eStart), so set mShouldSendPinchStart and when
|
|
// we return OnContentUpdated will check it and call
|
|
// SendPinch(Phase::eStart).
|
|
mShouldSendPinchStart = true;
|
|
break;
|
|
}
|
|
case State::eNone: {
|
|
// * -> eNone: only cleanup is needed.
|
|
break;
|
|
}
|
|
default:
|
|
MOZ_ASSERT(false);
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
DManipEventHandler::OnContentUpdated(IDirectManipulationViewport* viewport,
|
|
IDirectManipulationContent* content) {
|
|
float transform[6];
|
|
HRESULT hr = content->GetContentTransform(transform, ARRAYSIZE(transform));
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("GetContentTransform failed");
|
|
return S_OK;
|
|
}
|
|
|
|
float scale = transform[0];
|
|
float xoffset = transform[4];
|
|
float yoffset = transform[5];
|
|
|
|
// Not different from last time.
|
|
if (FuzzyEqualsMultiplicative(scale, mLastScale) && xoffset == mLastXOffset &&
|
|
yoffset == mLastYOffset) {
|
|
return S_OK;
|
|
}
|
|
|
|
// Consider this is a Scroll when scale factor equals 1.0.
|
|
if (FuzzyEqualsMultiplicative(scale, 1.f)) {
|
|
if (mState == State::eNone) {
|
|
TransitionToState(State::ePanning);
|
|
}
|
|
} else {
|
|
// Pinch gesture may begin with some scroll events.
|
|
TransitionToState(State::ePinching);
|
|
}
|
|
|
|
if (mState == State::ePanning || mState == State::eInertia) {
|
|
// Accumulate the offset (by not updating mLastX/YOffset) until we have at
|
|
// least one pixel.
|
|
float dx = std::abs(mLastXOffset - xoffset);
|
|
float dy = std::abs(mLastYOffset - yoffset);
|
|
if (dx < 1.f && dy < 1.f) {
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
bool updateLastScale = true;
|
|
if (mState == State::ePanning) {
|
|
if (mShouldSendPanStart) {
|
|
SendPan(Phase::eStart, mLastXOffset - xoffset, mLastYOffset - yoffset,
|
|
false);
|
|
mShouldSendPanStart = false;
|
|
} else {
|
|
SendPan(Phase::eMiddle, mLastXOffset - xoffset, mLastYOffset - yoffset,
|
|
false);
|
|
}
|
|
} else if (mState == State::eInertia) {
|
|
SendPan(Phase::eMiddle, mLastXOffset - xoffset, mLastYOffset - yoffset,
|
|
true);
|
|
} else if (mState == State::ePinching) {
|
|
if (mShouldSendPinchStart) {
|
|
updateLastScale = SendPinch(Phase::eStart, scale);
|
|
// Only clear mShouldSendPinchStart if we actually sent the event
|
|
// (updateLastScale tells us if we sent an event).
|
|
if (updateLastScale) {
|
|
mShouldSendPinchStart = false;
|
|
}
|
|
} else {
|
|
updateLastScale = SendPinch(Phase::eMiddle, scale);
|
|
}
|
|
}
|
|
|
|
if (updateLastScale) {
|
|
mLastScale = scale;
|
|
}
|
|
mLastXOffset = xoffset;
|
|
mLastYOffset = yoffset;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
DManipEventHandler::OnInteraction(
|
|
IDirectManipulationViewport2* viewport,
|
|
DIRECTMANIPULATION_INTERACTION_TYPE interaction) {
|
|
if (interaction == DIRECTMANIPULATION_INTERACTION_BEGIN) {
|
|
if (!mObserver) {
|
|
mObserver = new VObserver(this);
|
|
}
|
|
|
|
gfxWindowsPlatform::GetPlatform()
|
|
->GetGlobalVsyncDispatcher()
|
|
->AddMainThreadObserver(mObserver);
|
|
}
|
|
|
|
if (mObserver && interaction == DIRECTMANIPULATION_INTERACTION_END) {
|
|
gfxWindowsPlatform::GetPlatform()
|
|
->GetGlobalVsyncDispatcher()
|
|
->RemoveMainThreadObserver(mObserver);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void DManipEventHandler::Update() {
|
|
if (mOwner) {
|
|
mOwner->Update();
|
|
}
|
|
}
|
|
|
|
void DirectManipulationOwner::Update() {
|
|
if (mDmUpdateManager) {
|
|
mDmUpdateManager->Update(nullptr);
|
|
}
|
|
}
|
|
|
|
DirectManipulationOwner::DirectManipulationOwner(nsWindow* aWindow)
|
|
: mWindow(aWindow) {}
|
|
|
|
DirectManipulationOwner::~DirectManipulationOwner() { Destroy(); }
|
|
|
|
bool DManipEventHandler::SendPinch(Phase aPhase, float aScale) {
|
|
if (!mWindow) {
|
|
return false;
|
|
}
|
|
|
|
if (aScale == mLastScale && aPhase != Phase::eEnd) {
|
|
return false;
|
|
}
|
|
|
|
PinchGestureInput::PinchGestureType pinchGestureType =
|
|
PinchGestureInput::PINCHGESTURE_SCALE;
|
|
switch (aPhase) {
|
|
case Phase::eStart:
|
|
pinchGestureType = PinchGestureInput::PINCHGESTURE_START;
|
|
break;
|
|
case Phase::eMiddle:
|
|
pinchGestureType = PinchGestureInput::PINCHGESTURE_SCALE;
|
|
break;
|
|
case Phase::eEnd:
|
|
pinchGestureType = PinchGestureInput::PINCHGESTURE_END;
|
|
break;
|
|
default:
|
|
MOZ_ASSERT_UNREACHABLE("handle all enum values");
|
|
}
|
|
|
|
TimeStamp eventTimeStamp = TimeStamp::Now();
|
|
|
|
ModifierKeyState modifierKeyState;
|
|
Modifiers mods = modifierKeyState.GetModifiers();
|
|
|
|
ExternalPoint screenOffset = ViewAs<ExternalPixel>(
|
|
mWindow->WidgetToScreenOffset(),
|
|
PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
|
|
|
|
POINT cursor_pos;
|
|
::GetCursorPos(&cursor_pos);
|
|
HWND wnd = static_cast<HWND>(mWindow->GetNativeData(NS_NATIVE_WINDOW));
|
|
::ScreenToClient(wnd, &cursor_pos);
|
|
ScreenPoint position = {(float)cursor_pos.x, (float)cursor_pos.y};
|
|
|
|
PinchGestureInput event{pinchGestureType,
|
|
PinchGestureInput::TRACKPAD,
|
|
eventTimeStamp,
|
|
screenOffset,
|
|
position,
|
|
100.0 * ((aPhase == Phase::eEnd) ? 1.f : aScale),
|
|
100.0 * ((aPhase == Phase::eEnd) ? 1.f : mLastScale),
|
|
mods};
|
|
|
|
if (!event.SetLineOrPageDeltaY(mWindow)) {
|
|
return false;
|
|
}
|
|
|
|
mWindow->SendAnAPZEvent(event);
|
|
|
|
return true;
|
|
}
|
|
|
|
void DManipEventHandler::SendPan(Phase aPhase, float x, float y,
|
|
bool aIsInertia) {
|
|
if (!mWindow) {
|
|
return;
|
|
}
|
|
|
|
ModifierKeyState modifierKeyState;
|
|
Modifiers mods = modifierKeyState.GetModifiers();
|
|
|
|
POINT cursor_pos;
|
|
::GetCursorPos(&cursor_pos);
|
|
HWND wnd = static_cast<HWND>(mWindow->GetNativeData(NS_NATIVE_WINDOW));
|
|
::ScreenToClient(wnd, &cursor_pos);
|
|
ScreenPoint position = {(float)cursor_pos.x, (float)cursor_pos.y};
|
|
|
|
SendPanCommon(mWindow, aPhase, position, x, y, mods, aIsInertia);
|
|
}
|
|
|
|
/* static */
|
|
void DManipEventHandler::SendPanCommon(nsWindow* aWindow, Phase aPhase,
|
|
ScreenPoint aPosition, double aDeltaX,
|
|
double aDeltaY, Modifiers aMods,
|
|
bool aIsInertia) {
|
|
if (!aWindow) {
|
|
return;
|
|
}
|
|
|
|
PanGestureInput::PanGestureType panGestureType =
|
|
PanGestureInput::PANGESTURE_PAN;
|
|
if (aIsInertia) {
|
|
switch (aPhase) {
|
|
case Phase::eStart:
|
|
panGestureType = PanGestureInput::PANGESTURE_MOMENTUMSTART;
|
|
break;
|
|
case Phase::eMiddle:
|
|
panGestureType = PanGestureInput::PANGESTURE_MOMENTUMPAN;
|
|
break;
|
|
case Phase::eEnd:
|
|
panGestureType = PanGestureInput::PANGESTURE_MOMENTUMEND;
|
|
break;
|
|
default:
|
|
MOZ_ASSERT_UNREACHABLE("handle all enum values");
|
|
}
|
|
} else {
|
|
switch (aPhase) {
|
|
case Phase::eStart:
|
|
panGestureType = PanGestureInput::PANGESTURE_START;
|
|
break;
|
|
case Phase::eMiddle:
|
|
panGestureType = PanGestureInput::PANGESTURE_PAN;
|
|
break;
|
|
case Phase::eEnd:
|
|
panGestureType = PanGestureInput::PANGESTURE_END;
|
|
break;
|
|
default:
|
|
MOZ_ASSERT_UNREACHABLE("handle all enum values");
|
|
}
|
|
}
|
|
|
|
TimeStamp eventTimeStamp = TimeStamp::Now();
|
|
|
|
PanGestureInput event{panGestureType, eventTimeStamp, aPosition,
|
|
ScreenPoint(aDeltaX, aDeltaY), aMods};
|
|
|
|
aWindow->SendAnAPZEvent(event);
|
|
}
|
|
|
|
void DirectManipulationOwner::Init(const LayoutDeviceIntRect& aBounds) {
|
|
HRESULT hr = CoCreateInstance(
|
|
CLSID_DirectManipulationManager, nullptr, CLSCTX_INPROC_SERVER,
|
|
IID_IDirectManipulationManager, getter_AddRefs(mDmManager));
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("CoCreateInstance(CLSID_DirectManipulationManager failed");
|
|
mDmManager = nullptr;
|
|
return;
|
|
}
|
|
|
|
hr = mDmManager->GetUpdateManager(IID_IDirectManipulationUpdateManager,
|
|
getter_AddRefs(mDmUpdateManager));
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("GetUpdateManager failed");
|
|
mDmManager = nullptr;
|
|
mDmUpdateManager = nullptr;
|
|
return;
|
|
}
|
|
|
|
HWND wnd = static_cast<HWND>(mWindow->GetNativeData(NS_NATIVE_WINDOW));
|
|
|
|
hr = mDmManager->CreateViewport(nullptr, wnd, IID_IDirectManipulationViewport,
|
|
getter_AddRefs(mDmViewport));
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("CreateViewport failed");
|
|
mDmManager = nullptr;
|
|
mDmUpdateManager = nullptr;
|
|
mDmViewport = nullptr;
|
|
return;
|
|
}
|
|
|
|
DIRECTMANIPULATION_CONFIGURATION configuration =
|
|
DIRECTMANIPULATION_CONFIGURATION_INTERACTION |
|
|
DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_X |
|
|
DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_Y |
|
|
DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_INERTIA |
|
|
DIRECTMANIPULATION_CONFIGURATION_RAILS_X |
|
|
DIRECTMANIPULATION_CONFIGURATION_RAILS_Y;
|
|
if (StaticPrefs::apz_allow_zooming()) {
|
|
configuration |= DIRECTMANIPULATION_CONFIGURATION_SCALING;
|
|
}
|
|
|
|
hr = mDmViewport->ActivateConfiguration(configuration);
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("ActivateConfiguration failed");
|
|
mDmManager = nullptr;
|
|
mDmUpdateManager = nullptr;
|
|
mDmViewport = nullptr;
|
|
return;
|
|
}
|
|
|
|
hr = mDmViewport->SetViewportOptions(
|
|
DIRECTMANIPULATION_VIEWPORT_OPTIONS_MANUALUPDATE);
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("SetViewportOptions failed");
|
|
mDmManager = nullptr;
|
|
mDmUpdateManager = nullptr;
|
|
mDmViewport = nullptr;
|
|
return;
|
|
}
|
|
|
|
mDmHandler = new DManipEventHandler(mWindow, this, aBounds);
|
|
|
|
hr = mDmViewport->AddEventHandler(wnd, mDmHandler.get(),
|
|
&mDmViewportHandlerCookie);
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("AddEventHandler failed");
|
|
mDmManager = nullptr;
|
|
mDmUpdateManager = nullptr;
|
|
mDmViewport = nullptr;
|
|
mDmHandler = nullptr;
|
|
return;
|
|
}
|
|
|
|
RECT rect = {0, 0, aBounds.Width(), aBounds.Height()};
|
|
hr = mDmViewport->SetViewportRect(&rect);
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("SetViewportRect failed");
|
|
mDmManager = nullptr;
|
|
mDmUpdateManager = nullptr;
|
|
mDmViewport = nullptr;
|
|
mDmHandler = nullptr;
|
|
return;
|
|
}
|
|
|
|
hr = mDmManager->Activate(wnd);
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("manager Activate failed");
|
|
mDmManager = nullptr;
|
|
mDmUpdateManager = nullptr;
|
|
mDmViewport = nullptr;
|
|
mDmHandler = nullptr;
|
|
return;
|
|
}
|
|
|
|
hr = mDmViewport->Enable();
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("mDmViewport->Enable failed");
|
|
mDmManager = nullptr;
|
|
mDmUpdateManager = nullptr;
|
|
mDmViewport = nullptr;
|
|
mDmHandler = nullptr;
|
|
return;
|
|
}
|
|
|
|
hr = mDmUpdateManager->Update(nullptr);
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("mDmUpdateManager->Update failed");
|
|
mDmManager = nullptr;
|
|
mDmUpdateManager = nullptr;
|
|
mDmViewport = nullptr;
|
|
mDmHandler = nullptr;
|
|
return;
|
|
}
|
|
}
|
|
|
|
void DirectManipulationOwner::ResizeViewport(
|
|
const LayoutDeviceIntRect& aBounds) {
|
|
if (mDmHandler) {
|
|
mDmHandler->mBounds = aBounds;
|
|
}
|
|
|
|
if (mDmViewport) {
|
|
RECT rect = {0, 0, aBounds.Width(), aBounds.Height()};
|
|
HRESULT hr = mDmViewport->SetViewportRect(&rect);
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("SetViewportRect failed");
|
|
}
|
|
}
|
|
}
|
|
|
|
void DirectManipulationOwner::Destroy() {
|
|
if (mDmHandler) {
|
|
mDmHandler->mWindow = nullptr;
|
|
mDmHandler->mOwner = nullptr;
|
|
if (mDmHandler->mObserver) {
|
|
gfxWindowsPlatform::GetPlatform()
|
|
->GetGlobalVsyncDispatcher()
|
|
->RemoveMainThreadObserver(mDmHandler->mObserver);
|
|
mDmHandler->mObserver->ClearOwner();
|
|
mDmHandler->mObserver = nullptr;
|
|
}
|
|
}
|
|
|
|
HRESULT hr;
|
|
if (mDmViewport) {
|
|
hr = mDmViewport->Stop();
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("mDmViewport->Stop() failed");
|
|
}
|
|
|
|
hr = mDmViewport->Disable();
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("mDmViewport->Disable() failed");
|
|
}
|
|
|
|
hr = mDmViewport->RemoveEventHandler(mDmViewportHandlerCookie);
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("mDmViewport->RemoveEventHandler() failed");
|
|
}
|
|
|
|
hr = mDmViewport->Abandon();
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("mDmViewport->Abandon() failed");
|
|
}
|
|
}
|
|
|
|
if (mWindow) {
|
|
HWND wnd = static_cast<HWND>(mWindow->GetNativeData(NS_NATIVE_WINDOW));
|
|
|
|
if (mDmManager) {
|
|
hr = mDmManager->Deactivate(wnd);
|
|
if (!SUCCEEDED(hr)) {
|
|
NS_WARNING("mDmManager->Deactivate() failed");
|
|
}
|
|
}
|
|
}
|
|
|
|
mDmHandler = nullptr;
|
|
mDmViewport = nullptr;
|
|
mDmUpdateManager = nullptr;
|
|
mDmManager = nullptr;
|
|
mWindow = nullptr;
|
|
}
|
|
|
|
void DirectManipulationOwner::SetContact(UINT aContactId) {
|
|
if (mDmViewport) {
|
|
mDmViewport->SetContact(aContactId);
|
|
}
|
|
}
|
|
|
|
/*static */ void DirectManipulationOwner::SynthesizeNativeTouchpadPan(
|
|
nsWindow* aWindow, nsIWidget::TouchpadGesturePhase aEventPhase,
|
|
LayoutDeviceIntPoint aPoint, double aDeltaX, double aDeltaY,
|
|
int32_t aModifierFlags) {
|
|
DManipEventHandler::SynthesizeNativeTouchpadPan(
|
|
aWindow, aEventPhase, aPoint, aDeltaX, aDeltaY, aModifierFlags);
|
|
}
|
|
|
|
/*static */ void DManipEventHandler::SynthesizeNativeTouchpadPan(
|
|
nsWindow* aWindow, nsIWidget::TouchpadGesturePhase aEventPhase,
|
|
LayoutDeviceIntPoint aPoint, double aDeltaX, double aDeltaY,
|
|
int32_t aModifierFlags) {
|
|
ScreenPoint position = {(float)aPoint.x, (float)aPoint.y};
|
|
Phase phase = Phase::eStart;
|
|
if (aEventPhase == nsIWidget::PHASE_UPDATE) {
|
|
phase = Phase::eMiddle;
|
|
}
|
|
|
|
if (aEventPhase == nsIWidget::PHASE_END) {
|
|
phase = Phase::eEnd;
|
|
}
|
|
SendPanCommon(aWindow, phase, position, aDeltaX, aDeltaY, aModifierFlags,
|
|
/* aIsInertia = */ false);
|
|
}
|
|
|
|
} // namespace widget
|
|
} // namespace mozilla
|