1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "IDBFileHandle.h"
8
9 #include "ActorsChild.h"
10 #include "BackgroundChildImpl.h"
11 #include "IDBEvents.h"
12 #include "IDBMutableFile.h"
13 #include "mozilla/Assertions.h"
14 #include "mozilla/dom/File.h"
15 #include "mozilla/dom/IDBFileHandleBinding.h"
16 #include "mozilla/dom/IPCBlobUtils.h"
17 #include "mozilla/dom/PBackgroundFileHandle.h"
18 #include "mozilla/EventDispatcher.h"
19 #include "mozilla/ipc/BackgroundChild.h"
20 #include "nsContentUtils.h"
21 #include "nsQueryObject.h"
22 #include "nsServiceManagerUtils.h"
23 #include "nsWidgetsCID.h"
24
25 namespace mozilla {
26 namespace dom {
27
28 using namespace mozilla::dom::indexedDB;
29 using namespace mozilla::ipc;
30
31 namespace {
32
GenerateFileRequest(IDBFileHandle * aFileHandle)33 already_AddRefed<IDBFileRequest> GenerateFileRequest(
34 IDBFileHandle* aFileHandle) {
35 MOZ_ASSERT(aFileHandle);
36 aFileHandle->AssertIsOnOwningThread();
37
38 RefPtr<IDBFileRequest> fileRequest =
39 IDBFileRequest::Create(aFileHandle, /* aWrapAsDOMRequest */ false);
40 MOZ_ASSERT(fileRequest);
41
42 return fileRequest.forget();
43 }
44
45 } // namespace
46
IDBFileHandle(IDBMutableFile * aMutableFile,FileMode aMode)47 IDBFileHandle::IDBFileHandle(IDBMutableFile* aMutableFile, FileMode aMode)
48 : mMutableFile(aMutableFile),
49 mBackgroundActor(nullptr),
50 mLocation(0),
51 mPendingRequestCount(0),
52 mReadyState(INITIAL),
53 mMode(aMode),
54 mAborted(false),
55 mCreating(false)
56 #ifdef DEBUG
57 ,
58 mSentFinishOrAbort(false),
59 mFiredCompleteOrAbort(false)
60 #endif
61 {
62 MOZ_ASSERT(aMutableFile);
63 aMutableFile->AssertIsOnOwningThread();
64 }
65
~IDBFileHandle()66 IDBFileHandle::~IDBFileHandle() {
67 AssertIsOnOwningThread();
68 MOZ_ASSERT(!mPendingRequestCount);
69 MOZ_ASSERT(!mCreating);
70 MOZ_ASSERT(mSentFinishOrAbort);
71 MOZ_ASSERT_IF(mBackgroundActor, mFiredCompleteOrAbort);
72
73 mMutableFile->UnregisterFileHandle(this);
74
75 if (mBackgroundActor) {
76 mBackgroundActor->SendDeleteMeInternal();
77
78 MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
79 }
80 }
81
82 // static
Create(IDBMutableFile * aMutableFile,FileMode aMode)83 already_AddRefed<IDBFileHandle> IDBFileHandle::Create(
84 IDBMutableFile* aMutableFile, FileMode aMode) {
85 MOZ_ASSERT(aMutableFile);
86 aMutableFile->AssertIsOnOwningThread();
87 MOZ_ASSERT(aMode == FileMode::Readonly || aMode == FileMode::Readwrite);
88
89 RefPtr<IDBFileHandle> fileHandle = new IDBFileHandle(aMutableFile, aMode);
90
91 fileHandle->BindToOwner(aMutableFile);
92
93 // XXX Fix!
94 MOZ_ASSERT(NS_IsMainThread(), "This won't work on non-main threads!");
95
96 nsCOMPtr<nsIRunnable> runnable = do_QueryObject(fileHandle);
97 nsContentUtils::AddPendingIDBTransaction(runnable.forget());
98
99 fileHandle->mCreating = true;
100
101 aMutableFile->RegisterFileHandle(fileHandle);
102
103 return fileHandle.forget();
104 }
105
106 // static
GetCurrent()107 IDBFileHandle* IDBFileHandle::GetCurrent() {
108 MOZ_ASSERT(BackgroundChild::GetForCurrentThread());
109
110 BackgroundChildImpl::ThreadLocal* threadLocal =
111 BackgroundChildImpl::GetThreadLocalForCurrentThread();
112 MOZ_ASSERT(threadLocal);
113
114 return threadLocal->mCurrentFileHandle;
115 }
116
117 #ifdef DEBUG
118
AssertIsOnOwningThread() const119 void IDBFileHandle::AssertIsOnOwningThread() const {
120 MOZ_ASSERT(mMutableFile);
121 mMutableFile->AssertIsOnOwningThread();
122 }
123
124 #endif // DEBUG
125
SetBackgroundActor(BackgroundFileHandleChild * aActor)126 void IDBFileHandle::SetBackgroundActor(BackgroundFileHandleChild* aActor) {
127 AssertIsOnOwningThread();
128 MOZ_ASSERT(aActor);
129 MOZ_ASSERT(!mBackgroundActor);
130
131 mBackgroundActor = aActor;
132 }
133
StartRequest(IDBFileRequest * aFileRequest,const FileRequestParams & aParams)134 void IDBFileHandle::StartRequest(IDBFileRequest* aFileRequest,
135 const FileRequestParams& aParams) {
136 AssertIsOnOwningThread();
137 MOZ_ASSERT(aFileRequest);
138 MOZ_ASSERT(aParams.type() != FileRequestParams::T__None);
139
140 BackgroundFileRequestChild* actor =
141 new BackgroundFileRequestChild(aFileRequest);
142
143 mBackgroundActor->SendPBackgroundFileRequestConstructor(actor, aParams);
144
145 // Balanced in BackgroundFileRequestChild::Recv__delete__().
146 OnNewRequest();
147 }
148
OnNewRequest()149 void IDBFileHandle::OnNewRequest() {
150 AssertIsOnOwningThread();
151
152 if (!mPendingRequestCount) {
153 MOZ_ASSERT(mReadyState == INITIAL);
154 mReadyState = LOADING;
155 }
156
157 ++mPendingRequestCount;
158 }
159
OnRequestFinished(bool aActorDestroyedNormally)160 void IDBFileHandle::OnRequestFinished(bool aActorDestroyedNormally) {
161 AssertIsOnOwningThread();
162 MOZ_ASSERT(mPendingRequestCount);
163
164 --mPendingRequestCount;
165
166 if (!mPendingRequestCount && !mMutableFile->IsInvalidated()) {
167 mReadyState = FINISHING;
168
169 if (aActorDestroyedNormally) {
170 if (!mAborted) {
171 SendFinish();
172 } else {
173 SendAbort();
174 }
175 } else {
176 // Don't try to send any more messages to the parent if the request actor
177 // was killed.
178 #ifdef DEBUG
179 MOZ_ASSERT(!mSentFinishOrAbort);
180 mSentFinishOrAbort = true;
181 #endif
182 }
183 }
184 }
185
FireCompleteOrAbortEvents(bool aAborted)186 void IDBFileHandle::FireCompleteOrAbortEvents(bool aAborted) {
187 AssertIsOnOwningThread();
188 MOZ_ASSERT(!mFiredCompleteOrAbort);
189
190 mReadyState = DONE;
191
192 #ifdef DEBUG
193 mFiredCompleteOrAbort = true;
194 #endif
195
196 nsCOMPtr<nsIDOMEvent> event;
197 if (aAborted) {
198 event = CreateGenericEvent(this, nsDependentString(kAbortEventType),
199 eDoesBubble, eNotCancelable);
200 } else {
201 event = CreateGenericEvent(this, nsDependentString(kCompleteEventType),
202 eDoesNotBubble, eNotCancelable);
203 }
204 if (NS_WARN_IF(!event)) {
205 return;
206 }
207
208 bool dummy;
209 if (NS_FAILED(DispatchEvent(event, &dummy))) {
210 NS_WARNING("DispatchEvent failed!");
211 }
212 }
213
IsOpen() const214 bool IDBFileHandle::IsOpen() const {
215 AssertIsOnOwningThread();
216
217 // If we haven't started anything then we're open.
218 if (mReadyState == INITIAL) {
219 return true;
220 }
221
222 // If we've already started then we need to check to see if we still have the
223 // mCreating flag set. If we do (i.e. we haven't returned to the event loop
224 // from the time we were created) then we are open. Otherwise check the
225 // currently running file handles to see if it's the same. We only allow other
226 // requests to be made if this file handle is currently running.
227 if (mReadyState == LOADING && (mCreating || GetCurrent() == this)) {
228 return true;
229 }
230
231 return false;
232 }
233
Abort()234 void IDBFileHandle::Abort() {
235 AssertIsOnOwningThread();
236
237 if (IsFinishingOrDone()) {
238 // Already started (and maybe finished) the finish or abort so there is
239 // nothing to do here.
240 return;
241 }
242
243 const bool isInvalidated = mMutableFile->IsInvalidated();
244 bool needToSendAbort = mReadyState == INITIAL && !isInvalidated;
245
246 #ifdef DEBUG
247 if (isInvalidated) {
248 mSentFinishOrAbort = true;
249 }
250 #endif
251
252 mAborted = true;
253 mReadyState = DONE;
254
255 // Fire the abort event if there are no outstanding requests. Otherwise the
256 // abort event will be fired when all outstanding requests finish.
257 if (needToSendAbort) {
258 SendAbort();
259 }
260 }
261
GetMetadata(const IDBFileMetadataParameters & aParameters,ErrorResult & aRv)262 already_AddRefed<IDBFileRequest> IDBFileHandle::GetMetadata(
263 const IDBFileMetadataParameters& aParameters, ErrorResult& aRv) {
264 AssertIsOnOwningThread();
265
266 // Common state checking
267 if (!CheckState(aRv)) {
268 return nullptr;
269 }
270
271 // Argument checking for get metadata.
272 if (!aParameters.mSize && !aParameters.mLastModified) {
273 aRv.ThrowTypeError<MSG_METADATA_NOT_CONFIGURED>();
274 return nullptr;
275 }
276
277 // Do nothing if the window is closed
278 if (!CheckWindow()) {
279 return nullptr;
280 }
281
282 FileRequestGetMetadataParams params;
283 params.size() = aParameters.mSize;
284 params.lastModified() = aParameters.mLastModified;
285
286 RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
287
288 StartRequest(fileRequest, params);
289
290 return fileRequest.forget();
291 }
292
Truncate(const Optional<uint64_t> & aSize,ErrorResult & aRv)293 already_AddRefed<IDBFileRequest> IDBFileHandle::Truncate(
294 const Optional<uint64_t>& aSize, ErrorResult& aRv) {
295 AssertIsOnOwningThread();
296
297 // State checking for write
298 if (!CheckStateForWrite(aRv)) {
299 return nullptr;
300 }
301
302 // Getting location and additional state checking for truncate
303 uint64_t location;
304 if (aSize.WasPassed()) {
305 // Just in case someone calls us from C++
306 MOZ_ASSERT(aSize.Value() != UINT64_MAX, "Passed wrong size!");
307 location = aSize.Value();
308 } else {
309 if (mLocation == UINT64_MAX) {
310 aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
311 return nullptr;
312 }
313 location = mLocation;
314 }
315
316 // Do nothing if the window is closed
317 if (!CheckWindow()) {
318 return nullptr;
319 }
320
321 FileRequestTruncateParams params;
322 params.offset() = location;
323
324 RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
325
326 StartRequest(fileRequest, params);
327
328 if (aSize.WasPassed()) {
329 mLocation = aSize.Value();
330 }
331
332 return fileRequest.forget();
333 }
334
Flush(ErrorResult & aRv)335 already_AddRefed<IDBFileRequest> IDBFileHandle::Flush(ErrorResult& aRv) {
336 AssertIsOnOwningThread();
337
338 // State checking for write
339 if (!CheckStateForWrite(aRv)) {
340 return nullptr;
341 }
342
343 // Do nothing if the window is closed
344 if (!CheckWindow()) {
345 return nullptr;
346 }
347
348 FileRequestFlushParams params;
349
350 RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
351
352 StartRequest(fileRequest, params);
353
354 return fileRequest.forget();
355 }
356
Abort(ErrorResult & aRv)357 void IDBFileHandle::Abort(ErrorResult& aRv) {
358 AssertIsOnOwningThread();
359
360 // This method is special enough for not using generic state checking methods.
361
362 if (IsFinishingOrDone()) {
363 aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
364 return;
365 }
366
367 Abort();
368 }
369
CheckState(ErrorResult & aRv)370 bool IDBFileHandle::CheckState(ErrorResult& aRv) {
371 if (!IsOpen()) {
372 aRv.Throw(NS_ERROR_DOM_FILEHANDLE_INACTIVE_ERR);
373 return false;
374 }
375
376 return true;
377 }
378
CheckStateAndArgumentsForRead(uint64_t aSize,ErrorResult & aRv)379 bool IDBFileHandle::CheckStateAndArgumentsForRead(uint64_t aSize,
380 ErrorResult& aRv) {
381 // Common state checking
382 if (!CheckState(aRv)) {
383 return false;
384 }
385
386 // Additional state checking for read
387 if (mLocation == UINT64_MAX) {
388 aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
389 return false;
390 }
391
392 // Argument checking for read
393 if (!aSize) {
394 aRv.ThrowTypeError<MSG_INVALID_READ_SIZE>();
395 return false;
396 }
397
398 return true;
399 }
400
CheckStateForWrite(ErrorResult & aRv)401 bool IDBFileHandle::CheckStateForWrite(ErrorResult& aRv) {
402 // Common state checking
403 if (!CheckState(aRv)) {
404 return false;
405 }
406
407 // Additional state checking for write
408 if (mMode != FileMode::Readwrite) {
409 aRv.Throw(NS_ERROR_DOM_FILEHANDLE_READ_ONLY_ERR);
410 return false;
411 }
412
413 return true;
414 }
415
CheckStateForWriteOrAppend(bool aAppend,ErrorResult & aRv)416 bool IDBFileHandle::CheckStateForWriteOrAppend(bool aAppend, ErrorResult& aRv) {
417 // State checking for write
418 if (!CheckStateForWrite(aRv)) {
419 return false;
420 }
421
422 // Additional state checking for write
423 if (!aAppend && mLocation == UINT64_MAX) {
424 aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
425 return false;
426 }
427
428 return true;
429 }
430
CheckWindow()431 bool IDBFileHandle::CheckWindow() {
432 AssertIsOnOwningThread();
433
434 return GetOwner();
435 }
436
Read(uint64_t aSize,bool aHasEncoding,const nsAString & aEncoding,ErrorResult & aRv)437 already_AddRefed<IDBFileRequest> IDBFileHandle::Read(uint64_t aSize,
438 bool aHasEncoding,
439 const nsAString& aEncoding,
440 ErrorResult& aRv) {
441 AssertIsOnOwningThread();
442
443 // State and argument checking for read
444 if (!CheckStateAndArgumentsForRead(aSize, aRv)) {
445 return nullptr;
446 }
447
448 // Do nothing if the window is closed
449 if (!CheckWindow()) {
450 return nullptr;
451 }
452
453 FileRequestReadParams params;
454 params.offset() = mLocation;
455 params.size() = aSize;
456
457 RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
458 if (aHasEncoding) {
459 fileRequest->SetEncoding(aEncoding);
460 }
461
462 StartRequest(fileRequest, params);
463
464 mLocation += aSize;
465
466 return fileRequest.forget();
467 }
468
WriteOrAppend(const StringOrArrayBufferOrArrayBufferViewOrBlob & aValue,bool aAppend,ErrorResult & aRv)469 already_AddRefed<IDBFileRequest> IDBFileHandle::WriteOrAppend(
470 const StringOrArrayBufferOrArrayBufferViewOrBlob& aValue, bool aAppend,
471 ErrorResult& aRv) {
472 AssertIsOnOwningThread();
473
474 if (aValue.IsString()) {
475 return WriteOrAppend(aValue.GetAsString(), aAppend, aRv);
476 }
477
478 if (aValue.IsArrayBuffer()) {
479 return WriteOrAppend(aValue.GetAsArrayBuffer(), aAppend, aRv);
480 }
481
482 if (aValue.IsArrayBufferView()) {
483 return WriteOrAppend(aValue.GetAsArrayBufferView(), aAppend, aRv);
484 }
485
486 MOZ_ASSERT(aValue.IsBlob());
487 return WriteOrAppend(aValue.GetAsBlob(), aAppend, aRv);
488 }
489
WriteOrAppend(const nsAString & aValue,bool aAppend,ErrorResult & aRv)490 already_AddRefed<IDBFileRequest> IDBFileHandle::WriteOrAppend(
491 const nsAString& aValue, bool aAppend, ErrorResult& aRv) {
492 AssertIsOnOwningThread();
493
494 // State checking for write or append
495 if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
496 return nullptr;
497 }
498
499 NS_ConvertUTF16toUTF8 cstr(aValue);
500
501 uint64_t dataLength = cstr.Length();
502 ;
503 if (!dataLength) {
504 return nullptr;
505 }
506
507 FileRequestStringData stringData(cstr);
508
509 // Do nothing if the window is closed
510 if (!CheckWindow()) {
511 return nullptr;
512 }
513
514 return WriteInternal(stringData, dataLength, aAppend, aRv);
515 }
516
WriteOrAppend(const ArrayBuffer & aValue,bool aAppend,ErrorResult & aRv)517 already_AddRefed<IDBFileRequest> IDBFileHandle::WriteOrAppend(
518 const ArrayBuffer& aValue, bool aAppend, ErrorResult& aRv) {
519 AssertIsOnOwningThread();
520
521 // State checking for write or append
522 if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
523 return nullptr;
524 }
525
526 aValue.ComputeLengthAndData();
527
528 uint64_t dataLength = aValue.Length();
529 ;
530 if (!dataLength) {
531 return nullptr;
532 }
533
534 const char* data = reinterpret_cast<const char*>(aValue.Data());
535
536 FileRequestStringData stringData;
537 if (NS_WARN_IF(
538 !stringData.string().Assign(data, aValue.Length(), fallible_t()))) {
539 aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
540 return nullptr;
541 }
542
543 // Do nothing if the window is closed
544 if (!CheckWindow()) {
545 return nullptr;
546 }
547
548 return WriteInternal(stringData, dataLength, aAppend, aRv);
549 }
550
WriteOrAppend(const ArrayBufferView & aValue,bool aAppend,ErrorResult & aRv)551 already_AddRefed<IDBFileRequest> IDBFileHandle::WriteOrAppend(
552 const ArrayBufferView& aValue, bool aAppend, ErrorResult& aRv) {
553 AssertIsOnOwningThread();
554
555 // State checking for write or append
556 if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
557 return nullptr;
558 }
559
560 aValue.ComputeLengthAndData();
561
562 uint64_t dataLength = aValue.Length();
563 ;
564 if (!dataLength) {
565 return nullptr;
566 }
567
568 const char* data = reinterpret_cast<const char*>(aValue.Data());
569
570 FileRequestStringData stringData;
571 if (NS_WARN_IF(
572 !stringData.string().Assign(data, aValue.Length(), fallible_t()))) {
573 aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
574 return nullptr;
575 }
576
577 // Do nothing if the window is closed
578 if (!CheckWindow()) {
579 return nullptr;
580 }
581
582 return WriteInternal(stringData, dataLength, aAppend, aRv);
583 }
584
WriteOrAppend(Blob & aValue,bool aAppend,ErrorResult & aRv)585 already_AddRefed<IDBFileRequest> IDBFileHandle::WriteOrAppend(
586 Blob& aValue, bool aAppend, ErrorResult& aRv) {
587 AssertIsOnOwningThread();
588
589 // State checking for write or append
590 if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
591 return nullptr;
592 }
593
594 ErrorResult error;
595 uint64_t dataLength = aValue.GetSize(error);
596 if (NS_WARN_IF(error.Failed())) {
597 aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
598 return nullptr;
599 }
600
601 if (!dataLength) {
602 return nullptr;
603 }
604
605 PBackgroundChild* backgroundActor = BackgroundChild::GetForCurrentThread();
606 MOZ_ASSERT(backgroundActor);
607
608 IPCBlob ipcBlob;
609 nsresult rv =
610 IPCBlobUtils::Serialize(aValue.Impl(), backgroundActor, ipcBlob);
611 if (NS_WARN_IF(NS_FAILED(rv))) {
612 aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
613 return nullptr;
614 }
615
616 FileRequestBlobData blobData;
617 blobData.blob() = ipcBlob;
618
619 // Do nothing if the window is closed
620 if (!CheckWindow()) {
621 return nullptr;
622 }
623
624 return WriteInternal(blobData, dataLength, aAppend, aRv);
625 }
626
WriteInternal(const FileRequestData & aData,uint64_t aDataLength,bool aAppend,ErrorResult & aRv)627 already_AddRefed<IDBFileRequest> IDBFileHandle::WriteInternal(
628 const FileRequestData& aData, uint64_t aDataLength, bool aAppend,
629 ErrorResult& aRv) {
630 AssertIsOnOwningThread();
631
632 DebugOnly<ErrorResult> error;
633 MOZ_ASSERT(CheckStateForWrite(error));
634 MOZ_ASSERT_IF(!aAppend, mLocation != UINT64_MAX);
635 MOZ_ASSERT(aDataLength);
636 MOZ_ASSERT(CheckWindow());
637
638 FileRequestWriteParams params;
639 params.offset() = aAppend ? UINT64_MAX : mLocation;
640 params.data() = aData;
641 params.dataLength() = aDataLength;
642
643 RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
644 MOZ_ASSERT(fileRequest);
645
646 StartRequest(fileRequest, params);
647
648 if (aAppend) {
649 mLocation = UINT64_MAX;
650 } else {
651 mLocation += aDataLength;
652 }
653
654 return fileRequest.forget();
655 }
656
SendFinish()657 void IDBFileHandle::SendFinish() {
658 AssertIsOnOwningThread();
659 MOZ_ASSERT(!mAborted);
660 MOZ_ASSERT(IsFinishingOrDone());
661 MOZ_ASSERT(!mSentFinishOrAbort);
662 MOZ_ASSERT(!mPendingRequestCount);
663
664 MOZ_ASSERT(mBackgroundActor);
665 mBackgroundActor->SendFinish();
666
667 #ifdef DEBUG
668 mSentFinishOrAbort = true;
669 #endif
670 }
671
SendAbort()672 void IDBFileHandle::SendAbort() {
673 AssertIsOnOwningThread();
674 MOZ_ASSERT(mAborted);
675 MOZ_ASSERT(IsFinishingOrDone());
676 MOZ_ASSERT(!mSentFinishOrAbort);
677
678 MOZ_ASSERT(mBackgroundActor);
679 mBackgroundActor->SendAbort();
680
681 #ifdef DEBUG
682 mSentFinishOrAbort = true;
683 #endif
684 }
685
NS_IMPL_ADDREF_INHERITED(IDBFileHandle,DOMEventTargetHelper)686 NS_IMPL_ADDREF_INHERITED(IDBFileHandle, DOMEventTargetHelper)
687 NS_IMPL_RELEASE_INHERITED(IDBFileHandle, DOMEventTargetHelper)
688
689 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBFileHandle)
690 NS_INTERFACE_MAP_ENTRY(nsIRunnable)
691 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
692 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
693
694 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBFileHandle)
695
696 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBFileHandle,
697 DOMEventTargetHelper)
698 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMutableFile)
699 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
700
701 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBFileHandle,
702 DOMEventTargetHelper)
703 // Don't unlink mMutableFile!
704 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
705
706 NS_IMETHODIMP
707 IDBFileHandle::Run() {
708 AssertIsOnOwningThread();
709
710 // We're back at the event loop, no longer newborn.
711 mCreating = false;
712
713 // Maybe finish if there were no requests generated.
714 if (mReadyState == INITIAL) {
715 mReadyState = DONE;
716
717 SendFinish();
718 }
719
720 return NS_OK;
721 }
722
GetEventTargetParent(EventChainPreVisitor & aVisitor)723 nsresult IDBFileHandle::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
724 AssertIsOnOwningThread();
725
726 aVisitor.mCanHandle = true;
727 aVisitor.SetParentTarget(mMutableFile, false);
728 return NS_OK;
729 }
730
731 // virtual
WrapObject(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)732 JSObject* IDBFileHandle::WrapObject(JSContext* aCx,
733 JS::Handle<JSObject*> aGivenProto) {
734 AssertIsOnOwningThread();
735
736 return IDBFileHandleBinding::Wrap(aCx, this, aGivenProto);
737 }
738
739 } // namespace dom
740 } // namespace mozilla
741