1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "FileIOObject.h"
7 #include "mozilla/EventDispatcher.h"
10 #include "nsIDOMEvent.h"
11 #include "mozilla/dom/ProgressEvent.h"
12 #include "nsComponentManagerUtils.h"
14 #define ERROR_STR "error"
15 #define ABORT_STR "abort"
16 #define PROGRESS_STR "progress"
21 const uint64_t kUnknownSize
= uint64_t(-1);
23 NS_IMPL_ADDREF_INHERITED(FileIOObject
, DOMEventTargetHelper
)
24 NS_IMPL_RELEASE_INHERITED(FileIOObject
, DOMEventTargetHelper
)
26 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FileIOObject
)
27 NS_INTERFACE_MAP_ENTRY(nsITimerCallback
)
28 NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback
)
29 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper
)
31 NS_IMPL_CYCLE_COLLECTION_CLASS(FileIOObject
)
33 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FileIOObject
,
35 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProgressNotifier
)
36 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError
)
37 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
39 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FileIOObject
,
41 NS_IMPL_CYCLE_COLLECTION_UNLINK(mProgressNotifier
)
42 NS_IMPL_CYCLE_COLLECTION_UNLINK(mError
)
43 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
45 NS_IMPL_EVENT_HANDLER(FileIOObject
, abort
)
46 NS_IMPL_EVENT_HANDLER(FileIOObject
, error
)
47 NS_IMPL_EVENT_HANDLER(FileIOObject
, progress
)
49 FileIOObject::FileIOObject()
50 : mProgressEventWasDelayed(false),
51 mTimerIsActive(false),
53 mTotal(0), mTransferred(0)
56 FileIOObject::~FileIOObject()
60 FileIOObject::StartProgressEventTimer()
62 if (!mProgressNotifier
) {
63 mProgressNotifier
= do_CreateInstance(NS_TIMER_CONTRACTID
);
65 if (mProgressNotifier
) {
66 mProgressEventWasDelayed
= false;
67 mTimerIsActive
= true;
68 mProgressNotifier
->Cancel();
69 mProgressNotifier
->InitWithCallback(this, NS_PROGRESS_EVENT_INTERVAL
,
70 nsITimer::TYPE_ONE_SHOT
);
75 FileIOObject::ClearProgressEventTimer()
77 mProgressEventWasDelayed
= false;
78 mTimerIsActive
= false;
79 if (mProgressNotifier
) {
80 mProgressNotifier
->Cancel();
85 FileIOObject::DispatchError(nsresult rv
, nsAString
& finalEvent
)
87 // Set the status attribute, and dispatch the error event
89 case NS_ERROR_FILE_NOT_FOUND
:
90 mError
= new DOMError(GetOwner(), NS_LITERAL_STRING("NotFoundError"));
92 case NS_ERROR_FILE_ACCESS_DENIED
:
93 mError
= new DOMError(GetOwner(), NS_LITERAL_STRING("SecurityError"));
96 mError
= new DOMError(GetOwner(), NS_LITERAL_STRING("NotReadableError"));
100 // Dispatch error event to signify load failure
101 DispatchProgressEvent(NS_LITERAL_STRING(ERROR_STR
));
102 DispatchProgressEvent(finalEvent
);
106 FileIOObject::DispatchProgressEvent(const nsAString
& aType
)
108 ProgressEventInit init
;
109 init
.mBubbles
= false;
110 init
.mCancelable
= false;
111 init
.mLoaded
= mTransferred
;
113 if (mTotal
!= kUnknownSize
) {
114 init
.mLengthComputable
= true;
115 init
.mTotal
= mTotal
;
117 init
.mLengthComputable
= false;
120 nsRefPtr
<ProgressEvent
> event
=
121 ProgressEvent::Constructor(this, aType
, init
);
122 event
->SetTrusted(true);
124 return DispatchDOMEvent(nullptr, event
, nullptr, nullptr);
129 FileIOObject::Notify(nsITimer
* aTimer
)
132 mTimerIsActive
= false;
134 if (mProgressEventWasDelayed
) {
135 rv
= DispatchProgressEvent(NS_LITERAL_STRING("progress"));
136 NS_ENSURE_SUCCESS(rv
, rv
);
138 StartProgressEventTimer();
144 // InputStreamCallback
146 FileIOObject::OnInputStreamReady(nsIAsyncInputStream
* aStream
)
148 if (mReadyState
!= 1 || aStream
!= mAsyncStream
) {
153 nsresult rv
= aStream
->Available(&aCount
);
155 if (NS_SUCCEEDED(rv
) && aCount
) {
156 rv
= DoReadData(aStream
, aCount
);
159 if (NS_SUCCEEDED(rv
)) {
160 rv
= DoAsyncWait(aStream
);
163 if (NS_FAILED(rv
) || !aCount
) {
164 if (rv
== NS_BASE_STREAM_CLOSED
) {
167 return OnLoadEnd(rv
);
170 mTransferred
+= aCount
;
172 //Notify the timer is the appropriate timeframe has passed
173 if (mTimerIsActive
) {
174 mProgressEventWasDelayed
= true;
176 rv
= DispatchProgressEvent(NS_LITERAL_STRING(PROGRESS_STR
));
177 NS_ENSURE_SUCCESS(rv
, rv
);
179 StartProgressEventTimer();
186 FileIOObject::OnLoadEnd(nsresult aStatus
)
188 // Cancel the progress event timer
189 ClearProgressEventTimer();
191 // FileIOObject must be in DONE stage after an operation
194 nsString successEvent
, termEvent
;
195 nsresult rv
= DoOnLoadEnd(aStatus
, successEvent
, termEvent
);
196 NS_ENSURE_SUCCESS(rv
, rv
);
198 // Set the status field as appropriate
199 if (NS_FAILED(aStatus
)) {
200 DispatchError(aStatus
, termEvent
);
204 // Dispatch event to signify end of a successful operation
205 DispatchProgressEvent(successEvent
);
206 DispatchProgressEvent(termEvent
);
212 FileIOObject::DoAsyncWait(nsIAsyncInputStream
* aStream
)
214 return aStream
->AsyncWait(this,
216 /* aRequestedCount */ 0,
217 NS_GetCurrentThread());
221 FileIOObject::Abort(ErrorResult
& aRv
)
223 if (mReadyState
!= 1) {
224 // XXX The spec doesn't say this
225 aRv
.Throw(NS_ERROR_DOM_FILE_ABORT_ERR
);
229 ClearProgressEventTimer();
231 mReadyState
= 2; // There are DONE constants on multiple interfaces,
232 // but they all have value 2.
233 // XXX The spec doesn't say this
234 mError
= new DOMError(GetOwner(), NS_LITERAL_STRING("AbortError"));
239 // Dispatch the events
240 DispatchProgressEvent(NS_LITERAL_STRING(ABORT_STR
));
241 DispatchProgressEvent(finalEvent
);
245 } // namespace mozilla