|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=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 "ArchiveRequest.h" |
|
8 |
|
9 #include "mozilla/EventDispatcher.h" |
|
10 #include "mozilla/dom/ArchiveRequestBinding.h" |
|
11 #include "nsContentUtils.h" |
|
12 #include "nsCxPusher.h" |
|
13 |
|
14 using namespace mozilla; |
|
15 |
|
16 USING_FILE_NAMESPACE |
|
17 |
|
18 /** |
|
19 * Class used to make asynchronous the ArchiveRequest. |
|
20 */ |
|
21 class ArchiveRequestEvent : public nsRunnable |
|
22 { |
|
23 public: |
|
24 NS_DECL_NSIRUNNABLE |
|
25 |
|
26 ArchiveRequestEvent(ArchiveRequest* request) |
|
27 : mRequest(request) |
|
28 { |
|
29 MOZ_COUNT_CTOR(ArchiveRequestEvent); |
|
30 } |
|
31 |
|
32 ~ArchiveRequestEvent() |
|
33 { |
|
34 MOZ_COUNT_DTOR(ArchiveRequestEvent); |
|
35 } |
|
36 |
|
37 private: //data |
|
38 nsRefPtr<ArchiveRequest> mRequest; |
|
39 }; |
|
40 |
|
41 NS_IMETHODIMP |
|
42 ArchiveRequestEvent::Run() |
|
43 { |
|
44 NS_ABORT_IF_FALSE(mRequest, "the request is not longer valid"); |
|
45 mRequest->Run(); |
|
46 return NS_OK; |
|
47 } |
|
48 |
|
49 // ArchiveRequest |
|
50 |
|
51 ArchiveRequest::ArchiveRequest(nsPIDOMWindow* aWindow, |
|
52 ArchiveReader* aReader) |
|
53 : DOMRequest(aWindow), |
|
54 mArchiveReader(aReader) |
|
55 { |
|
56 MOZ_ASSERT(aReader); |
|
57 |
|
58 MOZ_COUNT_CTOR(ArchiveRequest); |
|
59 |
|
60 /* An event to make this request asynchronous: */ |
|
61 nsRefPtr<ArchiveRequestEvent> event = new ArchiveRequestEvent(this); |
|
62 NS_DispatchToCurrentThread(event); |
|
63 } |
|
64 |
|
65 ArchiveRequest::~ArchiveRequest() |
|
66 { |
|
67 MOZ_COUNT_DTOR(ArchiveRequest); |
|
68 } |
|
69 |
|
70 nsresult |
|
71 ArchiveRequest::PreHandleEvent(EventChainPreVisitor& aVisitor) |
|
72 { |
|
73 aVisitor.mCanHandle = true; |
|
74 aVisitor.mParentTarget = nullptr; |
|
75 return NS_OK; |
|
76 } |
|
77 |
|
78 /* virtual */ JSObject* |
|
79 ArchiveRequest::WrapObject(JSContext* aCx) |
|
80 { |
|
81 return ArchiveRequestBinding::Wrap(aCx, this); |
|
82 } |
|
83 |
|
84 ArchiveReader* |
|
85 ArchiveRequest::Reader() const |
|
86 { |
|
87 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
|
88 |
|
89 return mArchiveReader; |
|
90 } |
|
91 |
|
92 // Here the request is processed: |
|
93 void |
|
94 ArchiveRequest::Run() |
|
95 { |
|
96 // Register this request to the reader. |
|
97 // When the reader is ready to return data, a 'Ready()' will be called |
|
98 nsresult rv = mArchiveReader->RegisterRequest(this); |
|
99 if (NS_FAILED(rv)) { |
|
100 FireError(rv); |
|
101 } |
|
102 } |
|
103 |
|
104 void |
|
105 ArchiveRequest::OpGetFilenames() |
|
106 { |
|
107 mOperation = GetFilenames; |
|
108 } |
|
109 |
|
110 void |
|
111 ArchiveRequest::OpGetFile(const nsAString& aFilename) |
|
112 { |
|
113 mOperation = GetFile; |
|
114 mFilename = aFilename; |
|
115 } |
|
116 |
|
117 void |
|
118 ArchiveRequest::OpGetFiles() |
|
119 { |
|
120 mOperation = GetFiles; |
|
121 } |
|
122 |
|
123 nsresult |
|
124 ArchiveRequest::ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList, |
|
125 nsresult aStatus) |
|
126 { |
|
127 if (NS_FAILED(aStatus)) { |
|
128 FireError(aStatus); |
|
129 return NS_OK; |
|
130 } |
|
131 |
|
132 nsresult rv; |
|
133 |
|
134 nsIScriptContext* sc = GetContextForEventHandlers(&rv); |
|
135 NS_ENSURE_STATE(sc); |
|
136 |
|
137 AutoPushJSContext cx(sc->GetNativeContext()); |
|
138 NS_ASSERTION(cx, "Failed to get a context!"); |
|
139 |
|
140 JS::Rooted<JSObject*> global(cx, sc->GetWindowProxy()); |
|
141 NS_ASSERTION(global, "Failed to get global object!"); |
|
142 |
|
143 JSAutoCompartment ac(cx, global); |
|
144 |
|
145 JS::Rooted<JS::Value> result(cx); |
|
146 switch (mOperation) { |
|
147 case GetFilenames: |
|
148 rv = GetFilenamesResult(cx, result.address(), aFileList); |
|
149 break; |
|
150 |
|
151 case GetFile: |
|
152 rv = GetFileResult(cx, &result, aFileList); |
|
153 break; |
|
154 |
|
155 case GetFiles: |
|
156 rv = GetFilesResult(cx, &result, aFileList); |
|
157 break; |
|
158 } |
|
159 |
|
160 if (NS_FAILED(rv)) { |
|
161 NS_WARNING("Get*Result failed!"); |
|
162 } |
|
163 |
|
164 if (NS_SUCCEEDED(rv)) { |
|
165 FireSuccess(result); |
|
166 } |
|
167 else { |
|
168 FireError(rv); |
|
169 } |
|
170 |
|
171 return NS_OK; |
|
172 } |
|
173 |
|
174 nsresult |
|
175 ArchiveRequest::GetFilenamesResult(JSContext* aCx, |
|
176 JS::Value* aValue, |
|
177 nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList) |
|
178 { |
|
179 JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, aFileList.Length())); |
|
180 nsresult rv; |
|
181 |
|
182 if (!array) { |
|
183 return NS_ERROR_OUT_OF_MEMORY; |
|
184 } |
|
185 |
|
186 JS::Rooted<JSString*> str(aCx); |
|
187 for (uint32_t i = 0; i < aFileList.Length(); ++i) { |
|
188 nsCOMPtr<nsIDOMFile> file = aFileList[i]; |
|
189 |
|
190 nsString filename; |
|
191 rv = file->GetName(filename); |
|
192 NS_ENSURE_SUCCESS(rv, rv); |
|
193 |
|
194 str = JS_NewUCStringCopyZ(aCx, filename.get()); |
|
195 NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY); |
|
196 |
|
197 if (NS_FAILED(rv) || |
|
198 !JS_DefineElement(aCx, array, i, JS::StringValue(str), nullptr, nullptr, |
|
199 JSPROP_ENUMERATE)) { |
|
200 return NS_ERROR_FAILURE; |
|
201 } |
|
202 } |
|
203 |
|
204 if (!JS_FreezeObject(aCx, array)) { |
|
205 return NS_ERROR_FAILURE; |
|
206 } |
|
207 |
|
208 *aValue = OBJECT_TO_JSVAL(array); |
|
209 return NS_OK; |
|
210 } |
|
211 |
|
212 nsresult |
|
213 ArchiveRequest::GetFileResult(JSContext* aCx, |
|
214 JS::MutableHandle<JS::Value> aValue, |
|
215 nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList) |
|
216 { |
|
217 for (uint32_t i = 0; i < aFileList.Length(); ++i) { |
|
218 nsCOMPtr<nsIDOMFile> file = aFileList[i]; |
|
219 |
|
220 nsString filename; |
|
221 nsresult rv = file->GetName(filename); |
|
222 NS_ENSURE_SUCCESS(rv, rv); |
|
223 |
|
224 if (filename == mFilename) { |
|
225 return nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile), |
|
226 aValue); |
|
227 } |
|
228 } |
|
229 |
|
230 return NS_ERROR_FAILURE; |
|
231 } |
|
232 |
|
233 nsresult |
|
234 ArchiveRequest::GetFilesResult(JSContext* aCx, |
|
235 JS::MutableHandle<JS::Value> aValue, |
|
236 nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList) |
|
237 { |
|
238 JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, aFileList.Length())); |
|
239 if (!array) { |
|
240 return NS_ERROR_OUT_OF_MEMORY; |
|
241 } |
|
242 |
|
243 for (uint32_t i = 0; i < aFileList.Length(); ++i) { |
|
244 nsCOMPtr<nsIDOMFile> file = aFileList[i]; |
|
245 |
|
246 JS::Rooted<JS::Value> value(aCx); |
|
247 nsresult rv = nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile), |
|
248 &value); |
|
249 if (NS_FAILED(rv) || |
|
250 !JS_DefineElement(aCx, array, i, value, nullptr, nullptr, |
|
251 JSPROP_ENUMERATE)) { |
|
252 return NS_ERROR_FAILURE; |
|
253 } |
|
254 } |
|
255 |
|
256 aValue.setObject(*array); |
|
257 return NS_OK; |
|
258 } |
|
259 |
|
260 // static |
|
261 already_AddRefed<ArchiveRequest> |
|
262 ArchiveRequest::Create(nsPIDOMWindow* aOwner, |
|
263 ArchiveReader* aReader) |
|
264 { |
|
265 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
|
266 |
|
267 nsRefPtr<ArchiveRequest> request = new ArchiveRequest(aOwner, aReader); |
|
268 |
|
269 return request.forget(); |
|
270 } |
|
271 |
|
272 NS_IMPL_CYCLE_COLLECTION_INHERITED(ArchiveRequest, DOMRequest, |
|
273 mArchiveReader) |
|
274 |
|
275 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ArchiveRequest) |
|
276 NS_INTERFACE_MAP_END_INHERITING(DOMRequest) |
|
277 |
|
278 NS_IMPL_ADDREF_INHERITED(ArchiveRequest, DOMRequest) |
|
279 NS_IMPL_RELEASE_INHERITED(ArchiveRequest, DOMRequest) |