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/EventDispatcher.h"
10 #include "mozilla/dom/DocumentInlines.h"
11 #include "mozilla/dom/SVGAElementBinding.h"
12 #include "mozilla/FocusModel.h"
14 #include "nsContentUtils.h"
15 #include "nsGkAtoms.h"
16 #include "nsIContentInlines.h"
19 NS_IMPL_NS_NEW_SVG_ELEMENT(A
)
21 namespace mozilla::dom
{
23 JSObject
* SVGAElement::WrapNode(JSContext
* aCx
,
24 JS::Handle
<JSObject
*> aGivenProto
) {
25 return SVGAElement_Binding::Wrap(aCx
, this, aGivenProto
);
28 SVGElement::StringInfo
SVGAElement::sStringInfo
[3] = {
29 {nsGkAtoms::href
, kNameSpaceID_None
, true},
30 {nsGkAtoms::href
, kNameSpaceID_XLink
, true},
31 {nsGkAtoms::target
, kNameSpaceID_None
, true}};
33 //----------------------------------------------------------------------
34 // nsISupports methods
36 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGAElement
)
37 NS_INTERFACE_MAP_ENTRY(Link
)
38 NS_INTERFACE_MAP_END_INHERITING(SVGAElementBase
)
40 NS_IMPL_CYCLE_COLLECTION_INHERITED(SVGAElement
, SVGAElementBase
, mRelList
)
42 NS_IMPL_ADDREF_INHERITED(SVGAElement
, SVGAElementBase
)
43 NS_IMPL_RELEASE_INHERITED(SVGAElement
, SVGAElementBase
)
45 //----------------------------------------------------------------------
48 SVGAElement::SVGAElement(already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
)
49 : SVGAElementBase(std::move(aNodeInfo
)), Link(this) {}
51 already_AddRefed
<DOMSVGAnimatedString
> SVGAElement::Href() {
52 return mStringAttributes
[HREF
].IsExplicitlySet()
53 ? mStringAttributes
[HREF
].ToDOMAnimatedString(this)
54 : mStringAttributes
[XLINK_HREF
].ToDOMAnimatedString(this);
57 //----------------------------------------------------------------------
60 void SVGAElement::GetEventTargetParent(EventChainPreVisitor
& aVisitor
) {
61 Element::GetEventTargetParent(aVisitor
);
63 GetEventTargetParentForLinks(aVisitor
);
66 nsresult
SVGAElement::PostHandleEvent(EventChainPostVisitor
& aVisitor
) {
67 return PostHandleEventForLinks(aVisitor
);
70 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGAElement
)
72 //----------------------------------------------------------------------
74 already_AddRefed
<DOMSVGAnimatedString
> SVGAElement::Target() {
75 return mStringAttributes
[TARGET
].ToDOMAnimatedString(this);
78 void SVGAElement::GetDownload(nsAString
& aDownload
) {
79 GetAttr(nsGkAtoms::download
, aDownload
);
82 void SVGAElement::SetDownload(const nsAString
& aDownload
, ErrorResult
& rv
) {
83 SetAttr(nsGkAtoms::download
, aDownload
, rv
);
86 void SVGAElement::GetPing(nsAString
& aPing
) { GetAttr(nsGkAtoms::ping
, aPing
); }
88 void SVGAElement::SetPing(const nsAString
& aPing
, ErrorResult
& rv
) {
89 SetAttr(nsGkAtoms::ping
, aPing
, rv
);
92 void SVGAElement::GetRel(nsAString
& aRel
) { GetAttr(nsGkAtoms::rel
, aRel
); }
94 void SVGAElement::SetRel(const nsAString
& aRel
, ErrorResult
& rv
) {
95 SetAttr(nsGkAtoms::rel
, aRel
, rv
);
98 void SVGAElement::GetReferrerPolicy(nsAString
& aPolicy
) {
99 GetEnumAttr(nsGkAtoms::referrerpolicy
, "", aPolicy
);
102 void SVGAElement::SetReferrerPolicy(const nsAString
& aPolicy
,
103 mozilla::ErrorResult
& rv
) {
104 SetAttr(nsGkAtoms::referrerpolicy
, aPolicy
, rv
);
107 nsDOMTokenList
* SVGAElement::RelList() {
110 new nsDOMTokenList(this, nsGkAtoms::rel
, sAnchorAndFormRelValues
);
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 nsresult rv
= SVGAElementBase::BindToTree(aContext
, aParent
);
146 NS_ENSURE_SUCCESS(rv
, rv
);
147 Link::BindToTree(aContext
);
151 void SVGAElement::UnbindFromTree(UnbindContext
& aContext
) {
152 SVGAElementBase::UnbindFromTree(aContext
);
153 // Without removing the link state we risk a dangling pointer
154 // in the mStyledLinks hashtable
155 Link::UnbindFromTree();
158 int32_t SVGAElement::TabIndexDefault() { return 0; }
160 Focusable
SVGAElement::IsFocusableWithoutStyle(IsFocusableFlags
) {
162 if (IsSVGFocusable(&result
.mFocusable
, &result
.mTabIndex
)) {
166 if (!OwnerDoc()->LinkHandlingEnabled()) {
170 // Links that are in an editable region should never be focusable, even if
171 // they are in a contenteditable="false" region.
172 if (nsContentUtils::IsNodeInEditableRegion(this)) {
176 if (GetTabIndexAttrValue().isNothing()) {
177 // check whether we're actually a link
179 // Not tabbable or focusable without href (bug 17605), unless
180 // forced to be via presence of nonnegative tabindex attribute
184 if (!FocusModel::IsTabFocusable(TabFocusableType::Links
)) {
185 result
.mTabIndex
= -1;
190 bool SVGAElement::HasHref() const {
191 // Currently our SMIL implementation does not modify the DOM attributes. Once
192 // we implement the SVG 2 SMIL behaviour this can be removed.
193 return mStringAttributes
[HREF
].IsExplicitlySet() ||
194 mStringAttributes
[XLINK_HREF
].IsExplicitlySet();
197 already_AddRefed
<nsIURI
> SVGAElement::GetHrefURI() const {
198 // Optimization: check for href first for early return
199 bool useBareHref
= mStringAttributes
[HREF
].IsExplicitlySet();
200 if (useBareHref
|| mStringAttributes
[XLINK_HREF
].IsExplicitlySet()) {
203 const uint8_t idx
= useBareHref
? HREF
: XLINK_HREF
;
204 mStringAttributes
[idx
].GetAnimValue(str
, this);
205 nsCOMPtr
<nsIURI
> uri
;
206 nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri
), str
,
207 OwnerDoc(), GetBaseURI());
213 void SVGAElement::GetLinkTargetImpl(nsAString
& aTarget
) {
214 mStringAttributes
[TARGET
].GetAnimValue(aTarget
, this);
215 if (aTarget
.IsEmpty()) {
216 static Element::AttrValuesArray sShowVals
[] = {nsGkAtoms::_new
,
217 nsGkAtoms::replace
, nullptr};
219 switch (FindAttrValueIn(kNameSpaceID_XLink
, nsGkAtoms::show
, sShowVals
,
222 aTarget
.AssignLiteral("_blank");
227 Document
* ownerDoc
= OwnerDoc();
229 ownerDoc
->GetBaseTarget(aTarget
);
234 void SVGAElement::AfterSetAttr(int32_t aNameSpaceID
, nsAtom
* aName
,
235 const nsAttrValue
* aValue
,
236 const nsAttrValue
* aOldValue
,
237 nsIPrincipal
* aMaybeScriptedPrincipal
,
239 if (aName
== nsGkAtoms::href
&& (aNameSpaceID
== kNameSpaceID_XLink
||
240 aNameSpaceID
== kNameSpaceID_None
)) {
241 // We can't assume that null aValue means we no longer have an href, because
242 // we could be unsetting xlink:href but still have a null-namespace href, or
243 // vice versa. But we can fast-path the case when we _do_ have a new value.
244 Link::ResetLinkState(aNotify
, aValue
|| Link::ElementHasHref());
247 return SVGAElementBase::AfterSetAttr(aNameSpaceID
, aName
, aValue
, aOldValue
,
248 aMaybeScriptedPrincipal
, aNotify
);
251 //----------------------------------------------------------------------
252 // SVGElement methods
254 SVGElement::StringAttributesInfo
SVGAElement::GetStringInfo() {
255 return StringAttributesInfo(mStringAttributes
, sStringInfo
,
256 std::size(sStringInfo
));
259 void SVGAElement::DidAnimateAttribute(int32_t aNameSpaceID
,
260 nsAtom
* aAttribute
) {
261 if ((aNameSpaceID
== kNameSpaceID_None
||
262 aNameSpaceID
== kNameSpaceID_XLink
) &&
263 aAttribute
== nsGkAtoms::href
) {
264 Link::ResetLinkState(true, Link::ElementHasHref());
266 SVGAElementBase::DidAnimateAttribute(aNameSpaceID
, aAttribute
);
269 } // namespace mozilla::dom