Bug 1816170 - Disable perftest-on-autoland cron. r=aglavic
[gecko.git] / dom / html / HTMLFormElement.h
blobe6aba2150d3c9dc5c481f9786d87d89bee7a9963
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/. */
7 #ifndef mozilla_dom_HTMLFormElement_h
8 #define mozilla_dom_HTMLFormElement_h
10 #include "mozilla/AsyncEventDispatcher.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/UniquePtr.h"
13 #include "mozilla/dom/AnchorAreaFormRelValues.h"
14 #include "mozilla/dom/BrowsingContext.h"
15 #include "mozilla/dom/PopupBlocker.h"
16 #include "mozilla/dom/RadioGroupManager.h"
17 #include "nsCOMPtr.h"
18 #include "nsIFormControl.h"
19 #include "nsGenericHTMLElement.h"
20 #include "nsIRadioGroupContainer.h"
21 #include "nsIWeakReferenceUtils.h"
22 #include "nsThreadUtils.h"
23 #include "nsInterfaceHashtable.h"
24 #include "nsRefPtrHashtable.h"
25 #include "nsTHashMap.h"
26 #include "js/friend/DOMProxy.h" // JS::ExpandoAndGeneration
28 class nsIMutableArray;
29 class nsIURI;
31 namespace mozilla {
32 class EventChainPostVisitor;
33 class EventChainPreVisitor;
34 namespace dom {
35 class DialogFormSubmission;
36 class HTMLFormControlsCollection;
37 class HTMLFormSubmission;
38 class HTMLImageElement;
39 class FormData;
41 class HTMLFormElement final : public nsGenericHTMLElement,
42 public nsIRadioGroupContainer,
43 public AnchorAreaFormRelValues,
44 RadioGroupManager {
45 friend class HTMLFormControlsCollection;
47 public:
48 NS_IMPL_FROMNODE_HTML_WITH_TAG(HTMLFormElement, form)
50 explicit HTMLFormElement(
51 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
53 enum { FORM_CONTROL_LIST_HASHTABLE_LENGTH = 8 };
55 // nsISupports
56 NS_DECL_ISUPPORTS_INHERITED
58 int32_t IndexOfContent(nsIContent* aContent);
59 nsGenericHTMLFormElement* GetDefaultSubmitElement() const;
61 // nsIRadioGroupContainer
62 void SetCurrentRadioButton(const nsAString& aName,
63 HTMLInputElement* aRadio) override;
64 HTMLInputElement* GetCurrentRadioButton(const nsAString& aName) override;
65 NS_IMETHOD GetNextRadioButton(const nsAString& aName, const bool aPrevious,
66 HTMLInputElement* aFocusedRadio,
67 HTMLInputElement** aRadioOut) override;
68 NS_IMETHOD WalkRadioGroup(const nsAString& aName,
69 nsIRadioVisitor* aVisitor) override;
70 void AddToRadioGroup(const nsAString& aName,
71 HTMLInputElement* aRadio) override;
72 void RemoveFromRadioGroup(const nsAString& aName,
73 HTMLInputElement* aRadio) override;
74 virtual uint32_t GetRequiredRadioCount(const nsAString& aName) const override;
75 virtual void RadioRequiredWillChange(const nsAString& aName,
76 bool aRequiredAdded) override;
77 virtual bool GetValueMissingState(const nsAString& aName) const override;
78 virtual void SetValueMissingState(const nsAString& aName,
79 bool aValue) override;
81 virtual ElementState IntrinsicState() const override;
83 // EventTarget
84 virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
86 // nsIContent
87 virtual bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
88 const nsAString& aValue,
89 nsIPrincipal* aMaybeScriptedPrincipal,
90 nsAttrValue& aResult) override;
91 void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
92 void WillHandleEvent(EventChainPostVisitor& aVisitor) override;
93 virtual nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
95 virtual nsresult BindToTree(BindContext&, nsINode& aParent) override;
96 virtual void UnbindFromTree(bool aNullParent = true) override;
97 virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
98 const nsAttrValueOrString* aValue,
99 bool aNotify) override;
102 * Forget all information about the current submission (and the fact that we
103 * are currently submitting at all).
105 void ForgetCurrentSubmission();
107 virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
109 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLFormElement,
110 nsGenericHTMLElement)
113 * Remove an element from this form's list of elements
115 * @param aElement the element to remove
116 * @param aUpdateValidity If true, updates the form validity.
117 * @return NS_OK if the element was successfully removed.
119 nsresult RemoveElement(nsGenericHTMLFormElement* aElement,
120 bool aUpdateValidity);
123 * Remove an element from the lookup table maintained by the form.
124 * We can't fold this method into RemoveElement() because when
125 * RemoveElement() is called it doesn't know if the element is
126 * removed because the id attribute has changed, or because the
127 * name attribute has changed.
129 * @param aElement the element to remove
130 * @param aName the name or id of the element to remove
131 * @return NS_OK if the element was successfully removed.
133 nsresult RemoveElementFromTable(nsGenericHTMLFormElement* aElement,
134 const nsAString& aName);
137 * Add an element to end of this form's list of elements
139 * @param aElement the element to add
140 * @param aUpdateValidity If true, the form validity will be updated.
141 * @param aNotify If true, send DocumentObserver notifications as needed.
142 * @return NS_OK if the element was successfully added
144 nsresult AddElement(nsGenericHTMLFormElement* aElement, bool aUpdateValidity,
145 bool aNotify);
148 * Add an element to the lookup table maintained by the form.
150 * We can't fold this method into AddElement() because when
151 * AddElement() is called, the form control has no
152 * attributes. The name or id attributes of the form control
153 * are used as a key into the table.
155 nsresult AddElementToTable(nsGenericHTMLFormElement* aChild,
156 const nsAString& aName);
159 * Remove an image element from this form's list of image elements
161 * @param aElement the image element to remove
162 * @return NS_OK if the element was successfully removed.
164 nsresult RemoveImageElement(HTMLImageElement* aElement);
167 * Remove an image element from the lookup table maintained by the form.
168 * We can't fold this method into RemoveImageElement() because when
169 * RemoveImageElement() is called it doesn't know if the element is
170 * removed because the id attribute has changed, or because the
171 * name attribute has changed.
173 * @param aElement the image element to remove
174 * @param aName the name or id of the element to remove
175 * @return NS_OK if the element was successfully removed.
177 nsresult RemoveImageElementFromTable(HTMLImageElement* aElement,
178 const nsAString& aName);
180 * Add an image element to the end of this form's list of image elements
182 * @param aElement the element to add
183 * @return NS_OK if the element was successfully added
185 nsresult AddImageElement(HTMLImageElement* aElement);
188 * Add an image element to the lookup table maintained by the form.
190 * We can't fold this method into AddImageElement() because when
191 * AddImageElement() is called, the image attributes can change.
192 * The name or id attributes of the image are used as a key into the table.
194 nsresult AddImageElementToTable(HTMLImageElement* aChild,
195 const nsAString& aName);
198 * Returns true if implicit submission of this form is disabled. For more
199 * on implicit submission see:
201 * http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#implicit-submission
203 bool ImplicitSubmissionIsDisabled() const;
206 * Check whether a given nsGenericHTMLFormElement is the last single line
207 * input control that is not disabled. aElement is expected to not be null.
209 bool IsLastActiveElement(const nsGenericHTMLFormElement* aElement) const;
212 * Check whether a given nsGenericHTMLFormElement is the default submit
213 * element. This is different from just comparing to
214 * GetDefaultSubmitElement() in certain situations inside an update
215 * when GetDefaultSubmitElement() might not be up to date. aElement
216 * is expected to not be null.
218 bool IsDefaultSubmitElement(const nsGenericHTMLFormElement* aElement) const;
221 * Flag the form to know that a button or image triggered scripted form
222 * submission. In that case the form will defer the submission until the
223 * script handler returns and the return value is known.
225 void OnSubmitClickBegin(Element* aOriginatingElement);
226 void OnSubmitClickEnd();
229 * This method will update the form validity.
231 * This method has to be called by form elements whenever their validity state
232 * or status regarding constraint validation changes.
234 * @note This method isn't used for CheckValidity().
235 * @note If an element becomes barred from constraint validation, it has to be
236 * considered as valid.
238 * @param aElementValidityState the new validity state of the element
240 void UpdateValidity(bool aElementValidityState);
243 * This method check the form validity and make invalid form elements send
244 * invalid event if needed.
246 * @return Whether the form is valid.
248 * @note Do not call this method if novalidate/formnovalidate is used.
249 * @note This method might disappear with bug 592124, hopefuly.
250 * @see
251 * https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#interactively-validate-the-constraints
253 bool CheckValidFormSubmission();
256 * Contruct the entry list to get their data pumped into the FormData and
257 * fire a `formdata` event with the entry list in formData attribute.
258 * <https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#constructing-form-data-set>
260 * @param aFormData the form data object
262 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
263 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult ConstructEntryList(FormData* aFormData);
266 * Whether the submission of this form has been ever prevented because of
267 * being invalid.
269 * @return Whether the submission of this form has been prevented because of
270 * being invalid.
272 bool HasEverTriedInvalidSubmit() const { return mEverTriedInvalidSubmit; }
275 * Implements form[name]. Returns form controls in this form with the correct
276 * value of the name attribute.
278 already_AddRefed<nsISupports> FindNamedItem(const nsAString& aName,
279 nsWrapperCache** aCache);
281 // WebIDL
283 void GetAcceptCharset(DOMString& aValue) {
284 GetHTMLAttr(nsGkAtoms::acceptcharset, aValue);
287 void SetAcceptCharset(const nsAString& aValue, ErrorResult& aRv) {
288 SetHTMLAttr(nsGkAtoms::acceptcharset, aValue, aRv);
291 void GetAction(nsString& aValue);
292 void SetAction(const nsAString& aValue, ErrorResult& aRv) {
293 SetHTMLAttr(nsGkAtoms::action, aValue, aRv);
296 void GetAutocomplete(nsAString& aValue);
297 void SetAutocomplete(const nsAString& aValue, ErrorResult& aRv) {
298 SetHTMLAttr(nsGkAtoms::autocomplete, aValue, aRv);
301 void GetEnctype(nsAString& aValue);
302 void SetEnctype(const nsAString& aValue, ErrorResult& aRv) {
303 SetHTMLAttr(nsGkAtoms::enctype, aValue, aRv);
306 void GetEncoding(nsAString& aValue) { GetEnctype(aValue); }
307 void SetEncoding(const nsAString& aValue, ErrorResult& aRv) {
308 SetEnctype(aValue, aRv);
311 void GetMethod(nsAString& aValue);
312 void SetMethod(const nsAString& aValue, ErrorResult& aRv) {
313 SetHTMLAttr(nsGkAtoms::method, aValue, aRv);
316 void GetName(DOMString& aValue) { GetHTMLAttr(nsGkAtoms::name, aValue); }
318 void SetName(const nsAString& aValue, ErrorResult& aRv) {
319 SetHTMLAttr(nsGkAtoms::name, aValue, aRv);
322 bool NoValidate() const { return GetBoolAttr(nsGkAtoms::novalidate); }
324 void SetNoValidate(bool aValue, ErrorResult& aRv) {
325 SetHTMLBoolAttr(nsGkAtoms::novalidate, aValue, aRv);
328 void GetTarget(DOMString& aValue) { GetHTMLAttr(nsGkAtoms::target, aValue); }
330 void SetTarget(const nsAString& aValue, ErrorResult& aRv) {
331 SetHTMLAttr(nsGkAtoms::target, aValue, aRv);
334 void GetRel(DOMString& aValue) { GetHTMLAttr(nsGkAtoms::rel, aValue); }
335 void SetRel(const nsAString& aRel, ErrorResult& aError) {
336 SetHTMLAttr(nsGkAtoms::rel, aRel, aError);
338 nsDOMTokenList* RelList();
340 // it's only out-of-line because the class definition is not available in the
341 // header
342 nsIHTMLCollection* Elements();
344 int32_t Length();
347 * Check whether submission can proceed for this form then fire submit event.
348 * This basically implements steps 1-6 (more or less) of
349 * <https://html.spec.whatwg.org/multipage/forms.html#concept-form-submit>.
350 * @param aSubmitter If not null, is the "submitter" from that algorithm.
351 * Therefore it must be a valid submit control.
353 MOZ_CAN_RUN_SCRIPT void MaybeSubmit(Element* aSubmitter);
354 MOZ_CAN_RUN_SCRIPT void MaybeReset(Element* aSubmitter);
355 void Submit(ErrorResult& aRv);
358 * Requests to submit the form. Unlike submit(), this method includes
359 * interactive constraint validation and firing a submit event,
360 * either of which can cancel submission.
362 * @param aSubmitter The submitter argument can be used to point to a specific
363 * submit button.
364 * @param aRv An ErrorResult.
365 * @see
366 * https://html.spec.whatwg.org/multipage/forms.html#dom-form-requestsubmit
368 MOZ_CAN_RUN_SCRIPT void RequestSubmit(nsGenericHTMLElement* aSubmitter,
369 ErrorResult& aRv);
371 MOZ_CAN_RUN_SCRIPT void Reset();
373 bool CheckValidity() { return CheckFormValidity(nullptr); }
375 bool ReportValidity() { return CheckValidFormSubmission(); }
377 Element* IndexedGetter(uint32_t aIndex, bool& aFound);
379 already_AddRefed<nsISupports> NamedGetter(const nsAString& aName,
380 bool& aFound);
382 void GetSupportedNames(nsTArray<nsString>& aRetval);
384 static int32_t CompareFormControlPosition(Element* aElement1,
385 Element* aElement2,
386 const nsIContent* aForm);
387 #ifdef DEBUG
388 static void AssertDocumentOrder(
389 const nsTArray<nsGenericHTMLFormElement*>& aControls, nsIContent* aForm);
390 static void AssertDocumentOrder(
391 const nsTArray<RefPtr<nsGenericHTMLFormElement>>& aControls,
392 nsIContent* aForm);
393 #endif
395 JS::ExpandoAndGeneration mExpandoAndGeneration;
397 protected:
398 virtual JSObject* WrapNode(JSContext* aCx,
399 JS::Handle<JSObject*> aGivenProto) override;
401 void PostPasswordEvent();
402 void PostPossibleUsernameEvent();
404 RefPtr<AsyncEventDispatcher> mFormPasswordEventDispatcher;
405 RefPtr<AsyncEventDispatcher> mFormPossibleUsernameEventDispatcher;
407 class RemoveElementRunnable;
408 friend class RemoveElementRunnable;
410 class RemoveElementRunnable : public Runnable {
411 public:
412 explicit RemoveElementRunnable(HTMLFormElement* aForm)
413 : Runnable("dom::HTMLFormElement::RemoveElementRunnable"),
414 mForm(aForm) {}
416 NS_IMETHOD Run() override {
417 mForm->HandleDefaultSubmitRemoval();
418 return NS_OK;
421 private:
422 RefPtr<HTMLFormElement> mForm;
425 nsresult DoReset();
427 // Async callback to handle removal of our default submit
428 void HandleDefaultSubmitRemoval();
431 // Submit Helpers
435 * Attempt to submit (submission might be deferred)
437 * @param aPresContext the presentation context
438 * @param aEvent the DOM event that was passed to us for the submit
440 nsresult DoSubmit(Event* aEvent = nullptr);
443 * Prepare the submission object (called by DoSubmit)
445 * @param aFormSubmission the submission object
446 * @param aEvent the DOM event that was passed to us for the submit
448 nsresult BuildSubmission(HTMLFormSubmission** aFormSubmission, Event* aEvent);
450 * Perform the submission (called by DoSubmit and FlushPendingSubmission)
452 * @param aFormSubmission the submission object
454 nsresult SubmitSubmission(HTMLFormSubmission* aFormSubmission);
457 * Submit a form[method=dialog]
458 * @param aFormSubmission the submission object
460 nsresult SubmitDialog(DialogFormSubmission* aFormSubmission);
463 * Notify any submit observers of the submit.
465 * @param aActionURL the URL being submitted to
466 * @param aCancelSubmit out param where submit observers can specify that the
467 * submit should be cancelled.
469 nsresult NotifySubmitObservers(nsIURI* aActionURL, bool* aCancelSubmit,
470 bool aEarlyNotify);
473 * If this form submission is secure -> insecure, ask the user if they want
474 * to continue.
476 * @param aActionURL the URL being submitted to
477 * @param aCancelSubmit out param: will be true if the user wants to cancel
479 nsresult DoSecureToInsecureSubmitCheck(nsIURI* aActionURL,
480 bool* aCancelSubmit);
483 * Find form controls in this form with the correct value in the name
484 * attribute.
486 already_AddRefed<nsISupports> DoResolveName(const nsAString& aName);
489 * Check the form validity following this algorithm:
490 * https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#statically-validate-the-constraints
492 * @param aInvalidElements [out] parameter containing the list of unhandled
493 * invalid controls.
495 * @return Whether the form is currently valid.
497 bool CheckFormValidity(nsTArray<RefPtr<Element>>* aInvalidElements) const;
499 // Clear the mImageNameLookupTable and mImageElements.
500 void Clear();
502 // Insert a element into the past names map.
503 void AddToPastNamesMap(const nsAString& aName, nsISupports* aChild);
505 // Remove the given element from the past names map. The element must be an
506 // nsGenericHTMLFormElement or HTMLImageElement.
507 void RemoveElementFromPastNamesMap(Element* aElement);
509 nsresult AddElementToTableInternal(
510 nsInterfaceHashtable<nsStringHashKey, nsISupports>& aTable,
511 nsIContent* aChild, const nsAString& aName);
513 nsresult RemoveElementFromTableInternal(
514 nsInterfaceHashtable<nsStringHashKey, nsISupports>& aTable,
515 nsIContent* aChild, const nsAString& aName);
517 public:
519 * Flush a possible pending submission. If there was a scripted submission
520 * triggered by a button or image, the submission was defered. This method
521 * forces the pending submission to be submitted. (happens when the handler
522 * returns false or there is an action/target change in the script)
524 void FlushPendingSubmission();
527 * Get the full URL to submit to. Do not submit if the returned URL is null.
529 * @param aActionURL the full, unadulterated URL you'll be submitting to [OUT]
530 * @param aOriginatingElement the originating element of the form submission
531 * [IN]
533 nsresult GetActionURL(nsIURI** aActionURL, Element* aOriginatingElement);
535 // Returns a number for this form that is unique within its owner document.
536 // This is used by nsContentUtils::GenerateStateKey to identify form controls
537 // that are inserted into the document by the parser.
538 int32_t GetFormNumberForStateKey();
541 * Called when we have been cloned and adopted, and the information of the
542 * node has been changed.
544 void NodeInfoChanged(Document* aOldDoc) override;
546 protected:
548 // Data members
550 /** The list of controls (form.elements as well as stuff not in elements) */
551 RefPtr<HTMLFormControlsCollection> mControls;
553 /** The pending submission object */
554 UniquePtr<HTMLFormSubmission> mPendingSubmission;
556 /** The target browsing context, if any. */
557 RefPtr<BrowsingContext> mTargetContext;
558 /** The load identifier for the pending request created for a
559 * submit, used to be able to block double submits. */
560 Maybe<uint64_t> mCurrentLoadId;
562 /** The default submit element -- WEAK */
563 nsGenericHTMLFormElement* mDefaultSubmitElement;
565 /** The first submit element in mElements -- WEAK */
566 nsGenericHTMLFormElement* mFirstSubmitInElements;
568 /** The first submit element in mNotInElements -- WEAK */
569 nsGenericHTMLFormElement* mFirstSubmitNotInElements;
571 // This array holds on to all HTMLImageElement(s).
572 // This is needed to properly clean up the bi-directional references
573 // (both weak and strong) between the form and its HTMLImageElements.
575 nsTArray<HTMLImageElement*> mImageElements; // Holds WEAK references
577 // A map from an ID or NAME attribute to the HTMLImageElement(s), this
578 // hash holds strong references either to the named HTMLImageElement, or
579 // to a list of named HTMLImageElement(s), in the case where this hash
580 // holds on to a list of named HTMLImageElement(s) the list has weak
581 // references to the HTMLImageElement.
583 nsInterfaceHashtable<nsStringHashKey, nsISupports> mImageNameLookupTable;
585 // A map from names to elements that were gotten by those names from this
586 // form in that past. See "past names map" in the HTML5 specification.
588 nsInterfaceHashtable<nsStringHashKey, nsISupports> mPastNameLookupTable;
590 /** Keep track of what the popup state was when the submit was initiated */
591 PopupBlocker::PopupControlState mSubmitPopupState;
593 RefPtr<nsDOMTokenList> mRelList;
596 * Number of invalid and candidate for constraint validation elements in the
597 * form the last time UpdateValidity has been called.
599 int32_t mInvalidElementsCount;
601 // See GetFormNumberForStateKey.
602 int32_t mFormNumber;
604 /** Whether we are currently processing a submit event or not */
605 bool mGeneratingSubmit;
606 /** Whether we are currently processing a reset event or not */
607 bool mGeneratingReset;
608 /** Whether the submission is to be deferred in case a script triggers it */
609 bool mDeferSubmission;
610 /** Whether we notified NS_FORMSUBMIT_SUBJECT listeners already */
611 bool mNotifiedObservers;
612 /** If we notified the listeners early, what was the result? */
613 bool mNotifiedObserversResult;
615 * Whether the submission of this form has been ever prevented because of
616 * being invalid.
618 bool mEverTriedInvalidSubmit;
619 /** Whether we are constructing entry list */
620 bool mIsConstructingEntryList;
621 /** Whether we are firing submission event */
622 bool mIsFiringSubmissionEvents;
624 private:
625 bool IsSubmitting() const;
627 NotNull<const Encoding*> GetSubmitEncoding();
630 * Fire an event when the form is removed from the DOM tree. This is now only
631 * used by the password manager.
633 void MaybeFireFormRemoved();
635 ~HTMLFormElement();
638 } // namespace dom
640 } // namespace mozilla
642 #endif // mozilla_dom_HTMLFormElement_h