diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index 7dc5754ea061..3180c5714b76 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -1720,6 +1720,9 @@ APZEventResult APZCTreeManager::ReceiveInputEvent(InputData& aEvent) { aEvent.mLayersId = hit.mLayersId; hitResult = hit.mHitResult; + // We always handle pinch gestures as pinch zooms. + pinchInput.mHandledByAPZ = true; + if (hit.mTargetApzc) { MOZ_ASSERT(hitResult != CompositorHitTestInvisibleToHit); diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index 3cf2001fc426..688221dff69a 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -5026,6 +5026,11 @@ PanGestureBlockState* AsyncPanZoomController::GetCurrentPanGestureBlock() return GetInputQueue()->GetCurrentPanGestureBlock(); } +PinchGestureBlockState* AsyncPanZoomController::GetCurrentPinchGestureBlock() + const { + return GetInputQueue()->GetCurrentPinchGestureBlock(); +} + void AsyncPanZoomController::ResetTouchInputState() { MultiTouchInput cancel(MultiTouchInput::MULTITOUCH_CANCEL, 0, TimeStamp::Now(), 0); diff --git a/gfx/layers/apz/src/AsyncPanZoomController.h b/gfx/layers/apz/src/AsyncPanZoomController.h index fdf9ceba466b..e39ed23d0938 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.h +++ b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -1335,6 +1335,7 @@ class AsyncPanZoomController { bool HasReadyTouchBlock() const; PanGestureBlockState* GetCurrentPanGestureBlock() const; + PinchGestureBlockState* GetCurrentPinchGestureBlock() const; private: /* =================================================================== diff --git a/gfx/layers/apz/src/InputBlockState.cpp b/gfx/layers/apz/src/InputBlockState.cpp index 7a8b4175d5e2..501674b65c32 100644 --- a/gfx/layers/apz/src/InputBlockState.cpp +++ b/gfx/layers/apz/src/InputBlockState.cpp @@ -579,6 +579,47 @@ void PanGestureBlockState::SetNeedsToWaitForContentResponse( mWaitingForContentResponse = aWaitForContentResponse; } +PinchGestureBlockState::PinchGestureBlockState( + const RefPtr& aTargetApzc, + TargetConfirmationFlags aFlags) + : CancelableBlockState(aTargetApzc, aFlags), + mInterrupted(false), + mWaitingForContentResponse(false) {} + +bool PinchGestureBlockState::MustStayActive() { return true; } + +const char* PinchGestureBlockState::Type() { return "pinch gesture"; } + +bool PinchGestureBlockState::SetContentResponse(bool aPreventDefault) { + if (aPreventDefault) { + TBS_LOG("%p setting interrupted flag\n", this); + mInterrupted = true; + } + bool stateChanged = CancelableBlockState::SetContentResponse(aPreventDefault); + if (mWaitingForContentResponse) { + mWaitingForContentResponse = false; + stateChanged = true; + } + return stateChanged; +} + +bool PinchGestureBlockState::HasReceivedAllContentNotifications() const { + return CancelableBlockState::HasReceivedAllContentNotifications() && + !mWaitingForContentResponse; +} + +bool PinchGestureBlockState::IsReadyForHandling() const { + if (!CancelableBlockState::IsReadyForHandling()) { + return false; + } + return !mWaitingForContentResponse || IsContentResponseTimerExpired(); +} + +void PinchGestureBlockState::SetNeedsToWaitForContentResponse( + bool aWaitForContentResponse) { + mWaitingForContentResponse = aWaitForContentResponse; +} + TouchBlockState::TouchBlockState( const RefPtr& aTargetApzc, TargetConfirmationFlags aFlags, TouchCounter& aCounter) diff --git a/gfx/layers/apz/src/InputBlockState.h b/gfx/layers/apz/src/InputBlockState.h index b5590fec3d60..72834db0e85c 100644 --- a/gfx/layers/apz/src/InputBlockState.h +++ b/gfx/layers/apz/src/InputBlockState.h @@ -29,6 +29,7 @@ class TouchBlockState; class WheelBlockState; class DragBlockState; class PanGestureBlockState; +class PinchGestureBlockState; class KeyboardBlockState; /** @@ -59,6 +60,7 @@ class InputBlockState : public RefCounted { virtual WheelBlockState* AsWheelBlock() { return nullptr; } virtual DragBlockState* AsDragBlock() { return nullptr; } virtual PanGestureBlockState* AsPanGestureBlock() { return nullptr; } + virtual PinchGestureBlockState* AsPinchGestureBlock() { return nullptr; } virtual KeyboardBlockState* AsKeyboardBlock() { return nullptr; } virtual bool SetConfirmedTargetApzc( @@ -357,6 +359,31 @@ class PanGestureBlockState : public CancelableBlockState { ScrollDirections mAllowedScrollDirections; }; +/** + * A single block of pinch gesture events. + */ +class PinchGestureBlockState : public CancelableBlockState { + public: + PinchGestureBlockState(const RefPtr& aTargetApzc, + TargetConfirmationFlags aFlags); + + bool SetContentResponse(bool aPreventDefault) override; + bool HasReceivedAllContentNotifications() const override; + bool IsReadyForHandling() const override; + bool MustStayActive() override; + const char* Type() override; + + PinchGestureBlockState* AsPinchGestureBlock() override { return this; } + + bool WasInterrupted() const { return mInterrupted; } + + void SetNeedsToWaitForContentResponse(bool aWaitForContentResponse); + + private: + bool mInterrupted; + bool mWaitingForContentResponse; +}; + /** * This class represents a single touch block. A touch block is * a set of touch events that can be cancelled by web content via diff --git a/gfx/layers/apz/src/InputQueue.cpp b/gfx/layers/apz/src/InputQueue.cpp index dc3de00bf453..43cd2f2c1bee 100644 --- a/gfx/layers/apz/src/InputQueue.cpp +++ b/gfx/layers/apz/src/InputQueue.cpp @@ -52,6 +52,11 @@ nsEventStatus InputQueue::ReceiveInputEvent( return ReceivePanGestureInput(aTarget, aFlags, event, aOutInputBlockId); } + case PINCHGESTURE_INPUT: { + const PinchGestureInput& event = aEvent.AsPinchGestureInput(); + return ReceivePinchGestureInput(aTarget, aFlags, event, aOutInputBlockId); + } + case MOUSE_INPUT: { const MouseInput& event = aEvent.AsMouseInput(); return ReceiveMouseInput(aTarget, aFlags, event, aOutInputBlockId); @@ -410,6 +415,54 @@ nsEventStatus InputQueue::ReceivePanGestureInput( return result; } +nsEventStatus InputQueue::ReceivePinchGestureInput( + const RefPtr& aTarget, + TargetConfirmationFlags aFlags, const PinchGestureInput& aEvent, + uint64_t* aOutInputBlockId) { + PinchGestureBlockState* block = nullptr; + if (aEvent.mType != PinchGestureInput::PINCHGESTURE_START) { + block = mActivePinchGestureBlock.get(); + } + + nsEventStatus result = nsEventStatus_eConsumeDoDefault; + + if (!block || block->WasInterrupted()) { + if (aEvent.mType != PinchGestureInput::PINCHGESTURE_START) { + // Only PINCHGESTURE_START events are allowed to start a new pinch gesture + // block. + INPQ_LOG("pinchgesture block %p was interrupted %d\n", block, + block ? block->WasInterrupted() : 0); + return nsEventStatus_eConsumeDoDefault; + } + block = new PinchGestureBlockState(aTarget, aFlags); + INPQ_LOG("started new pinch gesture block %p id %" PRIu64 + " for target %p\n", + block, block->GetBlockId(), aTarget.get()); + + mActivePinchGestureBlock = block; + block->SetNeedsToWaitForContentResponse(true); + + CancelAnimationsForNewBlock(block); + MaybeRequestContentResponse(aTarget, block); + } else { + INPQ_LOG("received new event in block %p\n", block); + } + + if (aOutInputBlockId) { + *aOutInputBlockId = block->GetBlockId(); + } + + // Note that the |aTarget| the APZCTM sent us may contradict the confirmed + // target set on the block. In this case the confirmed target (which may be + // null) should take priority. This is equivalent to just always using the + // target (confirmed or not) from the block, which is what + // ProcessQueue() does. + mQueuedInputs.AppendElement(MakeUnique(aEvent, *block)); + ProcessQueue(); + + return result; +} + void InputQueue::CancelAnimationsForNewBlock(InputBlockState* aBlock, CancelAnimationFlags aExtraFlags) { // We want to cancel animations here as soon as possible (i.e. without waiting @@ -504,6 +557,11 @@ PanGestureBlockState* InputQueue::GetCurrentPanGestureBlock() const { return block ? block->AsPanGestureBlock() : mActivePanGestureBlock.get(); } +PinchGestureBlockState* InputQueue::GetCurrentPinchGestureBlock() const { + InputBlockState* block = GetCurrentBlock(); + return block ? block->AsPinchGestureBlock() : mActivePinchGestureBlock.get(); +} + KeyboardBlockState* InputQueue::GetCurrentKeyboardBlock() const { InputBlockState* block = GetCurrentBlock(); return block ? block->AsKeyboardBlock() : mActiveKeyboardBlock.get(); @@ -596,6 +654,9 @@ InputBlockState* InputQueue::FindBlockForId(uint64_t aInputBlockId, } else if (mActivePanGestureBlock && mActivePanGestureBlock->GetBlockId() == aInputBlockId) { block = mActivePanGestureBlock.get(); + } else if (mActivePinchGestureBlock && + mActivePinchGestureBlock->GetBlockId() == aInputBlockId) { + block = mActivePinchGestureBlock.get(); } else if (mActiveKeyboardBlock && mActiveKeyboardBlock->GetBlockId() == aInputBlockId) { block = mActiveKeyboardBlock.get(); @@ -780,6 +841,9 @@ void InputQueue::ProcessQueue() { if (CanDiscardBlock(mActivePanGestureBlock)) { mActivePanGestureBlock = nullptr; } + if (CanDiscardBlock(mActivePinchGestureBlock)) { + mActivePinchGestureBlock = nullptr; + } if (CanDiscardBlock(mActiveKeyboardBlock)) { mActiveKeyboardBlock = nullptr; } @@ -815,6 +879,7 @@ void InputQueue::Clear() { mActiveWheelBlock = nullptr; mActiveDragBlock = nullptr; mActivePanGestureBlock = nullptr; + mActivePinchGestureBlock = nullptr; mActiveKeyboardBlock = nullptr; mLastActiveApzc = nullptr; } diff --git a/gfx/layers/apz/src/InputQueue.h b/gfx/layers/apz/src/InputQueue.h index 6fa1505b8b26..6b7068e23a20 100644 --- a/gfx/layers/apz/src/InputQueue.h +++ b/gfx/layers/apz/src/InputQueue.h @@ -31,6 +31,7 @@ class TouchBlockState; class WheelBlockState; class DragBlockState; class PanGestureBlockState; +class PinchGestureBlockState; class KeyboardBlockState; class AsyncDragMetrics; class QueuedInput; @@ -112,6 +113,7 @@ class InputQueue { WheelBlockState* GetCurrentWheelBlock() const; DragBlockState* GetCurrentDragBlock() const; PanGestureBlockState* GetCurrentPanGestureBlock() const; + PinchGestureBlockState* GetCurrentPinchGestureBlock() const; KeyboardBlockState* GetCurrentKeyboardBlock() const; /** * Returns true iff the pending block at the head of the queue is a touch @@ -189,6 +191,10 @@ class InputQueue { const RefPtr& aTarget, TargetConfirmationFlags aFlags, const PanGestureInput& aEvent, uint64_t* aOutInputBlockId); + nsEventStatus ReceivePinchGestureInput( + const RefPtr& aTarget, + TargetConfirmationFlags aFlags, const PinchGestureInput& aEvent, + uint64_t* aOutInputBlockId); nsEventStatus ReceiveKeyboardInput( const RefPtr& aTarget, const KeyboardInput& aEvent, uint64_t* aOutInputBlockId); @@ -225,6 +231,7 @@ class InputQueue { RefPtr mActiveWheelBlock; RefPtr mActiveDragBlock; RefPtr mActivePanGestureBlock; + RefPtr mActivePinchGestureBlock; RefPtr mActiveKeyboardBlock; // The APZC to which the last event was delivered diff --git a/gfx/layers/apz/src/QueuedInput.cpp b/gfx/layers/apz/src/QueuedInput.cpp index fdef9704f131..87ffe7250e97 100644 --- a/gfx/layers/apz/src/QueuedInput.cpp +++ b/gfx/layers/apz/src/QueuedInput.cpp @@ -28,6 +28,10 @@ QueuedInput::QueuedInput(const PanGestureInput& aInput, PanGestureBlockState& aBlock) : mInput(MakeUnique(aInput)), mBlock(&aBlock) {} +QueuedInput::QueuedInput(const PinchGestureInput& aInput, + PinchGestureBlockState& aBlock) + : mInput(MakeUnique(aInput)), mBlock(&aBlock) {} + QueuedInput::QueuedInput(const KeyboardInput& aInput, KeyboardBlockState& aBlock) : mInput(MakeUnique(aInput)), mBlock(&aBlock) {} diff --git a/gfx/layers/apz/src/QueuedInput.h b/gfx/layers/apz/src/QueuedInput.h index 9864166810f2..db1b4122f48e 100644 --- a/gfx/layers/apz/src/QueuedInput.h +++ b/gfx/layers/apz/src/QueuedInput.h @@ -39,6 +39,7 @@ class QueuedInput { QueuedInput(const ScrollWheelInput& aInput, WheelBlockState& aBlock); QueuedInput(const MouseInput& aInput, DragBlockState& aBlock); QueuedInput(const PanGestureInput& aInput, PanGestureBlockState& aBlock); + QueuedInput(const PinchGestureInput& aInput, PinchGestureBlockState& aBlock); QueuedInput(const KeyboardInput& aInput, KeyboardBlockState& aBlock); InputData* Input(); diff --git a/widget/InputData.cpp b/widget/InputData.cpp index 72f57231f393..c1a8b7e27248 100644 --- a/widget/InputData.cpp +++ b/widget/InputData.cpp @@ -537,7 +537,9 @@ ParentLayerPoint PanGestureInput::UserMultipliedLocalPanDisplacement() const { } PinchGestureInput::PinchGestureInput() - : InputData(PINCHGESTURE_INPUT), mType(PINCHGESTURE_START) {} + : InputData(PINCHGESTURE_INPUT), + mType(PINCHGESTURE_START), + mHandledByAPZ(false) {} PinchGestureInput::PinchGestureInput( PinchGestureType aType, uint32_t aTime, TimeStamp aTimeStamp, @@ -548,7 +550,8 @@ PinchGestureInput::PinchGestureInput( mFocusPoint(aFocusPoint), mScreenOffset(aScreenOffset), mCurrentSpan(aCurrentSpan), - mPreviousSpan(aPreviousSpan) {} + mPreviousSpan(aPreviousSpan), + mHandledByAPZ(false) {} bool PinchGestureInput::TransformToLocal( const ScreenToParentLayerMatrix4x4& aTransform) { @@ -565,6 +568,74 @@ bool PinchGestureInput::TransformToLocal( return true; } +WidgetWheelEvent PinchGestureInput::ToWidgetWheelEvent( + nsIWidget* aWidget) const { + WidgetWheelEvent wheelEvent(true, eWheel, aWidget); + wheelEvent.mModifiers = this->modifiers | MODIFIER_CONTROL; + wheelEvent.mTime = mTime; + wheelEvent.mTimeStamp = mTimeStamp; + wheelEvent.mRefPoint = RoundedToInt(ViewAs( + mFocusPoint, + PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent)); + wheelEvent.mButtons = 0; + wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ; + wheelEvent.mDeltaMode = WheelEvent_Binding::DOM_DELTA_PIXEL; + +#if defined(OS_MACOSX) + // 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. + wheelEvent.mDeltaY = (mPreviousSpan - 100.0) * + (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f); +#else + // This calculation is based on what the Windows 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. It then seems reasonable to calculate |M = + // currentScale / lastScale| and use the same formula as the macOS code + // (|-100.0 * M * GetDefaultScaleInternal()|). + + // XXX When we write the code for other platforms to do the same we'll need to + // make sure this calculation is reasonable. + + if (mPreviousSpan != 0.f) { + wheelEvent.mDeltaY = -100.0 * (mCurrentSpan / mPreviousSpan) * + (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f); + } else { + // Not sure what makes sense here, this seems reasonable. + wheelEvent.mDeltaY = -100.0 * mCurrentSpan * + (aWidget ? aWidget->GetDefaultScaleInternal() : 1.f); + } +#endif + + return wheelEvent; +} + TapGestureInput::TapGestureInput() : InputData(TAPGESTURE_INPUT), mType(TAPGESTURE_LONG) {} diff --git a/widget/InputData.h b/widget/InputData.h index 6c68b4843f9f..a7fdc4236519 100644 --- a/widget/InputData.h +++ b/widget/InputData.h @@ -452,6 +452,8 @@ class PinchGestureInput : public InputData { bool TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform); + WidgetWheelEvent ToWidgetWheelEvent(nsIWidget* aWidget) const; + // Warning, this class is serialized and sent over IPC. Any change to its // fields must be reflected in its ParamTraits<>, in nsGUIEventIPC.h PinchGestureType mType; @@ -482,6 +484,8 @@ class PinchGestureInput : public InputData { // of this type then there must have been a history of spans. ScreenCoord mPreviousSpan; + bool mHandledByAPZ; + // A special value for mFocusPoint used in PINCHGESTURE_END events to // indicate that both fingers have been lifted. If only one finger has // been lifted, the coordinates of the remaining finger are expected to diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index d938df710a47..890c0955acd3 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -2049,10 +2049,23 @@ void nsChildView::ReportSwipeStarted(uint64_t aInputBlockId, bool aStartSwipe) { } nsEventStatus nsChildView::DispatchAPZInputEvent(InputData& aEvent) { + APZEventResult result; + if (mAPZC) { - return mAPZC->InputBridge()->ReceiveInputEvent(aEvent).mStatus; + result = mAPZC->InputBridge()->ReceiveInputEvent(aEvent); } - return nsEventStatus_eIgnore; + + if (result.mStatus == nsEventStatus_eConsumeNoDefault) { + return result.mStatus; + } + + if (aEvent.mInputType == PINCHGESTURE_INPUT) { + PinchGestureInput& pinchEvent = aEvent.AsPinchGestureInput(); + WidgetWheelEvent wheelEvent = pinchEvent.ToWidgetWheelEvent(this); + ProcessUntransformedAPZEvent(&wheelEvent, result); + } + + return result.mStatus; } void nsChildView::DispatchAPZWheelInputEvent(InputData& aEvent, bool aCanTriggerSwipe) { @@ -2791,53 +2804,53 @@ NSEvent* gLastDragMouseDownEvent = nil; // [strong] return; } + NSPoint locationInWindow = nsCocoaUtils::EventLocationForWindow(anEvent, [self window]); + ScreenPoint position = + ViewAs([self convertWindowCoordinatesRoundDown:locationInWindow], + PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent); + ExternalPoint screenOffset = + ViewAs(mGeckoChild->WidgetToScreenOffset(), + PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent); + + PRIntervalTime eventIntervalTime = PR_IntervalNow(); + TimeStamp eventTimeStamp = nsCocoaUtils::GetEventTimeStamp([anEvent timestamp]); + NSEventPhase eventPhase = [anEvent phase]; + PinchGestureInput::PinchGestureType pinchGestureType; + + switch (eventPhase) { + case NSEventPhaseBegan: { + pinchGestureType = PinchGestureInput::PINCHGESTURE_START; + break; + } + case NSEventPhaseChanged: { + pinchGestureType = PinchGestureInput::PINCHGESTURE_SCALE; + break; + } + case NSEventPhaseEnded: { + pinchGestureType = PinchGestureInput::PINCHGESTURE_END; + break; + } + default: { + NS_WARNING("Unexpected phase for pinch gesture event."); + return; + } + } + + PinchGestureInput event{pinchGestureType, + eventIntervalTime, + eventTimeStamp, + screenOffset, + position, + 100.0, + 100.0 * (1.0 - [anEvent magnification]), + nsCocoaUtils::ModifiersForEvent(anEvent)}; + + if (pinchGestureType == PinchGestureInput::PINCHGESTURE_END) { + event.mFocusPoint = PinchGestureInput::BothFingersLifted(); + } + // FIXME: bug 1525793 -- this may need to handle zooming or not on a per-document basis. if (StaticPrefs::apz_allow_zooming()) { - NSPoint locationInWindow = nsCocoaUtils::EventLocationForWindow(anEvent, [self window]); - ScreenPoint position = - ViewAs([self convertWindowCoordinatesRoundDown:locationInWindow], - PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent); - ExternalPoint screenOffset = - ViewAs(mGeckoChild->WidgetToScreenOffset(), - PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent); - - PRIntervalTime eventIntervalTime = PR_IntervalNow(); - TimeStamp eventTimeStamp = nsCocoaUtils::GetEventTimeStamp([anEvent timestamp]); - NSEventPhase eventPhase = [anEvent phase]; - PinchGestureInput::PinchGestureType pinchGestureType; - - switch (eventPhase) { - case NSEventPhaseBegan: { - pinchGestureType = PinchGestureInput::PINCHGESTURE_START; - break; - } - case NSEventPhaseChanged: { - pinchGestureType = PinchGestureInput::PINCHGESTURE_SCALE; - break; - } - case NSEventPhaseEnded: { - pinchGestureType = PinchGestureInput::PINCHGESTURE_END; - break; - } - default: { - NS_WARNING("Unexpected phase for pinch gesture event."); - return; - } - } - - PinchGestureInput event{pinchGestureType, - eventIntervalTime, - eventTimeStamp, - screenOffset, - position, - 100.0, - 100.0 * (1.0 - [anEvent magnification]), - nsCocoaUtils::ModifiersForEvent(anEvent)}; - - if (pinchGestureType == PinchGestureInput::PINCHGESTURE_END) { - event.mFocusPoint = PinchGestureInput::BothFingersLifted(); - } - mGeckoChild->DispatchAPZInputEvent(event); } else { if (!anEvent || [self beginOrEndGestureForEventPhase:anEvent]) { @@ -2865,29 +2878,10 @@ NSEvent* gLastDragMouseDownEvent = nil; // [strong] return; } - // This sends the pinch gesture value as 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. - WidgetWheelEvent geckoWheelEvent(true, EventMessage::eWheel, mGeckoChild); - [self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoWheelEvent]; - double backingScale = mGeckoChild->BackingScaleFactor(); - geckoWheelEvent.mDeltaY = -100.0 * [anEvent magnification] * backingScale; - geckoWheelEvent.mModifiers |= MODIFIER_CONTROL; + // See PinchGestureInput::ToWidgetWheelEvent for a lengthy explanation of the values we put into + // the WidgetWheelEvent that used to be here. + + WidgetWheelEvent geckoWheelEvent(event.ToWidgetWheelEvent(mGeckoChild)); mGeckoChild->DispatchWindowEvent(geckoWheelEvent); // If the fake wheel event wasn't stopped, then send a normal magnify event. diff --git a/widget/nsGUIEventIPC.h b/widget/nsGUIEventIPC.h index b37b42b6a906..d1f3d1e0f917 100644 --- a/widget/nsGUIEventIPC.h +++ b/widget/nsGUIEventIPC.h @@ -1297,6 +1297,7 @@ struct ParamTraits { WriteParam(aMsg, aParam.mLocalFocusPoint); WriteParam(aMsg, aParam.mCurrentSpan); WriteParam(aMsg, aParam.mPreviousSpan); + WriteParam(aMsg, aParam.mHandledByAPZ); } static bool Read(const Message* aMsg, PickleIterator* aIter, @@ -1307,7 +1308,8 @@ struct ParamTraits { ReadParam(aMsg, aIter, &aResult->mFocusPoint) && ReadParam(aMsg, aIter, &aResult->mLocalFocusPoint) && ReadParam(aMsg, aIter, &aResult->mCurrentSpan) && - ReadParam(aMsg, aIter, &aResult->mPreviousSpan); + ReadParam(aMsg, aIter, &aResult->mPreviousSpan) && + ReadParam(aMsg, aIter, &aResult->mHandledByAPZ); } }; diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 793d7c313579..122a77dcfa3b 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -2155,13 +2155,13 @@ class nsIWidget : public nsISupports { static already_AddRefed CreateBidiKeyboard(); - protected: /** * Like GetDefaultScale, but taking into account only the system settings * and ignoring Gecko preferences. */ virtual double GetDefaultScaleInternal() { return 1.0; } + protected: // keep the list of children. We also keep track of our siblings. // The ownership model is as follows: parent holds a strong ref to // the first element of the list, and each element holds a strong