Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 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
25 #include "core/svg/SVGAElement.h"
26
27 #include "SVGNames.h"
28 #include "XLinkNames.h"
29 #include "core/dom/Attr.h"
30 #include "core/dom/Attribute.h"
31 #include "core/dom/Document.h"
32 #include "core/events/KeyboardEvent.h"
33 #include "core/events/MouseEvent.h"
34 #include "core/events/ThreadLocalEventNames.h"
35 #include "core/frame/Frame.h"
36 #include "core/html/HTMLAnchorElement.h"
37 #include "core/html/HTMLFormElement.h"
38 #include "core/html/parser/HTMLParserIdioms.h"
39 #include "core/loader/FrameLoadRequest.h"
40 #include "core/loader/FrameLoader.h"
41 #include "core/loader/FrameLoaderTypes.h"
42 #include "core/page/Chrome.h"
43 #include "core/page/ChromeClient.h"
44 #include "core/page/Page.h"
45 #include "core/rendering/svg/RenderSVGInline.h"
46 #include "core/rendering/svg/RenderSVGText.h"
47 #include "core/rendering/svg/RenderSVGTransformableContainer.h"
48 #include "core/svg/SVGElementInstance.h"
49 #include "core/svg/animation/SVGSMILElement.h"
50 #include "platform/PlatformMouseEvent.h"
51 #include "platform/network/ResourceRequest.h"
52
53 namespace WebCore {
54
55 using namespace HTMLNames;
56
57 // Animated property definitions
58
59 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGAElement)
60     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGraphicsElement)
61 END_REGISTER_ANIMATED_PROPERTIES
62
63 inline SVGAElement::SVGAElement(Document& document)
64     : SVGGraphicsElement(SVGNames::aTag, document)
65     , SVGURIReference(this)
66     , m_svgTarget(SVGAnimatedString::create(this, SVGNames::targetAttr, SVGString::create()))
67 {
68     ScriptWrappable::init(this);
69     addToPropertyMap(m_svgTarget);
70     registerAnimatedPropertiesForSVGAElement();
71 }
72
73 PassRefPtr<SVGAElement> SVGAElement::create(Document& document)
74 {
75     return adoptRef(new SVGAElement(document));
76 }
77
78 String SVGAElement::title() const
79 {
80     // If the xlink:title is set (non-empty string), use it.
81     const AtomicString& title = fastGetAttribute(XLinkNames::titleAttr);
82     if (!title.isEmpty())
83         return title;
84
85     // Otherwise, use the title of this element.
86     return SVGElement::title();
87 }
88
89 bool SVGAElement::isSupportedAttribute(const QualifiedName& attrName)
90 {
91     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
92     if (supportedAttributes.isEmpty()) {
93         SVGURIReference::addSupportedAttributes(supportedAttributes);
94         supportedAttributes.add(SVGNames::targetAttr);
95     }
96     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
97 }
98
99 void SVGAElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
100 {
101     if (!isSupportedAttribute(name)) {
102         SVGGraphicsElement::parseAttribute(name, value);
103         return;
104     }
105
106     SVGParsingError parseError = NoError;
107
108     if (name == SVGNames::targetAttr) {
109         m_svgTarget->setBaseValueAsString(value, parseError);
110     } else if (SVGURIReference::parseAttribute(name, value, parseError)) {
111     } else {
112         ASSERT_NOT_REACHED();
113     }
114
115     reportAttributeParsingError(parseError, name, value);
116 }
117
118 void SVGAElement::svgAttributeChanged(const QualifiedName& attrName)
119 {
120     if (!isSupportedAttribute(attrName)) {
121         SVGGraphicsElement::svgAttributeChanged(attrName);
122         return;
123     }
124
125     SVGElementInstance::InvalidationGuard invalidationGuard(this);
126
127     // Unlike other SVG*Element classes, SVGAElement only listens to SVGURIReference changes
128     // as none of the other properties changes the linking behaviour for our <a> element.
129     if (SVGURIReference::isKnownAttribute(attrName)) {
130         bool wasLink = isLink();
131         setIsLink(!hrefString().isNull());
132
133         if (wasLink != isLink())
134             setNeedsStyleRecalc(SubtreeStyleChange);
135     }
136 }
137
138 RenderObject* SVGAElement::createRenderer(RenderStyle*)
139 {
140     if (parentNode() && parentNode()->isSVGElement() && toSVGElement(parentNode())->isTextContent())
141         return new RenderSVGInline(this);
142
143     return new RenderSVGTransformableContainer(this);
144 }
145
146 void SVGAElement::defaultEventHandler(Event* event)
147 {
148     if (isLink()) {
149         if (focused() && isEnterKeyKeydownEvent(event)) {
150             event->setDefaultHandled();
151             dispatchSimulatedClick(event);
152             return;
153         }
154
155         if (isLinkClick(event)) {
156             String url = stripLeadingAndTrailingHTMLSpaces(hrefString());
157
158             if (url[0] == '#') {
159                 Element* targetElement = treeScope().getElementById(AtomicString(url.substring(1)));
160                 if (targetElement && isSVGSMILElement(*targetElement)) {
161                     toSVGSMILElement(targetElement)->beginByLinkActivation();
162                     event->setDefaultHandled();
163                     return;
164                 }
165                 // Only allow navigation to internal <view> anchors.
166                 if (targetElement && !targetElement->hasTagName(SVGNames::viewTag))
167                     return;
168             }
169
170             AtomicString target(m_svgTarget->currentValue()->value());
171             if (target.isEmpty() && fastGetAttribute(XLinkNames::showAttr) == "new")
172                 target = AtomicString("_blank", AtomicString::ConstructFromLiteral);
173             event->setDefaultHandled();
174
175             Frame* frame = document().frame();
176             if (!frame)
177                 return;
178             FrameLoadRequest frameRequest(&document(), ResourceRequest(document().completeURL(url)), target);
179             frameRequest.setTriggeringEvent(event);
180             frame->loader().load(frameRequest);
181             return;
182         }
183     }
184
185     SVGGraphicsElement::defaultEventHandler(event);
186 }
187
188 bool SVGAElement::supportsFocus() const
189 {
190     if (rendererIsEditable())
191         return SVGGraphicsElement::supportsFocus();
192     return true;
193 }
194
195 bool SVGAElement::isURLAttribute(const Attribute& attribute) const
196 {
197     return attribute.name().localName() == hrefAttr || SVGGraphicsElement::isURLAttribute(attribute);
198 }
199
200 bool SVGAElement::isMouseFocusable() const
201 {
202     return false;
203 }
204
205 bool SVGAElement::isKeyboardFocusable() const
206 {
207     if (!isFocusable())
208         return false;
209
210     if (Page* page = document().page())
211         return page->chrome().client().tabsToLinks();
212     return false;
213 }
214
215 bool SVGAElement::willRespondToMouseClickEvents()
216 {
217     return isLink() || SVGGraphicsElement::willRespondToMouseClickEvents();
218 }
219
220 } // namespace WebCore