Rename AtomicString to AtomString
[WebKit-https.git] / Source / WebCore / svg / SVGAElement.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005, 2007 Rob Buis <buis@kde.org>
4  * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
5  * Copyright (C) 2010-2019 Apple Inc. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #include "config.h"
24 #include "SVGAElement.h"
25
26 #include "Document.h"
27 #include "EventHandler.h"
28 #include "Frame.h"
29 #include "FrameLoader.h"
30 #include "FrameLoaderTypes.h"
31 #include "HTMLAnchorElement.h"
32 #include "HTMLParserIdioms.h"
33 #include "KeyboardEvent.h"
34 #include "MouseEvent.h"
35 #include "PlatformMouseEvent.h"
36 #include "RenderSVGInline.h"
37 #include "RenderSVGText.h"
38 #include "RenderSVGTransformableContainer.h"
39 #include "ResourceRequest.h"
40 #include "SVGNames.h"
41 #include "SVGSMILElement.h"
42 #include "XLinkNames.h"
43 #include <wtf/IsoMallocInlines.h>
44
45 namespace WebCore {
46
47 WTF_MAKE_ISO_ALLOCATED_IMPL(SVGAElement);
48
49 inline SVGAElement::SVGAElement(const QualifiedName& tagName, Document& document)
50     : SVGGraphicsElement(tagName, document)
51     , SVGExternalResourcesRequired(this)
52     , SVGURIReference(this)
53 {
54     ASSERT(hasTagName(SVGNames::aTag));
55
56     static std::once_flag onceFlag;
57     std::call_once(onceFlag, [] {
58         PropertyRegistry::registerProperty<SVGNames::targetAttr, &SVGAElement::m_target>();
59     });
60 }
61
62 Ref<SVGAElement> SVGAElement::create(const QualifiedName& tagName, Document& document)
63 {
64     return adoptRef(*new SVGAElement(tagName, document));
65 }
66
67 String SVGAElement::title() const
68 {
69     // If the xlink:title is set (non-empty string), use it.
70     const AtomString& title = attributeWithoutSynchronization(XLinkNames::titleAttr);
71     if (!title.isEmpty())
72         return title;
73
74     // Otherwise, use the title of this element.
75     return SVGElement::title();
76 }
77
78 void SVGAElement::parseAttribute(const QualifiedName& name, const AtomString& value)
79 {
80     if (name == SVGNames::targetAttr) {
81         m_target->setBaseValInternal(value);
82         return;
83     }
84
85     SVGGraphicsElement::parseAttribute(name, value);
86     SVGURIReference::parseAttribute(name, value);
87     SVGExternalResourcesRequired::parseAttribute(name, value);
88 }
89
90 void SVGAElement::svgAttributeChanged(const QualifiedName& attrName)
91 {
92     if (SVGURIReference::isKnownAttribute(attrName)) {
93         bool wasLink = isLink();
94         setIsLink(!href().isNull() && !shouldProhibitLinks(this));
95         if (wasLink != isLink()) {
96             InstanceInvalidationGuard guard(*this);
97             invalidateStyleForSubtree();
98         }
99         return;
100     }
101
102     SVGGraphicsElement::svgAttributeChanged(attrName);
103     SVGExternalResourcesRequired::svgAttributeChanged(attrName);
104 }
105
106 RenderPtr<RenderElement> SVGAElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
107 {
108     if (parentNode() && parentNode()->isSVGElement() && downcast<SVGElement>(*parentNode()).isTextContent())
109         return createRenderer<RenderSVGInline>(*this, WTFMove(style));
110
111     return createRenderer<RenderSVGTransformableContainer>(*this, WTFMove(style));
112 }
113
114 void SVGAElement::defaultEventHandler(Event& event)
115 {
116     if (isLink()) {
117         if (focused() && isEnterKeyKeydownEvent(event)) {
118             event.setDefaultHandled();
119             dispatchSimulatedClick(&event);
120             return;
121         }
122
123         if (MouseEvent::canTriggerActivationBehavior(event)) {
124             String url = stripLeadingAndTrailingHTMLSpaces(href());
125
126             if (url[0] == '#') {
127                 auto targetElement = makeRefPtr(treeScope().getElementById(url.substringSharingImpl(1)));
128                 if (is<SVGSMILElement>(targetElement)) {
129                     downcast<SVGSMILElement>(*targetElement).beginByLinkActivation();
130                     event.setDefaultHandled();
131                     return;
132                 }
133                 // Only allow navigation to internal <view> anchors.
134                 if (targetElement && !targetElement->hasTagName(SVGNames::viewTag))
135                     return;
136             }
137
138             String target = this->target();
139             if (target.isEmpty() && attributeWithoutSynchronization(XLinkNames::showAttr) == "new")
140                 target = "_blank";
141             event.setDefaultHandled();
142
143             auto frame = makeRefPtr(document().frame());
144             if (!frame)
145                 return;
146             frame->loader().urlSelected(document().completeURL(url), target, &event, LockHistory::No, LockBackForwardList::No, MaybeSendReferrer, document().shouldOpenExternalURLsPolicyToPropagate());
147             return;
148         }
149     }
150
151     SVGGraphicsElement::defaultEventHandler(event);
152 }
153
154 int SVGAElement::tabIndex() const
155 {
156     // Skip the supportsFocus check in SVGElement.
157     return Element::tabIndex();
158 }
159
160 bool SVGAElement::supportsFocus() const
161 {
162     if (hasEditableStyle())
163         return SVGGraphicsElement::supportsFocus();
164     // If not a link we should still be able to focus the element if it has a tabIndex.
165     return isLink() || Element::supportsFocus();
166 }
167
168 bool SVGAElement::isURLAttribute(const Attribute& attribute) const
169 {
170     return SVGURIReference::isKnownAttribute(attribute.name()) || SVGGraphicsElement::isURLAttribute(attribute);
171 }
172
173 bool SVGAElement::isMouseFocusable() const
174 {
175     // Links are focusable by default, but only allow links with tabindex or contenteditable to be mouse focusable.
176     // https://bugs.webkit.org/show_bug.cgi?id=26856
177     if (isLink())
178         return Element::supportsFocus();
179     
180     return SVGElement::isMouseFocusable();
181 }
182
183 bool SVGAElement::isKeyboardFocusable(KeyboardEvent* event) const
184 {
185     if (isFocusable() && Element::supportsFocus())
186         return SVGElement::isKeyboardFocusable(event);
187
188     if (isLink())
189         return document().frame()->eventHandler().tabsToLinks(event);
190
191     return SVGElement::isKeyboardFocusable(event);
192 }
193
194 bool SVGAElement::canStartSelection() const
195 {
196     if (!isLink())
197         return SVGElement::canStartSelection();
198
199     return hasEditableStyle();
200 }
201
202 bool SVGAElement::childShouldCreateRenderer(const Node& child) const
203 {
204     // http://www.w3.org/2003/01/REC-SVG11-20030114-errata#linking-text-environment
205     // The 'a' element may contain any element that its parent may contain, except itself.
206     if (child.hasTagName(SVGNames::aTag))
207         return false;
208
209     if (parentElement() && parentElement()->isSVGElement())
210         return parentElement()->childShouldCreateRenderer(child);
211
212     return SVGElement::childShouldCreateRenderer(child);
213 }
214
215 bool SVGAElement::willRespondToMouseClickEvents()
216
217     return isLink() || SVGGraphicsElement::willRespondToMouseClickEvents(); 
218 }
219
220 SharedStringHash SVGAElement::visitedLinkHash() const
221 {
222     ASSERT(isLink());
223     if (!m_storedVisitedLinkHash)
224         m_storedVisitedLinkHash = computeVisitedLinkHash(document().baseURL(), getAttribute(SVGNames::hrefAttr, XLinkNames::hrefAttr));
225     return *m_storedVisitedLinkHash;
226 }
227
228 } // namespace WebCore