void nsWindow::DispatchTouchEventForAPZ(const MultiTouchInput& aInput, const ScrollableLayerGuid& aGuid, const uint64_t aInputBlockId) { MOZ_ASSERT(NS_IsMainThread()); UserActivity(); // Convert it to an event we can send to Goanna WidgetTouchEvent event = aInput.ToWidgetTouchEvent(this); // If there is an event capturing child process, send it directly there. // This happens if we already sent a touchstart event through the root // process hit test and it ended up going to a child process. The event // capturing process should get all subsequent touch events in the same // event block. In this case the TryCapture call below will return true, // and the child process will take care of responding to the event as needed // so we don't need to do anything else here. if (TabParent* capturer = TabParent::GetEventCapturer()) { InputAPZContext context(aGuid, aInputBlockId); if (capturer->TryCapture(event)) { return; } } // If it didn't get captured, dispatch the event into the goanna root process // for "normal" flow. The event might get sent to the child process still, // but if it doesn't we need to notify the APZ of various things. All of // that happens in DispatchEventForAPZ DispatchEventForAPZ(&event, aGuid, aInputBlockId); }
void GeckoTouchDispatcher::DispatchTouchEvent(MultiTouchInput& aMultiTouch) { if ((aMultiTouch.mType == MultiTouchInput::MULTITOUCH_END || aMultiTouch.mType == MultiTouchInput::MULTITOUCH_CANCEL) && aMultiTouch.mTouches.Length() == 1) { MutexAutoLock lock(mTouchQueueLock); mTouchMoveEvents.clear(); } else if (aMultiTouch.mType == MultiTouchInput::MULTITOUCH_START && aMultiTouch.mTouches.Length() == 1) { mTouchEventsFiltered = IsExpired(aMultiTouch); } if (mTouchEventsFiltered) { return; } bool captured = false; WidgetTouchEvent event = aMultiTouch.ToWidgetTouchEvent(nullptr); nsEventStatus status = nsWindow::DispatchInputEvent(event, &captured); if (mEnabledUniformityInfo) { const char* touchAction = "Invalid"; switch (aMultiTouch.mType) { case MultiTouchInput::MULTITOUCH_START: touchAction = "Touch_Event_Down"; break; case MultiTouchInput::MULTITOUCH_MOVE: touchAction = "Touch_Event_Move"; break; case MultiTouchInput::MULTITOUCH_END: case MultiTouchInput::MULTITOUCH_CANCEL: touchAction = "Touch_Event_Up"; break; } const SingleTouchData& firstTouch = aMultiTouch.mTouches[0]; const ScreenIntPoint& touchPoint = firstTouch.mScreenPoint; LOG("UniformityInfo %s %llu %d %d", touchAction, systemTime(SYSTEM_TIME_MONOTONIC), touchPoint.x, touchPoint.y); } if (!captured && (aMultiTouch.mTouches.Length() == 1)) { bool forwardToChildren = status != nsEventStatus_eConsumeNoDefault; DispatchMouseEvent(aMultiTouch, forwardToChildren); } }
void nsWindow::DispatchTouchEventForAPZ(const MultiTouchInput& aInput, const ScrollableLayerGuid& aGuid, const uint64_t aInputBlockId, nsEventStatus aApzResponse) { MOZ_ASSERT(NS_IsMainThread()); UserActivity(); // Convert it to an event we can send to Gecko WidgetTouchEvent event = aInput.ToWidgetTouchEvent(this); // Dispatch the event into the gecko root process for "normal" flow. // The event might get sent to a child process, // but if it doesn't we need to notify the APZ of various things. // All of that happens in ProcessUntransformedAPZEvent ProcessUntransformedAPZEvent(&event, aGuid, aInputBlockId, aApzResponse); }
nsEventStatus InputQueue::ReceiveTouchInput(const RefPtr<AsyncPanZoomController>& aTarget, bool aTargetConfirmed, const MultiTouchInput& aEvent, uint64_t* aOutInputBlockId) { TouchBlockState* block = nullptr; if (aEvent.mType == MultiTouchInput::MULTITOUCH_START) { nsTArray<TouchBehaviorFlags> currentBehaviors; bool haveBehaviors = false; if (!gfxPrefs::TouchActionEnabled()) { haveBehaviors = true; } else if (!mInputBlockQueue.IsEmpty() && CurrentBlock()->AsTouchBlock()) { haveBehaviors = CurrentTouchBlock()->GetAllowedTouchBehaviors(currentBehaviors); // If the behaviours aren't set, but the main-thread response timer on // the block is expired we still treat it as though it has behaviors, // because in that case we still want to interrupt the fast-fling and // use the default behaviours. haveBehaviors |= CurrentTouchBlock()->IsContentResponseTimerExpired(); } block = StartNewTouchBlock(aTarget, aTargetConfirmed, false); INPQ_LOG("started new touch block %p for target %p\n", block, aTarget.get()); // XXX using the chain from |block| here may be wrong in cases where the // target isn't confirmed and the real target turns out to be something // else. For now assume this is rare enough that it's not an issue. if (block == CurrentBlock() && aEvent.mTouches.Length() == 1 && block->GetOverscrollHandoffChain()->HasFastFlungApzc() && haveBehaviors) { // If we're already in a fast fling, and a single finger goes down, then // we want special handling for the touch event, because it shouldn't get // delivered to content. Note that we don't set this flag when going // from a fast fling to a pinch state (i.e. second finger goes down while // the first finger is moving). block->SetDuringFastFling(); block->SetConfirmedTargetApzc(aTarget); if (gfxPrefs::TouchActionEnabled()) { block->SetAllowedTouchBehaviors(currentBehaviors); } INPQ_LOG("block %p tagged as fast-motion\n", block); } CancelAnimationsForNewBlock(block); MaybeRequestContentResponse(aTarget, block); } else { if (!mInputBlockQueue.IsEmpty()) { block = mInputBlockQueue.LastElement().get()->AsTouchBlock(); } if (!block) { NS_WARNING("Received a non-start touch event while no touch blocks active!"); return nsEventStatus_eIgnore; } 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. RefPtr<AsyncPanZoomController> target = block->GetTargetApzc(); nsEventStatus result = nsEventStatus_eIgnore; // XXX calling ArePointerEventsConsumable on |target| may be wrong here if // the target isn't confirmed and the real target turns out to be something // else. For now assume this is rare enough that it's not an issue. if (block->IsDuringFastFling()) { INPQ_LOG("dropping event due to block %p being in fast motion\n", block); result = nsEventStatus_eConsumeNoDefault; } else if (target && target->ArePointerEventsConsumable(block, aEvent.AsMultiTouchInput().mTouches.Length())) { result = nsEventStatus_eConsumeDoDefault; } if (!MaybeHandleCurrentBlock(block, aEvent)) { block->AddEvent(aEvent.AsMultiTouchInput()); } return result; }