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
4 : *
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/
9 : *
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
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
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.
21 : *
22 : * Contributor(s):
23 : * Original Author: David W. Hyatt (hyatt@netscape.com)
24 : * Alec Flett <alecf@netscape.com>
25 : *
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.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #ifndef nsBindingManager_h_
41 : #define nsBindingManager_h_
42 :
43 : #include "nsStubMutationObserver.h"
44 : #include "pldhash.h"
45 : #include "nsInterfaceHashtable.h"
46 : #include "nsRefPtrHashtable.h"
47 : #include "nsURIHashKey.h"
48 : #include "nsCycleCollectionParticipant.h"
49 : #include "nsXBLBinding.h"
50 : #include "nsTArray.h"
51 : #include "nsThreadUtils.h"
52 :
53 : class nsIContent;
54 : class nsIXPConnectWrappedJS;
55 : class nsIAtom;
56 : class nsIDOMNodeList;
57 : class nsIDocument;
58 : class nsIURI;
59 : class nsXBLDocumentInfo;
60 : class nsIStreamListener;
61 : class nsStyleSet;
62 : class nsXBLBinding;
63 : template<class E> class nsRefPtr;
64 : typedef nsTArray<nsRefPtr<nsXBLBinding> > nsBindingList;
65 : class nsIPrincipal;
66 :
67 : class nsBindingManager : public nsStubMutationObserver
68 : {
69 : public:
70 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
71 :
72 : NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
73 : NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
74 : NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
75 :
76 : nsBindingManager(nsIDocument* aDocument);
77 : ~nsBindingManager();
78 :
79 : nsXBLBinding* GetBinding(nsIContent* aContent);
80 : nsresult SetBinding(nsIContent* aContent, nsXBLBinding* aBinding);
81 :
82 : nsIContent* GetInsertionParent(nsIContent* aContent);
83 : nsresult SetInsertionParent(nsIContent* aContent, nsIContent* aResult);
84 :
85 : /**
86 : * Notify the binding manager that an element
87 : * has been removed from its document,
88 : * so that it can update any bindings or
89 : * nsIAnonymousContentCreator-created anonymous
90 : * content that may depend on the document.
91 : * @param aContent the element that's being moved
92 : * @param aOldDocument the old document in which the
93 : * content resided.
94 : */
95 133429 : void RemovedFromDocument(nsIContent* aContent, nsIDocument* aOldDocument)
96 : {
97 133429 : if (aContent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
98 0 : RemovedFromDocumentInternal(aContent, aOldDocument);
99 : }
100 133429 : }
101 : void RemovedFromDocumentInternal(nsIContent* aContent,
102 : nsIDocument* aOldDocument);
103 :
104 : nsIAtom* ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID);
105 :
106 : /**
107 : * Return a list of all explicit children, including any children
108 : * that may have been inserted via XBL insertion points.
109 : */
110 : nsresult GetContentListFor(nsIContent* aContent, nsIDOMNodeList** aResult);
111 :
112 : /**
113 : * Non-COMy version of GetContentListFor.
114 : */
115 : nsINodeList* GetContentListFor(nsIContent* aContent);
116 :
117 : /**
118 : * Set the insertion point children for the specified element.
119 : * The binding manager assumes ownership of aList.
120 : */
121 : nsresult SetContentListFor(nsIContent* aContent,
122 : nsInsertionPointList* aList);
123 :
124 : /**
125 : * Determine whether or not the explicit child list has been altered
126 : * by XBL insertion points.
127 : */
128 : bool HasContentListFor(nsIContent* aContent);
129 :
130 : /**
131 : * Return the nodelist of "anonymous" kids for this node. This might
132 : * actually include some of the nodes actual DOM kids, if there are
133 : * <children> tags directly as kids of <content>. This will only end up
134 : * returning a non-null list for nodes which have a binding attached.
135 : */
136 : nsresult GetAnonymousNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult);
137 :
138 : /**
139 : * Same as above, but without the XPCOM goop
140 : */
141 : nsINodeList* GetAnonymousNodesFor(nsIContent* aContent);
142 :
143 : /**
144 : * Set the anonymous child content for the specified element.
145 : * The binding manager assumes ownership of aList.
146 : */
147 : nsresult SetAnonymousNodesFor(nsIContent* aContent,
148 : nsInsertionPointList* aList);
149 :
150 : /**
151 : * Retrieves the anonymous list of children if the element has one;
152 : * otherwise, retrieves the list of explicit children. N.B. that if
153 : * the explicit child list has not been altered by XBL insertion
154 : * points, then aResult will be null.
155 : */
156 : nsresult GetXBLChildNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult);
157 :
158 : /**
159 : * Non-COMy version of GetXBLChildNodesFor
160 : */
161 : nsINodeList* GetXBLChildNodesFor(nsIContent* aContent);
162 :
163 : /**
164 : * Given a parent element and a child content, determine where the
165 : * child content should be inserted in the parent element's
166 : * anonymous content tree. Specifically, aChild should be inserted
167 : * beneath aResult at the index specified by aIndex.
168 : */
169 : // XXXbz That's false. The aIndex doesn't seem to accurately reflect
170 : // anything resembling reality in terms of inserting content. It's really
171 : // only used to tell apart two different insertion points with the same
172 : // insertion parent when managing our internal data structures. We really
173 : // shouldn't be handing it out in our public API, since it's not useful to
174 : // anyone.
175 : nsIContent* GetInsertionPoint(nsIContent* aParent,
176 : const nsIContent* aChild, PRUint32* aIndex);
177 :
178 : /**
179 : * Return the unfiltered insertion point for the specified parent
180 : * element. If other filtered insertion points exist,
181 : * aMultipleInsertionPoints will be set to true.
182 : */
183 : nsIContent* GetSingleInsertionPoint(nsIContent* aParent, PRUint32* aIndex,
184 : bool* aMultipleInsertionPoints);
185 :
186 : nsIContent* GetNestedInsertionPoint(nsIContent* aParent,
187 : const nsIContent* aChild);
188 : nsIContent* GetNestedSingleInsertionPoint(nsIContent* aParent,
189 : bool* aMultipleInsertionPoints);
190 :
191 : nsresult AddLayeredBinding(nsIContent* aContent, nsIURI* aURL,
192 : nsIPrincipal* aOriginPrincipal);
193 : nsresult RemoveLayeredBinding(nsIContent* aContent, nsIURI* aURL);
194 : nsresult LoadBindingDocument(nsIDocument* aBoundDoc, nsIURI* aURL,
195 : nsIPrincipal* aOriginPrincipal);
196 :
197 : nsresult AddToAttachedQueue(nsXBLBinding* aBinding);
198 : void ProcessAttachedQueue(PRUint32 aSkipSize = 0);
199 :
200 : void ExecuteDetachedHandlers();
201 :
202 : nsresult PutXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo);
203 : nsXBLDocumentInfo* GetXBLDocumentInfo(nsIURI* aURI);
204 : void RemoveXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo);
205 :
206 : nsresult PutLoadingDocListener(nsIURI* aURL, nsIStreamListener* aListener);
207 : nsIStreamListener* GetLoadingDocListener(nsIURI* aURL);
208 : void RemoveLoadingDocListener(nsIURI* aURL);
209 :
210 : void FlushSkinBindings();
211 :
212 : nsresult GetBindingImplementation(nsIContent* aContent, REFNSIID aIID, void** aResult);
213 :
214 : // Style rule methods
215 : nsresult WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc,
216 : RuleProcessorData* aData,
217 : bool* aCutOffInheritance);
218 :
219 : void WalkAllRules(nsIStyleRuleProcessor::EnumFunc aFunc,
220 : RuleProcessorData* aData);
221 : /**
222 : * Do any processing that needs to happen as a result of a change in
223 : * the characteristics of the medium, and return whether this rule
224 : * processor's rules have changed (e.g., because of media queries).
225 : */
226 : nsresult MediumFeaturesChanged(nsPresContext* aPresContext,
227 : bool* aRulesChanged);
228 :
229 : void AppendAllSheets(nsTArray<nsCSSStyleSheet*>& aArray);
230 :
231 : NS_HIDDEN_(void) Traverse(nsIContent *aContent,
232 : nsCycleCollectionTraversalCallback &cb);
233 :
234 : NS_DECL_CYCLE_COLLECTION_CLASS(nsBindingManager)
235 :
236 : // Notify the binding manager when an outermost update begins and
237 : // ends. The end method can execute script.
238 : void BeginOutermostUpdate();
239 : void EndOutermostUpdate();
240 :
241 : // Called when the document is going away
242 : void DropDocumentReference();
243 :
244 : protected:
245 : nsIXPConnectWrappedJS* GetWrappedJS(nsIContent* aContent);
246 : nsresult SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult);
247 :
248 : nsINodeList* GetXBLChildNodesInternal(nsIContent* aContent,
249 : bool* aIsAnonymousContentList);
250 : nsINodeList* GetAnonymousNodesInternal(nsIContent* aContent,
251 : bool* aIsAnonymousContentList);
252 :
253 : // Called by ContentAppended and ContentInserted to handle a single child
254 : // insertion. aChild must not be null. aContainer may be null.
255 : // aIndexInContainer is the index of the child in the parent. aAppend is
256 : // true if this child is being appended, not inserted.
257 : void HandleChildInsertion(nsIContent* aContainer, nsIContent* aChild,
258 : PRUint32 aIndexInContainer, bool aAppend);
259 :
260 : // For the given container under which a child is being added, given
261 : // insertion parent and given index of the child being inserted, find the
262 : // right nsXBLInsertionPoint and the right index in that insertion point to
263 : // insert it at. If null is returned, aInsertionIndex might be garbage.
264 : // aAppend controls what should be returned as the aInsertionIndex if the
265 : // right index can't be found. If true, the length of the insertion point
266 : // will be returned; otherwise 0 will be returned.
267 : nsXBLInsertionPoint* FindInsertionPointAndIndex(nsIContent* aContainer,
268 : nsIContent* aInsertionParent,
269 : PRUint32 aIndexInContainer,
270 : PRInt32 aAppend,
271 : PRInt32* aInsertionIndex);
272 :
273 : // Same as ProcessAttachedQueue, but also nulls out
274 : // mProcessAttachedQueueEvent
275 : void DoProcessAttachedQueue();
276 :
277 : // Post an event to process the attached queue.
278 : void PostProcessAttachedQueueEvent();
279 :
280 : // MEMBER VARIABLES
281 : protected:
282 : void RemoveInsertionParent(nsIContent* aParent);
283 : // A mapping from nsIContent* to the nsXBLBinding* that is
284 : // installed on that element.
285 : nsRefPtrHashtable<nsISupportsHashKey,nsXBLBinding> mBindingTable;
286 :
287 : // A mapping from nsIContent* to an nsAnonymousContentList*. This
288 : // list contains an accurate reflection of our *explicit* children
289 : // (once intermingled with insertion points) in the altered DOM.
290 : // There is an entry for a content node in this table only if that
291 : // content node has some <children> kids.
292 : PLDHashTable mContentListTable;
293 :
294 : // A mapping from nsIContent* to an nsAnonymousContentList*. This
295 : // list contains an accurate reflection of our *anonymous* children
296 : // (if and only if they are intermingled with insertion points) in
297 : // the altered DOM. This table is not used if no insertion points
298 : // were defined directly underneath a <content> tag in a binding.
299 : // The NodeList from the <content> is used instead as a performance
300 : // optimization. There is an entry for a content node in this table
301 : // only if that content node has a binding with a <content> attached
302 : // and this <content> contains <children> elements directly.
303 : PLDHashTable mAnonymousNodesTable;
304 :
305 : // A mapping from nsIContent* to nsIContent*. The insertion parent
306 : // is our one true parent in the transformed DOM. This gives us a
307 : // more-or-less O(1) way of obtaining our transformed parent.
308 : PLDHashTable mInsertionParentTable;
309 :
310 : // A mapping from nsIContent* to nsIXPWrappedJS* (an XPConnect
311 : // wrapper for JS objects). For XBL bindings that implement XPIDL
312 : // interfaces, and that get referred to from C++, this table caches
313 : // the XPConnect wrapper for the binding. By caching it, I control
314 : // its lifetime, and I prevent a re-wrap of the same script object
315 : // (in the case where multiple bindings in an XBL inheritance chain
316 : // both implement an XPIDL interface).
317 : PLDHashTable mWrapperTable;
318 :
319 : // A mapping from a URL (a string) to nsXBLDocumentInfo*. This table
320 : // is the cache of all binding documents that have been loaded by a
321 : // given bound document.
322 : nsRefPtrHashtable<nsURIHashKey,nsXBLDocumentInfo> mDocumentTable;
323 :
324 : // A mapping from a URL (a string) to a nsIStreamListener. This
325 : // table is the currently loading binding docs. If they're in this
326 : // table, they have not yet finished loading.
327 : nsInterfaceHashtable<nsURIHashKey,nsIStreamListener> mLoadingDocTable;
328 :
329 : // A queue of binding attached event handlers that are awaiting execution.
330 : nsBindingList mAttachedStack;
331 : bool mProcessingAttachedStack;
332 : bool mDestroyed;
333 : PRUint32 mAttachedStackSizeOnOutermost;
334 :
335 : // Our posted event to process the attached queue, if any
336 : friend class nsRunnableMethod<nsBindingManager>;
337 : nsRefPtr< nsRunnableMethod<nsBindingManager> > mProcessAttachedQueueEvent;
338 :
339 : // Our document. This is a weak ref; the document owns us
340 : nsIDocument* mDocument;
341 : };
342 :
343 : #endif
|