|
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/. */ |
|
5 |
|
6 #include "mozilla/ArrayUtils.h" |
|
7 |
|
8 #include "nsCOMPtr.h" |
|
9 #include "nsNetUtil.h" |
|
10 #include "nsXBLService.h" |
|
11 #include "nsXBLWindowKeyHandler.h" |
|
12 #include "nsIInputStream.h" |
|
13 #include "nsNameSpaceManager.h" |
|
14 #include "nsIURI.h" |
|
15 #include "nsIDOMElement.h" |
|
16 #include "nsIURL.h" |
|
17 #include "nsIChannel.h" |
|
18 #include "nsXPIDLString.h" |
|
19 #include "plstr.h" |
|
20 #include "nsIContent.h" |
|
21 #include "nsIDocument.h" |
|
22 #include "nsIXMLContentSink.h" |
|
23 #include "nsContentCID.h" |
|
24 #include "mozilla/dom/XMLDocument.h" |
|
25 #include "nsGkAtoms.h" |
|
26 #include "nsIMemory.h" |
|
27 #include "nsIObserverService.h" |
|
28 #include "nsIDOMNodeList.h" |
|
29 #include "nsXBLContentSink.h" |
|
30 #include "nsXBLBinding.h" |
|
31 #include "nsXBLPrototypeBinding.h" |
|
32 #include "nsXBLDocumentInfo.h" |
|
33 #include "nsCRT.h" |
|
34 #include "nsContentUtils.h" |
|
35 #include "nsSyncLoadService.h" |
|
36 #include "nsContentPolicyUtils.h" |
|
37 #include "nsTArray.h" |
|
38 #include "nsError.h" |
|
39 |
|
40 #include "nsIPresShell.h" |
|
41 #include "nsIDocumentObserver.h" |
|
42 #include "nsFrameManager.h" |
|
43 #include "nsStyleContext.h" |
|
44 #include "nsIScriptSecurityManager.h" |
|
45 #include "nsIScriptError.h" |
|
46 #include "nsXBLSerialize.h" |
|
47 |
|
48 #ifdef MOZ_XUL |
|
49 #include "nsXULPrototypeCache.h" |
|
50 #endif |
|
51 #include "nsIDOMEventListener.h" |
|
52 #include "mozilla/Attributes.h" |
|
53 #include "mozilla/EventListenerManager.h" |
|
54 #include "mozilla/Preferences.h" |
|
55 #include "mozilla/dom/Event.h" |
|
56 #include "mozilla/dom/Element.h" |
|
57 |
|
58 using namespace mozilla; |
|
59 using namespace mozilla::dom; |
|
60 |
|
61 #define NS_MAX_XBL_BINDING_RECURSION 20 |
|
62 |
|
63 nsXBLService* nsXBLService::gInstance = nullptr; |
|
64 |
|
65 static bool |
|
66 IsAncestorBinding(nsIDocument* aDocument, |
|
67 nsIURI* aChildBindingURI, |
|
68 nsIContent* aChild) |
|
69 { |
|
70 NS_ASSERTION(aDocument, "expected a document"); |
|
71 NS_ASSERTION(aChildBindingURI, "expected a binding URI"); |
|
72 NS_ASSERTION(aChild, "expected a child content"); |
|
73 |
|
74 uint32_t bindingRecursion = 0; |
|
75 for (nsIContent *bindingParent = aChild->GetBindingParent(); |
|
76 bindingParent; |
|
77 bindingParent = bindingParent->GetBindingParent()) { |
|
78 nsXBLBinding* binding = bindingParent->GetXBLBinding(); |
|
79 if (!binding) { |
|
80 continue; |
|
81 } |
|
82 |
|
83 if (binding->PrototypeBinding()->CompareBindingURI(aChildBindingURI)) { |
|
84 ++bindingRecursion; |
|
85 if (bindingRecursion < NS_MAX_XBL_BINDING_RECURSION) { |
|
86 continue; |
|
87 } |
|
88 nsAutoCString spec; |
|
89 aChildBindingURI->GetSpec(spec); |
|
90 NS_ConvertUTF8toUTF16 bindingURI(spec); |
|
91 const char16_t* params[] = { bindingURI.get() }; |
|
92 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, |
|
93 NS_LITERAL_CSTRING("XBL"), aDocument, |
|
94 nsContentUtils::eXBL_PROPERTIES, |
|
95 "TooDeepBindingRecursion", |
|
96 params, ArrayLength(params)); |
|
97 return true; |
|
98 } |
|
99 } |
|
100 |
|
101 return false; |
|
102 } |
|
103 |
|
104 // Individual binding requests. |
|
105 class nsXBLBindingRequest |
|
106 { |
|
107 public: |
|
108 nsCOMPtr<nsIURI> mBindingURI; |
|
109 nsCOMPtr<nsIContent> mBoundElement; |
|
110 |
|
111 void DocumentLoaded(nsIDocument* aBindingDoc) |
|
112 { |
|
113 // We only need the document here to cause frame construction, so |
|
114 // we need the current doc, not the owner doc. |
|
115 nsIDocument* doc = mBoundElement->GetCurrentDoc(); |
|
116 if (!doc) |
|
117 return; |
|
118 |
|
119 // Get the binding. |
|
120 bool ready = false; |
|
121 nsXBLService::GetInstance()->BindingReady(mBoundElement, mBindingURI, &ready); |
|
122 if (!ready) |
|
123 return; |
|
124 |
|
125 // If |mBoundElement| is (in addition to having binding |mBinding|) |
|
126 // also a descendant of another element with binding |mBinding|, |
|
127 // then we might have just constructed it due to the |
|
128 // notification of its parent. (We can know about both if the |
|
129 // binding loads were triggered from the DOM rather than frame |
|
130 // construction.) So we have to check both whether the element |
|
131 // has a primary frame and whether it's in the undisplayed map |
|
132 // before sending a ContentInserted notification, or bad things |
|
133 // will happen. |
|
134 nsIPresShell *shell = doc->GetShell(); |
|
135 if (shell) { |
|
136 nsIFrame* childFrame = mBoundElement->GetPrimaryFrame(); |
|
137 if (!childFrame) { |
|
138 // Check to see if it's in the undisplayed content map. |
|
139 nsStyleContext* sc = |
|
140 shell->FrameManager()->GetUndisplayedContent(mBoundElement); |
|
141 |
|
142 if (!sc) { |
|
143 shell->RecreateFramesFor(mBoundElement); |
|
144 } |
|
145 } |
|
146 } |
|
147 } |
|
148 |
|
149 nsXBLBindingRequest(nsIURI* aURI, nsIContent* aBoundElement) |
|
150 : mBindingURI(aURI), |
|
151 mBoundElement(aBoundElement) |
|
152 { |
|
153 } |
|
154 }; |
|
155 |
|
156 // nsXBLStreamListener, a helper class used for |
|
157 // asynchronous parsing of URLs |
|
158 /* Header file */ |
|
159 class nsXBLStreamListener MOZ_FINAL : public nsIStreamListener, |
|
160 public nsIDOMEventListener |
|
161 { |
|
162 public: |
|
163 NS_DECL_ISUPPORTS |
|
164 NS_DECL_NSISTREAMLISTENER |
|
165 NS_DECL_NSIREQUESTOBSERVER |
|
166 NS_DECL_NSIDOMEVENTLISTENER |
|
167 |
|
168 nsXBLStreamListener(nsIDocument* aBoundDocument, |
|
169 nsIXMLContentSink* aSink, |
|
170 nsIDocument* aBindingDocument); |
|
171 ~nsXBLStreamListener(); |
|
172 |
|
173 void AddRequest(nsXBLBindingRequest* aRequest) { mBindingRequests.AppendElement(aRequest); } |
|
174 bool HasRequest(nsIURI* aURI, nsIContent* aBoundElement); |
|
175 |
|
176 private: |
|
177 nsCOMPtr<nsIStreamListener> mInner; |
|
178 nsAutoTArray<nsXBLBindingRequest*, 8> mBindingRequests; |
|
179 |
|
180 nsCOMPtr<nsIWeakReference> mBoundDocument; |
|
181 nsCOMPtr<nsIXMLContentSink> mSink; // Only set until OnStartRequest |
|
182 nsCOMPtr<nsIDocument> mBindingDocument; // Only set until OnStartRequest |
|
183 }; |
|
184 |
|
185 /* Implementation file */ |
|
186 NS_IMPL_ISUPPORTS(nsXBLStreamListener, |
|
187 nsIStreamListener, |
|
188 nsIRequestObserver, |
|
189 nsIDOMEventListener) |
|
190 |
|
191 nsXBLStreamListener::nsXBLStreamListener(nsIDocument* aBoundDocument, |
|
192 nsIXMLContentSink* aSink, |
|
193 nsIDocument* aBindingDocument) |
|
194 : mSink(aSink), mBindingDocument(aBindingDocument) |
|
195 { |
|
196 /* member initializers and constructor code */ |
|
197 mBoundDocument = do_GetWeakReference(aBoundDocument); |
|
198 } |
|
199 |
|
200 nsXBLStreamListener::~nsXBLStreamListener() |
|
201 { |
|
202 for (uint32_t i = 0; i < mBindingRequests.Length(); i++) { |
|
203 nsXBLBindingRequest* req = mBindingRequests.ElementAt(i); |
|
204 delete req; |
|
205 } |
|
206 } |
|
207 |
|
208 NS_IMETHODIMP |
|
209 nsXBLStreamListener::OnDataAvailable(nsIRequest *request, nsISupports* aCtxt, |
|
210 nsIInputStream* aInStr, |
|
211 uint64_t aSourceOffset, uint32_t aCount) |
|
212 { |
|
213 if (mInner) |
|
214 return mInner->OnDataAvailable(request, aCtxt, aInStr, aSourceOffset, aCount); |
|
215 return NS_ERROR_FAILURE; |
|
216 } |
|
217 |
|
218 NS_IMETHODIMP |
|
219 nsXBLStreamListener::OnStartRequest(nsIRequest* request, nsISupports* aCtxt) |
|
220 { |
|
221 // Make sure we don't hold on to the sink and binding document past this point |
|
222 nsCOMPtr<nsIXMLContentSink> sink; |
|
223 mSink.swap(sink); |
|
224 nsCOMPtr<nsIDocument> doc; |
|
225 mBindingDocument.swap(doc); |
|
226 |
|
227 nsCOMPtr<nsIChannel> channel = do_QueryInterface(request); |
|
228 NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED); |
|
229 |
|
230 nsCOMPtr<nsILoadGroup> group; |
|
231 request->GetLoadGroup(getter_AddRefs(group)); |
|
232 |
|
233 nsresult rv = doc->StartDocumentLoad("loadAsInteractiveData", |
|
234 channel, |
|
235 group, |
|
236 nullptr, |
|
237 getter_AddRefs(mInner), |
|
238 true, |
|
239 sink); |
|
240 NS_ENSURE_SUCCESS(rv, rv); |
|
241 |
|
242 // Make sure to add ourselves as a listener after StartDocumentLoad, |
|
243 // since that resets the event listners on the document. |
|
244 doc->AddEventListener(NS_LITERAL_STRING("load"), this, false); |
|
245 |
|
246 return mInner->OnStartRequest(request, aCtxt); |
|
247 } |
|
248 |
|
249 NS_IMETHODIMP |
|
250 nsXBLStreamListener::OnStopRequest(nsIRequest* request, nsISupports* aCtxt, nsresult aStatus) |
|
251 { |
|
252 nsresult rv = NS_OK; |
|
253 if (mInner) { |
|
254 rv = mInner->OnStopRequest(request, aCtxt, aStatus); |
|
255 } |
|
256 |
|
257 // Don't hold onto the inner listener; holding onto it can create a cycle |
|
258 // with the document |
|
259 mInner = nullptr; |
|
260 |
|
261 return rv; |
|
262 } |
|
263 |
|
264 bool |
|
265 nsXBLStreamListener::HasRequest(nsIURI* aURI, nsIContent* aElt) |
|
266 { |
|
267 // XXX Could be more efficient. |
|
268 uint32_t count = mBindingRequests.Length(); |
|
269 for (uint32_t i = 0; i < count; i++) { |
|
270 nsXBLBindingRequest* req = mBindingRequests.ElementAt(i); |
|
271 bool eq; |
|
272 if (req->mBoundElement == aElt && |
|
273 NS_SUCCEEDED(req->mBindingURI->Equals(aURI, &eq)) && eq) |
|
274 return true; |
|
275 } |
|
276 |
|
277 return false; |
|
278 } |
|
279 |
|
280 nsresult |
|
281 nsXBLStreamListener::HandleEvent(nsIDOMEvent* aEvent) |
|
282 { |
|
283 nsresult rv = NS_OK; |
|
284 uint32_t i; |
|
285 uint32_t count = mBindingRequests.Length(); |
|
286 |
|
287 // Get the binding document; note that we don't hold onto it in this object |
|
288 // to avoid creating a cycle |
|
289 Event* event = aEvent->InternalDOMEvent(); |
|
290 EventTarget* target = event->GetCurrentTarget(); |
|
291 nsCOMPtr<nsIDocument> bindingDocument = do_QueryInterface(target); |
|
292 NS_ASSERTION(bindingDocument, "Event not targeted at document?!"); |
|
293 |
|
294 // See if we're still alive. |
|
295 nsCOMPtr<nsIDocument> doc(do_QueryReferent(mBoundDocument)); |
|
296 if (!doc) { |
|
297 NS_WARNING("XBL load did not complete until after document went away! Modal dialog bug?\n"); |
|
298 } |
|
299 else { |
|
300 // We have to do a flush prior to notification of the document load. |
|
301 // This has to happen since the HTML content sink can be holding on |
|
302 // to notifications related to our children (e.g., if you bind to the |
|
303 // <body> tag) that result in duplication of content. |
|
304 // We need to get the sink's notifications flushed and then make the binding |
|
305 // ready. |
|
306 if (count > 0) { |
|
307 nsXBLBindingRequest* req = mBindingRequests.ElementAt(0); |
|
308 nsIDocument* document = req->mBoundElement->GetCurrentDoc(); |
|
309 if (document) |
|
310 document->FlushPendingNotifications(Flush_ContentAndNotify); |
|
311 } |
|
312 |
|
313 // Remove ourselves from the set of pending docs. |
|
314 nsBindingManager *bindingManager = doc->BindingManager(); |
|
315 nsIURI* documentURI = bindingDocument->GetDocumentURI(); |
|
316 bindingManager->RemoveLoadingDocListener(documentURI); |
|
317 |
|
318 if (!bindingDocument->GetRootElement()) { |
|
319 // FIXME: How about an error console warning? |
|
320 NS_WARNING("XBL doc with no root element - this usually shouldn't happen"); |
|
321 return NS_ERROR_FAILURE; |
|
322 } |
|
323 |
|
324 // Put our doc info in the doc table. |
|
325 nsBindingManager *xblDocBindingManager = bindingDocument->BindingManager(); |
|
326 nsRefPtr<nsXBLDocumentInfo> info = |
|
327 xblDocBindingManager->GetXBLDocumentInfo(documentURI); |
|
328 xblDocBindingManager->RemoveXBLDocumentInfo(info); // Break the self-imposed cycle. |
|
329 if (!info) { |
|
330 if (nsXBLService::IsChromeOrResourceURI(documentURI)) { |
|
331 NS_WARNING("An XBL file is malformed. Did you forget the XBL namespace on the bindings tag?"); |
|
332 } |
|
333 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, |
|
334 NS_LITERAL_CSTRING("XBL"), nullptr, |
|
335 nsContentUtils::eXBL_PROPERTIES, |
|
336 "MalformedXBL", |
|
337 nullptr, 0, documentURI); |
|
338 return NS_ERROR_FAILURE; |
|
339 } |
|
340 |
|
341 // If the doc is a chrome URI, then we put it into the XUL cache. |
|
342 #ifdef MOZ_XUL |
|
343 if (nsXBLService::IsChromeOrResourceURI(documentURI)) { |
|
344 nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance(); |
|
345 if (cache && cache->IsEnabled()) |
|
346 cache->PutXBLDocumentInfo(info); |
|
347 } |
|
348 #endif |
|
349 |
|
350 bindingManager->PutXBLDocumentInfo(info); |
|
351 |
|
352 // Notify all pending requests that their bindings are |
|
353 // ready and can be installed. |
|
354 for (i = 0; i < count; i++) { |
|
355 nsXBLBindingRequest* req = mBindingRequests.ElementAt(i); |
|
356 req->DocumentLoaded(bindingDocument); |
|
357 } |
|
358 } |
|
359 |
|
360 target->RemoveEventListener(NS_LITERAL_STRING("load"), this, false); |
|
361 |
|
362 return rv; |
|
363 } |
|
364 |
|
365 // Implementation ///////////////////////////////////////////////////////////////// |
|
366 |
|
367 // Static member variable initialization |
|
368 bool nsXBLService::gAllowDataURIs = false; |
|
369 |
|
370 // Implement our nsISupports methods |
|
371 NS_IMPL_ISUPPORTS(nsXBLService, nsISupportsWeakReference) |
|
372 |
|
373 void |
|
374 nsXBLService::Init() |
|
375 { |
|
376 gInstance = new nsXBLService(); |
|
377 NS_ADDREF(gInstance); |
|
378 } |
|
379 |
|
380 // Constructors/Destructors |
|
381 nsXBLService::nsXBLService(void) |
|
382 { |
|
383 Preferences::AddBoolVarCache(&gAllowDataURIs, "layout.debug.enable_data_xbl"); |
|
384 } |
|
385 |
|
386 nsXBLService::~nsXBLService(void) |
|
387 { |
|
388 } |
|
389 |
|
390 // static |
|
391 bool |
|
392 nsXBLService::IsChromeOrResourceURI(nsIURI* aURI) |
|
393 { |
|
394 bool isChrome = false; |
|
395 bool isResource = false; |
|
396 if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && |
|
397 NS_SUCCEEDED(aURI->SchemeIs("resource", &isResource))) |
|
398 return (isChrome || isResource); |
|
399 return false; |
|
400 } |
|
401 |
|
402 |
|
403 // This function loads a particular XBL file and installs all of the bindings |
|
404 // onto the element. |
|
405 nsresult |
|
406 nsXBLService::LoadBindings(nsIContent* aContent, nsIURI* aURL, |
|
407 nsIPrincipal* aOriginPrincipal, |
|
408 nsXBLBinding** aBinding, bool* aResolveStyle) |
|
409 { |
|
410 NS_PRECONDITION(aOriginPrincipal, "Must have an origin principal"); |
|
411 |
|
412 *aBinding = nullptr; |
|
413 *aResolveStyle = false; |
|
414 |
|
415 nsresult rv; |
|
416 |
|
417 nsCOMPtr<nsIDocument> document = aContent->OwnerDoc(); |
|
418 |
|
419 nsAutoCString urlspec; |
|
420 if (nsContentUtils::GetWrapperSafeScriptFilename(document, aURL, urlspec)) { |
|
421 // Block an attempt to load a binding that has special wrapper |
|
422 // automation needs. |
|
423 |
|
424 return NS_OK; |
|
425 } |
|
426 |
|
427 nsXBLBinding *binding = aContent->GetXBLBinding(); |
|
428 if (binding) { |
|
429 if (binding->MarkedForDeath()) { |
|
430 FlushStyleBindings(aContent); |
|
431 binding = nullptr; |
|
432 } |
|
433 else { |
|
434 // See if the URIs match. |
|
435 if (binding->PrototypeBinding()->CompareBindingURI(aURL)) |
|
436 return NS_OK; |
|
437 FlushStyleBindings(aContent); |
|
438 binding = nullptr; |
|
439 } |
|
440 } |
|
441 |
|
442 bool ready; |
|
443 nsRefPtr<nsXBLBinding> newBinding; |
|
444 if (NS_FAILED(rv = GetBinding(aContent, aURL, false, aOriginPrincipal, |
|
445 &ready, getter_AddRefs(newBinding)))) { |
|
446 return rv; |
|
447 } |
|
448 |
|
449 if (!newBinding) { |
|
450 #ifdef DEBUG |
|
451 nsAutoCString spec; |
|
452 aURL->GetSpec(spec); |
|
453 nsAutoCString str(NS_LITERAL_CSTRING("Failed to locate XBL binding. XBL is now using id instead of name to reference bindings. Make sure you have switched over. The invalid binding name is: ") + spec); |
|
454 NS_ERROR(str.get()); |
|
455 #endif |
|
456 return NS_OK; |
|
457 } |
|
458 |
|
459 if (::IsAncestorBinding(document, aURL, aContent)) { |
|
460 return NS_ERROR_ILLEGAL_VALUE; |
|
461 } |
|
462 |
|
463 // We loaded a style binding. It goes on the end. |
|
464 if (binding) { |
|
465 // Get the last binding that is in the append layer. |
|
466 binding->RootBinding()->SetBaseBinding(newBinding); |
|
467 } |
|
468 else { |
|
469 // Install the binding on the content node. |
|
470 aContent->SetXBLBinding(newBinding); |
|
471 } |
|
472 |
|
473 { |
|
474 nsAutoScriptBlocker scriptBlocker; |
|
475 |
|
476 // Set the binding's bound element. |
|
477 newBinding->SetBoundElement(aContent); |
|
478 |
|
479 // Tell the binding to build the anonymous content. |
|
480 newBinding->GenerateAnonymousContent(); |
|
481 |
|
482 // Tell the binding to install event handlers |
|
483 newBinding->InstallEventHandlers(); |
|
484 |
|
485 // Set up our properties |
|
486 rv = newBinding->InstallImplementation(); |
|
487 NS_ENSURE_SUCCESS(rv, rv); |
|
488 |
|
489 // Figure out if we have any scoped sheets. If so, we do a second resolve. |
|
490 *aResolveStyle = newBinding->HasStyleSheets(); |
|
491 |
|
492 newBinding.swap(*aBinding); |
|
493 } |
|
494 |
|
495 return NS_OK; |
|
496 } |
|
497 |
|
498 nsresult |
|
499 nsXBLService::FlushStyleBindings(nsIContent* aContent) |
|
500 { |
|
501 nsCOMPtr<nsIDocument> document = aContent->OwnerDoc(); |
|
502 |
|
503 nsXBLBinding *binding = aContent->GetXBLBinding(); |
|
504 if (binding) { |
|
505 // Clear out the script references. |
|
506 binding->ChangeDocument(document, nullptr); |
|
507 |
|
508 aContent->SetXBLBinding(nullptr); // Flush old style bindings |
|
509 } |
|
510 |
|
511 return NS_OK; |
|
512 } |
|
513 |
|
514 // |
|
515 // AttachGlobalKeyHandler |
|
516 // |
|
517 // Creates a new key handler and prepares to listen to key events on the given |
|
518 // event receiver (either a document or an content node). If the receiver is content, |
|
519 // then extra work needs to be done to hook it up to the document (XXX WHY??) |
|
520 // |
|
521 nsresult |
|
522 nsXBLService::AttachGlobalKeyHandler(EventTarget* aTarget) |
|
523 { |
|
524 // check if the receiver is a content node (not a document), and hook |
|
525 // it to the document if that is the case. |
|
526 nsCOMPtr<EventTarget> piTarget = aTarget; |
|
527 nsCOMPtr<nsIContent> contentNode(do_QueryInterface(aTarget)); |
|
528 if (contentNode) { |
|
529 // Only attach if we're really in a document |
|
530 nsCOMPtr<nsIDocument> doc = contentNode->GetCurrentDoc(); |
|
531 if (doc) |
|
532 piTarget = doc; // We're a XUL keyset. Attach to our document. |
|
533 } |
|
534 |
|
535 EventListenerManager* manager = piTarget->GetOrCreateListenerManager(); |
|
536 |
|
537 if (!piTarget || !manager) |
|
538 return NS_ERROR_FAILURE; |
|
539 |
|
540 // the listener already exists, so skip this |
|
541 if (contentNode && contentNode->GetProperty(nsGkAtoms::listener)) |
|
542 return NS_OK; |
|
543 |
|
544 nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(contentNode)); |
|
545 |
|
546 // Create the key handler |
|
547 nsRefPtr<nsXBLWindowKeyHandler> handler = |
|
548 NS_NewXBLWindowKeyHandler(elt, piTarget); |
|
549 |
|
550 // listen to these events |
|
551 manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keydown"), |
|
552 TrustedEventsAtSystemGroupBubble()); |
|
553 manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keyup"), |
|
554 TrustedEventsAtSystemGroupBubble()); |
|
555 manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keypress"), |
|
556 TrustedEventsAtSystemGroupBubble()); |
|
557 |
|
558 // The capturing listener is only used for XUL keysets to properly handle |
|
559 // shortcut keys in a multi-process environment. |
|
560 manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keydown"), |
|
561 TrustedEventsAtSystemGroupCapture()); |
|
562 manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keyup"), |
|
563 TrustedEventsAtSystemGroupCapture()); |
|
564 manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keypress"), |
|
565 TrustedEventsAtSystemGroupCapture()); |
|
566 |
|
567 if (contentNode) |
|
568 return contentNode->SetProperty(nsGkAtoms::listener, |
|
569 handler.forget().take(), |
|
570 nsPropertyTable::SupportsDtorFunc, true); |
|
571 |
|
572 // The reference to the handler will be maintained by the event target, |
|
573 // and, if there is a content node, the property. |
|
574 return NS_OK; |
|
575 } |
|
576 |
|
577 // |
|
578 // DetachGlobalKeyHandler |
|
579 // |
|
580 // Removes a key handler added by DeatchGlobalKeyHandler. |
|
581 // |
|
582 nsresult |
|
583 nsXBLService::DetachGlobalKeyHandler(EventTarget* aTarget) |
|
584 { |
|
585 nsCOMPtr<EventTarget> piTarget = aTarget; |
|
586 nsCOMPtr<nsIContent> contentNode(do_QueryInterface(aTarget)); |
|
587 if (!contentNode) // detaching is only supported for content nodes |
|
588 return NS_ERROR_FAILURE; |
|
589 |
|
590 // Only attach if we're really in a document |
|
591 nsCOMPtr<nsIDocument> doc = contentNode->GetCurrentDoc(); |
|
592 if (doc) |
|
593 piTarget = do_QueryInterface(doc); |
|
594 |
|
595 EventListenerManager* manager = piTarget->GetOrCreateListenerManager(); |
|
596 |
|
597 if (!piTarget || !manager) |
|
598 return NS_ERROR_FAILURE; |
|
599 |
|
600 nsIDOMEventListener* handler = |
|
601 static_cast<nsIDOMEventListener*>(contentNode->GetProperty(nsGkAtoms::listener)); |
|
602 if (!handler) |
|
603 return NS_ERROR_FAILURE; |
|
604 |
|
605 manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keydown"), |
|
606 TrustedEventsAtSystemGroupBubble()); |
|
607 manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keyup"), |
|
608 TrustedEventsAtSystemGroupBubble()); |
|
609 manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keypress"), |
|
610 TrustedEventsAtSystemGroupBubble()); |
|
611 |
|
612 manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keydown"), |
|
613 TrustedEventsAtSystemGroupCapture()); |
|
614 manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keyup"), |
|
615 TrustedEventsAtSystemGroupCapture()); |
|
616 manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keypress"), |
|
617 TrustedEventsAtSystemGroupCapture()); |
|
618 |
|
619 contentNode->DeleteProperty(nsGkAtoms::listener); |
|
620 |
|
621 return NS_OK; |
|
622 } |
|
623 |
|
624 // Internal helper methods //////////////////////////////////////////////////////////////// |
|
625 |
|
626 nsresult |
|
627 nsXBLService::BindingReady(nsIContent* aBoundElement, |
|
628 nsIURI* aURI, |
|
629 bool* aIsReady) |
|
630 { |
|
631 // Don't do a security check here; we know this binding is set to go. |
|
632 return GetBinding(aBoundElement, aURI, true, nullptr, aIsReady, nullptr); |
|
633 } |
|
634 |
|
635 nsresult |
|
636 nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI, |
|
637 bool aPeekOnly, nsIPrincipal* aOriginPrincipal, |
|
638 bool* aIsReady, nsXBLBinding** aResult) |
|
639 { |
|
640 // More than 6 binding URIs are rare, see bug 55070 comment 18. |
|
641 nsAutoTArray<nsIURI*, 6> uris; |
|
642 return GetBinding(aBoundElement, aURI, aPeekOnly, aOriginPrincipal, aIsReady, |
|
643 aResult, uris); |
|
644 } |
|
645 |
|
646 nsresult |
|
647 nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI, |
|
648 bool aPeekOnly, nsIPrincipal* aOriginPrincipal, |
|
649 bool* aIsReady, nsXBLBinding** aResult, |
|
650 nsTArray<nsIURI*>& aDontExtendURIs) |
|
651 { |
|
652 NS_ASSERTION(aPeekOnly || aResult, |
|
653 "Must have non-null out param if not just peeking to see " |
|
654 "whether the binding is ready"); |
|
655 |
|
656 if (aResult) |
|
657 *aResult = nullptr; |
|
658 |
|
659 if (!aURI) |
|
660 return NS_ERROR_FAILURE; |
|
661 |
|
662 nsAutoCString ref; |
|
663 aURI->GetRef(ref); |
|
664 |
|
665 nsCOMPtr<nsIDocument> boundDocument = aBoundElement->OwnerDoc(); |
|
666 |
|
667 nsRefPtr<nsXBLDocumentInfo> docInfo; |
|
668 nsresult rv = LoadBindingDocumentInfo(aBoundElement, boundDocument, aURI, |
|
669 aOriginPrincipal, |
|
670 false, getter_AddRefs(docInfo)); |
|
671 NS_ENSURE_SUCCESS(rv, rv); |
|
672 |
|
673 if (!docInfo) |
|
674 return NS_ERROR_FAILURE; |
|
675 |
|
676 nsXBLPrototypeBinding* protoBinding = docInfo->GetPrototypeBinding(ref); |
|
677 |
|
678 if (!protoBinding) { |
|
679 #ifdef DEBUG |
|
680 nsAutoCString uriSpec; |
|
681 aURI->GetSpec(uriSpec); |
|
682 nsAutoCString doc; |
|
683 boundDocument->GetDocumentURI()->GetSpec(doc); |
|
684 nsAutoCString message("Unable to locate an XBL binding for URI "); |
|
685 message += uriSpec; |
|
686 message += " in document "; |
|
687 message += doc; |
|
688 NS_WARNING(message.get()); |
|
689 #endif |
|
690 return NS_ERROR_FAILURE; |
|
691 } |
|
692 |
|
693 NS_ENSURE_TRUE(aDontExtendURIs.AppendElement(protoBinding->BindingURI()), |
|
694 NS_ERROR_OUT_OF_MEMORY); |
|
695 nsCOMPtr<nsIURI> altBindingURI = protoBinding->AlternateBindingURI(); |
|
696 if (altBindingURI) { |
|
697 NS_ENSURE_TRUE(aDontExtendURIs.AppendElement(altBindingURI), |
|
698 NS_ERROR_OUT_OF_MEMORY); |
|
699 } |
|
700 |
|
701 // Our prototype binding must have all its resources loaded. |
|
702 bool ready = protoBinding->LoadResources(); |
|
703 if (!ready) { |
|
704 // Add our bound element to the protos list of elts that should |
|
705 // be notified when the stylesheets and scripts finish loading. |
|
706 protoBinding->AddResourceListener(aBoundElement); |
|
707 return NS_ERROR_FAILURE; // The binding isn't ready yet. |
|
708 } |
|
709 |
|
710 rv = protoBinding->ResolveBaseBinding(); |
|
711 NS_ENSURE_SUCCESS(rv, rv); |
|
712 |
|
713 nsIURI* baseBindingURI; |
|
714 nsXBLPrototypeBinding* baseProto = protoBinding->GetBasePrototype(); |
|
715 if (baseProto) { |
|
716 baseBindingURI = baseProto->BindingURI(); |
|
717 } |
|
718 else { |
|
719 baseBindingURI = protoBinding->GetBaseBindingURI(); |
|
720 if (baseBindingURI) { |
|
721 uint32_t count = aDontExtendURIs.Length(); |
|
722 for (uint32_t index = 0; index < count; ++index) { |
|
723 bool equal; |
|
724 rv = aDontExtendURIs[index]->Equals(baseBindingURI, &equal); |
|
725 NS_ENSURE_SUCCESS(rv, rv); |
|
726 if (equal) { |
|
727 nsAutoCString spec, basespec; |
|
728 protoBinding->BindingURI()->GetSpec(spec); |
|
729 NS_ConvertUTF8toUTF16 protoSpec(spec); |
|
730 baseBindingURI->GetSpec(basespec); |
|
731 NS_ConvertUTF8toUTF16 baseSpecUTF16(basespec); |
|
732 const char16_t* params[] = { protoSpec.get(), baseSpecUTF16.get() }; |
|
733 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, |
|
734 NS_LITERAL_CSTRING("XBL"), nullptr, |
|
735 nsContentUtils::eXBL_PROPERTIES, |
|
736 "CircularExtendsBinding", |
|
737 params, ArrayLength(params), |
|
738 boundDocument->GetDocumentURI()); |
|
739 return NS_ERROR_ILLEGAL_VALUE; |
|
740 } |
|
741 } |
|
742 } |
|
743 } |
|
744 |
|
745 nsRefPtr<nsXBLBinding> baseBinding; |
|
746 if (baseBindingURI) { |
|
747 nsIContent* child = protoBinding->GetBindingElement(); |
|
748 rv = GetBinding(aBoundElement, baseBindingURI, aPeekOnly, |
|
749 child->NodePrincipal(), aIsReady, |
|
750 getter_AddRefs(baseBinding), aDontExtendURIs); |
|
751 if (NS_FAILED(rv)) |
|
752 return rv; // We aren't ready yet. |
|
753 } |
|
754 |
|
755 *aIsReady = true; |
|
756 |
|
757 if (!aPeekOnly) { |
|
758 // Make a new binding |
|
759 nsXBLBinding *newBinding = new nsXBLBinding(protoBinding); |
|
760 NS_ENSURE_TRUE(newBinding, NS_ERROR_OUT_OF_MEMORY); |
|
761 |
|
762 if (baseBinding) { |
|
763 if (!baseProto) { |
|
764 protoBinding->SetBasePrototype(baseBinding->PrototypeBinding()); |
|
765 } |
|
766 newBinding->SetBaseBinding(baseBinding); |
|
767 } |
|
768 |
|
769 NS_ADDREF(*aResult = newBinding); |
|
770 } |
|
771 |
|
772 return NS_OK; |
|
773 } |
|
774 |
|
775 static bool SchemeIs(nsIURI* aURI, const char* aScheme) |
|
776 { |
|
777 nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI); |
|
778 NS_ENSURE_TRUE(baseURI, false); |
|
779 |
|
780 bool isScheme = false; |
|
781 return NS_SUCCEEDED(baseURI->SchemeIs(aScheme, &isScheme)) && isScheme; |
|
782 } |
|
783 |
|
784 static bool |
|
785 IsSystemOrChromeURLPrincipal(nsIPrincipal* aPrincipal) |
|
786 { |
|
787 if (nsContentUtils::IsSystemPrincipal(aPrincipal)) { |
|
788 return true; |
|
789 } |
|
790 |
|
791 nsCOMPtr<nsIURI> uri; |
|
792 aPrincipal->GetURI(getter_AddRefs(uri)); |
|
793 NS_ENSURE_TRUE(uri, false); |
|
794 |
|
795 bool isChrome = false; |
|
796 return NS_SUCCEEDED(uri->SchemeIs("chrome", &isChrome)) && isChrome; |
|
797 } |
|
798 |
|
799 nsresult |
|
800 nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement, |
|
801 nsIDocument* aBoundDocument, |
|
802 nsIURI* aBindingURI, |
|
803 nsIPrincipal* aOriginPrincipal, |
|
804 bool aForceSyncLoad, |
|
805 nsXBLDocumentInfo** aResult) |
|
806 { |
|
807 NS_PRECONDITION(aBindingURI, "Must have a binding URI"); |
|
808 NS_PRECONDITION(!aOriginPrincipal || aBoundDocument, |
|
809 "If we're doing a security check, we better have a document!"); |
|
810 |
|
811 nsresult rv; |
|
812 if (aOriginPrincipal) { |
|
813 // Security check - Enforce same-origin policy, except to chrome. |
|
814 // We have to be careful to not pass aContent as the context here. |
|
815 // Otherwise, if there is a JS-implemented content policy, we will attempt |
|
816 // to wrap the content node, which will try to load XBL bindings for it, if |
|
817 // any. Since we're not done loading this binding yet, that will reenter |
|
818 // this method and we'll end up creating a binding and then immediately |
|
819 // clobbering it in our table. That makes things very confused, leading to |
|
820 // misbehavior and crashes. |
|
821 rv = nsContentUtils:: |
|
822 CheckSecurityBeforeLoad(aBindingURI, aOriginPrincipal, |
|
823 nsIScriptSecurityManager::ALLOW_CHROME, |
|
824 gAllowDataURIs, |
|
825 nsIContentPolicy::TYPE_XBL, |
|
826 aBoundDocument); |
|
827 NS_ENSURE_SUCCESS(rv, NS_ERROR_XBL_BLOCKED); |
|
828 |
|
829 if (!IsSystemOrChromeURLPrincipal(aOriginPrincipal)) { |
|
830 // Also make sure that we're same-origin with the bound document |
|
831 // except if the stylesheet has the system principal. |
|
832 if (!(gAllowDataURIs && SchemeIs(aBindingURI, "data")) && |
|
833 !SchemeIs(aBindingURI, "chrome")) { |
|
834 rv = aBoundDocument->NodePrincipal()->CheckMayLoad(aBindingURI, |
|
835 true, false); |
|
836 NS_ENSURE_SUCCESS(rv, NS_ERROR_XBL_BLOCKED); |
|
837 } |
|
838 |
|
839 // Finally check if this document is allowed to use XBL at all. |
|
840 NS_ENSURE_TRUE(aBoundDocument->AllowXULXBL(), |
|
841 NS_ERROR_XBL_BLOCKED); |
|
842 } |
|
843 } |
|
844 |
|
845 *aResult = nullptr; |
|
846 nsRefPtr<nsXBLDocumentInfo> info; |
|
847 |
|
848 nsCOMPtr<nsIURI> documentURI; |
|
849 rv = aBindingURI->CloneIgnoringRef(getter_AddRefs(documentURI)); |
|
850 NS_ENSURE_SUCCESS(rv, rv); |
|
851 |
|
852 #ifdef MOZ_XUL |
|
853 // We've got a file. Check our XBL document cache. |
|
854 nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance(); |
|
855 bool useXULCache = cache && cache->IsEnabled(); |
|
856 |
|
857 if (useXULCache) { |
|
858 // The first line of defense is the chrome cache. |
|
859 // This cache crosses the entire product, so that any XBL bindings that are |
|
860 // part of chrome will be reused across all XUL documents. |
|
861 info = cache->GetXBLDocumentInfo(documentURI); |
|
862 } |
|
863 #endif |
|
864 |
|
865 if (!info) { |
|
866 // The second line of defense is the binding manager's document table. |
|
867 nsBindingManager *bindingManager = nullptr; |
|
868 |
|
869 if (aBoundDocument) { |
|
870 bindingManager = aBoundDocument->BindingManager(); |
|
871 info = bindingManager->GetXBLDocumentInfo(documentURI); |
|
872 if (aBoundDocument->IsStaticDocument() && |
|
873 IsChromeOrResourceURI(aBindingURI)) { |
|
874 aForceSyncLoad = true; |
|
875 } |
|
876 } |
|
877 |
|
878 nsINodeInfo *ni = nullptr; |
|
879 if (aBoundElement) |
|
880 ni = aBoundElement->NodeInfo(); |
|
881 |
|
882 if (!info && bindingManager && |
|
883 (!ni || !(ni->Equals(nsGkAtoms::scrollbar, kNameSpaceID_XUL) || |
|
884 ni->Equals(nsGkAtoms::thumb, kNameSpaceID_XUL) || |
|
885 ((ni->Equals(nsGkAtoms::input) || |
|
886 ni->Equals(nsGkAtoms::select)) && |
|
887 aBoundElement->IsHTML()))) && !aForceSyncLoad) { |
|
888 // The third line of defense is to investigate whether or not the |
|
889 // document is currently being loaded asynchronously. If so, there's no |
|
890 // document yet, but we need to glom on our request so that it will be |
|
891 // processed whenever the doc does finish loading. |
|
892 nsCOMPtr<nsIStreamListener> listener; |
|
893 if (bindingManager) |
|
894 listener = bindingManager->GetLoadingDocListener(documentURI); |
|
895 if (listener) { |
|
896 nsXBLStreamListener* xblListener = |
|
897 static_cast<nsXBLStreamListener*>(listener.get()); |
|
898 // Create a new load observer. |
|
899 if (!xblListener->HasRequest(aBindingURI, aBoundElement)) { |
|
900 nsXBLBindingRequest* req = new nsXBLBindingRequest(aBindingURI, aBoundElement); |
|
901 xblListener->AddRequest(req); |
|
902 } |
|
903 return NS_OK; |
|
904 } |
|
905 } |
|
906 |
|
907 #ifdef MOZ_XUL |
|
908 // Next, look in the startup cache |
|
909 bool useStartupCache = useXULCache && IsChromeOrResourceURI(documentURI); |
|
910 if (!info && useStartupCache) { |
|
911 rv = nsXBLDocumentInfo::ReadPrototypeBindings(documentURI, getter_AddRefs(info)); |
|
912 if (NS_SUCCEEDED(rv)) { |
|
913 cache->PutXBLDocumentInfo(info); |
|
914 |
|
915 if (bindingManager) { |
|
916 // Cache it in our binding manager's document table. |
|
917 bindingManager->PutXBLDocumentInfo(info); |
|
918 } |
|
919 } |
|
920 } |
|
921 #endif |
|
922 |
|
923 if (!info) { |
|
924 // Finally, if all lines of defense fail, we go and fetch the binding |
|
925 // document. |
|
926 |
|
927 // Always load chrome synchronously |
|
928 bool chrome; |
|
929 if (NS_SUCCEEDED(documentURI->SchemeIs("chrome", &chrome)) && chrome) |
|
930 aForceSyncLoad = true; |
|
931 |
|
932 nsCOMPtr<nsIDocument> document; |
|
933 FetchBindingDocument(aBoundElement, aBoundDocument, documentURI, |
|
934 aBindingURI, aForceSyncLoad, getter_AddRefs(document)); |
|
935 |
|
936 if (document) { |
|
937 nsBindingManager *xblDocBindingManager = document->BindingManager(); |
|
938 info = xblDocBindingManager->GetXBLDocumentInfo(documentURI); |
|
939 if (!info) { |
|
940 NS_ERROR("An XBL file is malformed. Did you forget the XBL namespace on the bindings tag?"); |
|
941 return NS_ERROR_FAILURE; |
|
942 } |
|
943 xblDocBindingManager->RemoveXBLDocumentInfo(info); // Break the self-imposed cycle. |
|
944 |
|
945 // If the doc is a chrome URI, then we put it into the XUL cache. |
|
946 #ifdef MOZ_XUL |
|
947 if (useStartupCache) { |
|
948 cache->PutXBLDocumentInfo(info); |
|
949 |
|
950 // now write the bindings into the startup cache |
|
951 info->WritePrototypeBindings(); |
|
952 } |
|
953 #endif |
|
954 |
|
955 if (bindingManager) { |
|
956 // Also put it in our binding manager's document table. |
|
957 bindingManager->PutXBLDocumentInfo(info); |
|
958 } |
|
959 } |
|
960 } |
|
961 } |
|
962 |
|
963 info.forget(aResult); |
|
964 |
|
965 return NS_OK; |
|
966 } |
|
967 |
|
968 nsresult |
|
969 nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoundDocument, |
|
970 nsIURI* aDocumentURI, nsIURI* aBindingURI, |
|
971 bool aForceSyncLoad, nsIDocument** aResult) |
|
972 { |
|
973 nsresult rv = NS_OK; |
|
974 // Initialize our out pointer to nullptr |
|
975 *aResult = nullptr; |
|
976 |
|
977 // Now we have to synchronously load the binding file. |
|
978 // Create an XML content sink and a parser. |
|
979 nsCOMPtr<nsILoadGroup> loadGroup; |
|
980 if (aBoundDocument) |
|
981 loadGroup = aBoundDocument->GetDocumentLoadGroup(); |
|
982 |
|
983 // We really shouldn't have to force a sync load for anything here... could |
|
984 // we get away with not doing that? Not sure. |
|
985 if (IsChromeOrResourceURI(aDocumentURI)) |
|
986 aForceSyncLoad = true; |
|
987 |
|
988 // Create document and contentsink and set them up. |
|
989 nsCOMPtr<nsIDocument> doc; |
|
990 rv = NS_NewXMLDocument(getter_AddRefs(doc)); |
|
991 NS_ENSURE_SUCCESS(rv, rv); |
|
992 |
|
993 nsCOMPtr<nsIXMLContentSink> xblSink; |
|
994 rv = NS_NewXBLContentSink(getter_AddRefs(xblSink), doc, aDocumentURI, nullptr); |
|
995 NS_ENSURE_SUCCESS(rv, rv); |
|
996 |
|
997 // Open channel |
|
998 nsCOMPtr<nsIChannel> channel; |
|
999 rv = NS_NewChannel(getter_AddRefs(channel), aDocumentURI, nullptr, loadGroup); |
|
1000 NS_ENSURE_SUCCESS(rv, rv); |
|
1001 |
|
1002 nsCOMPtr<nsIInterfaceRequestor> sameOriginChecker = nsContentUtils::GetSameOriginChecker(); |
|
1003 NS_ENSURE_TRUE(sameOriginChecker, NS_ERROR_OUT_OF_MEMORY); |
|
1004 |
|
1005 channel->SetNotificationCallbacks(sameOriginChecker); |
|
1006 |
|
1007 if (!aForceSyncLoad) { |
|
1008 // We can be asynchronous |
|
1009 nsXBLStreamListener* xblListener = |
|
1010 new nsXBLStreamListener(aBoundDocument, xblSink, doc); |
|
1011 NS_ENSURE_TRUE(xblListener,NS_ERROR_OUT_OF_MEMORY); |
|
1012 |
|
1013 // Add ourselves to the list of loading docs. |
|
1014 nsBindingManager *bindingManager; |
|
1015 if (aBoundDocument) |
|
1016 bindingManager = aBoundDocument->BindingManager(); |
|
1017 else |
|
1018 bindingManager = nullptr; |
|
1019 |
|
1020 if (bindingManager) |
|
1021 bindingManager->PutLoadingDocListener(aDocumentURI, xblListener); |
|
1022 |
|
1023 // Add our request. |
|
1024 nsXBLBindingRequest* req = new nsXBLBindingRequest(aBindingURI, |
|
1025 aBoundElement); |
|
1026 xblListener->AddRequest(req); |
|
1027 |
|
1028 // Now kick off the async read. |
|
1029 rv = channel->AsyncOpen(xblListener, nullptr); |
|
1030 if (NS_FAILED(rv)) { |
|
1031 // Well, we won't be getting a load. Make sure to clean up our stuff! |
|
1032 if (bindingManager) { |
|
1033 bindingManager->RemoveLoadingDocListener(aDocumentURI); |
|
1034 } |
|
1035 } |
|
1036 return NS_OK; |
|
1037 } |
|
1038 |
|
1039 nsCOMPtr<nsIStreamListener> listener; |
|
1040 rv = doc->StartDocumentLoad("loadAsInteractiveData", |
|
1041 channel, |
|
1042 loadGroup, |
|
1043 nullptr, |
|
1044 getter_AddRefs(listener), |
|
1045 true, |
|
1046 xblSink); |
|
1047 NS_ENSURE_SUCCESS(rv, rv); |
|
1048 |
|
1049 // Now do a blocking synchronous parse of the file. |
|
1050 nsCOMPtr<nsIInputStream> in; |
|
1051 rv = channel->Open(getter_AddRefs(in)); |
|
1052 NS_ENSURE_SUCCESS(rv, rv); |
|
1053 |
|
1054 rv = nsSyncLoadService::PushSyncStreamToListener(in, listener, channel); |
|
1055 NS_ENSURE_SUCCESS(rv, rv); |
|
1056 |
|
1057 doc.swap(*aResult); |
|
1058 |
|
1059 return NS_OK; |
|
1060 } |