1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Original Author: David W. Hyatt (hyatt@netscape.com)
24 * - Brendan Eich (brendan@mozilla.org)
25 * - Mike Pinkerton (pinkerton@netscape.com)
26 * Mats Palmgren <mats.palmgren@bredband.net>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either of the GNU General Public License Version 2 or later (the "GPL"),
30 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
43 #include "nsNetUtil.h"
44 #include "nsXBLService.h"
45 #include "nsXBLWindowKeyHandler.h"
46 #include "nsIInputStream.h"
47 #include "nsINameSpaceManager.h"
48 #include "nsHashtable.h"
50 #include "nsIDOMElement.h"
52 #include "nsIChannel.h"
53 #include "nsXPIDLString.h"
54 #include "nsIParser.h"
55 #include "nsParserCIID.h"
56 #include "nsNetUtil.h"
58 #include "nsIContent.h"
59 #include "nsIDOMElement.h"
60 #include "nsIDocument.h"
61 #include "nsIXMLContentSink.h"
62 #include "nsContentCID.h"
63 #include "nsXMLDocument.h"
64 #include "mozilla/FunctionTimer.h"
65 #include "nsGkAtoms.h"
66 #include "nsIMemory.h"
67 #include "nsIObserverService.h"
68 #include "nsIDOMNodeList.h"
69 #include "nsXBLContentSink.h"
70 #include "nsXBLBinding.h"
71 #include "nsXBLPrototypeBinding.h"
72 #include "nsXBLDocumentInfo.h"
74 #include "nsContentUtils.h"
75 #include "nsSyncLoadService.h"
76 #include "nsIDOM3Node.h"
77 #include "nsContentPolicyUtils.h"
79 #include "nsContentErrors.h"
81 #include "nsIPresShell.h"
82 #include "nsIDocumentObserver.h"
83 #include "nsFrameManager.h"
84 #include "nsStyleContext.h"
85 #include "nsIScriptSecurityManager.h"
86 #include "nsIScriptError.h"
89 #include "nsXULPrototypeCache.h"
91 #include "nsIDOMLoadListener.h"
92 #include "nsIDOMEventGroup.h"
94 #define NS_MAX_XBL_BINDING_RECURSION 20
96 static PRBool
IsChromeOrResourceURI(nsIURI
* aURI
)
98 PRBool isChrome
= PR_FALSE
;
99 PRBool isResource
= PR_FALSE
;
100 if (NS_SUCCEEDED(aURI
->SchemeIs("chrome", &isChrome
)) &&
101 NS_SUCCEEDED(aURI
->SchemeIs("resource", &isResource
)))
102 return (isChrome
|| isResource
);
107 IsAncestorBinding(nsIDocument
* aDocument
,
108 nsIURI
* aChildBindingURI
,
111 NS_ASSERTION(aDocument
, "expected a document");
112 NS_ASSERTION(aChildBindingURI
, "expected a binding URI");
113 NS_ASSERTION(aChild
, "expected a child content");
115 PRUint32 bindingRecursion
= 0;
116 nsBindingManager
* bindingManager
= aDocument
->BindingManager();
117 for (nsIContent
*bindingParent
= aChild
->GetBindingParent();
119 bindingParent
= bindingParent
->GetBindingParent()) {
120 nsXBLBinding
* binding
= bindingManager
->GetBinding(bindingParent
);
125 if (binding
->PrototypeBinding()->CompareBindingURI(aChildBindingURI
)) {
127 if (bindingRecursion
< NS_MAX_XBL_BINDING_RECURSION
) {
131 aChildBindingURI
->GetSpec(spec
);
132 NS_ConvertUTF8toUTF16
bindingURI(spec
);
133 const PRUnichar
* params
[] = { bindingURI
.get() };
134 nsContentUtils::ReportToConsole(nsContentUtils::eXBL_PROPERTIES
,
135 "TooDeepBindingRecursion",
136 params
, NS_ARRAY_LENGTH(params
),
137 aDocument
->GetDocumentURI(),
139 nsIScriptError::warningFlag
,
148 PRBool
CheckTagNameWhiteList(PRInt32 aNameSpaceID
, nsIAtom
*aTagName
)
150 static nsIContent::AttrValuesArray kValidXULTagNames
[] = {
151 &nsGkAtoms::autorepeatbutton
, &nsGkAtoms::box
, &nsGkAtoms::browser
,
152 &nsGkAtoms::button
, &nsGkAtoms::hbox
, &nsGkAtoms::image
, &nsGkAtoms::menu
,
153 &nsGkAtoms::menubar
, &nsGkAtoms::menuitem
, &nsGkAtoms::menupopup
,
154 &nsGkAtoms::row
, &nsGkAtoms::slider
, &nsGkAtoms::spacer
,
155 &nsGkAtoms::splitter
, &nsGkAtoms::text
, &nsGkAtoms::tree
, nsnull
};
158 if (aNameSpaceID
== kNameSpaceID_XUL
) {
159 for (i
= 0; kValidXULTagNames
[i
]; ++i
) {
160 if (aTagName
== *(kValidXULTagNames
[i
])) {
166 else if (aNameSpaceID
== kNameSpaceID_SVG
&&
167 aTagName
== nsGkAtoms::generic
) {
175 // Individual binding requests.
176 class nsXBLBindingRequest
179 nsCOMPtr
<nsIURI
> mBindingURI
;
180 nsCOMPtr
<nsIContent
> mBoundElement
;
182 static nsXBLBindingRequest
*
183 Create(nsFixedSizeAllocator
& aPool
, nsIURI
* aURI
, nsIContent
* aBoundElement
) {
184 void* place
= aPool
.Alloc(sizeof(nsXBLBindingRequest
));
185 return place
? ::new (place
) nsXBLBindingRequest(aURI
, aBoundElement
) : nsnull
;
189 Destroy(nsFixedSizeAllocator
& aPool
, nsXBLBindingRequest
* aRequest
) {
190 aRequest
->~nsXBLBindingRequest();
191 aPool
.Free(aRequest
, sizeof(*aRequest
));
194 void DocumentLoaded(nsIDocument
* aBindingDoc
)
196 // We only need the document here to cause frame construction, so
197 // we need the current doc, not the owner doc.
198 nsIDocument
* doc
= mBoundElement
->GetCurrentDoc();
203 PRBool ready
= PR_FALSE
;
204 gXBLService
->BindingReady(mBoundElement
, mBindingURI
, &ready
);
209 // If |mBoundElement| is (in addition to having binding |mBinding|)
210 // also a descendant of another element with binding |mBinding|,
211 // then we might have just constructed it due to the
212 // notification of its parent. (We can know about both if the
213 // binding loads were triggered from the DOM rather than frame
214 // construction.) So we have to check both whether the element
215 // has a primary frame and whether it's in the undisplayed map
216 // before sending a ContentInserted notification, or bad things
218 nsIPresShell
*shell
= doc
->GetShell();
220 nsIFrame
* childFrame
= mBoundElement
->GetPrimaryFrame();
222 // Check to see if it's in the undisplayed content map.
224 shell
->FrameManager()->GetUndisplayedContent(mBoundElement
);
227 shell
->RecreateFramesFor(mBoundElement
);
233 static nsIXBLService
* gXBLService
;
237 nsXBLBindingRequest(nsIURI
* aURI
, nsIContent
* aBoundElement
)
239 mBoundElement(aBoundElement
)
243 CallGetService("@mozilla.org/xbl;1", &gXBLService
);
247 ~nsXBLBindingRequest()
251 NS_IF_RELEASE(gXBLService
);
256 // Hide so that only Create() and Destroy() can be used to
257 // allocate and deallocate from the heap
258 static void* operator new(size_t) CPP_THROW_NEW
{ return 0; }
259 static void operator delete(void*, size_t) {}
262 static const size_t kBucketSizes
[] = {
263 sizeof(nsXBLBindingRequest
)
266 static const PRInt32 kNumBuckets
= sizeof(kBucketSizes
)/sizeof(size_t);
267 static const PRInt32 kNumElements
= 64;
268 static const PRInt32 kInitialSize
= (NS_SIZE_IN_HEAP(sizeof(nsXBLBindingRequest
))) * kNumElements
;
270 nsIXBLService
* nsXBLBindingRequest::gXBLService
= nsnull
;
271 int nsXBLBindingRequest::gRefCnt
= 0;
273 // nsXBLStreamListener, a helper class used for
274 // asynchronous parsing of URLs
276 class nsXBLStreamListener
: public nsIStreamListener
, public nsIDOMLoadListener
280 NS_DECL_NSISTREAMLISTENER
281 NS_DECL_NSIREQUESTOBSERVER
283 NS_IMETHOD
Load(nsIDOMEvent
* aEvent
);
284 NS_IMETHOD
BeforeUnload(nsIDOMEvent
* aEvent
) { return NS_OK
; }
285 NS_IMETHOD
Unload(nsIDOMEvent
* aEvent
) { return NS_OK
; }
286 NS_IMETHOD
Abort(nsIDOMEvent
* aEvent
) { return NS_OK
; }
287 NS_IMETHOD
Error(nsIDOMEvent
* aEvent
) { return NS_OK
; }
288 NS_IMETHOD
HandleEvent(nsIDOMEvent
* aEvent
) { return NS_OK
; }
290 nsXBLStreamListener(nsXBLService
* aXBLService
,
291 nsIDocument
* aBoundDocument
,
292 nsIXMLContentSink
* aSink
,
293 nsIDocument
* aBindingDocument
);
294 ~nsXBLStreamListener();
296 void AddRequest(nsXBLBindingRequest
* aRequest
) { mBindingRequests
.AppendElement(aRequest
); }
297 PRBool
HasRequest(nsIURI
* aURI
, nsIContent
* aBoundElement
);
300 nsXBLService
* mXBLService
; // [WEAK]
302 nsCOMPtr
<nsIStreamListener
> mInner
;
303 nsAutoTArray
<nsXBLBindingRequest
*, 8> mBindingRequests
;
305 nsCOMPtr
<nsIWeakReference
> mBoundDocument
;
306 nsCOMPtr
<nsIXMLContentSink
> mSink
; // Only set until OnStartRequest
307 nsCOMPtr
<nsIDocument
> mBindingDocument
; // Only set until OnStartRequest
310 /* Implementation file */
311 NS_IMPL_ISUPPORTS4(nsXBLStreamListener
, nsIStreamListener
, nsIRequestObserver
, nsIDOMLoadListener
, nsIDOMEventListener
)
313 nsXBLStreamListener::nsXBLStreamListener(nsXBLService
* aXBLService
,
314 nsIDocument
* aBoundDocument
,
315 nsIXMLContentSink
* aSink
,
316 nsIDocument
* aBindingDocument
)
317 : mSink(aSink
), mBindingDocument(aBindingDocument
)
319 /* member initializers and constructor code */
320 mXBLService
= aXBLService
;
321 mBoundDocument
= do_GetWeakReference(aBoundDocument
);
324 nsXBLStreamListener::~nsXBLStreamListener()
326 for (PRUint32 i
= 0; i
< mBindingRequests
.Length(); i
++) {
327 nsXBLBindingRequest
* req
= mBindingRequests
.ElementAt(i
);
328 nsXBLBindingRequest::Destroy(mXBLService
->mPool
, req
);
333 nsXBLStreamListener::OnDataAvailable(nsIRequest
*request
, nsISupports
* aCtxt
, nsIInputStream
* aInStr
,
334 PRUint32 aSourceOffset
, PRUint32 aCount
)
337 return mInner
->OnDataAvailable(request
, aCtxt
, aInStr
, aSourceOffset
, aCount
);
338 return NS_ERROR_FAILURE
;
342 nsXBLStreamListener::OnStartRequest(nsIRequest
* request
, nsISupports
* aCtxt
)
344 // Make sure we don't hold on to the sink and binding document past this point
345 nsCOMPtr
<nsIXMLContentSink
> sink
;
347 nsCOMPtr
<nsIDocument
> doc
;
348 mBindingDocument
.swap(doc
);
350 nsCOMPtr
<nsIChannel
> channel
= do_QueryInterface(request
);
351 NS_ENSURE_TRUE(channel
, NS_ERROR_UNEXPECTED
);
353 nsCOMPtr
<nsILoadGroup
> group
;
354 request
->GetLoadGroup(getter_AddRefs(group
));
356 nsresult rv
= doc
->StartDocumentLoad("loadAsInteractiveData",
360 getter_AddRefs(mInner
),
363 NS_ENSURE_SUCCESS(rv
, rv
);
365 // Make sure to add ourselves as a listener after StartDocumentLoad,
366 // since that resets the event listners on the document.
367 nsCOMPtr
<nsIDOMEventTarget
> target(do_QueryInterface(doc
));
368 target
->AddEventListener(NS_LITERAL_STRING("load"), this, PR_FALSE
);
370 return mInner
->OnStartRequest(request
, aCtxt
);
374 nsXBLStreamListener::OnStopRequest(nsIRequest
* request
, nsISupports
* aCtxt
, nsresult aStatus
)
378 rv
= mInner
->OnStopRequest(request
, aCtxt
, aStatus
);
381 // Don't hold onto the inner listener; holding onto it can create a cycle
389 nsXBLStreamListener::HasRequest(nsIURI
* aURI
, nsIContent
* aElt
)
391 // XXX Could be more efficient.
392 PRUint32 count
= mBindingRequests
.Length();
393 for (PRUint32 i
= 0; i
< count
; i
++) {
394 nsXBLBindingRequest
* req
= mBindingRequests
.ElementAt(i
);
396 if (req
->mBoundElement
== aElt
&&
397 NS_SUCCEEDED(req
->mBindingURI
->Equals(aURI
, &eq
)) && eq
)
405 nsXBLStreamListener::Load(nsIDOMEvent
* aEvent
)
409 PRUint32 count
= mBindingRequests
.Length();
411 // Get the binding document; note that we don't hold onto it in this object
412 // to avoid creating a cycle
413 nsCOMPtr
<nsIDOMEventTarget
> target
;
414 aEvent
->GetCurrentTarget(getter_AddRefs(target
));
415 nsCOMPtr
<nsIDocument
> bindingDocument
= do_QueryInterface(target
);
416 NS_ASSERTION(bindingDocument
, "Event not targeted at document?!");
418 // See if we're still alive.
419 nsCOMPtr
<nsIDocument
> doc(do_QueryReferent(mBoundDocument
));
421 NS_WARNING("XBL load did not complete until after document went away! Modal dialog bug?\n");
424 // We have to do a flush prior to notification of the document load.
425 // This has to happen since the HTML content sink can be holding on
426 // to notifications related to our children (e.g., if you bind to the
427 // <body> tag) that result in duplication of content.
428 // We need to get the sink's notifications flushed and then make the binding
431 nsXBLBindingRequest
* req
= mBindingRequests
.ElementAt(0);
432 nsIDocument
* document
= req
->mBoundElement
->GetCurrentDoc();
434 document
->FlushPendingNotifications(Flush_ContentAndNotify
);
437 // Remove ourselves from the set of pending docs.
438 nsBindingManager
*bindingManager
= doc
->BindingManager();
439 nsIURI
* documentURI
= bindingDocument
->GetDocumentURI();
440 bindingManager
->RemoveLoadingDocListener(documentURI
);
442 if (!bindingDocument
->GetRootElement()) {
443 // FIXME: How about an error console warning?
444 NS_WARNING("*** XBL doc with no root element! Something went horribly wrong! ***");
445 return NS_ERROR_FAILURE
;
448 // Put our doc info in the doc table.
449 nsBindingManager
*xblDocBindingManager
= bindingDocument
->BindingManager();
450 nsRefPtr
<nsXBLDocumentInfo
> info
=
451 xblDocBindingManager
->GetXBLDocumentInfo(documentURI
);
452 xblDocBindingManager
->RemoveXBLDocumentInfo(info
); // Break the self-imposed cycle.
454 if (IsChromeOrResourceURI(documentURI
)) {
455 NS_WARNING("An XBL file is malformed. Did you forget the XBL namespace on the bindings tag?");
457 nsContentUtils::ReportToConsole(nsContentUtils::eXBL_PROPERTIES
,
459 nsnull
, 0, documentURI
,
461 nsIScriptError::warningFlag
,
463 return NS_ERROR_FAILURE
;
466 // If the doc is a chrome URI, then we put it into the XUL cache.
468 if (IsChromeOrResourceURI(documentURI
)) {
469 nsXULPrototypeCache
* cache
= nsXULPrototypeCache::GetInstance();
470 if (cache
&& cache
->IsEnabled())
471 cache
->PutXBLDocumentInfo(info
);
475 bindingManager
->PutXBLDocumentInfo(info
);
477 // Notify all pending requests that their bindings are
478 // ready and can be installed.
479 for (i
= 0; i
< count
; i
++) {
480 nsXBLBindingRequest
* req
= mBindingRequests
.ElementAt(i
);
481 req
->DocumentLoaded(bindingDocument
);
485 target
->RemoveEventListener(NS_LITERAL_STRING("load"), (nsIDOMLoadListener
*)this, PR_FALSE
);
490 // Implementation /////////////////////////////////////////////////////////////////
492 // Static member variable initialization
493 PRUint32
nsXBLService::gRefCnt
= 0;
494 PRBool
nsXBLService::gAllowDataURIs
= PR_FALSE
;
496 nsHashtable
* nsXBLService::gClassTable
= nsnull
;
498 JSCList
nsXBLService::gClassLRUList
= JS_INIT_STATIC_CLIST(&nsXBLService::gClassLRUList
);
499 PRUint32
nsXBLService::gClassLRUListLength
= 0;
500 PRUint32
nsXBLService::gClassLRUListQuota
= 64;
502 // Implement our nsISupports methods
503 NS_IMPL_ISUPPORTS3(nsXBLService
, nsIXBLService
, nsIObserver
, nsISupportsWeakReference
)
505 // Constructors/Destructors
506 nsXBLService::nsXBLService(void)
508 mPool
.Init("XBL Binding Requests", kBucketSizes
, kNumBuckets
, kInitialSize
);
512 gClassTable
= new nsHashtable();
515 nsContentUtils::AddBoolPrefVarCache("layout.debug.enable_data_xbl",
519 nsXBLService::~nsXBLService(void)
523 // Walk the LRU list removing and deleting the nsXBLJSClasses.
526 // Any straggling nsXBLJSClass instances held by unfinalized JS objects
527 // created for bindings will be deleted when those objects are finalized
528 // (and not put on gClassLRUList, because length >= quota).
529 gClassLRUListLength
= gClassLRUListQuota
= 0;
531 // At this point, the only hash table entries should be for referenced
532 // XBL class structs held by unfinalized JS binding objects.
534 gClassTable
= nsnull
;
538 // This function loads a particular XBL file and installs all of the bindings
541 nsXBLService::LoadBindings(nsIContent
* aContent
, nsIURI
* aURL
,
542 nsIPrincipal
* aOriginPrincipal
, PRBool aAugmentFlag
,
543 nsXBLBinding
** aBinding
, PRBool
* aResolveStyle
)
545 NS_PRECONDITION(aOriginPrincipal
, "Must have an origin principal");
548 *aResolveStyle
= PR_FALSE
;
552 nsCOMPtr
<nsIDocument
> document
= aContent
->GetOwnerDoc();
554 // XXX document may be null if we're in the midst of paint suppression
558 nsCAutoString urlspec
;
559 if (nsContentUtils::GetWrapperSafeScriptFilename(document
, aURL
, urlspec
)) {
560 // Block an attempt to load a binding that has special wrapper
566 nsBindingManager
*bindingManager
= document
->BindingManager();
568 nsXBLBinding
*binding
= bindingManager
->GetBinding(aContent
);
569 if (binding
&& !aAugmentFlag
) {
570 nsXBLBinding
*styleBinding
= binding
->GetFirstStyleBinding();
572 if (binding
->MarkedForDeath()) {
573 FlushStyleBindings(aContent
);
577 // See if the URIs match.
578 if (styleBinding
->PrototypeBinding()->CompareBindingURI(aURL
))
580 FlushStyleBindings(aContent
);
587 nsRefPtr
<nsXBLBinding
> newBinding
;
588 if (NS_FAILED(rv
= GetBinding(aContent
, aURL
, PR_FALSE
, aOriginPrincipal
,
589 &ready
, getter_AddRefs(newBinding
)))) {
597 nsCAutoString
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
);
603 if (::IsAncestorBinding(document
, aURL
, aContent
)) {
604 return NS_ERROR_ILLEGAL_VALUE
;
608 nsXBLBinding
*baseBinding
;
609 nsXBLBinding
*nextBinding
= newBinding
;
611 baseBinding
= nextBinding
;
612 nextBinding
= baseBinding
->GetBaseBinding();
613 baseBinding
->SetIsStyleBinding(PR_FALSE
);
614 } while (nextBinding
);
616 // XXX Handle adjusting the prototype chain! We need to somehow indicate to
617 // InstallImplementation that the whole chain should just be whacked and rebuilt.
618 // We are becoming the new binding.
619 baseBinding
->SetBaseBinding(binding
);
620 bindingManager
->SetBinding(aContent
, newBinding
);
623 // We loaded a style binding. It goes on the end.
625 // Get the last binding that is in the append layer.
626 binding
->RootBinding()->SetBaseBinding(newBinding
);
629 // Install the binding on the content node.
630 bindingManager
->SetBinding(aContent
, newBinding
);
635 nsAutoScriptBlocker scriptBlocker
;
637 // Set the binding's bound element.
638 newBinding
->SetBoundElement(aContent
);
640 // Tell the binding to build the anonymous content.
641 newBinding
->GenerateAnonymousContent();
643 // Tell the binding to install event handlers
644 newBinding
->InstallEventHandlers();
646 // Set up our properties
647 rv
= newBinding
->InstallImplementation();
648 NS_ENSURE_SUCCESS(rv
, rv
);
650 // Figure out if we have any scoped sheets. If so, we do a second resolve.
651 *aResolveStyle
= newBinding
->HasStyleSheets();
653 newBinding
.swap(*aBinding
);
660 nsXBLService::FlushStyleBindings(nsIContent
* aContent
)
662 nsCOMPtr
<nsIDocument
> document
= aContent
->GetOwnerDoc();
664 // XXX doc will be null if we're in the midst of paint suppression.
668 nsBindingManager
*bindingManager
= document
->BindingManager();
670 nsXBLBinding
*binding
= bindingManager
->GetBinding(aContent
);
673 nsXBLBinding
*styleBinding
= binding
->GetFirstStyleBinding();
676 // Clear out the script references.
677 styleBinding
->ChangeDocument(document
, nsnull
);
680 if (styleBinding
== binding
)
681 bindingManager
->SetBinding(aContent
, nsnull
); // Flush old style bindings
688 nsXBLService::ResolveTag(nsIContent
* aContent
, PRInt32
* aNameSpaceID
,
691 nsIDocument
* document
= aContent
->GetOwnerDoc();
693 *aResult
= document
->BindingManager()->ResolveTag(aContent
, aNameSpaceID
);
694 NS_IF_ADDREF(*aResult
);
697 *aNameSpaceID
= aContent
->GetNameSpaceID();
698 NS_ADDREF(*aResult
= aContent
->Tag());
706 // AttachGlobalKeyHandler
708 // Creates a new key handler and prepares to listen to key events on the given
709 // event receiver (either a document or an content node). If the receiver is content,
710 // then extra work needs to be done to hook it up to the document (XXX WHY??)
713 nsXBLService::AttachGlobalKeyHandler(nsPIDOMEventTarget
* aTarget
)
715 // check if the receiver is a content node (not a document), and hook
716 // it to the document if that is the case.
717 nsCOMPtr
<nsPIDOMEventTarget
> piTarget
= aTarget
;
718 nsCOMPtr
<nsIContent
> contentNode(do_QueryInterface(aTarget
));
720 // Only attach if we're really in a document
721 nsCOMPtr
<nsIDocument
> doc
= contentNode
->GetCurrentDoc();
723 piTarget
= do_QueryInterface(doc
); // We're a XUL keyset. Attach to our document.
727 return NS_ERROR_FAILURE
;
729 // the listener already exists, so skip this
730 if (contentNode
&& contentNode
->GetProperty(nsGkAtoms::listener
))
733 nsCOMPtr
<nsIDOMElement
> elt(do_QueryInterface(contentNode
));
735 // Create the key handler
736 nsXBLWindowKeyHandler
* handler
;
737 NS_NewXBLWindowKeyHandler(elt
, piTarget
, &handler
); // This addRef's
739 return NS_ERROR_FAILURE
;
741 // listen to these events
742 nsCOMPtr
<nsIDOMEventGroup
> systemGroup
;
743 piTarget
->GetSystemEventGroup(getter_AddRefs(systemGroup
));
744 nsCOMPtr
<nsIDOM3EventTarget
> target
= do_QueryInterface(piTarget
);
746 target
->AddGroupedEventListener(NS_LITERAL_STRING("keydown"), handler
,
747 PR_FALSE
, systemGroup
);
748 target
->AddGroupedEventListener(NS_LITERAL_STRING("keyup"), handler
,
749 PR_FALSE
, systemGroup
);
750 target
->AddGroupedEventListener(NS_LITERAL_STRING("keypress"), handler
,
751 PR_FALSE
, systemGroup
);
754 return contentNode
->SetProperty(nsGkAtoms::listener
, handler
,
755 nsPropertyTable::SupportsDtorFunc
, PR_TRUE
);
757 // release the handler. The reference will be maintained by the event target,
758 // and, if there is a content node, the property.
764 // DetachGlobalKeyHandler
766 // Removes a key handler added by DeatchGlobalKeyHandler.
769 nsXBLService::DetachGlobalKeyHandler(nsPIDOMEventTarget
* aTarget
)
771 nsCOMPtr
<nsPIDOMEventTarget
> piTarget
= aTarget
;
772 nsCOMPtr
<nsIContent
> contentNode(do_QueryInterface(aTarget
));
773 if (!contentNode
) // detaching is only supported for content nodes
774 return NS_ERROR_FAILURE
;
776 // Only attach if we're really in a document
777 nsCOMPtr
<nsIDocument
> doc
= contentNode
->GetCurrentDoc();
779 piTarget
= do_QueryInterface(doc
);
781 return NS_ERROR_FAILURE
;
783 nsIDOMEventListener
* handler
=
784 static_cast<nsIDOMEventListener
*>(contentNode
->GetProperty(nsGkAtoms::listener
));
786 return NS_ERROR_FAILURE
;
788 nsCOMPtr
<nsIDOMEventGroup
> systemGroup
;
789 piTarget
->GetSystemEventGroup(getter_AddRefs(systemGroup
));
790 nsCOMPtr
<nsIDOM3EventTarget
> target
= do_QueryInterface(piTarget
);
792 target
->RemoveGroupedEventListener(NS_LITERAL_STRING("keydown"), handler
,
793 PR_FALSE
, systemGroup
);
794 target
->RemoveGroupedEventListener(NS_LITERAL_STRING("keyup"), handler
,
795 PR_FALSE
, systemGroup
);
796 target
->RemoveGroupedEventListener(NS_LITERAL_STRING("keypress"), handler
,
797 PR_FALSE
, systemGroup
);
799 contentNode
->DeleteProperty(nsGkAtoms::listener
);
805 nsXBLService::Observe(nsISupports
* aSubject
, const char* aTopic
, const PRUnichar
* aSomeData
)
807 if (nsCRT::strcmp(aTopic
, "memory-pressure") == 0)
814 nsXBLService::FlushMemory()
816 while (!JS_CLIST_IS_EMPTY(&gClassLRUList
)) {
817 JSCList
* lru
= gClassLRUList
.next
;
818 nsXBLJSClass
* c
= static_cast<nsXBLJSClass
*>(lru
);
820 JS_REMOVE_AND_INIT_LINK(lru
);
822 gClassLRUListLength
--;
827 // Internal helper methods ////////////////////////////////////////////////////////////////
829 NS_IMETHODIMP
nsXBLService::BindingReady(nsIContent
* aBoundElement
,
833 // Don't do a security check here; we know this binding is set to go.
834 return GetBinding(aBoundElement
, aURI
, PR_TRUE
, nsnull
, aIsReady
, nsnull
);
838 nsXBLService::GetBinding(nsIContent
* aBoundElement
, nsIURI
* aURI
,
839 PRBool aPeekOnly
, nsIPrincipal
* aOriginPrincipal
,
840 PRBool
* aIsReady
, nsXBLBinding
** aResult
)
842 // More than 6 binding URIs are rare, see bug 55070 comment 18.
843 nsAutoTArray
<nsIURI
*, 6> uris
;
844 return GetBinding(aBoundElement
, aURI
, aPeekOnly
, aOriginPrincipal
, aIsReady
,
849 nsXBLService::GetBinding(nsIContent
* aBoundElement
, nsIURI
* aURI
,
850 PRBool aPeekOnly
, nsIPrincipal
* aOriginPrincipal
,
851 PRBool
* aIsReady
, nsXBLBinding
** aResult
,
852 nsTArray
<nsIURI
*>& aDontExtendURIs
)
854 NS_ASSERTION(aPeekOnly
|| aResult
,
855 "Must have non-null out param if not just peeking to see "
856 "whether the binding is ready");
862 return NS_ERROR_FAILURE
;
865 nsCOMPtr
<nsIURL
> url(do_QueryInterface(aURI
));
869 nsCOMPtr
<nsIDocument
> boundDocument
= aBoundElement
->GetOwnerDoc();
871 nsRefPtr
<nsXBLDocumentInfo
> docInfo
;
872 nsresult rv
= LoadBindingDocumentInfo(aBoundElement
, boundDocument
, aURI
,
874 PR_FALSE
, getter_AddRefs(docInfo
));
875 NS_ENSURE_SUCCESS(rv
, rv
);
878 return NS_ERROR_FAILURE
;
880 // Get our doc info and determine our script access.
881 nsCOMPtr
<nsIDocument
> doc
= docInfo
->GetDocument();
882 PRBool allowScripts
= docInfo
->GetScriptAccess();
884 nsXBLPrototypeBinding
* protoBinding
= docInfo
->GetPrototypeBinding(ref
);
886 NS_ASSERTION(protoBinding
, "Unable to locate an XBL binding.");
888 return NS_ERROR_FAILURE
;
890 NS_ENSURE_TRUE(aDontExtendURIs
.AppendElement(protoBinding
->BindingURI()),
891 NS_ERROR_OUT_OF_MEMORY
);
892 nsCOMPtr
<nsIURI
> altBindingURI
= protoBinding
->AlternateBindingURI();
894 NS_ENSURE_TRUE(aDontExtendURIs
.AppendElement(altBindingURI
),
895 NS_ERROR_OUT_OF_MEMORY
);
898 nsCOMPtr
<nsIContent
> child
= protoBinding
->GetBindingElement();
900 // Our prototype binding must have all its resources loaded.
901 PRBool ready
= protoBinding
->LoadResources();
903 // Add our bound element to the protos list of elts that should
904 // be notified when the stylesheets and scripts finish loading.
905 protoBinding
->AddResourceListener(aBoundElement
);
906 return NS_ERROR_FAILURE
; // The binding isn't ready yet.
909 // If our prototype already has a base, then don't check for an "extends" attribute.
910 nsRefPtr
<nsXBLBinding
> baseBinding
;
911 PRBool hasBase
= protoBinding
->HasBasePrototype();
912 nsXBLPrototypeBinding
* baseProto
= protoBinding
->GetBasePrototype();
914 // Use the NodePrincipal() of the <binding> element in question
915 // for the security check.
916 rv
= GetBinding(aBoundElement
, baseProto
->BindingURI(), aPeekOnly
,
917 child
->NodePrincipal(), aIsReady
,
918 getter_AddRefs(baseBinding
), aDontExtendURIs
);
920 return rv
; // We aren't ready yet.
923 // Check for the presence of 'extends' and 'display' attributes
924 nsAutoString display
, extends
;
925 child
->GetAttr(kNameSpaceID_None
, nsGkAtoms::display
, display
);
926 child
->GetAttr(kNameSpaceID_None
, nsGkAtoms::extends
, extends
);
927 PRBool hasDisplay
= !display
.IsEmpty();
928 PRBool hasExtends
= !extends
.IsEmpty();
930 nsAutoString
value(extends
);
933 protoBinding
->SetHasBasePrototype(PR_FALSE
);
935 // Now slice 'em up to see what we've got.
939 offset
= display
.FindChar(':');
941 display
.Left(prefix
, offset
);
942 display
.Cut(0, offset
+1);
945 else if (hasExtends
) {
946 offset
= extends
.FindChar(':');
948 extends
.Left(prefix
, offset
);
949 extends
.Cut(0, offset
+1);
954 nsAutoString nameSpace
;
956 if (!prefix
.IsEmpty()) {
957 nsCOMPtr
<nsIAtom
> prefixAtom
= do_GetAtom(prefix
);
959 nsCOMPtr
<nsIDOM3Node
> node(do_QueryInterface(child
));
962 node
->LookupNamespaceURI(prefix
, nameSpace
);
964 if (!nameSpace
.IsEmpty()) {
966 // We extend some widget/frame. We don't really have a
968 protoBinding
->SetHasBasePrototype(PR_FALSE
);
969 //child->UnsetAttr(kNameSpaceID_None, nsGkAtoms::extends, PR_FALSE);
972 PRInt32 nameSpaceID
=
973 nsContentUtils::NameSpaceManager()->GetNameSpaceID(nameSpace
);
975 nsCOMPtr
<nsIAtom
> tagName
= do_GetAtom(display
);
976 // Check the white list
977 if (!CheckTagNameWhiteList(nameSpaceID
, tagName
)) {
978 const PRUnichar
* params
[] = { display
.get() };
979 nsContentUtils::ReportToConsole(nsContentUtils::eXBL_PROPERTIES
,
980 "InvalidExtendsBinding",
981 params
, NS_ARRAY_LENGTH(params
),
982 doc
->GetDocumentURI(),
984 nsIScriptError::errorFlag
,
986 NS_ASSERTION(!IsChromeOrResourceURI(aURI
),
987 "Invalid extends value");
988 return NS_ERROR_ILLEGAL_VALUE
;
991 protoBinding
->SetBaseTag(nameSpaceID
, tagName
);
996 if (hasExtends
&& (hasDisplay
|| nameSpace
.IsEmpty())) {
997 // Look up the prefix.
998 // We have a base class binding. Load it right now.
999 nsCOMPtr
<nsIURI
> bindingURI
;
1000 rv
= NS_NewURI(getter_AddRefs(bindingURI
), value
,
1001 doc
->GetDocumentCharacterSet().get(),
1002 doc
->GetDocBaseURI());
1003 NS_ENSURE_SUCCESS(rv
, rv
);
1005 PRUint32 count
= aDontExtendURIs
.Length();
1006 for (PRUint32 index
= 0; index
< count
; ++index
) {
1008 rv
= aDontExtendURIs
[index
]->Equals(bindingURI
, &equal
);
1009 NS_ENSURE_SUCCESS(rv
, rv
);
1012 protoBinding
->BindingURI()->GetSpec(spec
);
1013 NS_ConvertUTF8toUTF16
protoSpec(spec
);
1014 const PRUnichar
* params
[] = { protoSpec
.get(), value
.get() };
1015 nsContentUtils::ReportToConsole(nsContentUtils::eXBL_PROPERTIES
,
1016 "CircularExtendsBinding",
1017 params
, NS_ARRAY_LENGTH(params
),
1018 boundDocument
->GetDocumentURI(),
1019 EmptyString(), 0, 0,
1020 nsIScriptError::warningFlag
,
1022 return NS_ERROR_ILLEGAL_VALUE
;
1026 // Use the NodePrincipal() of the <binding> element in question
1027 // for the security check.
1028 rv
= GetBinding(aBoundElement
, bindingURI
, aPeekOnly
,
1029 child
->NodePrincipal(), aIsReady
,
1030 getter_AddRefs(baseBinding
), aDontExtendURIs
);
1032 return rv
; // Binding not yet ready or an error occurred.
1034 // Make sure to set the base prototype.
1035 baseProto
= baseBinding
->PrototypeBinding();
1036 protoBinding
->SetBasePrototype(baseProto
);
1037 child
->UnsetAttr(kNameSpaceID_None
, nsGkAtoms::extends
, PR_FALSE
);
1038 child
->UnsetAttr(kNameSpaceID_None
, nsGkAtoms::display
, PR_FALSE
);
1044 *aIsReady
= PR_TRUE
;
1046 // Make a new binding
1047 nsXBLBinding
*newBinding
= new nsXBLBinding(protoBinding
);
1048 NS_ENSURE_TRUE(newBinding
, NS_ERROR_OUT_OF_MEMORY
);
1051 newBinding
->SetBaseBinding(baseBinding
);
1053 NS_ADDREF(*aResult
= newBinding
);
1059 static PRBool
SchemeIs(nsIURI
* aURI
, const char* aScheme
)
1061 nsCOMPtr
<nsIURI
> baseURI
= NS_GetInnermostURI(aURI
);
1062 NS_ENSURE_TRUE(baseURI
, PR_FALSE
);
1064 PRBool isScheme
= PR_FALSE
;
1065 return NS_SUCCEEDED(baseURI
->SchemeIs(aScheme
, &isScheme
)) && isScheme
;
1069 IsSystemOrChromeURLPrincipal(nsIPrincipal
* aPrincipal
)
1071 if (nsContentUtils::IsSystemPrincipal(aPrincipal
)) {
1075 nsCOMPtr
<nsIURI
> uri
;
1076 aPrincipal
->GetURI(getter_AddRefs(uri
));
1077 NS_ENSURE_TRUE(uri
, PR_FALSE
);
1079 PRBool isChrome
= PR_FALSE
;
1080 return NS_SUCCEEDED(uri
->SchemeIs("chrome", &isChrome
)) && isChrome
;
1084 nsXBLService::LoadBindingDocumentInfo(nsIContent
* aBoundElement
,
1085 nsIDocument
* aBoundDocument
,
1086 nsIURI
* aBindingURI
,
1087 nsIPrincipal
* aOriginPrincipal
,
1088 PRBool aForceSyncLoad
,
1089 nsXBLDocumentInfo
** aResult
)
1091 NS_PRECONDITION(aBindingURI
, "Must have a binding URI");
1092 NS_PRECONDITION(!aOriginPrincipal
|| aBoundDocument
,
1093 "If we're doing a security check, we better have a document!");
1096 if (aOriginPrincipal
) {
1097 // Security check - Enforce same-origin policy, except to chrome.
1098 // We have to be careful to not pass aContent as the context here.
1099 // Otherwise, if there is a JS-implemented content policy, we will attempt
1100 // to wrap the content node, which will try to load XBL bindings for it, if
1101 // any. Since we're not done loading this binding yet, that will reenter
1102 // this method and we'll end up creating a binding and then immediately
1103 // clobbering it in our table. That makes things very confused, leading to
1104 // misbehavior and crashes.
1105 rv
= nsContentUtils::
1106 CheckSecurityBeforeLoad(aBindingURI
, aOriginPrincipal
,
1107 nsIScriptSecurityManager::ALLOW_CHROME
,
1109 nsIContentPolicy::TYPE_XBL
,
1111 NS_ENSURE_SUCCESS(rv
, NS_ERROR_XBL_BLOCKED
);
1113 if (!IsSystemOrChromeURLPrincipal(aOriginPrincipal
)) {
1114 // Also make sure that we're same-origin with the bound document
1115 // except if the stylesheet has the system principal.
1116 if (!(gAllowDataURIs
&& SchemeIs(aBindingURI
, "data")) &&
1117 !SchemeIs(aBindingURI
, "chrome")) {
1118 rv
= aBoundDocument
->NodePrincipal()->CheckMayLoad(aBindingURI
,
1120 NS_ENSURE_SUCCESS(rv
, NS_ERROR_XBL_BLOCKED
);
1123 // Finally check if this document is allowed to use XBL at all.
1124 NS_ENSURE_TRUE(aBoundDocument
->AllowXULXBL(),
1125 NS_ERROR_XBL_BLOCKED
);
1130 nsRefPtr
<nsXBLDocumentInfo
> info
;
1132 nsCOMPtr
<nsIURI
> documentURI
;
1133 rv
= aBindingURI
->Clone(getter_AddRefs(documentURI
));
1134 NS_ENSURE_SUCCESS(rv
, rv
);
1136 nsCOMPtr
<nsIURL
> documentURL(do_QueryInterface(documentURI
));
1138 documentURL
->SetRef(EmptyCString());
1141 // We've got a file. Check our XBL document cache.
1142 nsXULPrototypeCache
* cache
= nsXULPrototypeCache::GetInstance();
1143 PRBool useXULCache
= cache
&& cache
->IsEnabled();
1146 // The first line of defense is the chrome cache.
1147 // This cache crosses the entire product, so that any XBL bindings that are
1148 // part of chrome will be reused across all XUL documents.
1149 info
= cache
->GetXBLDocumentInfo(documentURI
);
1154 // The second line of defense is the binding manager's document table.
1155 nsBindingManager
*bindingManager
= nsnull
;
1157 if (aBoundDocument
) {
1158 bindingManager
= aBoundDocument
->BindingManager();
1159 info
= bindingManager
->GetXBLDocumentInfo(documentURI
);
1162 nsINodeInfo
*ni
= nsnull
;
1164 ni
= aBoundElement
->NodeInfo();
1166 if (!info
&& bindingManager
&&
1167 (!ni
|| !(ni
->Equals(nsGkAtoms::scrollbar
, kNameSpaceID_XUL
) ||
1168 ni
->Equals(nsGkAtoms::thumb
, kNameSpaceID_XUL
) ||
1169 ((ni
->Equals(nsGkAtoms::input
) ||
1170 ni
->Equals(nsGkAtoms::select
)) &&
1171 aBoundElement
->IsHTML()))) && !aForceSyncLoad
) {
1172 // The third line of defense is to investigate whether or not the
1173 // document is currently being loaded asynchronously. If so, there's no
1174 // document yet, but we need to glom on our request so that it will be
1175 // processed whenever the doc does finish loading.
1176 nsCOMPtr
<nsIStreamListener
> listener
;
1178 listener
= bindingManager
->GetLoadingDocListener(documentURI
);
1180 nsXBLStreamListener
* xblListener
=
1181 static_cast<nsXBLStreamListener
*>(listener
.get());
1182 // Create a new load observer.
1183 if (!xblListener
->HasRequest(aBindingURI
, aBoundElement
)) {
1184 nsXBLBindingRequest
* req
= nsXBLBindingRequest::Create(mPool
, aBindingURI
, aBoundElement
);
1185 xblListener
->AddRequest(req
);
1192 // Finally, if all lines of defense fail, we go and fetch the binding
1195 // Always load chrome synchronously
1197 if (NS_SUCCEEDED(documentURI
->SchemeIs("chrome", &chrome
)) && chrome
)
1198 aForceSyncLoad
= PR_TRUE
;
1200 nsCOMPtr
<nsIDocument
> document
;
1201 FetchBindingDocument(aBoundElement
, aBoundDocument
, documentURI
,
1202 aBindingURI
, aForceSyncLoad
, getter_AddRefs(document
));
1205 nsBindingManager
*xblDocBindingManager
= document
->BindingManager();
1206 info
= xblDocBindingManager
->GetXBLDocumentInfo(documentURI
);
1208 NS_ERROR("An XBL file is malformed. Did you forget the XBL namespace on the bindings tag?");
1209 return NS_ERROR_FAILURE
;
1211 xblDocBindingManager
->RemoveXBLDocumentInfo(info
); // Break the self-imposed cycle.
1213 // If the doc is a chrome URI, then we put it into the XUL cache.
1215 if (useXULCache
&& IsChromeOrResourceURI(documentURI
)) {
1216 cache
->PutXBLDocumentInfo(info
);
1220 if (bindingManager
) {
1221 // Also put it in our binding manager's document table.
1222 bindingManager
->PutXBLDocumentInfo(info
);
1232 NS_IF_ADDREF(*aResult
);
1238 nsXBLService::FetchBindingDocument(nsIContent
* aBoundElement
, nsIDocument
* aBoundDocument
,
1239 nsIURI
* aDocumentURI
, nsIURI
* aBindingURI
,
1240 PRBool aForceSyncLoad
, nsIDocument
** aResult
)
1244 nsresult rv
= NS_OK
;
1245 // Initialize our out pointer to nsnull
1248 // Now we have to synchronously load the binding file.
1249 // Create an XML content sink and a parser.
1250 nsCOMPtr
<nsILoadGroup
> loadGroup
;
1252 loadGroup
= aBoundDocument
->GetDocumentLoadGroup();
1254 // We really shouldn't have to force a sync load for anything here... could
1255 // we get away with not doing that? Not sure.
1256 if (IsChromeOrResourceURI(aDocumentURI
))
1257 aForceSyncLoad
= PR_TRUE
;
1259 // Create document and contentsink and set them up.
1260 nsCOMPtr
<nsIDocument
> doc
;
1261 rv
= NS_NewXMLDocument(getter_AddRefs(doc
));
1262 NS_ENSURE_SUCCESS(rv
, rv
);
1264 nsCOMPtr
<nsIXMLContentSink
> xblSink
;
1265 rv
= NS_NewXBLContentSink(getter_AddRefs(xblSink
), doc
, aDocumentURI
, nsnull
);
1266 NS_ENSURE_SUCCESS(rv
, rv
);
1269 nsCOMPtr
<nsIChannel
> channel
;
1270 rv
= NS_NewChannel(getter_AddRefs(channel
), aDocumentURI
, nsnull
, loadGroup
);
1271 NS_ENSURE_SUCCESS(rv
, rv
);
1273 nsCOMPtr
<nsIInterfaceRequestor
> sameOriginChecker
= nsContentUtils::GetSameOriginChecker();
1274 NS_ENSURE_TRUE(sameOriginChecker
, NS_ERROR_OUT_OF_MEMORY
);
1276 channel
->SetNotificationCallbacks(sameOriginChecker
);
1278 if (!aForceSyncLoad
) {
1279 // We can be asynchronous
1280 nsXBLStreamListener
* xblListener
=
1281 new nsXBLStreamListener(this, aBoundDocument
, xblSink
, doc
);
1282 NS_ENSURE_TRUE(xblListener
,NS_ERROR_OUT_OF_MEMORY
);
1284 // Add ourselves to the list of loading docs.
1285 nsBindingManager
*bindingManager
;
1287 bindingManager
= aBoundDocument
->BindingManager();
1289 bindingManager
= nsnull
;
1292 bindingManager
->PutLoadingDocListener(aDocumentURI
, xblListener
);
1295 nsXBLBindingRequest
* req
= nsXBLBindingRequest::Create(mPool
,
1298 xblListener
->AddRequest(req
);
1300 // Now kick off the async read.
1301 rv
= channel
->AsyncOpen(xblListener
, nsnull
);
1302 if (NS_FAILED(rv
)) {
1303 // Well, we won't be getting a load. Make sure to clean up our stuff!
1304 if (bindingManager
) {
1305 bindingManager
->RemoveLoadingDocListener(aDocumentURI
);
1311 nsCOMPtr
<nsIStreamListener
> listener
;
1312 rv
= doc
->StartDocumentLoad("loadAsInteractiveData",
1316 getter_AddRefs(listener
),
1319 NS_ENSURE_SUCCESS(rv
, rv
);
1321 // Now do a blocking synchronous parse of the file.
1322 nsCOMPtr
<nsIInputStream
> in
;
1323 rv
= channel
->Open(getter_AddRefs(in
));
1324 NS_ENSURE_SUCCESS(rv
, rv
);
1326 rv
= nsSyncLoadService::PushSyncStreamToListener(in
, listener
, channel
);
1327 NS_ENSURE_SUCCESS(rv
, rv
);
1334 // Creation Routine ///////////////////////////////////////////////////////////////////////
1336 nsresult
NS_NewXBLService(nsIXBLService
** aResult
);
1339 NS_NewXBLService(nsIXBLService
** aResult
)
1341 nsXBLService
* result
= new nsXBLService
;
1343 return NS_ERROR_OUT_OF_MEMORY
;
1345 NS_ADDREF(*aResult
= result
);
1347 // Register the first (and only) nsXBLService as a memory pressure observer
1348 // so it can flush the LRU list in low-memory situations.
1349 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
1351 os
->AddObserver(result
, "memory-pressure", PR_TRUE
);