Refactor InputQueue to hold more than touch events. (bug 1013432 part 2, r=kats)

--HG--
extra : rebase_source : cd3691a2bda6aaf315cf3b844e4fdd3aa8b30334
This commit is contained in:
David Anderson 2014-12-09 02:34:27 -08:00
Родитель fd05150dca
Коммит d2831e46f4
4 изменённых файлов: 280 добавлений и 130 удалений

Просмотреть файл

@ -220,6 +220,18 @@ TouchBlockState::AddEvent(const MultiTouchInput& aEvent)
mEvents.AppendElement(aEvent); mEvents.AppendElement(aEvent);
} }
bool
TouchBlockState::MustStayActive()
{
return true;
}
const char*
TouchBlockState::Type()
{
return "touch";
}
void void
TouchBlockState::DropEvents() TouchBlockState::DropEvents()
{ {
@ -227,6 +239,14 @@ TouchBlockState::DropEvents()
mEvents.Clear(); mEvents.Clear();
} }
void
TouchBlockState::HandleEvents(const nsRefPtr<AsyncPanZoomController>& aTarget)
{
while (HasEvents()) {
aTarget->HandleInputEvent(RemoveFirstEvent());
}
}
MultiTouchInput MultiTouchInput
TouchBlockState::RemoveFirstEvent() TouchBlockState::RemoveFirstEvent()
{ {

Просмотреть файл

@ -16,6 +16,9 @@ namespace layers {
class AsyncPanZoomController; class AsyncPanZoomController;
class OverscrollHandoffChain; class OverscrollHandoffChain;
class CancelableBlockState;
class TouchBlockState;
class WheelBlockState;
/** /**
* A base class that stores state common to various input blocks. * A base class that stores state common to various input blocks.
@ -28,14 +31,16 @@ public:
explicit InputBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc, explicit InputBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
bool aTargetConfirmed); bool aTargetConfirmed);
virtual ~InputBlockState()
{}
bool SetConfirmedTargetApzc(const nsRefPtr<AsyncPanZoomController>& aTargetApzc); bool SetConfirmedTargetApzc(const nsRefPtr<AsyncPanZoomController>& aTargetApzc);
const nsRefPtr<AsyncPanZoomController>& GetTargetApzc() const; const nsRefPtr<AsyncPanZoomController>& GetTargetApzc() const;
const nsRefPtr<const OverscrollHandoffChain>& GetOverscrollHandoffChain() const; const nsRefPtr<const OverscrollHandoffChain>& GetOverscrollHandoffChain() const;
uint64_t GetBlockId() const; uint64_t GetBlockId() const;
protected:
bool IsTargetConfirmed() const; bool IsTargetConfirmed() const;
private: private:
nsRefPtr<AsyncPanZoomController> mTargetApzc; nsRefPtr<AsyncPanZoomController> mTargetApzc;
nsRefPtr<const OverscrollHandoffChain> mOverscrollHandoffChain; nsRefPtr<const OverscrollHandoffChain> mOverscrollHandoffChain;
@ -61,6 +66,10 @@ public:
CancelableBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc, CancelableBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
bool aTargetConfirmed); bool aTargetConfirmed);
virtual TouchBlockState *AsTouchBlock() {
return nullptr;
}
/** /**
* Record whether or not content cancelled this block of events. * Record whether or not content cancelled this block of events.
* @param aPreventDefault true iff the block is cancelled. * @param aPreventDefault true iff the block is cancelled.
@ -81,10 +90,37 @@ public:
bool IsDefaultPrevented() const; 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; 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: private:
bool mPreventDefault; bool mPreventDefault;
bool mContentResponded; bool mContentResponded;
@ -122,6 +158,10 @@ public:
explicit TouchBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc, explicit TouchBlockState(const nsRefPtr<AsyncPanZoomController>& aTargetApzc,
bool aTargetConfirmed); bool aTargetConfirmed);
TouchBlockState *AsTouchBlock() MOZ_OVERRIDE {
return this;
}
/** /**
* Set the allowed touch behavior flags for this block. * Set the allowed touch behavior flags for this block.
* @return false if this block already has these flags set, true if not. * @return false if this block already has these flags set, true if not.
@ -161,23 +201,10 @@ public:
*/ */
bool SingleTapOccurred() const; 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. * Add a new touch event to the queue of events in this input block.
*/ */
void AddEvent(const MultiTouchInput& aEvent); 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 * @return false iff touch-action is enabled and the allowed touch behaviors for
@ -197,6 +224,19 @@ public:
bool TouchActionAllowsPanningY() const; bool TouchActionAllowsPanningY() const;
bool TouchActionAllowsPanningXY() 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: private:
nsTArray<TouchBehaviorFlags> mAllowedTouchBehaviors; nsTArray<TouchBehaviorFlags> mAllowedTouchBehaviors;
bool mAllowedTouchBehaviorSet; bool mAllowedTouchBehaviorSet;

Просмотреть файл

@ -23,7 +23,7 @@ InputQueue::InputQueue()
} }
InputQueue::~InputQueue() { InputQueue::~InputQueue() {
mTouchBlockQueue.Clear(); mInputBlockQueue.Clear();
} }
nsEventStatus nsEventStatus
@ -33,70 +33,62 @@ InputQueue::ReceiveInputEvent(const nsRefPtr<AsyncPanZoomController>& aTarget,
uint64_t* aOutInputBlockId) { uint64_t* aOutInputBlockId) {
AsyncPanZoomController::AssertOnControllerThread(); AsyncPanZoomController::AssertOnControllerThread();
if (aEvent.mInputType != MULTITOUCH_INPUT) { switch (aEvent.mInputType) {
// The return value for non-touch input is only used by tests, so just pass case MULTITOUCH_INPUT: {
// through the return value for now. This can be changed later if needed. const MultiTouchInput& event = aEvent.AsMultiTouchInput();
// TODO (bug 1098430): we will eventually need to have smarter handling for return ReceiveTouchInput(aTarget, aTargetConfirmed, event, aOutInputBlockId);
// non-touch events as well. }
return aTarget->HandleInputEvent(aEvent);
}
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; TouchBlockState* block = nullptr;
if (aEvent.AsMultiTouchInput().mType == MultiTouchInput::MULTITOUCH_START) { if (aEvent.mType == MultiTouchInput::MULTITOUCH_START) {
block = StartNewTouchBlock(aTarget, aTargetConfirmed, false); block = StartNewTouchBlock(aTarget, aTargetConfirmed, false);
INPQ_LOG("started new touch block %p for target %p\n", block, aTarget.get()); 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 CancelAnimationsForNewBlock(block);
// content responses) because a finger has gone down and we don't want to keep moving MaybeRequestContentResponse(aTarget, block);
// the content under the finger. However, to prevent "future" touchstart events from } else {
// interfering with "past" animations (i.e. from a previous touch block that is still if (!mInputBlockQueue.IsEmpty()) {
// being processed) we only do this animation-cancellation if there are no older block = mInputBlockQueue.LastElement().get()->AsTouchBlock();
// 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 (!block) {
if (!gfxPrefs::LayoutEventRegionsEnabled()) { NS_WARNING("Received a non-start touch event while no touch blocks active!");
waitForMainThread |= aTarget->NeedToWaitForContent(); return nsEventStatus_eIgnore;
} }
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());
} 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); INPQ_LOG("received new event in block %p\n", block);
} }
if (!block) {
return nsEventStatus_eIgnore;
}
if (aOutInputBlockId) { if (aOutInputBlockId) {
*aOutInputBlockId = block->GetBlockId(); *aOutInputBlockId = block->GetBlockId();
} }
@ -108,6 +100,7 @@ InputQueue::ReceiveInputEvent(const nsRefPtr<AsyncPanZoomController>& aTarget,
nsRefPtr<AsyncPanZoomController> target = block->GetTargetApzc(); nsRefPtr<AsyncPanZoomController> target = block->GetTargetApzc();
nsEventStatus result = nsEventStatus_eIgnore; nsEventStatus result = nsEventStatus_eIgnore;
// XXX calling ArePointerEventsConsumable on |target| may be wrong here if // XXX calling ArePointerEventsConsumable on |target| may be wrong here if
// the target isn't confirmed and the real target turns out to be something // 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. // else. For now assume this is rare enough that it's not an issue.
@ -116,20 +109,58 @@ InputQueue::ReceiveInputEvent(const nsRefPtr<AsyncPanZoomController>& aTarget,
} else if (target && target->ArePointerEventsConsumable(block, aEvent.AsMultiTouchInput().mTouches.Length())) { } else if (target && target->ArePointerEventsConsumable(block, aEvent.AsMultiTouchInput().mTouches.Length())) {
result = nsEventStatus_eConsumeDoDefault; result = nsEventStatus_eConsumeDoDefault;
} }
if (!MaybeHandleCurrentBlock(target, block, aEvent)) {
block->AddEvent(aEvent.AsMultiTouchInput());
}
return result;
}
if (block == CurrentTouchBlock() && block->IsReadyForHandling()) { void
INPQ_LOG("current touch block is ready with target %p preventdefault %d\n", InputQueue::CancelAnimationsForNewBlock(CancelableBlockState* aBlock)
target.get(), block->IsDefaultPrevented()); {
if (!target || block->IsDefaultPrevented()) { // We want to cancel animations here as soon as possible (i.e. without waiting for
return result; // 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();
}
} }
target->HandleInputEvent(aEvent); aBlock->GetOverscrollHandoffChain()->CancelAnimations();
return result; }
}
void
InputQueue::MaybeRequestContentResponse(const nsRefPtr<AsyncPanZoomController>& aTarget,
CancelableBlockState* aBlock)
{
bool waitForMainThread = !aBlock->IsTargetConfirmed();
if (!gfxPrefs::LayoutEventRegionsEnabled()) {
waitForMainThread |= aTarget->NeedToWaitForContent();
} }
// Otherwise, add it to the queue for the touch block if (waitForMainThread) {
block->AddEvent(aEvent.AsMultiTouchInput()); // We either don't know for sure if aTarget is the right APZC, or we may
return result; // 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 uint64_t
@ -144,6 +175,22 @@ InputQueue::InjectNewTouchBlock(AsyncPanZoomController* aTarget)
return block->GetBlockId(); 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* TouchBlockState*
InputQueue::StartNewTouchBlock(const nsRefPtr<AsyncPanZoomController>& aTarget, InputQueue::StartNewTouchBlock(const nsRefPtr<AsyncPanZoomController>& aTarget,
bool aTargetConfirmed, bool aTargetConfirmed,
@ -154,35 +201,36 @@ InputQueue::StartNewTouchBlock(const nsRefPtr<AsyncPanZoomController>& aTarget,
newBlock->CopyAllowedTouchBehaviorsFrom(*CurrentTouchBlock()); newBlock->CopyAllowedTouchBehaviorsFrom(*CurrentTouchBlock());
} }
// We're going to start a new block, so clear out any depleted blocks at the head of the queue. SweepDepletedBlocks();
// 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;
}
}
// Add the new block to the queue. // Add the new block to the queue.
mTouchBlockQueue.AppendElement(newBlock); mInputBlockQueue.AppendElement(newBlock);
return newBlock; return newBlock;
} }
CancelableBlockState*
InputQueue::CurrentBlock() const
{
AsyncPanZoomController::AssertOnControllerThread();
MOZ_ASSERT(!mInputBlockQueue.IsEmpty());
return mInputBlockQueue[0].get();
}
TouchBlockState* TouchBlockState*
InputQueue::CurrentTouchBlock() const InputQueue::CurrentTouchBlock() const
{ {
AsyncPanZoomController::AssertOnControllerThread(); TouchBlockState *block = CurrentBlock()->AsTouchBlock();
MOZ_ASSERT(block);
MOZ_ASSERT(!mTouchBlockQueue.IsEmpty()); return block;
return mTouchBlockQueue[0].get();
} }
bool bool
InputQueue::HasReadyTouchBlock() const InputQueue::HasReadyTouchBlock() const
{ {
return !mTouchBlockQueue.IsEmpty() && mTouchBlockQueue[0]->IsReadyForHandling(); return !mInputBlockQueue.IsEmpty() &&
mInputBlockQueue[0]->AsTouchBlock() &&
mInputBlockQueue[0]->IsReadyForHandling();
} }
void void
@ -199,18 +247,18 @@ InputQueue::MainThreadTimeout(const uint64_t& aInputBlockId) {
INPQ_LOG("got a main thread timeout; block=%" PRIu64 "\n", aInputBlockId); INPQ_LOG("got a main thread timeout; block=%" PRIu64 "\n", aInputBlockId);
bool success = false; bool success = false;
for (size_t i = 0; i < mTouchBlockQueue.Length(); i++) { for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
if (mTouchBlockQueue[i]->GetBlockId() == aInputBlockId) { if (mInputBlockQueue[i]->GetBlockId() == aInputBlockId) {
// time out the touch-listener response and also confirm the existing // 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 // target apzc in the case where the main thread doesn't get back to us
// fast enough. // fast enough.
success = mTouchBlockQueue[i]->TimeoutContentResponse(); success = mInputBlockQueue[i]->TimeoutContentResponse();
success |= mTouchBlockQueue[i]->SetConfirmedTargetApzc(mTouchBlockQueue[i]->GetTargetApzc()); success |= mInputBlockQueue[i]->SetConfirmedTargetApzc(mInputBlockQueue[i]->GetTargetApzc());
break; break;
} }
} }
if (success) { 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); INPQ_LOG("got a content response; block=%" PRIu64 "\n", aInputBlockId);
bool success = false; bool success = false;
for (size_t i = 0; i < mTouchBlockQueue.Length(); i++) { for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
if (mTouchBlockQueue[i]->GetBlockId() == aInputBlockId) { if (mInputBlockQueue[i]->GetBlockId() == aInputBlockId) {
success = mTouchBlockQueue[i]->SetContentResponse(aPreventDefault); CancelableBlockState* block = mInputBlockQueue[i].get();
success = block->SetContentResponse(aPreventDefault);
break; break;
} }
} }
if (success) { 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", INPQ_LOG("got a target apzc; block=%" PRIu64 " guid=%s\n",
aInputBlockId, aTargetApzc ? Stringify(aTargetApzc->GetGuid()).c_str() : ""); aInputBlockId, aTargetApzc ? Stringify(aTargetApzc->GetGuid()).c_str() : "");
bool success = false; bool success = false;
for (size_t i = 0; i < mTouchBlockQueue.Length(); i++) { for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
if (mTouchBlockQueue[i]->GetBlockId() == aInputBlockId) { if (mInputBlockQueue[i]->GetBlockId() == aInputBlockId) {
success = mTouchBlockQueue[i]->SetConfirmedTargetApzc(aTargetApzc); success = mInputBlockQueue[i]->SetConfirmedTargetApzc(aTargetApzc);
break; break;
} }
} }
if (success) { if (success) {
ProcessPendingInputBlocks(); ProcessInputBlocks();
} else { } else {
NS_WARNING("INPQ received useless SetConfirmedTargetApzc"); 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); INPQ_LOG("got allowed touch behaviours; block=%" PRIu64 "\n", aInputBlockId);
bool success = false; bool success = false;
for (size_t i = 0; i < mTouchBlockQueue.Length(); i++) { for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
if (mTouchBlockQueue[i]->GetBlockId() == aInputBlockId) { if (mInputBlockQueue[i]->GetBlockId() == aInputBlockId) {
success = mTouchBlockQueue[i]->SetAllowedTouchBehaviors(aBehaviors); TouchBlockState *block = mInputBlockQueue[i]->AsTouchBlock();
if (block) {
success = block->SetAllowedTouchBehaviors(aBehaviors);
} else {
NS_WARNING("input block is not a touch block");
}
break; break;
} }
} }
if (success) { if (success) {
ProcessPendingInputBlocks(); ProcessInputBlocks();
} else { } else {
NS_WARNING("INPQ received useless SetAllowedTouchBehavior"); NS_WARNING("INPQ received useless SetAllowedTouchBehavior");
} }
} }
void void
InputQueue::ProcessPendingInputBlocks() { InputQueue::ProcessInputBlocks() {
AsyncPanZoomController::AssertOnControllerThread(); AsyncPanZoomController::AssertOnControllerThread();
while (true) { do {
TouchBlockState* curBlock = CurrentTouchBlock(); CancelableBlockState* curBlock = CurrentBlock();
if (!curBlock->IsReadyForHandling()) { if (!curBlock->IsReadyForHandling()) {
break; break;
} }
@ -292,25 +346,23 @@ InputQueue::ProcessPendingInputBlocks() {
curBlock->DropEvents(); curBlock->DropEvents();
target->ResetInputState(); target->ResetInputState();
} else { } else {
while (curBlock->HasEvents()) { curBlock->HandleEvents(target);
target->HandleInputEvent(curBlock->RemoveFirstEvent());
}
} }
MOZ_ASSERT(!curBlock->HasEvents()); MOZ_ASSERT(!curBlock->HasEvents());
if (mTouchBlockQueue.Length() == 1) { if (mInputBlockQueue.Length() == 1 && curBlock->MustStayActive()) {
// If |curBlock| is the only touch block in the queue, then it is still // Some types of blocks (e.g. touch blocks) accumulate events until the
// active and we cannot remove it yet. We only know that a touch block is // next input block is started. Therefore we cannot remove the block from
// over when we start the next one. This block will be removed by the code // the queue until we have started another block. This block will be
// in StartNewTouchBlock, where new touch blocks are added. // removed by SweepDeletedBlocks() whenever a new block is added.
break; break;
} }
// If we get here, we know there are more touch blocks in the queue after // 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. // |curBlock|, so we can remove |curBlock| and try to process the next one.
INPQ_LOG("discarding depleted touch block %p\n", curBlock); INPQ_LOG("discarding depleted touch block %p\n", curBlock);
mTouchBlockQueue.RemoveElementAt(0); mInputBlockQueue.RemoveElementAt(0);
} } while (!mInputBlockQueue.IsEmpty());
} }
} // namespace layers } // namespace layers

Просмотреть файл

@ -14,11 +14,13 @@
namespace mozilla { namespace mozilla {
class InputData; class InputData;
class MultiTouchInput;
namespace layers { namespace layers {
class AsyncPanZoomController; class AsyncPanZoomController;
class OverscrollHandoffChain; class OverscrollHandoffChain;
class CancelableBlockState;
class TouchBlockState; class TouchBlockState;
/** /**
@ -76,28 +78,64 @@ public:
*/ */
uint64_t InjectNewTouchBlock(AsyncPanZoomController* aTarget); 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; 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. * handling.
*/ */
bool HasReadyTouchBlock() const; bool HasReadyTouchBlock() const;
private: private:
~InputQueue(); ~InputQueue();
TouchBlockState* StartNewTouchBlock(const nsRefPtr<AsyncPanZoomController>& aTarget, TouchBlockState* StartNewTouchBlock(const nsRefPtr<AsyncPanZoomController>& aTarget,
bool aTargetConfirmed, bool aTargetConfirmed,
bool aCopyAllowedTouchBehaviorFromCurrent); 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 ScheduleMainThreadTimeout(const nsRefPtr<AsyncPanZoomController>& aTarget, uint64_t aInputBlockId);
void MainThreadTimeout(const uint64_t& aInputBlockId); void MainThreadTimeout(const uint64_t& aInputBlockId);
void ProcessPendingInputBlocks(); void ProcessInputBlocks();
private: 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. // This member must only be accessed on the controller/UI thread.
nsTArray<UniquePtr<TouchBlockState>> mTouchBlockQueue; nsTArray<UniquePtr<CancelableBlockState>> mInputBlockQueue;
}; };
} }