Source/WebCore: Ensure timers and other active DOM objects do not fire in suspended documents.

https://bugs.webkit.org/show_bug.cgi?id=53733

ScriptExecutionContext now remembers it has suspended active DOM objects
and suspends all newly installed active DOM objects as well.

All create-calls active DOM objects now calls the post constructor method
suspendIfNeeded that updates the suspend state. It is post constructor
because the suspend/resume functions are virtual and thus can not be called
from constructors.

Patch by Allan Sandfeld Jensen <allan.jensen@nokia.com> on 2012-02-03
Reviewed by Mihai Parparita.

Test: fast/events/suspend-timers.html

* Modules/intents/IntentRequest.cpp:
(WebCore::IntentRequest::create):
* bindings/generic/ActiveDOMCallback.cpp:
(WebCore::ActiveDOMCallback::ActiveDOMCallback):
* dom/ActiveDOMObject.cpp:
(WebCore::ActiveDOMObject::ActiveDOMObject):
(WebCore::ActiveDOMObject::~ActiveDOMObject):
(WebCore::ActiveDOMObject::suspendIfNeeded):
* dom/ActiveDOMObject.h:
(WebCore::ActiveDOMObject::suspendIfNeededCalled):
* dom/DocumentEventQueue.cpp:
(WebCore::DocumentEventQueue::DocumentEventQueue):
* dom/ScriptExecutionContext.cpp:
(WebCore::ScriptExecutionContext::ScriptExecutionContext):
(WebCore::ScriptExecutionContext::~ScriptExecutionContext):
(WebCore::ScriptExecutionContext::canSuspendActiveDOMObjects):
(WebCore::ScriptExecutionContext::suspendActiveDOMObjects):
(WebCore::ScriptExecutionContext::resumeActiveDOMObjects):
(WebCore::ScriptExecutionContext::stopActiveDOMObjects):
(WebCore::ScriptExecutionContext::suspendActiveDOMObjectIfNeeded):
* dom/ScriptExecutionContext.h:
(WebCore::ScriptExecutionContext::activeDOMObjectsAreSuspended):
* fileapi/DOMFileSystem.cpp:
(WebCore::DOMFileSystem::create):
* fileapi/FileReader.cpp:
(WebCore::FileReader::create):
* fileapi/FileReader.h:
* fileapi/FileWriter.cpp:
(WebCore::FileWriter::create):
* fileapi/FileWriter.h:
* history/CachedFrame.cpp:
(WebCore::CachedFrame::CachedFrame):
* html/HTMLAudioElement.cpp:
(WebCore::HTMLAudioElement::create):
* html/HTMLMarqueeElement.cpp:
(WebCore::HTMLMarqueeElement::create):
* html/HTMLVideoElement.cpp:
(WebCore::HTMLVideoElement::create):
* mediastream/PeerConnection.cpp:
(WebCore::PeerConnection::create):
* notifications/Notification.cpp:
(WebCore::Notification::create):
* notifications/NotificationCenter.cpp:
(WebCore::NotificationCenter::create):
* notifications/NotificationCenter.h:
* page/DOMTimer.cpp:
(WebCore::DOMTimer::install):
(WebCore::DOMTimer::fired):
* page/EventSource.cpp:
(WebCore::EventSource::create):
* page/SuspendableTimer.cpp:
(WebCore::SuspendableTimer::SuspendableTimer):
* storage/IDBDatabase.cpp:
(WebCore::IDBDatabase::create):
* storage/IDBRequest.cpp:
(WebCore::IDBRequest::create):
* storage/IDBTransaction.cpp:
(WebCore::IDBTransaction::create):
* webaudio/AudioContext.cpp:
(WebCore::AudioContext::create):
* websockets/WebSocket.cpp:
(WebCore::WebSocket::create):
* websockets/WebSocket.h:
* workers/SharedWorker.cpp:
(WebCore::SharedWorker::create):
* workers/Worker.cpp:
(WebCore::Worker::create):
* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::create):

LayoutTests: Test that timers do not fire from subframes of suspended documents.
https://bugs.webkit.org/show_bug.cgi?id=53733

Patch by Allan Sandfeld Jensen <allan.jensen@nokia.com> on 2012-02-03
Reviewed by Mihai Parparita.

* fast/events/resources/suspend-subframe-1.html: Added.
* fast/events/resources/suspend-subframe-2.html: Added.
* fast/events/suspend-timers-expected.txt: Added.
* fast/events/suspend-timers.html: Added.
* platform/chromium/test_expectations.txt:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@106654 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 3ac2660f
2012-02-03 Allan Sandfeld Jensen <allan.jensen@nokia.com>
Test that timers do not fire from subframes of suspended documents.
https://bugs.webkit.org/show_bug.cgi?id=53733
Reviewed by Mihai Parparita.
* fast/events/resources/suspend-subframe-1.html: Added.
* fast/events/resources/suspend-subframe-2.html: Added.
* fast/events/suspend-timers-expected.txt: Added.
* fast/events/suspend-timers.html: Added.
* platform/chromium/test_expectations.txt:
2012-02-03 Zoltan Arvai <zarvai@inf.u-szeged.hu>
New test introduced in r106642 failes on Qt Linux Release
<!DOCTYPE html>
<html>
<head>
<script>
function test() {
window.top.console.log('Timeout in subframe-1 created');
setTimeout(function() {
alert('Timeout created in subframe-1.html fired');
}, 50);
}
</script>
</head>
<body>
I am subframe-1.html
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<script>
onpagehide = function() {
window.top.document.getElementById('a-frame').contentWindow.test();
}
</script>
</head>
<body>
I am subframe-2.html
</body>
</html>
CONSOLE MESSAGE: line 6: Timeout in subframe-1 created
CONSOLE MESSAGE: line 5: Loaded pagehide-timeout-go-back.html, going back
CONSOLE MESSAGE: line 31: Restored page from page cache.
ALERT: Timeout created in subframe-1.html fired
Tests that all JS timers are suspended after the pagehide event is fired, so that timers created within it will not fire while the document is in the page cache.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<head>
<title>Suspend timers on navigate</title>
<style>
iframe {
display: block;
border: solid 1px #ccc;
margin: 1em;
width: 200px;
height: 200px;
}
</style>
<link rel="stylesheet" href="../js/resources/js-test-style.css">
<script src="../js/resources/js-test-pre.js"></script>
</head>
<body>
<iframe src="resources/suspend-subframe-1.html" id="a-frame"></iframe> <iframe src="resources/suspend-subframe-2.html" id="b-frame"></iframe>
<script type="text/javascript">
description('Tests that all JS timers are suspended after the pagehide event is fired, so that timers created within it will not fire while the document is in the page cache.');
if (window.layoutTestController)
layoutTestController.overridePreference('WebKitUsesPageCachePreferenceKey', 1);
onpageshow = function(event)
{
if (event.persisted) {
console.log('Restored page from page cache.');
if (!window.wasFinishJSTestCalled) {
setTimeout(function() {
finishJSTest();
}, 200);
}
}
}
onload = function()
{
setTimeout(function() {
location.href = 'resources/pagehide-timeout-go-back.html';
}, 10);
}
var successfullyParsed = true;
var jsTestIsAsync = true;
</script>
<script src="../js/resources/js-test-post.js"></script>
</body>
</html>
......@@ -203,6 +203,7 @@ WONTFIX SKIP : fast/dom/Window/timer-resume-on-navigation-back.html = TIMEOUT FA
WONTFIX SKIP : fast/events/pagehide-timeout.html = TIMEOUT
WONTFIX SKIP : fast/events/pageshow-pagehide-on-back-cached.html = TIMEOUT FAIL
WONTFIX SKIP : fast/events/pageshow-pagehide-on-back-cached-with-frames.html = TIMEOUT
WONTFIX SKIP : fast/events/suspend-timers.html = TIMEOUT
WONTFIX SKIP : media/restore-from-page-cache.html = TIMEOUT
WONTFIX SKIP : loader/go-back-to-different-window-size.html = TIMEOUT TEXT
WONTFIX SKIP : fast/loader/crash-copying-backforwardlist.html = TEXT
......
2012-02-03 Allan Sandfeld Jensen <allan.jensen@nokia.com>
Ensure timers and other active DOM objects do not fire in suspended documents.
https://bugs.webkit.org/show_bug.cgi?id=53733
ScriptExecutionContext now remembers it has suspended active DOM objects
and suspends all newly installed active DOM objects as well.
All create-calls active DOM objects now calls the post constructor method
suspendIfNeeded that updates the suspend state. It is post constructor
because the suspend/resume functions are virtual and thus can not be called
from constructors.
Reviewed by Mihai Parparita.
Test: fast/events/suspend-timers.html
* Modules/intents/IntentRequest.cpp:
(WebCore::IntentRequest::create):
* bindings/generic/ActiveDOMCallback.cpp:
(WebCore::ActiveDOMCallback::ActiveDOMCallback):
* dom/ActiveDOMObject.cpp:
(WebCore::ActiveDOMObject::ActiveDOMObject):
(WebCore::ActiveDOMObject::~ActiveDOMObject):
(WebCore::ActiveDOMObject::suspendIfNeeded):
* dom/ActiveDOMObject.h:
(WebCore::ActiveDOMObject::suspendIfNeededCalled):
* dom/DocumentEventQueue.cpp:
(WebCore::DocumentEventQueue::DocumentEventQueue):
* dom/ScriptExecutionContext.cpp:
(WebCore::ScriptExecutionContext::ScriptExecutionContext):
(WebCore::ScriptExecutionContext::~ScriptExecutionContext):
(WebCore::ScriptExecutionContext::canSuspendActiveDOMObjects):
(WebCore::ScriptExecutionContext::suspendActiveDOMObjects):
(WebCore::ScriptExecutionContext::resumeActiveDOMObjects):
(WebCore::ScriptExecutionContext::stopActiveDOMObjects):
(WebCore::ScriptExecutionContext::suspendActiveDOMObjectIfNeeded):
* dom/ScriptExecutionContext.h:
(WebCore::ScriptExecutionContext::activeDOMObjectsAreSuspended):
* fileapi/DOMFileSystem.cpp:
(WebCore::DOMFileSystem::create):
* fileapi/FileReader.cpp:
(WebCore::FileReader::create):
* fileapi/FileReader.h:
* fileapi/FileWriter.cpp:
(WebCore::FileWriter::create):
* fileapi/FileWriter.h:
* history/CachedFrame.cpp:
(WebCore::CachedFrame::CachedFrame):
* html/HTMLAudioElement.cpp:
(WebCore::HTMLAudioElement::create):
* html/HTMLMarqueeElement.cpp:
(WebCore::HTMLMarqueeElement::create):
* html/HTMLVideoElement.cpp:
(WebCore::HTMLVideoElement::create):
* mediastream/PeerConnection.cpp:
(WebCore::PeerConnection::create):
* notifications/Notification.cpp:
(WebCore::Notification::create):
* notifications/NotificationCenter.cpp:
(WebCore::NotificationCenter::create):
* notifications/NotificationCenter.h:
* page/DOMTimer.cpp:
(WebCore::DOMTimer::install):
(WebCore::DOMTimer::fired):
* page/EventSource.cpp:
(WebCore::EventSource::create):
* page/SuspendableTimer.cpp:
(WebCore::SuspendableTimer::SuspendableTimer):
* storage/IDBDatabase.cpp:
(WebCore::IDBDatabase::create):
* storage/IDBRequest.cpp:
(WebCore::IDBRequest::create):
* storage/IDBTransaction.cpp:
(WebCore::IDBTransaction::create):
* webaudio/AudioContext.cpp:
(WebCore::AudioContext::create):
* websockets/WebSocket.cpp:
(WebCore::WebSocket::create):
* websockets/WebSocket.h:
* workers/SharedWorker.cpp:
(WebCore::SharedWorker::create):
* workers/Worker.cpp:
(WebCore::Worker::create):
* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::create):
2012-02-03 Allan Sandfeld Jensen <allan.jensen@nokia.com>
Do not ASSERT on TouchStationary TouchPoint state.
......@@ -41,7 +41,9 @@ PassRefPtr<IntentRequest> IntentRequest::create(ScriptExecutionContext* context,
PassRefPtr<IntentResultCallback> successCallback,
PassRefPtr<IntentResultCallback> errorCallback)
{
return adoptRef(new IntentRequest(context, intent, successCallback, errorCallback));
RefPtr<IntentRequest> intentRequest(adoptRef(new IntentRequest(context, intent, successCallback, errorCallback)));
intentRequest->suspendIfNeeded();
return intentRequest.release();
}
IntentRequest::IntentRequest(ScriptExecutionContext* context,
......
......@@ -122,6 +122,7 @@ static void destroyOnContextThread(PassOwnPtr<ActiveDOMObjectCallbackImpl> impl)
ActiveDOMCallback::ActiveDOMCallback(ScriptExecutionContext* context)
: m_impl(adoptPtr(new ActiveDOMObjectCallbackImpl(context)))
{
m_impl->suspendIfNeeded();
}
ActiveDOMCallback::~ActiveDOMCallback()
......
......@@ -60,6 +60,9 @@ void ContextDestructionObserver::contextDestroyed()
ActiveDOMObject::ActiveDOMObject(ScriptExecutionContext* scriptExecutionContext, void* upcastPointer)
: ContextDestructionObserver(scriptExecutionContext)
, m_pendingActivityCount(0)
#if !ASSERT_DISABLED
, m_suspendIfNeededCalled(false)
#endif
{
if (!m_scriptExecutionContext)
return;
......@@ -73,10 +76,23 @@ ActiveDOMObject::~ActiveDOMObject()
if (!m_scriptExecutionContext)
return;
ASSERT(m_suspendIfNeededCalled);
ASSERT(m_scriptExecutionContext->isContextThread());
m_scriptExecutionContext->willDestroyActiveDOMObject(this);
}
void ActiveDOMObject::suspendIfNeeded()
{
#if !ASSERT_DISABLED
ASSERT(!m_suspendIfNeededCalled);
m_suspendIfNeededCalled = true;
#endif
if (!m_scriptExecutionContext)
return;
m_scriptExecutionContext->suspendActiveDOMObjectIfNeeded(this);
}
bool ActiveDOMObject::hasPendingActivity() const
{
return m_pendingActivityCount;
......
......@@ -51,6 +51,13 @@ namespace WebCore {
public:
ActiveDOMObject(ScriptExecutionContext*, void* upcastPointer);
// suspendIfNeeded() should be called exactly once after object construction to synchronize
// the suspend state with that in ScriptExecutionContext.
void suspendIfNeeded();
#if !ASSERT_DISABLED
bool suspendIfNeededCalled() const { return m_suspendIfNeededCalled; }
#endif
virtual bool hasPendingActivity() const;
// canSuspend() is used by the caller if there is a choice between suspending and stopping.
......@@ -88,6 +95,9 @@ namespace WebCore {
private:
unsigned m_pendingActivityCount;
#if !ASSERT_DISABLED
bool m_suspendIfNeededCalled;
#endif
};
} // namespace WebCore
......
......@@ -64,6 +64,7 @@ DocumentEventQueue::DocumentEventQueue(ScriptExecutionContext* context)
: m_pendingEventTimer(adoptPtr(new DocumentEventQueueTimer(this, context)))
, m_isClosed(false)
{
m_pendingEventTimer->suspendIfNeeded();
}
DocumentEventQueue::~DocumentEventQueue()
......
......@@ -92,6 +92,7 @@ ScriptExecutionContext::ScriptExecutionContext()
: m_iteratingActiveDOMObjects(false)
, m_inDestructor(false)
, m_inDispatchErrorEvent(false)
, m_activeDOMObjectsAreSuspended(false)
#if ENABLE(SQL_DATABASE)
, m_hasOpenDatabases(false)
#endif
......@@ -101,7 +102,6 @@ ScriptExecutionContext::ScriptExecutionContext()
ScriptExecutionContext::~ScriptExecutionContext()
{
m_inDestructor = true;
for (HashSet<ContextDestructionObserver*>::iterator iter = m_destructionObservers.begin(); iter != m_destructionObservers.end(); iter = m_destructionObservers.begin()) {
ContextDestructionObserver* observer = *iter;
m_destructionObservers.remove(observer);
......@@ -206,11 +206,12 @@ bool ScriptExecutionContext::canSuspendActiveDOMObjects()
HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
ASSERT(iter->first->scriptExecutionContext() == this);
ASSERT(iter->first->suspendIfNeededCalled());
if (!iter->first->canSuspend()) {
m_iteratingActiveDOMObjects = false;
return false;
}
}
}
m_iteratingActiveDOMObjects = false;
return true;
}
......@@ -222,18 +223,23 @@ void ScriptExecutionContext::suspendActiveDOMObjects(ActiveDOMObject::ReasonForS
HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
ASSERT(iter->first->scriptExecutionContext() == this);
ASSERT(iter->first->suspendIfNeededCalled());
iter->first->suspend(why);
}
m_iteratingActiveDOMObjects = false;
m_activeDOMObjectsAreSuspended = true;
m_reasonForSuspendingActiveDOMObjects = why;
}
void ScriptExecutionContext::resumeActiveDOMObjects()
{
m_activeDOMObjectsAreSuspended = false;
// No protection against m_activeDOMObjects changing during iteration: resume() shouldn't execute arbitrary JS.
m_iteratingActiveDOMObjects = true;
HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
ASSERT(iter->first->scriptExecutionContext() == this);
ASSERT(iter->first->suspendIfNeededCalled());
iter->first->resume();
}
m_iteratingActiveDOMObjects = false;
......@@ -246,6 +252,7 @@ void ScriptExecutionContext::stopActiveDOMObjects()
HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
ASSERT(iter->first->scriptExecutionContext() == this);
ASSERT(iter->first->suspendIfNeededCalled());
iter->first->stop();
}
m_iteratingActiveDOMObjects = false;
......@@ -254,6 +261,14 @@ void ScriptExecutionContext::stopActiveDOMObjects()
closeMessagePorts();
}
void ScriptExecutionContext::suspendActiveDOMObjectIfNeeded(ActiveDOMObject* object)
{
ASSERT(m_activeDOMObjects.contains(object));
// Ensure all ActiveDOMObjects are suspended also newly created ones.
if (m_activeDOMObjectsAreSuspended)
object->suspend(m_reasonForSuspendingActiveDOMObjects);
}
void ScriptExecutionContext::didCreateActiveDOMObject(ActiveDOMObject* object, void* upcastPointer)
{
ASSERT(object);
......
......@@ -103,9 +103,15 @@ public:
virtual void resumeActiveDOMObjects();
virtual void stopActiveDOMObjects();
bool activeDOMObjectsAreSuspended() const { return m_activeDOMObjectsAreSuspended; }
// Called from the constructor and destructors of ActiveDOMObject.
void didCreateActiveDOMObject(ActiveDOMObject*, void* upcastPointer);
void willDestroyActiveDOMObject(ActiveDOMObject*);
// Called after the construction of an ActiveDOMObject to synchronize suspend state.
void suspendActiveDOMObjectIfNeeded(ActiveDOMObject*);
typedef const HashMap<ActiveDOMObject*, void*> ActiveDOMObjectsMap;
ActiveDOMObjectsMap& activeDOMObjects() const { return m_activeDOMObjects; }
......@@ -206,6 +212,9 @@ private:
class PendingException;
OwnPtr<Vector<OwnPtr<PendingException> > > m_pendingExceptions;
bool m_activeDOMObjectsAreSuspended;
ActiveDOMObject::ReasonForSuspension m_reasonForSuspendingActiveDOMObjects;
#if ENABLE(SQL_DATABASE)
RefPtr<DatabaseThread> m_databaseThread;
bool m_hasOpenDatabases; // This never changes back to false, even after the database thread is closed.
......
......@@ -56,8 +56,9 @@ namespace WebCore {
PassRefPtr<DOMFileSystem> DOMFileSystem::create(ScriptExecutionContext* context, const String& name, PassOwnPtr<AsyncFileSystem> asyncFileSystem)
{
RefPtr<DOMFileSystem> fileSystem(adoptRef(new DOMFileSystem(context, name, asyncFileSystem)));
fileSystem->suspendIfNeeded();
InspectorInstrumentation::didOpenFileSystem(fileSystem.get());
return fileSystem;
return fileSystem.release();
}
DOMFileSystem::DOMFileSystem(ScriptExecutionContext* context, const String& name, PassOwnPtr<AsyncFileSystem> asyncFileSystem)
......
......@@ -48,6 +48,13 @@ namespace WebCore {
static const double progressNotificationIntervalMS = 50;
PassRefPtr<FileReader> FileReader::create(ScriptExecutionContext* context)
{
RefPtr<FileReader> fileReader(adoptRef(new FileReader(context)));
fileReader->suspendIfNeeded();
return fileReader.release();
}
FileReader::FileReader(ScriptExecutionContext* context)
: ActiveDOMObject(context, this)
, m_state(EMPTY)
......
......@@ -51,10 +51,7 @@ typedef int ExceptionCode;
class FileReader : public RefCounted<FileReader>, public ActiveDOMObject, public EventTarget, public FileReaderLoaderClient {
public:
static PassRefPtr<FileReader> create(ScriptExecutionContext* context)
{
return adoptRef(new FileReader(context));
}
static PassRefPtr<FileReader> create(ScriptExecutionContext*);
virtual ~FileReader();
......
......@@ -45,6 +45,13 @@ namespace WebCore {
static const int kMaxRecursionDepth = 3;
PassRefPtr<FileWriter> FileWriter::create(ScriptExecutionContext* context)
{
RefPtr<FileWriter> fileWriter(adoptRef(new FileWriter(context)));
fileWriter->suspendIfNeeded();
return fileWriter.release();
}
FileWriter::FileWriter(ScriptExecutionContext* context)
: ActiveDOMObject(context, this)
, m_readyState(INIT)
......
......@@ -48,10 +48,7 @@ class ScriptExecutionContext;
class FileWriter : public FileWriterBase, public ActiveDOMObject, public EventTarget, public AsyncFileWriterClient {
public:
static PassRefPtr<FileWriter> create(ScriptExecutionContext* context)
{
return adoptRef(new FileWriter(context));
}
static PassRefPtr<FileWriter> create(ScriptExecutionContext*);
enum ReadyState {
INIT = 0,
......
......@@ -168,7 +168,6 @@ CachedFrame::CachedFrame(Frame* frame)
// but after we've fired the pagehide event, in case that creates more objects.
// Suspending must also happen after we've recursed over child frames, in case
// those create more objects.
// FIXME: It's still possible to have objects created after suspending in some cases, see http://webkit.org/b/53733 for more details.
m_document->documentWillSuspendForPageCache();
m_document->suspendScriptedAnimationControllerCallbacks();
m_document->suspendActiveDOMObjects(ActiveDOMObject::DocumentWillBecomeInactive);
......
......@@ -43,7 +43,9 @@ HTMLAudioElement::HTMLAudioElement(const QualifiedName& tagName, Document* docum
PassRefPtr<HTMLAudioElement> HTMLAudioElement::create(const QualifiedName& tagName, Document* document, bool createdByParser)
{
return adoptRef(new HTMLAudioElement(tagName, document, createdByParser));
RefPtr<HTMLAudioElement> audioElement(adoptRef(new HTMLAudioElement(tagName, document, createdByParser)));
audioElement->suspendIfNeeded();
return audioElement.release();
}
PassRefPtr<HTMLAudioElement> HTMLAudioElement::createForJSConstructor(Document* document, const String& src)
......
......@@ -48,7 +48,9 @@ inline HTMLMarqueeElement::HTMLMarqueeElement(const QualifiedName& tagName, Docu
PassRefPtr<HTMLMarqueeElement> HTMLMarqueeElement::create(const QualifiedName& tagName, Document* document)
{
return adoptRef(new HTMLMarqueeElement(tagName, document));
RefPtr<HTMLMarqueeElement> marqueeElement(adoptRef(new HTMLMarqueeElement(tagName, document)));
marqueeElement->suspendIfNeeded();
return marqueeElement.release();
}
bool HTMLMarqueeElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
......
......@@ -54,7 +54,9 @@ inline HTMLVideoElement::HTMLVideoElement(const QualifiedName& tagName, Document
PassRefPtr<HTMLVideoElement> HTMLVideoElement::create(const QualifiedName& tagName, Document* document, bool createdByParser)
{
return adoptRef(new HTMLVideoElement(tagName, document, createdByParser));
RefPtr<HTMLVideoElement> videoElement(adoptRef(new HTMLVideoElement(tagName, document, createdByParser)));
videoElement->suspendIfNeeded();
return videoElement.release();
}
bool HTMLVideoElement::rendererIsNeeded(const NodeRenderingContext& context)
......
......@@ -41,6 +41,7 @@ PassRefPtr<PeerConnection> PeerConnection::create(ScriptExecutionContext* contex
RefPtr<PeerConnection> connection = adoptRef(new PeerConnection(context, serverConfiguration, signalingCallback));
connection->setPendingActivity(connection.get());
connection->scheduleInitialNegotiation();
connection->suspendIfNeeded();
return connection.release();
}
......
......@@ -102,12 +102,16 @@ Notification::~Notification()
PassRefPtr<Notification> Notification::create(const KURL& url, ScriptExecutionContext* context, ExceptionCode& ec, PassRefPtr<NotificationCenter> provider)
{
return adoptRef(new Notification(url, context, ec, provider));
RefPtr<Notification> notification(adoptRef(new Notification(url, context, ec, provider)));
notification->suspendIfNeeded();
return notification.release();
}
PassRefPtr<Notification> Notification::create(const NotificationContents& contents, ScriptExecutionContext* context, ExceptionCode& ec, PassRefPtr<NotificationCenter> provider)
{
return adoptRef(new Notification(contents, context, ec, provider));
RefPtr<Notification> notification(adoptRef(new Notification(contents, context, ec, provider)));
notification->suspendIfNeeded();
return notification.release();
}
const AtomicString& Notification::interfaceName() const
......
......@@ -41,6 +41,13 @@
namespace WebCore {
PassRefPtr<NotificationCenter> NotificationCenter::create(ScriptExecutionContext* context, NotificationPresenter* presenter)
{
RefPtr<NotificationCenter> notificationCenter(adoptRef(new NotificationCenter(context, presenter)));
notificationCenter->suspendIfNeeded();
return notificationCenter.release();
}
NotificationCenter::NotificationCenter(ScriptExecutionContext* context, NotificationPresenter* presenter)
: ActiveDOMObject(context, this)
, m_notificationPresenter(presenter) {}
......
......@@ -50,7 +50,7 @@ class VoidCallback;
class NotificationCenter : public RefCounted<NotificationCenter>, public ActiveDOMObject {
public:
static PassRefPtr<NotificationCenter> create(ScriptExecutionContext* context, NotificationPresenter* presenter) { return adoptRef(new NotificationCenter(context, presenter)); }
static PassRefPtr<NotificationCenter> create(ScriptExecutionContext*, NotificationPresenter*);
PassRefPtr<Notification> createHTMLNotification(const String& URI, ExceptionCode& ec)
{
......
......@@ -96,6 +96,7 @@ int DOMTimer::install(ScriptExecutionContext* context, PassOwnPtr<ScheduledActio
// or if it is a one-time timer and it has fired (DOMTimer::fired).
DOMTimer* timer = new DOMTimer(context, action, timeout, singleShot);
timer->suspendIfNeeded();
InspectorInstrumentation::didInstallTimer(context, timer->m_timeoutId, timeout, singleShot);
return timer->m_timeoutId;
......@@ -118,7 +119,7 @@ void DOMTimer::fired()
{
ScriptExecutionContext* context = scriptExecutionContext();
timerNestingLevel = m_nestingLevel;
ASSERT(!context->activeDOMObjectsAreSuspended());
UserGestureIndicator gestureIndicator(m_shouldForwardUserGesture ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
// Only the first execution of a multi-shot timer should get an affirmative user gesture indicator.
......
......@@ -98,6 +98,7 @@ PassRefPtr<EventSource> EventSource::create(ScriptExecutionContext* context, con
source->setPendingActivity(source.get());
source->connect();
source->suspendIfNeeded();
return source.release();
}
......
......@@ -35,8 +35,8 @@ SuspendableTimer::SuspendableTimer(ScriptExecutionContext* context)
: ActiveDOMObject(context, this)
, m_nextFireInterval(0)
, m_repeatInterval(0)
#if !ASSERT_DISABLED
, m_active(false)
#if !ASSERT_DISABLED
, m_suspended(false)
#endif
{
......
......@@ -50,7 +50,9 @@ namespace WebCore {
PassRefPtr<IDBDatabase> IDBDatabase::create(ScriptExecutionContext* context, PassRefPtr<IDBDatabaseBackendInterface> database)
{
return adoptRef(new IDBDatabase(context, database));
RefPtr<IDBDatabase> idbDatabase(adoptRef(new IDBDatabase(context, database)));
idbDatabase->suspendIfNeeded();
return idbDatabase.release();
}
IDBDatabase::IDBDatabase(ScriptExecutionContext* context, PassRefPtr<IDBDatabaseBackendInterface> backend)
......