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 #if ENABLE(SVG)
26 #include "SVGAElement.h"
27
28 #include "Attr.h"
29 #include "Attribute.h"
30 #include "Document.h"
31 #include "EventHandler.h"
32 #include "EventNames.h"
33 #include "Frame.h"
34 #include "FrameLoader.h"
35 #include "FrameLoaderTypes.h"
36 #include "HTMLAnchorElement.h"
37 #include "HTMLParserIdioms.h"
38 #include "KeyboardEvent.h"
39 #include "MouseEvent.h"
40 #include "PlatformMouseEvent.h"
41 #include "RenderSVGInline.h"
42 #include "RenderSVGTransformableContainer.h"
43 #include "ResourceRequest.h"
44 #include "SVGNames.h"
45 #include "SVGSMILElement.h"
46 #include "XLinkNames.h"
47
48 namespace WebCore {
49
50 // Animated property definitions
DEFINE_ANIMATED_STRING(SVGAElement,SVGNames::targetAttr,SVGTarget,svgTarget)51 DEFINE_ANIMATED_STRING(SVGAElement, SVGNames::targetAttr, SVGTarget, svgTarget)
52 DEFINE_ANIMATED_STRING(SVGAElement, XLinkNames::hrefAttr, Href, href)
53 DEFINE_ANIMATED_BOOLEAN(SVGAElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
54
55 inline SVGAElement::SVGAElement(const QualifiedName& tagName, Document* document)
56 : SVGStyledTransformableElement(tagName, document)
57 {
58 }
59
create(const QualifiedName & tagName,Document * document)60 PassRefPtr<SVGAElement> SVGAElement::create(const QualifiedName& tagName, Document* document)
61 {
62 return adoptRef(new SVGAElement(tagName, document));
63 }
64
title() const65 String SVGAElement::title() const
66 {
67 // If the xlink:title is set (non-empty string), use it.
68 const AtomicString& title = getAttribute(XLinkNames::titleAttr);
69 if (!title.isEmpty())
70 return title;
71
72 // Otherwise, use the title of this element.
73 return SVGStyledElement::title();
74 }
75
parseMappedAttribute(Attribute * attr)76 void SVGAElement::parseMappedAttribute(Attribute* attr)
77 {
78 if (attr->name() == SVGNames::targetAttr)
79 setSVGTargetBaseValue(attr->value());
80 else {
81 if (SVGURIReference::parseMappedAttribute(attr))
82 return;
83 if (SVGTests::parseMappedAttribute(attr))
84 return;
85 if (SVGLangSpace::parseMappedAttribute(attr))
86 return;
87 if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
88 return;
89 SVGStyledTransformableElement::parseMappedAttribute(attr);
90 }
91 }
92
svgAttributeChanged(const QualifiedName & attrName)93 void SVGAElement::svgAttributeChanged(const QualifiedName& attrName)
94 {
95 SVGStyledTransformableElement::svgAttributeChanged(attrName);
96
97 // Unlike other SVG*Element classes, SVGAElement only listens to SVGURIReference changes
98 // as none of the other properties changes the linking behaviour for our <a> element.
99 if (SVGURIReference::isKnownAttribute(attrName)) {
100 bool wasLink = isLink();
101 setIsLink(!href().isNull());
102
103 if (wasLink != isLink())
104 setNeedsStyleRecalc();
105 }
106 }
107
attributeToPropertyTypeMap()108 AttributeToPropertyTypeMap& SVGAElement::attributeToPropertyTypeMap()
109 {
110 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ());
111 return s_attributeToPropertyTypeMap;
112 }
113
fillAttributeToPropertyTypeMap()114 void SVGAElement::fillAttributeToPropertyTypeMap()
115 {
116 AttributeToPropertyTypeMap& attributeToPropertyTypeMap = this->attributeToPropertyTypeMap();
117
118 SVGStyledTransformableElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap);
119 attributeToPropertyTypeMap.set(SVGNames::targetAttr, AnimatedString);
120 attributeToPropertyTypeMap.set(XLinkNames::hrefAttr, AnimatedString);
121 }
122
synchronizeProperty(const QualifiedName & attrName)123 void SVGAElement::synchronizeProperty(const QualifiedName& attrName)
124 {
125 SVGStyledTransformableElement::synchronizeProperty(attrName);
126
127 if (attrName == anyQName()) {
128 synchronizeSVGTarget();
129 synchronizeHref();
130 synchronizeExternalResourcesRequired();
131 SVGTests::synchronizeProperties(this, attrName);
132 return;
133 }
134
135 if (attrName == SVGNames::targetAttr)
136 synchronizeSVGTarget();
137 else if (SVGURIReference::isKnownAttribute(attrName))
138 synchronizeHref();
139 else if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
140 synchronizeExternalResourcesRequired();
141 else if (SVGTests::isKnownAttribute(attrName))
142 SVGTests::synchronizeProperties(this, attrName);
143 }
144
createRenderer(RenderArena * arena,RenderStyle *)145 RenderObject* SVGAElement::createRenderer(RenderArena* arena, RenderStyle*)
146 {
147 if (static_cast<SVGElement*>(parentNode())->isTextContent())
148 return new (arena) RenderSVGInline(this);
149
150 return new (arena) RenderSVGTransformableContainer(this);
151 }
152
defaultEventHandler(Event * event)153 void SVGAElement::defaultEventHandler(Event* event)
154 {
155 if (isLink()) {
156 if (focused() && isEnterKeyKeydownEvent(event)) {
157 event->setDefaultHandled();
158 dispatchSimulatedClick(event);
159 return;
160 }
161
162 if (isLinkClick(event)) {
163 String url = stripLeadingAndTrailingHTMLSpaces(href());
164
165 #if ENABLE(SVG_ANIMATION)
166 if (url[0] == '#') {
167 Element* targetElement = document()->getElementById(url.substring(1));
168 if (SVGSMILElement::isSMILElement(targetElement)) {
169 static_cast<SVGSMILElement*>(targetElement)->beginByLinkActivation();
170 event->setDefaultHandled();
171 return;
172 }
173 }
174 #endif
175
176 // FIXME: Why does the SVG anchor element have this special logic
177 // for middle click that the HTML anchor element does not have?
178 // Making a middle click open a link in a new window or tab is
179 // properly handled at the client level, not inside WebKit; this
180 // code should be deleted.
181 String target = isMiddleMouseButtonEvent(event) ? "_blank" : this->target();
182
183 // FIXME: It's not clear why setting target to "_self" is ever
184 // helpful.
185 if (target.isEmpty())
186 target = (getAttribute(XLinkNames::showAttr) == "new") ? "_blank" : "_self";
187
188 handleLinkClick(event, document(), url, target);
189 return;
190 }
191 }
192
193 SVGStyledTransformableElement::defaultEventHandler(event);
194 }
195
supportsFocus() const196 bool SVGAElement::supportsFocus() const
197 {
198 if (rendererIsEditable())
199 return SVGStyledTransformableElement::supportsFocus();
200 return true;
201 }
202
isFocusable() const203 bool SVGAElement::isFocusable() const
204 {
205 if (renderer() && renderer()->absoluteClippedOverflowRect().isEmpty())
206 return false;
207
208 return SVGElement::isFocusable();
209 }
210
isMouseFocusable() const211 bool SVGAElement::isMouseFocusable() const
212 {
213 return false;
214 }
215
isKeyboardFocusable(KeyboardEvent * event) const216 bool SVGAElement::isKeyboardFocusable(KeyboardEvent* event) const
217 {
218 if (!isFocusable())
219 return false;
220
221 if (!document()->frame())
222 return false;
223
224 return document()->frame()->eventHandler()->tabsToLinks(event);
225 }
226
childShouldCreateRenderer(Node * child) const227 bool SVGAElement::childShouldCreateRenderer(Node* child) const
228 {
229 // http://www.w3.org/2003/01/REC-SVG11-20030114-errata#linking-text-environment
230 // The 'a' element may contain any element that its parent may contain, except itself.
231 if (child->hasTagName(SVGNames::aTag))
232 return false;
233 if (parentNode() && parentNode()->isSVGElement())
234 return parentNode()->childShouldCreateRenderer(child);
235
236 return SVGElement::childShouldCreateRenderer(child);
237 }
238
239 } // namespace WebCore
240
241 #endif // ENABLE(SVG)
242