Source code

Revision control

Other Tools

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
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
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
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
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
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
119
void IDBFileHandle::AssertIsOnOwningThread() const {
120
MOZ_ASSERT(mMutableFile);
121
mMutableFile->AssertIsOnOwningThread();
122
}
123
124
#endif // DEBUG
125
126
void IDBFileHandle::SetBackgroundActor(BackgroundFileHandleChild* aActor) {
127
AssertIsOnOwningThread();
128
MOZ_ASSERT(aActor);
129
MOZ_ASSERT(!mBackgroundActor);
130
131
mBackgroundActor = aActor;
132
}
133
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
149
void IDBFileHandle::OnNewRequest() {
150
AssertIsOnOwningThread();
151
152
if (!mPendingRequestCount) {
153
MOZ_ASSERT(mReadyState == INITIAL);
154
mReadyState = LOADING;
155
}
156
157
++mPendingRequestCount;
158
}
159
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
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
RefPtr<Event> 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
IgnoredErrorResult rv;
209
DispatchEvent(*event, rv);
210
if (rv.Failed()) {
211
NS_WARNING("DispatchEvent failed!");
212
}
213
}
214
215
bool IDBFileHandle::IsOpen() const {
216
AssertIsOnOwningThread();
217
218
// If we haven't started anything then we're open.
219
if (mReadyState == INITIAL) {
220
return true;
221
}
222
223
// If we've already started then we need to check to see if we still have the
224
// mCreating flag set. If we do (i.e. we haven't returned to the event loop
225
// from the time we were created) then we are open. Otherwise check the
226
// currently running file handles to see if it's the same. We only allow other
227
// requests to be made if this file handle is currently running.
228
if (mReadyState == LOADING && (mCreating || GetCurrent() == this)) {
229
return true;
230
}
231
232
return false;
233
}
234
235
void IDBFileHandle::Abort() {
236
AssertIsOnOwningThread();
237
238
if (IsFinishingOrDone()) {
239
// Already started (and maybe finished) the finish or abort so there is
240
// nothing to do here.
241
return;
242
}
243
244
const bool isInvalidated = mMutableFile->IsInvalidated();
245
bool needToSendAbort = mReadyState == INITIAL && !isInvalidated;
246
247
#ifdef DEBUG
248
if (isInvalidated) {
249
mSentFinishOrAbort = true;
250
}
251
#endif
252
253
mAborted = true;
254
mReadyState = DONE;
255
256
// Fire the abort event if there are no outstanding requests. Otherwise the
257
// abort event will be fired when all outstanding requests finish.
258
if (needToSendAbort) {
259
SendAbort();
260
}
261
}
262
263
already_AddRefed<IDBFileRequest> IDBFileHandle::GetMetadata(
264
const IDBFileMetadataParameters& aParameters, ErrorResult& aRv) {
265
AssertIsOnOwningThread();
266
267
// Common state checking
268
if (!CheckState(aRv)) {
269
return nullptr;
270
}
271
272
// Argument checking for get metadata.
273
if (!aParameters.mSize && !aParameters.mLastModified) {
274
aRv.ThrowTypeError(u"Either size or lastModified should be true.");
275
return nullptr;
276
}
277
278
// Do nothing if the window is closed
279
if (!CheckWindow()) {
280
return nullptr;
281
}
282
283
FileRequestGetMetadataParams params;
284
params.size() = aParameters.mSize;
285
params.lastModified() = aParameters.mLastModified;
286
287
RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
288
289
StartRequest(fileRequest, params);
290
291
return fileRequest.forget();
292
}
293
294
already_AddRefed<IDBFileRequest> IDBFileHandle::Truncate(
295
const Optional<uint64_t>& aSize, ErrorResult& aRv) {
296
AssertIsOnOwningThread();
297
298
// State checking for write
299
if (!CheckStateForWrite(aRv)) {
300
return nullptr;
301
}
302
303
// Getting location and additional state checking for truncate
304
uint64_t location;
305
if (aSize.WasPassed()) {
306
// Just in case someone calls us from C++
307
MOZ_ASSERT(aSize.Value() != UINT64_MAX, "Passed wrong size!");
308
location = aSize.Value();
309
} else {
310
if (mLocation == UINT64_MAX) {
311
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
312
return nullptr;
313
}
314
location = mLocation;
315
}
316
317
// Do nothing if the window is closed
318
if (!CheckWindow()) {
319
return nullptr;
320
}
321
322
FileRequestTruncateParams params;
323
params.offset() = location;
324
325
RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
326
327
StartRequest(fileRequest, params);
328
329
if (aSize.WasPassed()) {
330
mLocation = aSize.Value();
331
}
332
333
return fileRequest.forget();
334
}
335
336
already_AddRefed<IDBFileRequest> IDBFileHandle::Flush(ErrorResult& aRv) {
337
AssertIsOnOwningThread();
338
339
// State checking for write
340
if (!CheckStateForWrite(aRv)) {
341
return nullptr;
342
}
343
344
// Do nothing if the window is closed
345
if (!CheckWindow()) {
346
return nullptr;
347
}
348
349
FileRequestFlushParams params;
350
351
RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
352
353
StartRequest(fileRequest, params);
354
355
return fileRequest.forget();
356
}
357
358
void IDBFileHandle::Abort(ErrorResult& aRv) {
359
AssertIsOnOwningThread();
360
361
// This method is special enough for not using generic state checking methods.
362
363
if (IsFinishingOrDone()) {
364
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
365
return;
366
}
367
368
Abort();
369
}
370
371
bool IDBFileHandle::CheckState(ErrorResult& aRv) {
372
if (!IsOpen()) {
373
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_INACTIVE_ERR);
374
return false;
375
}
376
377
return true;
378
}
379
380
bool IDBFileHandle::CheckStateAndArgumentsForRead(uint64_t aSize,
381
ErrorResult& aRv) {
382
// Common state checking
383
if (!CheckState(aRv)) {
384
return false;
385
}
386
387
// Additional state checking for read
388
if (mLocation == UINT64_MAX) {
389
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
390
return false;
391
}
392
393
// Argument checking for read
394
if (!aSize) {
395
aRv.ThrowTypeError(u"0 (Zero) is not a valid read size.");
396
return false;
397
}
398
399
return true;
400
}
401
402
bool IDBFileHandle::CheckStateForWrite(ErrorResult& aRv) {
403
// Common state checking
404
if (!CheckState(aRv)) {
405
return false;
406
}
407
408
// Additional state checking for write
409
if (mMode != FileMode::Readwrite) {
410
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_READ_ONLY_ERR);
411
return false;
412
}
413
414
return true;
415
}
416
417
bool IDBFileHandle::CheckStateForWriteOrAppend(bool aAppend, ErrorResult& aRv) {
418
// State checking for write
419
if (!CheckStateForWrite(aRv)) {
420
return false;
421
}
422
423
// Additional state checking for write
424
if (!aAppend && mLocation == UINT64_MAX) {
425
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
426
return false;
427
}
428
429
return true;
430
}
431
432
bool IDBFileHandle::CheckWindow() {
433
AssertIsOnOwningThread();
434
435
return GetOwner();
436
}
437
438
already_AddRefed<IDBFileRequest> IDBFileHandle::Read(uint64_t aSize,
439
bool aHasEncoding,
440
const nsAString& aEncoding,
441
ErrorResult& aRv) {
442
AssertIsOnOwningThread();
443
444
// State and argument checking for read
445
if (!CheckStateAndArgumentsForRead(aSize, aRv)) {
446
return nullptr;
447
}
448
449
// Do nothing if the window is closed
450
if (!CheckWindow()) {
451
return nullptr;
452
}
453
454
FileRequestReadParams params;
455
params.offset() = mLocation;
456
params.size() = aSize;
457
458
RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
459
if (aHasEncoding) {
460
fileRequest->SetEncoding(aEncoding);
461
}
462
463
StartRequest(fileRequest, params);
464
465
mLocation += aSize;
466
467
return fileRequest.forget();
468
}
469
470
already_AddRefed<IDBFileRequest> IDBFileHandle::WriteOrAppend(
471
const StringOrArrayBufferOrArrayBufferViewOrBlob& aValue, bool aAppend,
472
ErrorResult& aRv) {
473
AssertIsOnOwningThread();
474
475
if (aValue.IsString()) {
476
return WriteOrAppend(aValue.GetAsString(), aAppend, aRv);
477
}
478
479
if (aValue.IsArrayBuffer()) {
480
return WriteOrAppend(aValue.GetAsArrayBuffer(), aAppend, aRv);
481
}
482
483
if (aValue.IsArrayBufferView()) {
484
return WriteOrAppend(aValue.GetAsArrayBufferView(), aAppend, aRv);
485
}
486
487
MOZ_ASSERT(aValue.IsBlob());
488
return WriteOrAppend(aValue.GetAsBlob(), aAppend, aRv);
489
}
490
491
already_AddRefed<IDBFileRequest> IDBFileHandle::WriteOrAppend(
492
const nsAString& aValue, bool aAppend, ErrorResult& aRv) {
493
AssertIsOnOwningThread();
494
495
// State checking for write or append
496
if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
497
return nullptr;
498
}
499
500
NS_ConvertUTF16toUTF8 cstr(aValue);
501
502
uint64_t dataLength = cstr.Length();
503
;
504
if (!dataLength) {
505
return nullptr;
506
}
507
508
FileRequestStringData stringData(cstr);
509
510
// Do nothing if the window is closed
511
if (!CheckWindow()) {
512
return nullptr;
513
}
514
515
return WriteInternal(stringData, dataLength, aAppend, aRv);
516
}
517
518
already_AddRefed<IDBFileRequest> IDBFileHandle::WriteOrAppend(
519
const ArrayBuffer& aValue, bool aAppend, ErrorResult& aRv) {
520
AssertIsOnOwningThread();
521
522
// State checking for write or append
523
if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
524
return nullptr;
525
}
526
527
aValue.ComputeLengthAndData();
528
529
uint64_t dataLength = aValue.Length();
530
;
531
if (!dataLength) {
532
return nullptr;
533
}
534
535
const char* data = reinterpret_cast<const char*>(aValue.Data());
536
537
FileRequestStringData stringData;
538
if (NS_WARN_IF(
539
!stringData.string().Assign(data, aValue.Length(), fallible_t()))) {
540
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
541
return nullptr;
542
}
543
544
// Do nothing if the window is closed
545
if (!CheckWindow()) {
546
return nullptr;
547
}
548
549
return WriteInternal(stringData, dataLength, aAppend, aRv);
550
}
551
552
already_AddRefed<IDBFileRequest> IDBFileHandle::WriteOrAppend(
553
const ArrayBufferView& aValue, bool aAppend, ErrorResult& aRv) {
554
AssertIsOnOwningThread();
555
556
// State checking for write or append
557
if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
558
return nullptr;
559
}
560
561
aValue.ComputeLengthAndData();
562
563
uint64_t dataLength = aValue.Length();
564
;
565
if (!dataLength) {
566
return nullptr;
567
}
568
569
const char* data = reinterpret_cast<const char*>(aValue.Data());
570
571
FileRequestStringData stringData;
572
if (NS_WARN_IF(
573
!stringData.string().Assign(data, aValue.Length(), fallible_t()))) {
574
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
575
return nullptr;
576
}
577
578
// Do nothing if the window is closed
579
if (!CheckWindow()) {
580
return nullptr;
581
}
582
583
return WriteInternal(stringData, dataLength, aAppend, aRv);
584
}
585
586
already_AddRefed<IDBFileRequest> IDBFileHandle::WriteOrAppend(
587
Blob& aValue, bool aAppend, ErrorResult& aRv) {
588
AssertIsOnOwningThread();
589
590
// State checking for write or append
591
if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
592
return nullptr;
593
}
594
595
ErrorResult error;
596
uint64_t dataLength = aValue.GetSize(error);
597
if (NS_WARN_IF(error.Failed())) {
598
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
599
return nullptr;
600
}
601
602
if (!dataLength) {
603
return nullptr;
604
}
605
606
PBackgroundChild* backgroundActor = BackgroundChild::GetForCurrentThread();
607
MOZ_ASSERT(backgroundActor);
608
609
IPCBlob ipcBlob;
610
nsresult rv =
611
IPCBlobUtils::Serialize(aValue.Impl(), backgroundActor, ipcBlob);
612
if (NS_WARN_IF(NS_FAILED(rv))) {
613
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
614
return nullptr;
615
}
616
617
FileRequestBlobData blobData;
618
blobData.blob() = ipcBlob;
619
620
// Do nothing if the window is closed
621
if (!CheckWindow()) {
622
return nullptr;
623
}
624
625
return WriteInternal(blobData, dataLength, aAppend, aRv);
626
}
627
628
already_AddRefed<IDBFileRequest> IDBFileHandle::WriteInternal(
629
const FileRequestData& aData, uint64_t aDataLength, bool aAppend,
630
ErrorResult& aRv) {
631
AssertIsOnOwningThread();
632
633
DebugOnly<ErrorResult> error;
634
MOZ_ASSERT(CheckStateForWrite(error));
635
MOZ_ASSERT_IF(!aAppend, mLocation != UINT64_MAX);
636
MOZ_ASSERT(aDataLength);
637
MOZ_ASSERT(CheckWindow());
638
639
FileRequestWriteParams params;
640
params.offset() = aAppend ? UINT64_MAX : mLocation;
641
params.data() = aData;
642
params.dataLength() = aDataLength;
643
644
RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
645
MOZ_ASSERT(fileRequest);
646
647
StartRequest(fileRequest, params);
648
649
if (aAppend) {
650
mLocation = UINT64_MAX;
651
} else {
652
mLocation += aDataLength;
653
}
654
655
return fileRequest.forget();
656
}
657
658
void IDBFileHandle::SendFinish() {
659
AssertIsOnOwningThread();
660
MOZ_ASSERT(!mAborted);
661
MOZ_ASSERT(IsFinishingOrDone());
662
MOZ_ASSERT(!mSentFinishOrAbort);
663
MOZ_ASSERT(!mPendingRequestCount);
664
665
MOZ_ASSERT(mBackgroundActor);
666
mBackgroundActor->SendFinish();
667
668
#ifdef DEBUG
669
mSentFinishOrAbort = true;
670
#endif
671
}
672
673
void IDBFileHandle::SendAbort() {
674
AssertIsOnOwningThread();
675
MOZ_ASSERT(mAborted);
676
MOZ_ASSERT(IsFinishingOrDone());
677
MOZ_ASSERT(!mSentFinishOrAbort);
678
679
MOZ_ASSERT(mBackgroundActor);
680
mBackgroundActor->SendAbort();
681
682
#ifdef DEBUG
683
mSentFinishOrAbort = true;
684
#endif
685
}
686
687
NS_IMPL_ADDREF_INHERITED(IDBFileHandle, DOMEventTargetHelper)
688
NS_IMPL_RELEASE_INHERITED(IDBFileHandle, DOMEventTargetHelper)
689
690
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBFileHandle)
691
NS_INTERFACE_MAP_ENTRY(nsIRunnable)
692
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
693
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
694
695
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBFileHandle)
696
697
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBFileHandle,
698
DOMEventTargetHelper)
699
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMutableFile)
700
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
701
702
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBFileHandle,
703
DOMEventTargetHelper)
704
// Don't unlink mMutableFile!
705
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
706
707
NS_IMETHODIMP
708
IDBFileHandle::Run() {
709
AssertIsOnOwningThread();
710
711
// We're back at the event loop, no longer newborn.
712
mCreating = false;
713
714
// Maybe finish if there were no requests generated.
715
if (mReadyState == INITIAL) {
716
mReadyState = DONE;
717
718
SendFinish();
719
}
720
721
return NS_OK;
722
}
723
724
void IDBFileHandle::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
725
AssertIsOnOwningThread();
726
727
aVisitor.mCanHandle = true;
728
aVisitor.SetParentTarget(mMutableFile, false);
729
}
730
731
// virtual
732
JSObject* IDBFileHandle::WrapObject(JSContext* aCx,
733
JS::Handle<JSObject*> aGivenProto) {
734
AssertIsOnOwningThread();
735
736
return IDBFileHandle_Binding::Wrap(aCx, this, aGivenProto);
737
}
738
739
} // namespace dom
740
} // namespace mozilla