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 #include "mozilla/dom/HTMLAnchorElement.h"
9 #include "mozilla/dom/BindContext.h"
10 #include "mozilla/dom/HTMLAnchorElementBinding.h"
11 #include "mozilla/dom/HTMLDNSPrefetch.h"
12 #include "mozilla/EventDispatcher.h"
13 #include "mozilla/MemoryReporting.h"
15 #include "nsContentUtils.h"
16 #include "nsGkAtoms.h"
17 #include "nsAttrValueOrString.h"
18 #include "mozilla/dom/Document.h"
19 #include "nsPresContext.h"
21 #include "nsWindowSizes.h"
23 NS_IMPL_NS_NEW_HTML_ELEMENT(Anchor
)
25 namespace mozilla::dom
{
27 HTMLAnchorElement::~HTMLAnchorElement() {
28 SupportsDNSPrefetch::Destroyed(*this);
31 bool HTMLAnchorElement::IsInteractiveHTMLContent() const {
32 return HasAttr(nsGkAtoms::href
) ||
33 nsGenericHTMLElement::IsInteractiveHTMLContent();
36 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLAnchorElement
,
37 nsGenericHTMLElement
, Link
)
39 NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLAnchorElement
, nsGenericHTMLElement
,
42 NS_IMPL_ELEMENT_CLONE(HTMLAnchorElement
)
44 JSObject
* HTMLAnchorElement::WrapNode(JSContext
* aCx
,
45 JS::Handle
<JSObject
*> aGivenProto
) {
46 return HTMLAnchorElement_Binding::Wrap(aCx
, this, aGivenProto
);
49 int32_t HTMLAnchorElement::TabIndexDefault() { return 0; }
51 bool HTMLAnchorElement::Draggable() const {
52 // links can be dragged as long as there is an href and the
53 // draggable attribute isn't false
54 if (!HasAttr(nsGkAtoms::href
)) {
55 // no href, so just use the same behavior as other elements
56 return nsGenericHTMLElement::Draggable();
59 return !AttrValueIs(kNameSpaceID_None
, nsGkAtoms::draggable
,
60 nsGkAtoms::_false
, eIgnoreCase
);
63 nsresult
HTMLAnchorElement::BindToTree(BindContext
& aContext
,
65 nsresult rv
= nsGenericHTMLElement::BindToTree(aContext
, aParent
);
66 NS_ENSURE_SUCCESS(rv
, rv
);
68 Link::BindToTree(aContext
);
71 MaybeTryDNSPrefetch();
75 void HTMLAnchorElement::UnbindFromTree(UnbindContext
& aContext
) {
76 // Cancel any DNS prefetches
77 // Note: Must come before ResetLinkState. If called after, it will recreate
78 // mCachedURI based on data that is invalid - due to a call to Link::GetURI()
79 // via GetURIForDNSPrefetch().
80 CancelDNSPrefetch(*this);
82 nsGenericHTMLElement::UnbindFromTree(aContext
);
84 // Without removing the link state we risk a dangling pointer in the
85 // mStyledLinks hashtable
86 Link::UnbindFromTree();
89 bool HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse
, bool* aIsFocusable
,
91 if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse
, aIsFocusable
,
96 // cannot focus links if there is no link handler
97 if (!OwnerDoc()->LinkHandlingEnabled()) {
99 *aIsFocusable
= false;
103 // Links that are in an editable region should never be focusable, even if
104 // they are in a contenteditable="false" region.
105 if (nsContentUtils::IsNodeInEditableRegion(this)) {
107 *aIsFocusable
= false;
111 if (GetTabIndexAttrValue().isNothing()) {
112 // check whether we're actually a link
114 // Not tabbable or focusable without href (bug 17605), unless
115 // forced to be via presence of nonnegative tabindex attribute
117 *aIsFocusable
= false;
122 if ((sTabFocusModel
& eTabFocus_linksMask
) == 0) {
125 *aIsFocusable
= true;
129 void HTMLAnchorElement::GetEventTargetParent(EventChainPreVisitor
& aVisitor
) {
130 GetEventTargetParentForAnchors(aVisitor
);
133 nsresult
HTMLAnchorElement::PostHandleEvent(EventChainPostVisitor
& aVisitor
) {
134 return PostHandleEventForAnchors(aVisitor
);
137 void HTMLAnchorElement::GetLinkTarget(nsAString
& aTarget
) {
138 GetAttr(nsGkAtoms::target
, aTarget
);
139 if (aTarget
.IsEmpty()) {
140 GetBaseTarget(aTarget
);
144 void HTMLAnchorElement::GetTarget(nsAString
& aValue
) const {
145 if (!GetAttr(nsGkAtoms::target
, aValue
)) {
146 GetBaseTarget(aValue
);
150 nsDOMTokenList
* HTMLAnchorElement::RelList() {
153 new nsDOMTokenList(this, nsGkAtoms::rel
, sAnchorAndFormRelValues
);
158 void HTMLAnchorElement::GetText(nsAString
& aText
,
159 mozilla::ErrorResult
& aRv
) const {
161 !nsContentUtils::GetNodeTextContent(this, true, aText
, fallible
))) {
162 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
166 void HTMLAnchorElement::SetText(const nsAString
& aText
, ErrorResult
& aRv
) {
167 aRv
= nsContentUtils::SetNodeTextContent(this, aText
, false);
170 already_AddRefed
<nsIURI
> HTMLAnchorElement::GetHrefURI() const {
171 if (nsCOMPtr
<nsIURI
> uri
= GetCachedURI()) {
174 return GetHrefURIForAnchors();
177 void HTMLAnchorElement::BeforeSetAttr(int32_t aNamespaceID
, nsAtom
* aName
,
178 const nsAttrValue
* aValue
, bool aNotify
) {
179 if (aNamespaceID
== kNameSpaceID_None
&& aName
== nsGkAtoms::href
) {
180 CancelDNSPrefetch(*this);
182 return nsGenericHTMLElement::BeforeSetAttr(aNamespaceID
, aName
, aValue
,
186 void HTMLAnchorElement::AfterSetAttr(int32_t aNamespaceID
, nsAtom
* aName
,
187 const nsAttrValue
* aValue
,
188 const nsAttrValue
* aOldValue
,
189 nsIPrincipal
* aSubjectPrincipal
,
191 if (aNamespaceID
== kNameSpaceID_None
) {
192 if (aName
== nsGkAtoms::href
) {
193 Link::ResetLinkState(aNotify
, !!aValue
);
195 MaybeTryDNSPrefetch();
200 return nsGenericHTMLElement::AfterSetAttr(
201 aNamespaceID
, aName
, aValue
, aOldValue
, aSubjectPrincipal
, aNotify
);
204 void HTMLAnchorElement::AddSizeOfExcludingThis(nsWindowSizes
& aSizes
,
205 size_t* aNodeSize
) const {
206 nsGenericHTMLElement::AddSizeOfExcludingThis(aSizes
, aNodeSize
);
207 *aNodeSize
+= Link::SizeOfExcludingThis(aSizes
.mState
);
210 void HTMLAnchorElement::MaybeTryDNSPrefetch() {
211 if (IsInComposedDoc()) {
212 nsIURI
* docURI
= OwnerDoc()->GetDocumentURI();
217 bool docIsHttps
= docURI
->SchemeIs("https");
219 StaticPrefs::dom_prefetch_dns_for_anchor_https_document()) ||
221 StaticPrefs::dom_prefetch_dns_for_anchor_http_document())) {
223 *this, HTMLDNSPrefetch::PrefetchSource::AnchorSpeculativePrefetch
);
228 } // namespace mozilla::dom