Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / indexeddb / IDBRequest.cpp
index 2d893cf..07bc48a 100644 (file)
 #include "config.h"
 #include "modules/indexeddb/IDBRequest.h"
 
-#include "bindings/v8/ExceptionState.h"
-#include "bindings/v8/ExceptionStatePlaceholder.h"
-#include "bindings/v8/IDBBindingUtilities.h"
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/ExceptionStatePlaceholder.h"
+#include "bindings/modules/v8/IDBBindingUtilities.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/events/EventQueue.h"
+#include "modules/IndexedDBNames.h"
 #include "modules/indexeddb/IDBCursorWithValue.h"
 #include "modules/indexeddb/IDBDatabase.h"
 #include "modules/indexeddb/IDBEventDispatcher.h"
 #include "modules/indexeddb/IDBTracing.h"
 #include "platform/SharedBuffer.h"
+#include "public/platform/WebBlobInfo.h"
 
-namespace WebCore {
+using blink::WebIDBCursor;
 
-PassRefPtr<IDBRequest> IDBRequest::create(ExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransaction* transaction)
+namespace blink {
+
+IDBRequest* IDBRequest::create(ScriptState* scriptState, IDBAny* source, IDBTransaction* transaction)
 {
-    RefPtr<IDBRequest> request(adoptRef(new IDBRequest(context, source, transaction)));
+    IDBRequest* request = adoptRefCountedGarbageCollectedWillBeNoop(new IDBRequest(scriptState, source, transaction));
     request->suspendIfNeeded();
     // Requests associated with IDBFactory (open/deleteDatabase/getDatabaseNames) are not associated with transactions.
     if (transaction)
-        transaction->registerRequest(request.get());
-    return request.release();
+        transaction->registerRequest(request);
+    return request;
 }
 
-IDBRequest::IDBRequest(ExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransaction* transaction)
-    : ActiveDOMObject(context)
+IDBRequest::IDBRequest(ScriptState* scriptState, IDBAny* source, IDBTransaction* transaction)
+    : ActiveDOMObject(scriptState->executionContext())
     , m_contextStopped(false)
     , m_transaction(transaction)
     , m_readyState(PENDING)
     , m_requestAborted(false)
+    , m_scriptState(scriptState)
     , m_source(source)
     , m_hasPendingActivity(true)
     , m_cursorType(IndexedDB::CursorKeyAndValue)
-    , m_cursorDirection(IndexedDB::CursorNext)
-    , m_pendingCursor(0)
+    , m_cursorDirection(WebIDBCursorDirectionNext)
+    , m_pendingCursor(nullptr)
     , m_didFireUpgradeNeededEvent(false)
     , m_preventPropagation(false)
     , m_resultDirty(true)
-    , m_requestState(context)
 {
     ScriptWrappable::init(this);
 }
@@ -74,6 +78,22 @@ IDBRequest::IDBRequest(ExecutionContext* context, PassRefPtr<IDBAny> source, IDB
 IDBRequest::~IDBRequest()
 {
     ASSERT(m_readyState == DONE || m_readyState == EarlyDeath || !executionContext());
+    handleBlobAcks();
+}
+
+void IDBRequest::trace(Visitor* visitor)
+{
+    visitor->trace(m_transaction);
+    visitor->trace(m_source);
+    visitor->trace(m_result);
+    visitor->trace(m_error);
+#if ENABLE(OILPAN)
+    visitor->trace(m_enqueuedEvents);
+#endif
+    visitor->trace(m_pendingCursor);
+    visitor->trace(m_cursorKey);
+    visitor->trace(m_cursorPrimaryKey);
+    EventTargetWithInlineData::trace(visitor);
 }
 
 ScriptValue IDBRequest::result(ExceptionState& exceptionState)
@@ -82,35 +102,39 @@ ScriptValue IDBRequest::result(ExceptionState& exceptionState)
         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::requestNotFinishedErrorMessage);
         return ScriptValue();
     }
+    if (m_contextStopped || !executionContext())
+        return ScriptValue();
     m_resultDirty = false;
-    return idbAnyToScriptValue(&m_requestState, m_result);
+    ScriptValue value = idbAnyToScriptValue(m_scriptState.get(), m_result);
+    handleBlobAcks();
+    return value;
 }
 
-PassRefPtr<DOMError> IDBRequest::error(ExceptionState& exceptionState) const
+PassRefPtrWillBeRawPtr<DOMError> IDBRequest::error(ExceptionState& exceptionState) const
 {
     if (m_readyState != DONE) {
         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::requestNotFinishedErrorMessage);
-        return 0;
+        return nullptr;
     }
     return m_error;
 }
 
-ScriptValue IDBRequest::source(ExecutionContext* context) const
+ScriptValue IDBRequest::source() const
 {
-    DOMRequestState requestState(context);
-    return idbAnyToScriptValue(&requestState, m_source);
+    if (m_contextStopped || !executionContext())
+        return ScriptValue();
+
+    return idbAnyToScriptValue(m_scriptState.get(), m_source);
 }
 
 const String& IDBRequest::readyState() const
 {
     ASSERT(m_readyState == PENDING || m_readyState == DONE);
-    DEFINE_STATIC_LOCAL(AtomicString, pending, ("pending", AtomicString::ConstructFromLiteral));
-    DEFINE_STATIC_LOCAL(AtomicString, done, ("done", AtomicString::ConstructFromLiteral));
 
     if (m_readyState == PENDING)
-        return pending;
+        return IndexedDBNames::pending;
 
-    return done;
+    return IndexedDBNames::done;
 }
 
 void IDBRequest::abort()
@@ -122,9 +146,6 @@ void IDBRequest::abort()
     if (m_readyState == DONE)
         return;
 
-    // Enqueued events may be the only reference to this object.
-    RefPtr<IDBRequest> self(this);
-
     EventQueue* eventQueue = executionContext()->eventQueue();
     for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
         bool removed = eventQueue->cancelEvent(m_enqueuedEvents[i].get());
@@ -138,7 +159,7 @@ void IDBRequest::abort()
     m_requestAborted = true;
 }
 
-void IDBRequest::setCursorDetails(IndexedDB::CursorType cursorType, IndexedDB::CursorDirection direction)
+void IDBRequest::setCursorDetails(IndexedDB::CursorType cursorType, WebIDBCursorDirection direction)
 {
     ASSERT(m_readyState == PENDING);
     ASSERT(!m_pendingCursor);
@@ -146,7 +167,7 @@ void IDBRequest::setCursorDetails(IndexedDB::CursorType cursorType, IndexedDB::C
     m_cursorDirection = direction;
 }
 
-void IDBRequest::setPendingCursor(PassRefPtr<IDBCursor> cursor)
+void IDBRequest::setPendingCursor(IDBCursor* cursor)
 {
     ASSERT(m_readyState == DONE);
     ASSERT(executionContext());
@@ -156,7 +177,7 @@ void IDBRequest::setPendingCursor(PassRefPtr<IDBCursor> cursor)
 
     m_hasPendingActivity = true;
     m_pendingCursor = cursor;
-    setResult(PassRefPtr<IDBAny>(0));
+    setResult(0);
     m_readyState = PENDING;
     m_error.clear();
     m_transaction->registerRequest(this);
@@ -173,28 +194,24 @@ IDBCursor* IDBRequest::getResultCursor() const
     return 0;
 }
 
-void IDBRequest::setResultCursor(PassRefPtr<IDBCursor> cursor, PassRefPtr<IDBKey> key, PassRefPtr<IDBKey> primaryKey, PassRefPtr<SharedBuffer> value)
+void IDBRequest::setResultCursor(IDBCursor* cursor, IDBKey* key, IDBKey* primaryKey, PassRefPtr<SharedBuffer> value, PassOwnPtr<Vector<WebBlobInfo> > blobInfo)
 {
     ASSERT(m_readyState == PENDING);
     m_cursorKey = key;
     m_cursorPrimaryKey = primaryKey;
     m_cursorValue = value;
+    ASSERT(!m_blobInfo.get());
+    m_blobInfo = blobInfo;
 
     onSuccessInternal(IDBAny::create(cursor));
 }
 
-void IDBRequest::checkForReferenceCycle()
+void IDBRequest::handleBlobAcks()
 {
-    // If this request and its cursor have the only references
-    // to each other, then explicitly break the cycle.
-    IDBCursor* cursor = getResultCursor();
-    if (!cursor || cursor->request() != this)
-        return;
-
-    if (!hasOneRef() || !cursor->hasOneRef())
-        return;
-
-    m_result.clear();
+    if (m_blobInfo.get() && m_blobInfo->size()) {
+        m_transaction->db()->ackReceivedBlobs(m_blobInfo.get());
+        m_blobInfo.clear();
+    }
 }
 
 bool IDBRequest::shouldEnqueueEvent() const
@@ -209,13 +226,14 @@ bool IDBRequest::shouldEnqueueEvent() const
     return true;
 }
 
-void IDBRequest::onError(PassRefPtr<DOMError> error)
+void IDBRequest::onError(PassRefPtrWillBeRawPtr<DOMError> error)
 {
     IDB_TRACE("IDBRequest::onError()");
     if (!shouldEnqueueEvent())
         return;
 
     m_error = error;
+    setResult(IDBAny::createUndefined());
     m_pendingCursor.clear();
     enqueueEvent(Event::createCancelableBubble(EventTypeNames::error));
 }
@@ -226,20 +244,20 @@ void IDBRequest::onSuccess(const Vector<String>& stringList)
     if (!shouldEnqueueEvent())
         return;
 
-    RefPtr<DOMStringList> domStringList = DOMStringList::create();
+    RefPtrWillBeRawPtr<DOMStringList> domStringList = DOMStringList::create();
     for (size_t i = 0; i < stringList.size(); ++i)
         domStringList->append(stringList[i]);
     onSuccessInternal(IDBAny::create(domStringList.release()));
 }
 
-void IDBRequest::onSuccess(PassOwnPtr<blink::WebIDBCursor> backend, PassRefPtr<IDBKey> key, PassRefPtr<IDBKey> primaryKey, PassRefPtr<SharedBuffer> value)
+void IDBRequest::onSuccess(PassOwnPtr<WebIDBCursor> backend, IDBKey* key, IDBKey* primaryKey, PassRefPtr<SharedBuffer> value, PassOwnPtr<Vector<WebBlobInfo> > blobInfo)
 {
     IDB_TRACE("IDBRequest::onSuccess(IDBCursor)");
     if (!shouldEnqueueEvent())
         return;
 
     ASSERT(!m_pendingCursor);
-    RefPtr<IDBCursor> cursor;
+    IDBCursor* cursor = 0;
     switch (m_cursorType) {
     case IndexedDB::CursorKeyOnly:
         cursor = IDBCursor::create(backend, m_cursorDirection, this, m_source.get(), m_transaction.get());
@@ -250,10 +268,10 @@ void IDBRequest::onSuccess(PassOwnPtr<blink::WebIDBCursor> backend, PassRefPtr<I
     default:
         ASSERT_NOT_REACHED();
     }
-    setResultCursor(cursor, key, primaryKey, value);
+    setResultCursor(cursor, key, primaryKey, value, blobInfo);
 }
 
-void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey)
+void IDBRequest::onSuccess(IDBKey* idbKey)
 {
     IDB_TRACE("IDBRequest::onSuccess(IDBKey)");
     if (!shouldEnqueueEvent())
@@ -265,7 +283,7 @@ void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey)
         onSuccessInternal(IDBAny::createUndefined());
 }
 
-void IDBRequest::onSuccess(PassRefPtr<SharedBuffer> valueBuffer)
+void IDBRequest::onSuccess(PassRefPtr<SharedBuffer> valueBuffer, PassOwnPtr<Vector<WebBlobInfo> > blobInfo)
 {
     IDB_TRACE("IDBRequest::onSuccess(SharedBuffer)");
     if (!shouldEnqueueEvent())
@@ -274,15 +292,18 @@ void IDBRequest::onSuccess(PassRefPtr<SharedBuffer> valueBuffer)
     if (m_pendingCursor) {
         // Value should be null, signifying the end of the cursor's range.
         ASSERT(!valueBuffer.get());
+        ASSERT(!blobInfo->size());
         m_pendingCursor->close();
         m_pendingCursor.clear();
     }
 
-    onSuccessInternal(IDBAny::create(valueBuffer));
+    ASSERT(!m_blobInfo.get());
+    m_blobInfo = blobInfo;
+    onSuccessInternal(IDBAny::create(valueBuffer, m_blobInfo.get()));
 }
 
-#ifndef NDEBUG
-static PassRefPtr<IDBObjectStore> effectiveObjectStore(PassRefPtr<IDBAny> source)
+#if ENABLE(ASSERT)
+static IDBObjectStore* effectiveObjectStore(IDBAny* source)
 {
     if (source->type() == IDBAny::IDBObjectStoreType)
         return source->idbObjectStore();
@@ -294,24 +315,24 @@ static PassRefPtr<IDBObjectStore> effectiveObjectStore(PassRefPtr<IDBAny> source
 }
 #endif
 
-void IDBRequest::onSuccess(PassRefPtr<SharedBuffer> prpValueBuffer, PassRefPtr<IDBKey> prpPrimaryKey, const IDBKeyPath& keyPath)
+void IDBRequest::onSuccess(PassRefPtr<SharedBuffer> prpValueBuffer, PassOwnPtr<Vector<WebBlobInfo> > blobInfo, IDBKey* prpPrimaryKey, const IDBKeyPath& keyPath)
 {
     IDB_TRACE("IDBRequest::onSuccess(SharedBuffer, IDBKey, IDBKeyPath)");
     if (!shouldEnqueueEvent())
         return;
 
-#ifndef NDEBUG
     ASSERT(keyPath == effectiveObjectStore(m_source)->metadata().keyPath);
-#endif
 
     RefPtr<SharedBuffer> valueBuffer = prpValueBuffer;
-    RefPtr<IDBKey> primaryKey = prpPrimaryKey;
+    IDBKey* primaryKey = prpPrimaryKey;
+    ASSERT(!m_blobInfo.get());
+    m_blobInfo = blobInfo;
 
-#ifndef NDEBUG
-    assertPrimaryKeyValidOrInjectable(&m_requestState, valueBuffer, primaryKey, keyPath);
+#if ENABLE(ASSERT)
+    assertPrimaryKeyValidOrInjectable(m_scriptState.get(), valueBuffer, m_blobInfo.get(), primaryKey, keyPath);
 #endif
 
-    onSuccessInternal(IDBAny::create(valueBuffer, primaryKey, keyPath));
+    onSuccessInternal(IDBAny::create(valueBuffer, m_blobInfo.get(), primaryKey, keyPath));
 }
 
 void IDBRequest::onSuccess(int64_t value)
@@ -330,7 +351,7 @@ void IDBRequest::onSuccess()
     onSuccessInternal(IDBAny::createUndefined());
 }
 
-void IDBRequest::onSuccessInternal(PassRefPtr<IDBAny> result)
+void IDBRequest::onSuccessInternal(IDBAny* result)
 {
     ASSERT(!m_contextStopped);
     ASSERT(!m_pendingCursor);
@@ -338,20 +359,20 @@ void IDBRequest::onSuccessInternal(PassRefPtr<IDBAny> result)
     enqueueEvent(Event::create(EventTypeNames::success));
 }
 
-void IDBRequest::setResult(PassRefPtr<IDBAny> result)
+void IDBRequest::setResult(IDBAny* result)
 {
     m_result = result;
     m_resultDirty = true;
 }
 
-void IDBRequest::onSuccess(PassRefPtr<IDBKey> key, PassRefPtr<IDBKey> primaryKey, PassRefPtr<SharedBuffer> value)
+void IDBRequest::onSuccess(IDBKey* key, IDBKey* primaryKey, PassRefPtr<SharedBuffer> value, PassOwnPtr<Vector<WebBlobInfo> > blobInfo)
 {
     IDB_TRACE("IDBRequest::onSuccess(key, primaryKey, value)");
     if (!shouldEnqueueEvent())
         return;
 
     ASSERT(m_pendingCursor);
-    setResultCursor(m_pendingCursor.release(), key, primaryKey, value);
+    setResultCursor(m_pendingCursor.release(), key, primaryKey, value, blobInfo);
 }
 
 bool IDBRequest::hasPendingActivity() const
@@ -368,9 +389,6 @@ void IDBRequest::stop()
         return;
 
     m_contextStopped = true;
-    m_requestState.clear();
-
-    RefPtr<IDBRequest> protect(this);
 
     if (m_readyState == PENDING) {
         m_readyState = EarlyDeath;
@@ -381,6 +399,12 @@ void IDBRequest::stop()
     }
 
     m_enqueuedEvents.clear();
+    if (m_source)
+        m_source->contextWillBeDestroyed();
+    if (m_result)
+        m_result->contextWillBeDestroyed();
+    if (m_pendingCursor)
+        m_pendingCursor->contextWillBeDestroyed();
 }
 
 const AtomicString& IDBRequest::interfaceName() const
@@ -393,24 +417,23 @@ ExecutionContext* IDBRequest::executionContext() const
     return ActiveDOMObject::executionContext();
 }
 
-bool IDBRequest::dispatchEvent(PassRefPtr<Event> event)
+bool IDBRequest::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
 {
     IDB_TRACE("IDBRequest::dispatchEvent");
     if (m_contextStopped || !executionContext())
         return false;
-    ASSERT(m_requestState.isValid());
     ASSERT(m_readyState == PENDING);
     ASSERT(m_hasPendingActivity);
     ASSERT(m_enqueuedEvents.size());
     ASSERT(event->target() == this);
 
-    DOMRequestState::Scope scope(m_requestState);
+    ScriptState::Scope scope(m_scriptState.get());
 
     if (event->type() != EventTypeNames::blocked)
         m_readyState = DONE;
     dequeueEvent(event.get());
 
-    Vector<RefPtr<EventTarget> > targets;
+    WillBeHeapVector<RefPtrWillBeMember<EventTarget> > targets;
     targets.append(this);
     if (m_transaction && !m_preventPropagation) {
         targets.append(m_transaction);
@@ -422,11 +445,11 @@ bool IDBRequest::dispatchEvent(PassRefPtr<Event> event)
     }
 
     // Cursor properties should not be updated until the success event is being dispatched.
-    RefPtr<IDBCursor> cursorToNotify;
+    IDBCursor* cursorToNotify = 0;
     if (event->type() == EventTypeNames::success) {
         cursorToNotify = getResultCursor();
         if (cursorToNotify)
-            cursorToNotify->setValueReady(m_cursorKey.release(), m_cursorPrimaryKey.release(), m_cursorValue.release());
+            cursorToNotify->setValueReady(m_cursorKey.release(), m_cursorPrimaryKey.release(), m_cursorValue.release(), m_blobInfo.release());
     }
 
     if (event->type() == EventTypeNames::upgradeneeded) {
@@ -493,7 +516,7 @@ void IDBRequest::transactionDidFinishAndDispatch()
     m_readyState = PENDING;
 }
 
-void IDBRequest::enqueueEvent(PassRefPtr<Event> event)
+void IDBRequest::enqueueEvent(PassRefPtrWillBeRawPtr<Event> event)
 {
     ASSERT(m_readyState == PENDING || m_readyState == DONE);
 
@@ -520,4 +543,4 @@ void IDBRequest::dequeueEvent(Event* event)
     }
 }
 
-} // namespace WebCore
+} // namespace blink