☠☠ backed out by 48680af02f8f ☠ ☠ | |
author | Rodrigo Silveira <rsilveira@mozilla.com> |
Wed, 26 Feb 2014 21:42:49 -0800 | |
changeset 173128 | c6fc27e68f455521abf328b28555c1ed97556160 |
parent 173127 | f25fb5db8893f3dec09a66c00ded2d546356335b |
child 173129 | 3c9c98992742be0349f65c340fdf53057b2c4fa1 |
push id | 26391 |
push user | cbook@mozilla.com |
push date | Wed, 12 Mar 2014 11:20:34 +0000 |
treeherder | mozilla-central@a56837cfc67c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jimm |
bugs | 953012 |
milestone | 30.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
|
widget/windows/winrt/MetroInput.cpp | file | annotate | diff | comparison | revisions | |
widget/windows/winrt/MetroInput.h | file | annotate | diff | comparison | revisions |
--- a/widget/windows/winrt/MetroInput.cpp +++ b/widget/windows/winrt/MetroInput.cpp @@ -9,25 +9,23 @@ #include "MetroWidget.h" // MetroInput::mWidget #include "mozilla/dom/Touch.h" // Touch #include "nsTArray.h" // Touch lists #include "nsIDOMSimpleGestureEvent.h" // Constants for gesture events #include "InputData.h" #include "UIABridgePrivate.h" #include "MetroAppShell.h" #include "mozilla/MouseEvents.h" -#include "mozilla/TouchEvents.h" #include "mozilla/Preferences.h" // for Preferences #include "WinUtils.h" #include "nsIPresShell.h" #include "nsEventStateManager.h" // System headers (alphabetical) #include <windows.ui.core.h> // ABI::Window::UI::Core namespace -#include <windows.ui.input.h> // ABI::Window::UI::Input namespace //#define DEBUG_INPUT // Using declarations using namespace ABI::Windows; // UI, System, Foundation namespaces using namespace Microsoft; // WRL namespace (ComPtr, possibly others) using namespace mozilla; using namespace mozilla::widget; @@ -233,30 +231,16 @@ namespace { aData->mRotationAngle, aData->mForce); copy->tiltX = aData->tiltX; copy->tiltY = aData->tiltY; touches->AppendElement(copy); aData->mChanged = false; return PL_DHASH_NEXT; } - - // Helper for making sure event ptrs get freed. - class AutoDeleteEvent - { - public: - AutoDeleteEvent(WidgetGUIEvent* aPtr) : - mPtr(aPtr) {} - ~AutoDeleteEvent() { - if (mPtr) { - delete mPtr; - } - } - WidgetGUIEvent* mPtr; - }; } namespace mozilla { namespace widget { namespace winrt { MetroInput::InputPrecisionLevel MetroInput::sCurrentInputLevel = MetroInput::InputPrecisionLevel::LEVEL_IMPRECISE; @@ -535,39 +519,39 @@ MetroInput::IsTouchBehaviorForbidden(con HRESULT MetroInput::OnPointerPressed(UI::Core::ICoreWindow* aSender, UI::Core::IPointerEventArgs* aArgs) { #ifdef DEBUG_INPUT LogFunction(); #endif - WRL::ComPtr<UI::Input::IPointerPoint> currentPoint; + UI::Input::IPointerPoint* currentPoint; WRL::ComPtr<Devices::Input::IPointerDevice> device; Devices::Input::PointerDeviceType deviceType; - aArgs->get_CurrentPoint(currentPoint.GetAddressOf()); + aArgs->get_CurrentPoint(¤tPoint); currentPoint->get_PointerDevice(device.GetAddressOf()); device->get_PointerDeviceType(&deviceType); // For mouse and pen input, simply call our helper function if (deviceType != Devices::Input::PointerDeviceType::PointerDeviceType_Touch) { - OnPointerNonTouch(currentPoint.Get()); - mGestureRecognizer->ProcessDownEvent(currentPoint.Get()); + OnPointerNonTouch(currentPoint); + mGestureRecognizer->ProcessDownEvent(currentPoint); return S_OK; } // This is touch input. UpdateInputLevel(LEVEL_IMPRECISE); // Create the new touch point and add it to our event. uint32_t pointerId; currentPoint->get_PointerId(&pointerId); - nsRefPtr<Touch> touch = CreateDOMTouch(currentPoint.Get()); + nsRefPtr<Touch> touch = CreateDOMTouch(currentPoint); touch->mChanged = true; mTouches.Put(pointerId, touch); WidgetTouchEvent* touchEvent = new WidgetTouchEvent(true, NS_TOUCH_START, mWidget.Get()); if (mTouches.Count() == 1) { // If this is the first touchstart of a touch session reset some @@ -577,35 +561,41 @@ MetroInput::OnPointerPressed(UI::Core::I mRecognizerWantsEvents = true; mCancelable = true; mCanceledIds.Clear(); } else { mCancelable = false; } InitTouchEventTouchList(touchEvent); - DispatchAsyncTouchEvent(touchEvent); + DispatchAsyncTouchEvent(new TouchEventQueueEntry(touchEvent, currentPoint)); - if (ShouldDeliverInputToRecognizer()) { - mGestureRecognizer->ProcessDownEvent(currentPoint.Get()); - } return S_OK; } void -MetroInput::AddPointerMoveDataToRecognizer(UI::Core::IPointerEventArgs* aArgs) +MetroInput::AddPointerMoveDataToRecognizer(IPointerEventArgs* aArgs) { if (ShouldDeliverInputToRecognizer()) { - WRL::ComPtr<Foundation::Collections::IVector<UI::Input::PointerPoint*>> - pointerPoints; + WRL::ComPtr<PointerPointVector> pointerPoints; aArgs->GetIntermediatePoints(pointerPoints.GetAddressOf()); mGestureRecognizer->ProcessMoveEvents(pointerPoints.Get()); } } +void +MetroInput::DeliverNextQueuedNoMoveTouch() { + nsAutoPtr<TouchEventQueueEntry> queueEntry = + static_cast<TouchEventQueueEntry*>(mInputEventQueue.PopFront()); + + if (ShouldDeliverInputToRecognizer()) { + mGestureRecognizer->ProcessMoveEvents(queueEntry->GetPointerPoints()); + } +} + // This event is raised when the user moves the mouse, moves a pen that is // in contact with the surface, or moves a finger that is in contact with // a touch screen. HRESULT MetroInput::OnPointerMoved(UI::Core::ICoreWindow* aSender, UI::Core::IPointerEventArgs* aArgs) { #ifdef DEBUG_INPUT @@ -639,94 +629,98 @@ MetroInput::OnPointerMoved(UI::Core::ICo // Some old drivers cause us to receive a PointerMoved event for a touchId // after we've already received a PointerReleased event for that touchId. // To work around those busted drivers, we simply ignore TouchMoved events // for touchIds that we are not currently tracking. See bug 819223. if (!touch) { return S_OK; } - AddPointerMoveDataToRecognizer(aArgs); + PointerPointVector* pointerPoints; + aArgs->GetIntermediatePoints(&pointerPoints); // If the point hasn't moved, filter it out per the spec. Pres shell does // this as well, but we need to know when our first touchmove is going to // get delivered so we can check the result. if (!HasPointMoved(touch, currentPoint.Get())) { + // Even when the pointer has not moved, the gesture recognizer requires it. + // Doing it asynchronously to keep the event's order. + mInputEventQueue.Push(new TouchEventQueueEntry(nullptr, pointerPoints)); + nsCOMPtr<nsIRunnable> runnable = + NS_NewRunnableMethod(this, &MetroInput::DeliverNextQueuedNoMoveTouch); + NS_DispatchToCurrentThread(runnable); return S_OK; } touch = CreateDOMTouch(currentPoint.Get()); touch->mChanged = true; // replacing old touch point in mTouches map mTouches.Put(pointerId, touch); WidgetTouchEvent* touchEvent = new WidgetTouchEvent(true, NS_TOUCH_MOVE, mWidget.Get()); InitTouchEventTouchList(touchEvent); - DispatchAsyncTouchEvent(touchEvent); + + DispatchAsyncTouchEvent(new TouchEventQueueEntry(touchEvent, pointerPoints)); return S_OK; } // This event is raised when the user lifts the left mouse button, lifts a // pen from the surface, or lifts her/his finger from a touch screen. HRESULT MetroInput::OnPointerReleased(UI::Core::ICoreWindow* aSender, UI::Core::IPointerEventArgs* aArgs) { #ifdef DEBUG_INPUT LogFunction(); #endif - WRL::ComPtr<UI::Input::IPointerPoint> currentPoint; + UI::Input::IPointerPoint* currentPoint; WRL::ComPtr<Devices::Input::IPointerDevice> device; Devices::Input::PointerDeviceType deviceType; - aArgs->get_CurrentPoint(currentPoint.GetAddressOf()); + aArgs->get_CurrentPoint(¤tPoint); currentPoint->get_PointerDevice(device.GetAddressOf()); device->get_PointerDeviceType(&deviceType); // For mouse and pen input, simply call our helper function if (deviceType != Devices::Input::PointerDeviceType::PointerDeviceType_Touch) { - OnPointerNonTouch(currentPoint.Get()); - mGestureRecognizer->ProcessUpEvent(currentPoint.Get()); + OnPointerNonTouch(currentPoint); + mGestureRecognizer->ProcessUpEvent(currentPoint); return S_OK; } // This is touch input. UpdateInputLevel(LEVEL_IMPRECISE); // Get the touch associated with this touch point. uint32_t pointerId; currentPoint->get_PointerId(&pointerId); nsRefPtr<Touch> touch = mTouches.Get(pointerId); // Purge any pending moves for this pointer if (touch->mChanged) { WidgetTouchEvent* touchEvent = new WidgetTouchEvent(true, NS_TOUCH_MOVE, mWidget.Get()); InitTouchEventTouchList(touchEvent); - DispatchAsyncTouchEvent(touchEvent); + DispatchAsyncTouchEvent(new TouchEventQueueEntry(touchEvent, (IPointerPoint*)nullptr)); } // Remove this touch point from our map. Eventually all touch points are // removed for this session since we receive released events for every // point. mTouches.Remove(pointerId); // touchend events only have a single touch; the touch that has been removed WidgetTouchEvent* touchEvent = new WidgetTouchEvent(true, NS_TOUCH_END, mWidget.Get()); - touchEvent->touches.AppendElement(CreateDOMTouch(currentPoint.Get())); - DispatchAsyncTouchEvent(touchEvent); - - if (ShouldDeliverInputToRecognizer()) { - mGestureRecognizer->ProcessUpEvent(currentPoint.Get()); - } + touchEvent->touches.AppendElement(CreateDOMTouch(currentPoint)); + DispatchAsyncTouchEvent(new TouchEventQueueEntry(touchEvent, currentPoint)); return S_OK; } // Tests for chrome vs. content target so we know whether input coordinates need // to be transformed through the apz. Eventually this hit testing should move // into the apz (bug 918288). bool @@ -1131,22 +1125,23 @@ MetroInput::DeliverNextQueuedEventIgnore nsEventStateManager* esm = presShell->GetPresContext()->EventStateManager(); if (esm) { esm->SetContentState(nullptr, NS_EVENT_STATE_HOVER); } } } void -MetroInput::DispatchAsyncTouchEvent(WidgetTouchEvent* aEvent) +MetroInput::DispatchAsyncTouchEvent(TouchEventQueueEntry* queueEntry) { - aEvent->time = ::GetMessageTime(); + WidgetTouchEvent* event = queueEntry->GetEvent(); + event->time = ::GetMessageTime(); mModifierKeyState.Update(); - mModifierKeyState.InitInputEvent(*aEvent); - mInputEventQueue.Push(aEvent); + mModifierKeyState.InitInputEvent(*event); + mInputEventQueue.Push(queueEntry); nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableMethod(this, &MetroInput::DeliverNextQueuedTouchEvent); NS_DispatchToCurrentThread(runnable); } static void DumpTouchIds(const char* aTarget, WidgetTouchEvent* aEvent) { // comment out for touch moves @@ -1347,22 +1342,23 @@ MetroInput::DeliverNextQueuedTouchEvent( * the events we can save ourselves the overhead of delivering dom events. * * Notes: * - never rely on the contents of mTouches here, since this is a delayed * callback. mTouches will likely have been modified. */ nsEventStatus status = nsEventStatus_eIgnore; - WidgetTouchEvent* event = - static_cast<WidgetTouchEvent*>(mInputEventQueue.PopFront()); + nsAutoPtr<TouchEventQueueEntry> queueEntry = + static_cast<TouchEventQueueEntry*>(mInputEventQueue.PopFront()); + + WidgetTouchEvent* event = queueEntry->GetEvent(); + MOZ_ASSERT(event); - AutoDeleteEvent wrap(event); - // Test for non-apz vs. apz target. To do this we only use the first touch // point since that will be the input batch target. Cache this for touch events // since HitTestChrome has to send a dom event. if (mCancelable && event->message == NS_TOUCH_START) { nsRefPtr<Touch> touch = event->touches[0]; LayoutDeviceIntPoint pt = LayoutDeviceIntPoint::FromUntyped(touch->mRefPoint); // This is currently a general contained rect hit test, it may produce a false // positive for overlay chrome elements. Also, some content pages won't support @@ -1382,16 +1378,35 @@ MetroInput::DeliverNextQueuedTouchEvent( if (nsEventStatus_eConsumeNoDefault == status) { mRecognizerWantsEvents = false; mGestureRecognizer->CompleteGesture(); } if (event->message == NS_TOUCH_MOVE) { mCancelable = false; } } + } + + if (ShouldDeliverInputToRecognizer()) { + switch (event->message) { + case NS_TOUCH_START: + mGestureRecognizer->ProcessDownEvent(queueEntry->GetPointerPoint()); + break; + case NS_TOUCH_END: + mGestureRecognizer->ProcessUpEvent(queueEntry->GetPointerPoint()); + break; + case NS_TOUCH_MOVE: + if (queueEntry->GetPointerPoints()) { + mGestureRecognizer->ProcessMoveEvents(queueEntry->GetPointerPoints()); + } + break; + } + } + + if (mNonApzTargetForTouch) { return; } if (mCancelable && event->message == NS_TOUCH_START) { HandleFirstTouchStartEvent(event); return; } else if (mCancelable && event->message == NS_TOUCH_MOVE) { HandleFirstTouchMoveEvent(event);
--- a/widget/windows/winrt/MetroInput.h +++ b/widget/windows/winrt/MetroInput.h @@ -3,25 +3,27 @@ * 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/. */ #pragma once // Moz headers (alphabetical) #include "keyboardlayout.h" // mModifierKeyState #include "nsBaseHashtable.h" // mTouches +#include "nsDeque.h" #include "nsHashKeys.h" // type of key for mTouches -#include "mozwrlbase.h" -#include "nsDeque.h" #include "mozilla/EventForwards.h" #include "mozilla/layers/APZCTreeManager.h" +#include "mozilla/TouchEvents.h" +#include "mozwrlbase.h" // System headers (alphabetical) #include <EventToken.h> // EventRegistrationToken #include <stdint.h> // uint32_t +#include <windows.ui.input.h> // ABI::Window::UI::Input namespace #include <wrl\client.h> // Microsoft::WRL::ComPtr class #include <wrl\implements.h> // Microsoft::WRL::InspectableClass macro // Moz forward declarations class MetroWidget; struct nsIntPoint; namespace mozilla { @@ -63,30 +65,62 @@ namespace ABI { }; }; }; namespace mozilla { namespace widget { namespace winrt { +class TouchEventQueueEntry { +private: + typedef ABI::Windows::UI::Input::IPointerPoint IPointerPoint; + typedef ABI::Windows::UI::Input::PointerPoint PointerPoint; + typedef ABI::Windows::Foundation::Collections::IVector<PointerPoint*> PointerPointVector; + + Microsoft::WRL::ComPtr<PointerPointVector> mPointerPoints; + Microsoft::WRL::ComPtr<IPointerPoint> mPointerPoint; + nsAutoPtr<WidgetTouchEvent> mTouchEvent; + +public: + TouchEventQueueEntry(WidgetTouchEvent* aTouchEvent, IPointerPoint* aPointerPoint) + : mTouchEvent(aTouchEvent), mPointerPoint(aPointerPoint) + { + } + + TouchEventQueueEntry(WidgetTouchEvent* aTouchEvent, PointerPointVector* aPointerPoints) + : mTouchEvent(aTouchEvent), mPointerPoints(aPointerPoints) + { + } + + IPointerPoint* GetPointerPoint() { + return mPointerPoint.Get(); + } + + PointerPointVector* GetPointerPoints() { + return mPointerPoints.Get(); + } + + WidgetTouchEvent* GetEvent() { + return mTouchEvent; + } +}; + + class MetroInput : public Microsoft::WRL::RuntimeClass<IInspectable> { InspectableClass(L"MetroInput", BaseTrust); private: typedef mozilla::layers::AllowedTouchBehavior AllowedTouchBehavior; typedef uint32_t TouchBehaviorFlags; // Devices typedef ABI::Windows::Devices::Input::PointerDeviceType PointerDeviceType; - // Foundation - typedef ABI::Windows::Foundation::Point Point; - // UI::Core typedef ABI::Windows::UI::Core::ICoreWindow ICoreWindow; typedef ABI::Windows::UI::Core::IAcceleratorKeyEventArgs \ IAcceleratorKeyEventArgs; typedef ABI::Windows::UI::Core::IKeyEventArgs IKeyEventArgs; typedef ABI::Windows::UI::Core::IPointerEventArgs IPointerEventArgs; // UI::Input @@ -98,16 +132,21 @@ private: typedef ABI::Windows::UI::Input::IManipulationStartedEventArgs \ IManipulationStartedEventArgs; typedef ABI::Windows::UI::Input::IManipulationUpdatedEventArgs \ IManipulationUpdatedEventArgs; typedef ABI::Windows::UI::Input::IPointerPoint IPointerPoint; typedef ABI::Windows::UI::Input::IRightTappedEventArgs IRightTappedEventArgs; typedef ABI::Windows::UI::Input::ITappedEventArgs ITappedEventArgs; typedef ABI::Windows::UI::Input::ManipulationDelta ManipulationDelta; + typedef ABI::Windows::UI::Input::PointerPoint PointerPoint; + + // Foundation + typedef ABI::Windows::Foundation::Point Point; + typedef ABI::Windows::Foundation::Collections::IVector<PointerPoint*> PointerPointVector; typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid; public: MetroInput(MetroWidget* aWidget, ICoreWindow* aWindow); virtual ~MetroInput(); @@ -278,21 +317,22 @@ private: // on the ui thread via a native event dispatch call get bounced through // the gecko thread event queue using runnables. Most events can be sent // async without the need to see the status result. Those that do have // specialty callbacks. Note any event that arrives to us on the ui thread // that originates from another thread is safe to send sync. // Async event dispatching void DispatchAsyncEventIgnoreStatus(WidgetInputEvent* aEvent); - void DispatchAsyncTouchEvent(WidgetTouchEvent* aEvent); + void DispatchAsyncTouchEvent(TouchEventQueueEntry* queueEntry); // Async event callbacks void DeliverNextQueuedEventIgnoreStatus(); void DeliverNextQueuedTouchEvent(); + void DeliverNextQueuedNoMoveTouch(); void HandleFirstTouchStartEvent(WidgetTouchEvent* aEvent); void HandleFirstTouchMoveEvent(WidgetTouchEvent* aEvent); // Sync event dispatching void DispatchEventIgnoreStatus(WidgetGUIEvent* aEvent); void DispatchTouchCancel(WidgetTouchEvent* aEvent);