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