• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "config.h"
30 #include "modules/indexeddb/IDBRequest.h"
31 
32 #include "bindings/core/v8/ExceptionState.h"
33 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
34 #include "bindings/modules/v8/IDBBindingUtilities.h"
35 #include "core/dom/ExecutionContext.h"
36 #include "core/events/EventQueue.h"
37 #include "modules/IndexedDBNames.h"
38 #include "modules/indexeddb/IDBCursorWithValue.h"
39 #include "modules/indexeddb/IDBDatabase.h"
40 #include "modules/indexeddb/IDBEventDispatcher.h"
41 #include "modules/indexeddb/IDBPendingTransactionMonitor.h"
42 #include "modules/indexeddb/IDBTracing.h"
43 #include "platform/SharedBuffer.h"
44 #include "public/platform/WebBlobInfo.h"
45 
46 using blink::WebIDBCursor;
47 
48 namespace blink {
49 
create(ScriptState * scriptState,IDBAny * source,IDBTransaction * transaction)50 IDBRequest* IDBRequest::create(ScriptState* scriptState, IDBAny* source, IDBTransaction* transaction)
51 {
52     IDBRequest* request = adoptRefCountedGarbageCollectedWillBeNoop(new IDBRequest(scriptState, source, transaction));
53     request->suspendIfNeeded();
54     // Requests associated with IDBFactory (open/deleteDatabase/getDatabaseNames) are not associated with transactions.
55     if (transaction)
56         transaction->registerRequest(request);
57     return request;
58 }
59 
IDBRequest(ScriptState * scriptState,IDBAny * source,IDBTransaction * transaction)60 IDBRequest::IDBRequest(ScriptState* scriptState, IDBAny* source, IDBTransaction* transaction)
61     : ActiveDOMObject(scriptState->executionContext())
62     , m_contextStopped(false)
63     , m_transaction(transaction)
64     , m_readyState(PENDING)
65     , m_requestAborted(false)
66     , m_scriptState(scriptState)
67     , m_source(source)
68     , m_hasPendingActivity(true)
69     , m_cursorType(IndexedDB::CursorKeyAndValue)
70     , m_cursorDirection(WebIDBCursorDirectionNext)
71     , m_pendingCursor(nullptr)
72     , m_didFireUpgradeNeededEvent(false)
73     , m_preventPropagation(false)
74     , m_resultDirty(true)
75 {
76 }
77 
~IDBRequest()78 IDBRequest::~IDBRequest()
79 {
80     ASSERT(m_readyState == DONE || m_readyState == EarlyDeath || !executionContext());
81     ASSERT(!m_blobInfo || m_blobInfo->size() == 0);
82 }
83 
dispose()84 void IDBRequest::dispose()
85 {
86     handleBlobAcks();
87 }
88 
trace(Visitor * visitor)89 void IDBRequest::trace(Visitor* visitor)
90 {
91     visitor->trace(m_transaction);
92     visitor->trace(m_source);
93     visitor->trace(m_result);
94     visitor->trace(m_error);
95 #if ENABLE(OILPAN)
96     visitor->trace(m_enqueuedEvents);
97 #endif
98     visitor->trace(m_pendingCursor);
99     visitor->trace(m_cursorKey);
100     visitor->trace(m_cursorPrimaryKey);
101     EventTargetWithInlineData::trace(visitor);
102 }
103 
result(ExceptionState & exceptionState)104 ScriptValue IDBRequest::result(ExceptionState& exceptionState)
105 {
106     if (m_readyState != DONE) {
107         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::requestNotFinishedErrorMessage);
108         return ScriptValue();
109     }
110     if (m_contextStopped || !executionContext())
111         return ScriptValue();
112     m_resultDirty = false;
113     ScriptValue value = idbAnyToScriptValue(m_scriptState.get(), m_result);
114     handleBlobAcks();
115     return value;
116 }
117 
error(ExceptionState & exceptionState) const118 PassRefPtrWillBeRawPtr<DOMError> IDBRequest::error(ExceptionState& exceptionState) const
119 {
120     if (m_readyState != DONE) {
121         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::requestNotFinishedErrorMessage);
122         return nullptr;
123     }
124     return m_error;
125 }
126 
source() const127 ScriptValue IDBRequest::source() const
128 {
129     if (m_contextStopped || !executionContext())
130         return ScriptValue();
131 
132     return idbAnyToScriptValue(m_scriptState.get(), m_source);
133 }
134 
readyState() const135 const String& IDBRequest::readyState() const
136 {
137     ASSERT(m_readyState == PENDING || m_readyState == DONE);
138 
139     if (m_readyState == PENDING)
140         return IndexedDBNames::pending;
141 
142     return IndexedDBNames::done;
143 }
144 
abort()145 void IDBRequest::abort()
146 {
147     ASSERT(!m_requestAborted);
148     if (m_contextStopped || !executionContext())
149         return;
150     ASSERT(m_readyState == PENDING || m_readyState == DONE);
151     if (m_readyState == DONE)
152         return;
153 
154     EventQueue* eventQueue = executionContext()->eventQueue();
155     for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
156         bool removed = eventQueue->cancelEvent(m_enqueuedEvents[i].get());
157         ASSERT_UNUSED(removed, removed);
158     }
159     m_enqueuedEvents.clear();
160 
161     m_error.clear();
162     m_result.clear();
163     onError(DOMError::create(AbortError, "The transaction was aborted, so the request cannot be fulfilled."));
164     m_requestAborted = true;
165 }
166 
setCursorDetails(IndexedDB::CursorType cursorType,WebIDBCursorDirection direction)167 void IDBRequest::setCursorDetails(IndexedDB::CursorType cursorType, WebIDBCursorDirection direction)
168 {
169     ASSERT(m_readyState == PENDING);
170     ASSERT(!m_pendingCursor);
171     m_cursorType = cursorType;
172     m_cursorDirection = direction;
173 }
174 
setPendingCursor(IDBCursor * cursor)175 void IDBRequest::setPendingCursor(IDBCursor* cursor)
176 {
177     ASSERT(m_readyState == DONE);
178     ASSERT(executionContext());
179     ASSERT(m_transaction);
180     ASSERT(!m_pendingCursor);
181     ASSERT(cursor == getResultCursor());
182 
183     m_hasPendingActivity = true;
184     m_pendingCursor = cursor;
185     setResult(0);
186     m_readyState = PENDING;
187     m_error.clear();
188     m_transaction->registerRequest(this);
189 }
190 
getResultCursor() const191 IDBCursor* IDBRequest::getResultCursor() const
192 {
193     if (!m_result)
194         return 0;
195     if (m_result->type() == IDBAny::IDBCursorType)
196         return m_result->idbCursor();
197     if (m_result->type() == IDBAny::IDBCursorWithValueType)
198         return m_result->idbCursorWithValue();
199     return 0;
200 }
201 
setResultCursor(IDBCursor * cursor,IDBKey * key,IDBKey * primaryKey,PassRefPtr<SharedBuffer> value,PassOwnPtr<Vector<WebBlobInfo>> blobInfo)202 void IDBRequest::setResultCursor(IDBCursor* cursor, IDBKey* key, IDBKey* primaryKey, PassRefPtr<SharedBuffer> value, PassOwnPtr<Vector<WebBlobInfo> > blobInfo)
203 {
204     ASSERT(m_readyState == PENDING);
205     m_cursorKey = key;
206     m_cursorPrimaryKey = primaryKey;
207     m_cursorValue = value;
208     setBlobInfo(blobInfo);
209 
210     onSuccessInternal(IDBAny::create(cursor));
211 }
212 
setBlobInfo(PassOwnPtr<Vector<WebBlobInfo>> blobInfo)213 void IDBRequest::setBlobInfo(PassOwnPtr<Vector<WebBlobInfo>> blobInfo)
214 {
215     ASSERT(!m_blobInfo);
216     m_blobInfo = blobInfo;
217     if (m_blobInfo && m_blobInfo->size() > 0)
218         V8PerIsolateData::from(scriptState()->isolate())->ensureIDBPendingTransactionMonitor()->registerRequest(*this);
219 }
220 
handleBlobAcks()221 void IDBRequest::handleBlobAcks()
222 {
223     if (m_blobInfo.get() && m_blobInfo->size()) {
224         m_transaction->db()->ackReceivedBlobs(m_blobInfo.get());
225         m_blobInfo.clear();
226         V8PerIsolateData::from(scriptState()->isolate())->ensureIDBPendingTransactionMonitor()->unregisterRequest(*this);
227     }
228 }
229 
shouldEnqueueEvent() const230 bool IDBRequest::shouldEnqueueEvent() const
231 {
232     if (m_contextStopped || !executionContext())
233         return false;
234     ASSERT(m_readyState == PENDING || m_readyState == DONE);
235     if (m_requestAborted)
236         return false;
237     ASSERT(m_readyState == PENDING);
238     ASSERT(!m_error && !m_result);
239     return true;
240 }
241 
onError(PassRefPtrWillBeRawPtr<DOMError> error)242 void IDBRequest::onError(PassRefPtrWillBeRawPtr<DOMError> error)
243 {
244     IDB_TRACE("IDBRequest::onError()");
245     if (!shouldEnqueueEvent())
246         return;
247 
248     m_error = error;
249     setResult(IDBAny::createUndefined());
250     m_pendingCursor.clear();
251     enqueueEvent(Event::createCancelableBubble(EventTypeNames::error));
252 }
253 
onSuccess(const Vector<String> & stringList)254 void IDBRequest::onSuccess(const Vector<String>& stringList)
255 {
256     IDB_TRACE("IDBRequest::onSuccess(StringList)");
257     if (!shouldEnqueueEvent())
258         return;
259 
260     RefPtrWillBeRawPtr<DOMStringList> domStringList = DOMStringList::create();
261     for (size_t i = 0; i < stringList.size(); ++i)
262         domStringList->append(stringList[i]);
263     onSuccessInternal(IDBAny::create(domStringList.release()));
264 }
265 
onSuccess(PassOwnPtr<WebIDBCursor> backend,IDBKey * key,IDBKey * primaryKey,PassRefPtr<SharedBuffer> value,PassOwnPtr<Vector<WebBlobInfo>> blobInfo)266 void IDBRequest::onSuccess(PassOwnPtr<WebIDBCursor> backend, IDBKey* key, IDBKey* primaryKey, PassRefPtr<SharedBuffer> value, PassOwnPtr<Vector<WebBlobInfo> > blobInfo)
267 {
268     IDB_TRACE("IDBRequest::onSuccess(IDBCursor)");
269     if (!shouldEnqueueEvent())
270         return;
271 
272     ASSERT(!m_pendingCursor);
273     IDBCursor* cursor = 0;
274     switch (m_cursorType) {
275     case IndexedDB::CursorKeyOnly:
276         cursor = IDBCursor::create(backend, m_cursorDirection, this, m_source.get(), m_transaction.get());
277         break;
278     case IndexedDB::CursorKeyAndValue:
279         cursor = IDBCursorWithValue::create(backend, m_cursorDirection, this, m_source.get(), m_transaction.get());
280         break;
281     default:
282         ASSERT_NOT_REACHED();
283     }
284     setResultCursor(cursor, key, primaryKey, value, blobInfo);
285 }
286 
onSuccess(IDBKey * idbKey)287 void IDBRequest::onSuccess(IDBKey* idbKey)
288 {
289     IDB_TRACE("IDBRequest::onSuccess(IDBKey)");
290     if (!shouldEnqueueEvent())
291         return;
292 
293     if (idbKey && idbKey->isValid())
294         onSuccessInternal(IDBAny::create(idbKey));
295     else
296         onSuccessInternal(IDBAny::createUndefined());
297 }
298 
onSuccess(PassRefPtr<SharedBuffer> valueBuffer,PassOwnPtr<Vector<WebBlobInfo>> blobInfo)299 void IDBRequest::onSuccess(PassRefPtr<SharedBuffer> valueBuffer, PassOwnPtr<Vector<WebBlobInfo> > blobInfo)
300 {
301     IDB_TRACE("IDBRequest::onSuccess(SharedBuffer)");
302     if (!shouldEnqueueEvent())
303         return;
304 
305     if (m_pendingCursor) {
306         // Value should be null, signifying the end of the cursor's range.
307         ASSERT(!valueBuffer.get());
308         ASSERT(!blobInfo->size());
309         m_pendingCursor->close();
310         m_pendingCursor.clear();
311     }
312 
313     setBlobInfo(blobInfo);
314     onSuccessInternal(IDBAny::create(valueBuffer, m_blobInfo.get()));
315 }
316 
317 #if ENABLE(ASSERT)
effectiveObjectStore(IDBAny * source)318 static IDBObjectStore* effectiveObjectStore(IDBAny* source)
319 {
320     if (source->type() == IDBAny::IDBObjectStoreType)
321         return source->idbObjectStore();
322     if (source->type() == IDBAny::IDBIndexType)
323         return source->idbIndex()->objectStore();
324 
325     ASSERT_NOT_REACHED();
326     return 0;
327 }
328 #endif
329 
onSuccess(PassRefPtr<SharedBuffer> prpValueBuffer,PassOwnPtr<Vector<WebBlobInfo>> blobInfo,IDBKey * prpPrimaryKey,const IDBKeyPath & keyPath)330 void IDBRequest::onSuccess(PassRefPtr<SharedBuffer> prpValueBuffer, PassOwnPtr<Vector<WebBlobInfo> > blobInfo, IDBKey* prpPrimaryKey, const IDBKeyPath& keyPath)
331 {
332     IDB_TRACE("IDBRequest::onSuccess(SharedBuffer, IDBKey, IDBKeyPath)");
333     if (!shouldEnqueueEvent())
334         return;
335 
336     ASSERT(keyPath == effectiveObjectStore(m_source)->metadata().keyPath);
337 
338     RefPtr<SharedBuffer> valueBuffer = prpValueBuffer;
339     IDBKey* primaryKey = prpPrimaryKey;
340     setBlobInfo(blobInfo);
341 
342 #if ENABLE(ASSERT)
343     assertPrimaryKeyValidOrInjectable(m_scriptState.get(), valueBuffer, m_blobInfo.get(), primaryKey, keyPath);
344 #endif
345 
346     onSuccessInternal(IDBAny::create(valueBuffer, m_blobInfo.get(), primaryKey, keyPath));
347 }
348 
onSuccess(int64_t value)349 void IDBRequest::onSuccess(int64_t value)
350 {
351     IDB_TRACE("IDBRequest::onSuccess(int64_t)");
352     if (!shouldEnqueueEvent())
353         return;
354     onSuccessInternal(IDBAny::create(value));
355 }
356 
onSuccess()357 void IDBRequest::onSuccess()
358 {
359     IDB_TRACE("IDBRequest::onSuccess()");
360     if (!shouldEnqueueEvent())
361         return;
362     onSuccessInternal(IDBAny::createUndefined());
363 }
364 
onSuccessInternal(IDBAny * result)365 void IDBRequest::onSuccessInternal(IDBAny* result)
366 {
367     ASSERT(!m_contextStopped);
368     ASSERT(!m_pendingCursor);
369     setResult(result);
370     enqueueEvent(Event::create(EventTypeNames::success));
371 }
372 
setResult(IDBAny * result)373 void IDBRequest::setResult(IDBAny* result)
374 {
375     m_result = result;
376     m_resultDirty = true;
377 }
378 
onSuccess(IDBKey * key,IDBKey * primaryKey,PassRefPtr<SharedBuffer> value,PassOwnPtr<Vector<WebBlobInfo>> blobInfo)379 void IDBRequest::onSuccess(IDBKey* key, IDBKey* primaryKey, PassRefPtr<SharedBuffer> value, PassOwnPtr<Vector<WebBlobInfo> > blobInfo)
380 {
381     IDB_TRACE("IDBRequest::onSuccess(key, primaryKey, value)");
382     if (!shouldEnqueueEvent())
383         return;
384 
385     ASSERT(m_pendingCursor);
386     setResultCursor(m_pendingCursor.release(), key, primaryKey, value, blobInfo);
387 }
388 
hasPendingActivity() const389 bool IDBRequest::hasPendingActivity() const
390 {
391     // FIXME: In an ideal world, we should return true as long as anyone has a or can
392     //        get a handle to us and we have event listeners. This is order to handle
393     //        user generated events properly.
394     return m_hasPendingActivity && !m_contextStopped;
395 }
396 
stop()397 void IDBRequest::stop()
398 {
399     if (m_contextStopped)
400         return;
401 
402     m_contextStopped = true;
403 
404     if (m_readyState == PENDING) {
405         m_readyState = EarlyDeath;
406         if (m_transaction) {
407             m_transaction->unregisterRequest(this);
408             m_transaction.clear();
409         }
410     }
411 
412     m_enqueuedEvents.clear();
413     if (m_source)
414         m_source->contextWillBeDestroyed();
415     if (m_result)
416         m_result->contextWillBeDestroyed();
417     if (m_pendingCursor)
418         m_pendingCursor->contextWillBeDestroyed();
419 }
420 
interfaceName() const421 const AtomicString& IDBRequest::interfaceName() const
422 {
423     return EventTargetNames::IDBRequest;
424 }
425 
executionContext() const426 ExecutionContext* IDBRequest::executionContext() const
427 {
428     return ActiveDOMObject::executionContext();
429 }
430 
dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)431 bool IDBRequest::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
432 {
433     IDB_TRACE("IDBRequest::dispatchEvent");
434     if (m_contextStopped || !executionContext())
435         return false;
436     ASSERT(m_readyState == PENDING);
437     ASSERT(m_hasPendingActivity);
438     ASSERT(m_enqueuedEvents.size());
439     ASSERT(event->target() == this);
440 
441     ScriptState::Scope scope(m_scriptState.get());
442 
443     if (event->type() != EventTypeNames::blocked)
444         m_readyState = DONE;
445     dequeueEvent(event.get());
446 
447     WillBeHeapVector<RefPtrWillBeMember<EventTarget> > targets;
448     targets.append(this);
449     if (m_transaction && !m_preventPropagation) {
450         targets.append(m_transaction);
451         // If there ever are events that are associated with a database but
452         // that do not have a transaction, then this will not work and we need
453         // this object to actually hold a reference to the database (to ensure
454         // it stays alive).
455         targets.append(m_transaction->db());
456     }
457 
458     // Cursor properties should not be updated until the success event is being dispatched.
459     IDBCursor* cursorToNotify = 0;
460     if (event->type() == EventTypeNames::success) {
461         cursorToNotify = getResultCursor();
462         if (cursorToNotify) {
463             if (m_blobInfo && m_blobInfo->size() > 0)
464                 V8PerIsolateData::from(scriptState()->isolate())->ensureIDBPendingTransactionMonitor()->unregisterRequest(*this);
465             cursorToNotify->setValueReady(m_cursorKey.release(), m_cursorPrimaryKey.release(), m_cursorValue.release(), m_blobInfo.release());
466         }
467     }
468 
469     if (event->type() == EventTypeNames::upgradeneeded) {
470         ASSERT(!m_didFireUpgradeNeededEvent);
471         m_didFireUpgradeNeededEvent = true;
472     }
473 
474     // FIXME: When we allow custom event dispatching, this will probably need to change.
475     ASSERT_WITH_MESSAGE(event->type() == EventTypeNames::success || event->type() == EventTypeNames::error || event->type() == EventTypeNames::blocked || event->type() == EventTypeNames::upgradeneeded, "event type was %s", event->type().utf8().data());
476     const bool setTransactionActive = m_transaction && (event->type() == EventTypeNames::success || event->type() == EventTypeNames::upgradeneeded || (event->type() == EventTypeNames::error && !m_requestAborted));
477 
478     if (setTransactionActive)
479         m_transaction->setActive(true);
480 
481     bool dontPreventDefault = IDBEventDispatcher::dispatch(event.get(), targets);
482 
483     if (m_transaction) {
484         if (m_readyState == DONE)
485             m_transaction->unregisterRequest(this);
486 
487         // Possibly abort the transaction. This must occur after unregistering (so this request
488         // doesn't receive a second error) and before deactivating (which might trigger commit).
489         if (event->type() == EventTypeNames::error && dontPreventDefault && !m_requestAborted) {
490             m_transaction->setError(m_error);
491             m_transaction->abort(IGNORE_EXCEPTION);
492         }
493 
494         // If this was the last request in the transaction's list, it may commit here.
495         if (setTransactionActive)
496             m_transaction->setActive(false);
497     }
498 
499     if (cursorToNotify)
500         cursorToNotify->postSuccessHandlerCallback();
501 
502     // An upgradeneeded event will always be followed by a success or error event, so must
503     // be kept alive.
504     if (m_readyState == DONE && event->type() != EventTypeNames::upgradeneeded)
505         m_hasPendingActivity = false;
506 
507     return dontPreventDefault;
508 }
509 
uncaughtExceptionInEventHandler()510 void IDBRequest::uncaughtExceptionInEventHandler()
511 {
512     if (m_transaction && !m_requestAborted) {
513         m_transaction->setError(DOMError::create(AbortError, "Uncaught exception in event handler."));
514         m_transaction->abort(IGNORE_EXCEPTION);
515     }
516 }
517 
transactionDidFinishAndDispatch()518 void IDBRequest::transactionDidFinishAndDispatch()
519 {
520     ASSERT(m_transaction);
521     ASSERT(m_transaction->isVersionChange());
522     ASSERT(m_didFireUpgradeNeededEvent);
523     ASSERT(m_readyState == DONE);
524     ASSERT(executionContext());
525     m_transaction.clear();
526 
527     if (m_contextStopped)
528         return;
529 
530     m_readyState = PENDING;
531 }
532 
enqueueEvent(PassRefPtrWillBeRawPtr<Event> event)533 void IDBRequest::enqueueEvent(PassRefPtrWillBeRawPtr<Event> event)
534 {
535     ASSERT(m_readyState == PENDING || m_readyState == DONE);
536 
537     if (m_contextStopped || !executionContext())
538         return;
539 
540     ASSERT_WITH_MESSAGE(m_readyState == PENDING || m_didFireUpgradeNeededEvent, "When queueing event %s, m_readyState was %d", event->type().utf8().data(), m_readyState);
541 
542     EventQueue* eventQueue = executionContext()->eventQueue();
543     event->setTarget(this);
544 
545     // Keep track of enqueued events in case we need to abort prior to dispatch,
546     // in which case these must be cancelled. If the events not dispatched for
547     // other reasons they must be removed from this list via dequeueEvent().
548     if (eventQueue->enqueueEvent(event.get()))
549         m_enqueuedEvents.append(event);
550 }
551 
dequeueEvent(Event * event)552 void IDBRequest::dequeueEvent(Event* event)
553 {
554     for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
555         if (m_enqueuedEvents[i].get() == event)
556             m_enqueuedEvents.remove(i);
557     }
558 }
559 
560 } // namespace blink
561