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 53namespace WebCore { 54 55using namespace HTMLNames; 56 57// Animated property definitions 58DEFINE_ANIMATED_STRING(SVGAElement, SVGNames::targetAttr, SVGTarget, svgTarget) 59DEFINE_ANIMATED_STRING(SVGAElement, XLinkNames::hrefAttr, Href, href) 60DEFINE_ANIMATED_BOOLEAN(SVGAElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired) 61 62BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGAElement) 63 REGISTER_LOCAL_ANIMATED_PROPERTY(svgTarget) 64 REGISTER_LOCAL_ANIMATED_PROPERTY(href) 65 REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired) 66 REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGraphicsElement) 67END_REGISTER_ANIMATED_PROPERTIES 68 69inline SVGAElement::SVGAElement(Document& document) 70 : SVGGraphicsElement(SVGNames::aTag, document) 71{ 72 ScriptWrappable::init(this); 73 registerAnimatedPropertiesForSVGAElement(); 74} 75 76PassRefPtr<SVGAElement> SVGAElement::create(Document& document) 77{ 78 return adoptRef(new SVGAElement(document)); 79} 80 81String SVGAElement::title() const 82{ 83 // If the xlink:title is set (non-empty string), use it. 84 const AtomicString& title = fastGetAttribute(XLinkNames::titleAttr); 85 if (!title.isEmpty()) 86 return title; 87 88 // Otherwise, use the title of this element. 89 return SVGElement::title(); 90} 91 92bool SVGAElement::isSupportedAttribute(const QualifiedName& attrName) 93{ 94 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); 95 if (supportedAttributes.isEmpty()) { 96 SVGURIReference::addSupportedAttributes(supportedAttributes); 97 SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes); 98 supportedAttributes.add(SVGNames::targetAttr); 99 } 100 return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName); 101} 102 103void SVGAElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 104{ 105 if (!isSupportedAttribute(name)) { 106 SVGGraphicsElement::parseAttribute(name, value); 107 return; 108 } 109 110 if (name == SVGNames::targetAttr) { 111 setSVGTargetBaseValue(value); 112 return; 113 } 114 115 if (SVGURIReference::parseAttribute(name, value)) 116 return; 117 if (SVGExternalResourcesRequired::parseAttribute(name, value)) 118 return; 119 120 ASSERT_NOT_REACHED(); 121} 122 123void SVGAElement::svgAttributeChanged(const QualifiedName& attrName) 124{ 125 if (!isSupportedAttribute(attrName)) { 126 SVGGraphicsElement::svgAttributeChanged(attrName); 127 return; 128 } 129 130 SVGElementInstance::InvalidationGuard invalidationGuard(this); 131 132 // Unlike other SVG*Element classes, SVGAElement only listens to SVGURIReference changes 133 // as none of the other properties changes the linking behaviour for our <a> element. 134 if (SVGURIReference::isKnownAttribute(attrName)) { 135 bool wasLink = isLink(); 136 setIsLink(!hrefCurrentValue().isNull()); 137 138 if (wasLink != isLink()) 139 setNeedsStyleRecalc(); 140 } 141} 142 143RenderObject* SVGAElement::createRenderer(RenderStyle*) 144{ 145 if (parentNode() && parentNode()->isSVGElement() && toSVGElement(parentNode())->isTextContent()) 146 return new RenderSVGInline(this); 147 148 return new RenderSVGTransformableContainer(this); 149} 150 151void SVGAElement::defaultEventHandler(Event* event) 152{ 153 if (isLink()) { 154 if (focused() && isEnterKeyKeydownEvent(event)) { 155 event->setDefaultHandled(); 156 dispatchSimulatedClick(event); 157 return; 158 } 159 160 if (isLinkClick(event)) { 161 String url = stripLeadingAndTrailingHTMLSpaces(hrefCurrentValue()); 162 163 if (url[0] == '#') { 164 Element* targetElement = treeScope().getElementById(url.substring(1)); 165 if (targetElement && isSVGSMILElement(*targetElement)) { 166 toSVGSMILElement(targetElement)->beginByLinkActivation(); 167 event->setDefaultHandled(); 168 return; 169 } 170 // Only allow navigation to internal <view> anchors. 171 if (targetElement && !targetElement->hasTagName(SVGNames::viewTag)) 172 return; 173 } 174 175 String target = this->target(); 176 if (target.isEmpty() && fastGetAttribute(XLinkNames::showAttr) == "new") 177 target = "_blank"; 178 event->setDefaultHandled(); 179 180 Frame* frame = document().frame(); 181 if (!frame) 182 return; 183 FrameLoadRequest frameRequest(&document(), ResourceRequest(document().completeURL(url)), target); 184 frameRequest.setTriggeringEvent(event); 185 frame->loader().load(frameRequest); 186 return; 187 } 188 } 189 190 SVGGraphicsElement::defaultEventHandler(event); 191} 192 193bool SVGAElement::supportsFocus() const 194{ 195 if (rendererIsEditable()) 196 return SVGGraphicsElement::supportsFocus(); 197 return true; 198} 199 200bool SVGAElement::rendererIsFocusable() const 201{ 202 if (renderer() && renderer()->absoluteClippedOverflowRect().isEmpty()) 203 return false; 204 205 return SVGElement::rendererIsFocusable(); 206} 207 208bool SVGAElement::isURLAttribute(const Attribute& attribute) const 209{ 210 return attribute.name().localName() == hrefAttr || SVGGraphicsElement::isURLAttribute(attribute); 211} 212 213bool SVGAElement::isMouseFocusable() const 214{ 215 return false; 216} 217 218bool SVGAElement::isKeyboardFocusable() const 219{ 220 if (!isFocusable()) 221 return false; 222 223 if (Page* page = document().page()) 224 return page->chrome().client().tabsToLinks(); 225 return false; 226} 227 228bool SVGAElement::childShouldCreateRenderer(const Node& child) const 229{ 230 // http://www.w3.org/2003/01/REC-SVG11-20030114-errata#linking-text-environment 231 // The 'a' element may contain any element that its parent may contain, except itself. 232 if (child.hasTagName(SVGNames::aTag)) 233 return false; 234 if (parentNode() && parentNode()->isSVGElement()) 235 return parentNode()->childShouldCreateRenderer(child); 236 237 return SVGGraphicsElement::childShouldCreateRenderer(child); 238} 239 240} // namespace WebCore 241