1 /* 2 * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2004, 2005, 2007 Rob Buis <buis (at) kde.org> 4 * Copyright (C) 2007 Eric Seidel <eric (at) 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 "core/SVGNames.h" 28 #include "core/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/frame/FrameHost.h" 35 #include "core/frame/LocalFrame.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/animation/SVGSMILElement.h" 49 #include "platform/PlatformMouseEvent.h" 50 #include "platform/network/ResourceRequest.h" 51 52 namespace WebCore { 53 54 using namespace HTMLNames; 55 56 inline SVGAElement::SVGAElement(Document& document) 57 : SVGGraphicsElement(SVGNames::aTag, document) 58 , SVGURIReference(this) 59 , m_svgTarget(SVGAnimatedString::create(this, SVGNames::targetAttr, SVGString::create())) 60 { 61 ScriptWrappable::init(this); 62 addToPropertyMap(m_svgTarget); 63 } 64 65 DEFINE_NODE_FACTORY(SVGAElement) 66 67 String SVGAElement::title() const 68 { 69 // If the xlink:title is set (non-empty string), use it. 70 const AtomicString& title = fastGetAttribute(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 bool SVGAElement::isSupportedAttribute(const QualifiedName& attrName) 79 { 80 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); 81 if (supportedAttributes.isEmpty()) { 82 SVGURIReference::addSupportedAttributes(supportedAttributes); 83 supportedAttributes.add(SVGNames::targetAttr); 84 } 85 return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName); 86 } 87 88 void SVGAElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 89 { 90 if (!isSupportedAttribute(name)) { 91 SVGGraphicsElement::parseAttribute(name, value); 92 return; 93 } 94 95 SVGParsingError parseError = NoError; 96 97 if (name == SVGNames::targetAttr) { 98 m_svgTarget->setBaseValueAsString(value, parseError); 99 } else if (SVGURIReference::parseAttribute(name, value, parseError)) { 100 } else { 101 ASSERT_NOT_REACHED(); 102 } 103 104 reportAttributeParsingError(parseError, name, value); 105 } 106 107 void SVGAElement::svgAttributeChanged(const QualifiedName& attrName) 108 { 109 if (!isSupportedAttribute(attrName)) { 110 SVGGraphicsElement::svgAttributeChanged(attrName); 111 return; 112 } 113 114 SVGElement::InvalidationGuard invalidationGuard(this); 115 116 // Unlike other SVG*Element classes, SVGAElement only listens to SVGURIReference changes 117 // as none of the other properties changes the linking behaviour for our <a> element. 118 if (SVGURIReference::isKnownAttribute(attrName)) { 119 bool wasLink = isLink(); 120 setIsLink(!hrefString().isNull()); 121 122 if (wasLink != isLink()) 123 setNeedsStyleRecalc(SubtreeStyleChange); 124 } 125 } 126 127 RenderObject* SVGAElement::createRenderer(RenderStyle*) 128 { 129 if (parentNode() && parentNode()->isSVGElement() && toSVGElement(parentNode())->isTextContent()) 130 return new RenderSVGInline(this); 131 132 return new RenderSVGTransformableContainer(this); 133 } 134 135 void SVGAElement::defaultEventHandler(Event* event) 136 { 137 if (isLink()) { 138 if (focused() && isEnterKeyKeydownEvent(event)) { 139 event->setDefaultHandled(); 140 dispatchSimulatedClick(event); 141 return; 142 } 143 144 if (isLinkClick(event)) { 145 String url = stripLeadingAndTrailingHTMLSpaces(hrefString()); 146 147 if (url[0] == '#') { 148 Element* targetElement = treeScope().getElementById(AtomicString(url.substring(1))); 149 if (targetElement && isSVGSMILElement(*targetElement)) { 150 toSVGSMILElement(targetElement)->beginByLinkActivation(); 151 event->setDefaultHandled(); 152 return; 153 } 154 } 155 156 AtomicString target(m_svgTarget->currentValue()->value()); 157 if (target.isEmpty() && fastGetAttribute(XLinkNames::showAttr) == "new") 158 target = AtomicString("_blank", AtomicString::ConstructFromLiteral); 159 event->setDefaultHandled(); 160 161 LocalFrame* frame = document().frame(); 162 if (!frame) 163 return; 164 FrameLoadRequest frameRequest(&document(), ResourceRequest(document().completeURL(url)), target); 165 frameRequest.setTriggeringEvent(event); 166 frame->loader().load(frameRequest); 167 return; 168 } 169 } 170 171 SVGGraphicsElement::defaultEventHandler(event); 172 } 173 174 short SVGAElement::tabIndex() const 175 { 176 // Skip the supportsFocus check in SVGElement. 177 return Element::tabIndex(); 178 } 179 180 bool SVGAElement::supportsFocus() const 181 { 182 if (rendererIsEditable()) 183 return SVGGraphicsElement::supportsFocus(); 184 // If not a link we should still be able to focus the element if it has tabIndex. 185 return isLink() || Element::supportsFocus(); 186 } 187 188 bool SVGAElement::isURLAttribute(const Attribute& attribute) const 189 { 190 return attribute.name().localName() == hrefAttr || SVGGraphicsElement::isURLAttribute(attribute); 191 } 192 193 bool SVGAElement::isMouseFocusable() const 194 { 195 // Links are focusable by default, but only allow links with tabindex or contenteditable to be mouse focusable. 196 // https://bugs.webkit.org/show_bug.cgi?id=26856 197 if (isLink()) 198 return Element::supportsFocus(); 199 200 return SVGElement::isMouseFocusable(); 201 } 202 203 bool SVGAElement::isKeyboardFocusable() const 204 { 205 if (isFocusable() && Element::supportsFocus()) 206 return SVGElement::isKeyboardFocusable(); 207 208 if (isLink()) 209 return document().frameHost()->chrome().client().tabsToLinks(); 210 return SVGElement::isKeyboardFocusable(); 211 } 212 213 bool SVGAElement::canStartSelection() const 214 { 215 if (!isLink()) 216 return SVGElement::canStartSelection(); 217 return rendererIsEditable(); 218 } 219 220 bool SVGAElement::willRespondToMouseClickEvents() 221 { 222 return isLink() || SVGGraphicsElement::willRespondToMouseClickEvents(); 223 } 224 225 } // namespace WebCore 226