2011-05-02 Roland Steiner <rolandsteiner@chromium.org>
[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 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
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
60 PassRefPtr<SVGAElement> SVGAElement::create(const QualifiedName& tagName, Document* document)
61 {
62     return adoptRef(new SVGAElement(tagName, document));
63 }
64
65 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
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
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
108 AttributeToPropertyTypeMap& SVGAElement::attributeToPropertyTypeMap()
109 {
110     DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ());
111     return s_attributeToPropertyTypeMap;
112 }
113
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
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
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
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 = treeScope()->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
196 bool SVGAElement::supportsFocus() const
197 {
198     if (rendererIsEditable())
199         return SVGStyledTransformableElement::supportsFocus();
200     return true;
201 }
202
203 bool SVGAElement::isFocusable() const
204 {
205     if (renderer() && renderer()->absoluteClippedOverflowRect().isEmpty())
206         return false;
207     
208     return SVGElement::isFocusable();
209 }
210
211 bool SVGAElement::isMouseFocusable() const
212 {
213     return false;
214 }
215
216 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
227 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)