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 /*
8  * Base class for all element classes as well as nsDocumentFragment.  This
9  * provides an implementation of nsINode, implements nsIContent, provides
10  * utility methods for subclasses, and so forth.
11  */
12 
13 #ifndef FragmentOrElement_h___
14 #define FragmentOrElement_h___
15 
16 #include "mozilla/Attributes.h"
17 #include "mozilla/MemoryReporting.h"
18 #include "mozilla/UniquePtr.h"
19 #include "nsCycleCollectionParticipant.h"  // NS_DECL_CYCLE_*
20 #include "nsIContent.h"                    // base class
21 #include "nsIHTMLCollection.h"
22 
23 class ContentUnbinder;
24 class nsContentList;
25 class nsLabelsNodeList;
26 class nsDOMAttributeMap;
27 class nsDOMTokenList;
28 class nsIControllers;
29 class nsICSSDeclaration;
30 class nsDOMCSSAttributeDeclaration;
31 class nsDOMStringMap;
32 class nsIURI;
33 
34 namespace mozilla {
35 class DeclarationBlock;
36 namespace dom {
37 struct CustomElementData;
38 class Element;
39 }  // namespace dom
40 }  // namespace mozilla
41 
42 /**
43  * Tearoff to use for nodes to implement nsISupportsWeakReference
44  */
45 class nsNodeSupportsWeakRefTearoff final : public nsISupportsWeakReference {
46  public:
nsNodeSupportsWeakRefTearoff(nsINode * aNode)47   explicit nsNodeSupportsWeakRefTearoff(nsINode* aNode) : mNode(aNode) {}
48 
49   // nsISupports
50   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
51 
52   // nsISupportsWeakReference
53   NS_DECL_NSISUPPORTSWEAKREFERENCE
54 
55   NS_DECL_CYCLE_COLLECTION_CLASS(nsNodeSupportsWeakRefTearoff)
56 
57  private:
58   ~nsNodeSupportsWeakRefTearoff() = default;
59 
60   nsCOMPtr<nsINode> mNode;
61 };
62 
63 /**
64  * A generic base class for DOM elements and document fragments,
65  * implementing many nsIContent, nsINode and Element methods.
66  */
67 namespace mozilla {
68 namespace dom {
69 
70 class ShadowRoot;
71 
72 class FragmentOrElement : public nsIContent {
73  public:
74   explicit FragmentOrElement(
75       already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
76   explicit FragmentOrElement(
77       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
78 
79   // We want to avoid the overhead of extra function calls for
80   // refcounting when we're not doing refcount logging, so we can't
81   // NS_DECL_ISUPPORTS_INHERITED.
82   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
83   NS_INLINE_DECL_REFCOUNTING_INHERITED(FragmentOrElement, nsIContent);
84 
85   NS_DECL_ADDSIZEOFEXCLUDINGTHIS
86 
87   // nsINode interface methods
88   virtual void GetTextContentInternal(nsAString& aTextContent,
89                                       mozilla::OOMReporter& aError) override;
90   virtual void SetTextContentInternal(const nsAString& aTextContent,
91                                       nsIPrincipal* aSubjectPrincipal,
92                                       mozilla::ErrorResult& aError) override;
93 
94   // nsIContent interface methods
95   virtual already_AddRefed<nsINodeList> GetChildren(uint32_t aFilter) override;
96   virtual const nsTextFragment* GetText() override;
97   virtual uint32_t TextLength() const override;
98   virtual bool TextIsOnlyWhitespace() override;
99   virtual bool ThreadSafeTextIsOnlyWhitespace() const override;
100   virtual bool IsLink(nsIURI** aURI) const override;
101 
102   virtual void DestroyContent() override;
103   virtual void SaveSubtreeState() override;
104 
105   nsIHTMLCollection* Children();
ChildElementCount()106   uint32_t ChildElementCount() {
107     if (!HasChildren()) {
108       return 0;
109     }
110     return Children()->Length();
111   }
112 
113  public:
114   /**
115    * If there are listeners for DOMNodeInserted event, fires the event on all
116    * aNodes
117    */
118   static void FireNodeInserted(Document* aDoc, nsINode* aParent,
119                                nsTArray<nsCOMPtr<nsIContent> >& aNodes);
120 
121   NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(
122       FragmentOrElement, nsIContent)
123 
124   /**
125    * Fire a DOMNodeRemoved mutation event for all children of this node
126    */
127   void FireNodeRemovedForChildren();
128 
129   static void ClearContentUnbinder();
130   static bool CanSkip(nsINode* aNode, bool aRemovingAllowed);
131   static bool CanSkipInCC(nsINode* aNode);
132   static bool CanSkipThis(nsINode* aNode);
133   static void RemoveBlackMarkedNode(nsINode* aNode);
134   static void MarkNodeChildren(nsINode* aNode);
135   static void InitCCCallbacks();
136 
137   /**
138    * Is the HTML local name a void element?
139    */
140   static bool IsHTMLVoid(nsAtom* aLocalName);
141 
142  protected:
143   virtual ~FragmentOrElement();
144 
145   /**
146    * Dummy CopyInnerTo so that we can use the same macros for
147    * Elements and DocumentFragments.
148    */
CopyInnerTo(FragmentOrElement * aDest)149   nsresult CopyInnerTo(FragmentOrElement* aDest) { return NS_OK; }
150 
151  public:
152   /**
153    * There are a set of DOM- and scripting-specific instance variables
154    * that may only be instantiated when a content object is accessed
155    * through the DOM. Rather than burn actual slots in the content
156    * objects for each of these instance variables, we put them off
157    * in a side structure that's only allocated when the content is
158    * accessed through the DOM.
159    */
160 
161   class nsExtendedDOMSlots : public nsIContent::nsExtendedContentSlots {
162    public:
163     nsExtendedDOMSlots();
164     ~nsExtendedDOMSlots();
165 
166     void TraverseExtendedSlots(nsCycleCollectionTraversalCallback&) final;
167     void UnlinkExtendedSlots() final;
168 
169     size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const final;
170 
171     /**
172      * SMIL Overridde style rules (for SMIL animation of CSS properties)
173      * @see Element::GetSMILOverrideStyle
174      */
175     RefPtr<nsDOMCSSAttributeDeclaration> mSMILOverrideStyle;
176 
177     /**
178      * Holds any SMIL override style declaration for this element.
179      */
180     RefPtr<DeclarationBlock> mSMILOverrideStyleDeclaration;
181 
182     /**
183      * The controllers of the XUL Element.
184      */
185     nsCOMPtr<nsIControllers> mControllers;
186 
187     /**
188      * An object implementing the .labels property for this element.
189      */
190     RefPtr<nsLabelsNodeList> mLabelsList;
191 
192     /**
193      * ShadowRoot bound to the element.
194      */
195     RefPtr<ShadowRoot> mShadowRoot;
196 
197     /**
198      * Web components custom element data.
199      */
200     RefPtr<CustomElementData> mCustomElementData;
201   };
202 
203   class nsDOMSlots : public nsIContent::nsContentSlots {
204    public:
205     nsDOMSlots();
206     ~nsDOMSlots();
207 
208     void Traverse(nsCycleCollectionTraversalCallback&) final;
209     void Unlink() final;
210 
211     size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
212 
213     /**
214      * The .style attribute (an interface that forwards to the actual
215      * style rules)
216      * @see nsGenericHTMLElement::GetStyle
217      */
218     nsCOMPtr<nsICSSDeclaration> mStyle;
219 
220     /**
221      * The .dataset attribute.
222      * @see nsGenericHTMLElement::GetDataset
223      */
224     nsDOMStringMap* mDataset;  // [Weak]
225 
226     /**
227      * @see Element::Attributes
228      */
229     RefPtr<nsDOMAttributeMap> mAttributeMap;
230 
231     /**
232      * An object implementing the .children property for this element.
233      */
234     RefPtr<nsContentList> mChildrenList;
235 
236     /**
237      * An object implementing the .classList property for this element.
238      */
239     RefPtr<nsDOMTokenList> mClassList;
240 
241     /**
242      * An object implementing the .part property for this element.
243      */
244     RefPtr<nsDOMTokenList> mPart;
245   };
246 
247   /**
248    * In case ExtendedDOMSlots is needed before normal DOMSlots, an instance of
249    * FatSlots class, which combines those two slot types, is created.
250    * This way we can avoid extra allocation for ExtendedDOMSlots.
251    * FatSlots is useful for example when creating Custom Elements.
252    */
253   class FatSlots final : public nsDOMSlots, public nsExtendedDOMSlots {
254    public:
FatSlots()255     FatSlots() : nsDOMSlots(), nsExtendedDOMSlots() {
256       MOZ_COUNT_CTOR(FatSlots);
257       SetExtendedContentSlots(this, false);
258     }
259 
~FatSlots()260     ~FatSlots() final { MOZ_COUNT_DTOR(FatSlots); }
261   };
262 
263  protected:
264   void GetMarkup(bool aIncludeSelf, nsAString& aMarkup);
265   void SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult& aError);
266 
267   // Override from nsINode
CreateSlots()268   nsIContent::nsContentSlots* CreateSlots() override {
269     return new nsDOMSlots();
270   }
271 
CreateExtendedSlots()272   nsIContent::nsExtendedContentSlots* CreateExtendedSlots() final {
273     return new nsExtendedDOMSlots();
274   }
275 
DOMSlots()276   nsDOMSlots* DOMSlots() { return static_cast<nsDOMSlots*>(Slots()); }
277 
GetExistingDOMSlots()278   nsDOMSlots* GetExistingDOMSlots() const {
279     return static_cast<nsDOMSlots*>(GetExistingSlots());
280   }
281 
ExtendedDOMSlots()282   nsExtendedDOMSlots* ExtendedDOMSlots() {
283     nsContentSlots* slots = GetExistingContentSlots();
284     if (!slots) {
285       FatSlots* fatSlots = new FatSlots();
286       mSlots = fatSlots;
287       return fatSlots;
288     }
289 
290     if (!slots->GetExtendedContentSlots()) {
291       slots->SetExtendedContentSlots(CreateExtendedSlots(), true);
292     }
293 
294     return static_cast<nsExtendedDOMSlots*>(slots->GetExtendedContentSlots());
295   }
296 
GetExistingExtendedDOMSlots()297   const nsExtendedDOMSlots* GetExistingExtendedDOMSlots() const {
298     return static_cast<const nsExtendedDOMSlots*>(
299         GetExistingExtendedContentSlots());
300   }
301 
GetExistingExtendedDOMSlots()302   nsExtendedDOMSlots* GetExistingExtendedDOMSlots() {
303     return static_cast<nsExtendedDOMSlots*>(GetExistingExtendedContentSlots());
304   }
305 
306   friend class ::ContentUnbinder;
307 };
308 
309 }  // namespace dom
310 }  // namespace mozilla
311 
312 #define NS_ELEMENT_INTERFACE_TABLE_TO_MAP_SEGUE               \
313   if (NS_SUCCEEDED(rv)) return rv;                            \
314                                                               \
315   rv = FragmentOrElement::QueryInterface(aIID, aInstancePtr); \
316   NS_INTERFACE_TABLE_TO_MAP_SEGUE
317 
318 #endif /* FragmentOrElement_h___ */
319