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 "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 52namespace blink { 53 54using namespace HTMLNames; 55 56inline SVGAElement::SVGAElement(Document& document) 57 : SVGGraphicsElement(SVGNames::aTag, document) 58 , SVGURIReference(this) 59 , m_svgTarget(SVGAnimatedString::create(this, SVGNames::targetAttr, SVGString::create())) 60 , m_wasFocusedByMouse(false) 61{ 62 addToPropertyMap(m_svgTarget); 63} 64 65DEFINE_NODE_FACTORY(SVGAElement) 66 67String 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 78void SVGAElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 79{ 80 parseAttributeNew(name, value); 81} 82 83void SVGAElement::svgAttributeChanged(const QualifiedName& attrName) 84{ 85 // Unlike other SVG*Element classes, SVGAElement only listens to SVGURIReference changes 86 // as none of the other properties changes the linking behaviour for our <a> element. 87 if (SVGURIReference::isKnownAttribute(attrName)) { 88 SVGElement::InvalidationGuard invalidationGuard(this); 89 90 bool wasLink = isLink(); 91 setIsLink(!hrefString().isNull()); 92 93 if (wasLink != isLink()) 94 setNeedsStyleRecalc(SubtreeStyleChange); 95 96 return; 97 } 98 99 SVGGraphicsElement::svgAttributeChanged(attrName); 100} 101 102RenderObject* SVGAElement::createRenderer(RenderStyle*) 103{ 104 if (parentNode() && parentNode()->isSVGElement() && toSVGElement(parentNode())->isTextContent()) 105 return new RenderSVGInline(this); 106 107 return new RenderSVGTransformableContainer(this); 108} 109 110void SVGAElement::defaultEventHandler(Event* event) 111{ 112 if (isLink()) { 113 if (focused() && isEnterKeyKeydownEvent(event)) { 114 event->setDefaultHandled(); 115 dispatchSimulatedClick(event); 116 return; 117 } 118 119 if (isLinkClick(event)) { 120 String url = stripLeadingAndTrailingHTMLSpaces(hrefString()); 121 122 if (url[0] == '#') { 123 Element* targetElement = treeScope().getElementById(AtomicString(url.substring(1))); 124 if (targetElement && isSVGSMILElement(*targetElement)) { 125 toSVGSMILElement(targetElement)->beginByLinkActivation(); 126 event->setDefaultHandled(); 127 return; 128 } 129 } 130 131 AtomicString target(m_svgTarget->currentValue()->value()); 132 if (target.isEmpty() && fastGetAttribute(XLinkNames::showAttr) == "new") 133 target = AtomicString("_blank", AtomicString::ConstructFromLiteral); 134 event->setDefaultHandled(); 135 136 LocalFrame* frame = document().frame(); 137 if (!frame) 138 return; 139 FrameLoadRequest frameRequest(&document(), ResourceRequest(document().completeURL(url)), target); 140 frameRequest.setTriggeringEvent(event); 141 frame->loader().load(frameRequest); 142 return; 143 } 144 } 145 146 SVGGraphicsElement::defaultEventHandler(event); 147} 148 149short SVGAElement::tabIndex() const 150{ 151 // Skip the supportsFocus check in SVGElement. 152 return Element::tabIndex(); 153} 154 155bool SVGAElement::supportsFocus() const 156{ 157 if (hasEditableStyle()) 158 return SVGGraphicsElement::supportsFocus(); 159 // If not a link we should still be able to focus the element if it has tabIndex. 160 return isLink() || SVGGraphicsElement::supportsFocus(); 161} 162 163bool SVGAElement::shouldHaveFocusAppearance() const 164{ 165 return !m_wasFocusedByMouse || SVGGraphicsElement::supportsFocus(); 166} 167 168void SVGAElement::dispatchFocusEvent(Element* oldFocusedElement, FocusType type) 169{ 170 if (type != FocusTypePage) 171 m_wasFocusedByMouse = type == FocusTypeMouse; 172 SVGGraphicsElement::dispatchFocusEvent(oldFocusedElement, type); 173} 174 175bool SVGAElement::isURLAttribute(const Attribute& attribute) const 176{ 177 return attribute.name().localName() == hrefAttr || SVGGraphicsElement::isURLAttribute(attribute); 178} 179 180bool SVGAElement::isMouseFocusable() const 181{ 182 if (isLink()) 183 return supportsFocus(); 184 185 return SVGElement::isMouseFocusable(); 186} 187 188bool SVGAElement::isKeyboardFocusable() const 189{ 190 if (isFocusable() && Element::supportsFocus()) 191 return SVGElement::isKeyboardFocusable(); 192 193 if (isLink()) 194 return document().frameHost()->chrome().client().tabsToLinks(); 195 return SVGElement::isKeyboardFocusable(); 196} 197 198bool SVGAElement::canStartSelection() const 199{ 200 if (!isLink()) 201 return SVGElement::canStartSelection(); 202 return hasEditableStyle(); 203} 204 205bool SVGAElement::willRespondToMouseClickEvents() 206{ 207 return isLink() || SVGGraphicsElement::willRespondToMouseClickEvents(); 208} 209 210} // namespace blink 211