|
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 #ifndef nsXBLPrototypeBinding_h__ |
|
7 #define nsXBLPrototypeBinding_h__ |
|
8 |
|
9 #include "nsClassHashtable.h" |
|
10 #include "nsCOMArray.h" |
|
11 #include "nsCOMPtr.h" |
|
12 #include "nsICSSLoaderObserver.h" |
|
13 #include "nsInterfaceHashtable.h" |
|
14 #include "nsWeakReference.h" |
|
15 #include "nsXBLDocumentInfo.h" |
|
16 #include "nsXBLProtoImpl.h" |
|
17 #include "nsXBLProtoImplMethod.h" |
|
18 #include "nsXBLPrototypeHandler.h" |
|
19 #include "nsXBLPrototypeResources.h" |
|
20 |
|
21 class nsIAtom; |
|
22 class nsIContent; |
|
23 class nsIDocument; |
|
24 class nsXBLAttributeEntry; |
|
25 class nsXBLBinding; |
|
26 class nsXBLProtoImplField; |
|
27 |
|
28 // *********************************************************************/ |
|
29 // The XBLPrototypeBinding class |
|
30 |
|
31 // Instances of this class are owned by the nsXBLDocumentInfo object returned |
|
32 // by XBLDocumentInfo(). Consumers who want to refcount things should refcount |
|
33 // that. |
|
34 class nsXBLPrototypeBinding MOZ_FINAL |
|
35 { |
|
36 public: |
|
37 nsIContent* GetBindingElement() const { return mBinding; } |
|
38 void SetBindingElement(nsIContent* aElement); |
|
39 |
|
40 nsIURI* BindingURI() const { return mBindingURI; } |
|
41 nsIURI* AlternateBindingURI() const { return mAlternateBindingURI; } |
|
42 nsIURI* DocURI() const { return mXBLDocInfoWeak->DocumentURI(); } |
|
43 nsIURI* GetBaseBindingURI() const { return mBaseBindingURI; } |
|
44 |
|
45 // Checks if aURI refers to this binding by comparing to both possible |
|
46 // binding URIs. |
|
47 bool CompareBindingURI(nsIURI* aURI) const; |
|
48 |
|
49 bool GetAllowScripts() const; |
|
50 |
|
51 nsresult BindingAttached(nsIContent* aBoundElement); |
|
52 nsresult BindingDetached(nsIContent* aBoundElement); |
|
53 |
|
54 bool LoadResources(); |
|
55 nsresult AddResource(nsIAtom* aResourceType, const nsAString& aSrc); |
|
56 |
|
57 bool InheritsStyle() const { return mInheritStyle; } |
|
58 void SetInheritsStyle(bool aInheritStyle) { mInheritStyle = aInheritStyle; } |
|
59 |
|
60 nsXBLPrototypeHandler* GetPrototypeHandlers() { return mPrototypeHandler; } |
|
61 void SetPrototypeHandlers(nsXBLPrototypeHandler* aHandler) { mPrototypeHandler = aHandler; } |
|
62 |
|
63 nsXBLProtoImplAnonymousMethod* GetConstructor(); |
|
64 nsresult SetConstructor(nsXBLProtoImplAnonymousMethod* aConstructor); |
|
65 nsXBLProtoImplAnonymousMethod* GetDestructor(); |
|
66 nsresult SetDestructor(nsXBLProtoImplAnonymousMethod* aDestructor); |
|
67 |
|
68 nsXBLProtoImplField* FindField(const nsString& aFieldName) const |
|
69 { |
|
70 return mImplementation ? mImplementation->FindField(aFieldName) : nullptr; |
|
71 } |
|
72 |
|
73 // Resolve all the fields for this binding on the object |obj|. |
|
74 // False return means a JS exception was set. |
|
75 bool ResolveAllFields(JSContext* cx, JS::Handle<JSObject*> obj) const |
|
76 { |
|
77 return !mImplementation || mImplementation->ResolveAllFields(cx, obj); |
|
78 } |
|
79 |
|
80 // Undefine all our fields from object |obj| (which should be a |
|
81 // JSObject for a bound element). |
|
82 void UndefineFields(JSContext* cx, JS::Handle<JSObject*> obj) const { |
|
83 if (mImplementation) { |
|
84 mImplementation->UndefineFields(cx, obj); |
|
85 } |
|
86 } |
|
87 |
|
88 const nsCString& ClassName() const { |
|
89 return mImplementation ? mImplementation->mClassName : EmptyCString(); |
|
90 } |
|
91 |
|
92 nsresult InitClass(const nsCString& aClassName, JSContext * aContext, |
|
93 JS::Handle<JSObject*> aScriptObject, |
|
94 JS::MutableHandle<JSObject*> aClassObject, |
|
95 bool* aNew); |
|
96 |
|
97 nsresult ConstructInterfaceTable(const nsAString& aImpls); |
|
98 |
|
99 void SetImplementation(nsXBLProtoImpl* aImpl) { mImplementation = aImpl; } |
|
100 nsXBLProtoImpl* GetImplementation() { return mImplementation; } |
|
101 nsresult InstallImplementation(nsXBLBinding* aBinding); |
|
102 bool HasImplementation() const { return mImplementation != nullptr; } |
|
103 |
|
104 void AttributeChanged(nsIAtom* aAttribute, int32_t aNameSpaceID, |
|
105 bool aRemoveFlag, nsIContent* aChangedElement, |
|
106 nsIContent* aAnonymousContent, bool aNotify); |
|
107 |
|
108 void SetBasePrototype(nsXBLPrototypeBinding* aBinding); |
|
109 nsXBLPrototypeBinding* GetBasePrototype() { return mBaseBinding; } |
|
110 |
|
111 nsXBLDocumentInfo* XBLDocumentInfo() const { return mXBLDocInfoWeak; } |
|
112 bool IsChrome() { return mXBLDocInfoWeak->IsChrome(); } |
|
113 |
|
114 void SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent); |
|
115 |
|
116 nsIStyleRuleProcessor* GetRuleProcessor(); |
|
117 nsXBLPrototypeResources::sheet_array_type* GetOrCreateStyleSheets(); |
|
118 nsXBLPrototypeResources::sheet_array_type* GetStyleSheets(); |
|
119 |
|
120 bool HasStyleSheets() { |
|
121 return mResources && mResources->mStyleSheetList.Length() > 0; |
|
122 } |
|
123 |
|
124 nsresult FlushSkinSheets(); |
|
125 |
|
126 nsIAtom* GetBaseTag(int32_t* aNamespaceID); |
|
127 void SetBaseTag(int32_t aNamespaceID, nsIAtom* aTag); |
|
128 |
|
129 bool ImplementsInterface(REFNSIID aIID) const; |
|
130 |
|
131 nsresult AddResourceListener(nsIContent* aBoundElement); |
|
132 |
|
133 void Initialize(); |
|
134 |
|
135 nsresult ResolveBaseBinding(); |
|
136 |
|
137 const nsCOMArray<nsXBLKeyEventHandler>* GetKeyEventHandlers() |
|
138 { |
|
139 if (!mKeyHandlersRegistered) { |
|
140 CreateKeyHandlers(); |
|
141 mKeyHandlersRegistered = true; |
|
142 } |
|
143 |
|
144 return &mKeyHandlers; |
|
145 } |
|
146 |
|
147 private: |
|
148 nsresult Read(nsIObjectInputStream* aStream, |
|
149 nsXBLDocumentInfo* aDocInfo, |
|
150 nsIDocument* aDocument, |
|
151 uint8_t aFlags); |
|
152 |
|
153 /** |
|
154 * Read a new binding from the stream aStream into the xbl document aDocument. |
|
155 * aDocInfo should be the xbl document info for the binding document. |
|
156 * aFlags can contain XBLBinding_Serialize_InheritStyle to indicate that |
|
157 * mInheritStyle flag should be set, and XBLBinding_Serialize_IsFirstBinding |
|
158 * to indicate the first binding in a document. |
|
159 * XBLBinding_Serialize_ChromeOnlyContent indicates that |
|
160 * nsXBLPrototypeBinding::mChromeOnlyContent should be true. |
|
161 */ |
|
162 public: |
|
163 static nsresult ReadNewBinding(nsIObjectInputStream* aStream, |
|
164 nsXBLDocumentInfo* aDocInfo, |
|
165 nsIDocument* aDocument, |
|
166 uint8_t aFlags); |
|
167 |
|
168 /** |
|
169 * Write this binding to the stream. |
|
170 */ |
|
171 nsresult Write(nsIObjectOutputStream* aStream); |
|
172 |
|
173 /** |
|
174 * Read a content node from aStream and return it in aChild. |
|
175 * aDocument and aNim are the document and node info manager for the document |
|
176 * the child will be inserted into. |
|
177 */ |
|
178 nsresult ReadContentNode(nsIObjectInputStream* aStream, |
|
179 nsIDocument* aDocument, |
|
180 nsNodeInfoManager* aNim, |
|
181 nsIContent** aChild); |
|
182 |
|
183 /** |
|
184 * Write the content node aNode to aStream. |
|
185 * |
|
186 * This method is called recursively for each child descendant. For the topmost |
|
187 * call, aNode must be an element. |
|
188 * |
|
189 * Text, CDATA and comment nodes are serialized as: |
|
190 * the constant XBLBinding_Serialize_TextNode, XBLBinding_Serialize_CDATANode |
|
191 * or XBLBinding_Serialize_CommentNode |
|
192 * the text for the node |
|
193 * Elements are serialized in the following format: |
|
194 * node's namespace, written with WriteNamespace |
|
195 * node's namespace prefix |
|
196 * node's tag |
|
197 * 32-bit attribute count |
|
198 * table of attributes: |
|
199 * attribute's namespace, written with WriteNamespace |
|
200 * attribute's namespace prefix |
|
201 * attribute's tag |
|
202 * attribute's value |
|
203 * attribute forwarding table: |
|
204 * source namespace |
|
205 * source attribute |
|
206 * destination namespace |
|
207 * destination attribute |
|
208 * the constant XBLBinding_Serialize_NoMoreAttributes |
|
209 * 32-bit count of the number of child nodes |
|
210 * each child node is serialized in the same manner in sequence |
|
211 * the constant XBLBinding_Serialize_NoContent |
|
212 */ |
|
213 nsresult WriteContentNode(nsIObjectOutputStream* aStream, nsIContent* aNode); |
|
214 |
|
215 /** |
|
216 * Read or write a namespace id from or to aStream. If the namespace matches |
|
217 * one of the built-in ones defined in nsNameSpaceManager.h, it will be written as |
|
218 * a single byte with that value. Otherwise, XBLBinding_Serialize_CustomNamespace is |
|
219 * written out, followed by a string written with writeWStringZ. |
|
220 */ |
|
221 nsresult ReadNamespace(nsIObjectInputStream* aStream, int32_t& aNameSpaceID); |
|
222 nsresult WriteNamespace(nsIObjectOutputStream* aStream, int32_t aNameSpaceID); |
|
223 |
|
224 public: |
|
225 nsXBLPrototypeBinding(); |
|
226 ~nsXBLPrototypeBinding(); |
|
227 |
|
228 // Init must be called after construction to initialize the prototype |
|
229 // binding. It may well throw errors (eg on out-of-memory). Do not confuse |
|
230 // this with the Initialize() method, which must be called after the |
|
231 // binding's handlers, properties, etc are all set. |
|
232 nsresult Init(const nsACString& aRef, |
|
233 nsXBLDocumentInfo* aInfo, |
|
234 nsIContent* aElement, |
|
235 bool aFirstBinding = false); |
|
236 |
|
237 void Traverse(nsCycleCollectionTraversalCallback &cb) const; |
|
238 void UnlinkJSObjects(); |
|
239 void Trace(const TraceCallbacks& aCallbacks, void *aClosure) const; |
|
240 |
|
241 // Internal member functions. |
|
242 public: |
|
243 /** |
|
244 * GetImmediateChild locates the immediate child of our binding element which |
|
245 * has the localname given by aTag and is in the XBL namespace. |
|
246 */ |
|
247 nsIContent* GetImmediateChild(nsIAtom* aTag); |
|
248 nsIContent* LocateInstance(nsIContent* aBoundElt, |
|
249 nsIContent* aTemplRoot, |
|
250 nsIContent* aCopyRoot, |
|
251 nsIContent* aTemplChild); |
|
252 |
|
253 bool ChromeOnlyContent() { return mChromeOnlyContent; } |
|
254 |
|
255 typedef nsClassHashtable<nsISupportsHashKey, nsXBLAttributeEntry> InnerAttributeTable; |
|
256 |
|
257 protected: |
|
258 // Ensure that mAttributeTable has been created. |
|
259 void EnsureAttributeTable(); |
|
260 // Ad an entry to the attribute table |
|
261 void AddToAttributeTable(int32_t aSourceNamespaceID, nsIAtom* aSourceTag, |
|
262 int32_t aDestNamespaceID, nsIAtom* aDestTag, |
|
263 nsIContent* aContent); |
|
264 void ConstructAttributeTable(nsIContent* aElement); |
|
265 void CreateKeyHandlers(); |
|
266 |
|
267 // MEMBER VARIABLES |
|
268 protected: |
|
269 nsCOMPtr<nsIURI> mBindingURI; |
|
270 nsCOMPtr<nsIURI> mAlternateBindingURI; // Alternate id-less URI that is only non-null on the first binding. |
|
271 nsCOMPtr<nsIContent> mBinding; // Strong. We own a ref to our content element in the binding doc. |
|
272 nsAutoPtr<nsXBLPrototypeHandler> mPrototypeHandler; // Strong. DocInfo owns us, and we own the handlers. |
|
273 |
|
274 // the url of the base binding |
|
275 nsCOMPtr<nsIURI> mBaseBindingURI; |
|
276 |
|
277 nsXBLProtoImpl* mImplementation; // Our prototype implementation (includes methods, properties, fields, |
|
278 // the constructor, and the destructor). |
|
279 |
|
280 nsXBLPrototypeBinding* mBaseBinding; // Weak. The docinfo will own our base binding. |
|
281 bool mInheritStyle; |
|
282 bool mCheckedBaseProto; |
|
283 bool mKeyHandlersRegistered; |
|
284 bool mChromeOnlyContent; |
|
285 |
|
286 nsAutoPtr<nsXBLPrototypeResources> mResources; // If we have any resources, this will be non-null. |
|
287 |
|
288 nsXBLDocumentInfo* mXBLDocInfoWeak; // A pointer back to our doc info. Weak, since it owns us. |
|
289 |
|
290 // A table for attribute containers. Namespace IDs are used as |
|
291 // keys in the table. Containers are InnerAttributeTables. |
|
292 // This table is used to efficiently handle attribute changes. |
|
293 nsAutoPtr<nsClassHashtable<nsUint32HashKey, InnerAttributeTable>> mAttributeTable; |
|
294 |
|
295 class IIDHashKey : public PLDHashEntryHdr |
|
296 { |
|
297 public: |
|
298 typedef const nsIID& KeyType; |
|
299 typedef const nsIID* KeyTypePointer; |
|
300 |
|
301 IIDHashKey(const nsIID* aKey) |
|
302 : mKey(*aKey) |
|
303 {} |
|
304 IIDHashKey(const IIDHashKey& aOther) |
|
305 : mKey(aOther.GetKey()) |
|
306 {} |
|
307 ~IIDHashKey() |
|
308 {} |
|
309 |
|
310 KeyType GetKey() const |
|
311 { |
|
312 return mKey; |
|
313 } |
|
314 bool KeyEquals(const KeyTypePointer aKey) const |
|
315 { |
|
316 return mKey.Equals(*aKey); |
|
317 } |
|
318 |
|
319 static KeyTypePointer KeyToPointer(KeyType aKey) |
|
320 { |
|
321 return &aKey; |
|
322 } |
|
323 static PLDHashNumber HashKey(const KeyTypePointer aKey) |
|
324 { |
|
325 // Just use the 32-bit m0 field. |
|
326 return aKey->m0; |
|
327 } |
|
328 |
|
329 enum { ALLOW_MEMMOVE = true }; |
|
330 |
|
331 private: |
|
332 nsIID mKey; |
|
333 }; |
|
334 nsInterfaceHashtable<IIDHashKey, nsIContent> mInterfaceTable; // A table of cached interfaces that we support. |
|
335 |
|
336 int32_t mBaseNameSpaceID; // If we extend a tagname/namespace, then that information will |
|
337 nsCOMPtr<nsIAtom> mBaseTag; // be stored in here. |
|
338 |
|
339 nsCOMArray<nsXBLKeyEventHandler> mKeyHandlers; |
|
340 }; |
|
341 |
|
342 #endif |