Bug 1440118 - If the APZ content response timeout is set to zero, use the fallback (timeout) behavior unconditionally. r=kats
MozReview-Commit-ID: HrkUd3MJoxC
--- a/gfx/layers/apz/src/InputQueue.cpp
+++ b/gfx/layers/apz/src/InputQueue.cpp
@@ -30,16 +30,18 @@ InputQueue::~InputQueue() {
nsEventStatus
InputQueue::ReceiveInputEvent(const RefPtr<AsyncPanZoomController>& aTarget,
TargetConfirmationFlags aFlags,
const InputData& aEvent,
uint64_t* aOutInputBlockId) {
APZThreadUtils::AssertOnControllerThread();
+ AutoRunImmediateTimeout timeoutRunner{this};
+
switch (aEvent.mInputType) {
case MULTITOUCH_INPUT: {
const MultiTouchInput& event = aEvent.AsMultiTouchInput();
return ReceiveTouchInput(aTarget, aFlags, event, aOutInputBlockId);
}
case SCROLLWHEEL_INPUT: {
const ScrollWheelInput& event = aEvent.AsScrollWheelInput();
@@ -440,16 +442,17 @@ InputQueue::MaybeRequestContentResponse(
// can run.
ScheduleMainThreadTimeout(aTarget, aBlock);
}
}
uint64_t
InputQueue::InjectNewTouchBlock(AsyncPanZoomController* aTarget)
{
+ AutoRunImmediateTimeout timeoutRunner{this};
TouchBlockState* block = StartNewTouchBlock(aTarget,
TargetConfirmationFlags{true},
/* aCopyPropertiesFromCurrent = */ true);
INPQ_LOG("injecting new touch block %p with id %" PRIu64 " and target %p\n",
block, block->GetBlockId(), aTarget);
ScheduleMainThreadTimeout(aTarget, block);
return block->GetBlockId();
}
@@ -562,22 +565,36 @@ InputQueue::IsDragOnScrollbar(bool aHitS
return mDragTracker.IsOnScrollbar(aHitScrollbar);
}
void
InputQueue::ScheduleMainThreadTimeout(const RefPtr<AsyncPanZoomController>& aTarget,
CancelableBlockState* aBlock) {
INPQ_LOG("scheduling main thread timeout for target %p\n", aTarget.get());
aBlock->StartContentResponseTimer();
- aTarget->PostDelayedTask(
- NewRunnableMethod<uint64_t>("layers::InputQueue::MainThreadTimeout",
- this,
- &InputQueue::MainThreadTimeout,
- aBlock->GetBlockId()),
- gfxPrefs::APZContentResponseTimeout());
+ RefPtr<Runnable> timeoutTask = NewRunnableMethod<uint64_t>("layers::InputQueue::MainThreadTimeout",
+ this,
+ &InputQueue::MainThreadTimeout,
+ aBlock->GetBlockId());
+ int32_t timeout = gfxPrefs::APZContentResponseTimeout();
+ if (timeout == 0) {
+ // If the timeout is zero, treat it as a request to ignore any main
+ // thread confirmation and unconditionally use fallback behaviour for
+ // when a timeout is reached. This codepath is used by tests that
+ // want to exercise the fallback behaviour.
+ // To ensure the fallback behaviour is used unconditionally, the timeout
+ // is run right away instead of using PostDelayedTask(). However,
+ // we can't run it right here, because MainThreadTimeout() expects that
+ // the input block has at least one input event in mQueuedInputs, and
+ // the event that triggered this call may not have been added to
+ // mQueuedInputs yet.
+ mImmediateTimeout = timeoutTask.forget();
+ } else {
+ aTarget->PostDelayedTask(timeoutTask.forget(), timeout);
+ }
}
InputBlockState*
InputQueue::FindBlockForId(uint64_t aInputBlockId,
InputData** aOutFirstInput)
{
for (const auto& queuedInput : mQueuedInputs) {
if (queuedInput->Block()->GetBlockId() == aInputBlockId) {
@@ -802,10 +819,24 @@ InputQueue::Clear()
mActiveTouchBlock = nullptr;
mActiveWheelBlock = nullptr;
mActiveDragBlock = nullptr;
mActivePanGestureBlock = nullptr;
mActiveKeyboardBlock = nullptr;
mLastActiveApzc = nullptr;
}
+InputQueue::AutoRunImmediateTimeout::AutoRunImmediateTimeout(InputQueue* aQueue)
+ : mQueue(aQueue)
+{
+ MOZ_ASSERT(!mQueue->mImmediateTimeout);
+}
+
+InputQueue::AutoRunImmediateTimeout::~AutoRunImmediateTimeout()
+{
+ if (mQueue->mImmediateTimeout) {
+ mQueue->mImmediateTimeout->Run();
+ mQueue->mImmediateTimeout = nullptr;
+ }
+}
+
} // namespace layers
} // namespace mozilla
--- a/gfx/layers/apz/src/InputQueue.h
+++ b/gfx/layers/apz/src/InputQueue.h
@@ -134,16 +134,26 @@ public:
* targeted at a scrollbar. If the drag was newly-created and doesn't know,
* use the provided |aOnScrollbar| to populate that information.
*/
bool IsDragOnScrollbar(bool aOnScrollbar);
private:
~InputQueue();
+ // RAII class for automatically running a timeout task that may
+ // need to be run immediately after an event has been queued.
+ class AutoRunImmediateTimeout {
+ public:
+ explicit AutoRunImmediateTimeout(InputQueue* aQueue);
+ ~AutoRunImmediateTimeout();
+ private:
+ InputQueue* mQueue;
+ };
+
TouchBlockState* StartNewTouchBlock(const RefPtr<AsyncPanZoomController>& aTarget,
TargetConfirmationFlags aFlags,
bool aCopyPropertiesFromCurrent);
/**
* If animations are present for the current pending input block, cancel
* them as soon as possible.
*/
@@ -213,14 +223,18 @@ private:
// The APZC to which the last event was delivered
RefPtr<AsyncPanZoomController> mLastActiveApzc;
// Track touches so we know when to clear mLastActiveApzc
TouchCounter mTouchCounter;
// Track mouse inputs so we know if we're in a drag or not
DragTracker mDragTracker;
+
+ // Temporarily stores a timeout task that needs to be run as soon as
+ // as the event that triggered it has been queued.
+ RefPtr<Runnable> mImmediateTimeout;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_InputQueue_h