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() {
111 new nsDOMTokenList(this, nsGkAtoms::rel
, sAnchorAndFormRelValues
);
116 void SVGAElement::GetHreflang(nsAString
& aHreflang
) {
117 GetAttr(nsGkAtoms::hreflang
, aHreflang
);
120 void SVGAElement::SetHreflang(const nsAString
& aHreflang
,
121 mozilla::ErrorResult
& rv
) {
122 SetAttr(nsGkAtoms::hreflang
, aHreflang
, rv
);
125 void SVGAElement::GetType(nsAString
& aType
) { GetAttr(nsGkAtoms::type
, aType
); }
127 void SVGAElement::SetType(const nsAString
& aType
, mozilla::ErrorResult
& rv
) {
128 SetAttr(nsGkAtoms::type
, aType
, rv
);
131 void SVGAElement::GetText(nsAString
& aText
, mozilla::ErrorResult
& rv
) const {
133 !nsContentUtils::GetNodeTextContent(this, true, aText
, fallible
))) {
134 rv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
138 void SVGAElement::SetText(const nsAString
& aText
, mozilla::ErrorResult
& rv
) {
139 rv
= nsContentUtils::SetNodeTextContent(this, aText
, false);
142 //----------------------------------------------------------------------
143 // nsIContent methods
145 nsresult
SVGAElement::BindToTree(BindContext
& aContext
, nsINode
& aParent
) {
146 nsresult rv
= SVGAElementBase::BindToTree(aContext
, aParent
);
147 NS_ENSURE_SUCCESS(rv
, rv
);
148 Link::BindToTree(aContext
);
152 void SVGAElement::UnbindFromTree(UnbindContext
& aContext
) {
153 SVGAElementBase::UnbindFromTree(aContext
);
154 // Without removing the link state we risk a dangling pointer
155 // in the mStyledLinks hashtable
156 Link::UnbindFromTree();
159 int32_t SVGAElement::TabIndexDefault() { return 0; }
161 Focusable
SVGAElement::IsFocusableWithoutStyle(bool aWithMouse
) {
163 if (IsSVGFocusable(&result
.mFocusable
, &result
.mTabIndex
)) {
167 if (!OwnerDoc()->LinkHandlingEnabled()) {
171 // Links that are in an editable region should never be focusable, even if
172 // they are in a contenteditable="false" region.
173 if (nsContentUtils::IsNodeInEditableRegion(this)) {
177 if (GetTabIndexAttrValue().isNothing()) {
178 // check whether we're actually a link
180 // Not tabbable or focusable without href (bug 17605), unless
181 // forced to be via presence of nonnegative tabindex attribute
185 if ((sTabFocusModel
& eTabFocus_linksMask
) == 0) {
186 result
.mTabIndex
= -1;
191 bool SVGAElement::HasHref() const {
192 // Currently our SMIL implementation does not modify the DOM attributes. Once
193 // we implement the SVG 2 SMIL behaviour this can be removed.
194 return mStringAttributes
[HREF
].IsExplicitlySet() ||
195 mStringAttributes
[XLINK_HREF
].IsExplicitlySet();
198 already_AddRefed
<nsIURI
> SVGAElement::GetHrefURI() const {
199 // Optimization: check for href first for early return
200 bool useBareHref
= mStringAttributes
[HREF
].IsExplicitlySet();
201 if (useBareHref
|| mStringAttributes
[XLINK_HREF
].IsExplicitlySet()) {
204 const uint8_t idx
= useBareHref
? HREF
: XLINK_HREF
;
205 mStringAttributes
[idx
].GetAnimValue(str
, this);
206 nsCOMPtr
<nsIURI
> uri
;
207 nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri
), str
,
208 OwnerDoc(), GetBaseURI());
214 void SVGAElement::GetLinkTarget(nsAString
& aTarget
) {
215 mStringAttributes
[TARGET
].GetAnimValue(aTarget
, this);
216 if (aTarget
.IsEmpty()) {
217 static Element::AttrValuesArray sShowVals
[] = {nsGkAtoms::_new
,
218 nsGkAtoms::replace
, nullptr};
220 switch (FindAttrValueIn(kNameSpaceID_XLink
, nsGkAtoms::show
, sShowVals
,
223 aTarget
.AssignLiteral("_blank");
228 Document
* ownerDoc
= OwnerDoc();
230 ownerDoc
->GetBaseTarget(aTarget
);
235 void SVGAElement::AfterSetAttr(int32_t aNameSpaceID
, nsAtom
* aName
,
236 const nsAttrValue
* aValue
,
237 const nsAttrValue
* aOldValue
,
238 nsIPrincipal
* aMaybeScriptedPrincipal
,
240 if (aName
== nsGkAtoms::href
&& (aNameSpaceID
== kNameSpaceID_XLink
||
241 aNameSpaceID
== kNameSpaceID_None
)) {
242 // We can't assume that null aValue means we no longer have an href, because
243 // we could be unsetting xlink:href but still have a null-namespace href, or
244 // vice versa. But we can fast-path the case when we _do_ have a new value.
245 Link::ResetLinkState(aNotify
, aValue
|| Link::ElementHasHref());
248 return SVGAElementBase::AfterSetAttr(aNameSpaceID
, aName
, aValue
, aOldValue
,
249 aMaybeScriptedPrincipal
, aNotify
);
252 //----------------------------------------------------------------------
253 // SVGElement methods
255 SVGElement::StringAttributesInfo
SVGAElement::GetStringInfo() {
256 return StringAttributesInfo(mStringAttributes
, sStringInfo
,
257 ArrayLength(sStringInfo
));
260 } // namespace mozilla::dom