WebCore/svg/SVGAElement.cpp
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebCore/svg/SVGAElement.cpp	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,232 @@
+/*
+    Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org>
+                  2004, 2005, 2007 Rob Buis <buis@kde.org>
+                  2007 Eric Seidel <eric@webkit.org>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGAElement.h"
+
+#include "Attr.h"
+#include "Attribute.h"
+#include "CSSHelper.h"
+#include "Document.h"
+#include "EventHandler.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoaderTypes.h"
+#include "KeyboardEvent.h"
+#include "MouseEvent.h"
+#include "PlatformMouseEvent.h"
+#include "RenderSVGInline.h"
+#include "RenderSVGTransformableContainer.h"
+#include "ResourceRequest.h"
+#include "SVGNames.h"
+#include "SVGSMILElement.h"
+#include "XLinkNames.h"
+
+namespace WebCore {
+
+SVGAElement::SVGAElement(const QualifiedName& tagName, Document *doc)
+    : SVGStyledTransformableElement(tagName, doc)
+    , SVGURIReference()
+    , SVGTests()
+    , SVGLangSpace()
+    , SVGExternalResourcesRequired()
+{
+}
+
+SVGAElement::~SVGAElement()
+{
+}
+
+String SVGAElement::title() const
+{
+    // If the xlink:title is set (non-empty string), use it.
+    const AtomicString& title = getAttribute(XLinkNames::titleAttr);
+    if (!title.isEmpty())
+        return title;
+
+    // Otherwise, use the title of this element.
+    return SVGStyledElement::title();
+}
+
+void SVGAElement::parseMappedAttribute(Attribute* attr)
+{
+    if (attr->name() == SVGNames::targetAttr)
+        setTargetBaseValue(attr->value());
+    else {
+        if (SVGURIReference::parseMappedAttribute(attr))
+            return;
+        if (SVGTests::parseMappedAttribute(attr))
+            return;
+        if (SVGLangSpace::parseMappedAttribute(attr))
+            return;
+        if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
+            return;
+        SVGStyledTransformableElement::parseMappedAttribute(attr);
+    }
+}
+
+void SVGAElement::svgAttributeChanged(const QualifiedName& attrName)
+{
+    SVGStyledTransformableElement::svgAttributeChanged(attrName);
+
+    // Unlike other SVG*Element classes, SVGAElement only listens to SVGURIReference changes
+    // as none of the other properties changes the linking behaviour for our <a> element.
+    if (SVGURIReference::isKnownAttribute(attrName)) {
+        bool wasLink = isLink();
+        setIsLink(!href().isNull());
+
+        if (wasLink != isLink())
+            setNeedsStyleRecalc();
+    }
+}
+
+void SVGAElement::synchronizeProperty(const QualifiedName& attrName)
+{
+    SVGStyledTransformableElement::synchronizeProperty(attrName);
+
+    if (attrName == anyQName()) {
+        synchronizeTarget();
+        synchronizeHref();
+        synchronizeExternalResourcesRequired();
+        return;
+    }
+
+    if (attrName == SVGNames::targetAttr)
+        synchronizeTarget();
+    else if (SVGURIReference::isKnownAttribute(attrName))
+        synchronizeHref();
+    else if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
+        synchronizeExternalResourcesRequired();
+}
+
+RenderObject* SVGAElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    if (static_cast<SVGElement*>(parent())->isTextContent())
+        return new (arena) RenderSVGInline(this);
+
+    return new (arena) RenderSVGTransformableContainer(this);
+}
+
+void SVGAElement::defaultEventHandler(Event* evt)
+{
+    if (isLink() && (evt->type() == eventNames().clickEvent || (evt->type() == eventNames().keydownEvent && focused()))) {
+        MouseEvent* e = 0;
+        if (evt->type() == eventNames().clickEvent && evt->isMouseEvent())
+            e = static_cast<MouseEvent*>(evt);
+        
+        KeyboardEvent* k = 0;
+        if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent())
+            k = static_cast<KeyboardEvent*>(evt);
+        
+        if (e && e->button() == RightButton) {
+            SVGStyledTransformableElement::defaultEventHandler(evt);
+            return;
+        }
+        
+        if (k) {
+            if (k->keyIdentifier() != "Enter") {
+                SVGStyledTransformableElement::defaultEventHandler(evt);
+                return;
+            }
+            evt->setDefaultHandled();
+            dispatchSimulatedClick(evt);
+            return;
+        }
+        
+        String target = this->target();
+        if (e && e->button() == MiddleButton)
+            target = "_blank";
+        else if (target.isEmpty()) // if target is empty, default to "_self" or use xlink:target if set
+            target = (getAttribute(XLinkNames::showAttr) == "new") ? "_blank" : "_self";
+
+        if (!evt->defaultPrevented()) {
+            String url = deprecatedParseURL(href());
+#if ENABLE(SVG_ANIMATION)
+            if (url.startsWith("#")) {
+                Element* targetElement = document()->getElementById(url.substring(1));
+                if (SVGSMILElement::isSMILElement(targetElement)) {
+                    SVGSMILElement* timed = static_cast<SVGSMILElement*>(targetElement);
+                    timed->beginByLinkActivation();
+                    evt->setDefaultHandled();
+                    SVGStyledTransformableElement::defaultEventHandler(evt);
+                    return;
+                }
+            }
+#endif
+            if (document()->frame())
+                document()->frame()->loader()->urlSelected(document()->completeURL(url), target, evt, false, false, true, SendReferrer);
+        }
+
+        evt->setDefaultHandled();
+    }
+
+    SVGStyledTransformableElement::defaultEventHandler(evt);
+}
+
+bool SVGAElement::supportsFocus() const
+{
+    if (isContentEditable())
+        return SVGStyledTransformableElement::supportsFocus();
+    return true;
+}
+
+bool SVGAElement::isFocusable() const
+{
+    if (renderer() && renderer()->absoluteClippedOverflowRect().isEmpty())
+        return false;
+    
+    return SVGElement::isFocusable();
+}
+
+bool SVGAElement::isMouseFocusable() const
+{
+    return false;
+}
+
+bool SVGAElement::isKeyboardFocusable(KeyboardEvent* event) const
+{
+    if (!isFocusable())
+        return false;
+    
+    if (!document()->frame())
+        return false;
+    
+    return document()->frame()->eventHandler()->tabsToLinks(event);
+}
+
+bool SVGAElement::childShouldCreateRenderer(Node* child) const
+{
+    // http://www.w3.org/2003/01/REC-SVG11-20030114-errata#linking-text-environment
+    // The 'a' element may contain any element that its parent may contain, except itself.
+    if (child->hasTagName(SVGNames::aTag))
+        return false;
+    if (parent() && parent()->isSVGElement())
+        return static_cast<SVGElement*>(parent())->childShouldCreateRenderer(child);
+
+    return SVGElement::childShouldCreateRenderer(child);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)