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
parent 20fc09e280
commit f027bf1442

View File

@ -88,34 +88,23 @@ public:
}
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) {
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;
}
void CheckHasDelayedTask() {
EXPECT_TRUE(mTaskQueue.Length() > 0);
insIndex--;
}
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);
mTaskQueue.InsertElementAt(insIndex, std::make_pair(aTask, runAtTime));
}
// 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
// value is 0 is the queue guaranteed to be empty.
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++) {
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;
}
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;
TimeStamp mTime;
};
@ -1386,7 +1394,6 @@ protected:
// Start the fling down.
Pan(apzc, mcc, touchStart, touchEnd);
// 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
// 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.
Pan(apzc, mcc, touchStart, touchEnd, false, nullptr, nullptr, &blockId);
apzc->ConfirmTarget(blockId);
apzc->ContentReceivedInputBlock(blockId, false);
while (mcc->RunThroughDelayedTasks());
// Sample the fling a couple of times to ensure it's going.
ParentLayerPoint point, finalPoint;
@ -1484,18 +1491,20 @@ TEST_F(APZCFlingStopTester, FlingStopPreventDefault) {
TEST_F(APZCGestureDetectorTester, ShortPress) {
MakeApzcUnzoomable();
TapAndCheckStatus(apzc, 10, 10, mcc, TimeDuration::FromMilliseconds(100));
// There will be delayed tasks posted for the long-tap and MAX_TAP timeouts, but
// we want to clear those.
mcc->ClearDelayedTask();
mcc->ClearDelayedTask();
MockFunction<void(std::string checkPointName)> check;
{
InSequence s;
// This verifies that the single tap notification is sent after the
// touchdown is fully processed. The ordering here is important.
mcc->CheckHasDelayedTask();
// touchup is fully processed. The ordering here is important.
EXPECT_CALL(check, Call("pre-tap"));
EXPECT_CALL(check, Call("post-tap"));
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();
}
@ -1503,18 +1512,20 @@ TEST_F(APZCGestureDetectorTester, ShortPress) {
TEST_F(APZCGestureDetectorTester, MediumPress) {
MakeApzcUnzoomable();
TapAndCheckStatus(apzc, 10, 10, mcc, TimeDuration::FromMilliseconds(400));
// There will be delayed tasks posted for the long-tap and MAX_TAP timeouts, but
// we want to clear those.
mcc->ClearDelayedTask();
mcc->ClearDelayedTask();
MockFunction<void(std::string checkPointName)> check;
{
InSequence s;
// This verifies that the single tap notification is sent after the
// touchdown is fully processed. The ordering here is important.
mcc->CheckHasDelayedTask();
// touchup is fully processed. The ordering here is important.
EXPECT_CALL(check, Call("pre-tap"));
EXPECT_CALL(check, Call("post-tap"));
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();
}
@ -1553,25 +1564,18 @@ protected:
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.
check.Call("preHandleLongTap");
mcc->RunDelayedTask();
mcc->RunThroughDelayedTasks();
check.Call("postHandleLongTap");
// Destroy pending MAX_TAP timeout task
mcc->DestroyOldestTask();
// Dispatching the longpress event starts a new touch block, which
// 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
// with preventDefault=false, and then we run the timeout task which
// "loses the race" and does nothing.
apzc->ContentReceivedInputBlock(blockId, false);
mcc->CheckHasDelayedTask();
mcc->RunDelayedTask();
mcc->RunThroughDelayedTasks();
mcc->AdvanceByMillis(1000);
@ -1579,7 +1583,7 @@ protected:
// prevent-defaulted, we should get a long-tap-up event.
check.Call("preHandleSingleTap");
status = TouchUp(apzc, 10, 10, mcc->Time());
mcc->RunDelayedTask();
mcc->RunThroughDelayedTasks();
EXPECT_EQ(nsEventStatus_eConsumeDoDefault, status);
check.Call("postHandleSingleTap");
@ -1620,24 +1624,18 @@ protected:
EXPECT_CALL(check, Call("postHandleLongTap"));
}
mcc->CheckHasDelayedTask();
// Manually invoke the longpress while the touch is currently down.
check.Call("preHandleLongTap");
mcc->RunDelayedTask();
mcc->RunThroughDelayedTasks();
check.Call("postHandleLongTap");
// Destroy pending MAX_TAP timeout task
mcc->DestroyOldestTask();
// There should be a TimeoutContentResponse task in the queue still,
// waiting for the response from the longtap event dispatched above.
// 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
// race. This takes the place of the "contextmenu" event.
apzc->ContentReceivedInputBlock(blockId, true);
mcc->CheckHasDelayedTask();
mcc->RunDelayedTask();
mcc->RunThroughDelayedTasks();
mcc->AdvanceByMillis(1000);