/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=99: */ /* 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 "mozilla/layers/IAPZCTreeManager.h" #include "gfxPrefs.h" // for gfxPrefs #include "InputData.h" // for InputData, etc #include "mozilla/EventStateManager.h" // for WheelPrefs #include "mozilla/layers/APZThreadUtils.h" // for AssertOnCompositorThread, etc #include "mozilla/MouseEvents.h" // for WidgetMouseEvent #include "mozilla/TouchEvents.h" // for WidgetTouchEvent namespace mozilla { namespace layers { static bool WillHandleMouseEvent(const WidgetMouseEventBase& aEvent) { return aEvent.mMessage == eMouseMove || aEvent.mMessage == eMouseDown || aEvent.mMessage == eMouseUp || aEvent.mMessage == eDragEnd; } // Returns whether or not a wheel event action will be (or was) performed by // APZ. If this returns true, the event must not perform a synchronous // scroll. // // Even if this returns false, all wheel events in APZ-aware widgets must // be sent through APZ so they are transformed correctly for TabParent. static bool WillHandleWheelEvent(WidgetWheelEvent* aEvent) { return EventStateManager::WheelEventIsScrollAction(aEvent) && (aEvent->mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE || aEvent->mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL || aEvent->mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE); } nsEventStatus IAPZCTreeManager::ReceiveInputEvent( WidgetInputEvent& aEvent, ScrollableLayerGuid* aOutTargetGuid, uint64_t* aOutInputBlockId) { APZThreadUtils::AssertOnControllerThread(); // Initialize aOutInputBlockId to a sane value, and then later we overwrite // it if the input event goes into a block. if (aOutInputBlockId) { *aOutInputBlockId = 0; } switch (aEvent.mClass) { case eMouseEventClass: case eDragEventClass: { WidgetMouseEvent& mouseEvent = *aEvent.AsMouseEvent(); // Note, we call this before having transformed the reference point. if (mouseEvent.IsReal()) { UpdateWheelTransaction(mouseEvent.mRefPoint, mouseEvent.mMessage); } if (WillHandleMouseEvent(mouseEvent)) { MouseInput input(mouseEvent); input.mOrigin = ScreenPoint(mouseEvent.mRefPoint.x, mouseEvent.mRefPoint.y); nsEventStatus status = ReceiveInputEvent(input, aOutTargetGuid, aOutInputBlockId); mouseEvent.mRefPoint.x = input.mOrigin.x; mouseEvent.mRefPoint.y = input.mOrigin.y; mouseEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ; return status; } TransformEventRefPoint(&mouseEvent.mRefPoint, aOutTargetGuid); return nsEventStatus_eIgnore; } case eTouchEventClass: { WidgetTouchEvent& touchEvent = *aEvent.AsTouchEvent(); MultiTouchInput touchInput(touchEvent); nsEventStatus result = ReceiveInputEvent(touchInput, aOutTargetGuid, aOutInputBlockId); // touchInput was modified in-place to possibly remove some // touch points (if we are overscrolled), and the coordinates were // modified using the APZ untransform. We need to copy these changes // back into the WidgetInputEvent. touchEvent.mTouches.Clear(); touchEvent.mTouches.SetCapacity(touchInput.mTouches.Length()); for (size_t i = 0; i < touchInput.mTouches.Length(); i++) { *touchEvent.mTouches.AppendElement() = touchInput.mTouches[i].ToNewDOMTouch(); } touchEvent.mFlags.mHandledByAPZ = touchInput.mHandledByAPZ; return result; } case eWheelEventClass: { WidgetWheelEvent& wheelEvent = *aEvent.AsWheelEvent(); if (WillHandleWheelEvent(&wheelEvent)) { ScrollWheelInput::ScrollMode scrollMode = ScrollWheelInput::SCROLLMODE_INSTANT; if (gfxPrefs::SmoothScrollEnabled() && ((wheelEvent.mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE && gfxPrefs::WheelSmoothScrollEnabled()) || (wheelEvent.mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE && gfxPrefs::PageSmoothScrollEnabled()))) { scrollMode = ScrollWheelInput::SCROLLMODE_SMOOTH; } ScreenPoint origin(wheelEvent.mRefPoint.x, wheelEvent.mRefPoint.y); ScrollWheelInput input(wheelEvent.mTime, wheelEvent.mTimeStamp, 0, scrollMode, ScrollWheelInput::DeltaTypeForDeltaMode( wheelEvent.mDeltaMode), origin, wheelEvent.mDeltaX, wheelEvent.mDeltaY, wheelEvent.mAllowToOverrideSystemScrollSpeed); // We add the user multiplier as a separate field, rather than premultiplying // it, because if the input is converted back to a WidgetWheelEvent, then // EventStateManager would apply the delta a second time. We could in theory // work around this by asking ESM to customize the event much sooner, and // then save the "mCustomizedByUserPrefs" bit on ScrollWheelInput - but for // now, this seems easier. EventStateManager::GetUserPrefsForWheelEvent(&wheelEvent, &input.mUserDeltaMultiplierX, &input.mUserDeltaMultiplierY); nsEventStatus status = ReceiveInputEvent(input, aOutTargetGuid, aOutInputBlockId); wheelEvent.mRefPoint.x = input.mOrigin.x; wheelEvent.mRefPoint.y = input.mOrigin.y; wheelEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ; return status; } UpdateWheelTransaction(aEvent.mRefPoint, aEvent.mMessage); TransformEventRefPoint(&aEvent.mRefPoint, aOutTargetGuid); return nsEventStatus_eIgnore; } default: { UpdateWheelTransaction(aEvent.mRefPoint, aEvent.mMessage); TransformEventRefPoint(&aEvent.mRefPoint, aOutTargetGuid); return nsEventStatus_eIgnore; } } MOZ_ASSERT_UNREACHABLE("Invalid WidgetInputEvent type."); return nsEventStatus_eConsumeNoDefault; } } // namespace layers } // namespace mozilla