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 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #ifndef nsXBLPrototypeBinding_h__
40 : #define nsXBLPrototypeBinding_h__
41 :
42 : #include "nsCOMPtr.h"
43 : #include "nsXBLPrototypeResources.h"
44 : #include "nsXBLPrototypeHandler.h"
45 : #include "nsXBLProtoImplMethod.h"
46 : #include "nsICSSLoaderObserver.h"
47 : #include "nsWeakReference.h"
48 : #include "nsIContent.h"
49 : #include "nsHashtable.h"
50 : #include "nsClassHashtable.h"
51 : #include "nsXBLDocumentInfo.h"
52 : #include "nsCOMArray.h"
53 : #include "nsXBLProtoImpl.h"
54 :
55 : class nsIAtom;
56 : class nsIDocument;
57 : class nsIScriptContext;
58 : class nsSupportsHashtable;
59 : class nsIXBLService;
60 : class nsFixedSizeAllocator;
61 : class nsXBLProtoImplField;
62 : class nsXBLBinding;
63 : class nsCSSStyleSheet;
64 :
65 : // This structure represents an insertion point, and is used when writing out
66 : // insertion points. It contains comparison operators so that it can be stored
67 : // in an array sorted by index.
68 0 : struct InsertionItem {
69 : PRUint32 insertionIndex;
70 : nsIAtom* tag;
71 : nsIContent* defaultContent;
72 :
73 0 : InsertionItem(PRUint32 aInsertionIndex, nsIAtom* aTag, nsIContent* aDefaultContent)
74 0 : : insertionIndex(aInsertionIndex), tag(aTag), defaultContent(aDefaultContent) { }
75 :
76 0 : bool operator<(const InsertionItem& item) const
77 : {
78 0 : NS_ASSERTION(insertionIndex != item.insertionIndex || defaultContent == item.defaultContent,
79 : "default content is different for same index");
80 0 : return insertionIndex < item.insertionIndex;
81 : }
82 :
83 0 : bool operator==(const InsertionItem& item) const
84 : {
85 0 : NS_ASSERTION(insertionIndex != item.insertionIndex || defaultContent == item.defaultContent,
86 : "default content is different for same index");
87 0 : return insertionIndex == item.insertionIndex;
88 : }
89 : };
90 :
91 : typedef nsClassHashtable<nsISupportsHashKey, nsAutoTArray<InsertionItem, 1> > ArrayOfInsertionPointsByContent;
92 :
93 : // *********************************************************************/
94 : // The XBLPrototypeBinding class
95 :
96 : // Instances of this class are owned by the nsXBLDocumentInfo object returned
97 : // by XBLDocumentInfo(). Consumers who want to refcount things should refcount
98 : // that.
99 : class nsXBLPrototypeBinding
100 : {
101 : public:
102 : already_AddRefed<nsIContent> GetBindingElement();
103 : void SetBindingElement(nsIContent* aElement);
104 :
105 0 : nsIURI* BindingURI() const { return mBindingURI; }
106 0 : nsIURI* AlternateBindingURI() const { return mAlternateBindingURI; }
107 0 : nsIURI* DocURI() const { return mXBLDocInfoWeak->DocumentURI(); }
108 0 : nsIURI* GetBaseBindingURI() const { return mBaseBindingURI; }
109 :
110 : // Checks if aURI refers to this binding by comparing to both possible
111 : // binding URIs.
112 : bool CompareBindingURI(nsIURI* aURI) const;
113 :
114 : bool GetAllowScripts();
115 :
116 : nsresult BindingAttached(nsIContent* aBoundElement);
117 : nsresult BindingDetached(nsIContent* aBoundElement);
118 :
119 : bool LoadResources();
120 : nsresult AddResource(nsIAtom* aResourceType, const nsAString& aSrc);
121 :
122 0 : bool InheritsStyle() const { return mInheritStyle; }
123 :
124 0 : nsXBLPrototypeHandler* GetPrototypeHandlers() { return mPrototypeHandler; }
125 0 : void SetPrototypeHandlers(nsXBLPrototypeHandler* aHandler) { mPrototypeHandler = aHandler; }
126 :
127 : nsXBLProtoImplAnonymousMethod* GetConstructor();
128 : nsresult SetConstructor(nsXBLProtoImplAnonymousMethod* aConstructor);
129 : nsXBLProtoImplAnonymousMethod* GetDestructor();
130 : nsresult SetDestructor(nsXBLProtoImplAnonymousMethod* aDestructor);
131 :
132 0 : nsXBLProtoImplField* FindField(const nsString& aFieldName) const
133 : {
134 0 : return mImplementation ? mImplementation->FindField(aFieldName) : nsnull;
135 : }
136 :
137 : // Resolve all the fields for this binding on the object |obj|.
138 : // False return means a JS exception was set.
139 0 : bool ResolveAllFields(JSContext* cx, JSObject* obj) const
140 : {
141 0 : return !mImplementation || mImplementation->ResolveAllFields(cx, obj);
142 : }
143 :
144 : // Undefine all our fields from object |obj| (which should be a
145 : // JSObject for a bound element).
146 0 : void UndefineFields(JSContext* cx, JSObject* obj) const {
147 0 : if (mImplementation) {
148 0 : mImplementation->UndefineFields(cx, obj);
149 : }
150 0 : }
151 :
152 : const nsCString& ClassName() const {
153 : return mImplementation ? mImplementation->mClassName : EmptyCString();
154 : }
155 :
156 : nsresult InitClass(const nsCString& aClassName, JSContext * aContext,
157 : JSObject * aGlobal, JSObject * aScriptObject,
158 : JSObject** aClassObject);
159 :
160 : nsresult ConstructInterfaceTable(const nsAString& aImpls);
161 :
162 0 : void SetImplementation(nsXBLProtoImpl* aImpl) { mImplementation = aImpl; }
163 : nsresult InstallImplementation(nsIContent* aBoundElement);
164 0 : bool HasImplementation() const { return mImplementation != nsnull; }
165 :
166 : void AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID,
167 : bool aRemoveFlag, nsIContent* aChangedElement,
168 : nsIContent* aAnonymousContent, bool aNotify);
169 :
170 : void SetBasePrototype(nsXBLPrototypeBinding* aBinding);
171 0 : nsXBLPrototypeBinding* GetBasePrototype() { return mBaseBinding; }
172 :
173 0 : nsXBLDocumentInfo* XBLDocumentInfo() const { return mXBLDocInfoWeak; }
174 0 : bool IsChrome() { return mXBLDocInfoWeak->IsChrome(); }
175 :
176 : void SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent);
177 :
178 : nsIStyleRuleProcessor* GetRuleProcessor();
179 : nsXBLPrototypeResources::sheet_array_type* GetStyleSheets();
180 :
181 0 : bool HasInsertionPoints() { return mInsertionPointTable != nsnull; }
182 :
183 0 : bool HasStyleSheets() {
184 0 : return mResources && mResources->mStyleSheetList.Length() > 0;
185 : }
186 :
187 : nsresult FlushSkinSheets();
188 :
189 : void InstantiateInsertionPoints(nsXBLBinding* aBinding);
190 :
191 : // XXXbz this aIndex has nothing to do with an index into the child
192 : // list of the insertion parent or anything.
193 : nsIContent* GetInsertionPoint(nsIContent* aBoundElement,
194 : nsIContent* aCopyRoot,
195 : const nsIContent *aChild,
196 : PRUint32* aIndex);
197 :
198 : nsIContent* GetSingleInsertionPoint(nsIContent* aBoundElement,
199 : nsIContent* aCopyRoot,
200 : PRUint32* aIndex, bool* aMultiple);
201 :
202 : nsIAtom* GetBaseTag(PRInt32* aNamespaceID);
203 : void SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag);
204 :
205 : bool ImplementsInterface(REFNSIID aIID) const;
206 :
207 : nsresult AddResourceListener(nsIContent* aBoundElement);
208 :
209 : void Initialize();
210 :
211 : nsresult ResolveBaseBinding();
212 :
213 0 : const nsCOMArray<nsXBLKeyEventHandler>* GetKeyEventHandlers()
214 : {
215 0 : if (!mKeyHandlersRegistered) {
216 0 : CreateKeyHandlers();
217 0 : mKeyHandlersRegistered = true;
218 : }
219 :
220 0 : return &mKeyHandlers;
221 : }
222 :
223 : /**
224 : * Read this binding from the stream aStream into the xbl document aDocument.
225 : * aDocInfo should be the xbl document info for the binding document.
226 : * aFlags can contain XBLBinding_Serialize_InheritStyle to indicate that
227 : * mInheritStyle flag should be set, and XBLBinding_Serialize_IsFirstBinding
228 : * to indicate the first binding in a document.
229 : */
230 : nsresult Read(nsIObjectInputStream* aStream,
231 : nsXBLDocumentInfo* aDocInfo,
232 : nsIDocument* aDocument,
233 : PRUint8 aFlags);
234 :
235 : /**
236 : * Write this binding to the stream.
237 : */
238 : nsresult Write(nsIObjectOutputStream* aStream);
239 :
240 : /**
241 : * Read a content node from aStream and return it in aChild.
242 : * aDocument and aNim are the document and node info manager for the document
243 : * the child will be inserted into.
244 : */
245 : nsresult ReadContentNode(nsIObjectInputStream* aStream,
246 : nsIDocument* aDocument,
247 : nsNodeInfoManager* aNim,
248 : nsIContent** aChild);
249 :
250 : /**
251 : * Write the content node aNode to aStream.
252 : * aInsertionPointsByContent is a hash of the insertion points in the binding,
253 : * keyed by where there are in the content hierarchy.
254 : *
255 : * This method is called recursively for each child descendant. For the topmost
256 : * call, aNode must be an element.
257 : *
258 : * Text, CDATA and comment nodes are serialized as:
259 : * the constant XBLBinding_Serialize_TextNode, XBLBinding_Serialize_CDATANode
260 : * or XBLBinding_Serialize_CommentNode
261 : * the text for the node
262 : * Elements are serialized in the following format:
263 : * node's namespace, written with WriteNamespace
264 : * node's namespace prefix
265 : * node's tag
266 : * 32-bit attribute count
267 : * table of attributes:
268 : * attribute's namespace, written with WriteNamespace
269 : * attribute's namespace prefix
270 : * attribute's tag
271 : * attribute's value
272 : * attribute forwarding table:
273 : * source namespace
274 : * source attribute
275 : * destination namespace
276 : * destination attribute
277 : * the constant XBLBinding_Serialize_NoMoreAttributes
278 : * insertion points within this node:
279 : * child index to insert within node
280 : * default content serialized in the same manner or XBLBinding_Serialize_NoContent
281 : * count of insertion points at that index
282 : * that number of string tags (those in the <children>'s includes attribute)
283 : * the constant XBLBinding_Serialize_NoMoreInsertionPoints
284 : * 32-bit count of the number of child nodes
285 : * each child node is serialized in the same manner in sequence
286 : * the constant XBLBinding_Serialize_NoContent
287 : */
288 : nsresult WriteContentNode(nsIObjectOutputStream* aStream,
289 : nsIContent* aNode,
290 : ArrayOfInsertionPointsByContent& aInsertionPointsByContent);
291 :
292 : /**
293 : * Read or write a namespace id from or to aStream. If the namespace matches
294 : * one of the built-in ones defined in nsINameSpaceManager.h, it will be written as
295 : * a single byte with that value. Otherwise, XBLBinding_Serialize_CustomNamespace is
296 : * written out, followed by a string written with writeWStringZ.
297 : */
298 : nsresult ReadNamespace(nsIObjectInputStream* aStream, PRInt32& aNameSpaceID);
299 : nsresult WriteNamespace(nsIObjectOutputStream* aStream, PRInt32 aNameSpaceID);
300 :
301 : public:
302 : nsXBLPrototypeBinding();
303 : ~nsXBLPrototypeBinding();
304 :
305 : // Init must be called after construction to initialize the prototype
306 : // binding. It may well throw errors (eg on out-of-memory). Do not confuse
307 : // this with the Initialize() method, which must be called after the
308 : // binding's handlers, properties, etc are all set.
309 : nsresult Init(const nsACString& aRef,
310 : nsXBLDocumentInfo* aInfo,
311 : nsIContent* aElement,
312 : bool aFirstBinding = false);
313 :
314 : void Traverse(nsCycleCollectionTraversalCallback &cb) const;
315 : void UnlinkJSObjects();
316 : void Trace(TraceCallback aCallback, void *aClosure) const;
317 :
318 : // Static members
319 : static PRUint32 gRefCnt;
320 :
321 : static nsFixedSizeAllocator* kAttrPool;
322 :
323 : // Internal member functions.
324 : // XXXbz GetImmediateChild needs to be public to be called by SetAttrs,
325 : // InstantiateInsertionPoints, etc; those should probably be a class static
326 : // method instead of a global (non-static!) ones.
327 : public:
328 : /**
329 : * GetImmediateChild locates the immediate child of our binding element which
330 : * has the localname given by aTag and is in the XBL namespace.
331 : */
332 : nsIContent* GetImmediateChild(nsIAtom* aTag);
333 : nsIContent* LocateInstance(nsIContent* aBoundElt,
334 : nsIContent* aTemplRoot,
335 : nsIContent* aCopyRoot,
336 : nsIContent* aTemplChild);
337 :
338 : protected:
339 : // Ensure that mAttributeTable has been created.
340 : void EnsureAttributeTable();
341 : // Ad an entry to the attribute table
342 : void AddToAttributeTable(PRInt32 aSourceNamespaceID, nsIAtom* aSourceTag,
343 : PRInt32 aDestNamespaceID, nsIAtom* aDestTag,
344 : nsIContent* aContent);
345 : void ConstructAttributeTable(nsIContent* aElement);
346 : void ConstructInsertionTable(nsIContent* aElement);
347 : void GetNestedChildren(nsIAtom* aTag, PRInt32 aNamespace,
348 : nsIContent* aContent,
349 : nsCOMArray<nsIContent> & aList);
350 : void CreateKeyHandlers();
351 :
352 : // MEMBER VARIABLES
353 : protected:
354 : nsCOMPtr<nsIURI> mBindingURI;
355 : nsCOMPtr<nsIURI> mAlternateBindingURI; // Alternate id-less URI that is only non-null on the first binding.
356 : nsCOMPtr<nsIContent> mBinding; // Strong. We own a ref to our content element in the binding doc.
357 : nsAutoPtr<nsXBLPrototypeHandler> mPrototypeHandler; // Strong. DocInfo owns us, and we own the handlers.
358 :
359 : // the url of the base binding
360 : nsCOMPtr<nsIURI> mBaseBindingURI;
361 :
362 : nsXBLProtoImpl* mImplementation; // Our prototype implementation (includes methods, properties, fields,
363 : // the constructor, and the destructor).
364 :
365 : nsXBLPrototypeBinding* mBaseBinding; // Weak. The docinfo will own our base binding.
366 : bool mInheritStyle;
367 : bool mCheckedBaseProto;
368 : bool mKeyHandlersRegistered;
369 :
370 : nsXBLPrototypeResources* mResources; // If we have any resources, this will be non-null.
371 :
372 : nsXBLDocumentInfo* mXBLDocInfoWeak; // A pointer back to our doc info. Weak, since it owns us.
373 :
374 : nsObjectHashtable* mAttributeTable; // A table for attribute containers. Namespace IDs are used as
375 : // keys in the table. Containers are nsObjectHashtables.
376 : // This table is used to efficiently handle attribute changes.
377 :
378 : nsObjectHashtable* mInsertionPointTable; // A table of insertion points for placing explicit content
379 : // underneath anonymous content.
380 :
381 : nsSupportsHashtable* mInterfaceTable; // A table of cached interfaces that we support.
382 :
383 : PRInt32 mBaseNameSpaceID; // If we extend a tagname/namespace, then that information will
384 : nsCOMPtr<nsIAtom> mBaseTag; // be stored in here.
385 :
386 : nsCOMArray<nsXBLKeyEventHandler> mKeyHandlers;
387 : };
388 :
389 : #endif
|