Bug 1663089 [wpt PR 25399] - idle-detection: Implement requestPermission() method...
[gecko.git] / dom / svg / SVGAElement.cpp
blob0e7f0a89e22a581bbe56b9689480a5d6652846f6
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/EventStates.h"
12 #include "mozilla/dom/BindContext.h"
13 #include "mozilla/dom/DocumentInlines.h"
14 #include "mozilla/dom/SVGAElementBinding.h"
15 #include "nsCOMPtr.h"
16 #include "nsContentUtils.h"
17 #include "nsGkAtoms.h"
18 #include "nsIContentInlines.h"
19 #include "nsIURI.h"
21 NS_IMPL_NS_NEW_SVG_ELEMENT(A)
23 namespace mozilla {
24 namespace dom {
26 JSObject* SVGAElement::WrapNode(JSContext* aCx,
27 JS::Handle<JSObject*> aGivenProto) {
28 return SVGAElement_Binding::Wrap(aCx, this, aGivenProto);
31 SVGElement::StringInfo SVGAElement::sStringInfo[3] = {
32 {nsGkAtoms::href, kNameSpaceID_None, true},
33 {nsGkAtoms::href, kNameSpaceID_XLink, true},
34 {nsGkAtoms::target, kNameSpaceID_None, true}};
36 // static
37 const DOMTokenListSupportedToken SVGAElement::sSupportedRelValues[] = {
38 "noreferrer", "noopener", nullptr};
40 //----------------------------------------------------------------------
41 // nsISupports methods
43 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGAElement)
44 NS_INTERFACE_MAP_ENTRY(Link)
45 NS_INTERFACE_MAP_END_INHERITING(SVGAElementBase)
47 NS_IMPL_CYCLE_COLLECTION_INHERITED(SVGAElement, SVGAElementBase, mRelList)
49 NS_IMPL_ADDREF_INHERITED(SVGAElement, SVGAElementBase)
50 NS_IMPL_RELEASE_INHERITED(SVGAElement, SVGAElementBase)
52 //----------------------------------------------------------------------
53 // Implementation
55 SVGAElement::SVGAElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
56 : SVGAElementBase(std::move(aNodeInfo)), Link(this) {}
58 already_AddRefed<DOMSVGAnimatedString> SVGAElement::Href() {
59 return mStringAttributes[HREF].IsExplicitlySet()
60 ? mStringAttributes[HREF].ToDOMAnimatedString(this)
61 : mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
64 //----------------------------------------------------------------------
65 // Link methods
67 bool SVGAElement::ElementHasHref() const {
68 return mStringAttributes[HREF].IsExplicitlySet() ||
69 mStringAttributes[XLINK_HREF].IsExplicitlySet();
72 //----------------------------------------------------------------------
73 // nsINode methods
75 void SVGAElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
76 Element::GetEventTargetParent(aVisitor);
78 GetEventTargetParentForLinks(aVisitor);
81 nsresult SVGAElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
82 return PostHandleEventForLinks(aVisitor);
85 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGAElement)
87 //----------------------------------------------------------------------
89 already_AddRefed<DOMSVGAnimatedString> SVGAElement::Target() {
90 return mStringAttributes[TARGET].ToDOMAnimatedString(this);
93 void SVGAElement::GetDownload(nsAString& aDownload) {
94 GetAttr(nsGkAtoms::download, aDownload);
97 void SVGAElement::SetDownload(const nsAString& aDownload, ErrorResult& rv) {
98 SetAttr(nsGkAtoms::download, aDownload, rv);
101 void SVGAElement::GetPing(nsAString& aPing) { GetAttr(nsGkAtoms::ping, aPing); }
103 void SVGAElement::SetPing(const nsAString& aPing, ErrorResult& rv) {
104 SetAttr(nsGkAtoms::ping, aPing, rv);
107 void SVGAElement::GetRel(nsAString& aRel) { GetAttr(nsGkAtoms::rel, aRel); }
109 void SVGAElement::SetRel(const nsAString& aRel, ErrorResult& rv) {
110 SetAttr(nsGkAtoms::rel, aRel, rv);
113 void SVGAElement::GetReferrerPolicy(nsAString& aPolicy) {
114 GetEnumAttr(nsGkAtoms::referrerpolicy, EmptyCString().get(), aPolicy);
117 void SVGAElement::SetReferrerPolicy(const nsAString& aPolicy,
118 mozilla::ErrorResult& rv) {
119 SetAttr(nsGkAtoms::referrerpolicy, aPolicy, rv);
122 nsDOMTokenList* SVGAElement::RelList() {
123 if (!mRelList) {
124 mRelList = new nsDOMTokenList(this, nsGkAtoms::rel, sSupportedRelValues);
126 return mRelList;
129 void SVGAElement::GetHreflang(nsAString& aHreflang) {
130 GetAttr(nsGkAtoms::hreflang, aHreflang);
133 void SVGAElement::SetHreflang(const nsAString& aHreflang,
134 mozilla::ErrorResult& rv) {
135 SetAttr(nsGkAtoms::hreflang, aHreflang, rv);
138 void SVGAElement::GetType(nsAString& aType) { GetAttr(nsGkAtoms::type, aType); }
140 void SVGAElement::SetType(const nsAString& aType, mozilla::ErrorResult& rv) {
141 SetAttr(nsGkAtoms::type, aType, rv);
144 void SVGAElement::GetText(nsAString& aText, mozilla::ErrorResult& rv) {
145 if (NS_WARN_IF(
146 !nsContentUtils::GetNodeTextContent(this, true, aText, fallible))) {
147 rv.Throw(NS_ERROR_OUT_OF_MEMORY);
151 void SVGAElement::SetText(const nsAString& aText, mozilla::ErrorResult& rv) {
152 rv = nsContentUtils::SetNodeTextContent(this, aText, false);
155 //----------------------------------------------------------------------
156 // nsIContent methods
158 nsresult SVGAElement::BindToTree(BindContext& aContext, nsINode& aParent) {
159 Link::ResetLinkState(false, Link::ElementHasHref());
161 nsresult rv = SVGAElementBase::BindToTree(aContext, aParent);
162 NS_ENSURE_SUCCESS(rv, rv);
164 if (Document* doc = aContext.GetComposedDoc()) {
165 doc->RegisterPendingLinkUpdate(this);
168 return NS_OK;
171 void SVGAElement::UnbindFromTree(bool aNullParent) {
172 // Without removing the link state we risk a dangling pointer
173 // in the mStyledLinks hashtable
174 Link::ResetLinkState(false, Link::ElementHasHref());
176 SVGAElementBase::UnbindFromTree(aNullParent);
179 already_AddRefed<nsIURI> SVGAElement::GetHrefURI() const {
180 nsCOMPtr<nsIURI> hrefURI;
181 return IsLink(getter_AddRefs(hrefURI)) ? hrefURI.forget() : nullptr;
184 NS_IMETHODIMP_(bool)
185 SVGAElement::IsAttributeMapped(const nsAtom* name) const {
186 static const MappedAttributeEntry* const map[] = {sFEFloodMap,
187 sFiltersMap,
188 sFontSpecificationMap,
189 sGradientStopMap,
190 sLightingEffectsMap,
191 sMarkersMap,
192 sTextContentElementsMap,
193 sViewportsMap};
195 return FindAttributeDependence(name, map) ||
196 SVGAElementBase::IsAttributeMapped(name);
199 int32_t SVGAElement::TabIndexDefault() { return 0; }
201 bool SVGAElement::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) {
202 bool isFocusable = false;
203 if (IsSVGFocusable(&isFocusable, aTabIndex)) {
204 return isFocusable;
207 if (!OwnerDoc()->LinkHandlingEnabled()) {
208 return false;
211 // Links that are in an editable region should never be focusable, even if
212 // they are in a contenteditable="false" region.
213 if (nsContentUtils::IsNodeInEditableRegion(this)) {
214 if (aTabIndex) {
215 *aTabIndex = -1;
217 return false;
220 if (GetTabIndexAttrValue().isNothing()) {
221 // check whether we're actually a link
222 if (!Link::HasURI()) {
223 // Not tabbable or focusable without href (bug 17605), unless
224 // forced to be via presence of nonnegative tabindex attribute
225 if (aTabIndex) {
226 *aTabIndex = -1;
228 return false;
232 if (aTabIndex && (sTabFocusModel & eTabFocus_linksMask) == 0) {
233 *aTabIndex = -1;
236 return true;
239 bool SVGAElement::IsLink(nsIURI** aURI) const {
240 // To be a clickable XLink for styling and interaction purposes, we require:
242 // xlink:href - must be set
243 // xlink:type - must be unset or set to "" or set to "simple"
244 // xlink:show - must be unset or set to "", "new" or "replace"
245 // xlink:actuate - must be unset or set to "" or "onRequest"
247 // For any other values, we're either not a *clickable* XLink, or the end
248 // result is poorly specified. Either way, we return false.
250 static Element::AttrValuesArray sTypeVals[] = {nsGkAtoms::_empty,
251 nsGkAtoms::simple, nullptr};
253 static Element::AttrValuesArray sShowVals[] = {
254 nsGkAtoms::_empty, nsGkAtoms::_new, nsGkAtoms::replace, nullptr};
256 static Element::AttrValuesArray sActuateVals[] = {
257 nsGkAtoms::_empty, nsGkAtoms::onRequest, nullptr};
259 // Optimization: check for href first for early return
260 bool useBareHref = mStringAttributes[HREF].IsExplicitlySet();
262 if ((useBareHref || mStringAttributes[XLINK_HREF].IsExplicitlySet()) &&
263 FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::type, sTypeVals,
264 eCaseMatters) != Element::ATTR_VALUE_NO_MATCH &&
265 FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::show, sShowVals,
266 eCaseMatters) != Element::ATTR_VALUE_NO_MATCH &&
267 FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::actuate, sActuateVals,
268 eCaseMatters) != Element::ATTR_VALUE_NO_MATCH) {
269 // Get absolute URI
270 nsAutoString str;
271 const uint8_t idx = useBareHref ? HREF : XLINK_HREF;
272 mStringAttributes[idx].GetAnimValue(str, this);
273 nsContentUtils::NewURIWithDocumentCharset(aURI, str, OwnerDoc(),
274 GetBaseURI());
275 // must promise out param is non-null if we return true
276 return !!*aURI;
279 *aURI = nullptr;
280 return false;
283 void SVGAElement::GetLinkTarget(nsAString& aTarget) {
284 mStringAttributes[TARGET].GetAnimValue(aTarget, this);
285 if (aTarget.IsEmpty()) {
286 static Element::AttrValuesArray sShowVals[] = {nsGkAtoms::_new,
287 nsGkAtoms::replace, nullptr};
289 switch (FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::show, sShowVals,
290 eCaseMatters)) {
291 case 0:
292 aTarget.AssignLiteral("_blank");
293 return;
294 case 1:
295 return;
297 Document* ownerDoc = OwnerDoc();
298 if (ownerDoc) {
299 ownerDoc->GetBaseTarget(aTarget);
304 EventStates SVGAElement::IntrinsicState() const {
305 return Link::LinkState() | SVGAElementBase::IntrinsicState();
308 nsresult SVGAElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
309 const nsAttrValue* aValue,
310 const nsAttrValue* aOldValue,
311 nsIPrincipal* aMaybeScriptedPrincipal,
312 bool aNotify) {
313 if (aName == nsGkAtoms::href && (aNameSpaceID == kNameSpaceID_XLink ||
314 aNameSpaceID == kNameSpaceID_None)) {
315 // We can't assume that null aValue means we no longer have an href, because
316 // we could be unsetting xlink:href but still have a null-namespace href, or
317 // vice versa. But we can fast-path the case when we _do_ have a new value.
318 Link::ResetLinkState(aNotify, aValue || Link::ElementHasHref());
321 return SVGAElementBase::AfterSetAttr(aNameSpaceID, aName, aValue, aOldValue,
322 aMaybeScriptedPrincipal, aNotify);
325 //----------------------------------------------------------------------
326 // SVGElement methods
328 SVGElement::StringAttributesInfo SVGAElement::GetStringInfo() {
329 return StringAttributesInfo(mStringAttributes, sStringInfo,
330 ArrayLength(sStringInfo));
333 } // namespace dom
334 } // namespace mozilla