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