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/SVGAElement.h"
9 #include "mozilla/Attributes.h"
10 #include "mozilla/EventDispatcher.h"
11 #include "mozilla/dom/BindContext.h"
12 #include "mozilla/dom/DocumentInlines.h"
13 #include "mozilla/dom/SVGAElementBinding.h"
15 #include "nsContentUtils.h"
16 #include "nsGkAtoms.h"
17 #include "nsIContentInlines.h"
20 NS_IMPL_NS_NEW_SVG_ELEMENT(A
)
22 namespace mozilla::dom
{
24 JSObject
* SVGAElement::WrapNode(JSContext
* aCx
,
25 JS::Handle
<JSObject
*> aGivenProto
) {
26 return SVGAElement_Binding::Wrap(aCx
, this, aGivenProto
);
29 SVGElement::StringInfo
SVGAElement::sStringInfo
[3] = {
30 {nsGkAtoms::href
, kNameSpaceID_None
, true},
31 {nsGkAtoms::href
, kNameSpaceID_XLink
, true},
32 {nsGkAtoms::target
, kNameSpaceID_None
, true}};
34 //----------------------------------------------------------------------
35 // nsISupports methods
37 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGAElement
)
38 NS_INTERFACE_MAP_ENTRY(Link
)
39 NS_INTERFACE_MAP_END_INHERITING(SVGAElementBase
)
41 NS_IMPL_CYCLE_COLLECTION_INHERITED(SVGAElement
, SVGAElementBase
, mRelList
)
43 NS_IMPL_ADDREF_INHERITED(SVGAElement
, SVGAElementBase
)
44 NS_IMPL_RELEASE_INHERITED(SVGAElement
, SVGAElementBase
)
46 //----------------------------------------------------------------------
49 SVGAElement::SVGAElement(already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
)
50 : SVGAElementBase(std::move(aNodeInfo
)), Link(this) {}
52 already_AddRefed
<DOMSVGAnimatedString
> SVGAElement::Href() {
53 return mStringAttributes
[HREF
].IsExplicitlySet()
54 ? mStringAttributes
[HREF
].ToDOMAnimatedString(this)
55 : mStringAttributes
[XLINK_HREF
].ToDOMAnimatedString(this);
58 //----------------------------------------------------------------------
61 void SVGAElement::GetEventTargetParent(EventChainPreVisitor
& aVisitor
) {
62 Element::GetEventTargetParent(aVisitor
);
64 GetEventTargetParentForLinks(aVisitor
);
67 nsresult
SVGAElement::PostHandleEvent(EventChainPostVisitor
& aVisitor
) {
68 return PostHandleEventForLinks(aVisitor
);
71 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGAElement
)
73 //----------------------------------------------------------------------
75 already_AddRefed
<DOMSVGAnimatedString
> SVGAElement::Target() {
76 return mStringAttributes
[TARGET
].ToDOMAnimatedString(this);
79 void SVGAElement::GetDownload(nsAString
& aDownload
) {
80 GetAttr(nsGkAtoms::download
, aDownload
);
83 void SVGAElement::SetDownload(const nsAString
& aDownload
, ErrorResult
& rv
) {
84 SetAttr(nsGkAtoms::download
, aDownload
, rv
);
87 void SVGAElement::GetPing(nsAString
& aPing
) { GetAttr(nsGkAtoms::ping
, aPing
); }
89 void SVGAElement::SetPing(const nsAString
& aPing
, ErrorResult
& rv
) {
90 SetAttr(nsGkAtoms::ping
, aPing
, rv
);
93 void SVGAElement::GetRel(nsAString
& aRel
) { GetAttr(nsGkAtoms::rel
, aRel
); }
95 void SVGAElement::SetRel(const nsAString
& aRel
, ErrorResult
& rv
) {
96 SetAttr(nsGkAtoms::rel
, aRel
, rv
);
99 void SVGAElement::GetReferrerPolicy(nsAString
& aPolicy
) {
100 GetEnumAttr(nsGkAtoms::referrerpolicy
, "", aPolicy
);
103 void SVGAElement::SetReferrerPolicy(const nsAString
& aPolicy
,
104 mozilla::ErrorResult
& rv
) {
105 SetAttr(nsGkAtoms::referrerpolicy
, aPolicy
, rv
);
108 nsDOMTokenList
* SVGAElement::RelList() {
110 mRelList
= new nsDOMTokenList(this, nsGkAtoms::rel
, sSupportedRelValues
);
115 void SVGAElement::GetHreflang(nsAString
& aHreflang
) {
116 GetAttr(nsGkAtoms::hreflang
, aHreflang
);
119 void SVGAElement::SetHreflang(const nsAString
& aHreflang
,
120 mozilla::ErrorResult
& rv
) {
121 SetAttr(nsGkAtoms::hreflang
, aHreflang
, rv
);
124 void SVGAElement::GetType(nsAString
& aType
) { GetAttr(nsGkAtoms::type
, aType
); }
126 void SVGAElement::SetType(const nsAString
& aType
, mozilla::ErrorResult
& rv
) {
127 SetAttr(nsGkAtoms::type
, aType
, rv
);
130 void SVGAElement::GetText(nsAString
& aText
, mozilla::ErrorResult
& rv
) const {
132 !nsContentUtils::GetNodeTextContent(this, true, aText
, fallible
))) {
133 rv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
137 void SVGAElement::SetText(const nsAString
& aText
, mozilla::ErrorResult
& rv
) {
138 rv
= nsContentUtils::SetNodeTextContent(this, aText
, false);
141 //----------------------------------------------------------------------
142 // nsIContent methods
144 nsresult
SVGAElement::BindToTree(BindContext
& aContext
, nsINode
& aParent
) {
145 Link::ResetLinkState(false, Link::ElementHasHref());
147 nsresult rv
= SVGAElementBase::BindToTree(aContext
, aParent
);
148 NS_ENSURE_SUCCESS(rv
, rv
);
150 if (Document
* doc
= aContext
.GetComposedDoc()) {
151 doc
->RegisterPendingLinkUpdate(this);
157 void SVGAElement::UnbindFromTree(bool aNullParent
) {
158 // Without removing the link state we risk a dangling pointer
159 // in the mStyledLinks hashtable
160 Link::ResetLinkState(false, Link::ElementHasHref());
162 SVGAElementBase::UnbindFromTree(aNullParent
);
165 int32_t SVGAElement::TabIndexDefault() { return 0; }
167 bool SVGAElement::IsFocusableInternal(int32_t* aTabIndex
, bool aWithMouse
) {
168 bool isFocusable
= false;
169 if (IsSVGFocusable(&isFocusable
, aTabIndex
)) {
173 if (!OwnerDoc()->LinkHandlingEnabled()) {
177 // Links that are in an editable region should never be focusable, even if
178 // they are in a contenteditable="false" region.
179 if (nsContentUtils::IsNodeInEditableRegion(this)) {
186 if (GetTabIndexAttrValue().isNothing()) {
187 // check whether we're actually a link
189 // Not tabbable or focusable without href (bug 17605), unless
190 // forced to be via presence of nonnegative tabindex attribute
198 if (aTabIndex
&& (sTabFocusModel
& eTabFocus_linksMask
) == 0) {
205 bool SVGAElement::HasHref() const {
206 // Currently our SMIL implementation does not modify the DOM attributes. Once
207 // we implement the SVG 2 SMIL behaviour this can be removed.
208 return mStringAttributes
[HREF
].IsExplicitlySet() ||
209 mStringAttributes
[XLINK_HREF
].IsExplicitlySet();
212 already_AddRefed
<nsIURI
> SVGAElement::GetHrefURI() const {
213 // Optimization: check for href first for early return
214 bool useBareHref
= mStringAttributes
[HREF
].IsExplicitlySet();
215 if (useBareHref
|| mStringAttributes
[XLINK_HREF
].IsExplicitlySet()) {
218 const uint8_t idx
= useBareHref
? HREF
: XLINK_HREF
;
219 mStringAttributes
[idx
].GetAnimValue(str
, this);
220 nsCOMPtr
<nsIURI
> uri
;
221 nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri
), str
,
222 OwnerDoc(), GetBaseURI());
228 void SVGAElement::GetLinkTarget(nsAString
& aTarget
) {
229 mStringAttributes
[TARGET
].GetAnimValue(aTarget
, this);
230 if (aTarget
.IsEmpty()) {
231 static Element::AttrValuesArray sShowVals
[] = {nsGkAtoms::_new
,
232 nsGkAtoms::replace
, nullptr};
234 switch (FindAttrValueIn(kNameSpaceID_XLink
, nsGkAtoms::show
, sShowVals
,
237 aTarget
.AssignLiteral("_blank");
242 Document
* ownerDoc
= OwnerDoc();
244 ownerDoc
->GetBaseTarget(aTarget
);
249 ElementState
SVGAElement::IntrinsicState() const {
250 return Link::LinkState() | SVGAElementBase::IntrinsicState();
253 void SVGAElement::AfterSetAttr(int32_t aNameSpaceID
, nsAtom
* aName
,
254 const nsAttrValue
* aValue
,
255 const nsAttrValue
* aOldValue
,
256 nsIPrincipal
* aMaybeScriptedPrincipal
,
258 if (aName
== nsGkAtoms::href
&& (aNameSpaceID
== kNameSpaceID_XLink
||
259 aNameSpaceID
== kNameSpaceID_None
)) {
260 // We can't assume that null aValue means we no longer have an href, because
261 // we could be unsetting xlink:href but still have a null-namespace href, or
262 // vice versa. But we can fast-path the case when we _do_ have a new value.
263 Link::ResetLinkState(aNotify
, aValue
|| Link::ElementHasHref());
266 return SVGAElementBase::AfterSetAttr(aNameSpaceID
, aName
, aValue
, aOldValue
,
267 aMaybeScriptedPrincipal
, aNotify
);
270 //----------------------------------------------------------------------
271 // SVGElement methods
273 SVGElement::StringAttributesInfo
SVGAElement::GetStringInfo() {
274 return StringAttributesInfo(mStringAttributes
, sStringInfo
,
275 ArrayLength(sStringInfo
));
278 } // namespace mozilla::dom