/* -*- 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 "InputData.h" #include "mozilla/dom/MouseEventBinding.h" #include "mozilla/dom/Touch.h" #include "mozilla/dom/WheelEventBinding.h" #include "mozilla/MouseEvents.h" #include "mozilla/StaticPrefs_dom.h" #include "mozilla/SwipeTracker.h" #include "mozilla/TextEvents.h" #include "mozilla/TouchEvents.h" #include "nsContentUtils.h" #include "nsDebug.h" #include "nsThreadUtils.h" #include "UnitTransforms.h" #include namespace mozilla { using namespace dom; template WidgetMouseEvent MouseInput::ToWidgetEvent(nsIWidget* aWidget) const; template WidgetPointerEvent MouseInput::ToWidgetEvent(nsIWidget* aWidget) const; InputData::~InputData() = default; InputData::InputData(InputType aInputType) : mInputType(aInputType), mFocusSequenceNumber(0), mLayersId{0}, modifiers(0) {} InputData::InputData(InputType aInputType, TimeStamp aTimeStamp, Modifiers aModifiers) : mInputType(aInputType), mTimeStamp(aTimeStamp), mFocusSequenceNumber(0), mLayersId{0}, modifiers(aModifiers) {} SingleTouchData::SingleTouchData(int32_t aIdentifier, ScreenIntPoint aScreenPoint, ScreenSize aRadius, float aRotationAngle, float aForce) : mIdentifier(aIdentifier), mScreenPoint(aScreenPoint), mRadius(aRadius), mRotationAngle(aRotationAngle), mForce(aForce) {} SingleTouchData::SingleTouchData(int32_t aIdentifier, ParentLayerPoint aLocalScreenPoint, ScreenSize aRadius, float aRotationAngle, float aForce) : mIdentifier(aIdentifier), mLocalScreenPoint(aLocalScreenPoint), mRadius(aRadius), mRotationAngle(aRotationAngle), mForce(aForce) {} SingleTouchData::SingleTouchData() : mIdentifier(0), mRotationAngle(0.0), mForce(0.0) {} already_AddRefed SingleTouchData::ToNewDOMTouch() const { MOZ_ASSERT(NS_IsMainThread(), "Can only create dom::Touch instances on main thread"); RefPtr touch = new Touch(mIdentifier, LayoutDeviceIntPoint::Truncate(mScreenPoint.x, mScreenPoint.y), LayoutDeviceIntPoint::Truncate(mRadius.width, mRadius.height), mRotationAngle, mForce); touch->tiltX = mTiltX; touch->tiltY = mTiltY; touch->twist = mTwist; return touch.forget(); } MultiTouchInput::MultiTouchInput(MultiTouchType aType, uint32_t aTime, TimeStamp aTimeStamp, Modifiers aModifiers) : InputData(MULTITOUCH_INPUT, aTimeStamp, aModifiers), mType(aType), mHandledByAPZ(false) {} MultiTouchInput::MultiTouchInput() : InputData(MULTITOUCH_INPUT), mType(MULTITOUCH_START), mHandledByAPZ(false) {} MultiTouchInput::MultiTouchInput(const WidgetTouchEvent& aTouchEvent) : InputData(MULTITOUCH_INPUT, aTouchEvent.mTimeStamp, aTouchEvent.mModifiers), mHandledByAPZ(aTouchEvent.mFlags.mHandledByAPZ), mButton(aTouchEvent.mButton), mButtons(aTouchEvent.mButtons) { MOZ_ASSERT(NS_IsMainThread(), "Can only copy from WidgetTouchEvent on main thread"); switch (aTouchEvent.mMessage) { case eTouchStart: mType = MULTITOUCH_START; break; case eTouchMove: mType = MULTITOUCH_MOVE; break; case eTouchEnd: mType = MULTITOUCH_END; break; case eTouchCancel: mType = MULTITOUCH_CANCEL; break; default: MOZ_ASSERT_UNREACHABLE("Did not assign a type to a MultiTouchInput"); break; } mScreenOffset = ViewAs( aTouchEvent.mWidget->WidgetToScreenOffset(), PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent); for (size_t i = 0; i < aTouchEvent.mTouches.Length(); i++) { const Touch* domTouch = aTouchEvent.mTouches[i]; // Extract data from weird interfaces. int32_t identifier = domTouch->Identifier(); int32_t radiusX = domTouch->RadiusX(CallerType::System); int32_t radiusY = domTouch->RadiusY(CallerType::System); float rotationAngle = domTouch->RotationAngle(CallerType::System); float force = domTouch->Force(CallerType::System); SingleTouchData data( identifier, ViewAs( domTouch->mRefPoint, PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent), ScreenSize((float)radiusX, (float)radiusY), rotationAngle, force); mTouches.AppendElement(data); } } void MultiTouchInput::Translate(const ScreenPoint& aTranslation) { ScreenIntPoint translation = RoundedToInt(aTranslation); for (auto& touchData : mTouches) { for (auto& historicalData : touchData.mHistoricalData) { historicalData.mScreenPoint.MoveBy(translation.x, translation.y); } touchData.mScreenPoint.MoveBy(translation.x, translation.y); } } WidgetTouchEvent MultiTouchInput::ToWidgetEvent(nsIWidget* aWidget, uint16_t aInputSource) const { MOZ_ASSERT(NS_IsMainThread(), "Can only convert To WidgetTouchEvent on main thread"); MOZ_ASSERT(aInputSource == mozilla::dom::MouseEvent_Binding::MOZ_SOURCE_TOUCH || aInputSource == mozilla::dom::MouseEvent_Binding::MOZ_SOURCE_PEN); EventMessage touchEventMessage = eVoidEvent; switch (mType) { case MULTITOUCH_START: touchEventMessage = eTouchStart; break; case MULTITOUCH_MOVE: touchEventMessage = eTouchMove; break; case MULTITOUCH_END: touchEventMessage = eTouchEnd; break; case MULTITOUCH_CANCEL: touchEventMessage = eTouchCancel; break; default: MOZ_ASSERT_UNREACHABLE( "Did not assign a type to WidgetTouchEvent in MultiTouchInput"); break; } WidgetTouchEvent event(true, touchEventMessage, aWidget); if (touchEventMessage == eVoidEvent) { return event; } event.mModifiers = this->modifiers; event.mTimeStamp = this->mTimeStamp; event.mFlags.mHandledByAPZ = mHandledByAPZ; event.mFocusSequenceNumber = mFocusSequenceNumber; event.mLayersId = mLayersId; event.mInputSource = aInputSource; event.mButton = mButton; event.mButtons = mButtons; for (size_t i = 0; i < mTouches.Length(); i++) { *event.mTouches.AppendElement() = mTouches[i].ToNewDOMTouch(); } return event; } int32_t MultiTouchInput::IndexOfTouch(int32_t aTouchIdentifier) { for (size_t i = 0; i < mTouches.Length(); i++) { if (mTouches[i].mIdentifier == aTouchIdentifier) { return (int32_t)i; } } return -1; } bool MultiTouchInput::TransformToLocal( const ScreenToParentLayerMatrix4x4& aTransform) { for (auto& touchData : mTouches) { for (auto& historicalData : touchData.mHistoricalData) { Maybe historicalPoint = UntransformBy(aTransform, historicalData.mScreenPoint); if (!historicalPoint) { return false; } historicalData.mLocalScreenPoint = *historicalPoint; } Maybe point = UntransformBy(aTransform, touchData.mScreenPoint); if (!point) { return false; } touchData.mLocalScreenPoint = *point; } return true; } MouseInput::MouseInput() : InputData(MOUSE_INPUT), mType(MOUSE_NONE), mButtonType(NONE), mInputSource(0), mButtons(0), mHandledByAPZ(false), mPreventClickEvent(false) {} MouseInput::MouseInput(MouseType aType, ButtonType aButtonType, uint16_t aInputSource, int16_t aButtons, const ScreenPoint& aPoint, TimeStamp aTimeStamp, Modifiers aModifiers) : InputData(MOUSE_INPUT, aTimeStamp, aModifiers), mType(aType), mButtonType(aButtonType), mInputSource(aInputSource), mButtons(aButtons), mOrigin(aPoint), mHandledByAPZ(false), mPreventClickEvent(false) {} MouseInput::MouseInput(const WidgetMouseEventBase& aMouseEvent) : InputData(MOUSE_INPUT, aMouseEvent.mTimeStamp, aMouseEvent.mModifiers), mType(MOUSE_NONE), mButtonType(NONE), mInputSource(aMouseEvent.mInputSource), mButtons(aMouseEvent.mButtons), mHandledByAPZ(aMouseEvent.mFlags.mHandledByAPZ), mPreventClickEvent(aMouseEvent.mClass == eMouseEventClass && aMouseEvent.AsMouseEvent()->mClickEventPrevented) { MOZ_ASSERT(NS_IsMainThread(), "Can only copy from WidgetTouchEvent on main thread"); mButtonType = NONE; switch (aMouseEvent.mButton) { case MouseButton::ePrimary: mButtonType = MouseInput::PRIMARY_BUTTON; break; case MouseButton::eMiddle: mButtonType = MouseInput::MIDDLE_BUTTON; break; case MouseButton::eSecondary: mButtonType = MouseInput::SECONDARY_BUTTON; break; } switch (aMouseEvent.mMessage) { case eMouseMove: mType = MOUSE_MOVE; break; case eMouseUp: mType = MOUSE_UP; break; case eMouseDown: mType = MOUSE_DOWN; break; case eDragStart: mType = MOUSE_DRAG_START; break; case eDragEnd: mType = MOUSE_DRAG_END; break; case eMouseEnterIntoWidget: mType = MOUSE_WIDGET_ENTER; break; case eMouseExitFromWidget: mType = MOUSE_WIDGET_EXIT; break; case eMouseExploreByTouch: mType = MOUSE_EXPLORE_BY_TOUCH; break; case eMouseHitTest: mType = MOUSE_HITTEST; break; case eContextMenu: mType = MOUSE_CONTEXTMENU; break; default: MOZ_ASSERT_UNREACHABLE("Mouse event type not supported"); break; } mOrigin = ScreenPoint(ViewAs( aMouseEvent.mRefPoint, PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent)); } bool MouseInput::IsLeftButton() const { return mButtonType == PRIMARY_BUTTON; } bool MouseInput::TransformToLocal( const ScreenToParentLayerMatrix4x4& aTransform) { Maybe point = UntransformBy(aTransform, mOrigin); if (!point) { return false; } mLocalOrigin = *point; return true; } bool MouseInput::IsPointerEventType() const { return StaticPrefs:: dom_w3c_pointer_events_dispatch_click_as_pointer_event() && mType == MOUSE_CONTEXTMENU; } template WidgetMouseOrPointerEvent MouseInput::ToWidgetEvent(nsIWidget* aWidget) const { MOZ_ASSERT(NS_IsMainThread(), "Can only convert To WidgetTouchEvent on main thread"); const DebugOnly isPointerEvent = std::is_same::value; const DebugOnly isMouseEvent = std::is_same::value; MOZ_ASSERT(!IsPointerEventType() || isPointerEvent, "Please use ToWidgetEvent() for the instance"); MOZ_ASSERT(IsPointerEventType() || isMouseEvent, "Please use ToWidgetEvent() for the instance"); EventMessage msg = eVoidEvent; uint32_t clickCount = 0; Maybe exitFrom; switch (mType) { case MOUSE_MOVE: msg = eMouseMove; break; case MOUSE_UP: msg = eMouseUp; clickCount = 1; break; case MOUSE_DOWN: msg = eMouseDown; clickCount = 1; break; case MOUSE_DRAG_START: msg = eDragStart; break; case MOUSE_DRAG_END: msg = eDragEnd; break; case MOUSE_WIDGET_ENTER: msg = eMouseEnterIntoWidget; break; case MOUSE_WIDGET_EXIT: msg = eMouseExitFromWidget; exitFrom = Some(WidgetMouseEvent::ePlatformChild); break; case MOUSE_EXPLORE_BY_TOUCH: msg = eMouseExploreByTouch; break; case MOUSE_HITTEST: msg = eMouseHitTest; break; case MOUSE_CONTEXTMENU: msg = eContextMenu; MOZ_ASSERT(mButtonType == MouseInput::SECONDARY_BUTTON); break; default: MOZ_ASSERT_UNREACHABLE( "Did not assign a type to WidgetMouseEvent in MouseInput"); break; } WidgetMouseOrPointerEvent event(true, msg, aWidget); if (msg == eVoidEvent) { return event; } switch (mButtonType) { case MouseInput::PRIMARY_BUTTON: event.mButton = MouseButton::ePrimary; break; case MouseInput::MIDDLE_BUTTON: event.mButton = MouseButton::eMiddle; break; case MouseInput::SECONDARY_BUTTON: event.mButton = MouseButton::eSecondary; break; case MouseInput::NONE: default: break; } event.mButtons = mButtons; event.mModifiers = modifiers; event.mTimeStamp = mTimeStamp; event.mLayersId = mLayersId; event.mFlags.mHandledByAPZ = mHandledByAPZ; event.mRefPoint = RoundedToInt(ViewAs( mOrigin, PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent)); event.mClickCount = clickCount; event.mInputSource = mInputSource; event.mFocusSequenceNumber = mFocusSequenceNumber; event.mExitFrom = exitFrom; event.mClickEventPrevented = mPreventClickEvent; return event; } PanGestureInput::PanGestureInput() : InputData(PANGESTURE_INPUT), mType(PANGESTURE_MAYSTART), mLineOrPageDeltaX(0), mLineOrPageDeltaY(0), mUserDeltaMultiplierX(1.0), mUserDeltaMultiplierY(1.0), mHandledByAPZ(false), mOverscrollBehaviorAllowsSwipe(false), mSimulateMomentum(false), mIsNoLineOrPageDelta(true), mMayTriggerSwipe(false) {} PanGestureInput::PanGestureInput(PanGestureType aType, TimeStamp aTimeStamp, const ScreenPoint& aPanStartPoint, const ScreenPoint& aPanDisplacement, Modifiers aModifiers) : InputData(PANGESTURE_INPUT, aTimeStamp, aModifiers), mType(aType), mPanStartPoint(aPanStartPoint), mPanDisplacement(aPanDisplacement), mLineOrPageDeltaX(0), mLineOrPageDeltaY(0), mUserDeltaMultiplierX(1.0), mUserDeltaMultiplierY(1.0), mHandledByAPZ(false), mOverscrollBehaviorAllowsSwipe(false), mSimulateMomentum(false), mIsNoLineOrPageDelta(true) { mMayTriggerSwipe = SwipeTracker::CanTriggerSwipe(*this); } PanGestureInput::PanGestureInput(PanGestureType aType, TimeStamp aTimeStamp, const ScreenPoint& aPanStartPoint, const ScreenPoint& aPanDisplacement, Modifiers aModifiers, IsEligibleForSwipe aIsEligibleForSwipe) : PanGestureInput(aType, aTimeStamp, aPanStartPoint, aPanDisplacement, aModifiers) { mMayTriggerSwipe &= bool(aIsEligibleForSwipe); } void PanGestureInput::SetLineOrPageDeltas(int32_t aLineOrPageDeltaX, int32_t aLineOrPageDeltaY) { mLineOrPageDeltaX = aLineOrPageDeltaX; mLineOrPageDeltaY = aLineOrPageDeltaY; mIsNoLineOrPageDelta = false; } bool PanGestureInput::IsMomentum() const { switch (mType) { case PanGestureInput::PANGESTURE_MOMENTUMSTART: case PanGestureInput::PANGESTURE_MOMENTUMPAN: case PanGestureInput::PANGESTURE_MOMENTUMEND: return true; default: return false; } } WidgetWheelEvent PanGestureInput::ToWidgetEvent(nsIWidget* aWidget) const { WidgetWheelEvent wheelEvent(true, eWheel, aWidget); wheelEvent.mModifiers = this->modifiers; wheelEvent.mTimeStamp = mTimeStamp; wheelEvent.mLayersId = mLayersId; wheelEvent.mRefPoint = RoundedToInt(ViewAs( mPanStartPoint, PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent)); wheelEvent.mButtons = 0; wheelEvent.mMayHaveMomentum = true; // pan inputs may have momentum wheelEvent.mIsMomentum = IsMomentum(); wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX; wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY; wheelEvent.mDeltaX = mPanDisplacement.x; wheelEvent.mDeltaY = mPanDisplacement.y; wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ; wheelEvent.mFocusSequenceNumber = mFocusSequenceNumber; wheelEvent.mIsNoLineOrPageDelta = mIsNoLineOrPageDelta; if (mDeltaType == PanGestureInput::PANDELTA_PAGE) { // widget/gtk is currently the only consumer that uses delta type // PANDELTA_PAGE // Emulate legacy widget/gtk behavior wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_LINE; wheelEvent.mScrollType = WidgetWheelEvent::SCROLL_ASYNCHRONOUSLY; wheelEvent.mDeltaX *= 3; wheelEvent.mDeltaY *= 3; } else { wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL; } return wheelEvent; } bool PanGestureInput::TransformToLocal( const ScreenToParentLayerMatrix4x4& aTransform) { Maybe panStartPoint = UntransformBy(aTransform, mPanStartPoint); if (!panStartPoint) { return false; } mLocalPanStartPoint = *panStartPoint; if (mDeltaType == PanGestureInput::PANDELTA_PAGE) { // Skip transforming the pan displacement because we want // raw page proportion counts. mLocalPanDisplacement = ViewAs( mPanDisplacement, PixelCastJustification::DeltaIsPageProportion); return true; } Maybe panDisplacement = UntransformVector(aTransform, mPanDisplacement, mPanStartPoint); if (!panDisplacement) { return false; } mLocalPanDisplacement = *panDisplacement; return true; } ScreenPoint PanGestureInput::UserMultipliedPanDisplacement() const { return ScreenPoint(mPanDisplacement.x * mUserDeltaMultiplierX, mPanDisplacement.y * mUserDeltaMultiplierY); } ParentLayerPoint PanGestureInput::UserMultipliedLocalPanDisplacement() const { return ParentLayerPoint(mLocalPanDisplacement.x * mUserDeltaMultiplierX, mLocalPanDisplacement.y * mUserDeltaMultiplierY); } static int32_t TakeLargestInt(gfx::Coord* aCoord) { int32_t result(aCoord->value); // truncate towards zero aCoord->value -= result; return result; } /* static */ gfx::IntPoint PanGestureInput::GetIntegerDeltaForEvent( bool aIsStart, float x, float y) { static gfx::Point sAccumulator(0.0f, 0.0f); if (aIsStart) { sAccumulator = gfx::Point(0.0f, 0.0f); } sAccumulator.x += x; sAccumulator.y += y; return gfx::IntPoint(TakeLargestInt(&sAccumulator.x), TakeLargestInt(&sAccumulator.y)); } PinchGestureInput::PinchGestureInput() : InputData(PINCHGESTURE_INPUT), mType(PINCHGESTURE_START), mSource(UNKNOWN), mHandledByAPZ(false) {} PinchGestureInput::PinchGestureInput( PinchGestureType aType, PinchGestureSource aSource, TimeStamp aTimeStamp, const ExternalPoint& aScreenOffset, const ScreenPoint& aFocusPoint, ScreenCoord aCurrentSpan, ScreenCoord aPreviousSpan, Modifiers aModifiers) : InputData(PINCHGESTURE_INPUT, aTimeStamp, aModifiers), mType(aType), mSource(aSource), mFocusPoint(aFocusPoint), mScreenOffset(aScreenOffset), mCurrentSpan(aCurrentSpan), mPreviousSpan(aPreviousSpan), mLineOrPageDeltaY(0), mHandledByAPZ(false) {} bool PinchGestureInput::TransformToLocal( const ScreenToParentLayerMatrix4x4& aTransform) { Maybe point = UntransformBy(aTransform, mFocusPoint); if (!point) { return false; } mLocalFocusPoint = *point; return true; } WidgetWheelEvent PinchGestureInput::ToWidgetEvent(nsIWidget* aWidget) const { WidgetWheelEvent wheelEvent(true, eWheel, aWidget); wheelEvent.mModifiers = this->modifiers | MODIFIER_CONTROL; wheelEvent.mTimeStamp = mTimeStamp; wheelEvent.mLayersId = mLayersId; wheelEvent.mRefPoint = RoundedToInt(ViewAs( mFocusPoint, PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent)); wheelEvent.mButtons = 0; wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ; wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL; wheelEvent.mDeltaY = ComputeDeltaY(aWidget); wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY; MOZ_ASSERT(mType == PINCHGESTURE_END || wheelEvent.mDeltaY != 0.0); return wheelEvent; } double PinchGestureInput::ComputeDeltaY(nsIWidget* aWidget) const { #if defined(XP_DARWIN) // This converts the pinch gesture value to a fake wheel event that has the // control key pressed so that pages can implement custom pinch gesture // handling. It may seem strange that this doesn't use a wheel event with // the deltaZ property set, but this matches Chrome's behavior as described // at https://code.google.com/p/chromium/issues/detail?id=289887 // // The intent of the formula below is to produce numbers similar to Chrome's // implementation of this feature. Chrome implements deltaY using the formula // "-100 * log(1 + [event magnification])" which is unfortunately incorrect. // All deltas for a single pinch gesture should sum to 0 if the start and end // of a pinch gesture end up in the same place. This doesn't happen in Chrome // because they followed Apple's misleading documentation, which implies that // "1 + [event magnification]" is the scale factor. The scale factor is // instead "pow(ratio, [event magnification])" so "[event magnification]" is // already in log space. // // The multiplication by the backing scale factor below counteracts the // division by the backing scale factor in WheelEvent. // We want to set deltaY to |-100.0 * M * GetDefaultScaleInternal()| where M // is [event magnification] but [event magnification] is only available in the // macOS widget code so we have to reverse engineer from mCurrentSpan and // mPreviousSpan (which are derived from [event magnification]) to get it. // Specifically, we know |mCurrentSpan == 100.0| and |mPreviousSpan == 100.0 * // (1.0 - M)|. We can calculate deltaY by solving the mPreviousSpan equation // for M in terms of mPreviousSpan and plugging that into to the formula for // deltaY. return (mPreviousSpan - 100.0) * (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f); #else // This calculation is based on what the Windows and Linux widget code does. // Specifically, it creates a PinchGestureInput with |mCurrentSpan == 100.0 * // currentScale| and |mPreviousSpan == 100.0 * lastScale| where currentScale // is the scale from the current OS event and lastScale is the scale when the // previous OS event happened. On macOS [event magnification] is a relative // change in scale factor, ie if the scale factor changed from 1 to 1.1 it // will be 0.1, similarly if it changed from 1 to 0.9 it will be -0.1. To // calculate the relative scale change on Windows we would calculate |M = // currentScale - lastScale = (mCurrentSpan-mPreviousSpan)/100| and use the // same formula as the macOS code // (|-100.0 * M * GetDefaultScaleInternal()|). return (mPreviousSpan - mCurrentSpan) * (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f); #endif } bool PinchGestureInput::SetLineOrPageDeltaY(nsIWidget* aWidget) { double deltaY = ComputeDeltaY(aWidget); if (deltaY == 0 && mType != PINCHGESTURE_END) { return false; } gfx::IntPoint lineOrPageDelta = PinchGestureInput::GetIntegerDeltaForEvent( (mType == PINCHGESTURE_START), 0, deltaY); mLineOrPageDeltaY = lineOrPageDelta.y; if (mLineOrPageDeltaY == 0) { // For PINCHGESTURE_SCALE events, don't dispatch them. Note that the delta // isn't lost; it remains in the accumulator in GetIntegerDeltaForEvent(). if (mType == PINCHGESTURE_SCALE) { return false; } // On Windows, drop PINCHGESTURE_START as well (the Windows widget code will // defer the START event until we accumulate enough delta). // The Linux widget code doesn't support this, so instead set the event's // mLineOrPageDeltaY to the smallest nonzero amount in the relevant // direction. if (mType == PINCHGESTURE_START) { #ifdef XP_WIN return false; #else mLineOrPageDeltaY = (deltaY >= 0) ? 1 : -1; #endif } // For PINCHGESTURE_END events, not dispatching a DOMMouseScroll for them is // fine. } return true; } /* static */ gfx::IntPoint PinchGestureInput::GetIntegerDeltaForEvent( bool aIsStart, float x, float y) { static gfx::Point sAccumulator(0.0f, 0.0f); if (aIsStart) { sAccumulator = gfx::Point(0.0f, 0.0f); } sAccumulator.x += x; sAccumulator.y += y; return gfx::IntPoint(TakeLargestInt(&sAccumulator.x), TakeLargestInt(&sAccumulator.y)); } TapGestureInput::TapGestureInput() : InputData(TAPGESTURE_INPUT), mType(TAPGESTURE_LONG) {} TapGestureInput::TapGestureInput(TapGestureType aType, TimeStamp aTimeStamp, const ScreenIntPoint& aPoint, Modifiers aModifiers) : InputData(TAPGESTURE_INPUT, aTimeStamp, aModifiers), mType(aType), mPoint(aPoint) {} TapGestureInput::TapGestureInput(TapGestureType aType, TimeStamp aTimeStamp, const ParentLayerPoint& aLocalPoint, Modifiers aModifiers) : InputData(TAPGESTURE_INPUT, aTimeStamp, aModifiers), mType(aType), mLocalPoint(aLocalPoint) {} bool TapGestureInput::TransformToLocal( const ScreenToParentLayerMatrix4x4& aTransform) { Maybe point = UntransformBy(aTransform, mPoint); if (!point) { return false; } mLocalPoint = *point; return true; } WidgetSimpleGestureEvent TapGestureInput::ToWidgetEvent( nsIWidget* aWidget) const { WidgetSimpleGestureEvent event(true, eTapGesture, aWidget); event.mTimeStamp = mTimeStamp; event.mLayersId = mLayersId; event.mRefPoint = ViewAs( mPoint, PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent); event.mButtons = 0; event.mClickCount = 1; event.mModifiers = modifiers; return event; } ScrollWheelInput::ScrollWheelInput() : InputData(SCROLLWHEEL_INPUT), mDeltaType(SCROLLDELTA_LINE), mScrollMode(SCROLLMODE_INSTANT), mHandledByAPZ(false), mDeltaX(0.0), mDeltaY(0.0), mLineOrPageDeltaX(0), mLineOrPageDeltaY(0), mScrollSeriesNumber(0), mUserDeltaMultiplierX(1.0), mUserDeltaMultiplierY(1.0), mMayHaveMomentum(false), mIsMomentum(false), mAPZAction(APZWheelAction::Scroll) {} ScrollWheelInput::ScrollWheelInput( TimeStamp aTimeStamp, Modifiers aModifiers, ScrollMode aScrollMode, ScrollDeltaType aDeltaType, const ScreenPoint& aOrigin, double aDeltaX, double aDeltaY, bool aAllowToOverrideSystemScrollSpeed, WheelDeltaAdjustmentStrategy aWheelDeltaAdjustmentStrategy) : InputData(SCROLLWHEEL_INPUT, aTimeStamp, aModifiers), mDeltaType(aDeltaType), mScrollMode(aScrollMode), mOrigin(aOrigin), mHandledByAPZ(false), mDeltaX(aDeltaX), mDeltaY(aDeltaY), mLineOrPageDeltaX(0), mLineOrPageDeltaY(0), mScrollSeriesNumber(0), mUserDeltaMultiplierX(1.0), mUserDeltaMultiplierY(1.0), mMayHaveMomentum(false), mIsMomentum(false), mAllowToOverrideSystemScrollSpeed(aAllowToOverrideSystemScrollSpeed), mWheelDeltaAdjustmentStrategy(aWheelDeltaAdjustmentStrategy), mAPZAction(APZWheelAction::Scroll) {} ScrollWheelInput::ScrollWheelInput(const WidgetWheelEvent& aWheelEvent) : InputData(SCROLLWHEEL_INPUT, aWheelEvent.mTimeStamp, aWheelEvent.mModifiers), mDeltaType(DeltaTypeForDeltaMode(aWheelEvent.mDeltaMode)), mScrollMode(SCROLLMODE_INSTANT), mHandledByAPZ(aWheelEvent.mFlags.mHandledByAPZ), mDeltaX(aWheelEvent.mDeltaX), mDeltaY(aWheelEvent.mDeltaY), mWheelTicksX(aWheelEvent.mWheelTicksX), mWheelTicksY(aWheelEvent.mWheelTicksX), mLineOrPageDeltaX(aWheelEvent.mLineOrPageDeltaX), mLineOrPageDeltaY(aWheelEvent.mLineOrPageDeltaY), mScrollSeriesNumber(0), mUserDeltaMultiplierX(1.0), mUserDeltaMultiplierY(1.0), mMayHaveMomentum(aWheelEvent.mMayHaveMomentum), mIsMomentum(aWheelEvent.mIsMomentum), mAllowToOverrideSystemScrollSpeed( aWheelEvent.mAllowToOverrideSystemScrollSpeed), mWheelDeltaAdjustmentStrategy(WheelDeltaAdjustmentStrategy::eNone), mAPZAction(APZWheelAction::Scroll) { mOrigin = ScreenPoint(ViewAs( aWheelEvent.mRefPoint, PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent)); } ScrollWheelInput::ScrollDeltaType ScrollWheelInput::DeltaTypeForDeltaMode( uint32_t aDeltaMode) { switch (aDeltaMode) { case WheelEvent_Binding::DOM_DELTA_LINE: return SCROLLDELTA_LINE; case WheelEvent_Binding::DOM_DELTA_PAGE: return SCROLLDELTA_PAGE; case WheelEvent_Binding::DOM_DELTA_PIXEL: return SCROLLDELTA_PIXEL; default: MOZ_CRASH(); } return SCROLLDELTA_LINE; } uint32_t ScrollWheelInput::DeltaModeForDeltaType(ScrollDeltaType aDeltaType) { switch (aDeltaType) { case ScrollWheelInput::SCROLLDELTA_LINE: return WheelEvent_Binding::DOM_DELTA_LINE; case ScrollWheelInput::SCROLLDELTA_PAGE: return WheelEvent_Binding::DOM_DELTA_PAGE; case ScrollWheelInput::SCROLLDELTA_PIXEL: default: return WheelEvent_Binding::DOM_DELTA_PIXEL; } } ScrollUnit ScrollWheelInput::ScrollUnitForDeltaType( ScrollDeltaType aDeltaType) { switch (aDeltaType) { case SCROLLDELTA_LINE: return ScrollUnit::LINES; case SCROLLDELTA_PAGE: return ScrollUnit::PAGES; case SCROLLDELTA_PIXEL: return ScrollUnit::DEVICE_PIXELS; default: MOZ_CRASH(); } return ScrollUnit::LINES; } WidgetWheelEvent ScrollWheelInput::ToWidgetEvent(nsIWidget* aWidget) const { WidgetWheelEvent wheelEvent(true, eWheel, aWidget); wheelEvent.mModifiers = this->modifiers; wheelEvent.mTimeStamp = mTimeStamp; wheelEvent.mLayersId = mLayersId; wheelEvent.mRefPoint = RoundedToInt(ViewAs( mOrigin, PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent)); wheelEvent.mButtons = 0; wheelEvent.mDeltaMode = DeltaModeForDeltaType(mDeltaType); wheelEvent.mMayHaveMomentum = mMayHaveMomentum; wheelEvent.mIsMomentum = mIsMomentum; wheelEvent.mDeltaX = mDeltaX; wheelEvent.mDeltaY = mDeltaY; wheelEvent.mWheelTicksX = mWheelTicksX; wheelEvent.mWheelTicksY = mWheelTicksY; wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX; wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY; wheelEvent.mAllowToOverrideSystemScrollSpeed = mAllowToOverrideSystemScrollSpeed; wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ; wheelEvent.mFocusSequenceNumber = mFocusSequenceNumber; return wheelEvent; } bool ScrollWheelInput::TransformToLocal( const ScreenToParentLayerMatrix4x4& aTransform) { Maybe point = UntransformBy(aTransform, mOrigin); if (!point) { return false; } mLocalOrigin = *point; return true; } bool ScrollWheelInput::IsCustomizedByUserPrefs() const { return mUserDeltaMultiplierX != 1.0 || mUserDeltaMultiplierY != 1.0; } KeyboardInput::KeyboardInput(const WidgetKeyboardEvent& aEvent) : InputData(KEYBOARD_INPUT, aEvent.mTimeStamp, aEvent.mModifiers), mKeyCode(aEvent.mKeyCode), mCharCode(aEvent.mCharCode), mHandledByAPZ(false) { switch (aEvent.mMessage) { case eKeyPress: { mType = KeyboardInput::KEY_PRESS; break; } case eKeyUp: { mType = KeyboardInput::KEY_UP; break; } case eKeyDown: { mType = KeyboardInput::KEY_DOWN; break; } default: mType = KeyboardInput::KEY_OTHER; break; } aEvent.GetShortcutKeyCandidates(mShortcutCandidates); } KeyboardInput::KeyboardInput() : InputData(KEYBOARD_INPUT), mType(KEY_DOWN), mKeyCode(0), mCharCode(0), mHandledByAPZ(false) {} } // namespace mozilla