diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index 0f7f2b756e..026ae15836 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -1532,6 +1532,14 @@ Navigator::Clipboard() return mClipboard; } +/* static */ +bool +Navigator::Webdriver() +{ + // We don't support Selenium or marionette, so this is always false. + return false; +} + #ifdef MOZ_EME static nsCString ToCString(const nsString& aString) diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index 10f9573ee9..d674f5cedc 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -219,6 +219,8 @@ public: dom::Clipboard* Clipboard(); + static bool Webdriver(); + void GetLanguages(nsTArray& aLanguages); bool MozE10sEnabled(); diff --git a/dom/html/HTMLButtonElement.cpp b/dom/html/HTMLButtonElement.cpp index e3fdbb4d32..7f0852d11d 100644 --- a/dom/html/HTMLButtonElement.cpp +++ b/dom/html/HTMLButtonElement.cpp @@ -33,6 +33,7 @@ #include "nsFocusManager.h" #include "mozilla/dom/HTMLFormElement.h" #include "mozAutoDocUpdate.h" +#include "mozilla/Preferences.h" #define NS_IN_SUBMIT_CLICK (1 << 0) #define NS_OUTER_ACTIVATE_EVENT (1 << 1) @@ -186,6 +187,9 @@ HTMLButtonElement::ParseAttribute(int32_t aNamespaceID, } if (aAttribute == nsGkAtoms::formmethod) { + if (Preferences::GetBool("dom.dialog_element.enabled", true)) { + return aResult.ParseEnumValue(aValue, kFormMethodTableDialogEnabled, false); + } return aResult.ParseEnumValue(aValue, kFormMethodTable, false); } if (aAttribute == nsGkAtoms::formenctype) { diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp index c8bb526379..d2b39461f1 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -321,6 +321,9 @@ HTMLFormElement::ParseAttribute(int32_t aNamespaceID, { if (aNamespaceID == kNameSpaceID_None) { if (aAttribute == nsGkAtoms::method) { + if (Preferences::GetBool("dom.dialog_element.enabled", true)) { + return aResult.ParseEnumValue(aValue, kFormMethodTableDialogEnabled, false); + } return aResult.ParseEnumValue(aValue, kFormMethodTable, false); } if (aAttribute == nsGkAtoms::enctype) { @@ -673,6 +676,30 @@ HTMLFormElement::DoSubmit(WidgetEvent* aEvent) mSubmitInitiatedFromUserInput = EventStateManager::IsHandlingUserInput(); + // + // perform the submission + // + if (!submission) { + mIsSubmitting = false; +#ifdef DEBUG + HTMLDialogElement* dialog = nullptr; + for (nsIContent* parent = GetParent(); parent; + parent = parent->GetParent()) { + dialog = HTMLDialogElement::FromContentOrNull(parent); + if (dialog) { + break; + } + } + MOZ_ASSERT(!dialog || !dialog->Open()); +#endif + return NS_OK; + } + + if (DialogFormSubmission* dialogSubmission = + submission->GetAsDialogSubmission()) { + return SubmitDialog(dialogSubmission); + } + if(mDeferSubmission) { // we are in an event handler, JS submitted so we have to // defer this submission. let's remember it and return @@ -683,9 +710,6 @@ HTMLFormElement::DoSubmit(WidgetEvent* aEvent) return NS_OK; } - // - // perform the submission - // return SubmitSubmission(submission); } @@ -722,8 +746,10 @@ HTMLFormElement::BuildSubmission(HTMLFormSubmission** aFormSubmission, // // Dump the data into the submission object // - rv = WalkFormElements(*aFormSubmission); - NS_ENSURE_SUBMIT_SUCCESS(rv); + if (!(*aFormSubmission)->GetAsDialogSubmission()) { + rv = WalkFormElements(*aFormSubmission); + NS_ENSURE_SUBMIT_SUCCESS(rv); + } return NS_OK; } @@ -862,6 +888,22 @@ HTMLFormElement::SubmitSubmission(HTMLFormSubmission* aFormSubmission) return rv; } +// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#submit-dialog +nsresult HTMLFormElement::SubmitDialog(DialogFormSubmission* aFormSubmission) { + mIsSubmitting = false; + + // Close the dialog subject. If there is a result, let that be the return + // value. + HTMLDialogElement* dialog = aFormSubmission->DialogElement(); + MOZ_ASSERT(dialog); + + Optional retValue; + retValue = &aFormSubmission->ReturnValue(); + dialog->Close(retValue); + + return NS_OK; +} + nsresult HTMLFormElement::DoSecureToInsecureSubmitCheck(nsIURI* aActionURL, bool* aCancelSubmit) diff --git a/dom/html/HTMLFormElement.h b/dom/html/HTMLFormElement.h index f13eab9acc..102e24fdf9 100644 --- a/dom/html/HTMLFormElement.h +++ b/dom/html/HTMLFormElement.h @@ -483,6 +483,12 @@ protected: */ nsresult SubmitSubmission(HTMLFormSubmission* aFormSubmission); + /** + * Submit a form[method=dialog] + * @param aFormSubmission the submission object + */ + nsresult SubmitDialog(DialogFormSubmission* aFormSubmission); + /** * Notify any submit observers of the submit. * diff --git a/dom/html/HTMLFormSubmission.cpp b/dom/html/HTMLFormSubmission.cpp index d447f51476..6a931858b3 100644 --- a/dom/html/HTMLFormSubmission.cpp +++ b/dom/html/HTMLFormSubmission.cpp @@ -944,6 +944,30 @@ HTMLFormSubmission::GetFromForm(nsGenericHTMLElement* aForm, charset.AssignLiteral("UTF-8"); } + if (method == NS_FORM_METHOD_DIALOG) { + HTMLDialogElement* dialog = nullptr; + for (nsIContent* parent = aForm->GetParent(); parent; + parent = parent->GetParent()) { + dialog = HTMLDialogElement::FromContentOrNull(parent); + if (dialog) { + break; + } + } + + // If there isn't one, or if it does not have an open attribute, do + // nothing. + if (!dialog || !dialog->Open()) { + return NS_ERROR_FAILURE; + } + + nsAutoString result; + if (aOriginatingElement) { + aOriginatingElement->ResultForDialogSubmit(result); + } + *aFormSubmission = new DialogFormSubmission(result, charset, aOriginatingElement, dialog); + return NS_OK; + } + // Choose encoder if (method == NS_FORM_METHOD_POST && enctype == NS_FORM_ENCTYPE_MULTIPART) { diff --git a/dom/html/HTMLFormSubmission.h b/dom/html/HTMLFormSubmission.h index 506aa668df..d2ea8df8b5 100644 --- a/dom/html/HTMLFormSubmission.h +++ b/dom/html/HTMLFormSubmission.h @@ -7,6 +7,7 @@ #define mozilla_dom_HTMLFormSubmission_h #include "mozilla/Attributes.h" +#include "mozilla/dom/HTMLDialogElement.h" #include "nsCOMPtr.h" #include "nsIContent.h" #include "nsNCRFallbackEncoderWrapper.h" @@ -121,6 +122,8 @@ public: return mOriginatingElement.get(); } + virtual DialogFormSubmission* GetAsDialogSubmission() { return nullptr; } + protected: /** * Can only be constructed by subclasses. @@ -168,6 +171,50 @@ private: nsNCRFallbackEncoderWrapper mEncoder; }; + +class DialogFormSubmission final : public HTMLFormSubmission { + public: + DialogFormSubmission(nsAString& aResult, + const nsACString& aCharset, Element* aSubmitter, + HTMLDialogElement* aDialogElement) + : HTMLFormSubmission(aCharset, aSubmitter) + , mDialogElement(aDialogElement) + , mReturnValue(aResult) { + } + + nsresult AddNameValuePair(const nsAString& aName, + const nsAString& aValue) override { + MOZ_CRASH("This method should not be called"); + return NS_OK; + } + + nsresult AddNameBlobOrNullPair(const nsAString& aName, Blob* aBlob) override { + MOZ_CRASH("This method should not be called"); + return NS_OK; + } + + nsresult AddNameDirectoryPair(const nsAString& aName, + Directory* aDirectory) override { + MOZ_CRASH("This method should not be called"); + return NS_OK; + } + + nsresult GetEncodedSubmission(nsIURI* aURI, nsIInputStream** aPostDataStream) override { + MOZ_CRASH("This method should not be called"); + return NS_OK; + } + + DialogFormSubmission* GetAsDialogSubmission() override { return this; } + + HTMLDialogElement* DialogElement() { return mDialogElement; } + + nsString& ReturnValue() { return mReturnValue; } + + private: + const RefPtr mDialogElement; + nsString mReturnValue; +}; + /** * Handle multipart/form-data encoding, which does files as well as normal * inputs. This always does POST. diff --git a/dom/html/HTMLFormSubmissionConstants.h b/dom/html/HTMLFormSubmissionConstants.h index 261af61652..d3a880c58a 100644 --- a/dom/html/HTMLFormSubmissionConstants.h +++ b/dom/html/HTMLFormSubmissionConstants.h @@ -14,6 +14,13 @@ static const nsAttrValue::EnumTable kFormMethodTable[] = { { nullptr, 0 } }; +static const nsAttrValue::EnumTable kFormMethodTableDialogEnabled[] = { + {"get", NS_FORM_METHOD_GET}, + {"post", NS_FORM_METHOD_POST}, + {"dialog", NS_FORM_METHOD_DIALOG}, + {nullptr, 0} +}; + // Default method is 'get'. static const nsAttrValue::EnumTable* kFormDefaultMethod = &kFormMethodTable[0]; diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index dd2d134f8e..7d9a4db1cd 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -1482,6 +1482,26 @@ NS_IMPL_STRING_ATTR(HTMLInputElement, Placeholder, placeholder) NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLInputElement, Type, type, kInputDefaultType->tag) +void HTMLInputElement::ResultForDialogSubmit(nsAString& aResult) { + if (mType == NS_FORM_INPUT_IMAGE) { + // Get a property set by the frame to find out where it was clicked. + nsIntPoint* lastClickedPoint = + static_cast(GetProperty(nsGkAtoms::imageClickedPoint)); + int32_t x, y; + if (lastClickedPoint) { + x = lastClickedPoint->x; + y = lastClickedPoint->y; + } else { + x = y = 0; + } + aResult.AppendInt(x); + aResult.AppendLiteral(","); + aResult.AppendInt(y); + } else { + GetAttr(kNameSpaceID_None, nsGkAtoms::value, aResult); + } +} + NS_IMETHODIMP HTMLInputElement::GetAutocomplete(nsAString& aValue) { @@ -5916,6 +5936,9 @@ HTMLInputElement::ParseAttribute(int32_t aNamespaceID, return aResult.ParseEnumValue(aValue, kFormMethodTable, false); } if (aAttribute == nsGkAtoms::formenctype) { + if (Preferences::GetBool("dom.dialog_element.enabled", true)) { + return aResult.ParseEnumValue(aValue, kFormMethodTableDialogEnabled, false); + } return aResult.ParseEnumValue(aValue, kFormEnctypeTable, false); } if (aAttribute == nsGkAtoms::autocomplete) { diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h index 24fc7454ac..44e1f9c1ca 100644 --- a/dom/html/HTMLInputElement.h +++ b/dom/html/HTMLInputElement.h @@ -968,6 +968,8 @@ protected: const nsAttrValue* aOldValue, bool aNotify) override; + virtual void ResultForDialogSubmit(nsAString& aResult) override; + /** * Dispatch a select event. Returns true if the event was not cancelled. */ diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h index 56812b445b..d2b7f45e9c 100644 --- a/dom/html/nsGenericHTMLElement.h +++ b/dom/html/nsGenericHTMLElement.h @@ -861,6 +861,10 @@ public: static bool IsScrollGrabAllowed(JSContext*, JSObject*); + virtual inline void ResultForDialogSubmit(nsAString& aResult) { + GetAttr(kNameSpaceID_None, nsGkAtoms::value, aResult); + } + protected: /** * Add/remove this element to the documents name cache diff --git a/dom/html/nsIForm.h b/dom/html/nsIForm.h index 44eedc5103..6c2b1d8623 100644 --- a/dom/html/nsIForm.h +++ b/dom/html/nsIForm.h @@ -12,6 +12,7 @@ class nsIFormControl; #define NS_FORM_METHOD_GET 0 #define NS_FORM_METHOD_POST 1 +#define NS_FORM_METHOD_DIALOG 2 #define NS_FORM_ENCTYPE_URLENCODED 0 #define NS_FORM_ENCTYPE_MULTIPART 1 #define NS_FORM_ENCTYPE_TEXTPLAIN 2 diff --git a/dom/html/nsIFormControl.h b/dom/html/nsIFormControl.h index 067ac7cae8..1815c88543 100644 --- a/dom/html/nsIFormControl.h +++ b/dom/html/nsIFormControl.h @@ -16,6 +16,7 @@ namespace dom { class Element; class HTMLFieldSetElement; class HTMLFormSubmission; +class DialogFormSubmission; } // namespace dom } // namespace mozilla diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index f2212de392..4541210a08 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -12,6 +12,7 @@ * https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#navigator-interface-extension * http://www.w3.org/TR/beacon/#sec-beacon-method * https://html.spec.whatwg.org/#navigatorconcurrenthardware + * https://w3c.github.io/webdriver/webdriver-spec.html#interface * * © Copyright 2004-2020 Apple Computer, Inc., Mozilla Foundation, * Opera Software ASA and Moonchild Productions. You are granted a license to use, @@ -31,6 +32,7 @@ Navigator implements NavigatorStorageUtils; Navigator implements NavigatorConcurrentHardware; Navigator implements NavigatorStorage; Navigator implements NavigatorGlobalPrivacyControl; +Navigator implements NavigatorAutomationInformation; [NoInterfaceObject, Exposed=(Window,Worker)] interface NavigatorID { @@ -334,3 +336,10 @@ partial interface Navigator { [Pref="dom.events.asyncClipboard", SecureContext, SameObject] readonly attribute Clipboard clipboard; }; + +// https://w3c.github.io/webdriver/webdriver-spec.html#interface +[NoInterfaceObject, Exposed=Window] +interface NavigatorAutomationInformation { + [Pref="dom.webdriver.enabled"] + readonly attribute boolean webdriver; +}; diff --git a/gfx/qcms/transform-altivec.c b/gfx/qcms/transform-altivec.c index 9dc17bc13f..df896db56c 100644 --- a/gfx/qcms/transform-altivec.c +++ b/gfx/qcms/transform-altivec.c @@ -29,7 +29,7 @@ static const ALIGN float floatScaleX4 = FLOATSCALE; static const ALIGN float clampMaxValueX4 = CLAMPMAXVAL; -inline vector float load_aligned_float(float *dataPtr) +static inline vector float load_aligned_float(float *dataPtr) { vector float data = vec_lde(0, dataPtr); vector unsigned char moveToStart = vec_lvsl(0, dataPtr); diff --git a/layout/forms/nsListControlFrame.cpp b/layout/forms/nsListControlFrame.cpp index 4daa470a9e..0f6772a09a 100644 --- a/layout/forms/nsListControlFrame.cpp +++ b/layout/forms/nsListControlFrame.cpp @@ -2236,11 +2236,20 @@ nsListControlFrame::KeyDown(nsIDOMEvent* aKeyEvent) return NS_OK; } + // We don't want to preventDefault for escape key if the dropdown + // popup is not shown. + // Need to do the check before AboutToRollup because AboutToRollup + // may update the dropdown flags. + bool doPreventDefault = + !mComboboxFrame || mComboboxFrame->IsDroppedDownOrHasParentPopup(); + AboutToRollup(); - // If the select element is a dropdown style, Enter key should be + // If the select element is a dropdown style, Escape key should be // consumed everytime since Escape key may be pressed accidentally after // the dropdown is closed by Escepe key. - aKeyEvent->PreventDefault(); + if (doPreventDefault) { + aKeyEvent->PreventDefault(); + } return NS_OK; } case NS_VK_PAGE_UP: { diff --git a/layout/style/res/ua.css b/layout/style/res/ua.css index ab51f67c53..bf32e66c56 100644 --- a/layout/style/res/ua.css +++ b/layout/style/res/ua.css @@ -320,6 +320,8 @@ position: fixed; top: 0; left: 0; right: 0; bottom: 0; + /* This prevents undesired interactions with the selection code. */ + -moz-user-select: none; } *|*:-moz-full-screen:not(:root)::backdrop { diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 12d05de4a9..128130349a 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -5264,6 +5264,9 @@ pref("media.seekToNextFrame.enabled", true); // return the maximum number of cores that navigator.hardwareConcurrency returns pref("dom.maxHardwareConcurrency", 16); +// Exposes the navigator.webdriver attribute. +pref("dom.webdriver.enabled", true); + // Shutdown the async osfile worker if it's no longer needed. pref("osfile.reset_worker_delay", 30000);