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 #ifndef nsIContent_h___ 7 #define nsIContent_h___ 8 9 #include "mozilla/FlushType.h" 10 #include "nsINode.h" 11 #include "nsStringFwd.h" 12 13 // Forward declarations 14 class nsIURI; 15 class nsTextFragment; 16 class nsIFrame; 17 18 namespace mozilla { 19 class EventChainPreVisitor; 20 struct URLExtraData; 21 namespace dom { 22 struct BindContext; 23 class ShadowRoot; 24 class HTMLSlotElement; 25 } // namespace dom 26 namespace widget { 27 enum class IMEEnabled; 28 struct IMEState; 29 } // namespace widget 30 } // namespace mozilla 31 32 // IID for the nsIContent interface 33 // Must be kept in sync with xpcom/rust/xpcom/src/interfaces/nonidl.rs 34 #define NS_ICONTENT_IID \ 35 { \ 36 0x8e1bab9d, 0x8815, 0x4d2c, { \ 37 0xa2, 0x4d, 0x7a, 0xba, 0x52, 0x39, 0xdc, 0x22 \ 38 } \ 39 } 40 41 /** 42 * A node of content in a document's content model. This interface 43 * is supported by all content objects. 44 */ 45 class nsIContent : public nsINode { 46 public: 47 using IMEEnabled = mozilla::widget::IMEEnabled; 48 using IMEState = mozilla::widget::IMEState; 49 using BindContext = mozilla::dom::BindContext; 50 51 void ConstructUbiNode(void* storage) override; 52 53 #ifdef MOZILLA_INTERNAL_API 54 // If you're using the external API, the only thing you can know about 55 // nsIContent is that it exists with an IID 56 nsIContent(already_AddRefed<mozilla::dom::NodeInfo> && aNodeInfo)57 explicit nsIContent(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo) 58 : nsINode(std::move(aNodeInfo)) { 59 MOZ_ASSERT(mNodeInfo); 60 MOZ_ASSERT(static_cast<nsINode*>(this) == reinterpret_cast<nsINode*>(this)); 61 SetNodeIsContent(); 62 } 63 #endif // MOZILLA_INTERNAL_API 64 65 NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENT_IID) 66 67 NS_DECL_CYCLE_COLLECTING_ISUPPORTS_FINAL_DELETECYCLECOLLECTABLE 68 69 NS_DECL_CYCLE_COLLECTION_CLASS(nsIContent) 70 71 NS_DECL_DOMARENA_DESTROY 72 73 NS_IMPL_FROMNODE_HELPER(nsIContent, IsContent()) 74 75 /** 76 * Bind this content node to a tree. If this method throws, the caller must 77 * call UnbindFromTree() on the node. In the typical case of a node being 78 * appended to a parent, this will be called after the node has been added to 79 * the parent's child list and before nsIDocumentObserver notifications for 80 * the addition are dispatched. 81 * BindContext propagates various information down the subtree; see its 82 * documentation to know how to set it up. 83 * @param aParent The new parent node for the content node. May be a document. 84 * @note This method must not be called by consumers of nsIContent on a node 85 * that is already bound to a tree. Call UnbindFromTree first. 86 * @note This method will handle rebinding descendants appropriately (eg 87 * changing their binding parent as needed). 88 * @note This method does not add the content node to aParent's child list 89 * @throws NS_ERROR_OUT_OF_MEMORY if that happens 90 * 91 * TODO(emilio): Should we move to nsIContent::BindToTree most of the 92 * FragmentOrElement / CharacterData duplicated code? 93 */ 94 virtual nsresult BindToTree(BindContext&, nsINode& aParent) = 0; 95 96 /** 97 * Unbind this content node from a tree. This will set its current document 98 * and binding parent to null. In the typical case of a node being removed 99 * from a parent, this will be called after it has been removed from the 100 * parent's child list and after the nsIDocumentObserver notifications for 101 * the removal have been dispatched. 102 * @param aDeep Whether to recursively unbind the entire subtree rooted at 103 * this node. The only time false should be passed is when the 104 * parent node of the content is being destroyed. 105 * @param aNullParent Whether to null out the parent pointer as well. This 106 * is usually desirable. This argument should only be false while 107 * recursively calling UnbindFromTree when a subtree is detached. 108 * @note This method is safe to call on nodes that are not bound to a tree. 109 */ 110 virtual void UnbindFromTree(bool aNullParent = true) = 0; 111 112 enum { 113 /** 114 * All XBL flattened tree children of the node, as well as :before and 115 * :after anonymous content and native anonymous children. 116 * 117 * @note the result children order is 118 * 1. :before generated node 119 * 2. XBL flattened tree children of this node 120 * 3. native anonymous nodes 121 * 4. :after generated node 122 */ 123 eAllChildren = 0, 124 125 /** 126 * All XBL explicit children of the node (see 127 * http://www.w3.org/TR/xbl/#explicit3 ), as well as :before and :after 128 * anonymous content and native anonymous children. 129 * 130 * @note the result children order is 131 * 1. :before generated node 132 * 2. XBL explicit children of the node 133 * 3. native anonymous nodes 134 * 4. :after generated node 135 */ 136 eAllButXBL = 1, 137 138 /** 139 * Skip native anonymous content created for placeholder of HTML input, 140 * used in conjunction with eAllChildren or eAllButXBL. 141 */ 142 eSkipPlaceholderContent = 2, 143 144 /** 145 * Skip native anonymous content created by ancestor frames of the root 146 * element's primary frame, such as scrollbar elements created by the root 147 * scroll frame. 148 */ 149 eSkipDocumentLevelNativeAnonymousContent = 4, 150 }; 151 152 /** 153 * Return either the XBL explicit children of the node or the XBL flattened 154 * tree children of the node, depending on the filter, as well as 155 * native anonymous children. 156 * 157 * @note calling this method with eAllButXBL will return children that are 158 * also in the eAllButXBL and eAllChildren child lists of other descendants 159 * of this node in the tree, but those other nodes cannot be reached from the 160 * eAllButXBL child list. 161 */ 162 virtual already_AddRefed<nsINodeList> GetChildren(uint32_t aFilter) = 0; 163 164 /** 165 * Makes this content anonymous 166 * @see nsIAnonymousContentCreator 167 */ SetIsNativeAnonymousRoot()168 void SetIsNativeAnonymousRoot() { 169 SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | 170 NODE_IS_NATIVE_ANONYMOUS_ROOT); 171 } 172 173 /** 174 * Returns |this| if it is not chrome-only/native anonymous, otherwise 175 * first non chrome-only/native anonymous ancestor. 176 */ 177 nsIContent* FindFirstNonChromeOnlyAccessContent() const; 178 179 /** 180 * Return true iff this node is in an HTML document (in the HTML5 sense of 181 * the term, i.e. not in an XHTML/XML document). 182 */ 183 inline bool IsInHTMLDocument() const; 184 185 /** 186 * Returns true if in a chrome document 187 */ 188 inline bool IsInChromeDocument() const; 189 190 /** 191 * Get the namespace that this element's tag is defined in 192 * @return the namespace 193 */ GetNameSpaceID()194 inline int32_t GetNameSpaceID() const { return mNodeInfo->NamespaceID(); } 195 IsHTMLElement()196 inline bool IsHTMLElement() const { 197 return IsInNamespace(kNameSpaceID_XHTML); 198 } 199 IsHTMLElement(const nsAtom * aTag)200 inline bool IsHTMLElement(const nsAtom* aTag) const { 201 return mNodeInfo->Equals(aTag, kNameSpaceID_XHTML); 202 } 203 204 template <typename First, typename... Args> IsAnyOfHTMLElements(First aFirst,Args...aArgs)205 inline bool IsAnyOfHTMLElements(First aFirst, Args... aArgs) const { 206 return IsHTMLElement() && IsNodeInternal(aFirst, aArgs...); 207 } 208 IsSVGElement()209 inline bool IsSVGElement() const { return IsInNamespace(kNameSpaceID_SVG); } 210 IsSVGElement(const nsAtom * aTag)211 inline bool IsSVGElement(const nsAtom* aTag) const { 212 return mNodeInfo->Equals(aTag, kNameSpaceID_SVG); 213 } 214 215 template <typename First, typename... Args> IsAnyOfSVGElements(First aFirst,Args...aArgs)216 inline bool IsAnyOfSVGElements(First aFirst, Args... aArgs) const { 217 return IsSVGElement() && IsNodeInternal(aFirst, aArgs...); 218 } 219 IsXULElement()220 inline bool IsXULElement() const { return IsInNamespace(kNameSpaceID_XUL); } 221 IsXULElement(const nsAtom * aTag)222 inline bool IsXULElement(const nsAtom* aTag) const { 223 return mNodeInfo->Equals(aTag, kNameSpaceID_XUL); 224 } 225 226 template <typename First, typename... Args> IsAnyOfXULElements(First aFirst,Args...aArgs)227 inline bool IsAnyOfXULElements(First aFirst, Args... aArgs) const { 228 return IsXULElement() && IsNodeInternal(aFirst, aArgs...); 229 } 230 IsMathMLElement()231 inline bool IsMathMLElement() const { 232 return IsInNamespace(kNameSpaceID_MathML); 233 } 234 IsMathMLElement(const nsAtom * aTag)235 inline bool IsMathMLElement(const nsAtom* aTag) const { 236 return mNodeInfo->Equals(aTag, kNameSpaceID_MathML); 237 } 238 239 template <typename First, typename... Args> IsAnyOfMathMLElements(First aFirst,Args...aArgs)240 inline bool IsAnyOfMathMLElements(First aFirst, Args... aArgs) const { 241 return IsMathMLElement() && IsNodeInternal(aFirst, aArgs...); 242 } 243 IsGeneratedContentContainerForBefore()244 bool IsGeneratedContentContainerForBefore() const { 245 return IsRootOfNativeAnonymousSubtree() && 246 mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore; 247 } 248 IsGeneratedContentContainerForAfter()249 bool IsGeneratedContentContainerForAfter() const { 250 return IsRootOfNativeAnonymousSubtree() && 251 mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentafter; 252 } 253 IsGeneratedContentContainerForMarker()254 bool IsGeneratedContentContainerForMarker() const { 255 return IsRootOfNativeAnonymousSubtree() && 256 mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentmarker; 257 } 258 259 /** 260 * Get direct access (but read only) to the text in the text content. 261 * NOTE: For elements this is *not* the concatenation of all text children, 262 * it is simply null; 263 */ 264 virtual const nsTextFragment* GetText() = 0; 265 266 /** 267 * Get the length of the text content. 268 * NOTE: This should not be called on elements. 269 */ 270 virtual uint32_t TextLength() const = 0; 271 272 /** 273 * Determines if an event attribute name (such as onclick) is valid for 274 * a given element type. 275 * @note calls nsContentUtils::IsEventAttributeName with right flag 276 * @note *Internal is overridden by subclasses as needed 277 * @param aName the event name to look up 278 */ 279 bool IsEventAttributeName(nsAtom* aName); 280 IsEventAttributeNameInternal(nsAtom * aName)281 virtual bool IsEventAttributeNameInternal(nsAtom* aName) { return false; } 282 283 /** 284 * Query method to see if the frame is nothing but whitespace 285 * NOTE: Always returns false for elements 286 */ 287 virtual bool TextIsOnlyWhitespace() = 0; 288 289 /** 290 * Thread-safe version of TextIsOnlyWhitespace. 291 */ 292 virtual bool ThreadSafeTextIsOnlyWhitespace() const = 0; 293 294 /** 295 * Check if this content is focusable and in the current tab order. 296 * Note: most callers should use nsIFrame::IsFocusable() instead as it 297 * checks visibility and other layout factors as well. 298 * Tabbable is indicated by a nonnegative tabindex & is a subset of focusable. 299 * For example, only the selected radio button in a group is in the 300 * tab order, unless the radio group has no selection in which case 301 * all of the visible, non-disabled radio buttons in the group are 302 * in the tab order. On the other hand, all of the visible, non-disabled 303 * radio buttons are always focusable via clicking or script. 304 * Also, depending on either the accessibility.tabfocus pref or 305 * a system setting (nowadays: Full keyboard access, mac only) 306 * some widgets may be focusable but removed from the tab order. 307 * @param [inout, optional] aTabIndex the computed tab index 308 * In: default tabindex for element (-1 nonfocusable, == 0 focusable) 309 * Out: computed tabindex 310 * @param [optional] aTabIndex the computed tab index 311 * < 0 if not tabbable 312 * == 0 if in normal tab order 313 * > 0 can be tabbed to in the order specified by this value 314 * @return whether the content is focusable via mouse, kbd or script. 315 */ 316 bool IsFocusable(int32_t* aTabIndex = nullptr, bool aWithMouse = false); 317 virtual bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse); 318 319 /* 320 * Get desired IME state for the content. 321 * 322 * @return The desired IME status for the content. 323 * This is a combination of an IME enabled value and 324 * an IME open value of widget::IMEState. 325 * If you return IMEEnabled::Disabled, you should not set the OPEN 326 * nor CLOSE value. 327 * IMEEnabled::Password should be returned only from password editor, 328 * this value has a special meaning. It is used as alternative of 329 * IMEEnabled::Disabled. IMEENabled::Plugin should be returned only 330 * when plug-in has focus. When a plug-in is focused content, we 331 * should send native events directly. Because we don't process some 332 * native events, but they may be needed by the plug-in. 333 */ 334 virtual IMEState GetDesiredIMEState(); 335 336 /** 337 * Gets the ShadowRoot binding for this element. 338 * 339 * @return The ShadowRoot currently bound to this element. 340 */ 341 inline mozilla::dom::ShadowRoot* GetShadowRoot() const; 342 343 /** 344 * Gets the root of the node tree for this content if it is in a shadow tree. 345 * 346 * @return The ShadowRoot that is the root of the node tree. 347 */ GetContainingShadow()348 mozilla::dom::ShadowRoot* GetContainingShadow() const { 349 const nsExtendedContentSlots* slots = GetExistingExtendedContentSlots(); 350 return slots ? slots->mContainingShadow.get() : nullptr; 351 } 352 353 /** 354 * Gets the assigned slot associated with this content. 355 * 356 * @return The assigned slot element or null. 357 */ GetAssignedSlot()358 mozilla::dom::HTMLSlotElement* GetAssignedSlot() const { 359 const nsExtendedContentSlots* slots = GetExistingExtendedContentSlots(); 360 return slots ? slots->mAssignedSlot.get() : nullptr; 361 } 362 363 /** 364 * Sets the assigned slot associated with this content. 365 * 366 * @param aSlot The assigned slot. 367 */ 368 void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot); 369 370 /** 371 * Gets the assigned slot associated with this content based on parent's 372 * shadow root mode. Returns null if parent's shadow root is "closed". 373 * https://dom.spec.whatwg.org/#dom-slotable-assignedslot 374 * 375 * @return The assigned slot element or null. 376 */ 377 mozilla::dom::HTMLSlotElement* GetAssignedSlotByMode() const; 378 379 /** 380 * Same as GetFlattenedTreeParentNode, but returns null if the parent is 381 * non-nsIContent. 382 */ 383 inline nsIContent* GetFlattenedTreeParent() const; 384 385 protected: 386 // Handles getting inserted or removed directly under a <slot> element. 387 // This is meant to only be called from the two functions below. 388 inline void HandleInsertionToOrRemovalFromSlot(); 389 390 // Handles Shadow-DOM-related state tracking. Meant to be called near the 391 // end of BindToTree(), only if the tree we're in actually changed, that is, 392 // after the subtree has been bound to the new parent. 393 inline void HandleShadowDOMRelatedInsertionSteps(bool aHadParent); 394 395 // Handles Shadow-DOM related state tracking. Meant to be called near the 396 // beginning of UnbindFromTree(), before the node has lost the reference to 397 // its parent. 398 inline void HandleShadowDOMRelatedRemovalSteps(bool aNullParent); 399 400 public: 401 /** 402 * API to check if this is a link that's traversed in response to user input 403 * (e.g. a click event). Specializations for HTML/SVG/generic XML allow for 404 * different types of link in different types of content. 405 * 406 * @param aURI Required out param. If this content is a link, a new nsIURI 407 * set to this link's URI will be passed out. 408 * 409 * @note The out param, aURI, is guaranteed to be set to a non-null pointer 410 * when the return value is true. 411 * 412 * XXXjwatt: IMO IsInteractiveLink would be a better name. 413 */ 414 virtual bool IsLink(nsIURI** aURI) const = 0; 415 416 /** 417 * Get a pointer to the full href URI (fully resolved and canonicalized, 418 * since it's an nsIURI object) for link elements. 419 * 420 * @return A pointer to the URI or null if the element is not a link or it 421 * has no HREF attribute. 422 */ GetHrefURI()423 virtual already_AddRefed<nsIURI> GetHrefURI() const { return nullptr; } 424 425 /** 426 * This method is called when the parser finishes creating the element. This 427 * particularly means that it has done everything you would expect it to have 428 * done after it encounters the > at the end of the tag (for HTML or XML). 429 * This includes setting the attributes, setting the document / form, and 430 * placing the element into the tree at its proper place. 431 * 432 * For container elements, this is called *before* any of the children are 433 * created or added into the tree. 434 * 435 * NOTE: this is only called for elements listed in 436 * RequiresDoneCreatingElement. This is an efficiency measure. 437 * 438 * If you also need to determine whether the parser is the one creating your 439 * element (through createElement() or cloneNode() generally) then add a 440 * uint32_t aFromParser to the NS_NewXXX() constructor for your element and 441 * have the parser pass the appropriate flags. See HTMLInputElement.cpp and 442 * nsHTMLContentSink::MakeContentObject(). 443 * 444 * DO NOT USE THIS METHOD to get around the fact that it's hard to deal with 445 * attributes dynamically. If you make attributes affect your element from 446 * this method, it will only happen on initialization and JavaScript will not 447 * be able to create elements (which requires them to first create the 448 * element and then call setAttribute() directly, at which point 449 * DoneCreatingElement() has already been called and is out of the picture). 450 */ DoneCreatingElement()451 virtual void DoneCreatingElement() {} 452 453 /** 454 * This method is called when the parser finishes creating the element's 455 * children, if any are present. 456 * 457 * NOTE: this is only called for elements listed in 458 * RequiresDoneAddingChildren. This is an efficiency measure. 459 * 460 * If you also need to determine whether the parser is the one creating your 461 * element (through createElement() or cloneNode() generally) then add a 462 * boolean aFromParser to the NS_NewXXX() constructor for your element and 463 * have the parser pass true. See HTMLInputElement.cpp and 464 * nsHTMLContentSink::MakeContentObject(). 465 * 466 * @param aHaveNotified Whether there has been a 467 * ContentInserted/ContentAppended notification for this content node 468 * yet. 469 */ DoneAddingChildren(bool aHaveNotified)470 virtual void DoneAddingChildren(bool aHaveNotified) {} 471 472 /** 473 * For HTML textarea, select, and object elements, returns true if all 474 * children have been added OR if the element was not created by the parser. 475 * Returns true for all other elements. 476 * 477 * @returns false if the element was created by the parser and 478 * it is an HTML textarea, select, or object 479 * element and not all children have been added. 480 * 481 * @returns true otherwise. 482 */ IsDoneAddingChildren()483 virtual bool IsDoneAddingChildren() { return true; } 484 485 /** 486 * Returns true if an element needs its DoneCreatingElement method to be 487 * called after it has been created. 488 * @see nsIContent::DoneCreatingElement 489 * 490 * @param aNamespaceID the node's namespace ID 491 * @param aName the node's tag name 492 */ RequiresDoneCreatingElement(int32_t aNamespace,nsAtom * aName)493 static inline bool RequiresDoneCreatingElement(int32_t aNamespace, 494 nsAtom* aName) { 495 if (aNamespace == kNameSpaceID_XHTML && 496 (aName == nsGkAtoms::input || aName == nsGkAtoms::button || 497 aName == nsGkAtoms::menuitem || aName == nsGkAtoms::audio || 498 aName == nsGkAtoms::video)) { 499 MOZ_ASSERT( 500 !RequiresDoneAddingChildren(aNamespace, aName), 501 "Both DoneCreatingElement and DoneAddingChildren on a same element " 502 "isn't supported."); 503 return true; 504 } 505 return false; 506 } 507 508 /** 509 * Returns true if an element needs its DoneAddingChildren method to be 510 * called after all of its children have been added. 511 * @see nsIContent::DoneAddingChildren 512 * 513 * @param aNamespace the node's namespace ID 514 * @param aName the node's tag name 515 */ RequiresDoneAddingChildren(int32_t aNamespace,nsAtom * aName)516 static inline bool RequiresDoneAddingChildren(int32_t aNamespace, 517 nsAtom* aName) { 518 return (aNamespace == kNameSpaceID_XHTML && 519 (aName == nsGkAtoms::select || aName == nsGkAtoms::textarea || 520 aName == nsGkAtoms::head || aName == nsGkAtoms::title || 521 aName == nsGkAtoms::object || aName == nsGkAtoms::output)) || 522 (aNamespace == kNameSpaceID_SVG && aName == nsGkAtoms::title) || 523 (aNamespace == kNameSpaceID_XUL && aName == nsGkAtoms::linkset); 524 } 525 526 /** 527 * Get the ID of this content node (the atom corresponding to the 528 * value of the id attribute). This may be null if there is no ID. 529 */ GetID()530 nsAtom* GetID() const { 531 if (HasID()) { 532 return DoGetID(); 533 } 534 return nullptr; 535 } 536 537 /** 538 * Should be called when the node can become editable or when it can stop 539 * being editable (for example when its contentEditable attribute changes, 540 * when it is moved into an editable parent, ...). If aNotify is true and 541 * the node is an element, this will notify the state change. 542 */ 543 virtual void UpdateEditableState(bool aNotify); 544 545 /** 546 * Destroy this node and its children. Ideally this shouldn't be needed 547 * but for now we need to do it to break cycles. 548 */ DestroyContent()549 virtual void DestroyContent() {} 550 551 /** 552 * Saves the form state of this node and its children. 553 */ 554 virtual void SaveSubtreeState() = 0; 555 556 /** 557 * Getter and setter for our primary frame pointer. This is the frame that 558 * is most closely associated with the content. A frame is more closely 559 * associated with the content than another frame if the one frame contains 560 * directly or indirectly the other frame (e.g., when a frame is scrolled 561 * there is a scroll frame that contains the frame being scrolled). This 562 * frame is always the first continuation. 563 * 564 * In the case of absolutely positioned elements and floated elements, this 565 * frame is the out of flow frame, not the placeholder. 566 */ GetPrimaryFrame()567 nsIFrame* GetPrimaryFrame() const { 568 return (IsInUncomposedDoc() || IsInShadowTree()) ? mPrimaryFrame : nullptr; 569 } 570 571 /** 572 * Get the primary frame for this content with flushing 573 * 574 * @param aType the kind of flush to do, typically FlushType::Frames or 575 * FlushType::Layout 576 * @return the primary frame 577 */ 578 nsIFrame* GetPrimaryFrame(mozilla::FlushType aType); 579 580 // Defined in nsIContentInlines.h because it needs nsIFrame. 581 inline void SetPrimaryFrame(nsIFrame* aFrame); 582 583 nsresult LookupNamespaceURIInternal(const nsAString& aNamespacePrefix, 584 nsAString& aNamespaceURI) const; 585 586 /** 587 * If this content has independent selection, e.g., if this is input field 588 * or textarea, this return TRUE. Otherwise, false. 589 */ 590 bool HasIndependentSelection() const; 591 592 /** 593 * If the content is a part of HTML editor, this returns editing 594 * host content. When the content is in designMode, this returns its body 595 * element. Also, when the content isn't editable, this returns null. 596 */ 597 mozilla::dom::Element* GetEditingHost(); 598 SupportsLangAttr()599 bool SupportsLangAttr() const { 600 return IsHTMLElement() || IsSVGElement() || IsXULElement(); 601 } 602 603 /** 604 * Determining language. Look at the nearest ancestor element that has a lang 605 * attribute in the XML namespace or is an HTML/SVG element and has a lang in 606 * no namespace attribute. 607 * 608 * Returns null if no language was specified. Can return the empty atom. 609 */ 610 nsAtom* GetLang() const; 611 GetLang(nsAString & aResult)612 bool GetLang(nsAString& aResult) const { 613 if (auto* lang = GetLang()) { 614 aResult.Assign(nsDependentAtomString(lang)); 615 return true; 616 } 617 618 return false; 619 } 620 621 // Overloaded from nsINode 622 nsIURI* GetBaseURI(bool aTryUseXHRDocBaseURI = false) const override; 623 624 // Returns base URI for style attribute. 625 nsIURI* GetBaseURIForStyleAttr() const; 626 627 // Returns the URL data for style attribute. 628 // If aSubjectPrincipal is passed, it should be the scripted principal 629 // responsible for generating the URL data. 630 already_AddRefed<mozilla::URLExtraData> GetURLDataForStyleAttr( 631 nsIPrincipal* aSubjectPrincipal = nullptr) const; 632 633 void GetEventTargetParent(mozilla::EventChainPreVisitor& aVisitor) override; 634 IsPurple()635 bool IsPurple() const { return mRefCnt.IsPurple(); } 636 RemovePurple()637 void RemovePurple() { mRefCnt.RemovePurple(); } 638 OwnedOnlyByTheDOMTree()639 bool OwnedOnlyByTheDOMTree() { 640 uint32_t rc = mRefCnt.get(); 641 if (GetParent()) { 642 --rc; 643 } 644 rc -= GetChildCount(); 645 return rc == 0; 646 } 647 648 protected: 649 /** 650 * Lazily allocated extended slots to avoid 651 * that may only be instantiated when a content object is accessed 652 * through the DOM. Rather than burn actual slots in the content 653 * objects for each of these instance variables, we put them off 654 * in a side structure that's only allocated when the content is 655 * accessed through the DOM. 656 */ 657 class nsExtendedContentSlots { 658 public: 659 nsExtendedContentSlots(); 660 virtual ~nsExtendedContentSlots(); 661 662 virtual void TraverseExtendedSlots(nsCycleCollectionTraversalCallback&); 663 virtual void UnlinkExtendedSlots(); 664 665 virtual size_t SizeOfExcludingThis( 666 mozilla::MallocSizeOf aMallocSizeOf) const; 667 668 /** 669 * @see nsIContent::GetContainingShadow 670 */ 671 RefPtr<mozilla::dom::ShadowRoot> mContainingShadow; 672 673 /** 674 * @see nsIContent::GetAssignedSlot 675 */ 676 RefPtr<mozilla::dom::HTMLSlotElement> mAssignedSlot; 677 }; 678 679 class nsContentSlots : public nsINode::nsSlots { 680 public: nsContentSlots()681 nsContentSlots() : nsINode::nsSlots(), mExtendedSlots(0) {} 682 ~nsContentSlots()683 ~nsContentSlots() { 684 if (!(mExtendedSlots & sNonOwningExtendedSlotsFlag)) { 685 delete GetExtendedContentSlots(); 686 } 687 } 688 Traverse(nsCycleCollectionTraversalCallback & aCb)689 void Traverse(nsCycleCollectionTraversalCallback& aCb) override { 690 nsINode::nsSlots::Traverse(aCb); 691 if (mExtendedSlots) { 692 GetExtendedContentSlots()->TraverseExtendedSlots(aCb); 693 } 694 } 695 Unlink()696 void Unlink() override { 697 nsINode::nsSlots::Unlink(); 698 if (mExtendedSlots) { 699 GetExtendedContentSlots()->UnlinkExtendedSlots(); 700 } 701 } 702 SetExtendedContentSlots(nsExtendedContentSlots * aSlots,bool aOwning)703 void SetExtendedContentSlots(nsExtendedContentSlots* aSlots, bool aOwning) { 704 mExtendedSlots = reinterpret_cast<uintptr_t>(aSlots); 705 if (!aOwning) { 706 mExtendedSlots |= sNonOwningExtendedSlotsFlag; 707 } 708 } 709 710 // OwnsExtendedSlots returns true if we have no extended slots or if we 711 // have extended slots and own them. OwnsExtendedSlots()712 bool OwnsExtendedSlots() const { 713 return !(mExtendedSlots & sNonOwningExtendedSlotsFlag); 714 } 715 GetExtendedContentSlots()716 nsExtendedContentSlots* GetExtendedContentSlots() const { 717 return reinterpret_cast<nsExtendedContentSlots*>( 718 mExtendedSlots & ~sNonOwningExtendedSlotsFlag); 719 } 720 721 private: 722 static const uintptr_t sNonOwningExtendedSlotsFlag = 1u; 723 724 uintptr_t mExtendedSlots; 725 }; 726 727 // Override from nsINode CreateSlots()728 nsContentSlots* CreateSlots() override { return new nsContentSlots(); } 729 ContentSlots()730 nsContentSlots* ContentSlots() { 731 return static_cast<nsContentSlots*>(Slots()); 732 } 733 GetExistingContentSlots()734 const nsContentSlots* GetExistingContentSlots() const { 735 return static_cast<nsContentSlots*>(GetExistingSlots()); 736 } 737 GetExistingContentSlots()738 nsContentSlots* GetExistingContentSlots() { 739 return static_cast<nsContentSlots*>(GetExistingSlots()); 740 } 741 CreateExtendedSlots()742 virtual nsExtendedContentSlots* CreateExtendedSlots() { 743 return new nsExtendedContentSlots(); 744 } 745 GetExistingExtendedContentSlots()746 const nsExtendedContentSlots* GetExistingExtendedContentSlots() const { 747 const nsContentSlots* slots = GetExistingContentSlots(); 748 return slots ? slots->GetExtendedContentSlots() : nullptr; 749 } 750 GetExistingExtendedContentSlots()751 nsExtendedContentSlots* GetExistingExtendedContentSlots() { 752 nsContentSlots* slots = GetExistingContentSlots(); 753 return slots ? slots->GetExtendedContentSlots() : nullptr; 754 } 755 ExtendedContentSlots()756 nsExtendedContentSlots* ExtendedContentSlots() { 757 nsContentSlots* slots = ContentSlots(); 758 if (!slots->GetExtendedContentSlots()) { 759 slots->SetExtendedContentSlots(CreateExtendedSlots(), true); 760 } 761 return slots->GetExtendedContentSlots(); 762 } 763 764 /** 765 * Hook for implementing GetID. This is guaranteed to only be 766 * called if HasID() is true. 767 */ 768 nsAtom* DoGetID() const; 769 770 ~nsIContent() = default; 771 772 public: 773 #if defined(DEBUG) || defined(MOZ_DUMP_PAINTING) 774 # define MOZ_DOM_LIST 775 #endif 776 777 #ifdef MOZ_DOM_LIST 778 /** 779 * List the content (and anything it contains) out to the given 780 * file stream. Use aIndent as the base indent during formatting. 781 */ 782 virtual void List(FILE* out = stdout, int32_t aIndent = 0) const = 0; 783 784 /** 785 * Dump the content (and anything it contains) out to the given 786 * file stream. Use aIndent as the base indent during formatting. 787 */ 788 virtual void DumpContent(FILE* out = stdout, int32_t aIndent = 0, 789 bool aDumpAll = true) const = 0; 790 #endif 791 792 enum ETabFocusType { 793 eTabFocus_textControlsMask = 794 (1 << 0), // textboxes and lists always tabbable 795 eTabFocus_formElementsMask = (1 << 1), // non-text form elements 796 eTabFocus_linksMask = (1 << 2), // links 797 eTabFocus_any = 1 + (1 << 1) + (1 << 2) // everything that can be focused 798 }; 799 800 // Tab focus model bit field: 801 static int32_t sTabFocusModel; 802 803 // accessibility.tabfocus_applies_to_xul pref - if it is set to true, 804 // the tabfocus bit field applies to xul elements. 805 static bool sTabFocusModelAppliesToXUL; 806 }; 807 808 NS_DEFINE_STATIC_IID_ACCESSOR(nsIContent, NS_ICONTENT_IID) 809 810 #endif /* nsIContent_h___ */ 811