- Revision
- 102278
- Author
- [email protected]
- Date
- 2011-12-07 15:41:21 -0800 (Wed, 07 Dec 2011)
Log Message
Defer ScriptExecutionContext::Task's in Document when page loading is deferred.
Schedule them with timer when page loading is resumed. The tasks will be performed
in the original order. This fixes the problem that database callbacks could be missed
when page loading was deferred.
https://bugs.webkit.org/show_bug.cgi?id=49401
Patch by Yong Li <[email protected]> on 2011-12-07
Reviewed by Darin Adler.
Manual test added: ManualTests/database-callback-deferred.html.
* dom/Document.cpp:
(WebCore::Document::Document):
(WebCore::Document::didReceiveTask):
(WebCore::Document::postTask):
(WebCore::Document::pendingTasksTimerFired):
(WebCore::Document::suspendScheduledTasks):
(WebCore::Document::resumeScheduledTasks):
* dom/Document.h:
* page/PageGroupLoadDeferrer.cpp:
(WebCore::PageGroupLoadDeferrer::PageGroupLoadDeferrer):
(WebCore::PageGroupLoadDeferrer::~PageGroupLoadDeferrer):
Modified Paths
Added Paths
Diff
Added: trunk/ManualTests/database-callback-deferred.html (0 => 102278)
--- trunk/ManualTests/database-callback-deferred.html (rev 0)
+++ trunk/ManualTests/database-callback-deferred.html 2011-12-07 23:41:21 UTC (rev 102278)
@@ -0,0 +1,17 @@
+<html>
+<script>
+function test() {
+ function transactionCallback()
+ {
+ document.getElementById("result").innerHTML = "Callback was called. Test passed";
+ }
+ var db = openDatabase("DatabaseCallbackDeferred", "1.0", "", 1);
+ db.transaction(function(tx) { tx.executeSql("CREATE TABLE IF NOT EXISTS CallbackDeferredTest (randomData)", []); }, transactionCallback, transactionCallback);
+
+ alert("Wait for a few seconds and close it");
+}
+</script>
+<body _onload_="test()">
+<p id="result">Wait...</p>
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (102277 => 102278)
--- trunk/Source/WebCore/ChangeLog 2011-12-07 22:48:49 UTC (rev 102277)
+++ trunk/Source/WebCore/ChangeLog 2011-12-07 23:41:21 UTC (rev 102278)
@@ -1,3 +1,28 @@
+2011-12-07 Yong Li <[email protected]>
+
+ Defer ScriptExecutionContext::Task's in Document when page loading is deferred.
+ Schedule them with timer when page loading is resumed. The tasks will be performed
+ in the original order. This fixes the problem that database callbacks could be missed
+ when page loading was deferred.
+ https://bugs.webkit.org/show_bug.cgi?id=49401
+
+
+ Reviewed by Darin Adler.
+
+ Manual test added: ManualTests/database-callback-deferred.html.
+
+ * dom/Document.cpp:
+ (WebCore::Document::Document):
+ (WebCore::Document::didReceiveTask):
+ (WebCore::Document::postTask):
+ (WebCore::Document::pendingTasksTimerFired):
+ (WebCore::Document::suspendScheduledTasks):
+ (WebCore::Document::resumeScheduledTasks):
+ * dom/Document.h:
+ * page/PageGroupLoadDeferrer.cpp:
+ (WebCore::PageGroupLoadDeferrer::PageGroupLoadDeferrer):
+ (WebCore::PageGroupLoadDeferrer::~PageGroupLoadDeferrer):
+
2011-12-07 Andreas Kling <[email protected]>
RenderObject::style(): Inline early-return condition.
Modified: trunk/Source/WebCore/dom/Document.cpp (102277 => 102278)
--- trunk/Source/WebCore/dom/Document.cpp 2011-12-07 22:48:49 UTC (rev 102277)
+++ trunk/Source/WebCore/dom/Document.cpp 2011-12-07 23:41:21 UTC (rev 102278)
@@ -7,6 +7,7 @@
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2008, 2009, 2011 Google Inc. All rights reserved.
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -429,6 +430,7 @@
, m_writeRecursionIsTooDeep(false)
, m_writeRecursionDepth(0)
, m_wheelEventHandlerCount(0)
+ , m_pendingTasksTimer(this, &Document::pendingTasksTimerFired)
{
m_document = this;
@@ -4704,24 +4706,61 @@
OwnPtr<ScriptExecutionContext::Task> task;
};
-static void performTask(void* ctx)
+void Document::didReceiveTask(void* untypedContext)
{
ASSERT(isMainThread());
- PerformTaskContext* context = reinterpret_cast<PerformTaskContext*>(ctx);
+ OwnPtr<PerformTaskContext> context = adoptPtr(static_cast<PerformTaskContext*>(untypedContext));
ASSERT(context);
- if (Document* document = context->documentReference->document())
- context->task->performTask(document);
+ Document* document = context->documentReference->document();
+ if (!document)
+ return;
- delete context;
+ Page* page = document->page();
+ if ((page && page->defersLoading()) || !document->m_pendingTasks.isEmpty()) {
+ document->m_pendingTasks.append(context->task.release());
+ return;
+ }
+
+ context->task->performTask(document);
}
void Document::postTask(PassOwnPtr<Task> task)
{
- callOnMainThread(performTask, new PerformTaskContext(m_weakReference, task));
+ callOnMainThread(didReceiveTask, new PerformTaskContext(m_weakReference, task));
}
+void Document::pendingTasksTimerFired(Timer<Document>*)
+{
+ while (!m_pendingTasks.isEmpty()) {
+ OwnPtr<Task> task = m_pendingTasks[0].release();
+ m_pendingTasks.remove(0);
+ task->performTask(this);
+ }
+}
+
+void Document::suspendScheduledTasks()
+{
+ suspendScriptedAnimationControllerCallbacks();
+ suspendActiveDOMObjects(ActiveDOMObject::WillShowDialog);
+ scriptRunner()->suspend();
+ m_pendingTasksTimer.stop();
+ if (m_parser)
+ m_parser->suspendScheduledTasks();
+}
+
+void Document::resumeScheduledTasks()
+{
+ if (m_parser)
+ m_parser->resumeScheduledTasks();
+ if (!m_pendingTasks.isEmpty())
+ m_pendingTasksTimer.startOneShot(0);
+ scriptRunner()->resume();
+ resumeActiveDOMObjects();
+ resumeScriptedAnimationControllerCallbacks();
+}
+
void Document::suspendScriptedAnimationControllerCallbacks()
{
#if ENABLE(REQUEST_ANIMATION_FRAME)
Modified: trunk/Source/WebCore/dom/Document.h (102277 => 102278)
--- trunk/Source/WebCore/dom/Document.h 2011-12-07 22:48:49 UTC (rev 102277)
+++ trunk/Source/WebCore/dom/Document.h 2011-12-07 23:41:21 UTC (rev 102278)
@@ -1114,7 +1114,7 @@
unsigned wheelEventHandlerCount() const { return m_wheelEventHandlerCount; }
void didAddWheelEventHandler();
void didRemoveWheelEventHandler();
-
+
bool visualUpdatesAllowed() const;
#if ENABLE(MICRODATA)
@@ -1124,6 +1124,9 @@
bool isInDocumentWrite() { return m_writeRecursionDepth > 0; }
+ void suspendScheduledTasks();
+ void resumeScheduledTasks();
+
protected:
Document(Frame*, const KURL&, bool isXHTML, bool isHTML);
@@ -1171,6 +1174,10 @@
void loadEventDelayTimerFired(Timer<Document>*);
+ void pendingTasksTimerFired(Timer<Document>*);
+
+ static void didReceiveTask(void*);
+
#if ENABLE(PAGE_VISIBILITY_API)
PageVisibilityState visibilityState() const;
#endif
@@ -1433,6 +1440,9 @@
#if ENABLE(REQUEST_ANIMATION_FRAME)
OwnPtr<ScriptedAnimationController> m_scriptedAnimationController;
#endif
+
+ Timer<Document> m_pendingTasksTimer;
+ Vector<OwnPtr<Task> > m_pendingTasks;
};
// Put these methods here, because they require the Document definition, but we really want to inline them.
Modified: trunk/Source/WebCore/page/PageGroupLoadDeferrer.cpp (102277 => 102278)
--- trunk/Source/WebCore/page/PageGroupLoadDeferrer.cpp 2011-12-07 22:48:49 UTC (rev 102277)
+++ trunk/Source/WebCore/page/PageGroupLoadDeferrer.cpp 2011-12-07 23:41:21 UTC (rev 102278)
@@ -48,13 +48,8 @@
// windows or sheets, which is exactly when PageGroupLoadDeferrer is used.
// NOTE: if PageGroupLoadDeferrer is ever used for tasks other than showing a modal window or sheet,
// the constructor will need to take a ActiveDOMObject::ReasonForSuspension.
- for (Frame* frame = otherPage->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
- frame->document()->suspendScriptedAnimationControllerCallbacks();
- frame->document()->suspendActiveDOMObjects(ActiveDOMObject::WillShowDialog);
- frame->document()->scriptRunner()->suspend();
- if (DocumentParser* parser = frame->document()->parser())
- parser->suspendScheduledTasks();
- }
+ for (Frame* frame = otherPage->mainFrame(); frame; frame = frame->tree()->traverseNext())
+ frame->document()->suspendScheduledTasks();
}
}
}
@@ -71,13 +66,8 @@
if (Page* page = m_deferredFrames[i]->page()) {
page->setDefersLoading(false);
- for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
- frame->document()->resumeActiveDOMObjects();
- frame->document()->resumeScriptedAnimationControllerCallbacks();
- frame->document()->scriptRunner()->resume();
- if (DocumentParser* parser = frame->document()->parser())
- parser->resumeScheduledTasks();
- }
+ for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext())
+ frame->document()->resumeScheduledTasks();
}
}
}