summaryrefslogtreecommitdiffstats
path: root/dom/html
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/html/HTMLAnchorElement.cpp37
-rw-r--r--dom/html/HTMLAnchorElement.h4
-rw-r--r--dom/html/HTMLButtonElement.cpp11
-rw-r--r--dom/html/HTMLButtonElement.h2
-rw-r--r--dom/html/HTMLCanvasElement.cpp14
-rw-r--r--dom/html/HTMLCanvasElement.h2
-rw-r--r--dom/html/HTMLDNSPrefetch.cpp138
-rw-r--r--dom/html/HTMLDNSPrefetch.h14
-rw-r--r--dom/html/HTMLDetailsElement.h2
-rw-r--r--dom/html/HTMLDialogElement.cpp2
-rw-r--r--dom/html/HTMLEmbedElement.cpp4
-rw-r--r--dom/html/HTMLEmbedElement.h2
-rw-r--r--dom/html/HTMLImageElement.cpp13
-rw-r--r--dom/html/HTMLImageElement.h2
-rw-r--r--dom/html/HTMLInputElement.cpp62
-rw-r--r--dom/html/HTMLInputElement.h26
-rw-r--r--dom/html/HTMLLinkElement.cpp2
-rw-r--r--dom/html/HTMLMediaElement.cpp48
-rw-r--r--dom/html/HTMLMediaElement.h24
-rw-r--r--dom/html/HTMLObjectElement.cpp3
-rw-r--r--dom/html/HTMLObjectElement.h2
-rw-r--r--dom/html/HTMLSelectElement.cpp5
-rw-r--r--dom/html/HTMLSelectElement.h2
-rw-r--r--dom/html/HTMLSharedElement.cpp12
-rw-r--r--dom/html/HTMLSummaryElement.cpp7
-rw-r--r--dom/html/HTMLSummaryElement.h2
-rw-r--r--dom/html/HTMLTextAreaElement.cpp5
-rw-r--r--dom/html/HTMLTextAreaElement.h2
-rw-r--r--dom/html/nsGenericHTMLElement.cpp40
-rw-r--r--dom/html/nsGenericHTMLElement.h11
-rw-r--r--dom/html/nsGenericHTMLFrameElement.cpp5
-rw-r--r--dom/html/nsGenericHTMLFrameElement.h12
-rw-r--r--dom/html/test/forms/mochitest.toml2
-rw-r--r--dom/html/test/forms/test_input_datetime_preventDefault.html23
34 files changed, 341 insertions, 201 deletions
diff --git a/dom/html/HTMLAnchorElement.cpp b/dom/html/HTMLAnchorElement.cpp
index fffe8d9545..8c1689fe7d 100644
--- a/dom/html/HTMLAnchorElement.cpp
+++ b/dom/html/HTMLAnchorElement.cpp
@@ -14,7 +14,7 @@
#include "nsCOMPtr.h"
#include "nsContentUtils.h"
#include "nsGkAtoms.h"
-#include "nsAttrValueOrString.h"
+#include "mozilla/FocusModel.h"
#include "mozilla/dom/Document.h"
#include "nsPresContext.h"
#include "nsIURI.h"
@@ -68,10 +68,7 @@ nsresult HTMLAnchorElement::BindToTree(BindContext& aContext,
Link::BindToTree(aContext);
// Prefetch links
- if (IsInComposedDoc()) {
- TryDNSPrefetch(*this);
- }
-
+ MaybeTryDNSPrefetch();
return rv;
}
@@ -89,10 +86,10 @@ void HTMLAnchorElement::UnbindFromTree(UnbindContext& aContext) {
Link::UnbindFromTree();
}
-bool HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+bool HTMLAnchorElement::IsHTMLFocusable(IsFocusableFlags aFlags,
+ bool* aIsFocusable,
int32_t* aTabIndex) {
- if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable,
- aTabIndex)) {
+ if (nsGenericHTMLElement::IsHTMLFocusable(aFlags, aIsFocusable, aTabIndex)) {
return true;
}
@@ -122,7 +119,7 @@ bool HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
}
}
- if ((sTabFocusModel & eTabFocus_linksMask) == 0) {
+ if (!FocusModel::IsTabFocusable(TabFocusableType::Links)) {
*aTabIndex = -1;
}
*aIsFocusable = true;
@@ -194,8 +191,8 @@ void HTMLAnchorElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
if (aNamespaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::href) {
Link::ResetLinkState(aNotify, !!aValue);
- if (aValue && IsInComposedDoc()) {
- TryDNSPrefetch(*this);
+ if (aValue) {
+ MaybeTryDNSPrefetch();
}
}
}
@@ -210,4 +207,22 @@ void HTMLAnchorElement::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
*aNodeSize += Link::SizeOfExcludingThis(aSizes.mState);
}
+void HTMLAnchorElement::MaybeTryDNSPrefetch() {
+ if (IsInComposedDoc()) {
+ nsIURI* docURI = OwnerDoc()->GetDocumentURI();
+ if (!docURI) {
+ return;
+ }
+
+ bool docIsHttps = docURI->SchemeIs("https");
+ if ((docIsHttps &&
+ StaticPrefs::dom_prefetch_dns_for_anchor_https_document()) ||
+ (!docIsHttps &&
+ StaticPrefs::dom_prefetch_dns_for_anchor_http_document())) {
+ TryDNSPrefetch(
+ *this, HTMLDNSPrefetch::PrefetchSource::AnchorSpeculativePrefetch);
+ }
+ }
+}
+
} // namespace mozilla::dom
diff --git a/dom/html/HTMLAnchorElement.h b/dom/html/HTMLAnchorElement.h
index 88669549e3..f7f808de05 100644
--- a/dom/html/HTMLAnchorElement.h
+++ b/dom/html/HTMLAnchorElement.h
@@ -48,7 +48,7 @@ class HTMLAnchorElement final : public nsGenericHTMLElement,
nsresult BindToTree(BindContext&, nsINode& aParent) override;
void UnbindFromTree(UnbindContext&) override;
- bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+ bool IsHTMLFocusable(IsFocusableFlags, bool* aIsFocusable,
int32_t* aTabIndex) override;
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
@@ -189,6 +189,8 @@ class HTMLAnchorElement final : public nsGenericHTMLElement,
protected:
virtual ~HTMLAnchorElement();
+ void MaybeTryDNSPrefetch();
+
JSObject* WrapNode(JSContext*, JS::Handle<JSObject*> aGivenProto) override;
RefPtr<nsDOMTokenList> mRelList;
};
diff --git a/dom/html/HTMLButtonElement.cpp b/dom/html/HTMLButtonElement.cpp
index 0d9cc921ad..7d7fa7f548 100644
--- a/dom/html/HTMLButtonElement.cpp
+++ b/dom/html/HTMLButtonElement.cpp
@@ -12,13 +12,13 @@
#include "nsAttrValueInlines.h"
#include "nsIContentInlines.h"
#include "nsGkAtoms.h"
-#include "nsStyleConsts.h"
#include "nsPresContext.h"
#include "nsIFormControl.h"
#include "nsIFrame.h"
#include "nsIFormControlFrame.h"
#include "mozilla/dom/Document.h"
#include "mozilla/ContentEvents.h"
+#include "mozilla/FocusModel.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/MouseEvents.h"
@@ -113,15 +113,14 @@ void HTMLButtonElement::GetType(nsAString& aType) {
int32_t HTMLButtonElement::TabIndexDefault() { return 0; }
-bool HTMLButtonElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+bool HTMLButtonElement::IsHTMLFocusable(IsFocusableFlags aFlags,
+ bool* aIsFocusable,
int32_t* aTabIndex) {
if (nsGenericHTMLFormControlElementWithState::IsHTMLFocusable(
- aWithMouse, aIsFocusable, aTabIndex)) {
+ aFlags, aIsFocusable, aTabIndex)) {
return true;
}
-
- *aIsFocusable = IsFormControlDefaultFocusable(aWithMouse) && !IsDisabled();
-
+ *aIsFocusable = IsFormControlDefaultFocusable(aFlags) && !IsDisabled();
return false;
}
diff --git a/dom/html/HTMLButtonElement.h b/dom/html/HTMLButtonElement.h
index b1a5c53f64..d4bfc3649d 100644
--- a/dom/html/HTMLButtonElement.h
+++ b/dom/html/HTMLButtonElement.h
@@ -87,7 +87,7 @@ class HTMLButtonElement final : public nsGenericHTMLFormControlElementWithState,
nsAttrValue& aResult) override;
// nsGenericHTMLElement
- bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+ bool IsHTMLFocusable(IsFocusableFlags, bool* aIsFocusable,
int32_t* aTabIndex) override;
bool IsDisabledForEvents(WidgetEvent* aEvent) override;
diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp
index 93a7bb3787..a138f2f30a 100644
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -857,6 +857,20 @@ already_AddRefed<CanvasCaptureMediaStream> HTMLCanvasElement::CaptureStream(
return nullptr;
}
+ // Check if we transferred the OffscreenCanvas to a DOM worker. This is not
+ // defined by the spec yet, so it is better to fail now than implement
+ // something not compliant:
+ // https://github.com/w3c/mediacapture-fromelement/issues/65
+ // https://github.com/w3c/mediacapture-extensions/pull/26
+ // https://github.com/web-platform-tests/wpt/issues/21102
+ if (mOffscreenDisplay &&
+ NS_WARN_IF(!mOffscreenDisplay->CanElementCaptureStream())) {
+ aRv.ThrowNotSupportedError(
+ "Capture stream not supported when OffscreenCanvas transferred to "
+ "worker");
+ return nullptr;
+ }
+
auto stream = MakeRefPtr<CanvasCaptureMediaStream>(window, this);
nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h
index 586a43fedc..d5a4e019ff 100644
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -356,6 +356,8 @@ class HTMLCanvasElement final : public nsGenericHTMLElement,
layers::ImageContainer* GetImageContainer() const { return mImageContainer; }
+ bool UsingCaptureStream() const { return !!mRequestedFrameRefreshObserver; }
+
protected:
bool mResetLayer;
bool mMaybeModified; // we fetched the context, so we may have written to the
diff --git a/dom/html/HTMLDNSPrefetch.cpp b/dom/html/HTMLDNSPrefetch.cpp
index a4043195fe..779ed23a15 100644
--- a/dom/html/HTMLDNSPrefetch.cpp
+++ b/dom/html/HTMLDNSPrefetch.cpp
@@ -105,7 +105,7 @@ class DeferredDNSPrefetches final : public nsIWebProgressListener,
void Flush();
void SubmitQueue();
- void SubmitQueueEntry(Element&, nsIDNSService::DNSFlags aFlags);
+ void SubmitQueueEntry(Element& aElement, nsIDNSService::DNSFlags aFlags);
uint16_t mHead;
uint16_t mTail;
@@ -206,8 +206,8 @@ nsIDNSService::DNSFlags HTMLDNSPrefetch::PriorityToDNSServiceFlags(
return nsIDNSService::RESOLVE_DEFAULT_FLAGS;
}
-nsresult HTMLDNSPrefetch::Prefetch(SupportsDNSPrefetch& aSupports,
- Element& aElement, Priority aPriority) {
+nsresult HTMLDNSPrefetch::DeferPrefetch(SupportsDNSPrefetch& aSupports,
+ Element& aElement, Priority aPriority) {
MOZ_ASSERT(&ToSupportsDNSPrefetch(aElement) == &aSupports);
if (!(sInitialized && sPrefetches && sDNSListener) || !EnsureDNSService()) {
return NS_ERROR_NOT_AVAILABLE;
@@ -362,10 +362,84 @@ void HTMLDNSPrefetch::ElementDestroyed(Element& aElement,
}
}
-void SupportsDNSPrefetch::TryDNSPrefetch(Element& aOwner) {
+void HTMLDNSPrefetch::SendRequest(Element& aElement,
+ nsIDNSService::DNSFlags aFlags) {
+ auto& supports = ToSupportsDNSPrefetch(aElement);
+
+ nsIURI* uri = supports.GetURIForDNSPrefetch(aElement);
+ if (!uri) {
+ return;
+ }
+
+ nsAutoCString hostName;
+ uri->GetAsciiHost(hostName);
+ if (hostName.IsEmpty()) {
+ return;
+ }
+
+ bool isLocalResource = false;
+ nsresult rv = NS_URIChainHasFlags(
+ uri, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE, &isLocalResource);
+ if (NS_FAILED(rv) || isLocalResource) {
+ return;
+ }
+
+ OriginAttributes oa;
+ StoragePrincipalHelper::GetOriginAttributesForNetworkState(
+ aElement.OwnerDoc(), oa);
+
+ bool isHttps = uri->SchemeIs("https");
+
+ if (IsNeckoChild()) {
+ // during shutdown gNeckoChild might be null
+ if (gNeckoChild) {
+ gNeckoChild->SendHTMLDNSPrefetch(NS_ConvertUTF8toUTF16(hostName), isHttps,
+ oa, aFlags);
+ }
+ } else {
+ nsCOMPtr<nsICancelable> tmpOutstanding;
+
+ rv = sDNSService->AsyncResolveNative(
+ hostName, nsIDNSService::RESOLVE_TYPE_DEFAULT,
+ aFlags | nsIDNSService::RESOLVE_SPECULATE, nullptr, sDNSListener,
+ nullptr, oa, getter_AddRefs(tmpOutstanding));
+ if (NS_FAILED(rv)) {
+ return;
+ }
+
+ // Fetch HTTPS RR if needed.
+ if (StaticPrefs::network_dns_upgrade_with_https_rr() ||
+ StaticPrefs::network_dns_use_https_rr_as_altsvc()) {
+ sDNSService->AsyncResolveNative(
+ hostName, nsIDNSService::RESOLVE_TYPE_HTTPSSVC,
+ aFlags | nsIDNSService::RESOLVE_SPECULATE, nullptr, sDNSListener,
+ nullptr, oa, getter_AddRefs(tmpOutstanding));
+ }
+ }
+
+ // Tell element that deferred prefetch was requested.
+ supports.DNSPrefetchRequestStarted();
+}
+
+void SupportsDNSPrefetch::TryDNSPrefetch(
+ Element& aOwner, HTMLDNSPrefetch::PrefetchSource aSource) {
MOZ_ASSERT(aOwner.IsInComposedDoc());
if (HTMLDNSPrefetch::IsAllowed(aOwner.OwnerDoc())) {
- HTMLDNSPrefetch::Prefetch(*this, aOwner, HTMLDNSPrefetch::Priority::Low);
+ if (!(sInitialized && sDNSListener) || !EnsureDNSService()) {
+ return;
+ }
+
+ if (aSource == HTMLDNSPrefetch::PrefetchSource::AnchorSpeculativePrefetch) {
+ HTMLDNSPrefetch::DeferPrefetch(*this, aOwner,
+ HTMLDNSPrefetch::Priority::Low);
+ } else if (aSource == HTMLDNSPrefetch::PrefetchSource::LinkDnsPrefetch) {
+ HTMLDNSPrefetch::SendRequest(
+ aOwner, GetDNSFlagsFromElement(aOwner) |
+ HTMLDNSPrefetch::PriorityToDNSServiceFlags(
+ HTMLDNSPrefetch::Priority::High));
+ } else {
+ MOZ_ASSERT_UNREACHABLE("Unknown DNS prefetch type");
+ }
}
}
@@ -470,59 +544,7 @@ void DeferredDNSPrefetches::SubmitQueueEntry(Element& aElement,
return;
}
- nsIURI* uri = supports.GetURIForDNSPrefetch(aElement);
- if (!uri) {
- return;
- }
-
- nsAutoCString hostName;
- uri->GetAsciiHost(hostName);
- if (hostName.IsEmpty()) {
- return;
- }
-
- bool isLocalResource = false;
- nsresult rv = NS_URIChainHasFlags(
- uri, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE, &isLocalResource);
- if (NS_FAILED(rv) || isLocalResource) {
- return;
- }
-
- OriginAttributes oa;
- StoragePrincipalHelper::GetOriginAttributesForNetworkState(
- aElement.OwnerDoc(), oa);
-
- bool isHttps = uri->SchemeIs("https");
-
- if (IsNeckoChild()) {
- // during shutdown gNeckoChild might be null
- if (gNeckoChild) {
- gNeckoChild->SendHTMLDNSPrefetch(NS_ConvertUTF8toUTF16(hostName), isHttps,
- oa, mEntries[mTail].mFlags);
- }
- } else {
- nsCOMPtr<nsICancelable> tmpOutstanding;
-
- rv = sDNSService->AsyncResolveNative(
- hostName, nsIDNSService::RESOLVE_TYPE_DEFAULT,
- mEntries[mTail].mFlags | nsIDNSService::RESOLVE_SPECULATE, nullptr,
- sDNSListener, nullptr, oa, getter_AddRefs(tmpOutstanding));
- if (NS_FAILED(rv)) {
- return;
- }
-
- // Fetch HTTPS RR if needed.
- if (StaticPrefs::network_dns_upgrade_with_https_rr() ||
- StaticPrefs::network_dns_use_https_rr_as_altsvc()) {
- sDNSService->AsyncResolveNative(
- hostName, nsIDNSService::RESOLVE_TYPE_HTTPSSVC,
- mEntries[mTail].mFlags | nsIDNSService::RESOLVE_SPECULATE, nullptr,
- sDNSListener, nullptr, oa, getter_AddRefs(tmpOutstanding));
- }
- }
-
- // Tell element that deferred prefetch was requested.
- supports.DNSPrefetchRequestStarted();
+ HTMLDNSPrefetch::SendRequest(aElement, aFlags);
}
void DeferredDNSPrefetches::Activate() {
diff --git a/dom/html/HTMLDNSPrefetch.h b/dom/html/HTMLDNSPrefetch.h
index 5820a6ecb2..5fd263d3f5 100644
--- a/dom/html/HTMLDNSPrefetch.h
+++ b/dom/html/HTMLDNSPrefetch.h
@@ -55,7 +55,13 @@ class HTMLDNSPrefetch {
Medium,
High,
};
- static nsresult Prefetch(SupportsDNSPrefetch&, Element&, Priority);
+ enum class PrefetchSource {
+ LinkDnsPrefetch,
+ AnchorSpeculativePrefetch,
+ };
+ static nsresult DeferPrefetch(SupportsDNSPrefetch& aSupports,
+ Element& aElement, Priority aPriority);
+ static void SendRequest(Element& aElement, nsIDNSService::DNSFlags aFlags);
static nsresult Prefetch(
const nsAString& host, bool isHttps,
const OriginAttributes& aPartitionedPrincipalOriginAttributes,
@@ -68,9 +74,9 @@ class HTMLDNSPrefetch {
nsresult aReason);
static void ElementDestroyed(Element&, SupportsDNSPrefetch&);
- private:
static nsIDNSService::DNSFlags PriorityToDNSServiceFlags(Priority);
+ private:
static nsresult Prefetch(
const nsAString& host, bool isHttps,
const OriginAttributes& aPartitionedPrincipalOriginAttributes,
@@ -114,8 +120,8 @@ class SupportsDNSPrefetch {
mDNSPrefetchDeferred(false),
mDestroyedCalled(false) {}
- void CancelDNSPrefetch(Element&);
- void TryDNSPrefetch(Element&);
+ void CancelDNSPrefetch(Element& aOwner);
+ void TryDNSPrefetch(Element& aOwner, HTMLDNSPrefetch::PrefetchSource aSource);
// This MUST be called on the destructor of the Element subclass.
// Our own destructor ensures that.
diff --git a/dom/html/HTMLDetailsElement.h b/dom/html/HTMLDetailsElement.h
index 2c7ed56d98..03df1f07a1 100644
--- a/dom/html/HTMLDetailsElement.h
+++ b/dom/html/HTMLDetailsElement.h
@@ -48,7 +48,7 @@ class HTMLDetailsElement final : public nsGenericHTMLElement {
void ToggleOpen() { SetOpen(!Open(), IgnoreErrors()); }
- virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
+ void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
void HandleInvokeInternal(nsAtom* aAction, ErrorResult& aRv) override;
diff --git a/dom/html/HTMLDialogElement.cpp b/dom/html/HTMLDialogElement.cpp
index cd36201182..3e717534d2 100644
--- a/dom/html/HTMLDialogElement.cpp
+++ b/dom/html/HTMLDialogElement.cpp
@@ -157,7 +157,7 @@ void HTMLDialogElement::FocusDialog() {
RefPtr<Element> control = HasAttr(nsGkAtoms::autofocus)
? this
- : GetFocusDelegate(false /* aWithMouse */);
+ : GetFocusDelegate(IsFocusableFlags(0));
// If there isn't one of those either, then let control be subject.
if (!control) {
diff --git a/dom/html/HTMLEmbedElement.cpp b/dom/html/HTMLEmbedElement.cpp
index 39582063a7..7cd9fd916c 100644
--- a/dom/html/HTMLEmbedElement.cpp
+++ b/dom/html/HTMLEmbedElement.cpp
@@ -133,8 +133,8 @@ int32_t HTMLEmbedElement::TabIndexDefault() {
return Type() == ObjectType::Document ? 0 : -1;
}
-bool HTMLEmbedElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
- int32_t* aTabIndex) {
+bool HTMLEmbedElement::IsHTMLFocusable(IsFocusableFlags aFlags,
+ bool* aIsFocusable, int32_t* aTabIndex) {
// Has non-plugin content: let the plugin decide what to do in terms of
// internal focus from mouse clicks
if (aTabIndex) {
diff --git a/dom/html/HTMLEmbedElement.h b/dom/html/HTMLEmbedElement.h
index 8e7bcd4166..4d7f1496e8 100644
--- a/dom/html/HTMLEmbedElement.h
+++ b/dom/html/HTMLEmbedElement.h
@@ -38,7 +38,7 @@ class HTMLEmbedElement final : public nsGenericHTMLElement,
nsresult BindToTree(BindContext&, nsINode& aParent) override;
void UnbindFromTree(UnbindContext&) override;
- bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+ bool IsHTMLFocusable(IsFocusableFlags, bool* aIsFocusable,
int32_t* aTabIndex) override;
int32_t TabIndexDefault() override;
diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp
index 691216d152..597d7f4b22 100644
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -6,6 +6,7 @@
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/PresShell.h"
+#include "mozilla/FocusModel.h"
#include "mozilla/dom/BindContext.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/HTMLImageElementBinding.h"
@@ -488,13 +489,13 @@ nsINode* HTMLImageElement::GetScopeChainParent() const {
return nsGenericHTMLElement::GetScopeChainParent();
}
-bool HTMLImageElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
- int32_t* aTabIndex) {
+bool HTMLImageElement::IsHTMLFocusable(IsFocusableFlags aFlags,
+ bool* aIsFocusable, int32_t* aTabIndex) {
int32_t tabIndex = TabIndex();
if (IsInComposedDoc() && FindImageMap()) {
// Use tab index on individual map areas.
- *aTabIndex = (sTabFocusModel & eTabFocus_linksMask) ? 0 : -1;
+ *aTabIndex = FocusModel::IsTabFocusable(TabFocusableType::Links) ? 0 : -1;
// Image map is not focusable itself, but flag as tabbable
// so that image map areas get walked into.
*aIsFocusable = false;
@@ -502,8 +503,10 @@ bool HTMLImageElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
}
// Can be in tab order if tabindex >=0 and form controls are tabbable.
- *aTabIndex = (sTabFocusModel & eTabFocus_formElementsMask) ? tabIndex : -1;
- *aIsFocusable = IsFormControlDefaultFocusable(aWithMouse) &&
+ *aTabIndex = FocusModel::IsTabFocusable(TabFocusableType::FormElements)
+ ? tabIndex
+ : -1;
+ *aIsFocusable = IsFormControlDefaultFocusable(aFlags) &&
(tabIndex >= 0 || GetTabIndexAttrValue().isSome());
return false;
diff --git a/dom/html/HTMLImageElement.h b/dom/html/HTMLImageElement.h
index bf41c68d40..1097d1fb04 100644
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -70,7 +70,7 @@ class HTMLImageElement final : public nsGenericHTMLElement,
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
nsINode* GetScopeChainParent() const override;
- bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+ bool IsHTMLFocusable(IsFocusableFlags, bool* aIsFocusable,
int32_t* aTabIndex) override;
nsresult BindToTree(BindContext&, nsINode& aParent) override;
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp
index 958601616b..9a7f7e02bd 100644
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -1986,18 +1986,21 @@ Decimal HTMLInputElement::GetStepBase() const {
return kDefaultStepBase;
}
-nsresult HTMLInputElement::GetValueIfStepped(int32_t aStep,
- StepCallerType aCallerType,
- Decimal* aNextStep) {
+Decimal HTMLInputElement::GetValueIfStepped(int32_t aStep,
+ StepCallerType aCallerType,
+ ErrorResult& aRv) {
+ constexpr auto kNaN = Decimal::nan();
if (!DoStepDownStepUpApply()) {
- return NS_ERROR_DOM_INVALID_STATE_ERR;
+ aRv.ThrowInvalidStateError("Step doesn't apply to this input type");
+ return kNaN;
}
Decimal stepBase = GetStepBase();
Decimal step = GetStep();
if (step == kStepAny) {
- if (aCallerType != CALLED_FOR_USER_EVENT) {
- return NS_ERROR_DOM_INVALID_STATE_ERR;
+ if (aCallerType != StepCallerType::ForUserEvent) {
+ aRv.ThrowInvalidStateError("Can't step an input with step=\"any\"");
+ return kNaN;
}
// Allow the spin buttons and up/down arrow keys to do something sensible:
step = GetDefaultStep();
@@ -2015,7 +2018,7 @@ nsresult HTMLInputElement::GetValueIfStepped(int32_t aStep,
// adjustment to align maximum on a step, or else (if we adjusted
// maximum) there is no valid step between minimum and the unadjusted
// maximum.
- return NS_OK;
+ return kNaN;
}
}
}
@@ -2062,25 +2065,20 @@ nsresult HTMLInputElement::GetValueIfStepped(int32_t aStep,
(aStep < 0 && value > valueBeforeStepping))) {
// We don't want step-up to effectively step down, or step-down to
// effectively step up, so return;
- return NS_OK;
+ return kNaN;
}
- *aNextStep = value;
- return NS_OK;
+ return value;
}
-nsresult HTMLInputElement::ApplyStep(int32_t aStep) {
- Decimal nextStep = Decimal::nan(); // unchanged if value will not change
-
- nsresult rv = GetValueIfStepped(aStep, CALLED_FOR_SCRIPT, &nextStep);
-
- if (NS_SUCCEEDED(rv) && nextStep.isFinite()) {
- // We know we're not a file input, so the caller type does not matter; just
- // pass "not system" to be safe.
- SetValue(nextStep, CallerType::NonSystem);
+void HTMLInputElement::ApplyStep(int32_t aStep, ErrorResult& aRv) {
+ Decimal nextStep = GetValueIfStepped(aStep, StepCallerType::ForScript, aRv);
+ if (aRv.Failed() || !nextStep.isFinite()) {
+ return;
}
-
- return rv;
+ // We know we're not a file input, so the caller type does not matter; just
+ // pass "not system" to be safe.
+ SetValue(nextStep, CallerType::NonSystem);
}
bool HTMLInputElement::IsDateTimeInputType(FormControlType aType) {
@@ -3520,11 +3518,9 @@ void HTMLInputElement::StepNumberControlForUserEvent(int32_t aDirection) {
}
}
- Decimal newValue = Decimal::nan(); // unchanged if value will not change
-
- nsresult rv = GetValueIfStepped(aDirection, CALLED_FOR_USER_EVENT, &newValue);
-
- if (NS_FAILED(rv) || !newValue.isFinite()) {
+ Decimal newValue = GetValueIfStepped(aDirection, StepCallerType::ForUserEvent,
+ IgnoreErrors());
+ if (!newValue.isFinite()) {
return; // value should not or will not change
}
@@ -3794,6 +3790,12 @@ nsresult HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
if (mType == FormControlType::InputRadio && keyEvent->IsTrusted() &&
!keyEvent->IsAlt() && !keyEvent->IsControl() &&
!keyEvent->IsMeta()) {
+ // Radio button navigation needs to check visibility, so flush
+ // to ensure visibility is up to date.
+ if (Document* doc = GetComposedDoc()) {
+ doc->FlushPendingNotifications(
+ FlushType::EnsurePresShellInitAndFrames);
+ }
rv = MaybeHandleRadioButtonNavigation(aVisitor, keyEvent->mKeyCode);
}
@@ -6427,10 +6429,10 @@ void HTMLInputElement::RemoveFromRadioGroup() {
mRadioGroupContainer = nullptr;
}
-bool HTMLInputElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
- int32_t* aTabIndex) {
+bool HTMLInputElement::IsHTMLFocusable(IsFocusableFlags aFlags,
+ bool* aIsFocusable, int32_t* aTabIndex) {
if (nsGenericHTMLFormControlElementWithState::IsHTMLFocusable(
- aWithMouse, aIsFocusable, aTabIndex)) {
+ aFlags, aIsFocusable, aTabIndex)) {
return true;
}
@@ -6444,7 +6446,7 @@ bool HTMLInputElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
return false;
}
- const bool defaultFocusable = IsFormControlDefaultFocusable(aWithMouse);
+ const bool defaultFocusable = IsFormControlDefaultFocusable(aFlags);
if (CreatesDateTimeWidget()) {
if (aTabIndex) {
// We only want our native anonymous child to be tabable to, not ourself.
diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h
index 2c90aa83fe..aa8bff8864 100644
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -162,7 +162,7 @@ class HTMLInputElement final : public TextControlElement,
void FieldSetDisabledChanged(bool aNotify) override;
// nsIContent
- bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+ bool IsHTMLFocusable(IsFocusableFlags, bool* aIsFocusable,
int32_t* aTabIndex) override;
bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
@@ -663,9 +663,8 @@ class HTMLInputElement final : public TextControlElement,
SetUnsignedIntAttr(nsGkAtoms::width, aValue, 0, aRv);
}
- void StepUp(int32_t aN, ErrorResult& aRv) { aRv = ApplyStep(aN); }
-
- void StepDown(int32_t aN, ErrorResult& aRv) { aRv = ApplyStep(-aN); }
+ void StepUp(int32_t aN, ErrorResult& aRv) { ApplyStep(aN, aRv); }
+ void StepDown(int32_t aN, ErrorResult& aRv) { ApplyStep(-aN, aRv); }
/**
* Returns the current step value.
@@ -1311,22 +1310,17 @@ class HTMLInputElement final : public TextControlElement,
*/
Decimal GetDefaultStep() const;
- enum StepCallerType { CALLED_FOR_USER_EVENT, CALLED_FOR_SCRIPT };
+ enum class StepCallerType { ForUserEvent, ForScript };
/**
- * Sets the aValue outparam to the value that this input would take if
- * someone tries to step aStep steps and this input's value would change as
- * a result. Leaves aValue untouched if this inputs value would not change
- * (e.g. already at max, and asking for the next step up).
+ * Returns the value that this input would take if someone tries to step
+ * aStepCount steps and this input's value would change as a result, or
+ * Decimal::nan() otherwise (e.g., if this inputs value would not change due
+ * to it being already at max, and asking for the next step up).
*
* Negative aStep means step down, positive means step up.
- *
- * Returns NS_OK or else the error values that should be thrown if this call
- * was initiated by a stepUp()/stepDown() call from script under conditions
- * that such a call should throw.
*/
- nsresult GetValueIfStepped(int32_t aStepCount, StepCallerType aCallerType,
- Decimal* aNextStep);
+ Decimal GetValueIfStepped(int32_t aStepCount, StepCallerType, ErrorResult&);
/**
* Apply a step change from stepUp or stepDown by multiplying aStep by the
@@ -1334,7 +1328,7 @@ class HTMLInputElement final : public TextControlElement,
*
* @param aStep The value used to be multiplied against the step value.
*/
- nsresult ApplyStep(int32_t aStep);
+ void ApplyStep(int32_t aStep, ErrorResult&);
/**
* Returns if the current type is an experimental mobile type.
diff --git a/dom/html/HTMLLinkElement.cpp b/dom/html/HTMLLinkElement.cpp
index cb316a6f7b..30994cf964 100644
--- a/dom/html/HTMLLinkElement.cpp
+++ b/dom/html/HTMLLinkElement.cpp
@@ -555,7 +555,7 @@ void HTMLLinkElement::
}
if (linkTypes & eDNS_PREFETCH) {
- TryDNSPrefetch(*this);
+ TryDNSPrefetch(*this, HTMLDNSPrefetch::PrefetchSource::LinkDnsPrefetch);
}
}
diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp
index 877f3ec3ba..2db729fa2f 100644
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -318,7 +318,7 @@ class HTMLMediaElement::MediaControlKeyListener final
MOZ_INIT_OUTSIDE_CTOR explicit MediaControlKeyListener(
HTMLMediaElement* aElement)
- : mElement(aElement) {
+ : mElement(aElement), mElementId(nsID::GenerateUUID()) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aElement);
}
@@ -411,6 +411,33 @@ class HTMLMediaElement::MediaControlKeyListener final
}
}
+ void NotifyMediaPositionState() {
+ if (!IsStarted()) {
+ return;
+ }
+
+ MOZ_ASSERT(mControlAgent);
+ auto* owner = Owner();
+ PositionState state(owner->Duration(), owner->PlaybackRate(),
+ owner->CurrentTime(), TimeStamp::Now());
+ MEDIACONTROL_LOG(
+ "Notify media position state (duration=%f, playbackRate=%f, "
+ "position=%f)",
+ state.mDuration, state.mPlaybackRate,
+ state.mLastReportedPlaybackPosition);
+ mControlAgent->UpdateGuessedPositionState(mOwnerBrowsingContextId,
+ mElementId, Some(state));
+ }
+
+ void Shutdown() {
+ StopIfNeeded();
+ if (!mControlAgent) {
+ return;
+ }
+ mControlAgent->UpdateGuessedPositionState(mOwnerBrowsingContextId,
+ mElementId, Nothing());
+ }
+
// This method can be called before the listener starts, which would cache
// the audible state and update after the listener starts.
void UpdateMediaAudibleState(bool aIsOwnerAudible) {
@@ -543,6 +570,10 @@ class HTMLMediaElement::MediaControlKeyListener final
MOZ_ASSERT(mState != aState, "Should not notify same state again!");
mState = aState;
mControlAgent->NotifyMediaPlaybackChanged(mOwnerBrowsingContextId, mState);
+
+ if (aState == MediaPlaybackState::ePlayed) {
+ NotifyMediaPositionState();
+ }
}
void NotifyAudibleStateChanged(MediaAudibleState aState) {
@@ -557,6 +588,7 @@ class HTMLMediaElement::MediaControlKeyListener final
bool mIsPictureInPictureEnabled = false;
bool mIsOwnerAudible = false;
MOZ_INIT_OUTSIDE_CTOR uint64_t mOwnerBrowsingContextId;
+ const nsID mElementId;
};
class HTMLMediaElement::MediaStreamTrackListener
@@ -994,7 +1026,7 @@ class HTMLMediaElement::MediaStreamRenderer {
graph->CreateSourceTrack(MediaSegment::AUDIO));
}
- void ResolveAudioDevicePromiseIfExists(const char* aMethodName) {
+ void ResolveAudioDevicePromiseIfExists(StaticString aMethodName) {
if (mSetAudioDevicePromise.IsEmpty()) {
return;
}
@@ -2065,7 +2097,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement,
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSeekDOMPromise)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSetMediaKeysDOMPromise)
if (tmp->mMediaControlKeyListener) {
- tmp->mMediaControlKeyListener->StopIfNeeded();
+ tmp->mMediaControlKeyListener->Shutdown();
}
if (tmp->mEventBlocker) {
tmp->mEventBlocker->Shutdown();
@@ -3384,6 +3416,8 @@ void HTMLMediaElement::Seek(double aTime, SeekTarget::Type aSeekType,
// We changed whether we're seeking so we need to AddRemoveSelfReference.
AddRemoveSelfReference();
+
+ mMediaControlKeyListener->NotifyMediaPositionState();
}
double HTMLMediaElement::Duration() const {
@@ -4804,10 +4838,9 @@ void HTMLMediaElement::DoneCreatingElement() {
}
}
-bool HTMLMediaElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
- int32_t* aTabIndex) {
- if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable,
- aTabIndex)) {
+bool HTMLMediaElement::IsHTMLFocusable(IsFocusableFlags aFlags,
+ bool* aIsFocusable, int32_t* aTabIndex) {
+ if (nsGenericHTMLElement::IsHTMLFocusable(aFlags, aIsFocusable, aTabIndex)) {
return true;
}
@@ -6871,6 +6904,7 @@ void HTMLMediaElement::SetPlaybackRate(double aPlaybackRate, ErrorResult& aRv) {
mDecoder->SetPlaybackRate(ClampPlaybackRate(mPlaybackRate));
}
DispatchAsyncEvent(u"ratechange"_ns);
+ mMediaControlKeyListener->NotifyMediaPositionState();
}
void HTMLMediaElement::SetPreservesPitch(bool aPreservesPitch) {
diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h
index 6c159a7971..2065796b08 100644
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -196,24 +196,24 @@ class HTMLMediaElement : public nsGenericHTMLElement,
void NodeInfoChanged(Document* aOldDoc) override;
- virtual bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
- const nsAString& aValue,
- nsIPrincipal* aMaybeScriptedPrincipal,
- nsAttrValue& aResult) override;
+ bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
+ const nsAString& aValue,
+ nsIPrincipal* aMaybeScriptedPrincipal,
+ nsAttrValue& aResult) override;
- virtual nsresult BindToTree(BindContext&, nsINode& aParent) override;
- virtual void UnbindFromTree(UnbindContext&) override;
- virtual void DoneCreatingElement() override;
+ nsresult BindToTree(BindContext&, nsINode& aParent) override;
+ void UnbindFromTree(UnbindContext&) override;
+ void DoneCreatingElement() override;
- virtual bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
- int32_t* aTabIndex) override;
- virtual int32_t TabIndexDefault() override;
+ bool IsHTMLFocusable(IsFocusableFlags, bool* aIsFocusable,
+ int32_t* aTabIndex) override;
+ int32_t TabIndexDefault() override;
// Called by the video decoder object, on the main thread,
// when it has read the metadata containing video dimensions,
// etc.
- virtual void MetadataLoaded(const MediaInfo* aInfo,
- UniquePtr<const MetadataTags> aTags) final;
+ void MetadataLoaded(const MediaInfo* aInfo,
+ UniquePtr<const MetadataTags> aTags) final;
// Called by the decoder object, on the main thread,
// when it has read the first frame of the video or audio.
diff --git a/dom/html/HTMLObjectElement.cpp b/dom/html/HTMLObjectElement.cpp
index f77a1f3ba2..d449e48407 100644
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -135,7 +135,8 @@ void HTMLObjectElement::AfterMaybeChangeAttr(int32_t aNamespaceID,
}));
}
-bool HTMLObjectElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+bool HTMLObjectElement::IsHTMLFocusable(IsFocusableFlags aFlags,
+ bool* aIsFocusable,
int32_t* aTabIndex) {
// TODO: this should probably be managed directly by IsHTMLFocusable.
// See bug 597242.
diff --git a/dom/html/HTMLObjectElement.h b/dom/html/HTMLObjectElement.h
index 00bcbc70d5..4e4eaf181e 100644
--- a/dom/html/HTMLObjectElement.h
+++ b/dom/html/HTMLObjectElement.h
@@ -42,7 +42,7 @@ class HTMLObjectElement final : public nsGenericHTMLFormControlElement,
nsresult BindToTree(BindContext&, nsINode& aParent) override;
void UnbindFromTree(UnbindContext&) override;
- bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+ bool IsHTMLFocusable(IsFocusableFlags, bool* aIsFocusable,
int32_t* aTabIndex) override;
// Overriden nsIFormControl methods
diff --git a/dom/html/HTMLSelectElement.cpp b/dom/html/HTMLSelectElement.cpp
index 6ca4209cd9..7a1b5ccf0d 100644
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -1026,10 +1026,11 @@ void HTMLSelectElement::SetValue(const nsAString& aValue) {
int32_t HTMLSelectElement::TabIndexDefault() { return 0; }
-bool HTMLSelectElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+bool HTMLSelectElement::IsHTMLFocusable(IsFocusableFlags aFlags,
+ bool* aIsFocusable,
int32_t* aTabIndex) {
if (nsGenericHTMLFormControlElementWithState::IsHTMLFocusable(
- aWithMouse, aIsFocusable, aTabIndex)) {
+ aFlags, aIsFocusable, aTabIndex)) {
return true;
}
diff --git a/dom/html/HTMLSelectElement.h b/dom/html/HTMLSelectElement.h
index 1ba5dc29f6..401748b9d1 100644
--- a/dom/html/HTMLSelectElement.h
+++ b/dom/html/HTMLSelectElement.h
@@ -198,7 +198,7 @@ class HTMLSelectElement final : public nsGenericHTMLFormControlElementWithState,
// nsIContent
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
- bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+ bool IsHTMLFocusable(IsFocusableFlags, bool* aIsFocusable,
int32_t* aTabIndex) override;
void InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify, ErrorResult& aRv) override;
diff --git a/dom/html/HTMLSharedElement.cpp b/dom/html/HTMLSharedElement.cpp
index 85849f9f79..0dd151f473 100644
--- a/dom/html/HTMLSharedElement.cpp
+++ b/dom/html/HTMLSharedElement.cpp
@@ -85,15 +85,22 @@ static void SetBaseURIUsingFirstBaseWithHref(Document* aDocument,
getter_AddRefs(newBaseURI), href, aDocument,
aDocument->GetFallbackBaseURI());
+ // Vaguely based on
+ // <https://html.spec.whatwg.org/multipage/semantics.html#set-the-frozen-base-url>
+
+ if (newBaseURI && (newBaseURI->SchemeIs("data") ||
+ newBaseURI->SchemeIs("javascript"))) {
+ newBaseURI = nullptr;
+ }
+
// Check if CSP allows this base-uri
- nsresult rv = NS_OK;
nsCOMPtr<nsIContentSecurityPolicy> csp = aDocument->GetCsp();
if (csp && newBaseURI) {
// base-uri is only enforced if explicitly defined in the
// policy - do *not* consult default-src, see:
// http://www.w3.org/TR/CSP2/#directive-default-src
bool cspPermitsBaseURI = true;
- rv = csp->Permits(
+ nsresult rv = csp->Permits(
child->AsElement(), nullptr /* nsICSPEventListener */, newBaseURI,
nsIContentSecurityPolicy::BASE_URI_DIRECTIVE, true /* aSpecific */,
true /* aSendViolationReports */, &cspPermitsBaseURI);
@@ -101,6 +108,7 @@ static void SetBaseURIUsingFirstBaseWithHref(Document* aDocument,
newBaseURI = nullptr;
}
}
+
aDocument->SetBaseURI(newBaseURI);
aDocument->SetChromeXHRDocBaseURI(nullptr);
return;
diff --git a/dom/html/HTMLSummaryElement.cpp b/dom/html/HTMLSummaryElement.cpp
index d1fcf22598..1422bb97be 100644
--- a/dom/html/HTMLSummaryElement.cpp
+++ b/dom/html/HTMLSummaryElement.cpp
@@ -68,10 +68,11 @@ nsresult HTMLSummaryElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
return rv;
}
-bool HTMLSummaryElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+bool HTMLSummaryElement::IsHTMLFocusable(IsFocusableFlags aFlags,
+ bool* aIsFocusable,
int32_t* aTabIndex) {
- bool disallowOverridingFocusability = nsGenericHTMLElement::IsHTMLFocusable(
- aWithMouse, aIsFocusable, aTabIndex);
+ bool disallowOverridingFocusability =
+ nsGenericHTMLElement::IsHTMLFocusable(aFlags, aIsFocusable, aTabIndex);
if (disallowOverridingFocusability || !IsMainSummary()) {
return disallowOverridingFocusability;
diff --git a/dom/html/HTMLSummaryElement.h b/dom/html/HTMLSummaryElement.h
index b70e8eebbb..d61f3813aa 100644
--- a/dom/html/HTMLSummaryElement.h
+++ b/dom/html/HTMLSummaryElement.h
@@ -30,7 +30,7 @@ class HTMLSummaryElement final : public nsGenericHTMLElement {
nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
- bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+ bool IsHTMLFocusable(IsFocusableFlags, bool* aIsFocusable,
int32_t* aTabIndex) override;
int32_t TabIndexDefault() override;
diff --git a/dom/html/HTMLTextAreaElement.cpp b/dom/html/HTMLTextAreaElement.cpp
index be4ba5a891..7624d53b85 100644
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -133,10 +133,11 @@ HTMLTextAreaElement::SelectAll(nsPresContext* aPresContext) {
return NS_OK;
}
-bool HTMLTextAreaElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+bool HTMLTextAreaElement::IsHTMLFocusable(IsFocusableFlags aFlags,
+ bool* aIsFocusable,
int32_t* aTabIndex) {
if (nsGenericHTMLFormControlElementWithState::IsHTMLFocusable(
- aWithMouse, aIsFocusable, aTabIndex)) {
+ aFlags, aIsFocusable, aTabIndex)) {
return true;
}
diff --git a/dom/html/HTMLTextAreaElement.h b/dom/html/HTMLTextAreaElement.h
index 0adaa48b21..d14523ae1c 100644
--- a/dom/html/HTMLTextAreaElement.h
+++ b/dom/html/HTMLTextAreaElement.h
@@ -122,7 +122,7 @@ class HTMLTextAreaElement final : public TextControlElement,
nsresult PreHandleEvent(EventChainVisitor& aVisitor) override;
nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
- bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+ bool IsHTMLFocusable(IsFocusableFlags, bool* aIsFocusable,
int32_t* aTabIndex) override;
void DoneAddingChildren(bool aHaveNotified) override;
diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp
index 1deaf719d3..11383863fd 100644
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -9,6 +9,7 @@
#include "mozilla/EventListenerManager.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/HTMLEditor.h"
+#include "mozilla/FocusModel.h"
#include "mozilla/IMEContentObserver.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/MappedDeclarationsBuilder.h"
@@ -286,7 +287,7 @@ static bool IsOffsetParent(nsIFrame* aFrame) {
struct OffsetResult {
Element* mParent = nullptr;
- CSSIntRect mRect;
+ nsRect mRect;
};
static OffsetResult GetUnretargetedOffsetsFor(const Element& aElement) {
@@ -303,6 +304,7 @@ static OffsetResult GetUnretargetedOffsetsFor(const Element& aElement) {
nsIContent* offsetParent = nullptr;
Element* docElement = aElement.GetComposedDoc()->GetRootElement();
nsIContent* content = frame->GetContent();
+ const auto effectiveZoom = frame->Style()->EffectiveZoom();
if (content &&
(content->IsHTMLElement(nsGkAtoms::body) || content == docElement)) {
@@ -321,6 +323,13 @@ static OffsetResult GetUnretargetedOffsetsFor(const Element& aElement) {
break;
}
+ // WebKit-ism: offsetParent stops at zoom changes.
+ // See https://github.com/w3c/csswg-drafts/issues/10252
+ if (effectiveZoom != parent->Style()->EffectiveZoom()) {
+ offsetParent = content;
+ break;
+ }
+
// Add the parent's origin to our own to get to the
// right coordinate system.
const bool isOffsetParent = !isPositioned && IsOffsetParent(parent);
@@ -370,8 +379,7 @@ static OffsetResult GetUnretargetedOffsetsFor(const Element& aElement) {
// we only care about the size. We just have to use something non-null.
nsRect rcFrame = nsLayoutUtils::GetAllInFlowRectsUnion(frame, frame);
rcFrame.MoveTo(origin);
- return {Element::FromNodeOrNull(offsetParent),
- CSSIntRect::FromAppUnitsRounded(rcFrame)};
+ return {Element::FromNodeOrNull(offsetParent), rcFrame};
}
static bool ShouldBeRetargeted(const Element& aReferenceElement,
@@ -393,20 +401,22 @@ static bool ShouldBeRetargeted(const Element& aReferenceElement,
Element* nsGenericHTMLElement::GetOffsetRect(CSSIntRect& aRect) {
aRect = CSSIntRect();
- if (!GetPrimaryFrame(FlushType::Layout)) {
+ nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
+ if (!frame) {
return nullptr;
}
OffsetResult thisResult = GetUnretargetedOffsetsFor(*this);
- aRect = thisResult.mRect;
-
+ nsRect rect = thisResult.mRect;
Element* parent = thisResult.mParent;
while (parent && ShouldBeRetargeted(*this, *parent)) {
OffsetResult result = GetUnretargetedOffsetsFor(*parent);
- aRect += result.mRect.TopLeft();
+ rect += result.mRect.TopLeft();
parent = result.mParent;
}
+ aRect = CSSIntRect::FromAppUnitsRounded(
+ frame->Style()->EffectiveZoom().Unzoom(rect));
return parent;
}
@@ -1757,8 +1767,8 @@ bool nsGenericHTMLElement::LegacyTouchAPIEnabled(JSContext* aCx,
}
bool nsGenericHTMLElement::IsFormControlDefaultFocusable(
- bool aWithMouse) const {
- if (!aWithMouse) {
+ IsFocusableFlags aFlags) const {
+ if (!(aFlags & IsFocusableFlags::WithMouse)) {
return true;
}
switch (StaticPrefs::accessibility_mouse_focuses_formcontrol()) {
@@ -2303,7 +2313,8 @@ void nsGenericHTMLElement::Click(CallerType aCallerType) {
ClearHandlingClick();
}
-bool nsGenericHTMLElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+bool nsGenericHTMLElement::IsHTMLFocusable(IsFocusableFlags aFlags,
+ bool* aIsFocusable,
int32_t* aTabIndex) {
MOZ_ASSERT(aIsFocusable);
MOZ_ASSERT(aTabIndex);
@@ -2589,15 +2600,15 @@ void nsGenericHTMLFormControlElement::GetAutocapitalize(
}
}
-bool nsGenericHTMLFormControlElement::IsHTMLFocusable(bool aWithMouse,
+bool nsGenericHTMLFormControlElement::IsHTMLFocusable(IsFocusableFlags aFlags,
bool* aIsFocusable,
int32_t* aTabIndex) {
- if (nsGenericHTMLFormElement::IsHTMLFocusable(aWithMouse, aIsFocusable,
+ if (nsGenericHTMLFormElement::IsHTMLFocusable(aFlags, aIsFocusable,
aTabIndex)) {
return true;
}
- *aIsFocusable = *aIsFocusable && IsFormControlDefaultFocusable(aWithMouse);
+ *aIsFocusable = *aIsFocusable && IsFormControlDefaultFocusable(aFlags);
return false;
}
@@ -3552,8 +3563,7 @@ void nsGenericHTMLElement::FocusPopover() {
RefPtr<Element> control = GetBoolAttr(nsGkAtoms::autofocus)
? this
- : GetAutofocusDelegate(false /* aWithMouse */);
-
+ : GetAutofocusDelegate(IsFocusableFlags(0));
if (!control) {
return;
}
diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h
index 86f87e8795..f63f070207 100644
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -198,7 +198,7 @@ class nsGenericHTMLElement : public nsGenericHTMLElementBase {
}
/** Returns whether a form control should be default-focusable. */
- bool IsFormControlDefaultFocusable(bool aWithMouse) const;
+ bool IsFormControlDefaultFocusable(mozilla::IsFocusableFlags) const;
/**
* Returns the count of descendants (inclusive of this node) in
@@ -333,16 +333,17 @@ class nsGenericHTMLElement : public nsGenericHTMLElementBase {
nsresult BindToTree(BindContext&, nsINode& aParent) override;
void UnbindFromTree(UnbindContext&) override;
- Focusable IsFocusableWithoutStyle(bool aWithMouse) override {
+ Focusable IsFocusableWithoutStyle(mozilla::IsFocusableFlags aFlags =
+ mozilla::IsFocusableFlags(0)) override {
Focusable result;
- IsHTMLFocusable(aWithMouse, &result.mFocusable, &result.mTabIndex);
+ IsHTMLFocusable(aFlags, &result.mFocusable, &result.mTabIndex);
return result;
}
/**
* Returns true if a subclass is not allowed to override the value returned
* in aIsFocusable.
*/
- virtual bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+ virtual bool IsHTMLFocusable(mozilla::IsFocusableFlags, bool* aIsFocusable,
int32_t* aTabIndex);
MOZ_CAN_RUN_SCRIPT
mozilla::Result<bool, nsresult> PerformAccesskey(
@@ -1176,7 +1177,7 @@ class nsGenericHTMLFormControlElement : public nsGenericHTMLFormElement,
// nsGenericHTMLElement
// autocapitalize attribute support
void GetAutocapitalize(nsAString& aValue) const override;
- bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
+ bool IsHTMLFocusable(mozilla::IsFocusableFlags, bool* aIsFocusable,
int32_t* aTabIndex) override;
// EventTarget
diff --git a/dom/html/nsGenericHTMLFrameElement.cpp b/dom/html/nsGenericHTMLFrameElement.cpp
index 92591d7b72..c854012f4b 100644
--- a/dom/html/nsGenericHTMLFrameElement.cpp
+++ b/dom/html/nsGenericHTMLFrameElement.cpp
@@ -311,11 +311,10 @@ nsresult nsGenericHTMLFrameElement::CopyInnerTo(Element* aDest) {
return rv;
}
-bool nsGenericHTMLFrameElement::IsHTMLFocusable(bool aWithMouse,
+bool nsGenericHTMLFrameElement::IsHTMLFocusable(IsFocusableFlags aFlags,
bool* aIsFocusable,
int32_t* aTabIndex) {
- if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable,
- aTabIndex)) {
+ if (nsGenericHTMLElement::IsHTMLFocusable(aFlags, aIsFocusable, aTabIndex)) {
return true;
}
diff --git a/dom/html/nsGenericHTMLFrameElement.h b/dom/html/nsGenericHTMLFrameElement.h
index 587e861b88..c61fea2c02 100644
--- a/dom/html/nsGenericHTMLFrameElement.h
+++ b/dom/html/nsGenericHTMLFrameElement.h
@@ -50,15 +50,15 @@ class nsGenericHTMLFrameElement : public nsGenericHTMLElement,
NS_DECLARE_STATIC_IID_ACCESSOR(NS_GENERICHTMLFRAMEELEMENT_IID)
// nsIContent
- virtual bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
- int32_t* aTabIndex) override;
- virtual nsresult BindToTree(BindContext&, nsINode& aParent) override;
- virtual void UnbindFromTree(UnbindContext&) override;
- virtual void DestroyContent() override;
+ bool IsHTMLFocusable(mozilla::IsFocusableFlags, bool* aIsFocusable,
+ int32_t* aTabIndex) override;
+ nsresult BindToTree(BindContext&, nsINode& aParent) override;
+ void UnbindFromTree(UnbindContext&) override;
+ void DestroyContent() override;
nsresult CopyInnerTo(mozilla::dom::Element* aDest);
- virtual int32_t TabIndexDefault() override;
+ int32_t TabIndexDefault() override;
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsGenericHTMLFrameElement,
nsGenericHTMLElement)
diff --git a/dom/html/test/forms/mochitest.toml b/dom/html/test/forms/mochitest.toml
index 80d6d3530f..82a8639659 100644
--- a/dom/html/test/forms/mochitest.toml
+++ b/dom/html/test/forms/mochitest.toml
@@ -73,6 +73,8 @@ support-files = ["file_double_submit.html"]
["test_input_datetime_input_change_events.html"]
+["test_input_datetime_preventDefault.html"]
+
["test_input_datetime_readonly.html"]
["test_input_datetime_reset_default_value_input_change_event.html"]
diff --git a/dom/html/test/forms/test_input_datetime_preventDefault.html b/dom/html/test/forms/test_input_datetime_preventDefault.html
new file mode 100644
index 0000000000..76e5928c18
--- /dev/null
+++ b/dom/html/test/forms/test_input_datetime_preventDefault.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>Test for bug 1848158</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+<input id="input" type="date" value="1998-01-22">
+<script>
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+ let value = input.value;
+
+ input.addEventListener("keydown", function(e) {
+ e.preventDefault();
+ });
+
+ isnot(value, "", "should have a value");
+
+ input.focus();
+ synthesizeKey("KEY_Backspace");
+ is(input.value, value, "Value shouldn't change");
+ SimpleTest.finish();
+});
+</script>