2011-02-03 Jeremy Orlow <jorlow@chromium.org>
authorjorlow@chromium.org <jorlow@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Feb 2011 19:50:24 +0000 (19:50 +0000)
committerjorlow@chromium.org <jorlow@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Feb 2011 19:50:24 +0000 (19:50 +0000)
        Reviewed by Nate Chapin.

        Refactor IDBRequest and IDBTransaction a bit
        https://bugs.webkit.org/show_bug.cgi?id=53565

        There were a lot of subtle issues with the way IDBTransaction
        and IDBRequest used to be written. This cleans a lot of them up
        and largely simplifies the logic. Using EventQueue rather than
        timers is one example of the simplification.

        * bindings/scripts/CodeGeneratorV8.pm:
        * dom/EventQueue.cpp:
        (WebCore::EventQueue::enqueueEvent):
        (WebCore::EventQueue::dispatchEvent):
        * storage/IDBCursor.cpp:
        (WebCore::IDBCursor::continueFunction):
        * storage/IDBRequest.cpp:
        (WebCore::IDBRequest::create):
        (WebCore::IDBRequest::IDBRequest):
        (WebCore::IDBRequest::resetReadyState):
        (WebCore::IDBRequest::onError):
        (WebCore::IDBRequest::onSuccess):
        (WebCore::IDBRequest::dispatchEvent):
        (WebCore::IDBRequest::enqueueEvent):
        (WebCore::IDBRequest::eventTargetData):
        (WebCore::IDBRequest::ensureEventTargetData):
        * storage/IDBRequest.h:
        (WebCore::IDBRequest::dispatchEvent):
        * storage/IDBTransaction.cpp:
        (WebCore::IDBTransaction::create):
        (WebCore::IDBTransaction::IDBTransaction):
        (WebCore::IDBTransaction::objectStore):
        (WebCore::IDBTransaction::abort):
        (WebCore::IDBTransaction::onAbort):
        (WebCore::IDBTransaction::onComplete):
        (WebCore::IDBTransaction::onTimeout):
        (WebCore::IDBTransaction::canSuspend):
        (WebCore::IDBTransaction::stop):
        (WebCore::IDBTransaction::enqueueEvent):
        (WebCore::IDBTransaction::eventTargetData):
        (WebCore::IDBTransaction::ensureEventTargetData):
        * storage/IDBTransaction.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@77650 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/bindings/scripts/CodeGeneratorV8.pm
Source/WebCore/dom/EventQueue.cpp
Source/WebCore/storage/IDBCursor.cpp
Source/WebCore/storage/IDBRequest.cpp
Source/WebCore/storage/IDBRequest.h
Source/WebCore/storage/IDBTransaction.cpp
Source/WebCore/storage/IDBTransaction.h

index c6ef466b3b8f2eafe0750f2a2ee0fb448ba48948..a77c15f675b8da2f7bb8bf4f3ea84d201e3a221f 100644 (file)
@@ -1,3 +1,48 @@
+2011-02-03  Jeremy Orlow  <jorlow@chromium.org>
+
+        Reviewed by Nate Chapin.
+
+        Refactor IDBRequest and IDBTransaction a bit
+        https://bugs.webkit.org/show_bug.cgi?id=53565
+
+        There were a lot of subtle issues with the way IDBTransaction
+        and IDBRequest used to be written. This cleans a lot of them up
+        and largely simplifies the logic. Using EventQueue rather than
+        timers is one example of the simplification.
+
+        * bindings/scripts/CodeGeneratorV8.pm:
+        * dom/EventQueue.cpp:
+        (WebCore::EventQueue::enqueueEvent):
+        (WebCore::EventQueue::dispatchEvent):
+        * storage/IDBCursor.cpp:
+        (WebCore::IDBCursor::continueFunction):
+        * storage/IDBRequest.cpp:
+        (WebCore::IDBRequest::create):
+        (WebCore::IDBRequest::IDBRequest):
+        (WebCore::IDBRequest::resetReadyState):
+        (WebCore::IDBRequest::onError):
+        (WebCore::IDBRequest::onSuccess):
+        (WebCore::IDBRequest::dispatchEvent):
+        (WebCore::IDBRequest::enqueueEvent):
+        (WebCore::IDBRequest::eventTargetData):
+        (WebCore::IDBRequest::ensureEventTargetData):
+        * storage/IDBRequest.h:
+        (WebCore::IDBRequest::dispatchEvent):
+        * storage/IDBTransaction.cpp:
+        (WebCore::IDBTransaction::create):
+        (WebCore::IDBTransaction::IDBTransaction):
+        (WebCore::IDBTransaction::objectStore):
+        (WebCore::IDBTransaction::abort):
+        (WebCore::IDBTransaction::onAbort):
+        (WebCore::IDBTransaction::onComplete):
+        (WebCore::IDBTransaction::onTimeout):
+        (WebCore::IDBTransaction::canSuspend):
+        (WebCore::IDBTransaction::stop):
+        (WebCore::IDBTransaction::enqueueEvent):
+        (WebCore::IDBTransaction::eventTargetData):
+        (WebCore::IDBTransaction::ensureEventTargetData):
+        * storage/IDBTransaction.h:
+
 2011-02-01  Jeremy Orlow  <jorlow@chromium.org>
 
         Reviewed by Nate Chapin.
index c18ef101f3fe8565389ac63abe7b1106466541c1..f3932308f40351b89b3daaea442afcba7c86459a 100644 (file)
@@ -2565,6 +2565,7 @@ sub IsActiveDomType
     return 1 if $type eq "Worker";
     return 1 if $type eq "SharedWorker";
     return 1 if $type eq "IDBRequest";
+    return 1 if $type eq "IDBTransaction";
     return 1 if $type eq "FileReader";
     return 1 if $type eq "FileWriter";
     return 0;
index a3daae64c9307fc479131032d0cffe395f48530b..5a1abe8ad15eb5cfdeae4c2bb7ce145b0025b613 100644 (file)
@@ -58,7 +58,7 @@ EventQueue::~EventQueue()
 
 void EventQueue::enqueueEvent(PassRefPtr<Event> event)
 {
-    ASSERT(event->target()->toNode() || event->target()->toDOMWindow());
+    ASSERT(event->target());
     m_queuedEvents.append(event);
     
     if (!m_pendingEventTimer->isActive())
@@ -98,7 +98,7 @@ void EventQueue::dispatchEvent(PassRefPtr<Event> event)
     else if (eventTarget->toDOMWindow())
         eventTarget->toDOMWindow()->dispatchEvent(event, 0);
     else
-        ASSERT_NOT_REACHED();
+        eventTarget->dispatchEvent(event);
 }
 
 }
index 444c109a1d56584a2346594d65b17519c285b477..4be6f4a552485954683b9168577a242b31292ce0 100644 (file)
@@ -84,7 +84,7 @@ void IDBCursor::continueFunction(PassRefPtr<IDBKey> key, ExceptionCode& ec)
     if (m_request->resetReadyState(m_transaction.get()))
         m_backend->continueFunction(key, m_request, ec);
     else
-        ASSERT_NOT_REACHED();
+        ec = IDBDatabaseException::NOT_ALLOWED_ERR;
 }
 
 PassRefPtr<IDBRequest> IDBCursor::deleteFunction(ScriptExecutionContext* context, ExceptionCode& ec)
index 157846d9e81b7d6da1a4ccf4f8ad82f0d6ae3ba3..a3a04f26ff0a921819d3269a144436bba2292442 100644 (file)
 
 #if ENABLE(INDEXED_DATABASE)
 
-#include "Event.h"
+#include "Document.h"
 #include "EventException.h"
 #include "EventListener.h"
 #include "EventNames.h"
+#include "EventQueue.h"
 #include "IDBCursor.h"
 #include "IDBDatabase.h"
 #include "IDBIndex.h"
 #include "IDBObjectStore.h"
 #include "IDBPendingTransactionMonitor.h"
 #include "IDBSuccessEvent.h"
-#include "ScriptExecutionContext.h"
 
 namespace WebCore {
 
+PassRefPtr<IDBRequest> IDBRequest::create(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransactionBackendInterface* transaction)
+{
+    return adoptRef(new IDBRequest(context, source, transaction));
+}
+
 IDBRequest::IDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransactionBackendInterface* transaction)
     : ActiveDOMObject(context, this)
     , m_source(source)
     , m_transaction(transaction)
-    , m_timer(this, &IDBRequest::timerFired)
     , m_readyState(LOADING)
 {
     if (m_transaction)
@@ -63,47 +67,53 @@ IDBRequest::~IDBRequest()
 
 bool IDBRequest::resetReadyState(IDBTransactionBackendInterface* transaction)
 {
-    ASSERT(m_readyState == DONE);
-    m_readyState = LOADING;
-    ASSERT(!m_transaction);
+    ASSERT(scriptExecutionContext());
+    if (m_readyState != DONE)
+        return false;
+
     m_transaction = transaction;
+    m_readyState = LOADING;
+
     IDBPendingTransactionMonitor::removePendingTransaction(m_transaction.get());
+
     return true;
 }
 
 void IDBRequest::onError(PassRefPtr<IDBDatabaseError> error)
 {
-    scheduleEvent(0, error);
+    enqueueEvent(IDBErrorEvent::create(m_source, *error));
 }
 
 void IDBRequest::onSuccess(PassRefPtr<IDBCursorBackendInterface> backend)
 {
-    scheduleEvent(IDBAny::create(IDBCursor::create(backend, this, m_transaction.get())), 0);
+    enqueueEvent(IDBSuccessEvent::create(m_source, IDBAny::create(IDBCursor::create(backend, this, m_transaction.get()))));
 }
 
 void IDBRequest::onSuccess(PassRefPtr<IDBDatabaseBackendInterface> backend)
 {
-    scheduleEvent(IDBAny::create(IDBDatabase::create(backend)), 0);
+    enqueueEvent(IDBSuccessEvent::create(m_source, IDBAny::create(IDBDatabase::create(backend))));
 }
 
 void IDBRequest::onSuccess(PassRefPtr<IDBIndexBackendInterface> backend)
 {
-    scheduleEvent(IDBAny::create(IDBIndex::create(backend, m_transaction.get())), 0);
+    ASSERT_NOT_REACHED(); // FIXME: This method should go away.
 }
 
 void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey)
 {
-    scheduleEvent(IDBAny::create(idbKey), 0);
+    enqueueEvent(IDBSuccessEvent::create(m_source, IDBAny::create(idbKey)));
 }
 
 void IDBRequest::onSuccess(PassRefPtr<IDBObjectStoreBackendInterface> backend)
 {
-    // FIXME: This function should go away once createObjectStore is sync.
-    scheduleEvent(IDBAny::create(IDBObjectStore::create(backend, m_transaction.get())), 0);
+    ASSERT_NOT_REACHED(); // FIXME: This method should go away.
 }
 
 void IDBRequest::onSuccess(PassRefPtr<IDBTransactionBackendInterface> prpBackend)
 {
+    if (!scriptExecutionContext())
+        return;
+
     RefPtr<IDBTransactionBackendInterface> backend = prpBackend;
     // This is only used by setVersion which will always have a source that's an IDBDatabase.
     m_source->idbDatabase()->setSetVersionTransaction(backend.get());
@@ -111,12 +121,12 @@ void IDBRequest::onSuccess(PassRefPtr<IDBTransactionBackendInterface> prpBackend
     backend->setCallbacks(frontend.get());
     m_transaction = backend;
     IDBPendingTransactionMonitor::removePendingTransaction(m_transaction.get());
-    scheduleEvent(IDBAny::create(frontend.release()), 0);
+    enqueueEvent(IDBSuccessEvent::create(m_source, IDBAny::create(frontend.release())));
 }
 
 void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> serializedScriptValue)
 {
-    scheduleEvent(IDBAny::create(serializedScriptValue), 0);
+    enqueueEvent(IDBSuccessEvent::create(m_source, IDBAny::create(serializedScriptValue)));
 }
 
 ScriptExecutionContext* IDBRequest::scriptExecutionContext() const
@@ -124,76 +134,39 @@ ScriptExecutionContext* IDBRequest::scriptExecutionContext() const
     return ActiveDOMObject::scriptExecutionContext();
 }
 
-bool IDBRequest::canSuspend() const
+bool IDBRequest::dispatchEvent(PassRefPtr<Event> event)
 {
-    // IDBTransactions cannot be suspended at the moment. We therefore
-    // disallow the back/forward cache for pages that use IndexedDatabase.
-    return false;
-}
+    ASSERT(m_readyState < DONE);
+    m_readyState = DONE;
 
-EventTargetData* IDBRequest::eventTargetData()
-{
-    return &m_eventTargetData;
-}
+    bool ret = EventTarget::dispatchEvent(event);
 
-EventTargetData* IDBRequest::ensureEventTargetData()
-{
-    return &m_eventTargetData;
+    if (m_transaction)
+        m_transaction->didCompleteTaskEvents();
+
+    return ret;
 }
 
-void IDBRequest::timerFired(Timer<IDBRequest>*)
+void IDBRequest::enqueueEvent(PassRefPtr<Event> event)
 {
-    ASSERT(m_selfRef);
-    ASSERT(m_pendingEvents.size());
-    // FIXME: We should handle the stop event and stop any timers when we see it. We can then assert here that scriptExecutionContext is non-null.
-
-    // We need to keep self-referencing ourself, otherwise it's possible we'll be deleted.
-    // But in some cases, suspend() could be called while we're dispatching an event, so we
-    // need to make sure that resume() doesn't re-start the timer based on m_selfRef being set.
-    RefPtr<IDBRequest> selfRef = m_selfRef.release();
-
-    // readyStateReset can be called synchronously while we're dispatching the event.
-    RefPtr<IDBTransactionBackendInterface> transaction = m_transaction;
-    m_transaction.clear();
-
-    Vector<PendingEvent> pendingEvents;
-    pendingEvents.swap(m_pendingEvents);
-    for (size_t i = 0; i < pendingEvents.size(); ++i) {
-        // It's possible we've navigated in which case we'll crash.
-        if (!scriptExecutionContext())
-            return;
+    ASSERT(m_readyState < DONE);
+    if (!scriptExecutionContext())
+        return;
 
-        if (pendingEvents[i].m_error) {
-            ASSERT(!pendingEvents[i].m_result);
-            dispatchEvent(IDBErrorEvent::create(m_source, *pendingEvents[i].m_error));
-        } else {
-            ASSERT(pendingEvents[i].m_result->type() != IDBAny::UndefinedType);
-            dispatchEvent(IDBSuccessEvent::create(m_source, pendingEvents[i].m_result));
-        }
-    }
-    if (transaction) {
-        // Now that we processed all pending events, let the transaction monitor check if
-        // it can commit the current transaction or if there's anything new pending.
-        // FIXME: Handle the workers case.
-        transaction->didCompleteTaskEvents();
-    }
+    ASSERT(scriptExecutionContext()->isDocument());
+    EventQueue* eventQueue = static_cast<Document*>(scriptExecutionContext())->eventQueue();
+    event->setTarget(this);
+    eventQueue->enqueueEvent(event);
 }
 
-void IDBRequest::scheduleEvent(PassRefPtr<IDBAny> result, PassRefPtr<IDBDatabaseError> error)
+EventTargetData* IDBRequest::eventTargetData()
 {
-    ASSERT(m_readyState < DONE);
-    ASSERT(!!m_selfRef == m_timer.isActive());
-
-    PendingEvent pendingEvent;
-    pendingEvent.m_result = result;
-    pendingEvent.m_error = error;
-    m_pendingEvents.append(pendingEvent);
+    return &m_eventTargetData;
+}
 
-    m_readyState = DONE;
-    if (!m_timer.isActive()) {
-        m_selfRef = this;
-        m_timer.startOneShot(0);
-    }
+EventTargetData* IDBRequest::ensureEventTargetData()
+{
+    return &m_eventTargetData;
 }
 
 } // namespace WebCore
index 548800dbd29ccfb4b1864fc0c3ef701731cb929f..7a049eea5d67b4427e9d2730214149e595b5fd9f 100644 (file)
 #if ENABLE(INDEXED_DATABASE)
 
 #include "ActiveDOMObject.h"
+#include "Event.h"
 #include "EventListener.h"
 #include "EventNames.h"
 #include "EventTarget.h"
 #include "IDBAny.h"
 #include "IDBCallbacks.h"
-#include "Timer.h"
-#include <wtf/Vector.h>
 
 namespace WebCore {
 
@@ -46,7 +45,7 @@ class IDBTransactionBackendInterface;
 
 class IDBRequest : public IDBCallbacks, public EventTarget, public ActiveDOMObject {
 public:
-    static PassRefPtr<IDBRequest> create(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransactionBackendInterface* transaction) { return adoptRef(new IDBRequest(context, source, transaction)); }
+    static PassRefPtr<IDBRequest> create(ScriptExecutionContext*, PassRefPtr<IDBAny> source, IDBTransactionBackendInterface*);
     virtual ~IDBRequest();
 
     // Defined in the IDL
@@ -72,10 +71,9 @@ public:
 
     // EventTarget
     virtual IDBRequest* toIDBRequest() { return this; }
-
-    // ActiveDOMObject
     virtual ScriptExecutionContext* scriptExecutionContext() const;
-    virtual bool canSuspend() const;
+    virtual bool dispatchEvent(PassRefPtr<Event>);
+    bool dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec) { return EventTarget::dispatchEvent(event, ec); }
 
     using ThreadSafeShared<IDBCallbacks>::ref;
     using ThreadSafeShared<IDBCallbacks>::deref;
@@ -83,8 +81,7 @@ public:
 private:
     IDBRequest(ScriptExecutionContext*, PassRefPtr<IDBAny> source, IDBTransactionBackendInterface* transaction);
 
-    void timerFired(Timer<IDBRequest>*);
-    void scheduleEvent(PassRefPtr<IDBAny> result, PassRefPtr<IDBDatabaseError>);
+    void enqueueEvent(PassRefPtr<Event>);
 
     // EventTarget
     virtual void refEventTarget() { ref(); }
@@ -95,17 +92,8 @@ private:
     RefPtr<IDBAny> m_source;
     RefPtr<IDBTransactionBackendInterface> m_transaction;
 
-    struct PendingEvent {
-        RefPtr<IDBAny> m_result;
-        RefPtr<IDBDatabaseError> m_error;
-    };
-    Vector<PendingEvent> m_pendingEvents;
-
-    // Used to fire events asynchronously.
-    Timer<IDBRequest> m_timer;
-    RefPtr<IDBRequest> m_selfRef; // This is set to us iff there's an event pending.
-
     ReadyState m_readyState;
+
     EventTargetData m_eventTargetData;
 };
 
index c0910c73bb98d89fdbd386998202cd0976826eae..38ebc755d7e7069ff01936a31669c854e92bc7a6 100644 (file)
@@ -28,8 +28,9 @@
 
 #if ENABLE(INDEXED_DATABASE)
 
-#include "Event.h"
+#include "Document.h"
 #include "EventException.h"
+#include "EventQueue.h"
 #include "IDBAbortEvent.h"
 #include "IDBCompleteEvent.h"
 #include "IDBDatabase.h"
 #include "IDBObjectStore.h"
 #include "IDBObjectStoreBackendInterface.h"
 #include "IDBPendingTransactionMonitor.h"
-#include "ScriptExecutionContext.h"
 
 namespace WebCore {
 
+PassRefPtr<IDBTransaction> IDBTransaction::create(ScriptExecutionContext* context, PassRefPtr<IDBTransactionBackendInterface> backend, IDBDatabase* db)
+{ 
+    return adoptRef(new IDBTransaction(context, backend, db));
+}
+
 IDBTransaction::IDBTransaction(ScriptExecutionContext* context, PassRefPtr<IDBTransactionBackendInterface> backend, IDBDatabase* db)
     : ActiveDOMObject(context, this)
     , m_backend(backend)
     , m_database(db)
     , m_mode(m_backend->mode())
-    , m_onAbortTimer(this, &IDBTransaction::onAbortTimerFired)
-    , m_onCompleteTimer(this, &IDBTransaction::onCompleteTimerFired)
 {
     IDBPendingTransactionMonitor::addPendingTransaction(m_backend.get());
 }
@@ -69,6 +72,7 @@ IDBDatabase* IDBTransaction::db()
 
 PassRefPtr<IDBObjectStore> IDBTransaction::objectStore(const String& name, ExceptionCode& ec)
 {
+    // FIXME: It'd be better (because it's more deterministic) if we didn't start throwing this until the complete or abort event fires.
     if (!m_backend) {
         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
         return 0;
@@ -84,6 +88,7 @@ PassRefPtr<IDBObjectStore> IDBTransaction::objectStore(const String& name, Excep
 
 void IDBTransaction::abort()
 {
+    RefPtr<IDBTransaction> selfRef = this;
     if (m_backend)
         m_backend->abort();
 }
@@ -95,58 +100,46 @@ ScriptExecutionContext* IDBTransaction::scriptExecutionContext() const
 
 void IDBTransaction::onAbort()
 {
-    ASSERT(!m_onAbortTimer.isActive());
-    ASSERT(!m_onCompleteTimer.isActive());
-    m_selfRef = this;
-    m_onAbortTimer.startOneShot(0);
-    m_backend.clear(); // Release the backend as it holds a (circular) reference back to us.
+    enqueueEvent(IDBAbortEvent::create());
 }
 
 void IDBTransaction::onComplete()
 {
-    ASSERT(!m_onAbortTimer.isActive());
-    ASSERT(!m_onCompleteTimer.isActive());
-    m_selfRef = this;
-    m_onCompleteTimer.startOneShot(0);
-    m_backend.clear(); // Release the backend as it holds a (circular) reference back to us.
+    enqueueEvent(IDBCompleteEvent::create());
 }
 
 bool IDBTransaction::canSuspend() const
 {
-    // We may be in the middle of a transaction so we cannot suspend our object.
-    // Instead, we simply don't allow the owner page to go into the back/forward cache.
-    return false;
+    return !m_backend;
 }
 
 void IDBTransaction::contextDestroyed()
 {
     ActiveDOMObject::contextDestroyed();
+
+    RefPtr<IDBTransaction> selfRef = this;
     if (m_backend)
         m_backend->abort();
+    m_backend.clear();
 }
 
-EventTargetData* IDBTransaction::eventTargetData()
+void IDBTransaction::enqueueEvent(PassRefPtr<Event> event)
 {
-    return &m_eventTargetData;
-}
+    if (!scriptExecutionContext())
+        return;
 
-EventTargetData* IDBTransaction::ensureEventTargetData()
-{
-    return &m_eventTargetData;
-}
-
-void IDBTransaction::onAbortTimerFired(Timer<IDBTransaction>* transaction)
-{
-    ASSERT(m_selfRef);
-    RefPtr<IDBTransaction> selfRef = m_selfRef.release();
-    dispatchEvent(IDBAbortEvent::create());
+    ASSERT(m_backend);
+    m_backend.clear();
+    
+    ASSERT(scriptExecutionContext()->isDocument());
+    EventQueue* eventQueue = static_cast<Document*>(scriptExecutionContext())->eventQueue();
+    event->setTarget(this);
+    eventQueue->enqueueEvent(event);
 }
 
-void IDBTransaction::onCompleteTimerFired(Timer<IDBTransaction>* transaction)
+EventTargetData* IDBTransaction::eventTargetData()
 {
-    ASSERT(m_selfRef);
-    RefPtr<IDBTransaction> selfRef = m_selfRef.release();
-    dispatchEvent(IDBCompleteEvent::create());
+    return &m_eventTargetData;
 }
 
 }
index f4cb664bc8d02ccf007717bd6b7d282b96f32c16..7a62e29b7f83b289f8ada9b7cf879224cccc5290 100644 (file)
@@ -35,7 +35,6 @@
 #include "EventTarget.h"
 #include "IDBTransactionBackendInterface.h"
 #include "IDBTransactionCallbacks.h"
-#include "Timer.h"
 #include <wtf/RefCounted.h>
 
 namespace WebCore {
@@ -45,10 +44,7 @@ class IDBObjectStore;
 
 class IDBTransaction : public IDBTransactionCallbacks, public EventTarget, public ActiveDOMObject {
 public:
-    static PassRefPtr<IDBTransaction> create(ScriptExecutionContext* context, PassRefPtr<IDBTransactionBackendInterface> backend, IDBDatabase* db)
-    { 
-        return adoptRef(new IDBTransaction(context, backend, db)); 
-    }
+    static PassRefPtr<IDBTransaction> create(ScriptExecutionContext*, PassRefPtr<IDBTransactionBackendInterface>, IDBDatabase*);
     virtual ~IDBTransaction();
 
     enum Mode {
@@ -71,9 +67,9 @@ public:
 
     // EventTarget
     virtual IDBTransaction* toIDBTransaction() { return this; }
+    virtual ScriptExecutionContext* scriptExecutionContext() const;
 
     // ActiveDOMObject
-    virtual ScriptExecutionContext* scriptExecutionContext() const;
     virtual bool canSuspend() const;
     virtual void contextDestroyed();
 
@@ -83,23 +79,19 @@ public:
 private:
     IDBTransaction(ScriptExecutionContext*, PassRefPtr<IDBTransactionBackendInterface>, IDBDatabase*);
 
+    void enqueueEvent(PassRefPtr<Event>);
+
     // EventTarget
     virtual void refEventTarget() { ref(); }
     virtual void derefEventTarget() { deref(); }
     virtual EventTargetData* eventTargetData();
     virtual EventTargetData* ensureEventTargetData();
 
-    void onAbortTimerFired(Timer<IDBTransaction>*);
-    void onCompleteTimerFired(Timer<IDBTransaction>*);
-
-    EventTargetData m_eventTargetData;
     RefPtr<IDBTransactionBackendInterface> m_backend;
     RefPtr<IDBDatabase> m_database;
     unsigned short m_mode;
 
-    Timer<IDBTransaction> m_onAbortTimer;
-    Timer<IDBTransaction> m_onCompleteTimer;
-    RefPtr<IDBTransaction> m_selfRef; // This is set to us iff there's an event pending.
+    EventTargetData m_eventTargetData;
 };
 
 } // namespace WebCore