Esempio n. 1
0
nsEventStatus
InputQueue::ReceiveMouseInput(const RefPtr<AsyncPanZoomController>& aTarget,
                              bool aTargetConfirmed,
                              const MouseInput& aEvent,
                              uint64_t* aOutInputBlockId) {
  // On a new mouse down we can have a new target so we must force a new block
  // with a new target.
  bool newBlock = DragTracker::StartsDrag(aEvent);

  DragBlockState* block = newBlock ? nullptr : mActiveDragBlock.get();
  if (block && block->HasReceivedMouseUp()) {
    block = nullptr;
  }

  if (!block && mDragTracker.InDrag()) {
    // If there's no current drag block, but we're getting a move with a button
    // down, we need to start a new drag block because we're obviously already
    // in the middle of a drag (it probably got interrupted by something else).
    INPQ_LOG("got a drag event outside a drag block, need to create a block to hold it\n");
    newBlock = true;
  }

  mDragTracker.Update(aEvent);

  if (!newBlock && !block) {
    // This input event is not in a drag block, so we're not doing anything
    // with it, return eIgnore.
    return nsEventStatus_eIgnore;
  }

  if (!block) {
    MOZ_ASSERT(newBlock);
    block = new DragBlockState(aTarget, aTargetConfirmed, aEvent);

    INPQ_LOG("started new drag block %p id %" PRIu64 " for %sconfirmed target %p\n",
        block, block->GetBlockId(), aTargetConfirmed ? "" : "un", aTarget.get());

    mActiveDragBlock = block;

    CancelAnimationsForNewBlock(block);
    MaybeRequestContentResponse(aTarget, block);
  }

  if (aOutInputBlockId) {
    *aOutInputBlockId = block->GetBlockId();
  }

  mQueuedInputs.AppendElement(MakeUnique<QueuedInput>(aEvent, *block));
  ProcessQueue();

  if (DragTracker::EndsDrag(aEvent)) {
    block->MarkMouseUpReceived();
  }

  // The event is part of a drag block and could potentially cause
  // scrolling, so return DoDefault.
  return nsEventStatus_eConsumeDoDefault;
}
Esempio n. 2
0
nsEventStatus
InputQueue::ReceiveScrollWheelInput(const RefPtr<AsyncPanZoomController>& aTarget,
                                    bool aTargetConfirmed,
                                    const ScrollWheelInput& aEvent,
                                    uint64_t* aOutInputBlockId) {
  WheelBlockState* block = nullptr;
  if (!mInputBlockQueue.IsEmpty()) {
    block = mInputBlockQueue.LastElement()->AsWheelBlock();

    // If the block is not accepting new events we'll create a new input block
    // (and therefore a new wheel transaction).
    if (block &&
        (!block->ShouldAcceptNewEvent() ||
         block->MaybeTimeout(aEvent)))
    {
      block = nullptr;
    }
  }

  MOZ_ASSERT(!block || block->InTransaction());

  if (!block) {
    block = new WheelBlockState(aTarget, aTargetConfirmed, aEvent);
    INPQ_LOG("started new scroll wheel block %p for target %p\n", block, aTarget.get());

    SweepDepletedBlocks();
    mInputBlockQueue.AppendElement(block);

    CancelAnimationsForNewBlock(block);
    MaybeRequestContentResponse(aTarget, block);
  } else {
    INPQ_LOG("received new event in block %p\n", block);
  }

  if (aOutInputBlockId) {
    *aOutInputBlockId = block->GetBlockId();
  }

  block->Update(aEvent);

  // 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
  // MaybeHandleCurrentBlock() does.
  if (!MaybeHandleCurrentBlock(block, aEvent)) {
    block->AddEvent(aEvent.AsScrollWheelInput());
  }

  return nsEventStatus_eConsumeDoDefault;
}
Esempio n. 3
0
nsEventStatus
InputQueue::ReceiveScrollWheelInput(const RefPtr<AsyncPanZoomController>& aTarget,
                                    bool aTargetConfirmed,
                                    const ScrollWheelInput& aEvent,
                                    uint64_t* aOutInputBlockId) {
  WheelBlockState* block = mActiveWheelBlock.get();
  // If the block is not accepting new events we'll create a new input block
  // (and therefore a new wheel transaction).
  if (block &&
      (!block->ShouldAcceptNewEvent() ||
       block->MaybeTimeout(aEvent)))
  {
    block = nullptr;
  }

  MOZ_ASSERT(!block || block->InTransaction());

  if (!block) {
    block = new WheelBlockState(aTarget, aTargetConfirmed, aEvent);
    INPQ_LOG("started new scroll wheel block %p id %" PRIu64 " for target %p\n",
        block, block->GetBlockId(), aTarget.get());

    mActiveWheelBlock = block;

    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<QueuedInput>(aEvent, *block));

  // The WheelBlockState needs to affix a counter to the event before we process
  // it. Note that the counter is affixed to the copy in the queue rather than
  // |aEvent|.
  block->Update(mQueuedInputs.LastElement()->Input()->AsScrollWheelInput());

  ProcessQueue();

  return nsEventStatus_eConsumeDoDefault;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
nsEventStatus
InputQueue::ReceivePanGestureInput(const RefPtr<AsyncPanZoomController>& aTarget,
                                   bool aTargetConfirmed,
                                   const PanGestureInput& aEvent,
                                   uint64_t* aOutInputBlockId) {
  if (aEvent.mType == PanGestureInput::PANGESTURE_MAYSTART ||
      aEvent.mType == PanGestureInput::PANGESTURE_CANCELLED) {
    // Ignore these events for now.
    return nsEventStatus_eConsumeDoDefault;
  }

  PanGestureBlockState* block = nullptr;
  if (!mInputBlockQueue.IsEmpty() &&
      aEvent.mType != PanGestureInput::PANGESTURE_START) {
    block = mInputBlockQueue.LastElement()->AsPanGestureBlock();
  }

  nsEventStatus result = nsEventStatus_eConsumeDoDefault;

  if (!block || block->WasInterrupted()) {
    if (aEvent.mType != PanGestureInput::PANGESTURE_START) {
      // Only PANGESTURE_START events are allowed to start a new pan gesture block.
      return nsEventStatus_eConsumeDoDefault;
    }
    block = new PanGestureBlockState(aTarget, aTargetConfirmed, aEvent);
    INPQ_LOG("started new pan gesture block %p for target %p\n", block, aTarget.get());

    if (aTargetConfirmed &&
        aEvent.mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection &&
        !CanScrollTargetHorizontally(aEvent, block)) {
      // This event may trigger a swipe gesture, depending on what our caller
      // wants to do it. We need to suspend handling of this block until we get
      // a content response which will tell us whether to proceed or abort the
      // block.
      block->SetNeedsToWaitForContentResponse(true);

      // Inform our caller that we haven't scrolled in response to the event
      // and that a swipe can be started from this event if desired.
      result = nsEventStatus_eIgnore;
    }

    SweepDepletedBlocks();
    mInputBlockQueue.AppendElement(block);

    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
  // MaybeHandleCurrentBlock() does.
  if (!MaybeHandleCurrentBlock(block, aEvent)) {
    block->AddEvent(aEvent.AsPanGestureInput());
  }

  return result;
}
Esempio n. 6
0
nsEventStatus
InputQueue::ReceivePanGestureInput(const RefPtr<AsyncPanZoomController>& aTarget,
                                   bool aTargetConfirmed,
                                   const PanGestureInput& aEvent,
                                   uint64_t* aOutInputBlockId) {
  if (aEvent.mType == PanGestureInput::PANGESTURE_MAYSTART ||
      aEvent.mType == PanGestureInput::PANGESTURE_CANCELLED) {
    // Ignore these events for now.
    return nsEventStatus_eConsumeDoDefault;
  }

  PanGestureBlockState* block = nullptr;
  if (aEvent.mType != PanGestureInput::PANGESTURE_START) {
    block = mActivePanGestureBlock.get();
  }

  PanGestureInput event = aEvent;
  nsEventStatus result = nsEventStatus_eConsumeDoDefault;

  if (!block || block->WasInterrupted()) {
    if (event.mType != PanGestureInput::PANGESTURE_START) {
      // Only PANGESTURE_START events are allowed to start a new pan gesture
      // block, but we really want to start a new block here, so we magically
      // turn this input into a PANGESTURE_START.
      INPQ_LOG("transmogrifying pan input %d to PANGESTURE_START for new block\n",
          event.mType);
      event.mType = PanGestureInput::PANGESTURE_START;
    }
    block = new PanGestureBlockState(aTarget, aTargetConfirmed, event);
    INPQ_LOG("started new pan gesture block %p id %" PRIu64 " for target %p\n",
        block, block->GetBlockId(), aTarget.get());

    if (aTargetConfirmed &&
        event.mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection &&
        !CanScrollTargetHorizontally(event, block)) {
      // This event may trigger a swipe gesture, depending on what our caller
      // wants to do it. We need to suspend handling of this block until we get
      // a content response which will tell us whether to proceed or abort the
      // block.
      block->SetNeedsToWaitForContentResponse(true);

      // Inform our caller that we haven't scrolled in response to the event
      // and that a swipe can be started from this event if desired.
      result = nsEventStatus_eIgnore;
    }

    mActivePanGestureBlock = block;

    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<QueuedInput>(event, *block));
  ProcessQueue();

  return result;
}