Commit 6e4d5b2f authored by aestes@apple.com's avatar aestes@apple.com

2011-03-13 Andy Estes <aestes@apple.com>

        Reviewed by Darin Adler.

        Timer-based events should inherit the user gesture state of their
        originating event in certain cases.
        https://bugs.webkit.org/show_bug.cgi?id=55104

        * fast/events/popup-blocking-timers-expected.txt: Added.
        * fast/events/popup-blocking-timers.html: Added.
2011-03-14  Andy Estes  <aestes@apple.com>

        Reviewed by Darin Adler.

        Timer-based events should inherit the user gesture state of their
        originating event in certain cases.
        https://bugs.webkit.org/show_bug.cgi?id=55104

        If a timer is installed by a gesture-originated event and will fire
        within one second, the timer-initiated event should behave as if it
        were also initiated by a user gesture. Multi-shot timers should only
        get this behavior on their first execution. Nested timers should not
        get this behavior. This makes us compatible with Gecko when handling
        popups and file chooser dialogs created from timer events.

        Test: fast/events/popup-blocking-timers.html

        * page/DOMTimer.cpp:
        (WebCore::timeoutId): Create a helper function so that m_timeoutId can
        be initialized in the data member initialization list.
        (WebCore::shouldForwardUserGesture): Ditto, but for
        m_shouldForwardUserGesture.
        (WebCore::DOMTimer::DOMTimer): Move initialization of data members from
        the ctor body to the data member initialization list. Also rename the
        argument 'timeout' to 'interval'.
        (WebCore::DOMTimer::fired): Create a UserGestureIndicator and set its
        state based on the value of m_shouldForwardUserGesture.
        (WebCore::DOMTimer::adjustMinimumTimerInterval): m_originalTimeout was
        renamed to m_originalInterval.
        * page/DOMTimer.h: Add m_shouldForwardUserGesture and rename
        m_originalTimeout to m_originalInterval.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@81057 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 688f641f
2011-03-13 Andy Estes <aestes@apple.com>
Reviewed by Darin Adler.
Timer-based events should inherit the user gesture state of their
originating event in certain cases.
https://bugs.webkit.org/show_bug.cgi?id=55104
* fast/events/popup-blocking-timers-expected.txt: Added.
* fast/events/popup-blocking-timers.html: Added.
2011-03-09 Levi Weintraub <leviw@chromium.org>
Reviewed by Ryosuke Niwa.
Click Here
Test calling window.open() directly. A popup should be allowed.
PASS newWindow is non-null.
Test calling window.open() with a 0 ms delay. A popup should be allowed.
PASS newWindow is non-null.
Test calling window.open() in a 100 ms interval. A popup should only be allowed on the first execution of the interval.
PASS newWindow is non-null.
Test calling window.open() in a 100 ms interval. A popup should only be allowed on the first execution of the interval.
PASS newWindow is undefined.
Test calling window.open() in a nested call to setTimeout(). A popup should not be allowed.
PASS newWindow is undefined.
Test calling window.open() with a 1000 ms delay. A popup should be allowed.
PASS newWindow is non-null.
Test calling window.open() with a 1001 ms delay. A popup should not be allowed.
PASS newWindow is undefined.
<head>
<link rel="stylesheet" href="../js/resources/js-test-style.css">
<script src="../js/resources/js-test-pre.js"></script>
<script>
var newWindow;
var intervalId;
var firstIntervalExecution = true;
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.setCanOpenWindows();
layoutTestController.waitUntilDone();
layoutTestController.setPopupBlockingEnabled(true);
}
function clickHandler() {
newWindow = window.open("about:blank");
self.focus();
debug("Test calling window.open() directly. A popup should be allowed.");
shouldBeNonNull("newWindow");
setTimeout(function() {
newWindow = window.open("about:blank");
self.focus();
debug("Test calling window.open() with a 0 ms delay. A popup should be allowed.")
shouldBeNonNull("newWindow");
}, 0);
setTimeout(function() {
newWindow = window.open("about:blank");
self.focus();
debug("Test calling window.open() with a 1000 ms delay. A popup should be allowed.")
shouldBeNonNull("newWindow");
}, 1000);
setTimeout(function() {
newWindow = window.open("about:blank");
self.focus();
debug("Test calling window.open() with a 1001 ms delay. A popup should not be allowed.")
shouldBeUndefined("newWindow");
if (window.layoutTestController)
layoutTestController.notifyDone();
}, 1001);
intervalId = setInterval(function() {
debug("Test calling window.open() in a 100 ms interval. A popup should only be allowed on the first execution of the interval.");
newWindow = window.open("about:blank");
self.focus();
if (firstIntervalExecution) {
shouldBeNonNull("newWindow");
firstIntervalExecution = false;
} else {
shouldBeUndefined("newWindow");
clearInterval(intervalId);
}
}, 100);
setTimeout(function() {
setTimeout(function() {
newWindow = window.open("about:blank");
self.focus();
debug("Test calling window.open() in a nested call to setTimeout(). A popup should not be allowed.")
shouldBeUndefined("newWindow");
}, 0);
}, 300);
if (window.eventSender)
eventSender.leapForward(1001);
}
function clickButton() {
var button = document.getElementById("test");
var buttonX = button.offsetLeft + button.offsetWidth / 2;
var buttonY = button.offsetTop + button.offsetHeight / 2;
if (window.eventSender) {
eventSender.mouseMoveTo(buttonX, buttonY);
eventSender.mouseDown();
eventSender.mouseUp();
}
}
</script>
</head>
<body onload="clickButton()">
<button id="test" onclick="clickHandler()">Click Here</button>
<div id="console"></div>
</body>
\ No newline at end of file
2011-03-14 Andy Estes <aestes@apple.com>
Reviewed by Darin Adler.
Timer-based events should inherit the user gesture state of their
originating event in certain cases.
https://bugs.webkit.org/show_bug.cgi?id=55104
If a timer is installed by a gesture-originated event and will fire
within one second, the timer-initiated event should behave as if it
were also initiated by a user gesture. Multi-shot timers should only
get this behavior on their first execution. Nested timers should not
get this behavior. This makes us compatible with Gecko when handling
popups and file chooser dialogs created from timer events.
Test: fast/events/popup-blocking-timers.html
* page/DOMTimer.cpp:
(WebCore::timeoutId): Create a helper function so that m_timeoutId can
be initialized in the data member initialization list.
(WebCore::shouldForwardUserGesture): Ditto, but for
m_shouldForwardUserGesture.
(WebCore::DOMTimer::DOMTimer): Move initialization of data members from
the ctor body to the data member initialization list. Also rename the
argument 'timeout' to 'interval'.
(WebCore::DOMTimer::fired): Create a UserGestureIndicator and set its
state based on the value of m_shouldForwardUserGesture.
(WebCore::DOMTimer::adjustMinimumTimerInterval): m_originalTimeout was
renamed to m_originalInterval.
* page/DOMTimer.h: Add m_shouldForwardUserGesture and rename
m_originalTimeout to m_originalInterval.
2011-03-09 Levi Weintraub <leviw@chromium.org>
Reviewed by Ryosuke Niwa.
......
......@@ -30,6 +30,7 @@
#include "InspectorInstrumentation.h"
#include "ScheduledAction.h"
#include "ScriptExecutionContext.h"
#include "UserGestureIndicator.h"
#include <wtf/HashSet.h>
#include <wtf/StdLibExtras.h>
......@@ -37,29 +38,41 @@ using namespace std;
namespace WebCore {
static const int maxIntervalForUserGestureForwarding = 1000; // One second matches Gecko.
static const int maxTimerNestingLevel = 5;
static const double oneMillisecond = 0.001;
double DOMTimer::s_minDefaultTimerInterval = 0.010; // 10 milliseconds
static int timerNestingLevel = 0;
DOMTimer::DOMTimer(ScriptExecutionContext* context, PassOwnPtr<ScheduledAction> action, int timeout, bool singleShot)
: SuspendableTimer(context)
, m_action(action)
, m_originalTimeout(timeout)
static int timeoutId()
{
static int lastUsedTimeoutId = 0;
++lastUsedTimeoutId;
// Avoid wraparound going negative on us.
if (lastUsedTimeoutId <= 0)
lastUsedTimeoutId = 1;
m_timeoutId = lastUsedTimeoutId;
m_nestingLevel = timerNestingLevel + 1;
return lastUsedTimeoutId;
}
static inline bool shouldForwardUserGesture(int interval, int nestingLevel)
{
return UserGestureIndicator::processingUserGesture()
&& interval <= maxIntervalForUserGestureForwarding
&& nestingLevel == 1; // Gestures should not be forwarded to nested timers.
}
DOMTimer::DOMTimer(ScriptExecutionContext* context, PassOwnPtr<ScheduledAction> action, int interval, bool singleShot)
: SuspendableTimer(context)
, m_timeoutId(timeoutId())
, m_nestingLevel(timerNestingLevel + 1)
, m_action(action)
, m_originalInterval(interval)
, m_shouldForwardUserGesture(shouldForwardUserGesture(interval, m_nestingLevel))
{
scriptExecutionContext()->addTimeout(m_timeoutId, this);
double intervalMilliseconds = intervalClampedToMinimum(timeout, context->minimumTimerInterval());
double intervalMilliseconds = intervalClampedToMinimum(interval, context->minimumTimerInterval());
if (singleShot)
startOneShot(intervalMilliseconds);
else
......@@ -101,6 +114,11 @@ void DOMTimer::fired()
{
ScriptExecutionContext* context = scriptExecutionContext();
timerNestingLevel = m_nestingLevel;
UserGestureIndicator gestureIndicator(m_shouldForwardUserGesture ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
// Only the first execution of a multi-shot timer should get an affirmative user gesture indicator.
m_shouldForwardUserGesture = false;
InspectorInstrumentationCookie cookie = InspectorInstrumentation::willFireTimer(context, m_timeoutId);
......@@ -155,14 +173,14 @@ void DOMTimer::adjustMinimumTimerInterval(double oldMinimumTimerInterval)
return;
double newMinimumInterval = scriptExecutionContext()->minimumTimerInterval();
double newClampedInterval = intervalClampedToMinimum(m_originalTimeout, newMinimumInterval);
double newClampedInterval = intervalClampedToMinimum(m_originalInterval, newMinimumInterval);
if (repeatInterval()) {
augmentRepeatInterval(newClampedInterval - repeatInterval());
return;
}
double previousClampedInterval = intervalClampedToMinimum(m_originalTimeout, oldMinimumTimerInterval);
double previousClampedInterval = intervalClampedToMinimum(m_originalInterval, oldMinimumTimerInterval);
augmentFireInterval(newClampedInterval - previousClampedInterval);
}
......
......@@ -55,7 +55,7 @@ namespace WebCore {
void adjustMinimumTimerInterval(double oldMinimumTimerInterval);
private:
DOMTimer(ScriptExecutionContext*, PassOwnPtr<ScheduledAction>, int timeout, bool singleShot);
DOMTimer(ScriptExecutionContext*, PassOwnPtr<ScheduledAction>, int interval, bool singleShot);
virtual void fired();
double intervalClampedToMinimum(int timeout, double minimumTimerInterval) const;
......@@ -68,7 +68,8 @@ namespace WebCore {
int m_timeoutId;
int m_nestingLevel;
OwnPtr<ScheduledAction> m_action;
int m_originalTimeout;
int m_originalInterval;
bool m_shouldForwardUserGesture;
static double s_minDefaultTimerInterval;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment