From be858b8d9f421fbcc32ab85b5c6ee43fb2c3eac2 Mon Sep 17 00:00:00 2001 From: "commit-queue@webkit.org" Date: Wed, 7 Dec 2011 23:41:21 +0000 Subject: [PATCH] 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 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): git-svn-id: https://svn.webkit.org/repository/webkit/trunk@102278 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- ManualTests/database-callback-deferred.html | 17 +++++++++ Source/WebCore/ChangeLog | 25 +++++++++++++ Source/WebCore/dom/Document.cpp | 51 +++++++++++++++++++++++---- Source/WebCore/dom/Document.h | 12 ++++++- Source/WebCore/page/PageGroupLoadDeferrer.cpp | 18 +++------- 5 files changed, 102 insertions(+), 21 deletions(-) create mode 100644 ManualTests/database-callback-deferred.html diff --git a/ManualTests/database-callback-deferred.html b/ManualTests/database-callback-deferred.html new file mode 100644 index 0000000..cf3d03a --- /dev/null +++ b/ManualTests/database-callback-deferred.html @@ -0,0 +1,17 @@ + + + +

Wait...

+ + diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog index 8f06fd8..26a3a50 100755 --- a/Source/WebCore/ChangeLog +++ b/Source/WebCore/ChangeLog @@ -1,3 +1,28 @@ +2011-12-07 Yong Li + + 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 RenderObject::style(): Inline early-return condition. diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp index 4e15f61..f23c2e6 100644 --- a/Source/WebCore/dom/Document.cpp +++ b/Source/WebCore/dom/Document.cpp @@ -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 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML) , m_writeRecursionIsTooDeep(false) , m_writeRecursionDepth(0) , m_wheelEventHandlerCount(0) + , m_pendingTasksTimer(this, &Document::pendingTasksTimerFired) { m_document = this; @@ -4704,22 +4706,59 @@ public: OwnPtr task; }; -static void performTask(void* ctx) +void Document::didReceiveTask(void* untypedContext) { ASSERT(isMainThread()); - PerformTaskContext* context = reinterpret_cast(ctx); + OwnPtr context = adoptPtr(static_cast(untypedContext)); ASSERT(context); - if (Document* document = context->documentReference->document()) - context->task->performTask(document); + Document* document = context->documentReference->document(); + if (!document) + return; + + Page* page = document->page(); + if ((page && page->defersLoading()) || !document->m_pendingTasks.isEmpty()) { + document->m_pendingTasks.append(context->task.release()); + return; + } - delete context; + context->task->performTask(document); } void Document::postTask(PassOwnPtr task) { - callOnMainThread(performTask, new PerformTaskContext(m_weakReference, task)); + callOnMainThread(didReceiveTask, new PerformTaskContext(m_weakReference, task)); +} + +void Document::pendingTasksTimerFired(Timer*) +{ + while (!m_pendingTasks.isEmpty()) { + OwnPtr 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() diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h index c9a7f40..51ca8b9 100644 --- a/Source/WebCore/dom/Document.h +++ b/Source/WebCore/dom/Document.h @@ -1114,7 +1114,7 @@ public: unsigned wheelEventHandlerCount() const { return m_wheelEventHandlerCount; } void didAddWheelEventHandler(); void didRemoveWheelEventHandler(); - + bool visualUpdatesAllowed() const; #if ENABLE(MICRODATA) @@ -1124,6 +1124,9 @@ public: bool isInDocumentWrite() { return m_writeRecursionDepth > 0; } + void suspendScheduledTasks(); + void resumeScheduledTasks(); + protected: Document(Frame*, const KURL&, bool isXHTML, bool isHTML); @@ -1171,6 +1174,10 @@ private: void loadEventDelayTimerFired(Timer*); + void pendingTasksTimerFired(Timer*); + + static void didReceiveTask(void*); + #if ENABLE(PAGE_VISIBILITY_API) PageVisibilityState visibilityState() const; #endif @@ -1433,6 +1440,9 @@ private: #if ENABLE(REQUEST_ANIMATION_FRAME) OwnPtr m_scriptedAnimationController; #endif + + Timer m_pendingTasksTimer; + Vector > m_pendingTasks; }; // Put these methods here, because they require the Document definition, but we really want to inline them. diff --git a/Source/WebCore/page/PageGroupLoadDeferrer.cpp b/Source/WebCore/page/PageGroupLoadDeferrer.cpp index 50b32bc..e85d40e 100644 --- a/Source/WebCore/page/PageGroupLoadDeferrer.cpp +++ b/Source/WebCore/page/PageGroupLoadDeferrer.cpp @@ -48,13 +48,8 @@ PageGroupLoadDeferrer::PageGroupLoadDeferrer(Page* page, bool deferSelf) // 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 @@ PageGroupLoadDeferrer::~PageGroupLoadDeferrer() 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(); } } } -- 1.8.3.1