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 #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 = document()->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) 242