1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 * Chris Waterson <waterson@netscape.com>
24 * Dan Rosen <dr@netscape.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #ifndef nsXULDocument_h__
41 #define nsXULDocument_h__
44 #include "nsXULPrototypeDocument.h"
45 #include "nsXULPrototypeCache.h"
48 #include "nsXMLDocument.h"
49 #include "nsForwardReference.h"
50 #include "nsIContent.h"
51 #include "nsIDOMEventTarget.h"
52 #include "nsIDOMXULCommandDispatcher.h"
53 #include "nsIDOMXULDocument.h"
54 #include "nsCOMArray.h"
56 #include "nsIXULDocument.h"
57 #include "nsScriptLoader.h"
58 #include "nsIStreamListener.h"
59 #include "nsICSSLoaderObserver.h"
63 class nsIXULPrototypeCache
;
64 class nsIFocusController
;
65 #if 0 // XXXbe save me, scc (need NSCAP_FORWARD_DECL(nsXULPrototypeScript))
66 class nsIObjectInputStream
;
67 class nsIObjectOutputStream
;
68 class nsIXULPrototypeScript
;
70 #include "nsIObjectInputStream.h"
71 #include "nsIObjectOutputStream.h"
72 #include "nsXULElement.h"
74 #include "nsURIHashKey.h"
75 #include "nsInterfaceHashtable.h"
78 struct PRLogModuleInfo
;
80 class nsRefMapEntry
: public nsISupportsHashKey
83 nsRefMapEntry(const nsISupports
* aKey
) :
84 nsISupportsHashKey(aKey
)
87 nsRefMapEntry(const nsRefMapEntry
& aOther
) :
88 nsISupportsHashKey(GetKey())
90 NS_ERROR("Should never be called");
93 nsIContent
* GetFirstContent();
94 void AppendAll(nsCOMArray
<nsIContent
>* aElements
);
96 * @return true if aContent was added, false if we failed due to OOM
98 PRBool
AddContent(nsIContent
* aContent
);
100 * @return true if aContent was removed and it was the last content for
101 * this ref, so this entry should be removed from the map
103 PRBool
RemoveContent(nsIContent
* aContent
);
106 nsSmallVoidArray mRefContentList
;
110 * The XUL document class
112 class nsXULDocument
: public nsXMLDocument
,
113 public nsIXULDocument
,
114 public nsIDOMXULDocument
,
115 public nsIStreamLoaderObserver
,
116 public nsICSSLoaderObserver
120 virtual ~nsXULDocument();
122 // nsISupports interface
123 NS_DECL_ISUPPORTS_INHERITED
124 NS_DECL_NSISTREAMLOADEROBSERVER
126 // nsIDocument interface
127 virtual void Reset(nsIChannel
* aChannel
, nsILoadGroup
* aLoadGroup
);
128 virtual void ResetToURI(nsIURI
*aURI
, nsILoadGroup
* aLoadGroup
,
129 nsIPrincipal
* aPrincipal
);
131 virtual nsresult
StartDocumentLoad(const char* aCommand
,
133 nsILoadGroup
* aLoadGroup
,
134 nsISupports
* aContainer
,
135 nsIStreamListener
**aDocListener
,
136 PRBool aReset
= PR_TRUE
,
137 nsIContentSink
* aSink
= nsnull
);
139 virtual void SetContentType(const nsAString
& aContentType
);
141 virtual void EndLoad();
143 // nsIMutationObserver interface
144 NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
145 NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
146 NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
147 NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
149 virtual void AttributeWillChange(nsIContent
* aChild
,
150 PRInt32 aNameSpaceID
,
151 nsIAtom
* aAttribute
);
153 // nsIXULDocument interface
154 NS_IMETHOD
AddElementForID(nsIContent
* aElement
);
155 NS_IMETHOD
GetElementsForID(const nsAString
& aID
,
156 nsCOMArray
<nsIContent
>& aElements
);
158 NS_IMETHOD
GetScriptGlobalObjectOwner(nsIScriptGlobalObjectOwner
** aGlobalOwner
);
159 NS_IMETHOD
AddSubtreeToDocument(nsIContent
* aElement
);
160 NS_IMETHOD
RemoveSubtreeFromDocument(nsIContent
* aElement
);
161 NS_IMETHOD
SetTemplateBuilderFor(nsIContent
* aContent
,
162 nsIXULTemplateBuilder
* aBuilder
);
163 NS_IMETHOD
GetTemplateBuilderFor(nsIContent
* aContent
,
164 nsIXULTemplateBuilder
** aResult
);
165 NS_IMETHOD
OnPrototypeLoadDone(PRBool aResumeWalk
);
166 PRBool
OnDocumentParserError();
168 // nsIDOMNode interface overrides
169 NS_IMETHOD
CloneNode(PRBool deep
, nsIDOMNode
**_retval
);
171 // nsIDOMDocument interface overrides
172 NS_IMETHOD
GetElementById(const nsAString
& elementId
,
173 nsIDOMElement
**_retval
);
175 // nsIDOMXULDocument interface
176 NS_DECL_NSIDOMXULDOCUMENT
179 NS_IMETHOD
GetContentType(nsAString
& aContentType
);
181 // nsICSSLoaderObserver
182 NS_IMETHOD
StyleSheetLoaded(nsICSSStyleSheet
* aSheet
,
183 PRBool aWasAlternate
,
186 virtual void EndUpdate(nsUpdateType aUpdateType
);
189 MatchAttribute(nsIContent
* aContent
,
190 PRInt32 aNameSpaceID
,
194 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULDocument
, nsXMLDocument
)
197 // Implementation methods
199 NS_NewXULDocument(nsIXULDocument
** aResult
);
202 nsresult
StartLayout(void);
205 AddElementToRefMap(nsIContent
* aElement
);
207 RemoveElementFromRefMap(nsIContent
* aElement
);
209 nsresult
GetViewportSize(PRInt32
* aWidth
, PRInt32
* aHeight
);
211 nsresult
PrepareToLoad(nsISupports
* aContainer
,
212 const char* aCommand
,
213 nsIChannel
* aChannel
,
214 nsILoadGroup
* aLoadGroup
,
215 nsIParser
** aResult
);
218 PrepareToLoadPrototype(nsIURI
* aURI
,
219 const char* aCommand
,
220 nsIPrincipal
* aDocumentPrincipal
,
221 nsIParser
** aResult
);
224 LoadOverlayInternal(nsIURI
* aURI
, PRBool aIsDynamic
, PRBool
* aShouldReturn
,
225 PRBool
* aFailureFromContent
);
227 nsresult
ApplyPersistentAttributes();
228 nsresult
ApplyPersistentAttributesInternal();
229 nsresult
ApplyPersistentAttributesToElements(nsIRDFResource
* aResource
,
230 nsCOMArray
<nsIContent
>& aElements
);
233 AddElementToDocumentPre(nsIContent
* aElement
);
236 AddElementToDocumentPost(nsIContent
* aElement
);
239 ExecuteOnBroadcastHandlerFor(nsIContent
* aBroadcaster
,
240 nsIDOMElement
* aListener
,
243 void GetFocusController(nsIFocusController
** aFocusController
);
245 PRInt32
GetDefaultNamespaceID() const
247 return kNameSpaceID_XUL
;
252 static PRInt32 gRefCnt
;
254 static nsIAtom
** kIdentityAttrs
[];
256 static nsIRDFService
* gRDFService
;
257 static nsIRDFResource
* kNC_persist
;
258 static nsIRDFResource
* kNC_attribute
;
259 static nsIRDFResource
* kNC_value
;
261 static nsXULPrototypeCache
* gXULCache
;
263 static PRLogModuleInfo
* gXULLog
;
266 IsCapabilityEnabled(const char* aCapabilityLabel
);
269 Persist(nsIContent
* aElement
, PRInt32 aNameSpaceID
, nsIAtom
* aAttribute
);
271 // IMPORTANT: The ownership implicit in the following member
272 // variables has been explicitly checked and set using nsCOMPtr
273 // for owning pointers and raw COM interface pointers for weak
274 // (ie, non owning) references. If you add any members to this
275 // class, please make the ownership explicit (pinkerton, scc).
276 // NOTE, THIS IS STILL IN PROGRESS, TALK TO PINK OR SCC BEFORE
279 nsXULDocument
* mNextSrcLoadWaiter
; // [OWNER] but not COMPtr
281 // Tracks elements with a 'ref' attribute, or an 'id' attribute where
282 // the element's namespace has no registered ID attribute name.
283 nsTHashtable
<nsRefMapEntry
> mRefMap
;
284 nsCOMPtr
<nsIRDFDataSource
> mLocalStore
;
285 PRPackedBool mApplyingPersistedAttrs
;
286 PRPackedBool mIsWritingFastLoad
;
287 PRPackedBool mDocumentLoaded
;
289 * Since ResumeWalk is interruptible, it's possible that last
290 * stylesheet finishes loading while the PD walk is still in
291 * progress (waiting for an overlay to finish loading).
292 * mStillWalking prevents DoneLoading (and StartLayout) from being
293 * called in this situation.
295 PRPackedBool mStillWalking
;
298 * An array of style sheets, that will be added (preserving order) to the
299 * document after all of them are loaded (in DoneWalking).
301 nsCOMArray
<nsICSSStyleSheet
> mOverlaySheets
;
303 nsCOMPtr
<nsIDOMXULCommandDispatcher
> mCommandDispatcher
; // [OWNER] of the focus tracker
305 // Maintains the template builders that have been attached to
307 typedef nsInterfaceHashtable
<nsISupportsHashKey
, nsIXULTemplateBuilder
>
309 BuilderTable
* mTemplateBuilderTable
;
311 PRUint32 mPendingSheets
;
316 * We used to have two pointers into the content model: mPopupNode and
317 * mTooltipNode, which were used to retrieve the objects triggering a
318 * popup or tooltip. You need that access because your reference has
319 * disappeared by the time you click on a popup item or do whatever
320 * with a tooltip. These were owning references (no cycles, as pinkerton
321 * pointed out, since we're still parent-child).
323 * We still have mTooltipNode, but mPopupNode has moved to the
324 * FocusController. The APIs (IDL attributes popupNode and tooltipNode)
325 * are still here for compatibility and ease of use, but we should
326 * probably move the mTooltipNode over to FocusController at some point
327 * as well, for consistency.
330 nsCOMPtr
<nsIDOMNode
> mTooltipNode
; // [OWNER] element triggering the tooltip
333 * Context stack, which maintains the state of the Builder and allows
334 * it to be interrupted.
339 nsXULPrototypeElement
* mPrototype
;
340 nsIContent
* mElement
;
352 PRInt32
Depth() { return mDepth
; }
354 nsresult
Push(nsXULPrototypeElement
* aPrototype
, nsIContent
* aElement
);
356 nsresult
Peek(nsXULPrototypeElement
** aPrototype
, nsIContent
** aElement
, PRInt32
* aIndex
);
358 nsresult
SetTopIndex(PRInt32 aIndex
);
360 PRBool
IsInsideXULTemplate();
363 friend class ContextStack
;
364 ContextStack mContextStack
;
366 enum State
{ eState_Master
, eState_Overlay
};
370 * An array of overlay nsIURIs that have yet to be resolved. The
371 * order of the array is significant: overlays at the _end_ of the
372 * array are resolved before overlays earlier in the array (i.e.,
375 * In the current implementation the order the overlays are loaded
376 * in is as follows: first overlays from xul-overlay PIs, in the
377 * same order as in the document, then the overlays from the chrome
380 nsCOMArray
<nsIURI
> mUnloadedOverlays
;
383 * Load the transcluded script at the specified URI. If the
384 * prototype construction must 'block' until the load has
385 * completed, aBlock will be set to true.
387 nsresult
LoadScript(nsXULPrototypeScript
*aScriptProto
, PRBool
* aBlock
);
390 * Execute the precompiled script object scoped by this XUL document's
391 * containing window object, and using its associated script context.
393 nsresult
ExecuteScript(nsIScriptContext
*aContext
, void* aScriptObject
);
396 * Helper method for the above that uses aScript to find the appropriate
397 * script context and object.
399 nsresult
ExecuteScript(nsXULPrototypeScript
*aScript
);
402 * Create a delegate content model element from a prototype.
403 * Note that the resulting content node is not bound to any tree
405 nsresult
CreateElementFromPrototype(nsXULPrototypeElement
* aPrototype
,
406 nsIContent
** aResult
);
409 * Create a hook-up element to which content nodes can be attached for
412 nsresult
CreateOverlayElement(nsXULPrototypeElement
* aPrototype
, nsIContent
** aResult
);
415 * Add attributes from the prototype to the element.
417 nsresult
AddAttributes(nsXULPrototypeElement
* aPrototype
, nsIContent
* aElement
);
420 * The prototype-script of the current transcluded script that is being
421 * loaded. For document.write('<script src="nestedwrite.js"><\/script>')
422 * to work, these need to be in a stack element type, and we need to hold
423 * the top of stack here.
425 nsXULPrototypeScript
* mCurrentScriptProto
;
428 * Check if a XUL template builder has already been hooked up.
431 CheckTemplateBuilderHookup(nsIContent
* aElement
, PRBool
* aNeedsHookup
);
434 * Create a XUL template builder on the specified node.
437 CreateTemplateBuilder(nsIContent
* aElement
);
440 * Add the current prototype's style sheets (currently it's just
441 * style overlays from the chrome registry) to the document.
443 nsresult
AddPrototypeSheets();
447 /* Declarations related to forward references.
449 * Forward references are declarations which are added to the temporary
450 * list (mForwardReferences) during the document (or overlay) load and
451 * are resolved later, when the document loading is almost complete.
455 * The list of different types of forward references to resolve. After
456 * a reference is resolved, it is removed from this array (and
457 * automatically deleted)
459 nsTArray
<nsAutoPtr
<nsForwardReference
> > mForwardReferences
;
461 /** Indicates what kind of forward references are still to be processed. */
462 nsForwardReference::Phase mResolutionPhase
;
465 * Adds aRef to the mForwardReferences array. Takes the ownership of aRef.
467 nsresult
AddForwardReference(nsForwardReference
* aRef
);
470 * Resolve all of the document's forward references.
472 nsresult
ResolveForwardReferences();
475 * Used to resolve broadcaster references
477 class BroadcasterHookup
: public nsForwardReference
480 nsXULDocument
* mDocument
; // [WEAK]
481 nsCOMPtr
<nsIContent
> mObservesElement
; // [OWNER]
485 BroadcasterHookup(nsXULDocument
* aDocument
,
486 nsIContent
* aObservesElement
)
487 : mDocument(aDocument
),
488 mObservesElement(aObservesElement
),
493 virtual ~BroadcasterHookup();
495 virtual Phase
GetPhase() { return eHookup
; }
496 virtual Result
Resolve();
499 friend class BroadcasterHookup
;
503 * Used to hook up overlays
505 class OverlayForwardReference
: public nsForwardReference
508 nsXULDocument
* mDocument
; // [WEAK]
509 nsCOMPtr
<nsIContent
> mOverlay
; // [OWNER]
512 nsresult
Merge(nsIContent
* aTargetNode
, nsIContent
* aOverlayNode
, PRBool aNotify
);
515 OverlayForwardReference(nsXULDocument
* aDocument
, nsIContent
* aOverlay
)
516 : mDocument(aDocument
), mOverlay(aOverlay
), mResolved(PR_FALSE
) {}
518 virtual ~OverlayForwardReference();
520 virtual Phase
GetPhase() { return eConstruction
; }
521 virtual Result
Resolve();
524 friend class OverlayForwardReference
;
526 class TemplateBuilderHookup
: public nsForwardReference
529 nsCOMPtr
<nsIContent
> mElement
; // [OWNER]
532 TemplateBuilderHookup(nsIContent
* aElement
)
533 : mElement(aElement
) {}
535 virtual Phase
GetPhase() { return eHookup
; }
536 virtual Result
Resolve();
539 friend class TemplateBuilderHookup
;
541 // The out params of FindBroadcaster only have values that make sense when
542 // the method returns NS_FINDBROADCASTER_FOUND. In all other cases, the
543 // values of the out params should not be relied on (though *aListener and
544 // *aBroadcaster do need to be released if non-null, of course).
546 FindBroadcaster(nsIContent
* aElement
,
547 nsIDOMElement
** aListener
,
548 nsString
& aBroadcasterID
,
549 nsString
& aAttribute
,
550 nsIDOMElement
** aBroadcaster
);
553 CheckBroadcasterHookup(nsIContent
* aElement
,
554 PRBool
* aNeedsHookup
,
555 PRBool
* aDidResolve
);
558 SynchronizeBroadcastListener(nsIDOMElement
*aBroadcaster
,
559 nsIDOMElement
*aListener
,
560 const nsAString
&aAttr
);
564 InsertElement(nsIContent
* aParent
, nsIContent
* aChild
, PRBool aNotify
);
568 RemoveElement(nsIContent
* aParent
, nsIContent
* aChild
);
571 * The current prototype that we are walking to construct the
574 nsRefPtr
<nsXULPrototypeDocument
> mCurrentPrototype
;
577 * The master document (outermost, .xul) prototype, from which
578 * all subdocuments get their security principals.
580 nsRefPtr
<nsXULPrototypeDocument
> mMasterPrototype
;
583 * Owning references to all of the prototype documents that were
584 * used to construct this document.
586 nsTArray
< nsRefPtr
<nsXULPrototypeDocument
> > mPrototypes
;
589 * Prepare to walk the current prototype.
591 nsresult
PrepareToWalk();
594 * Creates a processing instruction based on aProtoPI and inserts
595 * it to the DOM (as the aIndex-th child of aParent).
598 CreateAndInsertPI(const nsXULPrototypePI
* aProtoPI
,
599 nsINode
* aParent
, PRUint32 aIndex
);
602 * Inserts the passed <?xml-stylesheet ?> PI at the specified
603 * index. Loads and applies the associated stylesheet
605 * The prototype document walk can happen before the stylesheets
606 * are loaded, but the final steps in the load process (see
607 * DoneWalking()) are not run before all the stylesheets are done
611 InsertXMLStylesheetPI(const nsXULPrototypePI
* aProtoPI
,
614 nsIContent
* aPINode
);
617 * Inserts the passed <?xul-overlay ?> PI at the specified index.
618 * Schedules the referenced overlay URI for further processing.
621 InsertXULOverlayPI(const nsXULPrototypePI
* aProtoPI
,
624 nsIContent
* aPINode
);
627 * Add overlays from the chrome registry to the set of unprocessed
628 * overlays still to do.
630 nsresult
AddChromeOverlays();
633 * Resume (or initiate) an interrupted (or newly prepared)
636 nsresult
ResumeWalk();
639 * Called at the end of ResumeWalk() and from StyleSheetLoaded().
640 * Expects that both the prototype document walk is complete and
641 * all referenced stylesheets finished loading.
643 nsresult
DoneWalking();
646 * Report that an overlay failed to load
647 * @param aURI the URI of the overlay that failed to load
649 void ReportMissingOverlay(nsIURI
* aURI
);
651 #if defined(DEBUG_waterson) || defined(DEBUG_hyatt)
656 class CachedChromeStreamListener
: public nsIStreamListener
{
658 nsXULDocument
* mDocument
;
659 PRPackedBool mProtoLoaded
;
661 virtual ~CachedChromeStreamListener();
664 CachedChromeStreamListener(nsXULDocument
* aDocument
,
665 PRBool aProtoLoaded
);
668 NS_DECL_NSIREQUESTOBSERVER
669 NS_DECL_NSISTREAMLISTENER
672 friend class CachedChromeStreamListener
;
675 class ParserObserver
: public nsIRequestObserver
{
677 nsRefPtr
<nsXULDocument
> mDocument
;
678 nsRefPtr
<nsXULPrototypeDocument
> mPrototype
;
679 virtual ~ParserObserver();
682 ParserObserver(nsXULDocument
* aDocument
,
683 nsXULPrototypeDocument
* aPrototype
);
686 NS_DECL_NSIREQUESTOBSERVER
689 friend class ParserObserver
;
692 * A map from a broadcaster element to a list of listener elements.
694 PLDHashTable
* mBroadcasterMap
;
696 nsInterfaceHashtable
<nsURIHashKey
,nsIObserver
> mOverlayLoadObservers
;
697 nsInterfaceHashtable
<nsURIHashKey
,nsIObserver
> mPendingOverlayLoadNotifications
;
699 PRBool mInitialLayoutComplete
;
701 class nsDelayedBroadcastUpdate
704 nsDelayedBroadcastUpdate(nsIDOMElement
* aBroadcaster
,
705 nsIDOMElement
* aListener
,
706 const nsAString
&aAttr
)
707 : mBroadcaster(aBroadcaster
), mListener(aListener
), mAttr(aAttr
),
708 mSetAttr(PR_FALSE
) {}
710 nsDelayedBroadcastUpdate(nsIDOMElement
* aBroadcaster
,
711 nsIDOMElement
* aListener
,
713 const nsAString
&aAttr
,
715 : mBroadcaster(aBroadcaster
), mListener(aListener
), mAttr(aAttr
),
716 mAttrName(aAttrName
), mSetAttr(aSetAttr
) {}
718 nsDelayedBroadcastUpdate(const nsDelayedBroadcastUpdate
& aOther
)
719 : mBroadcaster(aOther
.mBroadcaster
), mListener(aOther
.mListener
),
720 mAttr(aOther
.mAttr
), mAttrName(aOther
.mAttrName
),
721 mSetAttr(aOther
.mSetAttr
) {}
723 nsCOMPtr
<nsIDOMElement
> mBroadcaster
;
724 nsCOMPtr
<nsIDOMElement
> mListener
;
725 // Note if mAttrName isn't used, this is the name of the attr, otherwise
726 // this is the value of the attribute.
728 nsCOMPtr
<nsIAtom
> mAttrName
;
732 nsTArray
<nsDelayedBroadcastUpdate
> mDelayedBroadcasters
;
733 nsTArray
<nsDelayedBroadcastUpdate
> mDelayedAttrChangeBroadcasts
;
739 #endif // nsXULDocument_h__