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