mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 01:05:45 +00:00
Refactor InputQueue to hold more than touch events. (bug 1013432 part 2, r=kats)
--HG-- extra : rebase_source : cd3691a2bda6aaf315cf3b844e4fdd3aa8b30334
This commit is contained in:
parent
fd05150dca
commit
d2831e46f4
@ -220,6 +220,18 @@ TouchBlockState::AddEvent(const MultiTouchInput& aEvent)
|
||||
mEvents.AppendElement(aEvent);
|
||||
}
|
||||
|
||||
bool
|
||||
TouchBlockState::MustStayActive()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const char*
|
||||
TouchBlockState::Type()
|
||||
{
|
||||
return "touch";
|
||||
}
|
||||
|
||||
void
|
||||
TouchBlockState::DropEvents()
|
||||
{
|
||||
@ -227,6 +239,14 @@ TouchBlockState::DropEvents()
|
||||
mEvents.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
TouchBlockState::HandleEvents(const nsRefPtr<AsyncPanZoomController>& aTarget)
|
||||
{
|
||||
while (HasEvents()) {
|
||||
aTarget->HandleInputEvent(RemoveFirstEvent());
|
||||
}
|
||||
}
|
||||
|
||||
MultiTouchInput
|
||||
TouchBlockState::RemoveFirstEvent()
|
||||
{
|
||||
|
@ -16,6 +16,9 @@ namespace layers {
|
||||
|
||||
class AsyncPanZoomController;
|
||||
class OverscrollHandoffChain;
|
||||
class CancelableBlockState;
|
||||
class TouchBlockState;
|
||||
class WheelBlockState;
|
||||
|
||||
/**
|
||||
* A base class that stores state common to various input blocks.
|
||||
@ -28,14 +31,16 @@ public:
|
||||
|
||||
explicit InputBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
|
||||
bool aTargetConfirmed);
|
||||
virtual ~InputBlockState()
|
||||
{}
|
||||
|
||||
bool SetConfirmedTargetApzc(const nsRefPtr<AsyncPanZoomController>& aTargetApzc);
|
||||
const nsRefPtr<AsyncPanZoomController>& GetTargetApzc() const;
|
||||
const nsRefPtr<const OverscrollHandoffChain>& GetOverscrollHandoffChain() const;
|
||||
uint64_t GetBlockId() const;
|
||||
|
||||
protected:
|
||||
bool IsTargetConfirmed() const;
|
||||
|
||||
private:
|
||||
nsRefPtr<AsyncPanZoomController> mTargetApzc;
|
||||
nsRefPtr<const OverscrollHandoffChain> mOverscrollHandoffChain;
|
||||
@ -61,6 +66,10 @@ public:
|
||||
CancelableBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
|
||||
bool aTargetConfirmed);
|
||||
|
||||
virtual TouchBlockState *AsTouchBlock() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record whether or not content cancelled this block of events.
|
||||
* @param aPreventDefault true iff the block is cancelled.
|
||||
@ -81,10 +90,37 @@ public:
|
||||
bool IsDefaultPrevented() const;
|
||||
|
||||
/**
|
||||
* @returns true if web content responded or timed out.
|
||||
* @return true iff this block has received all the information needed
|
||||
* to properly dispatch the events in the block.
|
||||
*/
|
||||
virtual bool IsReadyForHandling() const;
|
||||
|
||||
/**
|
||||
* Returns whether or not this block has pending events.
|
||||
*/
|
||||
virtual bool HasEvents() const = 0;
|
||||
|
||||
/**
|
||||
* Throw away all the events in this input block.
|
||||
*/
|
||||
virtual void DropEvents() = 0;
|
||||
|
||||
/**
|
||||
* Process all events given an apzc, leaving ths block depleted.
|
||||
*/
|
||||
virtual void HandleEvents(const nsRefPtr<AsyncPanZoomController>& aTarget) = 0;
|
||||
|
||||
/**
|
||||
* Return true if this input block must stay active if it would otherwise
|
||||
* be removed as the last item in the pending queue.
|
||||
*/
|
||||
virtual bool MustStayActive() = 0;
|
||||
|
||||
/**
|
||||
* Return a descriptive name for the block kind.
|
||||
*/
|
||||
virtual const char* Type() = 0;
|
||||
|
||||
private:
|
||||
bool mPreventDefault;
|
||||
bool mContentResponded;
|
||||
@ -122,6 +158,10 @@ public:
|
||||
explicit TouchBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
|
||||
bool aTargetConfirmed);
|
||||
|
||||
TouchBlockState *AsTouchBlock() MOZ_OVERRIDE {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the allowed touch behavior flags for this block.
|
||||
* @return false if this block already has these flags set, true if not.
|
||||
@ -161,23 +201,10 @@ public:
|
||||
*/
|
||||
bool SingleTapOccurred() const;
|
||||
|
||||
/**
|
||||
* @return true iff there are pending events in this touch block.
|
||||
*/
|
||||
bool HasEvents() const;
|
||||
/**
|
||||
* Add a new touch event to the queue of events in this input block.
|
||||
*/
|
||||
void AddEvent(const MultiTouchInput& aEvent);
|
||||
/**
|
||||
* Throw away all the events in this input block.
|
||||
*/
|
||||
void DropEvents();
|
||||
/**
|
||||
* @return the first event in the queue. The event is removed from the queue
|
||||
* before it is returned.
|
||||
*/
|
||||
MultiTouchInput RemoveFirstEvent();
|
||||
|
||||
/**
|
||||
* @return false iff touch-action is enabled and the allowed touch behaviors for
|
||||
@ -197,6 +224,19 @@ public:
|
||||
bool TouchActionAllowsPanningY() const;
|
||||
bool TouchActionAllowsPanningXY() const;
|
||||
|
||||
bool HasEvents() const MOZ_OVERRIDE;
|
||||
void DropEvents() MOZ_OVERRIDE;
|
||||
void HandleEvents(const nsRefPtr<AsyncPanZoomController>& aTarget) MOZ_OVERRIDE;
|
||||
bool MustStayActive() MOZ_OVERRIDE;
|
||||
const char* Type() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @return the first event in the queue. The event is removed from the queue
|
||||
* before it is returned.
|
||||
*/
|
||||
MultiTouchInput RemoveFirstEvent();
|
||||
|
||||
private:
|
||||
nsTArray<TouchBehaviorFlags> mAllowedTouchBehaviors;
|
||||
bool mAllowedTouchBehaviorSet;
|
||||
|
@ -23,7 +23,7 @@ InputQueue::InputQueue()
|
||||
}
|
||||
|
||||
InputQueue::~InputQueue() {
|
||||
mTouchBlockQueue.Clear();
|
||||
mInputBlockQueue.Clear();
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
@ -33,70 +33,62 @@ InputQueue::ReceiveInputEvent(const nsRefPtr<AsyncPanZoomController>& aTarget,
|
||||
uint64_t* aOutInputBlockId) {
|
||||
AsyncPanZoomController::AssertOnControllerThread();
|
||||
|
||||
if (aEvent.mInputType != MULTITOUCH_INPUT) {
|
||||
switch (aEvent.mInputType) {
|
||||
case MULTITOUCH_INPUT: {
|
||||
const MultiTouchInput& event = aEvent.AsMultiTouchInput();
|
||||
return ReceiveTouchInput(aTarget, aTargetConfirmed, event, aOutInputBlockId);
|
||||
}
|
||||
|
||||
default:
|
||||
// The return value for non-touch input is only used by tests, so just pass
|
||||
// through the return value for now. This can be changed later if needed.
|
||||
// TODO (bug 1098430): we will eventually need to have smarter handling for
|
||||
// non-touch events as well.
|
||||
return aTarget->HandleInputEvent(aEvent);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
InputQueue::MaybeHandleCurrentBlock(const nsRefPtr<AsyncPanZoomController>& aTarget,
|
||||
CancelableBlockState *block,
|
||||
const InputData& aEvent) {
|
||||
if (block == CurrentBlock() && block->IsReadyForHandling()) {
|
||||
INPQ_LOG("current block is ready with target %p preventdefault %d\n",
|
||||
aTarget.get(), block->IsDefaultPrevented());
|
||||
if (!aTarget || block->IsDefaultPrevented()) {
|
||||
return true;
|
||||
}
|
||||
aTarget->HandleInputEvent(aEvent);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
InputQueue::ReceiveTouchInput(const nsRefPtr<AsyncPanZoomController>& aTarget,
|
||||
bool aTargetConfirmed,
|
||||
const MultiTouchInput& aEvent,
|
||||
uint64_t* aOutInputBlockId) {
|
||||
TouchBlockState* block = nullptr;
|
||||
if (aEvent.AsMultiTouchInput().mType == MultiTouchInput::MULTITOUCH_START) {
|
||||
if (aEvent.mType == MultiTouchInput::MULTITOUCH_START) {
|
||||
block = StartNewTouchBlock(aTarget, aTargetConfirmed, false);
|
||||
INPQ_LOG("started new touch block %p for target %p\n", block, aTarget.get());
|
||||
|
||||
// We want to cancel animations here as soon as possible (i.e. without waiting for
|
||||
// content responses) because a finger has gone down and we don't want to keep moving
|
||||
// the content under the finger. However, to prevent "future" touchstart events from
|
||||
// interfering with "past" animations (i.e. from a previous touch block that is still
|
||||
// being processed) we only do this animation-cancellation if there are no older
|
||||
// touch blocks still in the queue.
|
||||
if (block == CurrentTouchBlock()) {
|
||||
// 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->GetOverscrollHandoffChain()->HasFastMovingApzc()) {
|
||||
// If we're already in a fast fling, then we want the touch event to stop the fling
|
||||
// and to disallow the touch event from being used as part of a fling.
|
||||
block->SetDuringFastMotion();
|
||||
INPQ_LOG("block %p tagged as fast-motion\n", block);
|
||||
}
|
||||
block->GetOverscrollHandoffChain()->CancelAnimations();
|
||||
}
|
||||
|
||||
bool waitForMainThread = !aTargetConfirmed;
|
||||
if (!gfxPrefs::LayoutEventRegionsEnabled()) {
|
||||
waitForMainThread |= aTarget->NeedToWaitForContent();
|
||||
}
|
||||
if (block->IsDuringFastMotion()) {
|
||||
block->SetConfirmedTargetApzc(aTarget);
|
||||
waitForMainThread = false;
|
||||
}
|
||||
if (waitForMainThread) {
|
||||
// We either don't know for sure if aTarget is the right APZC, or we may
|
||||
// need to wait to give content the opportunity to prevent-default the
|
||||
// touch events. Either way we schedule a timeout so the main thread stuff
|
||||
// can run.
|
||||
ScheduleMainThreadTimeout(aTarget, block->GetBlockId());
|
||||
CancelAnimationsForNewBlock(block);
|
||||
MaybeRequestContentResponse(aTarget, block);
|
||||
} else {
|
||||
// Content won't prevent-default this, so we can just pretend like we scheduled
|
||||
// a timeout and it expired. Note that we will still receive a ContentReceivedTouch
|
||||
// callback for this block, and so we need to make sure we adjust the touch balance.
|
||||
INPQ_LOG("not waiting for content response on block %p\n", block);
|
||||
block->TimeoutContentResponse();
|
||||
}
|
||||
} else if (mTouchBlockQueue.IsEmpty()) {
|
||||
NS_WARNING("Received a non-start touch event while no touch blocks active!");
|
||||
} else {
|
||||
// this touch is part of the most-recently created block
|
||||
block = mTouchBlockQueue.LastElement().get();
|
||||
INPQ_LOG("received new event in block %p\n", block);
|
||||
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();
|
||||
}
|
||||
@ -108,6 +100,7 @@ InputQueue::ReceiveInputEvent(const nsRefPtr<AsyncPanZoomController>& aTarget,
|
||||
nsRefPtr<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.
|
||||
@ -116,22 +109,60 @@ InputQueue::ReceiveInputEvent(const nsRefPtr<AsyncPanZoomController>& aTarget,
|
||||
} else if (target && target->ArePointerEventsConsumable(block, aEvent.AsMultiTouchInput().mTouches.Length())) {
|
||||
result = nsEventStatus_eConsumeDoDefault;
|
||||
}
|
||||
|
||||
if (block == CurrentTouchBlock() && block->IsReadyForHandling()) {
|
||||
INPQ_LOG("current touch block is ready with target %p preventdefault %d\n",
|
||||
target.get(), block->IsDefaultPrevented());
|
||||
if (!target || block->IsDefaultPrevented()) {
|
||||
return result;
|
||||
}
|
||||
target->HandleInputEvent(aEvent);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Otherwise, add it to the queue for the touch block
|
||||
if (!MaybeHandleCurrentBlock(target, block, aEvent)) {
|
||||
block->AddEvent(aEvent.AsMultiTouchInput());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
InputQueue::CancelAnimationsForNewBlock(CancelableBlockState* aBlock)
|
||||
{
|
||||
// We want to cancel animations here as soon as possible (i.e. without waiting for
|
||||
// content responses) because a finger has gone down and we don't want to keep moving
|
||||
// the content under the finger. However, to prevent "future" touchstart events from
|
||||
// interfering with "past" animations (i.e. from a previous touch block that is still
|
||||
// being processed) we only do this animation-cancellation if there are no older
|
||||
// touch blocks still in the queue.
|
||||
if (aBlock == CurrentBlock()) {
|
||||
// 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 (aBlock->GetOverscrollHandoffChain()->HasFastMovingApzc()) {
|
||||
// If we're already in a fast fling, then we want the touch event to stop the fling
|
||||
// and to disallow the touch event from being used as part of a fling.
|
||||
if (TouchBlockState* touch = aBlock->AsTouchBlock()) {
|
||||
touch->SetDuringFastMotion();
|
||||
}
|
||||
}
|
||||
aBlock->GetOverscrollHandoffChain()->CancelAnimations();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InputQueue::MaybeRequestContentResponse(const nsRefPtr<AsyncPanZoomController>& aTarget,
|
||||
CancelableBlockState* aBlock)
|
||||
{
|
||||
bool waitForMainThread = !aBlock->IsTargetConfirmed();
|
||||
if (!gfxPrefs::LayoutEventRegionsEnabled()) {
|
||||
waitForMainThread |= aTarget->NeedToWaitForContent();
|
||||
}
|
||||
|
||||
if (waitForMainThread) {
|
||||
// We either don't know for sure if aTarget is the right APZC, or we may
|
||||
// need to wait to give content the opportunity to prevent-default the
|
||||
// touch events. Either way we schedule a timeout so the main thread stuff
|
||||
// can run.
|
||||
ScheduleMainThreadTimeout(aTarget, aBlock->GetBlockId());
|
||||
} else {
|
||||
// Content won't prevent-default this, so we can just pretend like we scheduled
|
||||
// a timeout and it expired. Note that we will still receive a ContentReceivedTouch
|
||||
// callback for this block, and so we need to make sure we adjust the touch balance.
|
||||
INPQ_LOG("not waiting for content response on block %p\n", block);
|
||||
aBlock->TimeoutContentResponse();
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
InputQueue::InjectNewTouchBlock(AsyncPanZoomController* aTarget)
|
||||
{
|
||||
@ -144,6 +175,22 @@ InputQueue::InjectNewTouchBlock(AsyncPanZoomController* aTarget)
|
||||
return block->GetBlockId();
|
||||
}
|
||||
|
||||
void
|
||||
InputQueue::SweepDepletedBlocks()
|
||||
{
|
||||
// We're going to start a new block, so clear out any depleted blocks at the head of the queue.
|
||||
// See corresponding comment in ProcessInputBlocks.
|
||||
while (!mInputBlockQueue.IsEmpty()) {
|
||||
CancelableBlockState* block = mInputBlockQueue[0].get();
|
||||
if (!block->IsReadyForHandling() || block->HasEvents()) {
|
||||
break;
|
||||
}
|
||||
|
||||
INPQ_LOG("discarding depleted %s block %p\n", block->Type(), block);
|
||||
mInputBlockQueue.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
TouchBlockState*
|
||||
InputQueue::StartNewTouchBlock(const nsRefPtr<AsyncPanZoomController>& aTarget,
|
||||
bool aTargetConfirmed,
|
||||
@ -154,35 +201,36 @@ InputQueue::StartNewTouchBlock(const nsRefPtr<AsyncPanZoomController>& aTarget,
|
||||
newBlock->CopyAllowedTouchBehaviorsFrom(*CurrentTouchBlock());
|
||||
}
|
||||
|
||||
// We're going to start a new block, so clear out any depleted blocks at the head of the queue.
|
||||
// See corresponding comment in ProcessPendingInputBlocks.
|
||||
while (!mTouchBlockQueue.IsEmpty()) {
|
||||
if (mTouchBlockQueue[0]->IsReadyForHandling() && !mTouchBlockQueue[0]->HasEvents()) {
|
||||
INPQ_LOG("discarding depleted touch block %p\n", mTouchBlockQueue[0].get());
|
||||
mTouchBlockQueue.RemoveElementAt(0);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
SweepDepletedBlocks();
|
||||
|
||||
// Add the new block to the queue.
|
||||
mTouchBlockQueue.AppendElement(newBlock);
|
||||
mInputBlockQueue.AppendElement(newBlock);
|
||||
return newBlock;
|
||||
}
|
||||
|
||||
CancelableBlockState*
|
||||
InputQueue::CurrentBlock() const
|
||||
{
|
||||
AsyncPanZoomController::AssertOnControllerThread();
|
||||
|
||||
MOZ_ASSERT(!mInputBlockQueue.IsEmpty());
|
||||
return mInputBlockQueue[0].get();
|
||||
}
|
||||
|
||||
TouchBlockState*
|
||||
InputQueue::CurrentTouchBlock() const
|
||||
{
|
||||
AsyncPanZoomController::AssertOnControllerThread();
|
||||
|
||||
MOZ_ASSERT(!mTouchBlockQueue.IsEmpty());
|
||||
return mTouchBlockQueue[0].get();
|
||||
TouchBlockState *block = CurrentBlock()->AsTouchBlock();
|
||||
MOZ_ASSERT(block);
|
||||
return block;
|
||||
}
|
||||
|
||||
bool
|
||||
InputQueue::HasReadyTouchBlock() const
|
||||
{
|
||||
return !mTouchBlockQueue.IsEmpty() && mTouchBlockQueue[0]->IsReadyForHandling();
|
||||
return !mInputBlockQueue.IsEmpty() &&
|
||||
mInputBlockQueue[0]->AsTouchBlock() &&
|
||||
mInputBlockQueue[0]->IsReadyForHandling();
|
||||
}
|
||||
|
||||
void
|
||||
@ -199,18 +247,18 @@ InputQueue::MainThreadTimeout(const uint64_t& aInputBlockId) {
|
||||
|
||||
INPQ_LOG("got a main thread timeout; block=%" PRIu64 "\n", aInputBlockId);
|
||||
bool success = false;
|
||||
for (size_t i = 0; i < mTouchBlockQueue.Length(); i++) {
|
||||
if (mTouchBlockQueue[i]->GetBlockId() == aInputBlockId) {
|
||||
for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
|
||||
if (mInputBlockQueue[i]->GetBlockId() == aInputBlockId) {
|
||||
// time out the touch-listener response and also confirm the existing
|
||||
// target apzc in the case where the main thread doesn't get back to us
|
||||
// fast enough.
|
||||
success = mTouchBlockQueue[i]->TimeoutContentResponse();
|
||||
success |= mTouchBlockQueue[i]->SetConfirmedTargetApzc(mTouchBlockQueue[i]->GetTargetApzc());
|
||||
success = mInputBlockQueue[i]->TimeoutContentResponse();
|
||||
success |= mInputBlockQueue[i]->SetConfirmedTargetApzc(mInputBlockQueue[i]->GetTargetApzc());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
ProcessPendingInputBlocks();
|
||||
ProcessInputBlocks();
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,14 +268,15 @@ InputQueue::ContentReceivedTouch(uint64_t aInputBlockId, bool aPreventDefault) {
|
||||
|
||||
INPQ_LOG("got a content response; block=%" PRIu64 "\n", aInputBlockId);
|
||||
bool success = false;
|
||||
for (size_t i = 0; i < mTouchBlockQueue.Length(); i++) {
|
||||
if (mTouchBlockQueue[i]->GetBlockId() == aInputBlockId) {
|
||||
success = mTouchBlockQueue[i]->SetContentResponse(aPreventDefault);
|
||||
for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
|
||||
if (mInputBlockQueue[i]->GetBlockId() == aInputBlockId) {
|
||||
CancelableBlockState* block = mInputBlockQueue[i].get();
|
||||
success = block->SetContentResponse(aPreventDefault);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
ProcessPendingInputBlocks();
|
||||
ProcessInputBlocks();
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,14 +287,14 @@ InputQueue::SetConfirmedTargetApzc(uint64_t aInputBlockId, const nsRefPtr<AsyncP
|
||||
INPQ_LOG("got a target apzc; block=%" PRIu64 " guid=%s\n",
|
||||
aInputBlockId, aTargetApzc ? Stringify(aTargetApzc->GetGuid()).c_str() : "");
|
||||
bool success = false;
|
||||
for (size_t i = 0; i < mTouchBlockQueue.Length(); i++) {
|
||||
if (mTouchBlockQueue[i]->GetBlockId() == aInputBlockId) {
|
||||
success = mTouchBlockQueue[i]->SetConfirmedTargetApzc(aTargetApzc);
|
||||
for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
|
||||
if (mInputBlockQueue[i]->GetBlockId() == aInputBlockId) {
|
||||
success = mInputBlockQueue[i]->SetConfirmedTargetApzc(aTargetApzc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
ProcessPendingInputBlocks();
|
||||
ProcessInputBlocks();
|
||||
} else {
|
||||
NS_WARNING("INPQ received useless SetConfirmedTargetApzc");
|
||||
}
|
||||
@ -257,25 +306,30 @@ InputQueue::SetAllowedTouchBehavior(uint64_t aInputBlockId, const nsTArray<Touch
|
||||
|
||||
INPQ_LOG("got allowed touch behaviours; block=%" PRIu64 "\n", aInputBlockId);
|
||||
bool success = false;
|
||||
for (size_t i = 0; i < mTouchBlockQueue.Length(); i++) {
|
||||
if (mTouchBlockQueue[i]->GetBlockId() == aInputBlockId) {
|
||||
success = mTouchBlockQueue[i]->SetAllowedTouchBehaviors(aBehaviors);
|
||||
for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
|
||||
if (mInputBlockQueue[i]->GetBlockId() == aInputBlockId) {
|
||||
TouchBlockState *block = mInputBlockQueue[i]->AsTouchBlock();
|
||||
if (block) {
|
||||
success = block->SetAllowedTouchBehaviors(aBehaviors);
|
||||
} else {
|
||||
NS_WARNING("input block is not a touch block");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
ProcessPendingInputBlocks();
|
||||
ProcessInputBlocks();
|
||||
} else {
|
||||
NS_WARNING("INPQ received useless SetAllowedTouchBehavior");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InputQueue::ProcessPendingInputBlocks() {
|
||||
InputQueue::ProcessInputBlocks() {
|
||||
AsyncPanZoomController::AssertOnControllerThread();
|
||||
|
||||
while (true) {
|
||||
TouchBlockState* curBlock = CurrentTouchBlock();
|
||||
do {
|
||||
CancelableBlockState* curBlock = CurrentBlock();
|
||||
if (!curBlock->IsReadyForHandling()) {
|
||||
break;
|
||||
}
|
||||
@ -292,25 +346,23 @@ InputQueue::ProcessPendingInputBlocks() {
|
||||
curBlock->DropEvents();
|
||||
target->ResetInputState();
|
||||
} else {
|
||||
while (curBlock->HasEvents()) {
|
||||
target->HandleInputEvent(curBlock->RemoveFirstEvent());
|
||||
}
|
||||
curBlock->HandleEvents(target);
|
||||
}
|
||||
MOZ_ASSERT(!curBlock->HasEvents());
|
||||
|
||||
if (mTouchBlockQueue.Length() == 1) {
|
||||
// If |curBlock| is the only touch block in the queue, then it is still
|
||||
// active and we cannot remove it yet. We only know that a touch block is
|
||||
// over when we start the next one. This block will be removed by the code
|
||||
// in StartNewTouchBlock, where new touch blocks are added.
|
||||
if (mInputBlockQueue.Length() == 1 && curBlock->MustStayActive()) {
|
||||
// Some types of blocks (e.g. touch blocks) accumulate events until the
|
||||
// next input block is started. Therefore we cannot remove the block from
|
||||
// the queue until we have started another block. This block will be
|
||||
// removed by SweepDeletedBlocks() whenever a new block is added.
|
||||
break;
|
||||
}
|
||||
|
||||
// If we get here, we know there are more touch blocks in the queue after
|
||||
// |curBlock|, so we can remove |curBlock| and try to process the next one.
|
||||
INPQ_LOG("discarding depleted touch block %p\n", curBlock);
|
||||
mTouchBlockQueue.RemoveElementAt(0);
|
||||
}
|
||||
mInputBlockQueue.RemoveElementAt(0);
|
||||
} while (!mInputBlockQueue.IsEmpty());
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
|
@ -14,11 +14,13 @@
|
||||
namespace mozilla {
|
||||
|
||||
class InputData;
|
||||
class MultiTouchInput;
|
||||
|
||||
namespace layers {
|
||||
|
||||
class AsyncPanZoomController;
|
||||
class OverscrollHandoffChain;
|
||||
class CancelableBlockState;
|
||||
class TouchBlockState;
|
||||
|
||||
/**
|
||||
@ -76,28 +78,64 @@ public:
|
||||
*/
|
||||
uint64_t InjectNewTouchBlock(AsyncPanZoomController* aTarget);
|
||||
/**
|
||||
* Returns the touch block at the head of the queue.
|
||||
* Returns the pending input block at the head of the queue.
|
||||
*/
|
||||
CancelableBlockState* CurrentBlock() const;
|
||||
/**
|
||||
* Returns the current pending input block as a touch block. It must only
|
||||
* called if the current pending block is a touch block.
|
||||
*/
|
||||
TouchBlockState* CurrentTouchBlock() const;
|
||||
/**
|
||||
* Returns true iff the touch block at the head of the queue is ready for
|
||||
* Returns true iff the pending block at the head of the queue is ready for
|
||||
* handling.
|
||||
*/
|
||||
bool HasReadyTouchBlock() const;
|
||||
|
||||
private:
|
||||
~InputQueue();
|
||||
|
||||
TouchBlockState* StartNewTouchBlock(const nsRefPtr<AsyncPanZoomController>& aTarget,
|
||||
bool aTargetConfirmed,
|
||||
bool aCopyAllowedTouchBehaviorFromCurrent);
|
||||
|
||||
/**
|
||||
* If animations are present for the current pending input block, cancel
|
||||
* them as soon as possible.
|
||||
*/
|
||||
void CancelAnimationsForNewBlock(CancelableBlockState* aBlock);
|
||||
|
||||
/**
|
||||
* If we need to wait for a content response, schedule that now.
|
||||
*/
|
||||
void MaybeRequestContentResponse(const nsRefPtr<AsyncPanZoomController>& aTarget,
|
||||
CancelableBlockState* aBlock);
|
||||
|
||||
nsEventStatus ReceiveTouchInput(const nsRefPtr<AsyncPanZoomController>& aTarget,
|
||||
bool aTargetConfirmed,
|
||||
const MultiTouchInput& aEvent,
|
||||
uint64_t* aOutInputBlockId);
|
||||
|
||||
/**
|
||||
* Remove any blocks that are inactive - not ready, and having no events.
|
||||
*/
|
||||
void SweepDepletedBlocks();
|
||||
|
||||
/**
|
||||
* Processes the current block if it's ready for handling.
|
||||
*/
|
||||
bool MaybeHandleCurrentBlock(const nsRefPtr<AsyncPanZoomController>& aTarget,
|
||||
CancelableBlockState* block,
|
||||
const InputData& aEvent);
|
||||
|
||||
void ScheduleMainThreadTimeout(const nsRefPtr<AsyncPanZoomController>& aTarget, uint64_t aInputBlockId);
|
||||
void MainThreadTimeout(const uint64_t& aInputBlockId);
|
||||
void ProcessPendingInputBlocks();
|
||||
void ProcessInputBlocks();
|
||||
|
||||
private:
|
||||
// The queue of touch blocks that have not yet been processed.
|
||||
// The queue of touch blocks that have not yet been fully processed.
|
||||
// This member must only be accessed on the controller/UI thread.
|
||||
nsTArray<UniquePtr<TouchBlockState>> mTouchBlockQueue;
|
||||
nsTArray<UniquePtr<CancelableBlockState>> mInputBlockQueue;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user