Commit 3b2f2c3b authored by ap@webkit.org's avatar ap@webkit.org

2008-12-28 Dmitry Titov <dimich@chromium.org>

        Reviewed by Darin Adler.

        https://bugs.webkit.org/show_bug.cgi?id=22755
        Prepare to add create/remove timeout methods to JSWorkerContext by moving
        timer-specific code from JSDOMWindowBase to DOMTimer.
        Moved everything JS-related from DOMTimer to ScheduledAction.
        Now ScheduledAction is what it wanted to be all the time: a JS engine-specific 
        container for timer callback that knows how to invoke it.
        DOMTimer is not anymore JS-specific.

        This is mostly moving the code around. No intended functional changes.

        * bindings/js/DOMTimer.cpp:
        (WebCore::DOMTimer::DOMTimer):
        (WebCore::DOMTimer::~DOMTimer):
        (WebCore::DOMTimer::install):
        (WebCore::DOMTimer::removeById):
        (WebCore::DOMTimer::fired):
        (WebCore::DOMTimer::stop):
        * bindings/js/DOMTimer.h:
        * bindings/js/JSDOMWindowBase.cpp:
        (WebCore::JSDOMWindowBase::installTimeout):
        (WebCore::JSDOMWindowBase::removeTimeout):
        * bindings/js/JSDOMWindowBase.h:
        * bindings/js/ScheduledAction.cpp:
        (WebCore::ScheduledAction::execute):
        * bindings/js/ScheduledAction.h:
        * dom/Document.cpp:
        (WebCore::Document::addTimeout):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@39489 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 8d1101dc
2008-12-28 Dmitry Titov <dimich@chromium.org>
Reviewed by Darin Adler.
https://bugs.webkit.org/show_bug.cgi?id=22755
Prepare to add create/remove timeout methods to JSWorkerContext by moving
timer-specific code from JSDOMWindowBase to DOMTimer.
Moved everything JS-related from DOMTimer to ScheduledAction.
Now ScheduledAction is what it wanted to be all the time: a JS engine-specific
container for timer callback that knows how to invoke it.
DOMTimer is not anymore JS-specific.
This is mostly moving the code around. No intended functional changes.
* bindings/js/DOMTimer.cpp:
(WebCore::DOMTimer::DOMTimer):
(WebCore::DOMTimer::~DOMTimer):
(WebCore::DOMTimer::install):
(WebCore::DOMTimer::removeById):
(WebCore::DOMTimer::fired):
(WebCore::DOMTimer::stop):
* bindings/js/DOMTimer.h:
* bindings/js/JSDOMWindowBase.cpp:
(WebCore::JSDOMWindowBase::installTimeout):
(WebCore::JSDOMWindowBase::removeTimeout):
* bindings/js/JSDOMWindowBase.h:
* bindings/js/ScheduledAction.cpp:
(WebCore::ScheduledAction::execute):
* bindings/js/ScheduledAction.h:
* dom/Document.cpp:
(WebCore::Document::addTimeout):
2008-12-26 Zalan Bujtas <zbujtas@gmail.com>
Reviewed by Darin Adler.
......@@ -28,16 +28,22 @@
#include "DOMTimer.h"
#include "Document.h"
#include "JSDOMWindow.h"
#include "ScheduledAction.h"
#include "ScriptExecutionContext.h"
#include <runtime/JSLock.h>
#include <wtf/HashSet.h>
#include <wtf/StdLibExtras.h>
using namespace std;
namespace WebCore {
int DOMTimer::m_timerNestingLevel = 0;
static const int maxTimerNestingLevel = 5;
static const double oneMillisecond = 0.001;
static const double minTimerInterval = 0.010; // 10 milliseconds
static int timerNestingLevel = 0;
DOMTimer::DOMTimer(ScriptExecutionContext* context, ScheduledAction* action)
DOMTimer::DOMTimer(ScriptExecutionContext* context, ScheduledAction* action, int timeout, bool singleShot)
: ActiveDOMObject(context, this)
, m_action(action)
, m_nextFireInterval(0)
......@@ -50,29 +56,76 @@ DOMTimer::DOMTimer(ScriptExecutionContext* context, ScheduledAction* action)
lastUsedTimeoutId = 1;
m_timeoutId = lastUsedTimeoutId;
m_nestingLevel = m_timerNestingLevel + 1;
m_nestingLevel = timerNestingLevel + 1;
// FIXME: Move the timeout map and API to ScriptExecutionContext to be able
// to create timeouts from Workers.
ASSERT(scriptExecutionContext() && scriptExecutionContext()->isDocument());
static_cast<Document*>(scriptExecutionContext())->addTimeout(m_timeoutId, this);
double intervalMilliseconds = max(oneMillisecond, timeout * oneMillisecond);
// Use a minimum interval of 10 ms to match other browsers, but only once we've
// nested enough to notice that we're repeating.
// Faster timers might be "better", but they're incompatible.
if (intervalMilliseconds < minTimerInterval && m_nestingLevel >= maxTimerNestingLevel)
intervalMilliseconds = minTimerInterval;
if (singleShot)
startOneShot(intervalMilliseconds);
else
startRepeating(intervalMilliseconds);
}
DOMTimer::~DOMTimer()
{
if (m_action) {
JSC::JSLock lock(false);
delete m_action;
}
}
int DOMTimer::install(ScriptExecutionContext* context, ScheduledAction* action, int timeout, bool singleShot)
{
// DOMTimer constructor links the new timer into a list of ActiveDOMObjects held by the 'context'.
// The timer is deleted when context is deleted (DOMTimer::contextDestroyed) or explicitly via DOMTimer::removeById().
DOMTimer* timer = new DOMTimer(context, action, timeout, singleShot);
return timer->m_timeoutId;
}
void DOMTimer::removeById(ScriptExecutionContext* context, int timeoutId)
{
// timeout IDs have to be positive, and 0 and -1 are unsafe to
// even look up since they are the empty and deleted value
// respectively
if (timeoutId <= 0)
return;
ASSERT(context && context->isDocument());
static_cast<Document*>(context)->removeTimeout(timeoutId);
}
void DOMTimer::fired()
{
ScriptExecutionContext* context = scriptExecutionContext();
// FIXME: make it work with Workers SEC too.
if (context->isDocument()) {
Document* document = static_cast<Document*>(context);
if (JSDOMWindow* window = toJSDOMWindow(document->frame())) {
m_timerNestingLevel = m_nestingLevel;
window->timerFired(this);
m_timerNestingLevel = 0;
timerNestingLevel = m_nestingLevel;
// Simple case for non-one-shot timers.
if (isActive()) {
if (repeatInterval() && repeatInterval() < minTimerInterval) {
m_nestingLevel++;
if (m_nestingLevel >= maxTimerNestingLevel)
augmentRepeatInterval(minTimerInterval - repeatInterval());
}
// No access to member variables after this point, it can delete the timer.
m_action->execute(context);
return;
}
// Delete timer before executing the action for one-shot timers.
ScheduledAction* action = m_action.release();
// No access to member variables after this point.
delete this;
action->execute(context);
delete action;
timerNestingLevel = 0;
}
bool DOMTimer::hasPendingActivity() const
......@@ -92,9 +145,7 @@ void DOMTimer::stop()
// Need to release JS objects potentially protected by ScheduledAction
// because they can form circular references back to the ScriptExecutionContext
// which will cause a memory leak.
JSC::JSLock lock(false);
delete m_action;
m_action = 0;
m_action.clear();
}
void DOMTimer::suspend()
......
......@@ -29,25 +29,19 @@
#include "ActiveDOMObject.h"
#include "Timer.h"
#include <wtf/OwnPtr.h>
namespace WebCore {
class JSDOMWindowBase;
class ScheduledAction;
class DOMTimer : public TimerBase, public ActiveDOMObject {
public:
// Creates a new timer with the next id and nesting level.
DOMTimer(ScriptExecutionContext*, ScheduledAction*);
virtual ~DOMTimer();
int timeoutId() const { return m_timeoutId; }
int nestingLevel() const { return m_nestingLevel; }
void setNestingLevel(int n) { m_nestingLevel = n; }
ScheduledAction* action() const { return m_action; }
ScheduledAction* takeAction() { ScheduledAction* a = m_action; m_action = 0; return a; }
// Creates a new timer owned by specified ScriptExecutionContext, starts it
// and returns its Id.
static int install(ScriptExecutionContext*, ScheduledAction*, int timeout, bool singleShot);
static void removeById(ScriptExecutionContext*, int timeoutId);
// ActiveDOMObject
virtual bool hasPendingActivity() const;
......@@ -58,12 +52,12 @@ public:
virtual void resume();
private:
DOMTimer(ScriptExecutionContext*, ScheduledAction*, int timeout, bool singleShot);
virtual void fired();
int m_timeoutId;
int m_nestingLevel;
ScheduledAction* m_action;
static int m_timerNestingLevel;
OwnPtr<ScheduledAction> m_action;
double m_nextFireInterval;
double m_repeatInterval;
};
......
......@@ -97,9 +97,6 @@ static void setJSDOMWindowBaseXSLTProcessor(ExecState*, JSObject*, JSValue*);
namespace WebCore {
const int cMaxTimerNestingLevel = 5;
const double cMinimumTimerInterval = 0.010;
////////////////////// JSDOMWindowBase Object ////////////////////////
const ClassInfo JSDOMWindowBase::s_info = { "Window", 0, &JSDOMWindowBaseTable, 0 };
......@@ -824,23 +821,7 @@ void JSDOMWindowBase::setReturnValueSlot(JSValue** slot)
int JSDOMWindowBase::installTimeout(ScheduledAction* a, int t, bool singleShot)
{
DOMTimer* timer = new DOMTimer(scriptExecutionContext(), a);
int timeoutId = timer->timeoutId();
ASSERT(d()->impl->document());
d()->impl->document()->addTimeout(timeoutId, timer);
// Use a minimum interval of 10 ms to match other browsers, but only once we've
// nested enough to notice that we're repeating.
// Faster timers might be "better", but they're incompatible.
double interval = max(0.001, t * 0.001);
if (interval < cMinimumTimerInterval && timer->nestingLevel() >= cMaxTimerNestingLevel)
interval = cMinimumTimerInterval;
if (singleShot)
timer->startOneShot(interval);
else
timer->startRepeating(interval);
return timeoutId;
return DOMTimer::install(scriptExecutionContext(), a, t, singleShot);
}
int JSDOMWindowBase::installTimeout(const UString& handler, int t, bool singleShot)
......@@ -855,45 +836,7 @@ int JSDOMWindowBase::installTimeout(ExecState* exec, JSValue* func, const ArgLis
void JSDOMWindowBase::removeTimeout(int timeoutId)
{
// timeout IDs have to be positive, and 0 and -1 are unsafe to
// even look up since they are the empty and deleted value
// respectively
if (timeoutId <= 0)
return;
ASSERT(d()->impl->document());
d()->impl->document()->removeTimeout(timeoutId);
}
void JSDOMWindowBase::timerFired(DOMTimer* timer)
{
// Simple case for non-one-shot timers.
if (timer->isActive()) {
int timeoutId = timer->timeoutId();
timer->action()->execute(shell());
// The DOMTimer object may have been deleted or replaced during execution,
// so we re-fetch it.
ASSERT(d()->impl->document());
timer = d()->impl->document()->findTimeout(timeoutId);
if (!timer)
return;
if (timer->repeatInterval() && timer->repeatInterval() < cMinimumTimerInterval) {
timer->setNestingLevel(timer->nestingLevel() + 1);
if (timer->nestingLevel() >= cMaxTimerNestingLevel)
timer->augmentRepeatInterval(cMinimumTimerInterval - timer->repeatInterval());
}
return;
}
// Delete timer before executing the action for one-shot timers.
ScheduledAction* action = timer->takeAction();
removeTimeout(timer->timeoutId());
action->execute(shell());
JSLock lock(false);
delete action;
DOMTimer::removeById(scriptExecutionContext(), timeoutId);
}
void JSDOMWindowBase::disconnectFrame()
......
......@@ -29,7 +29,6 @@
namespace WebCore {
class AtomicString;
class DOMTimer;
class DOMWindow;
class Event;
class Frame;
......@@ -68,8 +67,6 @@ namespace WebCore {
int installTimeout(JSC::ExecState*, JSC::JSValue* function, const JSC::ArgList& args, int t, bool singleShot);
void removeTimeout(int timeoutId);
void timerFired(DOMTimer*);
void clear();
// Set a place to put a dialog return value when the window is cleared.
......
......@@ -31,6 +31,7 @@
#include "JSDOMBinding.h"
#include "JSDOMWindow.h"
#include "ScriptController.h"
#include "ScriptExecutionContext.h"
#include "ScriptValue.h"
#include <runtime/JSLock.h>
......@@ -46,6 +47,15 @@ ScheduledAction::ScheduledAction(ExecState* exec, JSValue* function, const ArgLi
m_args.append((*it).jsValue(exec));
}
void ScheduledAction::execute(ScriptExecutionContext* context)
{
// FIXME: make it work with Workers SEC too.
ASSERT(context->isDocument());
Document* document = static_cast<Document*>(context);
if (JSDOMWindow* window = toJSDOMWindow(document->frame()))
execute(window->shell());
}
void ScheduledAction::execute(JSDOMWindowShell* windowShell)
{
RefPtr<Frame> frame = windowShell->window()->impl()->frame();
......
......@@ -27,6 +27,7 @@
namespace WebCore {
class JSDOMWindowShell;
class ScriptExecutionContext;
/* An action (either function or string) to be executed after a specified
* time interval, either once or repeatedly. Used for window.setTimeout()
......@@ -39,10 +40,12 @@ namespace WebCore {
: m_code(code)
{
}
void execute(ScriptExecutionContext*);
private:
void execute(JSDOMWindowShell*);
private:
JSC::ProtectedPtr<JSC::JSValue> m_function;
Vector<JSC::ProtectedPtr<JSC::JSValue> > m_args;
String m_code;
......
......@@ -4273,7 +4273,7 @@ void Document::parseDNSPrefetchControlHeader(const String& dnsPrefetchControl)
void Document::addTimeout(int timeoutId, DOMTimer* timer)
{
ASSERT(!m_timeouts.get(timeoutId));
ASSERT(!m_timeouts.contains(timeoutId));
m_timeouts.set(timeoutId, timer);
}
......
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