1 /* 2 Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann (at) kde.org> 3 2004, 2005, 2007 Rob Buis <buis (at) kde.org> 4 2007 Eric Seidel <eric (at) webkit.org> 5 6 This library is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Library General Public 8 License as published by the Free Software Foundation; either 9 version 2 of the License, or (at your option) any later version. 10 11 This library is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Library General Public License for more details. 15 16 You should have received a copy of the GNU Library General Public License 17 along with this library; see the file COPYING.LIB. If not, write to 18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 Boston, MA 02110-1301, USA. 20 */ 21 22 #include "config.h" 23 24 #if ENABLE(SVG) 25 #include "SVGAElement.h" 26 27 #include "Attr.h" 28 #include "CSSHelper.h" 29 #include "Document.h" 30 #include "EventHandler.h" 31 #include "EventNames.h" 32 #include "Frame.h" 33 #include "FrameLoader.h" 34 #include "FrameLoaderTypes.h" 35 #include "KeyboardEvent.h" 36 #include "MappedAttribute.h" 37 #include "MouseEvent.h" 38 #include "PlatformMouseEvent.h" 39 #include "RenderSVGInline.h" 40 #include "RenderSVGTransformableContainer.h" 41 #include "ResourceRequest.h" 42 #include "SVGNames.h" 43 #include "SVGSMILElement.h" 44 #include "XLinkNames.h" 45 46 namespace WebCore { 47 48 SVGAElement::SVGAElement(const QualifiedName& tagName, Document *doc) 49 : SVGStyledTransformableElement(tagName, doc) 50 , SVGURIReference() 51 , SVGTests() 52 , SVGLangSpace() 53 , SVGExternalResourcesRequired() 54 { 55 } 56 57 SVGAElement::~SVGAElement() 58 { 59 } 60 61 String SVGAElement::title() const 62 { 63 return getAttribute(XLinkNames::titleAttr); 64 } 65 66 void SVGAElement::parseMappedAttribute(MappedAttribute* attr) 67 { 68 if (attr->name() == SVGNames::targetAttr) 69 setTargetBaseValue(attr->value()); 70 else { 71 if (SVGURIReference::parseMappedAttribute(attr)) 72 return; 73 if (SVGTests::parseMappedAttribute(attr)) 74 return; 75 if (SVGLangSpace::parseMappedAttribute(attr)) 76 return; 77 if (SVGExternalResourcesRequired::parseMappedAttribute(attr)) 78 return; 79 SVGStyledTransformableElement::parseMappedAttribute(attr); 80 } 81 } 82 83 void SVGAElement::svgAttributeChanged(const QualifiedName& attrName) 84 { 85 SVGStyledTransformableElement::svgAttributeChanged(attrName); 86 87 // Unlike other SVG*Element classes, SVGAElement only listens to SVGURIReference changes 88 // as none of the other properties changes the linking behaviour for our <a> element. 89 if (SVGURIReference::isKnownAttribute(attrName)) { 90 bool wasLink = isLink(); 91 setIsLink(!href().isNull()); 92 93 if (wasLink != isLink()) 94 setNeedsStyleRecalc(); 95 } 96 } 97 98 void SVGAElement::synchronizeProperty(const QualifiedName& attrName) 99 { 100 SVGStyledTransformableElement::synchronizeProperty(attrName); 101 102 if (attrName == anyQName()) { 103 synchronizeTarget(); 104 synchronizeHref(); 105 synchronizeExternalResourcesRequired(); 106 return; 107 } 108 109 if (attrName == SVGNames::targetAttr) 110 synchronizeTarget(); 111 else if (SVGURIReference::isKnownAttribute(attrName)) 112 synchronizeHref(); 113 else if (SVGExternalResourcesRequired::isKnownAttribute(attrName)) 114 synchronizeExternalResourcesRequired(); 115 } 116 117 RenderObject* SVGAElement::createRenderer(RenderArena* arena, RenderStyle*) 118 { 119 if (static_cast<SVGElement*>(parent())->isTextContent()) 120 return new (arena) RenderSVGInline(this); 121 122 return new (arena) RenderSVGTransformableContainer(this); 123 } 124 125 void SVGAElement::defaultEventHandler(Event* evt) 126 { 127 if (isLink() && (evt->type() == eventNames().clickEvent || (evt->type() == eventNames().keydownEvent && focused()))) { 128 MouseEvent* e = 0; 129 if (evt->type() == eventNames().clickEvent && evt->isMouseEvent()) 130 e = static_cast<MouseEvent*>(evt); 131 132 KeyboardEvent* k = 0; 133 if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent()) 134 k = static_cast<KeyboardEvent*>(evt); 135 136 if (e && e->button() == RightButton) { 137 SVGStyledTransformableElement::defaultEventHandler(evt); 138 return; 139 } 140 141 if (k) { 142 if (k->keyIdentifier() != "Enter") { 143 SVGStyledTransformableElement::defaultEventHandler(evt); 144 return; 145 } 146 evt->setDefaultHandled(); 147 dispatchSimulatedClick(evt); 148 return; 149 } 150 151 String target = this->target(); 152 if (e && e->button() == MiddleButton) 153 target = "_blank"; 154 else if (target.isEmpty()) // if target is empty, default to "_self" or use xlink:target if set 155 target = (getAttribute(XLinkNames::showAttr) == "new") ? "_blank" : "_self"; 156 157 if (!evt->defaultPrevented()) { 158 String url = deprecatedParseURL(href()); 159 #if ENABLE(SVG_ANIMATION) 160 if (url.startsWith("#")) { 161 Element* targetElement = document()->getElementById(url.substring(1)); 162 if (SVGSMILElement::isSMILElement(targetElement)) { 163 SVGSMILElement* timed = static_cast<SVGSMILElement*>(targetElement); 164 timed->beginByLinkActivation(); 165 evt->setDefaultHandled(); 166 SVGStyledTransformableElement::defaultEventHandler(evt); 167 return; 168 } 169 } 170 #endif 171 if (document()->frame()) 172 document()->frame()->loader()->urlSelected(document()->completeURL(url), target, evt, false, false, true, SendReferrer); 173 } 174 175 evt->setDefaultHandled(); 176 } 177 178 SVGStyledTransformableElement::defaultEventHandler(evt); 179 } 180 181 bool SVGAElement::supportsFocus() const 182 { 183 if (isContentEditable()) 184 return SVGStyledTransformableElement::supportsFocus(); 185 return true; 186 } 187 188 bool SVGAElement::isFocusable() const 189 { 190 if (renderer() && renderer()->absoluteClippedOverflowRect().isEmpty()) 191 return false; 192 193 return SVGElement::isFocusable(); 194 } 195 196 bool SVGAElement::isMouseFocusable() const 197 { 198 return false; 199 } 200 201 bool SVGAElement::isKeyboardFocusable(KeyboardEvent* event) const 202 { 203 if (!isFocusable()) 204 return false; 205 206 if (!document()->frame()) 207 return false; 208 209 return document()->frame()->eventHandler()->tabsToLinks(event); 210 } 211 212 bool SVGAElement::childShouldCreateRenderer(Node* child) const 213 { 214 // http://www.w3.org/2003/01/REC-SVG11-20030114-errata#linking-text-environment 215 // The 'a' element may contain any element that its parent may contain, except itself. 216 if (child->hasTagName(SVGNames::aTag)) 217 return false; 218 if (parent() && parent()->isSVGElement()) 219 return static_cast<SVGElement*>(parent())->childShouldCreateRenderer(child); 220 221 return SVGElement::childShouldCreateRenderer(child); 222 } 223 224 } // namespace WebCore 225 226 #endif // ENABLE(SVG) 227