Bug 1169695 - Ensure timed tasks are dispatched appropriately when advancing the time. r=botond

This commit is contained in:
Kartikaya Gupta 2015-06-01 14:36:12 -04:00
Родитель d67fa2cccc
Коммит 7d039d70cb
1 изменённых файлов: 67 добавлений и 69 удалений

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

@ -88,34 +88,23 @@ public:
} }
void AdvanceBy(const TimeDuration& aIncrement) { void AdvanceBy(const TimeDuration& aIncrement) {
mTime += aIncrement; TimeStamp target = mTime + aIncrement;
while (mTaskQueue.Length() > 0 && mTaskQueue[0].second <= target) {
RunNextDelayedTask();
}
mTime = target;
} }
void PostDelayedTask(Task* aTask, int aDelayMs) { void PostDelayedTask(Task* aTask, int aDelayMs) {
mTaskQueue.AppendElement(std::make_pair(aTask, mTime + TimeDuration::FromMilliseconds(aDelayMs))); TimeStamp runAtTime = mTime + TimeDuration::FromMilliseconds(aDelayMs);
int insIndex = mTaskQueue.Length();
while (insIndex > 0) {
if (mTaskQueue[insIndex - 1].second <= runAtTime) {
break;
} }
insIndex--;
void CheckHasDelayedTask() {
EXPECT_TRUE(mTaskQueue.Length() > 0);
} }
mTaskQueue.InsertElementAt(insIndex, std::make_pair(aTask, runAtTime));
void ClearDelayedTask() {
mTaskQueue.RemoveElementAt(0);
}
void DestroyOldestTask() {
delete mTaskQueue[0].first;
mTaskQueue.RemoveElementAt(0);
}
// Note that deleting mCurrentTask is important in order to
// release the reference to the callee object. Without this
// that object might be leaked. This is also why we don't
// expose mTaskQueue to any users of MockContentControllerDelayed.
void RunDelayedTask() {
mTaskQueue[0].first->Run();
delete mTaskQueue[0].first;
mTaskQueue.RemoveElementAt(0);
} }
// Run all the tasks in the queue, returning the number of tasks // Run all the tasks in the queue, returning the number of tasks
@ -124,14 +113,33 @@ public:
// in the queue after this function is called. Only when the return // in the queue after this function is called. Only when the return
// value is 0 is the queue guaranteed to be empty. // value is 0 is the queue guaranteed to be empty.
int RunThroughDelayedTasks() { int RunThroughDelayedTasks() {
int numTasks = mTaskQueue.Length(); nsTArray<std::pair<Task*, TimeStamp>> runQueue;
runQueue.SwapElements(mTaskQueue);
int numTasks = runQueue.Length();
for (int i = 0; i < numTasks; i++) { for (int i = 0; i < numTasks; i++) {
RunDelayedTask(); mTime = runQueue[i].second;
runQueue[i].first->Run();
// Deleting the task is important in order to release the reference to
// the callee object.
delete runQueue[i].first;
} }
return numTasks; return numTasks;
} }
private: private:
void RunNextDelayedTask() {
std::pair<Task*, TimeStamp> next = mTaskQueue[0];
mTaskQueue.RemoveElementAt(0);
mTime = next.second;
next.first->Run();
// Deleting the task is important in order to release the reference to
// the callee object.
delete next.first;
}
// The following array is sorted by timestamp (tasks are inserted in order by
// timestamp).
nsTArray<std::pair<Task*, TimeStamp>> mTaskQueue; nsTArray<std::pair<Task*, TimeStamp>> mTaskQueue;
TimeStamp mTime; TimeStamp mTime;
}; };
@ -1386,7 +1394,6 @@ protected:
// Start the fling down. // Start the fling down.
Pan(apzc, mcc, touchStart, touchEnd); Pan(apzc, mcc, touchStart, touchEnd);
// The touchstart from the pan will leave some cancelled tasks in the queue, clear them out // The touchstart from the pan will leave some cancelled tasks in the queue, clear them out
while (mcc->RunThroughDelayedTasks());
// If we want to tap while the fling is fast, let the fling advance for 10ms only. If we want // If we want to tap while the fling is fast, let the fling advance for 10ms only. If we want
// the fling to slow down more, advance to 2000ms. These numbers may need adjusting if our // the fling to slow down more, advance to 2000ms. These numbers may need adjusting if our
@ -1429,8 +1436,8 @@ protected:
// Start the fling down. // Start the fling down.
Pan(apzc, mcc, touchStart, touchEnd, false, nullptr, nullptr, &blockId); Pan(apzc, mcc, touchStart, touchEnd, false, nullptr, nullptr, &blockId);
apzc->ConfirmTarget(blockId);
apzc->ContentReceivedInputBlock(blockId, false); apzc->ContentReceivedInputBlock(blockId, false);
while (mcc->RunThroughDelayedTasks());
// Sample the fling a couple of times to ensure it's going. // Sample the fling a couple of times to ensure it's going.
ParentLayerPoint point, finalPoint; ParentLayerPoint point, finalPoint;
@ -1484,18 +1491,20 @@ TEST_F(APZCFlingStopTester, FlingStopPreventDefault) {
TEST_F(APZCGestureDetectorTester, ShortPress) { TEST_F(APZCGestureDetectorTester, ShortPress) {
MakeApzcUnzoomable(); MakeApzcUnzoomable();
TapAndCheckStatus(apzc, 10, 10, mcc, TimeDuration::FromMilliseconds(100)); MockFunction<void(std::string checkPointName)> check;
// There will be delayed tasks posted for the long-tap and MAX_TAP timeouts, but {
// we want to clear those. InSequence s;
mcc->ClearDelayedTask();
mcc->ClearDelayedTask();
// This verifies that the single tap notification is sent after the // This verifies that the single tap notification is sent after the
// touchdown is fully processed. The ordering here is important. // touchup is fully processed. The ordering here is important.
mcc->CheckHasDelayedTask(); EXPECT_CALL(check, Call("pre-tap"));
EXPECT_CALL(check, Call("post-tap"));
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1); EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
mcc->RunDelayedTask(); }
check.Call("pre-tap");
TapAndCheckStatus(apzc, 10, 10, mcc, TimeDuration::FromMilliseconds(100));
check.Call("post-tap");
while (mcc->RunThroughDelayedTasks());
apzc->AssertStateIsReset(); apzc->AssertStateIsReset();
} }
@ -1503,18 +1512,20 @@ TEST_F(APZCGestureDetectorTester, ShortPress) {
TEST_F(APZCGestureDetectorTester, MediumPress) { TEST_F(APZCGestureDetectorTester, MediumPress) {
MakeApzcUnzoomable(); MakeApzcUnzoomable();
TapAndCheckStatus(apzc, 10, 10, mcc, TimeDuration::FromMilliseconds(400)); MockFunction<void(std::string checkPointName)> check;
// There will be delayed tasks posted for the long-tap and MAX_TAP timeouts, but {
// we want to clear those. InSequence s;
mcc->ClearDelayedTask();
mcc->ClearDelayedTask();
// This verifies that the single tap notification is sent after the // This verifies that the single tap notification is sent after the
// touchdown is fully processed. The ordering here is important. // touchup is fully processed. The ordering here is important.
mcc->CheckHasDelayedTask(); EXPECT_CALL(check, Call("pre-tap"));
EXPECT_CALL(check, Call("post-tap"));
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1); EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
mcc->RunDelayedTask(); }
check.Call("pre-tap");
TapAndCheckStatus(apzc, 10, 10, mcc, TimeDuration::FromMilliseconds(400));
check.Call("post-tap");
while (mcc->RunThroughDelayedTasks());
apzc->AssertStateIsReset(); apzc->AssertStateIsReset();
} }
@ -1553,25 +1564,18 @@ protected:
EXPECT_CALL(check, Call("postHandleSingleTap")); EXPECT_CALL(check, Call("postHandleSingleTap"));
} }
// There is a longpress event scheduled on a timeout
mcc->CheckHasDelayedTask();
// Manually invoke the longpress while the touch is currently down. // Manually invoke the longpress while the touch is currently down.
check.Call("preHandleLongTap"); check.Call("preHandleLongTap");
mcc->RunDelayedTask(); mcc->RunThroughDelayedTasks();
check.Call("postHandleLongTap"); check.Call("postHandleLongTap");
// Destroy pending MAX_TAP timeout task
mcc->DestroyOldestTask();
// Dispatching the longpress event starts a new touch block, which // Dispatching the longpress event starts a new touch block, which
// needs a new content response and also has a pending timeout task // needs a new content response and also has a pending timeout task
// in the queue. Deal with those here. We do the content response first // in the queue. Deal with those here. We do the content response first
// with preventDefault=false, and then we run the timeout task which // with preventDefault=false, and then we run the timeout task which
// "loses the race" and does nothing. // "loses the race" and does nothing.
apzc->ContentReceivedInputBlock(blockId, false); apzc->ContentReceivedInputBlock(blockId, false);
mcc->CheckHasDelayedTask(); mcc->RunThroughDelayedTasks();
mcc->RunDelayedTask();
mcc->AdvanceByMillis(1000); mcc->AdvanceByMillis(1000);
@ -1579,7 +1583,7 @@ protected:
// prevent-defaulted, we should get a long-tap-up event. // prevent-defaulted, we should get a long-tap-up event.
check.Call("preHandleSingleTap"); check.Call("preHandleSingleTap");
status = TouchUp(apzc, 10, 10, mcc->Time()); status = TouchUp(apzc, 10, 10, mcc->Time());
mcc->RunDelayedTask(); mcc->RunThroughDelayedTasks();
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status); EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status);
check.Call("postHandleSingleTap"); check.Call("postHandleSingleTap");
@ -1620,24 +1624,18 @@ protected:
EXPECT_CALL(check, Call("postHandleLongTap")); EXPECT_CALL(check, Call("postHandleLongTap"));
} }
mcc->CheckHasDelayedTask();
// Manually invoke the longpress while the touch is currently down. // Manually invoke the longpress while the touch is currently down.
check.Call("preHandleLongTap"); check.Call("preHandleLongTap");
mcc->RunDelayedTask(); mcc->RunThroughDelayedTasks();
check.Call("postHandleLongTap"); check.Call("postHandleLongTap");
// Destroy pending MAX_TAP timeout task
mcc->DestroyOldestTask();
// There should be a TimeoutContentResponse task in the queue still, // There should be a TimeoutContentResponse task in the queue still,
// waiting for the response from the longtap event dispatched above. // waiting for the response from the longtap event dispatched above.
// Send the signal that content has handled the long-tap, and then run // Send the signal that content has handled the long-tap, and then run
// the timeout task (it will be a no-op because the content "wins" the // the timeout task (it will be a no-op because the content "wins" the
// race. This takes the place of the "contextmenu" event. // race. This takes the place of the "contextmenu" event.
apzc->ContentReceivedInputBlock(blockId, true); apzc->ContentReceivedInputBlock(blockId, true);
mcc->CheckHasDelayedTask(); mcc->RunThroughDelayedTasks();
mcc->RunDelayedTask();
mcc->AdvanceByMillis(1000); mcc->AdvanceByMillis(1000);