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 nsXBLBinding_h_
8 #define nsXBLBinding_h_
9 
10 #include "nsXBLService.h"
11 #include "nsCOMPtr.h"
12 #include "nsINodeList.h"
13 #ifdef MOZ_OLD_STYLE
14 #include "nsIStyleRuleProcessor.h"
15 #endif
16 #include "nsClassHashtable.h"
17 #include "nsTArray.h"
18 #include "nsCycleCollectionParticipant.h"
19 #include "nsISupportsImpl.h"
20 #include "js/TypeDecls.h"
21 
22 class nsXBLPrototypeBinding;
23 class nsIContent;
24 class nsAtom;
25 class nsIDocument;
26 struct RawServoAuthorStyles;
27 
28 namespace mozilla {
29 namespace dom {
30 
31 class ShadowRoot;
32 class XBLChildrenElement;
33 
34 }  // namespace dom
35 }  // namespace mozilla
36 
37 class nsAnonymousContentList;
38 
39 // *********************************************************************/
40 // The XBLBinding class
41 
42 class nsXBLBinding final {
43  public:
44   explicit nsXBLBinding(nsXBLPrototypeBinding* aProtoBinding);
45   nsXBLBinding(mozilla::dom::ShadowRoot* aShadowRoot,
46                nsXBLPrototypeBinding* aProtoBinding);
47 
48   /**
49    * XBLBindings are refcounted.  They are held onto in 3 ways:
50    * 1. The binding manager's binding table holds onto all bindings that are
51    *    currently attached to a content node.
52    * 2. Bindings hold onto their base binding.  This is important since
53    *    the base binding itself may not be attached to anything.
54    * 3. The binding manager holds an additional reference to bindings
55    *    which are queued to fire their constructors.
56    */
57 
58   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsXBLBinding)
59 
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLBinding)60   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLBinding)
61 
62   nsXBLPrototypeBinding* PrototypeBinding() const { return mPrototypeBinding; }
GetAnonymousContent()63   nsIContent* GetAnonymousContent() { return mContent.get(); }
64   nsXBLBinding* GetBindingWithContent();
65 
GetBaseBinding()66   nsXBLBinding* GetBaseBinding() const { return mNextBinding; }
67   void SetBaseBinding(nsXBLBinding* aBinding);
68 
GetBoundElement()69   mozilla::dom::Element* GetBoundElement() { return mBoundElement; }
70   void SetBoundElement(mozilla::dom::Element* aElement);
71 
72   /*
73    * Does a lookup for a method or attribute provided by one of the bindings'
74    * prototype implementation. If found, |desc| will be set up appropriately,
75    * and wrapped into cx->compartment.
76    *
77    * May only be called when XBL code is being run in a separate scope, because
78    * otherwise we don't have untainted data with which to do a proper lookup.
79    */
80   bool LookupMember(JSContext* aCx, JS::Handle<jsid> aId,
81                     JS::MutableHandle<JS::PropertyDescriptor> aDesc);
82 
83   /*
84    * Determines whether the binding has a field with the given name.
85    */
86   bool HasField(nsString& aName);
87 
88  protected:
89   ~nsXBLBinding();
90 
91   /*
92    * Internal version. Requires that aCx is in appropriate xbl scope.
93    */
94   bool LookupMemberInternal(JSContext* aCx, nsString& aName,
95                             JS::Handle<jsid> aNameAsId,
96                             JS::MutableHandle<JS::PropertyDescriptor> aDesc,
97                             JS::Handle<JSObject*> aXBLScope);
98 
99  public:
100   void MarkForDeath();
MarkedForDeath()101   bool MarkedForDeath() const { return mMarkedForDeath; }
102 
103   bool HasStyleSheets() const;
104   bool InheritsStyle() const;
105   bool ImplementsInterface(REFNSIID aIID) const;
106 
107   void GenerateAnonymousContent();
108   void BindAnonymousContent(nsIContent* aAnonParent, nsIContent* aElement,
109                             bool aNativeAnon);
110   static void UnbindAnonymousContent(nsIDocument* aDocument,
111                                      nsIContent* aAnonParent,
112                                      bool aNullParent = true);
113   void InstallEventHandlers();
114   nsresult InstallImplementation();
115 
116   void ExecuteAttachedHandler();
117   void ExecuteDetachedHandler();
118   void UnhookEventHandlers();
119 
120   nsAtom* GetBaseTag(int32_t* aNameSpaceID);
121   nsXBLBinding* RootBinding();
122 
123   // Resolve all the fields for this binding and all ancestor bindings on the
124   // object |obj|.  False return means a JS exception was set.
125   bool ResolveAllFields(JSContext* cx, JS::Handle<JSObject*> obj) const;
126 
127   void AttributeChanged(nsAtom* aAttribute, int32_t aNameSpaceID,
128                         bool aRemoveFlag, bool aNotify);
129 
130   void ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument);
131 
132 #ifdef MOZ_OLD_STYLE
133   void WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, void* aData);
134 #endif
135 
136   const RawServoAuthorStyles* GetServoStyles() const;
137 
138   static nsresult DoInitJSClass(JSContext* cx, JS::Handle<JSObject*> obj,
139                                 const nsString& aClassName,
140                                 nsXBLPrototypeBinding* aProtoBinding,
141                                 JS::MutableHandle<JSObject*> aClassObject,
142                                 bool* aNew);
143 
144   bool AllowScripts();
145 
146   mozilla::dom::XBLChildrenElement* FindInsertionPointFor(nsIContent* aChild);
147 
HasFilteredInsertionPoints()148   bool HasFilteredInsertionPoints() { return !mInsertionPoints.IsEmpty(); }
149 
GetDefaultInsertionPoint()150   mozilla::dom::XBLChildrenElement* GetDefaultInsertionPoint() {
151     return mDefaultInsertionPoint;
152   }
153 
154   // Removes all inserted node from <xbl:children> insertion points under us.
155   void ClearInsertionPoints();
156 
157   // Returns a live node list that iterates over the anonymous nodes generated
158   // by this binding.
159   nsAnonymousContentList* GetAnonymousNodeList();
160 
161   nsIURI* GetSourceDocURI();
162 
163   // MEMBER VARIABLES
164  protected:
165   bool mMarkedForDeath;
166   bool mUsingContentXBLScope;
167   bool mIsShadowRootBinding;
168 
169   nsXBLPrototypeBinding*
170       mPrototypeBinding;  // Weak, but we're holding a ref to the docinfo
171   nsCOMPtr<nsIContent>
172       mContent;  // Strong. Our anonymous content stays around with us.
173   RefPtr<nsXBLBinding> mNextBinding;  // Strong. The derived binding owns the
174                                       // base class bindings.
175 
176   mozilla::dom::Element*
177       mBoundElement;  // [WEAK] We have a reference, but we don't own it.
178 
179   // The <xbl:children> elements that we found in our <xbl:content> when we
180   // processed this binding. The default insertion point has no includes
181   // attribute and all other insertion points must have at least one includes
182   // attribute. These points must be up-to-date with respect to their parent's
183   // children, even if their parent has another binding attached to it,
184   // preventing us from rendering their contents directly.
185   RefPtr<mozilla::dom::XBLChildrenElement> mDefaultInsertionPoint;
186   nsTArray<RefPtr<mozilla::dom::XBLChildrenElement> > mInsertionPoints;
187   RefPtr<nsAnonymousContentList> mAnonymousContentList;
188 
189   mozilla::dom::XBLChildrenElement* FindInsertionPointForInternal(
190       nsIContent* aChild);
191 };
192 
193 #endif  // nsXBLBinding_h_
194