tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsGenericHTMLElement.h (56096B)


      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 nsGenericHTMLElement_h___
      7 #define nsGenericHTMLElement_h___
      8 
      9 #include <cstdint>
     10 
     11 #include "mozilla/Attributes.h"
     12 #include "mozilla/EventForwards.h"
     13 #include "mozilla/dom/BindingDeclarations.h"
     14 #include "mozilla/dom/DOMRect.h"
     15 #include "mozilla/dom/Element.h"
     16 #include "mozilla/dom/PopoverData.h"
     17 #include "mozilla/dom/ToggleEvent.h"
     18 #include "mozilla/dom/ValidityState.h"
     19 #include "nsContentCreatorFunctions.h"
     20 #include "nsGkAtoms.h"
     21 #include "nsIFormControl.h"
     22 #include "nsNameSpaceManager.h"  // for kNameSpaceID_None
     23 #include "nsStyledElement.h"
     24 
     25 class nsDOMTokenList;
     26 class nsIFrame;
     27 class nsILayoutHistoryState;
     28 class nsIURI;
     29 struct nsSize;
     30 
     31 enum NonCustomCSSPropertyId : uint16_t;
     32 
     33 namespace mozilla {
     34 class EditorBase;
     35 class ErrorResult;
     36 class EventChainPostVisitor;
     37 class EventChainPreVisitor;
     38 class EventChainVisitor;
     39 class EventListenerManager;
     40 class PresState;
     41 namespace dom {
     42 class BooleanOrUnrestrictedDoubleOrString;
     43 class ElementInternals;
     44 class HTMLFormElement;
     45 class OwningBooleanOrUnrestrictedDoubleOrString;
     46 class TogglePopoverOptionsOrBoolean;
     47 enum class FetchPriority : uint8_t;
     48 struct ShowPopoverOptions;
     49 }  // namespace dom
     50 }  // namespace mozilla
     51 
     52 using nsGenericHTMLElementBase = nsStyledElement;
     53 
     54 /**
     55 * A common superclass for HTML elements
     56 */
     57 class nsGenericHTMLElement : public nsGenericHTMLElementBase {
     58 public:
     59  using ContentEditableState = mozilla::ContentEditableState;
     60  using Element::Command;
     61  using Element::Focus;
     62  using Element::SetTabIndex;
     63 
     64  explicit nsGenericHTMLElement(
     65      already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
     66      : nsGenericHTMLElementBase(std::move(aNodeInfo)) {
     67    NS_ASSERTION(mNodeInfo->NamespaceID() == kNameSpaceID_XHTML,
     68                 "Unexpected namespace");
     69  }
     70 
     71  NS_INLINE_DECL_REFCOUNTING_INHERITED(nsGenericHTMLElement,
     72                                       nsGenericHTMLElementBase)
     73 
     74  NS_IMPL_FROMNODE(nsGenericHTMLElement, kNameSpaceID_XHTML)
     75 
     76  // From Element
     77  nsresult CopyInnerTo(mozilla::dom::Element* aDest);
     78 
     79  void GetTitle(mozilla::dom::DOMString& aTitle) {
     80    GetHTMLAttr(nsGkAtoms::title, aTitle);
     81  }
     82  void SetTitle(const nsAString& aTitle) {
     83    SetHTMLAttr(nsGkAtoms::title, aTitle);
     84  }
     85  void GetLang(mozilla::dom::DOMString& aLang) {
     86    GetHTMLAttr(nsGkAtoms::lang, aLang);
     87  }
     88  void SetLang(const nsAString& aLang) { SetHTMLAttr(nsGkAtoms::lang, aLang); }
     89  bool Translate() const override;
     90  void SetTranslate(bool aTranslate, mozilla::ErrorResult& aError) {
     91    SetHTMLAttr(nsGkAtoms::translate, aTranslate ? u"yes"_ns : u"no"_ns,
     92                aError);
     93  }
     94  void GetDir(nsAString& aDir) { GetHTMLEnumAttr(nsGkAtoms::dir, aDir); }
     95  void SetDir(const nsAString& aDir, mozilla::ErrorResult& aError) {
     96    SetHTMLAttr(nsGkAtoms::dir, aDir, aError);
     97  }
     98  void GetPopover(nsString& aPopover) const;
     99  void SetPopover(const nsAString& aPopover, mozilla::ErrorResult& aError) {
    100    SetOrRemoveNullableStringAttr(nsGkAtoms::popover, aPopover, aError);
    101  }
    102 
    103  void GetHidden(mozilla::dom::Nullable<
    104                 mozilla::dom::OwningBooleanOrUnrestrictedDoubleOrString>&
    105                     aHidden) const;
    106 
    107  void SetHidden(
    108      const mozilla::dom::Nullable<
    109          mozilla::dom::BooleanOrUnrestrictedDoubleOrString>& aHidden,
    110      mozilla::ErrorResult& aRv);
    111 
    112  bool Inert() const { return GetBoolAttr(nsGkAtoms::inert); }
    113  void SetInert(bool aInert, mozilla::ErrorResult& aError) {
    114    SetHTMLBoolAttr(nsGkAtoms::inert, aInert, aError);
    115  }
    116  MOZ_CAN_RUN_SCRIPT void Click(mozilla::dom::CallerType aCallerType);
    117  void GetAccessKey(nsString& aAccessKey) {
    118    GetHTMLAttr(nsGkAtoms::accesskey, aAccessKey);
    119  }
    120  void SetAccessKey(const nsAString& aAccessKey, mozilla::ErrorResult& aError) {
    121    SetHTMLAttr(nsGkAtoms::accesskey, aAccessKey, aError);
    122  }
    123  void GetAccessKeyLabel(nsString& aAccessKeyLabel);
    124  virtual bool Draggable() const {
    125    return AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable,
    126                       nsGkAtoms::_true, eIgnoreCase);
    127  }
    128  void SetDraggable(bool aDraggable, mozilla::ErrorResult& aError) {
    129    SetHTMLAttr(nsGkAtoms::draggable, aDraggable ? u"true"_ns : u"false"_ns,
    130                aError);
    131  }
    132  void GetContentEditable(nsString& aContentEditable) const {
    133    switch (GetContentEditableState()) {
    134      case ContentEditableState::True:
    135        aContentEditable.AssignLiteral("true");
    136        return;
    137      case ContentEditableState::False:
    138        aContentEditable.AssignLiteral("false");
    139        return;
    140      case ContentEditableState::PlainTextOnly:
    141        aContentEditable.AssignLiteral("plaintext-only");
    142        return;
    143      case ContentEditableState::Inherit:
    144        aContentEditable.AssignLiteral("inherit");
    145        return;
    146    }
    147  }
    148  void SetContentEditable(const nsAString& aContentEditable,
    149                          mozilla::ErrorResult& aError) {
    150    if (aContentEditable.LowerCaseEqualsLiteral("inherit")) {
    151      UnsetHTMLAttr(nsGkAtoms::contenteditable, aError);
    152    } else if (aContentEditable.LowerCaseEqualsLiteral("true")) {
    153      SetHTMLAttr(nsGkAtoms::contenteditable, u"true"_ns, aError);
    154    } else if (aContentEditable.LowerCaseEqualsLiteral("false")) {
    155      SetHTMLAttr(nsGkAtoms::contenteditable, u"false"_ns, aError);
    156    } else if (aContentEditable.LowerCaseEqualsLiteral("plaintext-only")) {
    157      SetHTMLAttr(nsGkAtoms::contenteditable, u"plaintext-only"_ns, aError);
    158    } else {
    159      aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
    160    }
    161  }
    162 
    163  [[nodiscard]] bool IsContentEditable() const;
    164 
    165  /**
    166   * Returns ContentEditableState::True if the element has a contentEditable
    167   * attribute and its value is "true" or an empty string. Returns
    168   * ContentEditableState::False if the *element has a contentEditable attribute
    169   * and its value is "false". Returns ContentEditableState::PlainTextOnly if
    170   * the element has a contentEditable attribute and its value is
    171   * "plaintext-only". Otherwise returns ContentEditableState::Inherit.
    172   */
    173  [[nodiscard]] inline ContentEditableState GetContentEditableState() const {
    174    if (!MayHaveContentEditableAttr()) {
    175      return ContentEditableState::Inherit;
    176    }
    177    static constexpr AttrValuesArray kValidValuesExceptInherit[] = {
    178        nsGkAtoms::_empty, nsGkAtoms::_true, nsGkAtoms::plaintextOnly,
    179        nsGkAtoms::_false, nullptr};
    180    switch (mAttrs.FindAttrValueIn(kNameSpaceID_None,
    181                                   nsGkAtoms::contenteditable,
    182                                   kValidValuesExceptInherit, eIgnoreCase)) {
    183      case 0:
    184      case 1:
    185        return ContentEditableState::True;
    186      case 2:
    187        return ContentEditableState::PlainTextOnly;
    188      case 3:
    189        return ContentEditableState::False;
    190      default:
    191        return ContentEditableState::Inherit;
    192    }
    193  }
    194 
    195  mozilla::dom::PopoverAttributeState GetPopoverAttributeState() const;
    196  void PopoverPseudoStateUpdate(bool aOpen, bool aNotify);
    197  bool PopoverOpen() const;
    198  bool CheckPopoverValidity(mozilla::dom::PopoverVisibilityState aExpectedState,
    199                            Document* aExpectedDocument, ErrorResult& aRv);
    200  already_AddRefed<mozilla::dom::ToggleEvent> CreateToggleEvent(
    201      const nsAString& aEventType, const nsAString& aOldState,
    202      const nsAString& aNewState, mozilla::Cancelable, Element* aSource);
    203  /** Returns true if the event has been cancelled. */
    204  MOZ_CAN_RUN_SCRIPT bool FireToggleEvent(const nsAString& aOldState,
    205                                          const nsAString& aNewState,
    206                                          const nsAString& aType,
    207                                          Element* aSource);
    208  MOZ_CAN_RUN_SCRIPT void QueuePopoverEventTask(
    209      mozilla::dom::PopoverVisibilityState aOldState, Element* aSource);
    210  MOZ_CAN_RUN_SCRIPT void RunPopoverToggleEventTask(
    211      mozilla::dom::PopoverToggleEventTask* aTask,
    212      mozilla::dom::PopoverVisibilityState aOldState,
    213      mozilla::dom::Element* aSource);
    214  MOZ_CAN_RUN_SCRIPT void ShowPopover(
    215      const mozilla::dom::ShowPopoverOptions& aOptions, ErrorResult& aRv);
    216  MOZ_CAN_RUN_SCRIPT void ShowPopoverInternal(Element* aInvoker,
    217                                              ErrorResult& aRv);
    218  MOZ_CAN_RUN_SCRIPT_BOUNDARY void HidePopoverWithoutRunningScript();
    219  MOZ_CAN_RUN_SCRIPT void HidePopoverInternal(bool aFocusPreviousElement,
    220                                              bool aFireEvents,
    221                                              mozilla::dom::Element* aSource,
    222                                              ErrorResult& aRv);
    223  MOZ_CAN_RUN_SCRIPT void HidePopover(ErrorResult& aRv);
    224  MOZ_CAN_RUN_SCRIPT bool TogglePopover(
    225      const mozilla::dom::TogglePopoverOptionsOrBoolean& aOptions,
    226      ErrorResult& aRv);
    227  MOZ_CAN_RUN_SCRIPT void FocusPopover();
    228  void ForgetPreviouslyFocusedElementAfterHidingPopover();
    229  MOZ_CAN_RUN_SCRIPT void FocusPreviousElementAfterHidingPopover();
    230 
    231  bool IsValidCommandAction(Command aCommand) const override;
    232 
    233  MOZ_CAN_RUN_SCRIPT bool HandleCommandInternal(Element* aSource,
    234                                                Command aCommand,
    235                                                ErrorResult& aRv) override;
    236 
    237  MOZ_CAN_RUN_SCRIPT void FocusCandidate(Element*, bool aClearUpFocus);
    238 
    239  void SetNonce(const nsAString& aNonce) {
    240    SetProperty(nsGkAtoms::nonce, new nsString(aNonce),
    241                nsINode::DeleteProperty<nsString>, /* aTransfer = */ true);
    242  }
    243  void RemoveNonce() { RemoveProperty(nsGkAtoms::nonce); }
    244  void GetNonce(nsAString& aNonce) const {
    245    nsString* cspNonce = static_cast<nsString*>(GetProperty(nsGkAtoms::nonce));
    246    if (cspNonce) {
    247      aNonce = *cspNonce;
    248    }
    249  }
    250 
    251  /** Returns whether a form control should be default-focusable. */
    252  bool IsFormControlDefaultFocusable(mozilla::IsFocusableFlags) const;
    253 
    254  /**
    255   * Returns the count of descendants (inclusive of this node) in
    256   * the uncomposed document that are explicitly set as editable.
    257   */
    258  uint32_t EditableInclusiveDescendantCount();
    259 
    260  bool Spellcheck();
    261  void SetSpellcheck(bool aSpellcheck, mozilla::ErrorResult& aError) {
    262    SetHTMLAttr(nsGkAtoms::spellcheck, aSpellcheck ? u"true"_ns : u"false"_ns,
    263                aError);
    264  }
    265 
    266  MOZ_CAN_RUN_SCRIPT
    267  void GetInnerText(mozilla::dom::DOMString& aValue, ErrorResult& aError);
    268  MOZ_CAN_RUN_SCRIPT
    269  void GetOuterText(mozilla::dom::DOMString& aValue, ErrorResult& aError) {
    270    return GetInnerText(aValue, aError);
    271  }
    272  MOZ_CAN_RUN_SCRIPT void SetInnerText(const nsAString& aValue) {
    273    SetInnerTextInternal(aValue, MutationEffectOnScript::DropTrustWorthiness);
    274  }
    275  MOZ_CAN_RUN_SCRIPT void SetInnerTextInternal(
    276      const nsAString& aValue, MutationEffectOnScript aMutationEffectOnScript);
    277  MOZ_CAN_RUN_SCRIPT void SetOuterText(const nsAString& aValue,
    278                                       ErrorResult& aRv);
    279 
    280  void GetInputMode(nsAString& aValue) {
    281    GetEnumAttr(nsGkAtoms::inputmode, nullptr, aValue);
    282  }
    283  void SetInputMode(const nsAString& aValue, ErrorResult& aRv) {
    284    SetHTMLAttr(nsGkAtoms::inputmode, aValue, aRv);
    285  }
    286  virtual void GetAutocapitalize(nsAString& aValue) const;
    287  void SetAutocapitalize(const nsAString& aValue, ErrorResult& aRv) {
    288    SetHTMLAttr(nsGkAtoms::autocapitalize, aValue, aRv);
    289  }
    290 
    291  void GetEnterKeyHint(nsAString& aValue) const {
    292    GetEnumAttr(nsGkAtoms::enterkeyhint, nullptr, aValue);
    293  }
    294  void SetEnterKeyHint(const nsAString& aValue, ErrorResult& aRv) {
    295    SetHTMLAttr(nsGkAtoms::enterkeyhint, aValue, aRv);
    296  }
    297 
    298  virtual bool Autocorrect() const;
    299  void SetAutocorrect(bool aAutocorrect, mozilla::ErrorResult& aError) {
    300    SetHTMLAttr(nsGkAtoms::autocorrect, aAutocorrect ? u"on"_ns : u"off"_ns,
    301                aError);
    302  }
    303 
    304  /**
    305   * Determine whether an attribute is an event (onclick, etc.)
    306   * @param aName the attribute
    307   * @return whether the name is an event handler name
    308   */
    309  bool IsEventAttributeNameInternal(nsAtom* aName) override;
    310 
    311 #define EVENT(name_, id_, type_, struct_) /* nothing; handled by nsINode */
    312 // The using nsINode::Get/SetOn* are to avoid warnings about shadowing the XPCOM
    313 // getter and setter on nsINode.
    314 #define FORWARDED_EVENT(name_, id_, type_, struct_)  \
    315  using nsINode::GetOn##name_;                       \
    316  using nsINode::SetOn##name_;                       \
    317  mozilla::dom::EventHandlerNonNull* GetOn##name_(); \
    318  void SetOn##name_(mozilla::dom::EventHandlerNonNull* handler);
    319 #define ERROR_EVENT(name_, id_, type_, struct_)                       \
    320  using nsINode::GetOn##name_;                                        \
    321  using nsINode::SetOn##name_;                                        \
    322  already_AddRefed<mozilla::dom::EventHandlerNonNull> GetOn##name_(); \
    323  void SetOn##name_(mozilla::dom::EventHandlerNonNull* handler);
    324 #include "mozilla/EventNameList.h"  // IWYU pragma: keep
    325 #undef ERROR_EVENT
    326 #undef FORWARDED_EVENT
    327 #undef EVENT
    328  // These methods are already implemented in nsIContent but we want something
    329  // faster for HTMLElements ignoring the namespace checking.
    330  // This is safe because we already know that we are in the HTML namespace.
    331  inline bool IsHTMLElement() const { return true; }
    332 
    333  inline bool IsHTMLElement(nsAtom* aTag) const {
    334    return mNodeInfo->Equals(aTag);
    335  }
    336 
    337  template <typename First, typename... Args>
    338  inline bool IsAnyOfHTMLElements(First aFirst, Args... aArgs) const {
    339    return IsNodeInternal(aFirst, aArgs...);
    340  }
    341 
    342  // https://html.spec.whatwg.org/multipage/custom-elements.html#dom-attachinternals
    343  virtual already_AddRefed<mozilla::dom::ElementInternals> AttachInternals(
    344      ErrorResult& aRv);
    345 
    346  mozilla::dom::ElementInternals* GetInternals() const;
    347 
    348  bool IsFormAssociatedCustomElement() const;
    349 
    350  // Returns true if the event should not be handled from GetEventTargetParent.
    351  virtual bool IsDisabledForEvents(mozilla::WidgetEvent* aEvent) {
    352    return false;
    353  }
    354 
    355  bool Autofocus() const { return GetBoolAttr(nsGkAtoms::autofocus); }
    356  void SetAutofocus(bool aVal, ErrorResult& aRv) {
    357    SetHTMLBoolAttr(nsGkAtoms::autofocus, aVal, aRv);
    358  }
    359 
    360 protected:
    361  virtual ~nsGenericHTMLElement() = default;
    362 
    363 public:
    364  // Implementation for nsIContent
    365  nsresult BindToTree(BindContext&, nsINode& aParent) override;
    366  void UnbindFromTree(UnbindContext&) override;
    367 
    368  Focusable IsFocusableWithoutStyle(mozilla::IsFocusableFlags aFlags =
    369                                        mozilla::IsFocusableFlags(0)) override {
    370    Focusable result;
    371    IsHTMLFocusable(aFlags, &result.mFocusable, &result.mTabIndex);
    372    return result;
    373  }
    374  /**
    375   * Returns true if a subclass is not allowed to override the value returned
    376   * in aIsFocusable.
    377   */
    378  virtual bool IsHTMLFocusable(mozilla::IsFocusableFlags, bool* aIsFocusable,
    379                               int32_t* aTabIndex);
    380  MOZ_CAN_RUN_SCRIPT
    381  mozilla::Result<bool, nsresult> PerformAccesskey(
    382      bool aKeyCausesActivation, bool aIsTrustedEvent) override;
    383 
    384  /**
    385   * Check if an event for an anchor can be handled
    386   * @return true if the event can be handled, false otherwise
    387   */
    388  bool CheckHandleEventForAnchorsPreconditions(
    389      mozilla::EventChainVisitor& aVisitor);
    390  void GetEventTargetParentForAnchors(mozilla::EventChainPreVisitor& aVisitor);
    391  MOZ_CAN_RUN_SCRIPT
    392  nsresult PostHandleEventForAnchors(mozilla::EventChainPostVisitor& aVisitor);
    393  bool IsHTMLLink(nsIURI** aURI) const;
    394 
    395  // HTML element methods
    396  void Compact() { mAttrs.Compact(); }
    397 
    398  void UpdateEditableState(bool aNotify) override;
    399 
    400  bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
    401                      const nsAString& aValue,
    402                      nsIPrincipal* aMaybeScriptedPrincipal,
    403                      nsAttrValue& aResult) override;
    404 
    405  bool ParseBackgroundAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
    406                                const nsAString& aValue, nsAttrValue& aResult);
    407 
    408  NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
    409  nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
    410 
    411  /**
    412   * Get the base target for any links within this piece
    413   * of content. Generally, this is the document's base target,
    414   * but certain content carries a local base for backward
    415   * compatibility.
    416   *
    417   * @param aBaseTarget the base target [OUT]
    418   */
    419  void GetBaseTarget(nsAString& aBaseTarget) const;
    420 
    421  /**
    422   * Parse an alignment attribute (top/middle/bottom/baseline)
    423   *
    424   * @param aString the string to parse
    425   * @param aResult the resulting HTMLValue
    426   * @return whether the value was parsed
    427   */
    428  static bool ParseAlignValue(const nsAString& aString, nsAttrValue& aResult);
    429 
    430  /**
    431   * Parse a div align string to value (left/right/center/middle/justify)
    432   *
    433   * @param aString the string to parse
    434   * @param aResult the resulting HTMLValue
    435   * @return whether the value was parsed
    436   */
    437  static bool ParseDivAlignValue(const nsAString& aString,
    438                                 nsAttrValue& aResult);
    439 
    440  /**
    441   * Convert a table halign string to value (left/right/center/char/justify)
    442   *
    443   * @param aString the string to parse
    444   * @param aResult the resulting HTMLValue
    445   * @return whether the value was parsed
    446   */
    447  static bool ParseTableHAlignValue(const nsAString& aString,
    448                                    nsAttrValue& aResult);
    449 
    450  /**
    451   * Convert a table cell halign string to value
    452   *
    453   * @param aString the string to parse
    454   * @param aResult the resulting HTMLValue
    455   * @return whether the value was parsed
    456   */
    457  static bool ParseTableCellHAlignValue(const nsAString& aString,
    458                                        nsAttrValue& aResult);
    459 
    460  /**
    461   * Convert a table valign string to value (left/right/center/char/justify/
    462   * abscenter/absmiddle/middle)
    463   *
    464   * @param aString the string to parse
    465   * @param aResult the resulting HTMLValue
    466   * @return whether the value was parsed
    467   */
    468  static bool ParseTableVAlignValue(const nsAString& aString,
    469                                    nsAttrValue& aResult);
    470 
    471  /**
    472   * Convert an image attribute to value (width, height, hspace, vspace, border)
    473   *
    474   * @param aAttribute the attribute to parse
    475   * @param aString the string to parse
    476   * @param aResult the resulting HTMLValue
    477   * @return whether the value was parsed
    478   */
    479  static bool ParseImageAttribute(nsAtom* aAttribute, const nsAString& aString,
    480                                  nsAttrValue& aResult);
    481 
    482  static bool ParseReferrerAttribute(const nsAString& aString,
    483                                     nsAttrValue& aResult);
    484 
    485  /**
    486   * Convert a frameborder string to value (yes/no/1/0)
    487   *
    488   * @param aString the string to parse
    489   * @param aResult the resulting HTMLValue
    490   * @return whether the value was parsed
    491   */
    492  static bool ParseFrameborderValue(const nsAString& aString,
    493                                    nsAttrValue& aResult);
    494 
    495  /**
    496   * Convert a scrolling string to value (yes/no/on/off/scroll/noscroll/auto)
    497   *
    498   * @param aString the string to parse
    499   * @param aResult the resulting HTMLValue
    500   * @return whether the value was parsed
    501   */
    502  static bool ParseScrollingValue(const nsAString& aString,
    503                                  nsAttrValue& aResult);
    504 
    505  /*
    506   * Attribute Mapping Helpers
    507   */
    508 
    509  /**
    510   * A style attribute mapping function for the most common attributes, to be
    511   * called by subclasses' attribute mapping functions.  Currently handles
    512   * dir, lang and hidden, could handle others.
    513   *
    514   * @param aAttributes the list of attributes to map
    515   * @param aData the returned rule data [INOUT]
    516   * @see GetAttributeMappingFunction
    517   */
    518  static void MapCommonAttributesInto(mozilla::MappedDeclarationsBuilder&);
    519  /**
    520   * Same as MapCommonAttributesInto except that it does not handle hidden.
    521   * @see GetAttributeMappingFunction
    522   */
    523  static void MapCommonAttributesIntoExceptHidden(
    524      mozilla::MappedDeclarationsBuilder&);
    525 
    526  static const MappedAttributeEntry sCommonAttributeMap[];
    527  static const MappedAttributeEntry sImageMarginSizeAttributeMap[];
    528  static const MappedAttributeEntry sImageBorderAttributeMap[];
    529  static const MappedAttributeEntry sImageAlignAttributeMap[];
    530  static const MappedAttributeEntry sDivAlignAttributeMap[];
    531  static const MappedAttributeEntry sBackgroundAttributeMap[];
    532  static const MappedAttributeEntry sBackgroundColorAttributeMap[];
    533 
    534  /**
    535   * Helper to map the align attribute.
    536   * @see GetAttributeMappingFunction
    537   */
    538  static void MapImageAlignAttributeInto(mozilla::MappedDeclarationsBuilder&);
    539 
    540  /**
    541   * Helper to map the align attribute for things like <div>, <h1>, etc.
    542   * @see GetAttributeMappingFunction
    543   */
    544  static void MapDivAlignAttributeInto(mozilla::MappedDeclarationsBuilder&);
    545 
    546  /**
    547   * Helper to map the valign attribute for various table elements.
    548   * @see GetAttributeMappingFunction
    549   */
    550  static void MapTableVAlignAttributeInto(mozilla::MappedDeclarationsBuilder&);
    551 
    552  /**
    553   * Helper to map the align attribute for <table>.
    554   * @see GetAttributeMappingFunction
    555   */
    556  static void MapTableHAlignAttributeInto(mozilla::MappedDeclarationsBuilder&);
    557 
    558  /**
    559   * Helper to map the align attribute for various table elements.
    560   * @see GetAttributeMappingFunction
    561   */
    562  static void MapTableCellHAlignAttributeInto(
    563      mozilla::MappedDeclarationsBuilder&);
    564 
    565  /**
    566   * Helper to map the image border attribute.
    567   * @see GetAttributeMappingFunction
    568   */
    569  static void MapImageBorderAttributeInto(mozilla::MappedDeclarationsBuilder&);
    570  /**
    571   * Helper to map the image margin attribute into a style struct.
    572   *
    573   * @param aAttributes the list of attributes to map
    574   * @param aData the returned rule data [INOUT]
    575   * @see GetAttributeMappingFunction
    576   */
    577  static void MapImageMarginAttributeInto(mozilla::MappedDeclarationsBuilder&);
    578 
    579  /**
    580   * Helper to map a given dimension (width/height) into the declaration
    581   * block, handling percentages and numbers.
    582   */
    583  static void MapDimensionAttributeInto(mozilla::MappedDeclarationsBuilder&,
    584                                        NonCustomCSSPropertyId,
    585                                        const nsAttrValue&);
    586 
    587  /**
    588   * Maps the aspect ratio given width and height attributes.
    589   */
    590  static void DoMapAspectRatio(const nsAttrValue& aWidth,
    591                               const nsAttrValue& aHeight,
    592                               mozilla::MappedDeclarationsBuilder&);
    593 
    594  // Whether to map the width and height attributes to aspect-ratio.
    595  enum class MapAspectRatio { No, Yes };
    596 
    597  /**
    598   * Helper to map the image position attribute into a style struct.
    599   */
    600  static void MapImageSizeAttributesInto(mozilla::MappedDeclarationsBuilder&,
    601                                         MapAspectRatio = MapAspectRatio::No);
    602 
    603  /**
    604   * Helper to map the width and height attributes into the aspect-ratio
    605   * property.
    606   *
    607   * If you also map the width/height attributes to width/height (as you should
    608   * for any HTML element that isn't <canvas>) then you should use
    609   * MapImageSizeAttributesInto instead, passing MapAspectRatio::Yes instead, as
    610   * that'd be faster.
    611   */
    612  static void MapAspectRatioInto(mozilla::MappedDeclarationsBuilder&);
    613 
    614  /**
    615   * Helper to map `width` attribute into a style struct.
    616   *
    617   * @param aAttributes the list of attributes to map
    618   * @param aData the returned rule data [INOUT]
    619   * @see GetAttributeMappingFunction
    620   */
    621  static void MapWidthAttributeInto(mozilla::MappedDeclarationsBuilder&);
    622 
    623  /**
    624   * Helper to map `height` attribute.
    625   * @see GetAttributeMappingFunction
    626   */
    627  static void MapHeightAttributeInto(mozilla::MappedDeclarationsBuilder&);
    628  /**
    629   * Helper to map the background attribute
    630   * @see GetAttributeMappingFunction
    631   */
    632  static void MapBackgroundInto(mozilla::MappedDeclarationsBuilder&);
    633  /**
    634   * Helper to map the bgcolor attribute
    635   * @see GetAttributeMappingFunction
    636   */
    637  static void MapBGColorInto(mozilla::MappedDeclarationsBuilder&);
    638  /**
    639   * Helper to map the background attributes (currently background and bgcolor)
    640   * @see GetAttributeMappingFunction
    641   */
    642  static void MapBackgroundAttributesInto(mozilla::MappedDeclarationsBuilder&);
    643  /**
    644   * Helper to map the scrolling attribute on FRAME and IFRAME.
    645   * @see GetAttributeMappingFunction
    646   */
    647  static void MapScrollingAttributeInto(mozilla::MappedDeclarationsBuilder&);
    648 
    649  // Form Helper Routines
    650  /**
    651   * Find an ancestor of this content node which is a form (could be null)
    652   * @param aCurrentForm the current form for this node.  If this is
    653   *        non-null, and no ancestor form is found, and the current form is in
    654   *        a connected subtree with the node, the current form will be
    655   *        returned.  This is needed to handle cases when HTML elements have a
    656   *        current form that they're not descendants of.
    657   * @note This method should not be called if the element has a form attribute.
    658   */
    659  mozilla::dom::HTMLFormElement* FindAncestorForm(
    660      mozilla::dom::HTMLFormElement* aCurrentForm = nullptr);
    661 
    662  /**
    663   * See if the document being tested has nav-quirks mode enabled.
    664   * @param doc the document
    665   */
    666  static bool InNavQuirksMode(Document*);
    667 
    668  /**
    669   * Gets the absolute URI value of an attribute, by resolving any relative
    670   * URIs in the attribute against the baseuri of the element. If the attribute
    671   * isn't a relative URI the value of the attribute is returned as is. Only
    672   * works for attributes in null namespace.
    673   *
    674   * @param aAttr      name of attribute.
    675   * @param aBaseAttr  name of base attribute.
    676   * @param aResult    result value [out]
    677   */
    678  void GetURIAttr(nsAtom* aAttr, nsAtom* aBaseAttr, nsAString& aResult) const;
    679  void GetURIAttr(nsAtom* aAttr, nsAtom* aBaseAttr, nsACString& aResult) const;
    680 
    681  /**
    682   * Gets the absolute URI values of an attribute, by resolving any relative
    683   * URIs in the attribute against the baseuri of the element. If a substring
    684   * isn't a relative URI, the substring is returned as is. Only works for
    685   * attributes in null namespace.
    686   */
    687  const nsAttrValue* GetURIAttr(nsAtom* aAttr, nsAtom* aBaseAttr,
    688                                nsIURI** aURI) const;
    689 
    690  bool IsHidden() const { return HasAttr(nsGkAtoms::hidden); }
    691 
    692  bool IsLabelable() const override;
    693 
    694  static bool MatchLabelsElement(Element* aElement, int32_t aNamespaceID,
    695                                 nsAtom* aAtom, void* aData);
    696 
    697  already_AddRefed<nsINodeList> Labels();
    698 
    699  static bool LegacyTouchAPIEnabled(JSContext* aCx, JSObject* aObj);
    700 
    701  // https://html.spec.whatwg.org/#dom-window-nameditem-filter
    702  static inline bool CanHaveName(nsAtom* aTag) {
    703    return aTag == nsGkAtoms::img || aTag == nsGkAtoms::form ||
    704           aTag == nsGkAtoms::embed || aTag == nsGkAtoms::object;
    705  }
    706  static inline bool ShouldExposeNameAsWindowProperty(Element* aElement) {
    707    return aElement->IsHTMLElement() &&
    708           CanHaveName(aElement->NodeInfo()->NameAtom());
    709  }
    710  // https://html.spec.whatwg.org/#dom-document-nameditem-filter
    711  static inline bool ShouldExposeIdAsHTMLDocumentProperty(Element* aElement) {
    712    if (!aElement->HasID() || aElement->IsInNativeAnonymousSubtree()) {
    713      return false;
    714    }
    715    // XXX Not all objects is exposed per spec, but other browsers doesn't check
    716    // if object is exposed, either.
    717    if (aElement->IsHTMLElement(nsGkAtoms::object)) {
    718      return true;
    719    }
    720 
    721    // Per spec, <img> is exposed by id only if it also has a nonempty
    722    // name (which doesn't have to match the id or anything).
    723    // HasName() is true precisely when name is nonempty.
    724    return aElement->IsHTMLElement(nsGkAtoms::img) && aElement->HasName();
    725  }
    726  static inline bool ShouldExposeNameAsHTMLDocumentProperty(Element* aElement) {
    727    if (!aElement->HasName() || aElement->IsInNativeAnonymousSubtree()) {
    728      return false;
    729    }
    730    // XXX Not all embeds/objects are exposed per spec, but other browser
    731    // doesn't check if embeds/objects are exposed.
    732    return aElement->IsAnyOfHTMLElements(nsGkAtoms::embed, nsGkAtoms::form,
    733                                         nsGkAtoms::iframe, nsGkAtoms::img,
    734                                         nsGkAtoms::object);
    735  }
    736 
    737  virtual inline void ResultForDialogSubmit(nsAString& aResult) {
    738    GetAttr(nsGkAtoms::value, aResult);
    739  }
    740 
    741  // <https://html.spec.whatwg.org/#fetch-priority-attribute>.
    742  static mozilla::dom::FetchPriority ToFetchPriority(const nsAString& aValue);
    743 
    744  void GetFetchPriority(nsAString& aFetchPriority) const;
    745 
    746  void SetFetchPriority(const nsAString& aFetchPriority) {
    747    SetHTMLAttr(nsGkAtoms::fetchpriority, aFetchPriority);
    748  }
    749 
    750 private:
    751  /**
    752   * Add/remove this element to the documents name cache
    753   */
    754  void AddToNameTable(nsAtom* aName);
    755  void RemoveFromNameTable();
    756 
    757  /**
    758   * Register or unregister an access key to this element based on the
    759   * accesskey attribute.
    760   */
    761  void RegUnRegAccessKey(bool aDoReg) override {
    762    if (!HasFlag(NODE_HAS_ACCESSKEY)) {
    763      return;
    764    }
    765 
    766    nsStyledElement::RegUnRegAccessKey(aDoReg);
    767  }
    768 
    769 protected:
    770  void BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
    771                     const nsAttrValue* aValue, bool aNotify) override;
    772  // TODO: Convert AfterSetAttr to MOZ_CAN_RUN_SCRIPT and get rid of
    773  // kungFuDeathGrip in it.
    774  MOZ_CAN_RUN_SCRIPT_BOUNDARY void AfterSetAttr(
    775      int32_t aNamespaceID, nsAtom* aName, const nsAttrValue* aValue,
    776      const nsAttrValue* aOldValue, nsIPrincipal* aMaybeScriptedPrincipal,
    777      bool aNotify) override;
    778 
    779  void OnAttrSetButNotChanged(int32_t aNamespaceID, nsAtom* aName,
    780                              const nsAttrValueOrString& aValue,
    781                              bool aNotify) override;
    782 
    783  MOZ_CAN_RUN_SCRIPT void AfterSetPopoverAttr();
    784 
    785  mozilla::EventListenerManager* GetEventListenerManagerForAttr(
    786      nsAtom* aAttrName, bool* aDefer) override;
    787 
    788  /**
    789   * Handles dispatching a simulated click on `this` on space or enter.
    790   * TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
    791   */
    792  MOZ_CAN_RUN_SCRIPT_BOUNDARY void HandleKeyboardActivation(
    793      mozilla::EventChainPostVisitor&);
    794 
    795  /** Dispatch a simulated mouse click by keyboard to the given element. */
    796  MOZ_CAN_RUN_SCRIPT static nsresult DispatchSimulatedClick(
    797      nsGenericHTMLElement* aElement, bool aIsTrusted,
    798      nsPresContext* aPresContext);
    799 
    800  /**
    801   * Create a URI for the given aURISpec string.
    802   * Returns INVALID_STATE_ERR and nulls *aURI if aURISpec is empty
    803   * and the document's URI matches the element's base URI.
    804   */
    805  nsresult NewURIFromString(const nsAString& aURISpec, nsIURI** aURI);
    806 
    807  void GetHTMLAttr(nsAtom* aName, nsAString& aResult) const {
    808    GetAttr(aName, aResult);
    809  }
    810  void GetHTMLAttr(nsAtom* aName, mozilla::dom::DOMString& aResult) const {
    811    GetAttr(aName, aResult);
    812  }
    813  void GetHTMLEnumAttr(nsAtom* aName, nsAString& aResult) const {
    814    GetEnumAttr(aName, nullptr, aResult);
    815  }
    816  void GetHTMLURIAttr(nsAtom* aName, nsAString& aResult) const {
    817    GetURIAttr(aName, nullptr, aResult);
    818  }
    819  void GetHTMLURIAttr(nsAtom* aName, nsACString& aResult) const {
    820    GetURIAttr(aName, nullptr, aResult);
    821  }
    822 
    823  void SetHTMLAttr(nsAtom* aName, const nsAString& aValue) {
    824    SetAttr(kNameSpaceID_None, aName, aValue, true);
    825  }
    826  void SetHTMLAttr(nsAtom* aName, const nsAString& aValue,
    827                   mozilla::ErrorResult& aError) {
    828    SetAttr(aName, aValue, aError);
    829  }
    830  void SetHTMLAttr(nsAtom* aName, const nsAString& aValue,
    831                   nsIPrincipal* aTriggeringPrincipal,
    832                   mozilla::ErrorResult& aError) {
    833    SetAttr(aName, aValue, aTriggeringPrincipal, aError);
    834  }
    835  void UnsetHTMLAttr(nsAtom* aName, mozilla::ErrorResult& aError) {
    836    UnsetAttr(aName, aError);
    837  }
    838  void SetHTMLBoolAttr(nsAtom* aName, bool aValue,
    839                       mozilla::ErrorResult& aError) {
    840    if (aValue) {
    841      SetHTMLAttr(aName, u""_ns, aError);
    842    } else {
    843      UnsetHTMLAttr(aName, aError);
    844    }
    845  }
    846  template <typename T>
    847  void SetHTMLIntAttr(nsAtom* aName, T aValue, mozilla::ErrorResult& aError) {
    848    nsAutoString value;
    849    value.AppendInt(aValue);
    850 
    851    SetHTMLAttr(aName, value, aError);
    852  }
    853 
    854  /**
    855   * Gets the integer-value of an attribute, returns specified default value
    856   * if the attribute isn't set or isn't set to an integer. Only works for
    857   * attributes in null namespace.
    858   *
    859   * @param aAttr    name of attribute.
    860   * @param aDefault default-value to return if attribute isn't set.
    861   */
    862  int32_t GetIntAttr(nsAtom* aAttr, int32_t aDefault) const;
    863 
    864  /**
    865   * Sets value of attribute to specified integer. Only works for attributes
    866   * in null namespace.
    867   *
    868   * @param aAttr    name of attribute.
    869   * @param aValue   Integer value of attribute.
    870   */
    871  nsresult SetIntAttr(nsAtom* aAttr, int32_t aValue);
    872 
    873  /**
    874   * Gets the unsigned integer-value of an attribute, returns specified default
    875   * value if the attribute isn't set or isn't set to an integer. Only works for
    876   * attributes in null namespace.
    877   *
    878   * @param aAttr    name of attribute.
    879   * @param aDefault default-value to return if attribute isn't set.
    880   */
    881  uint32_t GetUnsignedIntAttr(nsAtom* aAttr, uint32_t aDefault) const;
    882 
    883  /**
    884   * Sets value of attribute to specified unsigned integer. Only works for
    885   * attributes in null namespace.
    886   *
    887   * @param aAttr    name of attribute.
    888   * @param aValue   Integer value of attribute.
    889   * @param aDefault Default value (in case value is out of range).  If the spec
    890   *                 doesn't provide one, should be 1 if the value is limited to
    891   *                 nonzero values, and 0 otherwise.
    892   */
    893  void SetUnsignedIntAttr(nsAtom* aName, uint32_t aValue, uint32_t aDefault,
    894                          mozilla::ErrorResult& aError) {
    895    nsAutoString value;
    896    if (aValue > INT32_MAX) {
    897      value.AppendInt(aDefault);
    898    } else {
    899      value.AppendInt(aValue);
    900    }
    901 
    902    SetHTMLAttr(aName, value, aError);
    903  }
    904 
    905  /**
    906   * Gets the unsigned integer-value of an attribute that is stored as a
    907   * dimension (i.e. could be an integer or a percentage), returns specified
    908   * default value if the attribute isn't set or isn't set to a dimension. Only
    909   * works for attributes in null namespace.
    910   *
    911   * @param aAttr    name of attribute.
    912   * @param aDefault default-value to return if attribute isn't set.
    913   */
    914  uint32_t GetDimensionAttrAsUnsignedInt(nsAtom* aAttr,
    915                                         uint32_t aDefault) const;
    916 
    917  enum class Reflection {
    918    Unlimited,
    919    OnlyPositive,
    920  };
    921 
    922  /**
    923   * Sets value of attribute to specified double. Only works for attributes
    924   * in null namespace.
    925   *
    926   * Implements
    927   * https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes:idl-double
    928   *
    929   * @param aAttr    name of attribute.
    930   * @param aValue   Double value of attribute.
    931   */
    932  template <Reflection Limited = Reflection::Unlimited>
    933  void SetDoubleAttr(nsAtom* aAttr, double aValue, mozilla::ErrorResult& aRv) {
    934    // 1. If the reflected IDL attribute is limited to only positive numbers and
    935    //    the given value is not greater than 0, then return.
    936    if (Limited == Reflection::OnlyPositive && aValue <= 0) {
    937      return;
    938    }
    939 
    940    // 2. Run this's set the content attribute with the given value, converted
    941    //    to the best representation of the number as a floating-point number.
    942    nsAutoString value;
    943    value.AppendFloat(aValue);
    944 
    945    SetHTMLAttr(aAttr, value, aRv);
    946  }
    947 
    948  /**
    949   * Locates the EditorBase associated with this node.  In general this is
    950   * equivalent to GetEditorInternal(), but for designmode or contenteditable,
    951   * this may need to get an editor that's not actually on this element's
    952   * associated TextControlFrame.  This is used by the spellchecking routines
    953   * to get the editor affected by changing the spellcheck attribute on this
    954   * node.
    955   */
    956  virtual already_AddRefed<mozilla::EditorBase> GetAssociatedEditor();
    957 
    958  /**
    959   * Ensures all editors associated with a subtree are synced, for purposes of
    960   * spellchecking.
    961   */
    962  static void SyncEditorsOnSubtree(nsIContent* content);
    963 
    964  [[nodiscard]] inline static bool IsEditableState(
    965      ContentEditableState aState) {
    966    return aState == ContentEditableState::True ||
    967           aState == ContentEditableState::PlainTextOnly;
    968  }
    969 
    970  // Used by A, AREA, LINK, and STYLE.
    971  already_AddRefed<nsIURI> GetHrefURIForAnchors() const;
    972 
    973 private:
    974  MOZ_CAN_RUN_SCRIPT void ChangeEditableState(int32_t aChange);
    975 };
    976 
    977 namespace mozilla::dom {
    978 class HTMLFieldSetElement;
    979 }  // namespace mozilla::dom
    980 
    981 #define HTML_ELEMENT_FLAG_BIT(n_) \
    982  NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
    983 
    984 // HTMLElement specific bits
    985 enum {
    986  // Used to handle keyboard activation.
    987  HTML_ELEMENT_ACTIVE_FOR_KEYBOARD = HTML_ELEMENT_FLAG_BIT(0),
    988  // Similar to HTMLInputElement's mInhibitRestoration, used to prevent
    989  // form-associated custom elements not created by a network parser from
    990  // being restored.
    991  HTML_ELEMENT_INHIBIT_RESTORATION = HTML_ELEMENT_FLAG_BIT(1),
    992 
    993  // Remaining bits are type specific.
    994  HTML_ELEMENT_TYPE_SPECIFIC_BITS_OFFSET =
    995      ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 2,
    996 };
    997 
    998 ASSERT_NODE_FLAGS_SPACE(HTML_ELEMENT_TYPE_SPECIFIC_BITS_OFFSET);
    999 
   1000 #define FORM_ELEMENT_FLAG_BIT(n_) \
   1001  NODE_FLAG_BIT(HTML_ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
   1002 
   1003 // Form element specific bits
   1004 enum {
   1005  // If this flag is set on an nsGenericHTMLFormElement or an HTMLImageElement,
   1006  // that means that we have added ourselves to our mForm.  It's possible to
   1007  // have a non-null mForm, but not have this flag set.  That happens when the
   1008  // form is set via the content sink.
   1009  ADDED_TO_FORM = FORM_ELEMENT_FLAG_BIT(0),
   1010 
   1011  // If this flag is set on an nsGenericHTMLFormElement or an HTMLImageElement,
   1012  // that means that its form is in the process of being unbound from the tree,
   1013  // and this form element hasn't re-found its form in
   1014  // nsGenericHTMLFormElement::UnbindFromTree yet.
   1015  MAYBE_ORPHAN_FORM_ELEMENT = FORM_ELEMENT_FLAG_BIT(1),
   1016 
   1017  // If this flag is set on an nsGenericHTMLElement or an HTMLImageElement, then
   1018  // the element might be in the past names map of its form.
   1019  MAY_BE_IN_PAST_NAMES_MAP = FORM_ELEMENT_FLAG_BIT(2)
   1020 };
   1021 
   1022 // NOTE: I don't think it's possible to have both ADDED_TO_FORM and
   1023 // MAYBE_ORPHAN_FORM_ELEMENT set at the same time, so if it becomes an issue we
   1024 // can probably merge them into the same bit.  --bz
   1025 
   1026 ASSERT_NODE_FLAGS_SPACE(HTML_ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 3);
   1027 
   1028 #undef FORM_ELEMENT_FLAG_BIT
   1029 
   1030 /**
   1031 * A helper class for form elements that can contain children
   1032 */
   1033 class nsGenericHTMLFormElement : public nsGenericHTMLElement {
   1034 public:
   1035  nsGenericHTMLFormElement(
   1036      already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
   1037 
   1038  // nsIContent
   1039  void SaveSubtreeState() override;
   1040  nsresult BindToTree(BindContext&, nsINode& aParent) override;
   1041  void UnbindFromTree(UnbindContext&) override;
   1042 
   1043  /**
   1044   * This callback is called by a fieldest on all its elements whenever its
   1045   * disabled attribute is changed so the element knows its disabled state
   1046   * might have changed.
   1047   *
   1048   * @note Classes redefining this method should not do any content
   1049   * state updates themselves but should just make sure to call into
   1050   * nsGenericHTMLFormElement::FieldSetDisabledChanged.
   1051   */
   1052  virtual void FieldSetDisabledChanged(bool aNotify);
   1053 
   1054  void FieldSetFirstLegendChanged(bool aNotify) { UpdateFieldSet(aNotify); }
   1055 
   1056  /**
   1057   * This callback is called by a fieldset on all it's elements when it's being
   1058   * destroyed. When called, the elements should check that aFieldset is there
   1059   * first parent fieldset and null mFieldset in that case only.
   1060   *
   1061   * @param aFieldSet The fieldset being removed.
   1062   */
   1063  void ForgetFieldSet(nsIContent* aFieldset);
   1064 
   1065  void ClearForm(bool aRemoveFromForm, bool aUnbindOrDelete);
   1066 
   1067  /**
   1068   * Get the layout history object for a particular piece of content.
   1069   *
   1070   * @param aRead if true, won't return a layout history state if the
   1071   *              layout history state is empty.
   1072   * @return the history state object
   1073   */
   1074  already_AddRefed<nsILayoutHistoryState> GetLayoutHistory(bool aRead);
   1075 
   1076  // Sets the user-interacted flag in
   1077  // https://html.spec.whatwg.org/#user-interacted, if it applies.
   1078  virtual void SetUserInteracted(bool aNotify) {}
   1079 
   1080 protected:
   1081  virtual ~nsGenericHTMLFormElement() = default;
   1082 
   1083  void BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
   1084                     const nsAttrValue* aValue, bool aNotify) override;
   1085 
   1086  void AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
   1087                    const nsAttrValue* aValue, const nsAttrValue* aOldValue,
   1088                    nsIPrincipal* aMaybeScriptedPrincipal,
   1089                    bool aNotify) override;
   1090 
   1091  virtual void BeforeSetForm(mozilla::dom::HTMLFormElement* aForm,
   1092                             bool aBindToTree) {}
   1093 
   1094  virtual void AfterClearForm(bool aUnbindOrDelete) {}
   1095 
   1096  /**
   1097   * Check our disabled content attribute and fieldset's (if it exists) disabled
   1098   * state to decide whether our disabled flag should be toggled.
   1099   */
   1100  virtual void UpdateDisabledState(bool aNotify);
   1101  bool IsReadOnlyInternal() const final;
   1102 
   1103  virtual void SetFormInternal(mozilla::dom::HTMLFormElement* aForm,
   1104                               bool aBindToTree) {}
   1105 
   1106  virtual mozilla::dom::HTMLFormElement* GetFormInternal() const {
   1107    return nullptr;
   1108  }
   1109 
   1110  virtual mozilla::dom::HTMLFieldSetElement* GetFieldSetInternal() const {
   1111    return nullptr;
   1112  }
   1113 
   1114  virtual void SetFieldSetInternal(
   1115      mozilla::dom::HTMLFieldSetElement* aFieldset) {}
   1116 
   1117  /**
   1118   * This method will update the form owner, using @form or looking to a parent.
   1119   *
   1120   * @param aBindToTree Whether the element is being attached to the tree.
   1121   * @param aFormIdElement The element associated with the id in @form. If
   1122   * aBindToTree is false, aFormIdElement *must* contain the element associated
   1123   * with the id in @form. Otherwise, it *must* be null.
   1124   *
   1125   * @note Callers of UpdateFormOwner have to be sure the element is in a
   1126   * document (GetUncomposedDoc() != nullptr).
   1127   */
   1128  virtual void UpdateFormOwner(bool aBindToTree, Element* aFormIdElement);
   1129 
   1130  /**
   1131   * This method will update mFieldset and set it to the first fieldset parent.
   1132   */
   1133  void UpdateFieldSet(bool aNotify);
   1134 
   1135  /**
   1136   * Add a form id observer which will observe when the element with the id in
   1137   * @form will change.
   1138   *
   1139   * @return The element associated with the current id in @form (may be null).
   1140   */
   1141  Element* AddFormIdObserver();
   1142 
   1143  /**
   1144   * Remove the form id observer.
   1145   */
   1146  void RemoveFormIdObserver();
   1147 
   1148  /**
   1149   * This method is a a callback for IDTargetObserver (from Document).
   1150   * It will be called each time the element associated with the id in @form
   1151   * changes.
   1152   */
   1153  static bool FormIdUpdated(Element* aOldElement, Element* aNewElement,
   1154                            void* aData);
   1155 
   1156  // Returns true if the event should not be handled from GetEventTargetParent
   1157  bool IsElementDisabledForEvents(mozilla::WidgetEvent* aEvent,
   1158                                  nsIFrame* aFrame);
   1159 
   1160  /**
   1161   * Returns if the control can be disabled.
   1162   */
   1163  virtual bool CanBeDisabled() const { return false; }
   1164 
   1165  /**
   1166   * Returns true if :read-write pseudo class may match the element even if the
   1167   * element isn't part of designMode or contenteditable.
   1168   */
   1169  virtual bool DoesReadWriteApply() const { return false; }
   1170 
   1171  /**
   1172   *  Returns true if the element is a form associated element.
   1173   *  See https://html.spec.whatwg.org/#form-associated-element.
   1174   */
   1175  virtual bool IsFormAssociatedElement() const { return false; }
   1176 
   1177  /**
   1178   * Save to presentation state.  The form element will determine whether it
   1179   * has anything to save and if so, create an entry in the layout history for
   1180   * its pres context.
   1181   */
   1182  virtual void SaveState() {}
   1183 };
   1184 
   1185 class nsGenericHTMLFormControlElement : public nsGenericHTMLFormElement,
   1186                                        public nsIFormControl {
   1187 public:
   1188  nsGenericHTMLFormControlElement(
   1189      already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, FormControlType);
   1190 
   1191  NS_DECL_ISUPPORTS_INHERITED
   1192 
   1193  NS_IMPL_FROMNODE_HELPER(nsGenericHTMLFormControlElement,
   1194                          IsHTMLFormControlElement())
   1195 
   1196  [[nodiscard]] nsIFormControl* GetAsFormControl() final { return this; }
   1197  [[nodiscard]] const nsIFormControl* GetAsFormControl() const final {
   1198    return this;
   1199  }
   1200 
   1201  // nsINode
   1202  nsINode* GetScopeChainParent() const override;
   1203  bool IsHTMLFormControlElement() const final { return true; }
   1204 
   1205  // nsIContent
   1206  IMEState GetDesiredIMEState() override;
   1207 
   1208  // nsGenericHTMLElement
   1209  // autocapitalize attribute support
   1210  void GetAutocapitalize(nsAString& aValue) const override;
   1211  // autocorrect attribute support
   1212  bool Autocorrect() const override;
   1213  bool IsHTMLFocusable(mozilla::IsFocusableFlags, bool* aIsFocusable,
   1214                       int32_t* aTabIndex) override;
   1215 
   1216  // nsIFormControl
   1217  mozilla::dom::HTMLFieldSetElement* GetFieldSet() override;
   1218  mozilla::dom::HTMLFormElement* GetForm() const override { return mForm; }
   1219  void SetForm(mozilla::dom::HTMLFormElement* aForm) override;
   1220  void ClearForm(bool aRemoveFromForm, bool aUnbindOrDelete) override;
   1221 
   1222 protected:
   1223  virtual ~nsGenericHTMLFormControlElement();
   1224 
   1225  // Element
   1226  bool IsLabelable() const override;
   1227 
   1228  // nsGenericHTMLFormElement
   1229  bool CanBeDisabled() const override;
   1230  bool DoesReadWriteApply() const override;
   1231  void SetFormInternal(mozilla::dom::HTMLFormElement* aForm,
   1232                       bool aBindToTree) override;
   1233  mozilla::dom::HTMLFormElement* GetFormInternal() const override;
   1234  mozilla::dom::HTMLFieldSetElement* GetFieldSetInternal() const override;
   1235  void SetFieldSetInternal(
   1236      mozilla::dom::HTMLFieldSetElement* aFieldset) override;
   1237  bool IsFormAssociatedElement() const override { return true; }
   1238 
   1239  /**
   1240   * Update our required/optional flags to match the given aIsRequired boolean.
   1241   */
   1242  void UpdateRequiredState(bool aIsRequired, bool aNotify);
   1243 
   1244  bool IsAutocapitalizeOrAutocorrectInheriting() const;
   1245 
   1246  nsresult SubmitDirnameDir(mozilla::dom::FormData* aFormData);
   1247 
   1248  void GetFormAutofillState(nsAString& aState) const;
   1249  void SetFormAutofillState(const nsAString& aState);
   1250 
   1251  /** The form that contains this control */
   1252  mozilla::dom::HTMLFormElement* mForm;
   1253 
   1254  /* This is a pointer to our closest fieldset parent if any */
   1255  mozilla::dom::HTMLFieldSetElement* mFieldSet;
   1256 };
   1257 
   1258 enum class PopoverTargetAction : uint8_t {
   1259  Toggle,
   1260  Show,
   1261  Hide,
   1262 };
   1263 
   1264 class nsGenericHTMLFormControlElementWithState
   1265    : public nsGenericHTMLFormControlElement {
   1266 public:
   1267  nsGenericHTMLFormControlElementWithState(
   1268      already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
   1269      mozilla::dom::FromParser aFromParser, FormControlType);
   1270 
   1271  bool IsGenericHTMLFormControlElementWithState() const final { return true; }
   1272  NS_IMPL_FROMNODE_HELPER(nsGenericHTMLFormControlElementWithState,
   1273                          IsGenericHTMLFormControlElementWithState())
   1274 
   1275  // Element
   1276  bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
   1277                      const nsAString& aValue,
   1278                      nsIPrincipal* aMaybeScriptedPrincipal,
   1279                      nsAttrValue& aResult) override;
   1280 
   1281  // PopoverInvokerElement
   1282  mozilla::dom::Element* GetPopoverTargetElement() const;
   1283  void SetPopoverTargetElement(mozilla::dom::Element*);
   1284  void GetPopoverTargetAction(nsAString& aValue) const {
   1285    GetHTMLEnumAttr(nsGkAtoms::popovertargetaction, aValue);
   1286  }
   1287  void SetPopoverTargetAction(const nsAString& aValue) {
   1288    SetHTMLAttr(nsGkAtoms::popovertargetaction, aValue);
   1289  }
   1290 
   1291  /**
   1292   * https://html.spec.whatwg.org/#popover-target-attribute-activation-behavior
   1293   */
   1294  MOZ_CAN_RUN_SCRIPT void HandlePopoverTargetAction(mozilla::dom::Element*);
   1295 
   1296  /**
   1297   * Get the presentation state for a piece of content, or create it if it does
   1298   * not exist.  Generally used by SaveState().
   1299   */
   1300  mozilla::PresState* GetPrimaryPresState();
   1301 
   1302  /**
   1303   * Called when we have been cloned and adopted, and the information of the
   1304   * node has been changed.
   1305   */
   1306  void NodeInfoChanged(Document* aOldDoc) override;
   1307 
   1308  void GetFormAction(nsString& aValue);
   1309 
   1310 protected:
   1311  /**
   1312   * Restore from presentation state.  You pass in the presentation state for
   1313   * this form control (generated with GenerateStateKey() + "-C") and the form
   1314   * control will grab its state from there.
   1315   *
   1316   * @param aState the pres state to use to restore the control
   1317   * @return true if the form control was a checkbox and its
   1318   *         checked state was restored, false otherwise.
   1319   */
   1320  virtual bool RestoreState(mozilla::PresState* aState) { return false; }
   1321 
   1322  /**
   1323   * Restore the state for a form control in response to the element being
   1324   * inserted into the document by the parser.  Ends up calling RestoreState().
   1325   *
   1326   * GenerateStateKey() must already have been called.
   1327   *
   1328   * @return false if RestoreState() was not called, the return
   1329   *         value of RestoreState() otherwise.
   1330   */
   1331  bool RestoreFormControlState();
   1332 
   1333  /* Generates the state key for saving the form state in the session if not
   1334     computed already. The result is stored in mStateKey. */
   1335  void GenerateStateKey();
   1336 
   1337  int32_t GetParserInsertedControlNumberForStateKey() const override {
   1338    return mControlNumber;
   1339  }
   1340 
   1341  /* Used to store the key to that element in the session. Is void until
   1342     GenerateStateKey has been used */
   1343  nsCString mStateKey;
   1344 
   1345  // A number for this form control that is unique within its owner document.
   1346  // This is only set to a number for elements inserted into the document by
   1347  // the parser from the network.  Otherwise, it is -1.
   1348  int32_t mControlNumber;
   1349 };
   1350 
   1351 #define NS_INTERFACE_MAP_ENTRY_IF_TAG(_interface, _tag) \
   1352  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(_interface,        \
   1353                                     mNodeInfo->Equals(nsGkAtoms::_tag))
   1354 
   1355 namespace mozilla::dom {
   1356 
   1357 using HTMLContentCreatorFunction =
   1358    nsGenericHTMLElement* (*)(already_AddRefed<mozilla::dom::NodeInfo>&&,
   1359                              mozilla::dom::FromParser);
   1360 
   1361 }  // namespace mozilla::dom
   1362 
   1363 /**
   1364 * A macro to declare the NS_NewHTMLXXXElement() functions.
   1365 */
   1366 #define NS_DECLARE_NS_NEW_HTML_ELEMENT(_elementName)        \
   1367  namespace mozilla {                                       \
   1368  namespace dom {                                           \
   1369  class HTML##_elementName##Element;                        \
   1370  }                                                         \
   1371  }                                                         \
   1372  nsGenericHTMLElement* NS_NewHTML##_elementName##Element(  \
   1373      already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, \
   1374      mozilla::dom::FromParser aFromParser = mozilla::dom::NOT_FROM_PARSER);
   1375 
   1376 #define NS_DECLARE_NS_NEW_HTML_ELEMENT_AS_SHARED(_elementName)                \
   1377  inline nsGenericHTMLElement* NS_NewHTML##_elementName##Element(             \
   1378      already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,                   \
   1379      mozilla::dom::FromParser aFromParser = mozilla::dom::NOT_FROM_PARSER) { \
   1380    return NS_NewHTMLSharedElement(std::move(aNodeInfo), aFromParser);        \
   1381  }
   1382 
   1383 /**
   1384 * A macro to implement the NS_NewHTMLXXXElement() functions.
   1385 */
   1386 #define NS_IMPL_NS_NEW_HTML_ELEMENT(_elementName)                     \
   1387  nsGenericHTMLElement* NS_NewHTML##_elementName##Element(            \
   1388      already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,           \
   1389      mozilla::dom::FromParser aFromParser) {                         \
   1390    RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);               \
   1391    auto* nim = nodeInfo->NodeInfoManager();                          \
   1392    MOZ_ASSERT(nim);                                                  \
   1393    return new (nim)                                                  \
   1394        mozilla::dom::HTML##_elementName##Element(nodeInfo.forget()); \
   1395  }
   1396 
   1397 #define NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(_elementName)  \
   1398  nsGenericHTMLElement* NS_NewHTML##_elementName##Element(      \
   1399      already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,     \
   1400      mozilla::dom::FromParser aFromParser) {                   \
   1401    RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);         \
   1402    auto* nim = nodeInfo->NodeInfoManager();                    \
   1403    MOZ_ASSERT(nim);                                            \
   1404    return new (nim) mozilla::dom::HTML##_elementName##Element( \
   1405        nodeInfo.forget(), aFromParser);                        \
   1406  }
   1407 
   1408 // Here, we expand 'NS_DECLARE_NS_NEW_HTML_ELEMENT()' by hand.
   1409 // (Calling the macro directly (with no args) produces compiler warnings.)
   1410 nsGenericHTMLElement* NS_NewHTMLElement(
   1411    already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
   1412    mozilla::dom::FromParser aFromParser = mozilla::dom::NOT_FROM_PARSER);
   1413 
   1414 // Distinct from the above in order to have function pointer that compared
   1415 // unequal to a function pointer to the above.
   1416 nsGenericHTMLElement* NS_NewCustomElement(
   1417    already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
   1418    mozilla::dom::FromParser aFromParser = mozilla::dom::NOT_FROM_PARSER);
   1419 
   1420 NS_DECLARE_NS_NEW_HTML_ELEMENT(Shared)
   1421 NS_DECLARE_NS_NEW_HTML_ELEMENT(SharedList)
   1422 
   1423 NS_DECLARE_NS_NEW_HTML_ELEMENT(Anchor)
   1424 NS_DECLARE_NS_NEW_HTML_ELEMENT(Area)
   1425 NS_DECLARE_NS_NEW_HTML_ELEMENT(Audio)
   1426 NS_DECLARE_NS_NEW_HTML_ELEMENT(BR)
   1427 NS_DECLARE_NS_NEW_HTML_ELEMENT(Body)
   1428 NS_DECLARE_NS_NEW_HTML_ELEMENT(Button)
   1429 NS_DECLARE_NS_NEW_HTML_ELEMENT(Canvas)
   1430 NS_DECLARE_NS_NEW_HTML_ELEMENT(Content)
   1431 NS_DECLARE_NS_NEW_HTML_ELEMENT(Mod)
   1432 NS_DECLARE_NS_NEW_HTML_ELEMENT(Data)
   1433 NS_DECLARE_NS_NEW_HTML_ELEMENT(DataList)
   1434 NS_DECLARE_NS_NEW_HTML_ELEMENT(Details)
   1435 NS_DECLARE_NS_NEW_HTML_ELEMENT(Dialog)
   1436 NS_DECLARE_NS_NEW_HTML_ELEMENT(Div)
   1437 NS_DECLARE_NS_NEW_HTML_ELEMENT(Embed)
   1438 NS_DECLARE_NS_NEW_HTML_ELEMENT(FieldSet)
   1439 NS_DECLARE_NS_NEW_HTML_ELEMENT(Font)
   1440 NS_DECLARE_NS_NEW_HTML_ELEMENT(Form)
   1441 NS_DECLARE_NS_NEW_HTML_ELEMENT(Frame)
   1442 NS_DECLARE_NS_NEW_HTML_ELEMENT(FrameSet)
   1443 NS_DECLARE_NS_NEW_HTML_ELEMENT(HR)
   1444 NS_DECLARE_NS_NEW_HTML_ELEMENT_AS_SHARED(Head)
   1445 NS_DECLARE_NS_NEW_HTML_ELEMENT(Heading)
   1446 NS_DECLARE_NS_NEW_HTML_ELEMENT_AS_SHARED(Html)
   1447 NS_DECLARE_NS_NEW_HTML_ELEMENT(IFrame)
   1448 NS_DECLARE_NS_NEW_HTML_ELEMENT(Image)
   1449 NS_DECLARE_NS_NEW_HTML_ELEMENT(Input)
   1450 NS_DECLARE_NS_NEW_HTML_ELEMENT(LI)
   1451 NS_DECLARE_NS_NEW_HTML_ELEMENT(Label)
   1452 NS_DECLARE_NS_NEW_HTML_ELEMENT(Legend)
   1453 NS_DECLARE_NS_NEW_HTML_ELEMENT(Link)
   1454 NS_DECLARE_NS_NEW_HTML_ELEMENT(Marquee)
   1455 NS_DECLARE_NS_NEW_HTML_ELEMENT(Map)
   1456 NS_DECLARE_NS_NEW_HTML_ELEMENT(Menu)
   1457 NS_DECLARE_NS_NEW_HTML_ELEMENT(Meta)
   1458 NS_DECLARE_NS_NEW_HTML_ELEMENT(Meter)
   1459 NS_DECLARE_NS_NEW_HTML_ELEMENT(Object)
   1460 NS_DECLARE_NS_NEW_HTML_ELEMENT(OptGroup)
   1461 NS_DECLARE_NS_NEW_HTML_ELEMENT(Option)
   1462 NS_DECLARE_NS_NEW_HTML_ELEMENT(Output)
   1463 NS_DECLARE_NS_NEW_HTML_ELEMENT(Paragraph)
   1464 NS_DECLARE_NS_NEW_HTML_ELEMENT(Picture)
   1465 NS_DECLARE_NS_NEW_HTML_ELEMENT(Pre)
   1466 NS_DECLARE_NS_NEW_HTML_ELEMENT(Progress)
   1467 NS_DECLARE_NS_NEW_HTML_ELEMENT(Script)
   1468 NS_DECLARE_NS_NEW_HTML_ELEMENT(Select)
   1469 NS_DECLARE_NS_NEW_HTML_ELEMENT(Slot)
   1470 NS_DECLARE_NS_NEW_HTML_ELEMENT(Source)
   1471 NS_DECLARE_NS_NEW_HTML_ELEMENT(Span)
   1472 NS_DECLARE_NS_NEW_HTML_ELEMENT(Style)
   1473 NS_DECLARE_NS_NEW_HTML_ELEMENT(Summary)
   1474 NS_DECLARE_NS_NEW_HTML_ELEMENT(TableCaption)
   1475 NS_DECLARE_NS_NEW_HTML_ELEMENT(TableCell)
   1476 NS_DECLARE_NS_NEW_HTML_ELEMENT(TableCol)
   1477 NS_DECLARE_NS_NEW_HTML_ELEMENT(Table)
   1478 NS_DECLARE_NS_NEW_HTML_ELEMENT(TableRow)
   1479 NS_DECLARE_NS_NEW_HTML_ELEMENT(TableSection)
   1480 NS_DECLARE_NS_NEW_HTML_ELEMENT(Tbody)
   1481 NS_DECLARE_NS_NEW_HTML_ELEMENT(Template)
   1482 NS_DECLARE_NS_NEW_HTML_ELEMENT(TextArea)
   1483 NS_DECLARE_NS_NEW_HTML_ELEMENT(Tfoot)
   1484 NS_DECLARE_NS_NEW_HTML_ELEMENT(Thead)
   1485 NS_DECLARE_NS_NEW_HTML_ELEMENT(Time)
   1486 NS_DECLARE_NS_NEW_HTML_ELEMENT(Title)
   1487 NS_DECLARE_NS_NEW_HTML_ELEMENT(Track)
   1488 NS_DECLARE_NS_NEW_HTML_ELEMENT(Unknown)
   1489 NS_DECLARE_NS_NEW_HTML_ELEMENT(Video)
   1490 
   1491 #endif /* nsGenericHTMLElement_h___ */